Preskoči na sadržaj

Odoo 19 Community: Spajanje nacrta računa – naš open source modul Merge Draft Invoices

18. septembar 2026. by
Odoo 19 Community: Spajanje nacrta računa – naš open source modul Merge Draft Invoices
Alexander Biringer | Biricon IT Services GmbH

Ko u Odoou fakturiše iz narudžbi, Helpdesk tiketa i evidencije vremena, poznaje rezultat: kupac na kraju mjeseca ne dobije jedan račun, nego pet. Svaki potiče iz druge narudžbe ili tiketa, svaki je stručno ispravan – a ipak kupac pita ne bi li sve stalo na jedan dokument.

Upravo za to u Odoo 19 Community ne postoji čisto rješenje. Poznati OCA modul account_invoice_merge još nije objavljen za Odoo 19, a problem rješava na način koji za pružaoce usluga predstavlja ozbiljan rizik: iste stavke se objedinjuju, čime se gubi veza nazad prema narudžbi, zadatku i evidentiranom vremenu.

Za našu vlastitu Odoo 19 Community instalaciju zato smo razvili modul Merge Draft Invoices. Budući da ovaj problem ne pogađa samo nas, besplatno ga stavljamo na raspolaganje na GitHubu pod slobodnom AGPL-3 licencom.

Na projekt na GitHubu:

Odoo 19 Merge Draft Invoices

Zašto vlastiti modul umjesto OCA rješenja?

OCA već dugi niz godina održava account_invoice_merge u repozitoriju OCA/account-invoicing. U trenutku pisanja ovog članka migracija na 19.0 tamo je još otvoren Pull Request, a ne objavljen modul.

Važnije je, međutim, da ova dva modula rade različite stvari:


OCA account_invoice_mergeMerge Draft Invoices
Rezultatspaja se u jedan od odabranih računauvijek novi račun
Stavkeiste stavke se objedinjuju, količine se zbrajajusvaka stavka se preuzima jedan prema jedan
Porijekloinvoice_origin / payment_reference spojeni u zaglavljupolja porijekla po stavci kopiraju se putem Odoo vlastitog hooka _copy_data_extend_business_fields
Evidencija vremenanije uzeta u obzirtimesheet_invoice_id se prebacuje na novi račun
Čitljivo za kupcaništanaslov iznad stavki svakog izvora s narudžbom i tiketom
Izvorni računise stornirajustornirati (standardno), obrisati ili zadržati – s jasno imenovanim posljedicama

Objedinjavanje istih stavki je presudna razlika. Objedinjena stavka može imati samo jedno porijeklo. Čim dva reda iz dvije različite narudžbe izgledaju isto, veza od računa nazad prema narudžbi, zadatku i knjiženju vremena je izgubljena. U uslužnom preduzeću u kojem se obračun odvija preko Tiket → Evidencija vremena → Račun to znači: iste se sate fakturiše dvaput ili nestaju.

Naš modul zato u principu ništa ne objedinjuje. Spojeni račun ima tačno onoliko stavki koliko ih imaju svi izvori zajedno.

Nije preuzet nikakav kod iz OCA modula. Oba modula su pod AGPL-3.

Šta modul radi

U prikazu liste računa označiti dva ili više nacrta, u meniju akcija odabrati Spoji nacrte računa – čarobnjak prikazuje odabir, provjere i opcije za izvorne račune. Nakon potvrde odmah se dospijeva na novi račun.

Prije spajanja modul provjerava, i to sve tačke odjednom, kako se nakon svake ispravke ne bi vidjela sljedeća greška:

  • odabrana najmanje dva računa
  • svi u statusu Nacrt
  • nijedan nikada nije proknjižen (dokument vraćen na nacrt zadržava svoju historiju knjiženja i odbija se)
  • nijedan nije već spojen
  • svi su račun, račun dobavljača, odobrenje ili dokument – nikako čisti nalozi za knjiženje
  • isti partner, tip dokumenta, preduzeće, valuta i žurnal

