Skip to Content

Odoo 19 Community: melnraksta rēķinu apvienošana – mūsu atvērtā koda modulis Merge Draft Invoices

2026. gada 18. septembris by
Odoo 19 Community: melnraksta rēķinu apvienošana – mūsu atvērtā koda modulis Merge Draft Invoices
Alexander Biringer | Biricon IT Services GmbH

Kas programmā Odoo izraksta rēķinus no pasūtījumiem, Helpdesk biļetēm un laika uzskaites, zina rezultātu: klients mēneša beigās saņem nevis vienu rēķinu, bet piecus. Katrs ir no cita pasūtījuma vai biļetes, katrs ir pēc būtības pareizs – un tomēr klients jautā, vai to nevarētu ietilpināt vienā dokumentā.

Tieši tam Odoo 19 Community nav tīra risinājuma. Zināmais OCA modulis account_invoice_merge Odoo 19 vēl nav izlaists, un tas risina problēmu tā, ka pakalpojumu sniedzējiem tas rada nopietnu risku: vienādas pozīcijas tiek apvienotas, un tādējādi tiek zaudēta saikne atpakaļ ar pasūtījumu, uzdevumu un reģistrēto laiku.

Savai Odoo 19 Community instalācijai mēs tāpēc izstrādājām moduli Merge Draft Invoices. Tā kā šī problēma skar ne tikai mūs, mēs to bez maksas nododam vietnē GitHub ar brīvo AGPL-3 licenci.

Uz projektu vietnē GitHub:

Odoo 19 Merge Draft Invoices

Kāpēc savs modulis, nevis OCA risinājums?

OCA jau daudzus gadus uztur account_invoice_merge repozitorijā OCA/account-invoicing. Šī raksta rakstīšanas brīdī migrācija uz 19.0 tur joprojām ir atvērts Pull Request, nevis publicēts modulis.

Svarīgāk gan ir tas, ka abi moduļi dara dažādas lietas:


OCA account_invoice_mergeMerge Draft Invoices
Rezultātstiek apvienots vienā no izvēlētajiem rēķiniemvienmēr jauns rēķins
Pozīcijasvienādas pozīcijas tiek apvienotas, daudzumi summētikatra pozīcija tiek pārņemta viens pret vienu
Izcelsmeinvoice_origin / payment_reference galvenē sasaistīti kopāizcelsmes lauki katrai pozīcijai tiek kopēti ar paša Odoo _copy_data_extend_business_fields hook
Laika uzskaitenetiek ņemta vērātimesheet_invoice_id tiek pārslēgts uz jauno rēķinu
Lasāms klientamnekasvirsraksts virs katra avota pozīcijām ar pasūtījumu un biļeti
Avota rēķinitiek anulētianulēt (noklusējums), dzēst vai paturēt – ar skaidri nosauktām sekām

Vienādu pozīciju apvienošana ir izšķirošā atšķirība. Apvienota pozīcija var nest tikai vienu izcelsmi. Līdzko divas rindas no diviem dažādiem pasūtījumiem izskatās vienādas, saikne no rēķina atpakaļ uz pasūtījumu, uzdevumu un laika grāmatojumu ir zudusi. Pakalpojumu uzņēmumā, kur norēķini notiek pa ķēdi biļete → laika uzskaite → rēķins, tas nozīmē: vienas un tās pašas stundas tiek aprēķinātas divreiz vai pazūd.

Tāpēc mūsu modulis principā neko neapvieno. Apvienotajā rēķinā ir tieši tik pozīciju, cik to kopā ir avotos.

No OCA moduļa kods nav pārņemts. Abi moduļi ir ar AGPL-3 licenci.

Ko modulis dara

Rēķinu saraksta skatā atzīmējiet divus vai vairākus melnrakstus, darbību izvēlnē izvēlieties Apvienot melnraksta rēķinus – vednis parāda izvēli, pārbaudes un opcijas avota rēķiniem. Pēc apstiprināšanas jūs uzreiz nonākat jaunajā rēķinā.

