Order Confirmations
Order Confirmations
Turn an accepted quote into a binding Auftragsbestätigung (AB) — the written confirmation of the order before delivery and invoicing
Visibility (production): As of v0.223.8 the entire Accounting surface (sidebar entries,
/accounting/*routes, Settings → Accounting tab) is gated to owner accounts in production. Dev / staging builds keep everything visible. This page documents the feature for owners and for the eventual general-availability release.
Overview
The Order Confirmations module lives at /accounting/order-confirmations and sits in the German document chain between the quote and the invoice:
Angebot (Quote) → Auftragsbestätigung (AB) → Lieferschein (LS) → Rechnung (Invoice).
An Auftragsbestätigung is the written, post-acceptance confirmation that you and the customer have a deal — in many trades the moment the contract becomes binding. It is not a tax-allocation event: there is no VAT deadline, no Storno chain, no payment tracking, and no Mahnwesen. It restates what the customer ordered so both sides have a record before the gear ships or the service starts.
You reach it from the sidebar under Accounting → Order confirmations. The list view (/accounting/order-confirmations) holds every AB; opening one navigates to the block editor (/accounting/order-confirmations/:id).
Order confirmations are local-first: drafting and editing work fully offline (auto-saved to IndexedDB, backed up to OPFS), and the row syncs to your self-hosted Supabase when you come back online. Only finalize — which allocates a gap-free AB number — needs connectivity.
Lifecycle
An order confirmation follows a status machine. The states are draft, pending, sent, acknowledged, expired, cancelled, and superseded. The path you drive through the shipped UI today is short:
draft ──finalize──▶ sent (create from quote) (AB number assigned, record locked)
- draft — fully editable. Lives on your device until you finalize; auto-saved every 500 ms.
- pending — transient internal state while finalize allocates the AB number (you will rarely see it).
- sent — finalized. The AB number is assigned and the customer + line items + totals + dates are frozen (read-only).
- acknowledged / expired / cancelled / superseded — defined in the model so the document chain can express "the customer confirmed", "the validity window lapsed", or "this AB was replaced". These downstream states are not yet driven by a one-click action in the UI (see Not yet available).
The client status machine is the authoritative gate — every transition is validated by
assertValidTransitionbefore it is written. Because order confirmations are stored assync_entities(status lives inside the JSON blob, not a dedicated column), there is no server-side transition trigger; the client matrix is the single source of truth.
Creating an order confirmation
An AB is always created from an accepted quote — there is no blank-AB form. This guarantees the confirmation restates exactly what the customer agreed to.
- Open Order confirmations in the sidebar.
- In the Create from an accepted quote card, pick a quote from the dropdown (only quotes with status accepted appear). If you have no accepted quotes yet, the card links you to Quotes.
- Click Create AB. The app:
- Applies the customer's acceptance selections — chosen alternatives and opted-in optional lines — exactly as the quote-to-invoice path does, so the AB reflects what was actually ordered.
- Copies the customer snapshot, line items, currency, and tax treatment, and computes subtotal / VAT / total.
- Records a
sourceRefback to the originating quote (its number prints on the PDF). - Opens the new draft in the editor.
If the accepted quote still has unresolved optional or alternative lines (the customer never chose), creation is blocked with an error rather than silently under-confirming the order — resolve the selection on the quote first. The quote itself stays accepted; creating an AB does not consume or change it.
Editing a draft
The editor (/accounting/order-confirmations/:id) mirrors the slimmed invoice editor:
- Customer — shown read-only. The customer identity is fixed at quote acceptance and cannot be changed on the AB.
- Line items — the shared invoice line-items table. Add freeform positions, edit description / quantity / unit price, reorder or remove lines, and toggle the Brutto / Netto price display. Totals (subtotal, VAT, total) recompute live.
- Customer reference — free text (e.g. the customer's PO number), prints on the PDF.
- Valid until — an optional expiration date.
- Notes — free text printed at the foot of the PDF.
Edits auto-save with a 500 ms debounce. If the same AB is changed on another device while you are editing, a save-conflict banner appears — choose Keep mine (re-apply your edit over the remote change) or discard your edit and reload the remote version. Never lose an edit silently.
Once finalized, the whole editor switches to read-only ("Finalized — read only").
Finalizing — assigning the AB number
Finalize is the irreversible step that turns a draft into a binding, numbered document. It lives on the list row (not the editor), behind a confirmation modal:
- On the list, click Finalize on a draft row.
- The Finalize order confirmation modal shows the customer and the total, and requires you to tick the acknowledgement checkbox ("…assigns a permanent sequential AB number and this order confirmation can no longer be edited").
- Confirm. The app:
- Allocates the next number from your gap-free, year-resetting counter via an atomic Supabase RPC — format
AB-YYYY-NNNN(e.g.AB-2026-0001). The year is derived server-side from Europe/Berlin time, so a skewed browser clock at a New-Year rollover can't produce a wrong-year number. - Recomputes the totals from the current line items and freezes subtotal / VAT / total so the locked record, the list row, and the PDF always agree.
- Advances the status
draft → pending → sentand locks the record.
- Allocates the next number from your gap-free, year-resetting counter via an atomic Supabase RPC — format
The acknowledgement gate exists because finalize burns a sequential legal counter — a mis-click must not consume a number. Finalize requires connectivity (the counter is server-side); attempting it offline surfaces an error.
Numbering prefix. The prefix is fixed at
AB. There is no settings page to customize it yet (see Not yet available).
The PDF
Every order confirmation can be rendered as a PDF — Preview PDF in the editor, or Download (↓) on any list row. A draft renders with "Entwurf" in place of the number; a finalized AB carries its AB-YYYY-NNNN number.
The document is generated client-side (pdfmake + the bundled Ubuntu fonts — no server round-trip) and uses your saved branding accent colour. If you have built an AB layout in the Document layout designer, that template is used; otherwise the built-in layout renders:
- AUFTRAGSBESTÄTIGUNG banner + the AB number (or Entwurf).
- Sender + customer address blocks.
- A quote-reference line — "Diese Auftragsbestätigung bezieht sich auf Angebot ANG-…" — when a source quote is present.
- Your customer-reference line, when set.
- A line-item table: Pos. / Beschreibung / Menge / Einzelpreis / Netto.
- Totals: Zwischensumme (netto), USt per rate, Gesamtbetrag.
There is no payment block, no Skonto, and no embedded e-invoice XML — an AB is not an invoice, so it does not carry a ZUGFeRD / Factur-X attachment (that lives on the invoice). The file is named after the AB number (e.g. ab-2026-0001.pdf). Both the PDF text and the editor follow the active app language (DE / EN).
The list view
The list shows every active (non-archived) order confirmation:
- Create card — the accepted-quote picker described above.
- Filter bar — status pills + a search box (matches the AB number, customer name, email, city, and customer reference) with a live result count.
- Table — columns AB#, Customer, Total, Status, and per-row actions: Open (✎), Finalize (drafts only), Download PDF (↓). Drafts bubble to the top; finalized rows sort newest-first. A status badge colours each row (info = sent, success = acknowledged, error = expired/cancelled, muted = draft/superseded).
- Mobile — below the
smbreakpoint the table becomes a card stack with the same data and actions.
Storage, sync & privacy
- Order confirmations are an array entity (
orderConfirmations) on the standard persistence pipeline: IndexedDB (primary) → OPFS (backup) → Supabase (opt-in cloud sync). The Supabase rows are RLS-protected to the owner. - Concurrent edits resolve via last-writer-wins on the mutable fields (
status,acknowledgedAt,linkedDeliveryNoteId,archivedAt); the save-conflict banner guards the editable body. - With multi-company accounting enabled, the list and the create-source picker are scoped to the active company, and new confirmations are stamped to it.
Document chain & cross-feature links
- Quotes — the only source for an AB. The quote stays accepted; see Quotes.
- Delivery notes — a finalized (sent) AB is a source for a delivery note (
AB sent → LS draft), carrying the ordered quantities forward as the delivered quantities. - Invoices — you bill from the invoice surface. Today the invoice is created from the quote / project / sub-rental / timesheet; the automatic delivery-note → invoice bridge is deferred.
Not yet available
These are designed into the data model or specced but not exposed in the current UI — documented so you don't go looking for them:
- Manual blank AB and auto-create AB on quote acceptance — creation is only the manual "from an accepted quote" flow.
- Public acknowledgement page — the customer-facing receipt link that would flip an AB to
acknowledged(mirroring the public quote-acceptance page) is not wired; there is no "mark acknowledged", "expire", or "cancel" one-click action yet. - Email send — an AB is downloaded / previewed as a PDF; there is no in-app "send to customer" action (unlike invoices).
- ZUGFeRD on the AB (UN/CEFACT TypeCode 220) — deferred until the e-invoice dispatcher refactor lands.
- Auftragsbestätigung settings sub-page — a dedicated page under Settings → Accounting for the counter prefix, default validity window, template selection and the auto-conversion toggle is specced but not yet built. The accounting settings nav has no such entry today.
Related documentation
- Quotes — the upstream document; accepted quotes feed the AB
- Delivery Notes — the next document in the chain (Lieferschein)
- Invoices — the final document (Rechnung), ZUGFeRD / Factur-X, Mahnwesen, Storno
- Accounting / Expense Tracking — the wider accounting surface (SKR04 categories, EÜR, UStVA)
- Cloud Sync Consent — how accounting documents traverse the sync engine
- Developer specs:
docs/features/v2-nh-316-auftragsbestaetigung-lieferschein/requirements.md,docs/features/v2-nh-316-auftragsbestaetigung-lieferschein/design.md
Last Updated: 2026-09-08 Version: 0.790.2
