Bosanska lokalizacija Odoo: Modul l10n_ba_auto_reconcile 16.0.1.3.1 - Pravilo 0, preview lista, provjera integriteta


O čemu se radi?

Modul l10n_ba_auto_reconcile postoji da automatizuje zatvaranje otvorenih stavki glavne knjige po dva pravila:

  • Pravilo 1 — stavke na istom kontu i istom partneru čiji rezidualni saldo iznosi nula
  • Pravilo 2 — stavke u istoj klasi konta (prve dvije cifre) i istom partneru, gdje na nivou klase saldo iznosi nula, uz kreiranje preknjiženja između konta

Tokom dnevne upotrebe na produkcijskoj bazi naišli smo na klasu slučajeva koje pravila 1 i 2 nisu mogla zatvoriti — iako su stavke matematički bile uparene. Današnji update donosi Pravilo 0, preview listu, provjeru integriteta, i nekoliko bugfixova koji čine wizard pouzdaniji.

Verzije objavljene danas: 16.0.1.1.0 → 16.0.1.1.1 → 16.0.1.2.0 → 16.0.1.3.0 → 16.0.1.3.1.

Pravilo 0 — Finalizacija nezavršenih parcijalnih

Najveća promjena. U Odoo bazi smo zatekli desetine account_partial_reconcile redova kod kojih je full_reconcile_id bio prazan, iako su obje povezane stavke imale amount_residual = 0. Drugim riječima — uparivanje je matematički bilo završeno (parcijalni reconcile je potrošio kompletan saldo svih povezanih stavki), ali računovodstveni wrapper koji veže grupu — account.full.reconcile — nikad nije kreiran.

Zašto je to bilo nevidljivo

Odoo’s _compute_reconciled metod kalkuliše stored polje account.move.line.reconciled po pravilu:

if line.full_reconcile_id:
    line.reconciled = True
elif line.matched_debit_ids or line.matched_credit_ids:
    line.reconciled = float_is_zero(line.amount_residual, ...)

Drugi grananje znači: ako stavka ima parcijalni reconcile i rezidual = 0, Odoo je smatra zatvorenom — bez obzira na nedostatak full_reconcile_id. Posljedica: original wizard je filtrirao kandidate sa ('reconciled', '=', False) što je preskakalo upravo ovu klasu polu-zatvorenih stavki. One su godinama sjedile zaboravljene, blokiraju Open Items izvještaje i pojavljuju se kao “stara dugovanja” iako su zapravo plaćena.

Kako Pravilo 0 radi

Algoritam:

  1. SQL skenira sve account_partial_reconcile redove gdje je full_reconcile_id IS NULL, a obje linkovane account_move_line imaju amount_residual = 0 i takođe nemaju full_reconcile_id.
  2. Na grafu parcijalnih (čvor = stavka, ivica = parcijalni reconcile) se primjenjuje union-find algoritam za grupisanje povezanih komponenti.
  3. Za svaku komponentu (od po dvije ili više stavki) kreira se jedan account.full.reconcile red.
  4. Postojeći parcijalni i sve linkovane stavke dobijaju full_reconcile_id postavljen na novi wrapper.
@api.model
def _run_stale_partial_rule(self, results, dry_run=False):
    """Pravilo 0: finalizuje stale partial reconciliations."""
    cur = self.env.cr
    cur.execute("""
        SELECT pr.id, pr.debit_move_id, pr.credit_move_id, pr.max_date
        FROM account_partial_reconcile pr
        JOIN account_move_line dml ON dml.id = pr.debit_move_id
        JOIN account_move_line cml ON cml.id = pr.credit_move_id
        WHERE pr.full_reconcile_id IS NULL
          AND dml.amount_residual = 0
          AND cml.amount_residual = 0
          AND dml.full_reconcile_id IS NULL
          AND cml.full_reconcile_id IS NULL
    """)
    # ... union-find, create full_reconcile, link partials and lines ...

Operacija je idempotentna — ako pokrenete wizard ponovo, naredni put broji se 0 jer SQL filter više ne pronalazi kandidate.

Šta Pravilo 0 NE radi

  • Ne kreira nove parcijalne reconcile redove (postojeći su tačni).
  • Ne mijenja saldo nijednog konta.
  • Ne pravi nikakva knjiženja niti zaduženja.

To je čista metadata fix — popravljanje nedostajućih veza u bookkeeping sloju.

Preview lista — Stavke koje će biti zatvorene

Ranije je wizard nakon pokretanja prikazivao samo brojeve (npr. “Pravilo 1: zatvoreno 3 grupe, 6 stavki”). To nije dovoljno — operator nije mogao prije pokretanja vidjeti koje konkretno stavke će biti pogođene.

Sada wizard ima dva taba u rezultatu:

  • Stavke (preview) — readonly tree sa svim stavkama koje će biti pogođene, kolone:
    • Pravilo (0_stale, 1_same, 1_pair, 2_class, 2_cross, integrity_*)
    • Datum, Nalog, Konto, Partner
    • Duguje, Potražuje sa sumama na dnu liste
    • Rezidual
    • Razlog — slobodan tekst koji opisuje zašto je stavka pogođena
  • Tekstualni rezultat — postojeći sažetak po pravilima

Ovo omogućava potpunu provjeru u Samo prikaz modu prije nego što kliknete Pokreni stvarno. Lista se dinamički gradi tokom svakog pravila — svaka stavka koja prolazi kroz reconcile logiku se prijavi u results['preview'] kroz {rule, line_id, reason} zapis.

Pravilo 1 — Zaštita od “naked full_reconcile”

Tokom prvog testiranja Pravila 0 na produkciji desila se još jedna manjа anomalija: dvije stavke su dobile full_reconcile_id postavljen, ali bez ijednog account_partial_reconcile reda ispod njega. Odoo je tu grupu vidio kao “kreiranu”, ali bez podloge.

