Rechnungsanalyse: Termin landet im Akquise-Ticket und damit im Planboard
Der im Gespraech vereinbarte Termin wird mit einem Klick am Akquise-Ticket
eingetragen (startDate/startTime/endTime/assignedTo/assignedName) - genau die
Felder, die das WOMS-Planboard liest. Kein zweiter Datensatz, damit Termin und
Ticket nicht auseinanderlaufen koennen.
- server/services/appointments.js: Ticket des Kunden finden, Termin schreiben,
belegte Zeiten lesen; Umrechnung ISO <-> "dd.mm.yyyy" und "hh:mm" <-> "hhmm"
- Routen GET /api/portal-admin/appointments und
POST /api/portal-admin/customers/:id/appointment
- Bereits vergebene Zeiten sind in der Terminauswahl gesperrt ("belegt"), der
eigene Termin bleibt waehlbar; steht am Ticket schon einer, ist er beim
Oeffnen vorausgewaehlt
- Zeiten, die jemand von Hand in WOMS gesetzt hat, tauchen mit auf
Sicherung gegen Datenverlust: bevorzugt wird das Akquise-Ticket. Gibt es keins,
kommt nur ein anderes offenes Ticket OHNE Datum in Frage - bei Webpage- und
Projekttickets bedeutet startDate den Projektstart, den wuerden wir sonst still
ueberschreiben. Die Rueckmeldung nennt immer Nummer und Art des Tickets.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
Query,
|
||||
ID,
|
||||
} from '../services/appwriteAdmin.js'
|
||||
import { listAppointments, saveAppointment } from '../services/appointments.js'
|
||||
import { getCustomerActivity } from '../services/customerActivity.js'
|
||||
import { listInvoicesForClient } from '../services/invoiceNinja.js'
|
||||
import { sanitizeMessage } from './chat.js'
|
||||
@@ -185,6 +186,36 @@ router.get('/customers', async (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
// ----------------------------------------------------------------- Termine --
|
||||
// Termine haengen am Akquise-Ticket (workorders) und werden vom WOMS-Planboard
|
||||
// gelesen. Siehe server/services/appointments.js.
|
||||
router.get('/appointments', async (req, res) => {
|
||||
try {
|
||||
const appointments = await listAppointments({
|
||||
from: String(req.query.from || ''),
|
||||
to: String(req.query.to || ''),
|
||||
})
|
||||
return res.json({ appointments })
|
||||
} catch (err) {
|
||||
return res.status(err.status || 500).json({ error: err.message || 'Termine konnten nicht geladen werden' })
|
||||
}
|
||||
})
|
||||
|
||||
router.post('/customers/:customerId/appointment', async (req, res) => {
|
||||
const { date, time, employeeEmail } = req.body || {}
|
||||
try {
|
||||
const appointment = await saveAppointment({
|
||||
customerId: req.params.customerId,
|
||||
employeeEmail,
|
||||
date,
|
||||
time,
|
||||
})
|
||||
return res.json({ success: true, appointment })
|
||||
} catch (err) {
|
||||
return res.status(err.status || 500).json({ error: err.message || 'Termin konnte nicht gespeichert werden' })
|
||||
}
|
||||
})
|
||||
|
||||
// --------------------------------------------- Einzelner Kunde (Stammdaten) --
|
||||
// Fuer die Rechnungsanalyse (kalkulation.html), die den Lead vorbefuellt.
|
||||
router.get('/customers/:customerId', async (req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user