feat(issued-orders): make line items optional (issue by sections alone)

Items are no longer required on issued orders — an order can be issued
purely from its rich-text sections (Obsah).

- DocumentItemsEditor: opt-in allowEmpty prop lets the list go to zero
  rows (default false keeps the offers/invoices at-least-one-item rule).
- IssuedOrderDetail: allowEmpty on the editor; a saved order with no
  items reopens empty (not a blank starter row); submit guard now
  requires at least one item OR a non-empty section, not an item.
- PDF: with no items the billing heading, items table and total row are
  omitted entirely — a sections-only order shows only its Obsah.
- Service: finalize (draft->sent) and create-as-non-draft reject a
  completely blank order (no items AND no sections) with a Czech 400
  (empty_document); drafts may still be saved empty as WIP.
- Tests: sections-only finalize + blank-order rejection + sections-only
  PDF render; existing finalize fixtures given minimal content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-06-24 21:36:35 +02:00
parent 983a1408f1
commit 237ebf3ef8
7 changed files with 174 additions and 17 deletions

View File

@@ -87,7 +87,9 @@ describe("issued-order drafts — deferred numbering", () => {
it("finalizing a draft (draft -> sent) assigns the next sequence number", async () => {
const expected = (await previewIssuedOrderNumber()).number;
const draft = await createIssuedOrder({});
const draft = await createIssuedOrder({
items: [{ description: "Položka", quantity: 1, unit_price: 1 }],
});
if ("error" in draft)
throw new Error(`createIssuedOrder failed: ${draft.error}`);
issuedOrderIds.push(draft.id);
@@ -104,7 +106,9 @@ describe("issued-order drafts — deferred numbering", () => {
});
it("finalizing is idempotent — re-finalizing does not re-number", async () => {
const draft = await createIssuedOrder({});
const draft = await createIssuedOrder({
items: [{ description: "Položka", quantity: 1, unit_price: 1 }],
});
if ("error" in draft)
throw new Error(`createIssuedOrder failed: ${draft.error}`);
issuedOrderIds.push(draft.id);