Uzrok: kada Pravilo 1 pozove aml.reconcile() na stavkama čiji je amount_residual = 0 već prije ulaska u poziv (npr. zato što ih je upravo finalizovalo Pravilo 0 u istom run-u), Odoo’s _reconcile_plan_execute u tom slučaju kreira account.full.reconcile ali ne kreira nikakav novi parcijalni — jer nema neutrošenog rezidualа za potrošiti.

Rezultat: gola full_reconcile, lista stavki ide u nju ali bookkeeping veza je nepotpuna. _compute_reconciled ne reaguje jer ne mijenja se nijedna od polja od kojih zavisi (matched_debit_ids, matched_credit_ids, amount_residual). Stavka ostaje vidljiva u Open Items.

Fix: Pravilo 1 sada filtrira na ulazu — odbacuje stavke sa amount_residual = 0. Takve stavke su ili stvarno zatvorene, ili u stale-partial stanju koje Pravilo 0 obrađuje. Pravilo 1 se ne miješa.

lines = self._get_unreconciled_lines().filtered(
    lambda l: abs(l.amount_residual) >= ROUNDING_PRECISION
)

Pored toga, Pravilo 0 sada eksplicitno upisuje reconciled=True zajedno sa full_reconcile_id, kako bi stored compute polje bilo konzistentno bez čekanja na re-trigger:

Line.browse(line_ids).write({
    'full_reconcile_id': full.id,
    'reconciled': True,
})

Provjera integriteta nakon svakog pokretanja

Najvažniji UX dodatak. Wizard nakon završetka pokretanja izvršava tri provjere bookkeeping invarijanti i prikazuje rezultat kao color-coded banner na vrhu forme.

Tri invarijante

  1. Saldo svake account.full.reconcile grupe = 0

    Suma balance polja svih stavki povezanih jednim full_reconcile_id mora biti 0. Ako nije, grupa je u pokvarenom stanju (npr. zaostala iz nekonzistentne transakcije).

  2. Nema “praznih grupa” (bez parcijalnih)

    Svaki account.full.reconcile red mora imati barem jedan account.partial.reconcile koji ga referencira. Ako nema — to je upravo “naked full_reconcile” anomalija opisana iznad.

  3. Nema nezavršenih parcijalnih

    Nakon Pravila 0, ne smije ostati ni jedan account_partial_reconcile sa full_reconcile_id IS NULL čije obje stavke imaju rezidual = 0.

Kada sve tri provjere prođu — zelena alert traka na vrhu forme:

✓ Integritet OK: Sve provjere integriteta su prošle — 1223 zatvorenih
grupa, saldo=0 svuda, nema praznih grupa (bez parcijalnih), nema
nezavršenih parcijalnih.

Kada nešto nije u redu — crvena alert traka sa specifičnim brojkama:

⚠ Integritet problem: 3 grupa sa saldom različitim od 0;
1 praznih grupa (bez parcijalnih)

Ispod, u Stavke (preview) tabu, pojavljuju se konkretne stavke u problematičnim grupama, sa rule oznakom integrity_broken ili integrity_naked da operator može odmah otići do njih.

Vrijednost

Provjera integriteta je continuous health check — pokreće se nakon svakog Pokreni, čak i ako nijedno pravilo nije pronašlo kandidate. Rana detekcija anomalija u account_full_reconcile / account_partial_reconcile sloju je daleko jeftinija nego forenzički ispravljati ih nakon mjeseci.

Bosanske oznake

Ranije verzije su koristile direktne engleske termine u izvještaju (“naked full_reconcile”, “stale partials”). Sada wizard u potpunosti komunicira na bosanskom:

Engleski (16.0.1.2.0)Bosanski (16.0.1.3.1)
naked full_reconcileprazne grupe (bez parcijalnih)
stale partialsnezavršeni parcijalni
saldo != 0saldo različit od 0
ReconciledZatvoreno

Operator i računovodstvo dobijaju lokaliziranu poruku — manje frikcije pri svakodnevnom korištenju.

Verzija i deploy

PoljeVrijednost
Modull10n_ba_auto_reconcile
Verzija16.0.1.3.1 (sa 16.0.1.0.0)
Odoo serija16.0
Zavisi odaccount
LicencaAGPL-3
Repogithub.com/bringout/odoo-bringout-l10n_ba_auto_reconcile

Migracija nije potrebna — postojeći podaci se ne diraju automatski. Kada operator prvi put pokrene wizard nakon update-a, Pravilo 0 će obraditi sve nakupljene stale-partial slučajeve (kod nas je to bilo 31 grupa, 67 stavki, 36 parcijalnih).

Kratki zaključci za druge timove

  1. Računajte na to da Odoo’s reconciled flag nije pouzdana mjera zatvorenosti stavke. Za heath-check upite radije provjeravajte direktno full_reconcile_id IS NOT NULL ili balansirajte sumiranje po account_full_reconcile grupama.

  2. Direktni full_reconcile_id upis kroz ORM ne uvijek povlači re-compute stored polja koja od njega zavise. Eksplicitno upisivanje reconciled=True u istom write-u je sigurnije.

  3. Preview lista u svakom batch-tipu wizardu štedi sate analize. Ako vaš modul mijenja desetinu redova — neka operator vidi koje, prije nego što klikne Apply.

  4. Continuous integrity checks su jeftine kada su izražene kao dva-tri SQL upita. Za GL provjeru: SUM(balance) per full_reconcile_id, plus orphan / dangling detekcija. Stavite ih iza svakog batch operatora.

Napomena

Generisano od strane Claude 🤖


Ernad Husremović, hernad@bring.out.ba