Skip to Content

Odoo 19 Community: Zlúčenie konceptov faktúr – náš open source modul Merge Draft Invoices

18. septembra 2026 pomocou
Odoo 19 Community: Zlúčenie konceptov faktúr – náš open source modul Merge Draft Invoices
Alexander Biringer | Biricon IT Services GmbH

Kto v Odoo fakturuje zo zákaziek, tiketov helpdesku a evidencie času, pozná výsledok: Zákazník na konci mesiaca nedostane jednu faktúru, ale päť. Každá pochádza z inej zákazky alebo tiketu, každá je vecne správna – a napriek tomu sa zákazník pýta, či by sa to nedalo zmestiť do jedného dokladu.

Práve na to neexistuje v Odoo 19 Community čisté riešenie. Známy modul OCA account_invoice_merge zatiaľ nie je pre Odoo 19 uvoľnený a rieši problém spôsobom, ktorý pre poskytovateľov služieb predstavuje vážne riziko: Rovnaké položky sa zlúčia a tým sa stratí väzba späť na zákazku, úlohu a zaevidovaný čas.

Pre našu vlastnú inštaláciu Odoo 19 Community sme preto vyvinuli modul Merge Draft Invoices. Keďže tento problém netrápi len nás, poskytujeme ho bezplatne na GitHube pod slobodnou licenciou AGPL-3.

Prejsť na projekt na GitHube:

Odoo 19 Merge Draft Invoices

Prečo vlastný modul namiesto riešenia OCA?

OCA už mnoho rokov udržiava account_invoice_merge v repozitári OCA/account-invoicing. V čase vzniku tohto príspevku je migrácia na 19.0 tam stále otvoreným pull requestom, nie zverejneným modulom.

Dôležitejšie však je, že oba moduly robia odlišné veci:


OCA account_invoice_mergeMerge Draft Invoices
Výsledokzlúči sa do jednej z vybraných faktúrvždy nová faktúra
Položkyrovnaké položky sa zlúčia, množstvá sa sčítajúkaždá položka sa prevezme jedna k jednej
Pôvodinvoice_origin / payment_reference sa v hlavičke spojapolia pôvodu sa pre každú položku skopírujú cez vlastný hook Odoo _copy_data_extend_business_fields
Evidencia časunezohľadňuje satimesheet_invoice_id sa prepojí na novú faktúru
Čitateľné pre zákazníkaničnadpis nad položkami každého zdroja so zákazkou a tiketom
Zdrojové faktúrysa stornujústornovať (štandard), zmazať alebo ponechať – s jasne pomenovanými dôsledkami

Zlučovanie rovnakých položiek je rozhodujúci rozdiel. Zlúčená položka môže mať len jeden pôvod. Hneď ako dva riadky z dvoch rôznych zákaziek vyzerajú rovnako, je väzba od faktúry späť na zákazku, úlohu a časový záznam preč. V prevádzke poskytovateľa služieb, kde fakturácia prebieha cez tiket → evidencia času → faktúra, to znamená: Tie isté hodiny sa buď fakturujú dvakrát, alebo zmiznú.

Náš modul preto v zásade nič nezlučuje. Zlúčená faktúra má presne toľko položiek, koľko majú jej zdroje spolu.

Z modulu OCA sa neprevzal žiadny kód. Oba moduly sú pod AGPL-3.

Čo modul robí

V zobrazení zoznamu faktúr označiť dva alebo viac konceptov, v menu akcií zvoliť Zlúčiť koncepty faktúr – sprievodca zobrazí výber, kontroly a možnosti pre zdrojové faktúry. Po potvrdení sa používateľ ocitne priamo na novej faktúre.

Pred zlúčením modul kontroluje, a to všetky body naraz, aby človek po každej oprave nevidel ďalšiu chybu:

  • vybrané aspoň dve faktúry
  • všetky v stave Koncept
  • žiadna nebola nikdy zaúčtovaná (doklad vrátený do konceptu si ponecháva históriu zaúčtovania a je zamietnutý)
  • žiadna nebola už zlúčená
  • všetky sú faktúra, dodávateľská faktúra, dobropis alebo doklad – nie čisto účtovné zápisy
  • rovnaký partner, typ dokladu, spoločnosť, mena a denník

