Darstellung
05 – Angebote / Vertrieb
Reifegrad: 🟢 produktiv · Schicht: offers + offer_items, @work7/domain (Offer-Funktionen), src/app/offers/*, src/app/api/offers/*, src/templates/offer-*.html
Zweck
Angebote (Kostenvoranschläge) erstellen, als PDF/E-Mail versenden, vom Kunden signieren lassen und in Aufträge/Rechnungen überführen.
Datenmodell
offers:offer_number(UNIQUE),status(Defaultdraft),customer_id(→kontakte),project_id,contact_user_id, Summen (subtotal,vat_rateDefault 20,vat_amount,total),valid_until,notes. Signatur:signed_pdf(BYTEA),signed_at,signed_by_name,signed_by_email.offer_items:position,description,quantity(NUMERIC),unit(DefaultStk),unit_price,total_priceals generierte Spalte (quantity * unit_price).
Status-Workflow
draft → sent → accepted (sowie Ableitungen). Guards in @work7/domain: isOfferDraft, assertOfferDraft – Positionen dürfen nur im Draft geändert werden, acceptOffer markiert Annahme.
Domain-Funktionen (@work7/domain)
listOffers, getOffer, createOffer, updateOffer, addOfferItem, acceptOffer, deleteOffer, getOfferPdfLink, sendOffer (E-Mail-Versand mit Subject/Body/Empfänger).
API-Endpunkte
| Endpoint | Funktion |
|---|---|
GET/POST /api/offers | Liste / anlegen |
GET/PUT/DELETE /api/offers/[id] | Detail / ändern / löschen |
GET/POST /api/offers/[id]/items · /api/offers/items | Positionen verwalten |
POST /api/offers/[id]/send-email | Angebot per E-Mail senden |
GET /api/pdf/offers/[id] · GET /api/print/offers/[id] | PDF / Druckansicht |
… /api/signing/offer/[id] | digitale Signatur starten (DocuSign, siehe 14-docusign-signing) |
PDF & Druck
- Templates:
src/templates/offer-template.html,offer-multi-page.html,order-confirmation-template.html(Auftragsbestätigung). Rendering siehe 18-pdf-print-templates. - Druckseite:
/print/offers/[id](serverseitig gerendert für sauberen Druck/PDF).
Überführung in Folgeprozesse
- Anfrage → Angebot:
POST /api/anfragen/[id]/create-offerlegt einendraft-Angebot an, verknüpft beidseitig (anfragen.offer_id↔offers.anfrage_id) und setzt den Anfrage-Statusangebot_erstellt. Der Kanban-Status bedeutet „Angebot hängt an der Anfrage“, nicht „versendet“. Detail- und Board-UI zeigen Nummernlink + Angebotsstatus (z. B. Entwurf). Direkter Statuswechsel aufangebot_erstelltohne Angebot ist blockiert (setAnfrageStatus). - Rechnung aus Angebot:
POST /api/invoices/from-offererzeugt eine Rechnung inkl. Positionen aus dem Angebot (createInvoiceFromOffer, siehe 10-rechnungen-e-rechnung). - Signatur: signiertes PDF wird am Angebot gespeichert (
signed_pdf/signed_*). - Versand auch über den WhatsApp-Agent möglich (Domain-Tool
sendOffer).
UI
/offers (Liste), /offers/[id] (Detail mit Positionen, Versand, Signatur-Status). Komponenten: src/components/offers/*.
Besonderheiten
kontakt_idam Angebot darf Person oder Organisation sein (Privatkunden oftkind=person). Gleiches gilt für Projekt/Rapport/Rechnung/Abnahme.
Bekannte Befunde / offene Punkte
- Default-
vat_rateist 20 % (AT-orientiert) – für DE-Mandanten ggf. über Firmen-Default (companies.default_vat_rate) zu setzen. - Angebots-Nummernformat steuert
companies.quote_number_format.