- Ya
- 27 Agosti 2026, 23:21 UTC
- Mwandishi
- Kamo
- Ahadi ya
- c48342c
Kamo's own invoice, written only by InvoicingService. Nothing on it is supplied by a caller: every figure is derived from the lines on every write, which is the opposite of **************** where subtotal/tax/total are taken verbatim off the request and a total is derived only when two of the three are null — so a caller can post a populated order with total = 0. UX_INVOICE_ORG_NUMBER is the BACKSTOP, not the mechanism. The row lock in DocumentNumberService is the mechanism; this exists so that a future bug which bypasses the lock fails as a loud constraint violation rather than two customers holding the same invoice number. INVOICE_NUMBER is nullable because a DRAFT has none, and Postgres treats NULLs as distinct so drafts coexist under it. The four classification enums (SERVICE_LINE_TYPE / PROPERTY_CLASS / WORK_CLASS / CONTRACT_FORM) are carried even though nothing computes tax — B5: Kamo stores every tax field and computes none. They are NULL on every ServiceLineItem in production because the one writer, **************** sets only base-class fields. TAX_CLASS_ID is a UUID and never a Long: Offering.taxClassId is a Long against TaxClass's UUID key, a structurally impossible reference and a large part of why the tax tables have never been readable. Currency is on the header and never on a line; ServiceJob has money columns and no currency at all, so a job-derived invoice takes it from the org. AMOUNT_PAID / AMOUNT_DUE / PARTIALLY_PAID ship as SHAPE ONLY. Deposits and progress billing are deliberately out of BL2's scope: nothing in commerce models a deposit, milestone or retainage, and there is no partial-payment writer. There is no @PreUpdate immutability guard on a line, and that is deliberate: a callback fires at FLUSH, so the recompute finalize legitimately performs would be rejected by a guard that reads the parent's status at commit time. The guard lives in the service; the enforcement that survives bulk JPQL is the REVOKE. The repository extends Repository, not JpaRepository — a finalized invoice is a money event and the correction path is a credit note, not a delete. Observed failures, verbatim. RED (before the entities existed): InvoiceTotalsTest.java:[3,50] cannot find symbol CommerceInvoiceTest.java:[3,50] cannot find symbol (package **************** GREEN: Tests run: 62, Failures: 0, Errors: 0, Skipped: 0 — including the Spring context test, which builds the SessionFactory and so proves the BILL_TO_ prefix on EmbAddress does not collide.