Pirms apvienošanas modulis veic pārbaudi, un tieši visus punktus uzreiz, lai pēc katra labojuma nebūtu jāredz nākamā kļūda:

  • izvēlēti vismaz divi rēķini
  • visi ar statusu Melnraksts
  • neviens nav kādreiz grāmatots (uz melnrakstu atiestatīts dokuments saglabā savu grāmatojumu vēsturi un tiek noraidīts)
  • neviens nav jau apvienots
  • visi ir rēķins, piegādātāja rēķins, kredītrēķins vai dokuments – nevis tīri grāmatojumu ieraksti
  • tas pats partneris, dokumenta veids, uzņēmums, valūta un žurnāls

Atšķirības maksājuma noteikumos, nodokļu piesaistē, piegādes adresē, bankas kontā vai pārdevējā nebloķē. Vednis brīdina un pārņem vecākā izvēlētā rēķina vērtību.

Kas tiek saglabāts

Moduļa kodols ir tas, ka katra saikne, kas rēķina pozīcijai ir ar tās izcelsmi, pastāv arī jaunajā rēķinā:

SaikneApstrāde
Pārdošanas pasūtījuma pozīcijas (sale_line_ids)katrai pozīcijai tiek kopēts ar Odoo _copy_data_extend_business_fields
Iepirkuma pasūtījuma pozīcijas (purchase_line_id)tāpat
Izmaksu centru sadalījums (analytic_distribution)katrai pozīcijai tiek kopēts
citi izcelsmes lauki katrai pozīcijaiautomātiski, ja nodrošinošais modulis implementē dokumentēto Odoo hook
Izcelsme un atsauce rēķina galvenēapvienota, dedublicēta, vednī rediģējama
Pārdošanas pasūtījums: invoice_ids, invoice_status, qty_invoicedtiek aprēķināti no pozīcijām – pasūtījums jauno rēķinu atpazīst pats
Laika uzskaite (timesheet_invoice_id)tiek pārslēgta uz jauno rēķinu, pirms avoti kļūst nederīgi
Helpdesk biļeteir piesaistīta laika uzskaitei un tādējādi automātiski norāda uz jauno rēķinu
Chatterziņa jaunajā rēķinā ar visiem avotiem, ziņa katrā avotā ar saiti uz jauno
merged_into_move_id / merged_from_move_idssaglabāta saikne abos virzienos

Nodokļu rindas, maksājuma noteikumu rindas, noapaļošanas un atlaižu rindas netiek kopētas, bet Odoo tās no jauna aprēķina pēc satura. Apvienotajā rēķinā tātad ir viena nodokļu rinda katrai nodokļa likmei, nevis viena katram avotam. Tas tiek izveidots kā melnraksts bez numura; pati apvienošana neizmanto dokumenta numuru.

Virsraksti: klients redz, no kurienes katra pozīcija nāk

Šī ir funkcija, kas ikdienā rada atšķirību. Virs katra avota rēķina pozīcijām modulis ievieto sadaļas rindu – to pašu elementu, ko Odoo pats izmanto sadaļai „Avansa maksājumi“:

BE10181                                     <- Virsraksts
  22,500 x Tehniķa stunda         3.577,50
                    Starpsumma    3.577,50
BE10182 · Biļete: HT00219                   <- Virsraksts
   3,000 x Tehniķa stunda           477,00
                    Starpsumma      477,00
                      NETO SUMMA  4.054,50

Virsraksts tiek drukāts dokumentā, ko saņem klients, un Odoo standarta rēķina pārskats pats papildina starpsummu katrai sadaļai. Tādējādi klients redz arī to, cik izmaksāja katra daļa.

Uzraksts tiek veidots no tā, kas avotam patiešām ir:

  1. pasūtījumi, tieši no pozīciju saitēm – nosaukumi tādējādi ir precīzi; ja pasūtījumu saišu nav, tiek izmantots brīvais teksts no invoice_origin
  2. biļetes, noteiktas pēc laika uzskaites – izvadītas kā Biļete: HT00219 vai Biļetes: …, ierobežotas līdz piecām plus „un vēl N“
  3. ja nav neviena no tiem: avota rēķina numurs, tad tā atsauce
  4. ja nav nekā: neitrāls „Papildu pozīcijas“, lai kāda avota rindas nekad klusējot nepazustu augstāk esošajā blokā

Kas trūkst, tiek izlaists, nevis izdomāts. Biļete tiek drukāta ar savu numuru – helpdesk_mgmt numurs, Enterprise ticket_ref vai modeļa attēlojamais nosaukums – nekad ar datubāzes ID.

