Skip to Content

Odoo 19 Community: Bashkimi i faturave draft – moduli ynë me burim të hapur Merge Draft Invoices

18 shtator 2026 by
Odoo 19 Community: Bashkimi i faturave draft – moduli ynë me burim të hapur Merge Draft Invoices
Alexander Biringer | Biricon IT Services GmbH

Kush faturon në Odoo nga porositë, tiketat e Helpdesk-ut dhe regjistrimi i kohës, e njeh rezultatin: një klient në fund të muajit nuk merr një faturë, por pesë. Secila vjen nga një porosi ose tiket tjetër, secila është e saktë nga ana profesionale – dhe megjithatë klienti pyet nëse nuk do të mund të futej e gjitha në një dokument.

Pikërisht për këtë, në Odoo 19 Community nuk ekziston një zgjidhje e pastër. Moduli i njohur i OCA account_invoice_merge nuk është ende i miratuar për Odoo 19 dhe e zgjidh problemin në një mënyrë që për ofruesit e shërbimeve përbën një rrezik serioz: pozicionet e barabarta bashkohen dhe kështu humbet lidhja me porosinë, me detyrën dhe me kohën e regjistruar.

Për instalimin tonë të Odoo 19 Community kemi zhvilluar prandaj modulin Merge Draft Invoices. Meqenëse ky problem nuk na prek vetëm ne, e vëmë falas në dispozicion në GitHub nën licencën e lirë AGPL-3.

Te projekti në GitHub:

Odoo 19 Merge Draft Invoices

Pse një modul i vetë në vend të zgjidhjes së OCA-s?

OCA mirëmban prej shumë vitesh account_invoice_merge në repozitorin OCA/account-invoicing. Në kohën e këtij artikulli migrimi në 19.0 atje është ende një pull request i hapur, jo një modul i publikuar.

Më e rëndësishme, megjithatë, është që të dy modulet bëjnë gjëra të ndryshme:


OCA account_invoice_mergeMerge Draft Invoices
Rezultatibashkohet në një nga faturat e zgjedhuragjithmonë një faturë e re
Pozicionetpozicionet e barabarta bashkohen, sasitë mblidhençdo pozicion merret një me një
Origjinainvoice_origin / payment_reference të bashkuara në kokëfushat e origjinës për çdo pozicion kopjohen përmes hook-ut të vetë Odoo-s _copy_data_extend_business_fields
Regjistrimi i kohësnuk merret parasyshtimesheet_invoice_id kalohet te fatura e re
I lexueshëm për klientinasgjënjë titull mbi pozicionet e çdo burimi me porosinë dhe tiketin
Faturat burimoreanulohenanulohen (parazgjedhje), fshihen ose mbahen – me pasoja të emërtuara qartë

Bashkimi i pozicioneve të barabarta është dallimi vendimtar. Një pozicion i bashkuar mund të mbajë vetëm një origjinë. Sapo dy rreshta nga dy porosi të ndryshme duken njësoj, lidhja nga fatura mbrapsht te porosia, te detyra dhe te regjistrimi i kohës humbet. Në një ndërmarrje shërbimesh, ku faturimi kalon përmes tiketit → regjistrimit të kohës → faturës, kjo do të thotë: të njëjtat orë faturohen dy herë ose zhduken.

Prandaj moduli ynë në parim nuk bashkon asgjë. Fatura e bashkuar ka saktësisht aq pozicione sa kanë burimet e saj së bashku.

Nuk është marrë asnjë kod nga moduli i OCA-s. Të dy modulet janë nën AGPL-3.

Çfarë bën moduli

Në pamjen e listës së faturave shënoni dy ose më shumë draft-e, zgjidhni në menunë e veprimeve Bashkimi i faturave draft – një asistent shfaq përzgjedhjen, kontrollet dhe opsionet për faturat burimore. Pas konfirmimit hyni drejtpërdrejt te fatura e re.

Përpara bashkimit moduli kontrollon, dhe pikërisht të gjitha pikat njëherësh, në mënyrë që të mos shihet gabimi tjetër pas çdo korrigjimi:

  • të paktën dy fatura të zgjedhura
  • të gjitha në statusin Draft
  • asnjë nuk është regjistruar ndonjëherë (një dokument i kthyer në draft ruan historikun e regjistrimit dhe refuzohet)
  • asnjë nuk është bashkuar tashmë
  • të gjitha janë faturë, faturë furnitori, notë krediti ose dokument – jo thjesht regjistrime kontabël
  • i njëjti partner, lloj dokumenti, kompani, monedhë dhe ditar