Razlike u uvjetima plaćanja, poreznom mapiranju, adresi isporuke, bankovnom računu ili prodavaču ne blokiraju. Čarobnjak upozorava i preuzima vrijednost najstarijeg odabranog računa.

Šta ostaje sačuvano

Srž modula je da svaka veza koju stavka računa ima prema svom porijeklu postoji i na novom računu:

VezaPostupanje
Stavke prodajne narudžbe (sale_line_ids)kopiraju se po stavci putem Odoo _copy_data_extend_business_fields
Stavke nabavne narudžbe (purchase_line_id)isto tako
Raspodjela po troškovnim mjestima (analytic_distribution)kopira se po stavci
druga polja porijekla po stavciautomatski, ako modul koji ih isporučuje implementira dokumentirani Odoo hook
Porijeklo i referenca u zaglavlju računaspojeno, deduplicirano, može se uređivati u čarobnjaku
Prodajna narudžba: invoice_ids, invoice_status, qty_invoicedizračunavaju se iz stavki – narudžba sama prepoznaje novi račun
Evidencija vremena (timesheet_invoice_id)prebacuje se na novi račun prije nego izvori postanu nevažeći
Helpdesk tiketvezan je za evidenciju vremena i tako automatski pokazuje na novi račun
Chatterporuka na novom računu sa svim izvorima, poruka na svakom izvoru s linkom na novi
merged_into_move_id / merged_from_move_idspohranjena veza u oba smjera

Redovi poreza, redovi uvjeta plaćanja, redovi zaokruživanja i skonta ne kopiraju se, nego ih Odoo iznova izračunava iz sadržaja. Spojeni račun tako ima jedan red poreza po poreznoj stopi, a ne jedan po izvoru. Izrađuje se nenumerirano kao nacrt; samo spajanje ne troši broj dokumenta.

Naslovi: Kupac vidi odakle potiče svaka stavka

Ovo je funkcija koja u svakodnevnom radu pravi razliku. Iznad stavki svakog izvornog računa modul postavlja red odjeljka – isti element koji i sam Odoo koristi za odjeljak „Avansna plaćanja“:

BE10181                                     <- Naslov
  22,500 x Sat tehničara          3.577,50
                    Međuzbir      3.577,50
BE10182 · Tiket: HT00219                    <- Naslov
   3,000 x Sat tehničara            477,00
                    Međuzbir        477,00
                      NETO IZNOS  4.054,50

Naslov se štampa na dokumentu koji kupac dobija, a Odoo standardni izvještaj o računu sam dodaje međuzbir po odjeljku. Kupac tako vidi i koliko je koji dio koštao.

Natpis se sastavlja iz onoga što izvor zaista ima:

  1. narudžbe, izravno iz veza stavki – imena su tako tačna; ako nema veza s narudžbama, koristi se slobodni tekst iz invoice_origin
  2. tiketi, utvrđeni putem evidencije vremena – ispisani kao Tiket: HT00219 ili Tiketi: …, ograničeno na pet plus „i još N“
  3. ako nema ni jednog ni drugog: broj izvornog računa, zatim njegova referenca
  4. ako nema ničega: neutralno „Dodatne stavke“, kako redovi jednog izvora nikada ne bi neprimjetno nestali u bloku iznad

Ono što nedostaje se izostavlja, ne izmišlja. Tiket se štampa s vlastitim brojem – helpdesk_mgmt broj, Enterprise ticket_ref ili prikazano ime modela – nikada s ID-om baze podataka.

Naslovi se pišu na jeziku kupca, onako kako to Odoo radi pri izradi računa iz narudžbi. Chatter ostaje na jeziku korisnika.

Naslov ne nosi proizvod, količinu, cijenu, porez, konto niti raspodjelu po troškovnim mjestima. Ne može utjecati na zbirove, poreznu osnovicu i obračun troškova. Ko isključi naslove u čarobnjaku, dobija tačno onaj račun koji bi nastao bez ove funkcije – test uspoređuje oba rezultata do centa.

