Read-only merge gate · Fixera

Do not merge yet.

The current working tree contains a compile-breaking supplier credit-note path plus unproven VAT/Peppol/admin behaviors. The pure helper tests pass, but they do not establish that PDF, UBL, Odoo, email, completion, and admin correction flows work together.

Prioritized findings

Evidence against the merge claim

P0 · compile

Supplier credit-note dispatch was added incompletely.

fixera-server/src/services/invoiceArtifacts.ts:1246–1248 passes undefined creditNoteNumber/creditNoteUblUrl and an undeclared ublXml. The function also returns optional values where its result type requires strings at lines 1282–1283. Current npm run build fails with five TypeScript errors. The supplier credit PDF/UBL is prepared at lines 1176–1200, but its Peppol dispatch is not implemented at all; only the customer credit-note call is present.

Gate: Fix the path, then test customer and supplier credit PDFs, UBLs, related-invoice references, self-billing profile/note, persistence, and separate Peppol statuses.

P0 · payout state

Customer completion can still return success after a failed professional transfer.

fixera-server/src/handlers/Booking/completion.ts:713–746 treats a completed payment as sufficient even when captureAndTransferPayment returned TRANSFER_FAILED. The payment-safety change deliberately stores status completed with transferStatus: failed at fixera-server/src/handlers/Stripe/payment.ts:965–1002; completion therefore continues, starts invoice generation at lines 796–801, and returns “Booking completed successfully” at lines 848–854.

Gate: A transfer failure must produce an explicit pending/recovery outcome, avoid false completion messaging, and define whether invoices are held until payout recovery.

P1 · VAT

Supplier-side CH/LI/NO/GR exceptions are bypassed cross-border.

fixera-server/src/utils/vatManagement.ts:318–326 returns reverse charge for every valid cross-border supplier/buyer pair before applyB2BInvoiceRule can apply B2B_SAME_AS_B2C_COUNTRIES. This conflicts with the spec’s same-as-B2C rates for Switzerland, Liechtenstein, Norway, and Greece when those countries are the applicable supplier-side VAT jurisdiction.

Gate: Add explicit supplier-side cases for CH/LI/NO/GR, NL/DE cross-border reverse charge, and Belgian immovable vs exempt/movable work.

P1 · VAT config

Article 47 create-flow validation is ordered incorrectly.

fixera-server/src/handlers/Admin/serviceConfigurationManagement.ts:213–221 validates logic rules before injecting the Article 47 professional question. Update injects first at lines 270–275, so a new project-dependent configuration that references article47_immovable fails while the equivalent update succeeds.

Gate: POST a project-dependent service config whose rule references the generated field; assert 201, persisted question, and valid rule.

P1 · Peppol

“Sent” means Odoo API request accepted, not Peppol delivery.

fixera-server/src/services/peppolDispatch.ts:432–452 marks a document sent after button_process_edi_web_services returns and describes it as “send requested.” There is no delivery/accepted/rejected state from Odoo, no external sandbox proof, and no dedicated Peppol contract test. The provider also ignores peppolEnabled when provider is Odoo at lines 487–488.

Gate: Mock the full Odoo JSON-RPC sequence and add a controlled sandbox test that distinguishes posted, send-requested, queued, delivered, and failed.

P1 · corrections

Admin correction is still regeneration, not manual invoice composition.

The only routes are fixera-server/src/routes/Admin/index.ts:257–260: capture, invoice, and one generic credit-note endpoint. The endpoint consumes an existing payment/booking and has no request model for corrected party, lines, VAT, related invoice, or supplier-vs-customer selection. The new supplier credit fields are not exposed in the admin payment UI.

Gate: Test a supplier-side credit note end to end and, if the original requirement remains in scope, define and test an audited manual correction command/API.

P2 · UI

VAT country is a free-text input with a missing datalist.

fixera/components/ServiceConfigurationManagement.tsx:1696–1701 references list="vat-country-options", but the frontend has no matching <datalist id="vat-country-options">. This does not satisfy the original country-dropdown requirement.

Gate: Render the admin form and assert selectable ISO country options, plus comma-decimal storage such as 6,5 → 6.5.

P2 · invoice integrity

Actual dates are no longer fabricated, but they are not enforced.

fixera-server/src/services/invoiceGenerator.ts:830–831 now omits absent actual dates, correctly avoiding the previous scheduled-date fallback. However, completion only sets actualEndDate at completion.ts:673–676; an invoice can therefore omit the required actual start date. There are no PDF artifact tests.

Gate: Generate a completed unit booking and extract PDF text: assert actual start/end, unit quantity/price, materials, options, extra costs, customer VAT answers, page numbers, and totals on both FIX and SUP documents.

Required release tests

The exact test layers still missing

LayerTestExpected assertion
Type/buildnpm run build in serverZero TypeScript errors, including supplier credit path.
VAT unitSupplier CH/LI/NO/GR → BE; NL → BE; BE immovable/movable/exemptException rates remain B2C; eligible EU cases are Reverse Charge €0.
VAT APICreate booking with missing/unknown country or missing required VAT answer400/RFQ review; never silent Belgian fallback; required answers enforced server-side.
Config APIPOST Article 47 config with rule referencing generated field201 and persisted injected professional question.
Accounting576.43 base + selected options; extra cost at completion; commissionOne charge, correct customer gross, supplier net, platform fee, and payout.
ArtifactsGenerate FIX/SUP invoice and both customer/supplier credit notesDistinct totals/VAT/parties/numbers; PDF text and UBL totals agree; self-billing note present.
PeppolMock Odoo discovery/create/post/attach/send, retry, tax mapping, idempotencyCorrect side/move type/status/reason/reference; no false “sent”; failed dispatch retryable.
Completion/UIStripe transfer rejects after capture; admin retry; customer confirmationRecovery state is visible, no false booking success, no duplicate transfer, retry succeeds.
NotificationsInvoice generation for customer and professionalTwo email deliveries with the correct PDF attachment/number.

What is actually covered

Several requested fixes are present, but mostly without end-to-end proof.

Current code does contain RFQ/chat prefill, checkbox option editors that preserve commas/spaces, flexible comma-decimal VAT input, Dutch B2B customer resolution, separate FIX-/SUP- invoice generation, extra-cost accounting, invoice email attachment plumbing, and admin transfer retry fields. The server test run reported 31 files and 204 passing tests; frontend TypeScript passed.

Those tests are concentrated in pure VAT/pricing/notification helpers. There are no dedicated artifact-generator, PDF extraction, UBL schema, Peppol dispatch, admin payment handler, or completion integration tests. The server build failure and unstaged changes are release blockers regardless of the helper-test result.

Scope note: this audit made no edits to either Fixera repository. The server and frontend both contain unstaged changes at audit time; they must be reviewed and committed before a PR can be considered.