Virsraksti tiek rakstīti klienta valodā, tāpat kā Odoo to dara, veidojot rēķinus no pasūtījumiem. Chatter paliek lietotāja valodā.

Virsraksts nenes ne produktu, ne daudzumu, ne cenu, ne nodokli, ne kontu, ne izmaksu centru sadalījumu. Tas nevar ietekmēt summas, nodokļu bāzi un izmaksu uzskaiti. Kas virsrakstus vednī izslēdz, saņem tieši to rēķinu, kas rastos bez šīs funkcijas – tests salīdzina abus rezultātus līdz centam.

Kas notiek ar avota rēķiniem

Vednis piedāvā trīs opcijas:

  • Anulēt (noklusējums, ieteicams). Melnraksta anulēšanai nav seku: nav dokumenta numura, nav grāmatojuma. Rēķini datubāzē paliek kā anulēti dokumenti ar Chatter un saiti uz jauno rēķinu. qty_invoiced pārdošanas pasūtījumā anulētos dokumentus izlaiž, nekas netiek skaitīts divreiz. Tā ir opcija, kas arī pēc sešiem mēnešiem joprojām ir izsekojama.
  • Dzēst. Neatsaucami. Chatter un atpakaļsaite izzūd līdz ar ierakstu; paliek tikai ziņa jaunajā rēķinā. Lietderīgi vienreizlietojamiem melnrakstiem, ko neviens vairs nedrīkst redzēt.
  • Atstāt kā melnrakstu. Avoti paliek atvērti. To pārdošanas pasūtījumi tad skaita gan avotu, gan jauno rēķinu kā izrakstītu – darbs izskatās divreiz norēķināts, kamēr kāds melnrakstus nesakārto ar roku. Paredzēts retajam gadījumam, kad pirms lēmuma vēlas salīdzināt. Tests fiksē tieši šo dubulto skaitīšanu, lai tā nevienu nepārsteigtu.

Robežas – ko modulis apzināti nedara

Lūdzu, izlasiet pirms produktīvas lietošanas:

  • Tikai melnraksti. Grāmatoti rēķini netiek apvienoti. Tas ir kredītrēķinu uzdevums, nevis kopēšanas process.
  • Reiz grāmatoti, atiestatīti melnraksti tiek noraidīti. Tiem ir numurs un grāmatojumu vēsture; slēpt to citā dokumentā nav kaut kas, ko kopējai darbībai būtu jādara klusējot.
  • Nekāda apvienošana pāri partneriem, valūtām, uzņēmumiem vai žurnāliem. Tam nav jēgpilnas atsevišķas vērtības, tāpēc modulis noraida, nevis minē.
  • payment_reference netiek pārņemta. Strukturētas maksājuma atsauces identificē dokumentu; divas sasaistītas neder nekam bankā. Jaunais rēķins grāmatojot saņem savu atsauci.
  • Avansa pozīcijas tiek kopētas kā jebkura cita pozīcija. Ja avoti satur avansa rindas no sale, rezultāts pirms grāmatošanas jāpārbauda.
  • Automātiski tiek pārslēgts tikai timesheet_invoice_id. Jebkurš cits modelis ar Many2one uz account.move (savi norēķinu cikli, abonementu saites, EDI pārsūtīšanas) joprojām norāda uz avotu. Šim nolūkam ir hook _merge_draft_relink.
  • Vienādu pozīciju apvienošanas nav – apzināti. Kas vēlas īsu, sakārtotu rēķinu, ir nepareizā vietā un par to maksātu ar izcelsmes saitēm.
  • Virsraksti rodas vienu reizi apvienošanas laikā. Pēc tam tās ir parastas sadaļas rindas: rediģējamas, dzēšamas un netiek atjauninātas, ja pasūtījums vai biļete vēlāk tiek pārdēvēta.
  • Virsrakstā ir minētas visa avota rēķina biļetes, nevis atsevišķās pozīcijas.

Instalēšana Odoo 19 Community

Instalēšana notiek tāpat kā ar parastu Odoo papildmoduli:

  1. Nokopēt moduļa direktoriju konfigurētā addons ceļā.
  2. Atjaunināt lietotņu sarakstu Odoo.
  3. Instalēt moduli account_invoice_merge_draft.

Modulis ir atkarīgs tikai no account. Viss, ko tas zina par sale, purchase, project, hr_timesheet, sale_timesheet vai Helpdesk moduli, tiek noteikts izpildes laikā – tas instalējas un darbojas arī tīrā norēķinu datubāzē.