Šta se događa s izvornim računima

Čarobnjak nudi tri opcije:

  • Stornirati (standardno, preporučeno). Storniranje nacrta je bez posljedica: nema broja dokumenta, nema knjiženja. Računi ostaju u bazi podataka kao stornirani dokumenti s chatterom i linkom na novi račun. qty_invoiced na prodajnoj narudžbi preskače stornirane dokumente, ništa se ne računa dvaput. To je opcija koja je razumljiva i nakon šest mjeseci.
  • Obrisati. Nepovratno. Chatter i povratna referenca nestaju sa zapisom; ostaje samo poruka na novom računu. Smisleno za nacrte za bacanje koje niko više ne treba vidjeti.
  • Ostaviti kao nacrt. Izvori ostaju otvoreni. Njihove prodajne narudžbe tada broje izvor i novi račun kao fakturisane – rad izgleda dvaput obračunat dok neko ručno ne očisti nacrte. Namijenjeno rijetkom slučaju kada se prije odluke želi uporediti. Test bilježi upravo to dvostruko brojanje kako nikoga ne bi iznenadilo.

Granice – šta modul namjerno ne radi

Molimo pročitati prije produktivne upotrebe:

  • Samo nacrti. Proknjiženi računi se ne spajaju. To je zadatak za odobrenja, a ne postupak kopiranja.
  • Jednom proknjiženi, vraćeni nacrti se odbijaju. Imaju broj i historiju knjiženja; skrivanje toga u drugom dokumentu nije nešto što bi zbirna akcija trebala tiho obaviti.
  • Nema spajanja preko partnera, valuta, preduzeća ili žurnala. Za to ne postoji smislena pojedinačna vrijednost, pa modul odbija, umjesto da pogađa.
  • payment_reference se ne preuzima. Strukturirane reference plaćanja identificiraju dokument; dvije spojene ne odgovaraju ničemu u banci. Novi račun dobija vlastitu pri knjiženju.
  • Stavke avansnih plaćanja kopiraju se kao i svaka druga stavka. Ako izvori sadrže redove avansa iz modula sale, rezultat treba provjeriti prije knjiženja.
  • Samo timesheet_invoice_id se automatski prebacuje. Svaki drugi model s Many2one poljem na account.move (vlastiti obračunski prolazi, veze s pretplatama, EDI slanja) i dalje pokazuje na izvor. Za to postoji hook _merge_draft_relink.
  • Nema objedinjavanja istih stavki – namjerno. Ko želi kratak, uredan račun, ovdje je na pogrešnom mjestu i za to bi platio vezama porijekla.
  • Naslovi nastaju jednokratno pri spajanju. Poslije su to obični redovi odjeljaka: mogu se uređivati, brisati i ne ažuriraju se ako se narudžba ili tiket kasnije preimenuju.
  • Naslov navodi tikete cijelog izvornog računa, a ne pojedine stavke.

Instalacija u Odoo 19 Community

Instalacija se vrši kao i kod uobičajenog dodatnog Odoo modula:

  1. Kopirati direktorij modula u konfigurirani addons putanju.
  2. Ažurirati listu aplikacija u Odoou.
  3. Instalirati modul account_invoice_merge_draft.

Modul zavisi samo od modula account. Sve što zna o modulima sale, purchase, project, hr_timesheet, sale_timesheet ili nekom Helpdesk modulu utvrđuje se tokom rada – instalira se i funkcionira i na čistoj bazi za obračun.

Zatim: Računovodstvo → Kupci → Računi (ili Dobavljači → Računi), označiti dva ili više nacrta, meni sa zupčanikom → Spoji nacrte računa. Akcija je dostupna svim korisnicima s grupom Obračun / Fakturisanje.

