# VAT-inclusive pricing fix (PDV uračunat u cijene) — MC #106829, 2026-08-04

**MC #106829** · Status: **Implementirano lokalno, NIJE pushano/deployano** · 2026-08-04 · Grana `fix/106829-vat-inclusive`, worktree `~/business/ALAI-Holding-AS/products/qody-106829-vat`, baza `azdo/main @ 0f0acf4`

## 1. Kontekst

CEO direktiva 2026-08-04 (doslovno): „ako meni na qody stavi 3 km kafa mi ne dodajemo pdv — pdv je obracun u tu cjenu“. Cijene na meniju su BRUTO (PDV 17% je već uračunat) — kafa od 3 KM ostaje 3 KM za gosta, ne 3.51 KM. Postojeći kod je radio suprotno: `OrderService.kt` je PDV dodavao POVRH cijene (add-on formula, `lineTax = lineTotal * taxRate`, zaokruživano na 4 decimale po liniji), što je gosta naplaćivalo više nego što je meni pokazivao, a usput je i platformska provizija (`SuperAdminService.kt`) računata na tu naduvanu osnovicu — što znači da je ALAI od lansiranja naplaćivao lokale na precijenjenoj osnovi.

## 2. Šta je promijenjeno (D1–D6)

Implementacija je prošla kroz forged-prompt proces (panel od 5 eksperata → mehanik CLEAR TO DISPATCH → S1 build → S2 nezavisna verifikacija), commitovi `58e6b84` (glavna implementacija) + `e922518` (fix lažno-pozitivnog grep matcha u D5 komentaru), 18 izmijenjenih fajlova. **NIJE pushano na azdo/origin** — commitovi su samo lokalni na grani.

- **D1 — ekstrakcija PDV-a per-rate-group:** `OrderService.validateCart` grupiše linije korpe po `item.taxRate`, sabira BRUTO iznos po grupi, PDV izdvaja formulom `rate/(1+rate)` izračunatom u letu (nikad perzistiranom kao multiplikator, jer 17/117 skraćuje se na `NUMERIC(5,4)`), zaokružuje na 2 decimale PO GRUPI STOPE (ne 4dp po liniji kao ranije — BiH fiskalna praksa zaokružuje na nivou računa/grupe stope). `total` ostaje nepromijenjeni bruto iznos s menija; `subtotal` postaje osnovica (`total - taxTotal`). Testni slučaj: 3.00 KM stavka @ 0.17 → `taxTotal=0.44`, `total=3.00` (ne 3.51).
- **D2 — era diskriminator u šemi:** nova migracija `V30__vat_inclusive_pricing_era.sql` dodaje `"order".pricing_model` (backfill postojećih redova na `'v1_addon'` PRIJE nego default postane `'v2_inclusive'`); `order.version` (optimistic-lock brojač) namjerno NIJE preimenovan/reupotrijebljen za ovu svrhu.
- **D3 — receipt/CSV lockstep:** umjesto izvođenja `vatRate` iz `taxTotal/subtotal` pri čitanju (fragilno preko era granice), `OrderService.submitOrder` sada snimi `tax_rate_snapshot` JEDNOM pri kreiranju narudžbe; `ReceiptService` čita taj snapshot direktno, više ne dijeli iznova.
- **D4 — billing korekcija (bez tihe historijske izmjene):** `tax_total` i `pricing_model` dodani u CSV izvoz (`EnhancedSalesReportService` — stvarna lokacija exporta, forged-prompt je pogrešno citirao `SalesReportService.kt`, greška disclosed i dokumentovana u kodu); `SuperAdminService.kt` dobija opširan komentar koji eksplicitno iznosi nalaz o precijenjenom obračunu provizije i tačan upit za rekonstrukciju raspona, uz eksplicitno upućivanje na OPEN CEO DECISION #1 — nikakva automatska korekcija historijskih naplata nije izvršena.
- **D5 — guest/admin frontend lockstep:** `apps/guest/src/format.ts::cartSubtotal()` verifikovano ne radi nikakvu poresku matematiku (0 matcheva za rate/formula), pa strukturalno ne može divergirati od backend formule; ostavljen s komentarom koji upućuje na `OrderService.kt`. `CartPage.tsx`/`CheckoutPage.tsx`/`ReportsView.tsx` verifikovano (ne pretpostavljeno) da koriste API vrijednosti bez lokalnog preračunavanja.
- **D6 — testovi:** svi postojeći testovi koji su tvrdili staru add-on formulu ažurirani na PDV-uključene iznose (uključujući stvarnu regresiju uhvaćenu tokom rada: hardkodovan iznos 11.70 umjesto 10.00 u dva test fajla). Novi test fajl `VatInclusivePricingIntTest.kt` (5 testova): jednostruka stopa, mixed-rate (dvije različite stope u istoj korpi, dokazano da se NE blendaju), idempotency replay preko era granice, group-rounding kontrast (2.18 grupno vs 2.19 naivno po liniji). Rezultat: **107 Kotlin integracionih/unit testova, 0 failures, 0 errors**; guest vitest 30/30; staff-kitchen vitest 22/22; admin 4 pre-postojeća faila (nepovezana s ovim MC-om, root-uzrok potvrđen — testni fajl i njegova zavisnost netaknuti u grani).