Rozdiely v platobných podmienkach, daňovom zaradení, dodacej adrese, bankovom účte alebo predajcovi neblokujú. Sprievodca upozorní a prevezme hodnotu z najstaršej vybranej faktúry.

Čo sa zachová

Jadrom modulu je, že každá väzba, ktorú má položka faktúry na svoj pôvod, existuje aj na novej faktúre:

PrepojenieSpracovanie
Položky predajnej objednávky (sale_line_ids)pre každú položku skopírované cez _copy_data_extend_business_fields z Odoo
Položky nákupnej objednávky (purchase_line_id)rovnako
Rozdelenie nákladových stredísk (analytic_distribution)skopírované pre každú položku
ďalšie polia pôvodu pri jednotlivých položkáchautomaticky, ak dodávajúci modul implementuje zdokumentovaný hook Odoo
Pôvod a referencia v hlavičke faktúryzlúčené, deduplikované, upraviteľné v sprievodcovi
Predajná objednávka: invoice_ids, invoice_status, qty_invoicedvypočítajú sa z položiek – objednávka novú faktúru rozpozná sama
Evidencia času (timesheet_invoice_id)prepojí sa na novú faktúru skôr, než zdroje prestanú platiť
Tiket helpdeskuje naviazaný na evidenciu času a tým automaticky odkazuje na novú faktúru
Chatterspráva na novej faktúre so všetkými zdrojmi, správa na každom zdroji s odkazom na novú
merged_into_move_id / merged_from_move_idsuložené prepojenie v oboch smeroch

Daňové riadky, riadky platobných podmienok, riadky zaokrúhlenia a zliav za skoré zaplatenie sa nekopírujú, ale Odoo ich prepočíta nanovo z obsahu. Zlúčená faktúra má teda jeden daňový riadok na sadzbu dane, nie jeden na zdroj. Vytvorí sa bez čísla ako koncept; samotné zlúčenie nespotrebuje žiadne číslo dokladu.

Nadpisy: Zákazník vidí, odkiaľ každá položka pochádza

Toto je funkcia, ktorá robí v každodennej praxi rozdiel. Nad položkami každej zdrojovej faktúry vloží modul riadok sekcie – ten istý prvok, ktorý Odoo samo používa pre sekciu „Zálohy“:

BE10181                                     <- nadpis
  22,500 x Hodina technika        3.577,50
                    Medzisúčet    3.577,50
BE10182 · Tiket: HT00219                    <- nadpis
   3,000 x Hodina technika          477,00
                    Medzisúčet      477,00
                     ČISTÁ SUMA   4.054,50

Nadpis sa vytlačí na doklade, ktorý zákazník dostane, a štandardná správa faktúry Odoo sama doplní medzisúčet za každú sekciu. Zákazník tak vidí aj to, koľko stála každá časť.

Popis sa zostavuje z toho, čo zdroj skutočne má:

  1. zákazky, priamo z prepojení položiek – názvy sú tak presné; ak chýbajú prepojenia na zákazky, použije sa voľný text z invoice_origin
  2. tikety, zistené cez evidenciu času – uvedené ako Tiket: HT00219 alebo Tikety: …, obmedzené na päť plus „a N ďalších“
  3. ak neexistuje ani jedno: číslo zdrojovej faktúry, potom jej referencia
  4. ak neexistuje vôbec nič: neutrálne „Ďalšie položky“, aby riadky zdroja nikdy potichu nezmizli v bloku nad nimi

Čo chýba, sa vynechá, nevymyslí sa. Tiket sa vytlačí s vlastným číslom – číslo helpdesk_mgmt, ticket_ref z Enterprise alebo zobrazovaný názov modelu – nikdy nie s ID z databázy.

