sevDesk: automatische Rechnung (Entwurf) bei Konfigurator-Bestellung

- Neue Hook-Extension skrift-sevdesk: legt bei orders.items.create (source=
  configurator) eine sevDesk-Rechnung als ENTWURF an – Kontakt wird angelegt/
  wiederverwendet (sevdesk_contact_id am Konto), Positionen aus price_lines
  (Produkt mit Menge; Versand/Motiv/Zusatz je eigene Position), 19% USt.
  Nicht-blockierend, per SEVDESK_API_TOKEN aktiviert; Versand NICHT über sevDesk.
- orders.price_lines (JSON) speichert die Positionsaufstellung bei Bestellung
  (Konfigurator + manueller Auftrag).
- bootstrap: orders.price_lines/sevdesk_invoice_id/sevdesk_invoice_number,
  directus_users.sevdesk_contact_id.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
s4luorth
2026-09-18 07:44:28 +02:00
parent 10776764d7
commit 0f73a653b3
4 changed files with 234 additions and 0 deletions

View File

@@ -137,6 +137,7 @@ const USER_FIELDS = [
// Veraltet (frühere Mehrfach-Adressliste) – bleibt für Alt-Daten erhalten.
f('addresses', 'json', { interface: 'list', hidden: true, note: 'Veraltet – ersetzt durch billing_address/shipping_address.', options: { fields: ADDRESS_SUBFIELDS } }),
f('notes', 'text', { interface: 'input-multiline', note: 'Interne Notizen (für den Kunden nicht sichtbar).' }),
f('sevdesk_contact_id', 'string', { interface: 'input', hidden: true, note: 'Verknüpfter sevDesk-Kontakt (für Rechnungen).' }),
// Zusätzliche Login-Mailadressen: Wer sich mit einer dieser Mails per Code
// anmeldet, landet im SELBEN Konto (voller Zugriff). Liste von E-Mails.
f('alt_emails', 'json', { interface: 'tags', note: 'Weitere Login-Mailadressen (gleiches Konto).' }),
@@ -312,6 +313,11 @@ const collections = [
f('artifact_path', 'string', { interface: 'input', note: 'Verweis auf Backend-Output.' }),
f('internal_note', 'text', { interface: 'input-multiline', note: 'Interne Notiz zum Auftrag (Produktion).' }),
m2o('linked_order', 'orders', { onDelete: 'SET NULL', note: 'Verknüpfter Auftrag (z. B. Kuverts zum Unterschriftenservice). Nachträglich änderbar.' }),
// Rechnungs-Positionsaufstellung (aus der Preisberechnung) – Basis für die sevDesk-Rechnung.
f('price_lines', 'json', { interface: 'input-code', note: 'Positionsaufstellung [{label, amount, per_unit}] zum Auftragszeitpunkt.' }),
// sevDesk-Rechnung (automatisch erzeugt).
f('sevdesk_invoice_id', 'string', { interface: 'input', note: 'sevDesk-Rechnungs-ID (Entwurf/gebucht).' }),
f('sevdesk_invoice_number', 'string', { interface: 'input', note: 'sevDesk-Rechnungsnummer.' }),
{ field: 'date_created', type: 'timestamp', meta: { interface: 'datetime', readonly: true, special: ['date-created'] }, schema: {} },
{ field: 'date_updated', type: 'timestamp', meta: { interface: 'datetime', readonly: true, special: ['date-updated'] }, schema: {} },
// Produktionsansicht: durchsuchbare Empfängertabelle (Briefnummer + volle