## 3. Verifikacija

Put: panel od 5 eksperata (petter-graff, bilko-racunovodstvo-hr, markos-zachariadis, bruce-momjian, devils-advocate) → mehanik **CLEAR TO DISPATCH** → S1 build → S2 nezavisna verifikacija (Angie Jones/Proveo persona, odvojena sesija, Writer≠Witness).

**S2 VERDICT: PASS** — verifikator je nezavisno reprodukovao SVE acceptance signale (ne vjerujući builderovim ispisima): ponovo pokrenuo `./gradlew integrationTest` i sam sabrao JUnit XML rezultate (107/0/0, tačno poklapanje), ponovo pokrenuo guest/kitchen vitest testove, ručno preračunao PDV matematiku prije čitanja test asertacija (3.00→0.44/2.56 osnovica; grupno zaokruživanje 2.18 vs naivno 2.19; mixed-rate 3.45 vs pogrešno-blendovano 3.47 — sve se poklopilo), root-uzrokovao 4 pred-postojeća admin test faila preko git diff-a (grana dira samo `types.ts` u admin app-u), provjerio odsustvo kolizije verzije migracije, tražio UTF-8 korupciju (nije nađena).

**3–4 disclosed gapa (nijedan blokirajući):**

1. `SalesReportService.kt` (JSON izvještaj) ne grana eksplicitno na `pricing_model` za agregatne sume — matematički odbranjeno komentarom u kodu (sabiranje stvarno naplaćenih iznosa je uvijek validno), ali tehnički djelimično, ne potpuno, ispunjava D2-ov zahtjev „MUST branch“.
2. Mixed-rate narudžbe dobijaju JEDAN blendovan `tax_rate_snapshot` na nivou narudžbe (ne breakdown po stopi) jer `ReceiptDto` ima samo jedno `vatRate` polje — nije regresija (postojeće arhitekturno ograničenje), ali relevantno tek kad BiH lokal stvarno ima više PDV stopa (danas sva live podaci 17%, nije nezavisno potvrđeno protiv žive baze).
3. `ReportsView.tsx` „bez lokalnog preračuna“ potvrđeno samo preko `git diff --stat` (fajl netaknut u grani), ne direktnim čitanjem sadržaja od strane verifikatora.
4. Live DB probe (distinct `tax_rate` vrijednosti, broj historijskih narudžbi) — odbijen dozvolskim slojem sesije i builderu i verifikatoru identično; ostaje otvoreno za deploy/PI2 fazu.

## 4. OPEN CEO DECISIONS (4, nijedna auto-riješena)

1. **Historijski kredit lokalima za platformsku proviziju** — ALAI je proviziju obračunavao na precijenjenoj (add-on) osnovici za svaku `v1_addon`-era naplatu. CEO treba odlučiti: retroaktivni kredit, jednokratni otpis, ili bez akcije, i za koji vremenski raspon (upitno tek nakon što D2-ov diskriminator omogući upit).
2. **Rekonstrukcijski izvještaj za historijske narudžbe gostiju** — obavezan ili ne? Prag zavisi od broja pogođenih historijskih narudžbi (probe nije mogao biti izvršen zbog dozvolskog sloja) — odvojeno pitanje od odluke #1 (to je ALAI-jeva provizija, ovo je pitanje gostijskih povrata).
3. **PDV tretman napojnice/tipa po BiH zakonu** — panel eksplicitno NIJE mogao potvrditi (HR-persona odbila certificirati BiH praksu izvan svoje domene). Praćeno zajedno s postojećim taskom #106745 (BiH poreski savjetnik) kao njegovo 9. otvoreno pitanje.
4. **Stripe/Monri verifikacioni prag prije produkcije** — ovo mijenja stvarne naplaćene iznose, ne samo prikaz. CEO treba odlučiti koji verifikacioni gate (npr. N uspješnih test-mode naplata pregledanih od strane čovjeka) je potreban prije promovisanja D1–D5 u produkciju, odvojeno od D6-ove automatske test pokrivenosti.

## 5. Follow-up

MC #106830 — mixed-rate snapshot: proširiti `ReceiptDto`/snapshot mehanizam da podrži breakdown po stopi umjesto jednog blendovanog `vatRate` polja, relevantno kad BiH lokal stvarno uvede više PDV stopa.

---

*Evidence: `/Users/makinja/system/evidence/106829/` (dispatch-plan.md, panel/1-5\*.md, s1-build-report.md, s2-verify-report.md, p2p-native-verify-transcript.md); forged prompt: `/Users/makinja/system/prompts/forged/106829.md`.*