Nadpisy sa píšu v jazyku zákazníka, tak ako to robí Odoo pri vytváraní faktúr zo zákaziek. Chatter zostáva v jazyku používateľa.

Nadpis nenesie žiadny produkt, množstvo, cenu, daň, účet ani rozdelenie nákladových stredísk. Nemôže ovplyvniť súčty, základ dane ani nákladové účtovníctvo. Kto nadpisy v sprievodcovi vypne, dostane presne takú faktúru, aká by vznikla bez tejto funkcie – test porovnáva oba výsledky s presnosťou na cent.

Čo sa stane so zdrojovými faktúrami

Sprievodca ponúka tri možnosti:

  • Stornovať (štandard, odporúčané). Stornovanie konceptu je bez následkov: žiadne číslo dokladu, žiadne zaúčtovanie. Faktúry zostanú v databáze ako stornované doklady s chatterom a odkazom na novú faktúru. qty_invoiced pri predajnej objednávke stornované doklady preskakuje, nič sa nezapočíta dvakrát. Je to možnosť, ktorá je dohľadateľná aj o šesť mesiacov.
  • Zmazať. Nenávratne. Chatter a spätný odkaz zaniknú spolu so záznamom; zostane len správa na novej faktúre. Zmysluplné pre jednorazové koncepty, ktoré už nikto nemá vidieť.
  • Ponechať ako koncept. Zdroje zostanú otvorené. Ich predajné objednávky potom počítajú zdroj aj novú faktúru ako vyfakturované – práca vyzerá ako dvakrát vyúčtovaná, kým niekto koncepty ručne nevyčistí. Určené pre zriedkavý prípad, keď chce človek pred rozhodnutím porovnávať. Test zachytáva práve toto dvojité započítanie, aby nikoho neprekvapilo.

Hranice – čo modul zámerne nerobí

Prosím, prečítajte si pred produkčným nasadením:

  • Len koncepty. Zaúčtované faktúry sa nezlučujú. To je úloha pre dobropisy, nie kopírovací proces.
  • Raz zaúčtované, vrátené koncepty sa zamietajú. Majú číslo a históriu zaúčtovania; schovať to v inom doklade nie je vec, ktorú by mala potichu vybaviť hromadná akcia.
  • Žiadne zlučovanie cez partnerov, meny, spoločnosti alebo denníky. Na to neexistuje zmysluplná jednotlivá hodnota, preto modul odmietne namiesto toho, aby hádal.
  • payment_reference sa neprevezme. Štruktúrované platobné referencie identifikujú doklad; dve spojené nezodpovedajú v banke ničomu. Nová faktúra dostane pri zaúčtovaní vlastnú.
  • Položky záloh sa kopírujú ako každá iná položka. Ak zdroje obsahujú riadky záloh zo sale, treba výsledok pred zaúčtovaním skontrolovať.
  • Automaticky sa prepája iba timesheet_invoice_id. Každý ďalší model s Many2one na account.move (vlastné fakturačné behy, prepojenia predplatného, odoslania EDI) naďalej ukazuje na zdroj. Na to slúži hook _merge_draft_relink.
  • Žiadne zlučovanie rovnakých položiek – zámerne. Kto chce krátku, upratanú faktúru, je tu na zlej adrese a zaplatil by za to väzbami na pôvod.
  • Nadpisy vznikajú jednorazovo pri zlúčení. Potom sú to bežné riadky sekcií: upraviteľné, zmazateľné a neaktualizujú sa, ak sa zákazka alebo tiket neskôr premenuje.
  • Nadpis uvádza tikety celej zdrojovej faktúry, nie jednotlivej položky.

Inštalácia v Odoo 19 Community

Inštalácia prebieha ako pri bežnom doplnkovom module Odoo:

  1. Skopírovať adresár modulu do nakonfigurovanej cesty addonov.
  2. Aktualizovať zoznam aplikácií v Odoo.
  3. Nainštalovať modul account_invoice_merge_draft.

