Skip to main content

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.