Dallimet në kushtet e pagesës, caktimin e taksave, adresën e dërgesës, llogarinë bankare ose shitësin nuk bllokojnë. Asistenti paralajmëron dhe merr vlerën e faturës më të vjetër të zgjedhur.

Çfarë ruhet

Thelbi i modulit është që çdo lidhje që ka një pozicion fature me origjinën e vet ekziston edhe te fatura e re:

LidhjaTrajtimi
Pozicionet e porosisë së shitjes (sale_line_ids)kopjohen për çdo pozicion përmes _copy_data_extend_business_fields të Odoo-s
Pozicionet e porosisë së blerjes (purchase_line_id)njësoj
Shpërndarja e qendrave të kostos (analytic_distribution)kopjohet për çdo pozicion
fusha të tjera origjine për çdo pozicionautomatikisht, kur moduli furnizues implementon hook-un e dokumentuar të Odoo-s
Origjina dhe referenca në kokën e faturësbashkuar, pa dublikate, i redaktueshëm në asistent
Porosia e shitjes: invoice_ids, invoice_status, qty_invoicedllogariten nga pozicionet – porosia e njeh vetë faturën e re
Regjistrimi i kohës (timesheet_invoice_id)kalohet te fatura e re përpara se burimet të bëhen të pavlefshme
Tiketi i Helpdesk-utvaret nga regjistrimi i kohës dhe kështu tregon automatikisht te fatura e re
Chattermesazh te fatura e re me të gjitha burimet, mesazh te çdo burim me lidhje për te e reja
merged_into_move_id / merged_from_move_idslidhje e ruajtur në të dy drejtimet

Rreshtat e taksave, rreshtat e kushteve të pagesës, rreshtat e rrumbullakimit dhe të skontos nuk kopjohen, por rillogariten nga Odoo nga përmbajtja. Fatura e bashkuar ka pra një rresht takse për çdo normë takse, jo një për çdo burim. Ajo krijohet pa numërim si draft; vetë bashkimi nuk konsumon asnjë numër dokumenti.

Titujt: klienti sheh nga vjen çdo pozicion

Ky është funksioni që bën dallimin në përditshmëri. Mbi pozicionet e çdo fature burimore moduli vendos një rresht seksioni – të njëjtin element që vetë Odoo e përdor për seksionin „Paradhëniet“:

BE10181                                     <- Titulli
  22,500 x Ora e teknikut         3.577,50
                    Nëntotali     3.577,50
BE10182 · Ticket: HT00219                   <- Titulli
   3,000 x Ora e teknikut           477,00
                    Nëntotali       477,00
                      SHUMA NETO  4.054,50

Titulli shtypet në dokumentin që merr klienti dhe raporti standard i faturës i Odoo-s shton vetë një nëntotal për çdo seksion. Kështu klienti sheh edhe sa ka kushtuar çdo pjesë.

Etiketa përbëhet nga ajo që ka në fakt burimi:

  1. porositë, drejtpërdrejt nga lidhjet e pozicioneve – emrat janë kështu të saktë; nëse mungojnë lidhjet me porositë, përdoret teksti i lirë nga invoice_origin
  2. tiketat, të përcaktuara përmes regjistrimit të kohës – shfaqen si Ticket: HT00219 ose Tickets: …, të kufizuara në pesë plus „dhe N të tjera“
  3. nëse nuk ka asnjërën: numri i faturës burimore, pastaj referenca e saj
  4. nëse nuk ka asgjë fare: një „Pozicione të tjera“ neutrale, në mënyrë që rreshtat e një burimi të mos zhduken kurrë në heshtje në bllokun sipër

Ajo që mungon lihet jashtë, nuk shpiket. Tiketi shtypet me numrin e vet – numri helpdesk_mgmt, ticket_ref i Enterprise ose emri i shfaqur i modelit – kurrë me ID-në e bazës së të dhënave.