Modul závisí len od account. Všetko, čo vie o sale, purchase, project, hr_timesheet, sale_timesheet alebo module helpdesku, sa zisťuje za behu – inštaluje sa a funguje aj na čisto fakturačnej databáze.

Potom: Účtovníctvo → Zákazníci → Faktúry (alebo Dodávatelia → Faktúry), označiť dva alebo viac konceptov, menu ozubeného kolesa → Zlúčiť koncepty faktúr. Akcia je k dispozícii všetkým používateľom so skupinou Vyúčtovanie / Fakturácia.

Kto aktualizuje z predchádzajúcej verzie modulu, mal by jednorazovo aktualizovať pomocou -u account_invoice_merge_draft --i18n-overwrite, aby sa zmenené označenia polí dostali do nemeckého prekladu. Nová inštalácia sa to netýka.

Pre vývojárov: API a hooky

Zlúčenie možno vyvolať aj z vlastného kódu:

python

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

merge_draft_moves vyhodí UserError so všetkými dôvodmi zamietnutia, ak sa výber nedá zlúčiť. _merge_draft_get_errors() vráti rovnaké dôvody ako zoznam bez výnimky.

Kto má vlastné spätné odkazy na account.move, prepíše _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}
        )

Kto má spätný odkaz na položke faktúry, tento modul vôbec nepotrebuje: stačí vlastný hook Odoo account.move.line._copy_data_extend_business_fields a pole sa prevezme rovnako pri zlúčení, pri storne aj pri duplikovaní. Pre iné moduly helpdesku alebo inú formuláciu nadpisov existujú _merge_draft_get_source_tickets() a _merge_draft_section_name().

Otestované ešte predtým, než beží na produkčných údajoch

48 testov pokrýva zmiešané stavy, rôznych partnerov, meny a typy dokladov, položky s predajnou či nákupnou objednávkou aj bez nej, dane, sekcie a poznámky, rozdelenia nákladových stredísk, prepojenie evidencie času, všetky tri možnosti pre zdrojové faktúry, sprievodcu a nadpisy – že sú predvolene aktívne, že ich vypnutie reprodukuje starý výsledok s presnosťou na cent, že nadpis nenesie sumy ani účty, že položky jedného zdroja zostanú spolu, že sa tiket zobrazuje so svojím číslom a nikdy s ID z databázy.

Testovacie údaje stavajú na existujúcej účtovej osnove aktívnej firmy namiesto na AccountTestInvoicingCommon – tento helper sa na migrovaných produkčných databázach často nespustí, a práve na takých má modul bežať.

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

Ako pri každom rozšírení v oblasti účtovníctva odporúčame inštaláciu najprv otestovať v testovacom prostredí s kópiou vlastnej databázy.

Bezplatne a open source pre komunitu Odoo

My v Biricon IT Services GmbH vyvíjame riešenia najprv pre konkrétne požiadavky z našej vlastnej prevádzky. Ak z toho vznikne všeobecne použiteľný modul, nechceme ho skrývať v jednej inštalácii.

Merge Draft Invoices je preto k dispozícii bezplatne ako open source projekt. Zdrojový kód možno prezerať, kontrolovať, upravovať a v rámci licencie AGPL-3 ďalej rozvíjať.

Naším cieľom nebola čo najkratšia faktúra, ale faktúra, pri ktorej aj o rok každá položka vedie späť k svojej zákazke, svojmu tiketu a svojmu časovému záznamu.

Projekt, zdrojový kód a spolupráca

Kompletný zdrojový kód, pokyny na inštaláciu a technická dokumentácia sú dostupné na GitHube:

Otvoriť Odoo 19 Merge Draft Invoices na GitHube

Tešíme sa na skúsenosti z praxe, hlásenia chýb, návrhy na zlepšenie a príspevky z komunity Odoo.

Bezplatne. Dohľadateľne. Open source. Pre Odoo 19 Community.