Ko ažurira sa ranije verzije modula, trebao bi jednokratno ažurirati pomoću -u account_invoice_merge_draft --i18n-overwrite, kako bi izmijenjeni nazivi polja stigli u njemački prijevod. Nova instalacija time nije pogođena.

Za programere: API i hookovi

Spajanje se može pozvati i iz vlastitog koda:

python

merged = draft_moves.merge_draft_moves(
    extra_vals={"invoice_date": date(2026, 3, 31), "ref": "Q1"},
    source_handling="cancel",   # "delete" ili "keep"
    add_source_sections=True,   # Naslovi; standardno True
)

merge_draft_moves baca UserError sa svim razlozima odbijanja ako se odabir ne može spojiti. _merge_draft_get_errors() vraća iste razloge kao listu bez izuzetka.

Ko ima vlastite povratne reference na account.move, nadjačava _merge_draft_relink:

python

class AccountMove(models.Model):
    _inherit = "account.move"

    def _merge_draft_relink(self, new_move):
        super()._merge_draft_relink(new_move)
        if "my_move_id" not in self.env["my.model"]._fields:
            return
        self.env["my.model"].search([("my_move_id", "in", self.ids)]).write(
            {"my_move_id": new_move.id}
        )

Ko ima povratnu referencu na stavci računa, ovaj modul uopće ne treba: dovoljan je Odoo vlastiti hook account.move.line._copy_data_extend_business_fields, a polje se jednako preuzima pri spajanju, storniranju i dupliciranju. Za druge Helpdesk module ili drugačiju formulaciju naslova postoje _merge_draft_get_source_tickets() i _merge_draft_section_name().

Testirano prije nego što se pokrene na produktivnim podacima

48 testova pokriva miješane statuse, različite partnere, valute i tipove dokumenata, stavke s prodajnom ili nabavnom narudžbom i bez njih, poreze, odjeljke i napomene, raspodjele po troškovnim mjestima, prebacivanje evidencije vremena, sve tri opcije za izvorne račune, čarobnjak i naslove – da su standardno aktivni, da njihovo isključivanje reproducira stari rezultat do centa, da naslov ne nosi iznose ni konta, da stavke jednog izvora ostaju zajedno, da se tiket pojavljuje sa svojim brojem, a nikada s ID-om baze podataka.

Testni podaci grade se na postojećem kontnom planu aktivne firme umjesto na AccountTestInvoicingCommon – taj helper se na migriranim produktivnim bazama često ne pokreće, a upravo na takvima modul treba raditi.

odoo-bin -d <db> -u account_invoice_merge_draft --test-enable \
         --test-tags /account_invoice_merge_draft --stop-after-init

Kao i kod svakog proširenja u računovodstvenom području, preporučujemo da se instalacija najprije provjeri u testnom okruženju s kopijom vlastite baze podataka.

Besplatno i open source za Odoo Community

Mi u Biricon IT Services GmbH rješenja prvo razvijamo za konkretne zahtjeve iz vlastitog poslovanja. Ako iz toga nastane modul opće upotrebljivosti, ne želimo ga sakriti u jednoj instalaciji.

Merge Draft Invoices zato je besplatno dostupan kao open source projekt. Izvorni kod se može pregledati, provjeriti, prilagoditi i dalje razvijati u okviru AGPL-3 licence.

Naš cilj nije bio najkraći mogući račun, nego račun kod kojeg i za godinu dana svaka stavka vodi nazad do svoje narudžbe, svog tiketa i svog knjiženja vremena.

Projekt, izvorni kod i saradnja

Potpuni izvorni kod, napomene o instalaciji i tehnička dokumentacija dostupni su na GitHubu:

Otvoriti Odoo 19 Merge Draft Invoices na GitHubu

Radujemo se iskustvima iz prakse, izvještajima o greškama, prijedlozima za poboljšanje i doprinosima iz Odoo Community.

Besplatno. Razumljivo. Open source. Za Odoo 19 Community.