Skip to main content

HR firma ne može poslati račun — lanac kvarova u kontnom planu (MC #900023 / #107364 / #107372)

HR firma ne može poslati račun — lanac kvarova u kontnom planu (MC #900023 / #107364 / #107372)

Status: U RADU · Otkriveno: 2026-08-20, odmah nakon aktivacije HR eRačuna (MC #103443) Mjereno protiv: azdo/main @ d068e36d i produkcijske baze bilko-demo-pg

Aktivacija HR eRačuna je završena i dokazana istog dana, ali prvi račun se ne može poslati. Blokada nije u eRačunu nego jedan sloj niže — u kontnom planu.


1. Simptom

Draft računa se napravi. Slanje puca s HTTP 400. Slanje je tačno ono što okida eRačun, pa cijela aktivacija stoji iza vrata koja se ne otvaraju.

InvoiceService.kt:1982-1986:

val receivableAccount = resolveAccount(orgUuid, ACCOUNT_TYPE_ASSET, "1200", "12%")
    ?: throw BadRequestException("Required accounts not found (Receivable, Revenue)")
val revenueAccount = resolveAccount(orgUuid, ACCOUNT_TYPE_REVENUE, "6000", "6%")
    ?: throw BadRequestException("Required accounts not found (Receivable, Revenue)")

2. Dva ukoštena kvara

Kvar 1 — org uopšte nema kontni plan (#107364)

Izmjereno u produkcijskoj bazi: org Smart Forge (65376c57-…) ima nula redova u accounts.

Živi Entra JIT put (provision_user_with_org, V148) upisuje organizations + users + entra_external_identities ali nikad accounts. seedChartOfAccounts() (CountryService.kt:214) ima nula pozivalaca u živom kodu. AuthService.register() je mrtav (410 Gone).

CI ovo ne hvata jer svi testovi ručno rade Accounts.insert kao fixture — dakle testira se mehanizam, ne rezultat.

Kvar 2 — motor traži tuđe šifre (#900023)

resolveAccount() pokušava tačnu šifru, pa prefiks. Trećeg pokušaja nema.

Za HR promašuju tačno dva od šest poziva:

poziv traži HR (CountryService)
InvoiceService:1985 prihod 6000 / 6% 7500
ExpenseService:659 trošak 5000 / 5% 4000/4100
InvoiceService:1982/2035 potraživanja 1200 / 12% 1200
InvoiceService:2032, ExpenseService:721 banka 1000 / 10% 1000
ExpenseService:662/718 obveze 2200 / 22% 2200

6000 je srpski/bosanski kontni plan. U hrvatskom RRiF-u razred 7 su prihodi — 75xx je ispravno. Motor je hardkodiran na tuđu jurisdikciju.


3. Nalaz koji mijenja popravku — tri nekompatibilna HR plana

U istoj bazi koda postoje tri HR kontna plana i međusobno se poriču:

izvor prihod trošak obveze konta
CountryService.kt CROATIAN_CHART_OF_ACCOUNTS 7500 4000/4100 2200 9
PluginHR.kt:272 getChartOfAccountsDefaults() 4000 5000/5100 2000 12
packages/core (TS) 41
V97__hr_rrif_chart_of_accounts.sql 90, hardkodirano na jedan demo UUID

Posljedica: koji god plan se seeda, nešto pukne — samo drugo.

  • CountryService plan → prihod i trošak padaju, obveze prolaze
  • PluginHR plan → prihod i obveze padaju, trošak prolazi

Zato fallback po tipu konta nije kozmetika nego nosivi dio popravke.

Otvoreno pitanje pod provjerom: PluginHR koristi AccountType.INCOME, a InvoiceService traži ACCOUNT_TYPE_REVENUE. Ako se ne mapiraju na isti account_type_id, fallback po tipu neće raditi ni kad je plan ispravno seedovan. Moguće da je to pravi korijen.


4. Arhitektonska ograda

BUILD-BLUEPRINT.md linija 447, doslovno:

Country plugins — Tax logic and chart-of-accounts defaults belong in packages/domain-*, not in API service code.

Prvi dispatch je pogrešno tražio popravku u CountryService.kt. Ispravljeno: izvor istine za kontni plan mora biti country plugin (packages/domain-hr), ne API servis.


5. Šta se radi

A. Treći fallback po TIPU konta u oba resolveAccount (InvoiceService.kt:1907, ExpenseService.kt:57) — kad ni tačna šifra ni prefiks ne pogode, uzeti najnižu šifru tog tipa za taj org.

B. Jedinstven izvor istine za HR kontni plan — odabrati koji je od tri ispravan po RRiF-u, ugasiti ostale, dati mu živog pozivaoca na JIT provisioning putu. Ne dodavati četvrti.

Izričito zabranjeno

Ubaciti konto 6000 u hrvatski plan da bi prošlo. Radilo bi danas, a knjige bi nosile pogrešnu šifru. Hrvatski prihod je 75xx i tako ostaje.

Testirati u oba smjera

  1. HR org s planom mora poslati račun i proknjižiti DR 1200 / CR 75xx
  2. RS/BA org mora i dalje razrješavati na 6000/5000 tačno kao prije — fallback se okida samo kad prva dva pokušaja vrate null
  3. Nov org kroz JIT provisioning mora dobiti kontni plan svoje zemlje

Verifikacija

Ishodom, ne zelenim buildom: stvaran račun kroz app.bilko.cloud iz HR orga do statusa SENT + red u transactions.


6. Kontekst

SMART FORGE d.o.o., OIB HR09582110234, org 65376c57-…, vlasnik [email protected]. Trenutno 0 računa / 0 kontakata / 0 konta.

Nema propuštenog roka: zakonska obaveza od 01.01.2026. je mogućnost primanja eRačuna, što je aktivirano i dokazano. Slanje se aktivira tek kad postoji račun za izdati.

Aktivacija eRačuna: MC #103443 · Evidence: ~/system/evidence/103443/