Bosanska lokalizacija "Odoo" open-source platforme: portiranje fiskalnog i modula za obračun PDV-a na verziju 19 (l10n_ba_edi, l10n_ba_pdv v16 => v19)
Portiranje bosanskohercegovačke lokalizacije na Odoo 19 je značajan korak naprijed. Moduli l10n_ba_edi (fiskalizacija) i l10n_ba_pdv (obračun PDV-a) su uspješno portirani sa verzije 16 na verziju 19.
Kontni plan
Bosanski kontni plan na Odoo 19 sa 494 konta:

Porezne stope
Konfigurisane porezne stope za PDV (17%, 0%) sa oznakama za različite vrste prometa - prodaja, nabavke, carinske oznake (C15, C24-25, C27, CXX), kompenzacije (KP), avansi:

Fiskalizacija (l10n_ba_edi)
Podešavanje fiskalnog servera
Modul l10n_ba_edi omogućava povezivanje sa EDI serverom za fiskalizaciju. Podešavanja uključuju parametre EDI servera (host URL, API key, PIN), vrstu fiskalnog sistema (OFS - Republika Srpska, FPrint - Federacija), te izbor fiskalnog režima - VP (Veleprodaja - Wholesale) ili MP (Maloprodaja - Retail):

Podešavanje dnevnika za EDI
Na dnevniku prodaje se aktivira opcija “Electronic Invoicing” sa provajderom “Fiskalizacija (BA)”:

Faktura sa fiskalnim statusom
Primjer proknjižene fakture IF/2026/00001 sa EDI statusom i dugmetom “RETRY EDI” za ponovni pokušaj slanja na fiskalni server:

Obračun PDV-a (l10n_ba_pdv)
PDV obračun wizard
Modul l10n_ba_pdv omogućava generisanje PDV obračuna za odabrani period. Wizard podržava generisanje XLSX izvještaja te CSV fajlova za enabavke i eisporuke:

PDV CSV izvještaj - eisporuke
Generisani CSV sa podacima o eisporukama, uključujući poreski period, redni broj, datum fakture, broj fakture, podatke o kupcu, iznose sa i bez PDV-a:

Odoo 19 core bugfix: QwebJSON circular reference
Tokom portiranja na Odoo 19 otkriven je latentni bug u Odoo 19 core-u koji se manifestuje kao ValueError: Circular reference detected prilikom učitavanja web klijenta.
Problem
QWeb template web.webclient_bootstrap pada sa greškom na liniji:
<t t-out="json.dumps(session_info)"/>
Uzrok
Klasa QwebJSON u odoo/addons/base/models/ir_qweb.py ima default handler koji vraća neserijalizabilne objekte nepromijenjene:
# Originalni (pokvareni) kod
class QwebJSON(json.JSON):
def dumps(self, *args, **kwargs):
prev_default = kwargs.pop('default', lambda obj: obj)
return super().dumps(*args, **kwargs, default=(
lambda obj: prev_default(str(obj) if isinstance(obj, QwebContent) else obj)
))
Kada JSON encoder naiđe na neserijalizabilan tip (ReadonlyDict, lazy, datetime, bytes, Domain), poziva default handler. Handler vraća objekat nepromijenjen (jer nije QwebContent). Encoder ponovo pokuša serijalizaciju, dobije isti objekat nazad i prijavi “Circular reference detected.”
U vanilla Odoo-u se rijetko manifestuje jer su session_info vrijednosti tipično JSON-serijalizabilne. Međutim, svaki modul (OCA ili custom) koji unese neserijalizabilan tip u session_info ili bilo koji drugi QWeb JSON kontekst će izazvati ovaj bug.
Ispravka
Koristiti odoo.tools.json.json_default() kao fallback za objekte koji nisu QwebContent:
# Ispravljen kod
class QwebJSON(json.JSON):
def dumps(self, *args, **kwargs):
prev_default = kwargs.pop('default', lambda obj: obj)
return super().dumps(*args, **kwargs, default=(
lambda obj: prev_default(str(obj) if isinstance(obj, QwebContent) else json.json_default(obj))
))
Funkcija json_default() (iz odoo/tools/json.py) pravilno obrađuje: datetime, date, lazy, ReadonlyDict, bytes, Domain i ostale tipove.
Detalji ispravke: QWEBJSON_CIRCULAR_REFERENCE.md
Napomena
Većinu sadržaja ovog članka je napisao 🤖 Claude
Prethodni blog postovi o bosanskoj lokalizaciji: