Headline
The configurable B2C form was built. Place-of-supply was not.
Admin can write customer questions and IF/AND/OR rules. The booking wizard can show those questions and take reduced rate, RFQ + chat, or “proceed at standard.” CH/LI/NO/GR keep local B2C rates. Self-billing note exists. Platform VAT number and address are configurable.
Everything that depends on where the work is and whether it is immovable is absent. There is one question list, shown only to the customer. VAT country is the profile location (empty → BE), not the booking address. movable, immovable, project dependant, and “immovable but exempt from Belgian reverse charge” do not exist in the schema. Project creation wizard has no VAT questions at all.
Points 2–3
What the B2B table required vs what applyB2BInvoiceRule does
| VAT country | Spec (platform B2B charge) | Code today |
|---|---|---|
| All except five exceptions | VAT €0, label Reverse Charge (not a 0% rate) | 0% + Article 39bis note. Label is not “Reverse Charge.” Only if country resolves to NL/DE/… and VAT is VIES-verified. |
| Belgium, movable or “exempt from Belgian reverse charge” | Same as B2C (21% or reduced 6%) | Belgium is always same-as-B2C. No movable flag, no exempt checkbox. |
| Belgium, immovable | Reverse Charge, VAT €0 | Missing — BE is in B2B_SAME_AS_B2C_COUNTRIES. Immovable Belgian B2B still gets 6%/21%. |
| Switzerland / Liechtenstein / Norway / Greece | Same as B2C (8.1 / 8.1 / 25 / 24) | Done |
Source: spec table in chat · vatManagement.ts B2B_SAME_AS_B2C_COUNTRIES and applyB2BInvoiceRule
Full scoreboard
Original spec, item by item
| # | Requirement | Status | What’s in code |
|---|---|---|---|
| 1 | VAT management block on service configuration | Done | Admin toggle, questions, logic rules. |
| 1a | Customer questions in booking wizard (text, field, type, unit) | Partial | Shown on booking step 3. Checkbox options cannot accept commas while typing. |
| 1b | Professional questions in project creation wizard | Missing | One reducedVatQuestions array. Project wizard has no VAT UI. Zero vatManagement references under project-wizard/. |
| 1c | Logic: country dropdown, standard/reduced %, IF/AND/OR, THEN reduced or RFQ, custom text | Partial | Engine works. Country is a free-text ISO box, not a dropdown. |
| 1d | No match → standard rate; reduced → checkout reduced; RFQ → chat, or proceed at standard | Partial | All three branches exist. Chat does not carry wizard answers. Reduced path uses the wrong country (see 2). |
| 2a | B2C VAT country = booking / service address | Missing | Uses customer.location.country. Service address is notes text only. |
| 2b | B2B immovable → booking address; movable → customer business address | Missing | No movable classification, so no split. |
| 2c | Admin: movable / immovable / project-dependent (Article 47) | Missing | No field on IServiceConfiguration. Grep for movable/immovable/article 47: no matches. |
| 2d | Checkbox “immovable but exempt from Belgian reverse charge” | Missing | Not in schema or admin UI. |
| 2e | Project-dependent injects Article 47 question for the professional | Missing | Depends on 1b + 2c. |
| 3a | Default B2B: €0, show “Reverse Charge” | Partial | 0% + “Intra-Community supply… Article 39bis”. UI still says 0% VAT. |
| 3b | BE immovable B2B: Reverse Charge €0 | Missing | Opposite of spec: BE never reverse-charges. |
| 3c | CH / LI / NO / GR same as B2C | Done | Hardcoded exception set. |
| 4 | Belgian B2B: Peppol, auto PDF + UBL via Odoo (Belgian only) | Partial | UBL + Odoo create exist. Default Peppol off. Odoo does not send. Status sent never written. |
| 5 | Invoice after completion: service, project, scope, units, options, extras, discounts, VAT, dates, pro company/VAT, B2B customer details | Partial | Generated at payment authorize, not completion. Description + amount only (no unit qty). Extras usually missing. Dates, pro VAT, B2B name/address/VAT can print if populated. Discounts yes. |
| 6 | Self-billing note “Prepared and sent on behalf of the supplier.” | Done | On the single self-billed PDF. There is still only one invoice, not customer + supplier documents. |
| 7 | Quotation: multiple lines, description, price, VAT dropdown for that service and customer country; B2B rates only for business | Partial | Multi-line + dropdown exist. Options come from a often-wrong country, so the list is Belgian 21/6. Totals auto-sum. |
| 8 | Admin can manually create invoices and credit notes to customers and on behalf of the supplier | Partial | Can regenerate PDF/UBL or a credit note from an existing payment. Cannot compose a standalone FIX or SUP correction. |
| 9 | Fixtract VAT number and address configurable | Done | Admin settings → Invoice issuer. |
23 rows after splitting 1 and 2. Weighted: 5×1 + 10×0.4 + 8×0 ≈ 39%.
Not in the original 1–9
Later feedback is also unfinished
The 20 Aug bug list sits on top of this spec, not instead of it. Still open from that pass: extras double-counted at payment, FIX vs SUP numbering and different VAT on each document, invoice email, quote VAT as a numeric comma field, RFQ chat prefills, admin payment oversight missing completion extras, commission applied twice.
The named attachments (vat_developer_service_and_reduced_rate_setup.xlsx, VAT Implementation Briefing.docx, article47_vs_belgian_domestic_reverse_charge_all_services.xlsx) are not in the repo or this workspace. Scoring used the spec text you pasted.
What “pending” means
Do not treat VAT management as implemented
Pending is not a punch-list of UI nits. The remaining work is the actual EU place-of-supply engine:
- Service classification (movable / immovable / project-dependent + BE exempt checkbox).
- Professional questions in the project wizard, including the Article 47 question when project-dependent.
- VAT country = booking address (B2C and immovable B2B) or business address (movable B2B).
- Rewrite B2B: Reverse Charge label; Belgian immovable €0; Belgian movable follows B2C.
- Then Peppol send, completion-timed dual invoices, and the payment double-count.
20 Aug 2026 · diagnosis only