Titujt shkruhen në gjuhën e klientit, ashtu siç e bën Odoo kur krijon fatura nga porositë. Chatter mbetet në gjuhën e përdoruesit.

Një titull nuk mban produkt, sasi, çmim, taksë, llogari dhe shpërndarje të qendrës së kostos. Ai nuk mund të ndikojë në totalet, bazën e taksës dhe kontabilitetin e kostos. Kush i çaktivizon titujt në asistent, merr saktësisht faturën që do të krijohej pa këtë funksion – një test i krahason të dy rezultatet deri në cent.

Çfarë ndodh me faturat burimore

Asistenti ofron tre opsione:

  • Anulo (parazgjedhje, e rekomanduar). Anulimi i një draft-i nuk ka pasoja: pa numër dokumenti, pa regjistrim. Faturat mbeten në bazën e të dhënave si dokumente të anuluara me chatter dhe lidhje për te fatura e re. qty_invoiced te porosia e shitjes kalon mbi dokumentet e anuluara, asgjë nuk numërohet dy herë. Ky është opsioni që mbetet i kuptueshëm edhe pas gjashtë muajsh.
  • Fshi. E pakthyeshme. Chatter dhe lidhja e kthimit vdesin bashkë me regjistrimin; mbetet vetëm mesazhi te fatura e re. I dobishëm për draft-e të hedhshme që nuk duhet t'i shohë më askush.
  • Lër si draft. Burimet mbeten të hapura. Porositë e tyre të shitjes numërojnë atëherë burimin dhe faturën e re si të faturuara – puna duket e faturuar dy herë, derisa dikush t'i pastrojë draft-et me dorë. E menduar për rastin e rrallë kur dëshirohet krahasimi përpara vendimit. Një test e fiksoi pikërisht këtë numërim të dyfishtë, që të mos e befasojë askënd.

Kufijtë – çfarë nuk bën qëllimisht moduli

Ju lutemi lexojeni përpara përdorimit në prodhim:

  • Vetëm draft-e. Faturat e regjistruara nuk bashkohen. Kjo është detyrë për nota krediti, jo proces kopjimi.
  • Draft-et e regjistruara dikur dhe të kthyera refuzohen. Ato kanë një numër dhe një histori regjistrimi; ta fshehësh këtë në një dokument tjetër nuk është diçka që duhet ta bëjë në heshtje një veprim i përbashkët.
  • Asnjë bashkim ndërmjet partnerëve, monedhave, kompanive ose ditarëve. Për këtë nuk ka vlerë të vetme kuptimplotë, ndaj moduli refuzon në vend që të hamendësojë.
  • payment_reference nuk merret. Referencat e strukturuara të pagesës identifikojnë një dokument; dy të ngjitura bashkë nuk përputhen me asgjë te banka. Fatura e re merr referencën e vet gjatë regjistrimit.
  • Pozicionet e paradhënies kopjohen si çdo pozicion tjetër. Nëse burimet përmbajnë rreshta paradhënieje nga sale, rezultati duhet kontrolluar para regjistrimit.
  • Vetëm timesheet_invoice_id kalohet automatikisht. Çdo model tjetër me një Many2one te account.move (cikle faturimi të vetë, lidhje abonimesh, dërgime EDI) vazhdon të tregojë te burimi. Për këtë ekziston hook-u _merge_draft_relink.
  • Pa bashkim të pozicioneve të barabarta – qëllimisht. Kush dëshiron një faturë të shkurtër e të rregullt, nuk është në vendin e duhur këtu dhe do ta paguante këtë me lidhjet e origjinës.
  • Titujt krijohen vetëm një herë gjatë bashkimit. Pas kësaj janë rreshta të zakonshëm seksioni: të redaktueshëm, të fshirshëm dhe nuk përditësohen nëse porosia ose tiketi riemërtohet më vonë.
  • Një titull përmend tiketat e të gjithë faturës burimore, jo të pozicionit individual.

Instalimi në Odoo 19 Community

Instalimi bëhet si te një modul shtesë i zakonshëm i Odoo-s:

  1. Kopjoni dosjen e modulit në një shteg të konfiguruar addons.
  2. Përditësoni listën e aplikacioneve në Odoo.
  3. Instaloni modulin account_invoice_merge_draft.

