Skip to content

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 (Default draft), customer_id (→ kontakte), project_id, contact_user_id, Summen (subtotal, vat_rate Default 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 (Default Stk), unit_price, total_price als 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

EndpointFunktion
GET/POST /api/offersListe / anlegen
GET/PUT/DELETE /api/offers/[id]Detail / ändern / löschen
GET/POST /api/offers/[id]/items · /api/offers/itemsPositionen verwalten
POST /api/offers/[id]/send-emailAngebot 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-offer legt einen draft-Angebot an, verknüpft beidseitig (anfragen.offer_idoffers.anfrage_id) und setzt den Anfrage-Status angebot_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 auf angebot_erstellt ohne Angebot ist blockiert (setAnfrageStatus).
  • Rechnung aus Angebot: POST /api/invoices/from-offer erzeugt 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_id am Angebot darf Person oder Organisation sein (Privatkunden oft kind=person). Gleiches gilt für Projekt/Rapport/Rechnung/Abnahme.

Bekannte Befunde / offene Punkte

  • Default-vat_rate ist 20 % (AT-orientiert) – für DE-Mandanten ggf. über Firmen-Default (companies.default_vat_rate) zu setzen.
  • Angebots-Nummernformat steuert companies.quote_number_format.

Verwandte Notes

Work7 · Software für Handwerksbetriebe