Pēc tam: Grāmatvedība → Klienti → Rēķini (vai Piegādātāji → Rēķini), atzīmēt divus vai vairākus melnrakstus, zobrata izvēlne → Apvienot melnraksta rēķinus. Darbība ir pieejama visiem lietotājiem ar grupu Norēķini / Rēķinu izrakstīšana.

Kas atjaunina no iepriekšējās moduļa versijas, vienu reizi ar -u account_invoice_merge_draft --i18n-overwrite jāveic atjauninājums, lai mainītie lauku nosaukumi nonāktu vācu tulkojumā. Jauna instalēšana to neietekmē.

Izstrādātājiem: API un hooks

Apvienošanu var izsaukt arī no sava koda:

python

merged = draft_moves.merge_draft_moves(
    extra_vals={"invoice_date": date(2026, 3, 31), "ref": "Q1"},
    source_handling="cancel",   # "delete" vai "keep"
    add_source_sections=True,   # virsraksti; noklusējums True
)

merge_draft_moves izmet UserError ar visiem noraidīšanas iemesliem, ja izvēli nevar apvienot. _merge_draft_get_errors() atgriež tos pašus iemeslus kā sarakstu bez Exception.

Kam ir savas atpakaļsaites uz account.move, pārraksta _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}
        )

Kam ir atpakaļsaite rēķina pozīcijā, šis modulis nemaz nav vajadzīgs: pietiek ar paša Odoo hook account.move.line._copy_data_extend_business_fields, un lauks tiek pārņemts gan apvienojot, gan anulējot, gan dublējot. Citiem Helpdesk moduļiem vai citam virsrakstu formulējumam ir _merge_draft_get_source_tickets() un _merge_draft_section_name().

Pārbaudīts, pirms tas darbojas ar produktīviem datiem

48 testi aptver jauktus statusus, dažādus partnerus, valūtas un dokumentu veidus, pozīcijas ar un bez pārdošanas vai iepirkuma pasūtījuma, nodokļus, sadaļas un piezīmes, izmaksu centru sadalījumus, laika uzskaites pārslēgšanu, visas trīs opcijas avota rēķiniem, vedni un virsrakstus – ka tie pēc noklusējuma ir aktīvi, ka to izslēgšana līdz centam reproducē iepriekšējo rezultātu, ka virsraksts nenes summas vai kontus, ka viena avota pozīcijas paliek kopā, ka biļete parādās ar savu numuru un nekad ar datubāzes ID.

Testa dati balstās uz aktīvā uzņēmuma esošo kontu plānu, nevis uz AccountTestInvoicingCommon – šis palīgs uz migrētām produktīvām datubāzēm bieži nestartējas, un tieši uz tādām modulim jādarbojas.

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

Tāpat kā ar katru paplašinājumu grāmatvedības jomā, mēs iesakām instalēšanu vispirms pārbaudīt testa vidē ar savas datubāzes kopiju.

Bez maksas un atvērtā koda Odoo kopienai

Mēs Biricon IT Services GmbH risinājumus vispirms izstrādājam konkrētām prasībām no sava uzņēmuma darbības. Ja no tā rodas vispārīgi lietojams modulis, mēs nevēlamies to paslēpt vienā atsevišķā instalācijā.

Tāpēc Merge Draft Invoices ir bez maksas pieejams kā atvērtā koda projekts. Pirmkodu var apskatīt, pārbaudīt, pielāgot un AGPL-3 licences ietvaros tālāk attīstīt.

Mūsu mērķis nebija pēc iespējas īsāks rēķins, bet rēķins, kurā pat pēc gada katra pozīcija joprojām ved atpakaļ uz savu pasūtījumu, savu biļeti un savu laika grāmatojumu.

Projekts, pirmkods un līdzdalība

Pilns pirmkods, instalēšanas norādes un tehniskā dokumentācija ir pieejami vietnē GitHub:

Atvērt Odoo 19 Merge Draft Invoices vietnē GitHub

Mēs priecājamies par pieredzes atsauksmēm, kļūdu ziņojumiem, uzlabojumu priekšlikumiem un Odoo kopienas ieguldījumu.

Bez maksas. Izsekojami. Atvērtā koda. Odoo 19 Community.