Moduli varet vetëm nga account. Gjithçka që di për sale, purchase, project, hr_timesheet, sale_timesheet ose një modul Helpdesk përcaktohet gjatë ekzekutimit – instalohet dhe funksionon edhe në një bazë të dhënash vetëm për faturim.

Pastaj: Kontabiliteti → Klientët → Faturat (ose Furnitorët → Faturat), shënoni dy ose më shumë draft-e, menuja e ingranazhit → Bashkimi i faturave draft. Veprimi u vihet në dispozicion të gjithë përdoruesve me grupin Faturim / Faturimi.

Kush përditësohet nga një version i mëparshëm i modulit, duhet një herë ta përditësojë me -u account_invoice_merge_draft --i18n-overwrite, që emërtimet e ndryshuara të fushave të arrijnë në përkthimin gjerman. Një instalim i ri nuk preket nga kjo.

Për zhvilluesit: API dhe hooks

Bashkimi mund të thirret edhe nga kodi i vetë:

python

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

merge_draft_moves hedh një UserError me të gjitha arsyet e refuzimit, kur përzgjedhja nuk mund të bashkohet. _merge_draft_get_errors() kthen të njëjtat arsye si listë pa përjashtim.

Kush ka lidhje kthimi të vetat te account.move, mbishkruan _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}
        )

Kush ka një lidhje kthimi te pozicioni i faturës, nuk ka fare nevojë për këtë modul: hook-u i vetë Odoo-s account.move.line._copy_data_extend_business_fields mjafton, dhe fusha merret njësoj gjatë bashkimit, anulimit dhe dublikimit. Për module të tjera Helpdesk ose një formulim tjetër të titujve ekzistojnë _merge_draft_get_source_tickets() dhe _merge_draft_section_name().

I testuar para se të punojë me të dhëna prodhimi

48 teste mbulojnë statuse të përziera, partnerë, monedha dhe lloje dokumentesh të ndryshme, pozicione me dhe pa porosi shitjeje ose blerjeje, taksa, seksione dhe shënime, shpërndarje të qendrave të kostos, kalimin e regjistrimit të kohës, të tria opsionet për faturat burimore, asistentin dhe titujt – që janë aktivë si parazgjedhje, që çaktivizimi i tyre riprodhon rezultatin e vjetër deri në cent, që një titull nuk mban shuma ose llogari, që pozicionet e një burimi qëndrojnë bashkë, që tiketi shfaqet me numrin e vet dhe kurrë me ID-në e bazës së të dhënave.

Të dhënat e testit mbështeten te plani ekzistues i llogarive të kompanisë aktive në vend të AccountTestInvoicingCommon – ky helper shpesh nuk niset në baza të dhënash prodhimi të migruara, dhe pikërisht në to duhet të punojë moduli.

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

Si te çdo zgjerim në fushën e kontabilitetit, rekomandojmë që instalimi të kontrollohet fillimisht në një mjedis testimi me një kopje të bazës së të dhënave tuaja.

Falas dhe me burim të hapur për komunitetin Odoo

Ne te Biricon IT Services GmbH i zhvillojmë zgjidhjet fillimisht për kërkesa konkrete nga operimi ynë. Kur prej tyre krijohet një modul i përdorshëm në përgjithësi, nuk duam ta fshehim në një instalim të vetëm.

Merge Draft Invoices është prandaj i disponueshëm falas si projekt me burim të hapur. Kodi burimor mund të shikohet, të kontrollohet, të përshtatet dhe të zhvillohet më tej në kuadër të licencës AGPL-3.

Qëllimi ynë nuk ishte fatura më e shkurtër e mundshme, por një faturë ku edhe pas një viti çdo pozicion të çon prapa te porosia, tiketi dhe regjistrimi i kohës së vet.

Projekti, kodi burimor dhe bashkëpunimi

Kodi burimor i plotë, udhëzimet e instalimit dhe dokumentacioni teknik janë të disponueshëm në GitHub:

Hapni Odoo 19 Merge Draft Invoices në GitHub

Na vlerësojmë përvojat praktike, raportet e gabimeve, propozimet për përmirësim dhe kontributet nga komuniteti Odoo.

Falas. E gjurmueshme. Burim i hapur. Për Odoo 19 Community.