Odoo-da sifarişlərdən, Helpdesk tiketlərindən və vaxt uçotundan hesablaşan hər kəs nəticəni tanıyır: Müştəri ay sonunda bir deyil, beş faktura alır. Hər biri başqa sifarişdən və ya tiketdən gəlir, hər biri məzmunca düzgündür – və yenə də müştəri bunun bir sənədə sığıb-sığmayacağını soruşur.
Məhz bunun üçün Odoo 19 Community-də səliqəli həll yoxdur. Tanınmış OCA modulu account_invoice_merge Odoo 19 üçün hələ buraxılmayıb və problemi xidmət təchizatçıları üçün ciddi risk yaradan şəkildə həll edir: Eyni mövqelər birləşdirilir və bununla sifarişə, tapşırığa və qeydə alınmış vaxta geri bağlantı itir.
Buna görə öz Odoo 19 Community quraşdırmamız üçün Merge Draft Invoices modulunu hazırladıq. Bu problem təkcə bizə aid olmadığına görə onu azad AGPL-3 lisenziyası ilə GitHub-da pulsuz təqdim edirik.
GitHub-da layihəyə keçid:
Niyə OCA həlli əvəzinə ayrıca modul?
OCA account_invoice_merge modulunu uzun illərdir OCA/account-invoicing repozitoriyasında saxlayır. Bu yazının dərc olunduğu vaxt oradakı 19.0-a miqrasiya hələ açıq Pull Request-dir, dərc edilmiş modul deyil.
Lakin daha vacibi odur ki, bu iki modul fərqli işlər görür:
| OCA account_invoice_merge | Merge Draft Invoices | |
|---|---|---|
| Nəticə | seçilmiş fakturalardan birinə birləşdirilir | həmişə yeni faktura |
| Mövqelər | eyni mövqelər birləşdirilir, miqdarlar toplanır | hər mövqe bir-bir götürülür |
| Mənşə | invoice_origin / payment_reference başlıqda birləşdirilir | mənşə sahələri hər mövqe üzrə Odoo-nun öz _copy_data_extend_business_fields hook-u vasitəsilə köçürülür |
| Vaxt uçotu | nəzərə alınmır | timesheet_invoice_id yeni fakturaya keçirilir |
| Müştəri üçün oxunaqlı | heç nə | hər mənbənin mövqeləri üzərində sifariş və tiketlə başlıq |
| Mənbə fakturaları | ləğv edilir | ləğv etmək (standart), silmək və ya saxlamaq – aydın adlandırılmış nəticələrlə |
Eyni mövqelərin birləşdirilməsi həlledici fərqdir. Birləşdirilmiş mövqe yalnız bir mənşə daşıya bilər. İki fərqli sifarişdən iki sətir eyni göründüyü andan faktura ilə sifarişə, tapşırığa və vaxt qeydinə geri bağlantı yox olur. Hesablaşmanın Tiket → Vaxt uçotu → Faktura üzrə getdiyi xidmət müəssisəsində bu o deməkdir: Eyni saatlar ikiqat hesablanır və ya yox olur.
Buna görə modulumuz prinsip etibarilə heç nəyi birləşdirmir. Birləşdirilmiş fakturada mənbələrin cəmi qədər mövqe olur.
OCA modulundan heç bir kod götürülməyib. Hər iki modul AGPL-3 altındadır.
Modul nə edir
Faktura siyahısı görünüşündə iki və ya daha çox qaralamanı işarələyin, əməliyyat menyusunda Qaralama fakturaları birləşdir seçin – köməkçi seçimi, yoxlamaları və mənbə fakturaları üçün seçimləri göstərir. Təsdiqdən sonra birbaşa yeni fakturaya keçirsiniz.
Birləşdirmədən əvvəl modul yoxlayır, özü də bütün məqamları bir dəfəyə, ki, hər düzəlişdən sonra növbəti xətanı görməyəsiniz:
- ən azı iki faktura seçilib
- hamısı Qaralama statusundadır
- heç biri heç vaxt mühasibat yazısına keçirilməyib (qaralamaya qaytarılmış sənəd mühasibat tarixçəsini saxlayır və rədd edilir)
- heç biri artıq birləşdirilməyib
- hamısı faktura, təchizatçı fakturası, kredit-notu və ya sənəddir – saf mühasibat yazıları deyil
- eyni tərəfdaş, sənəd növü, şirkət, valyuta və jurnal
Ödəniş şərti, vergi təyinatı, çatdırılma ünvanı, bank hesabı və ya satıcıdakı fərqlər bloklamır. Köməkçi xəbərdarlıq edir və seçilmiş ən köhnə fakturanın dəyərini götürür.
Nə qorunur
Modulun əsası odur ki, faktura mövqeyinin mənşəyi ilə hər bağlantısı yeni fakturada da mövcuddur:
| Əlaqə | Rəftar |
|---|---|
| Satış sifarişi mövqeləri (sale_line_ids) | hər mövqe üzrə Odoo-nun _copy_data_extend_business_fields vasitəsilə köçürülür |
| Satınalma sifarişi mövqeləri (purchase_line_id) | eyni qaydada |
| Xərc mərkəzi bölgüsü (analytic_distribution) | hər mövqe üzrə köçürülür |
| hər mövqe üzrə digər mənşə sahələri | təmin edən modul sənədləşdirilmiş Odoo hook-unu həyata keçirdikdə avtomatik |
| Faktura başlığında mənşə və istinad | birləşdirilir, təkrarlar silinir, köməkçidə redaktə edilə bilər |
| Satış sifarişi: invoice_ids, invoice_status, qty_invoiced | mövqelərdən hesablanır – sifariş yeni fakturanı özü tanıyır |
| Vaxt uçotu (timesheet_invoice_id) | mənbələr etibarsız olmazdan əvvəl yeni fakturaya keçirilir |
| Helpdesk tiketi | vaxt uçotuna bağlıdır və beləliklə avtomatik yeni fakturaya işarə edir |
| Chatter | Yeni fakturada bütün mənbələrlə mesaj, hər mənbədə yeni fakturaya keçidlə mesaj |
| merged_into_move_id / merged_from_move_ids | hər iki istiqamətdə saxlanılan əlaqə |
Vergi sətirləri, ödəniş şərti sətirləri, yuvarlaqlaşdırma və skonto sətirləri kopyalanmır, Odoo tərəfindən məzmundan yenidən hesablanır. Beləliklə birləşdirilmiş fakturada hər mənbə üzrə yox, hər vergi dərəcəsi üzrə bir vergi sətri olur. O, nömrəsiz qaralama kimi yaradılır; birləşdirmənin özü sənəd nömrəsi sərf etmir.
Başlıqlar: Müştəri hər mövqenin haradan gəldiyini görür
Gündəlik həyatda fərq yaradan funksiya budur. Hər mənbə fakturasının mövqeləri üzərində modul bölmə sətri qoyur – Odoo-nun özünün “Avanslar” bölməsi üçün istifadə etdiyi eyni element:
BE10181 <- Başlıq
22,500 x Texnik saatı 3.577,50
Aralıq cəm 3.577,50
BE10182 · Tiket: HT00219 <- Başlıq
3,000 x Texnik saatı 477,00
Aralıq cəm 477,00
XALİS MƏBLƏĞ 4.054,50
Başlıq müştəriyə verilən sənəddə çap olunur və Odoo-nun standart faktura hesabatı özü hər bölmə üzrə aralıq cəm əlavə edir. Beləliklə müştəri hər hissənin nəyə başa gəldiyini də görür.
Etiket mənbənin həqiqətən malik olduğu məlumatlardan tərtib olunur:
- sifarişlər, birbaşa mövqe bağlantılarından – adlar beləliklə dəqiqdir; sifariş bağlantıları yoxdursa, invoice_origin-dən sərbəst mətn istifadə olunur
- tiketlər, vaxt uçotu vasitəsilə müəyyən edilir – Tiket: HT00219 və ya Tiketlər: … şəklində çıxarılır, beş ilə məhdudlaşdırılır və “və N digər” əlavə olunur
- hər ikisi yoxdursa: mənbə fakturasının nömrəsi, sonra onun istinadı
- heç nə yoxdursa: neytral “Digər mövqelər”, ki, bir mənbənin sətirləri heç vaxt səssizcə yuxarıdakı blokda itməsin
Çatışmayan buraxılır, uydurulmur. Tiket öz nömrəsi ilə çap olunur – helpdesk_mgmt nömrəsi, Enterprise ticket_ref və ya modelin göstərilən adı – heç vaxt verilənlər bazası ID-si ilə yox.
Başlıqlar sifarişlərdən faktura yaradılarkən Odoo-nun etdiyi kimi müştərinin dilində yazılır. Chatter istifadəçinin dilində qalır.
Başlıq nə məhsul, nə miqdar, nə qiymət, nə vergi, nə hesab, nə də xərc mərkəzi bölgüsü daşıyır. O, cəmlərə, vergi bazasına və xərc hesablamasına təsir edə bilməz. Başlıqları köməkçidə söndürən kəs bu funksiya olmadan yaranacaq fakturanı dəqiq əldə edir – test hər iki nəticəni qəpiyinə qədər müqayisə edir.
Mənbə fakturalarına nə olur
Köməkçi üç seçim təklif edir:
- Ləğv etmək (standart, tövsiyə olunur). Qaralamanın ləğvi nəticəsizdir: nə sənəd nömrəsi, nə mühasibat yazısı. Fakturalar ləğv edilmiş sənədlər kimi chatter və yeni fakturaya keçidlə verilənlər bazasında qalır. Satış sifarişindəki qty_invoiced ləğv edilmiş sənədləri atlayır, heç nə ikiqat sayılmır. Bu, altı aydan sonra da izlənilə bilən seçimdir.
- Silmək. Geri qaytarılmaz. Chatter və geri istinad qeyd ilə birgə yox olur; yalnız yeni fakturadakı mesaj qalır. Artıq heç kimin görməməli olduğu birdəfəlik qaralamalar üçün məqsədəuyğundur.
- Qaralama kimi saxlamaq. Mənbələr açıq qalır. Onların satış sifarişləri bu zaman mənbəni və yeni fakturanı hesablaşılmış sayır – iş kimsə qaralamaları əllə təmizləyənə qədər ikiqat hesablanmış görünür. Qərar verməzdən əvvəl müqayisə etmək istənilən nadir hal üçün nəzərdə tutulub. Test məhz bu ikiqat sayımı qeyd edir ki, o, heç kimi təəccübləndirməsin.
Məhdudiyyətlər – modulun qəsdən etmədikləri
Zəhmət olmasa istehsal istifadəsindən əvvəl oxuyun:
- Yalnız qaralamalar. Mühasibat yazısına keçirilmiş fakturalar birləşdirilmir. Bu, kredit-not işidir, kopyalama prosesi deyil.
- Bir dəfə mühasibat yazısına keçirilmiş, geri qaytarılmış qaralamalar rədd edilir. Onların nömrəsi və mühasibat tarixçəsi var; bunu başqa sənəddə gizlətmək toplu əməliyyatın səssizcə yerinə yetirməli olduğu şey deyil.
- Tərəfdaşlar, valyutalar, şirkətlər və ya jurnallar üzrə birləşdirmə yoxdur. Bunun üçün məntiqli tək dəyər yoxdur, ona görə modul təxmin etmək əvəzinə rədd edir.
- payment_reference köçürülmür. Strukturlaşdırılmış ödəniş istinadları sənədi eyniləşdirir; birləşdirilmiş iki istinad bankda heç nəyə uyğun gəlmir. Yeni faktura mühasibat yazısına keçirilərkən öz istinadını alır.
- Avans mövqeləri hər digər mövqe kimi köçürülür. Mənbələrdə sale modulundan avans sətirləri varsa, nəticə mühasibat yazısına keçirilməzdən əvvəl yoxlanılmalıdır.
- Yalnız timesheet_invoice_id avtomatik keçirilir. account.move üzərində Many2one olan hər digər model (xüsusi hesablaşma işə salınmaları, abunə əlaqələri, EDI ötürmələri) hələ də mənbəyə işarə edir. Bunun üçün _merge_draft_relink hook-u var.
- Eyni mövqelərin birləşdirilməsi yoxdur – qəsdən. Qısa, səliqəli faktura istəyən burada yanlış yerdədir və bunun əvəzini mənşə bağlantıları ilə ödəyərdi.
- Başlıqlar birləşdirmə zamanı bir dəfə yaranır. Sonra onlar adi bölmə sətirləridir: redaktə edilə, silinə bilər və sifariş və ya tiket sonradan adını dəyişərsə yenilənmir.
- Başlıq ayrıca mövqenin deyil, bütün mənbə fakturasının tiketlərini göstərir.
Odoo 19 Community-də quraşdırma
Quraşdırma adi Odoo əlavə modulunda olduğu kimi aparılır:
- Modul qovluğunu konfiqurasiya edilmiş Addons yoluna köçürün.
- Odoo-da tətbiq siyahısını yeniləyin.
- account_invoice_merge_draft modulunu quraşdırın.
Modul yalnız account-dan asılıdır. Onun sale, purchase, project, hr_timesheet, sale_timesheet və ya Helpdesk modulu haqqında bildiyi hər şey icra zamanı müəyyən edilir – o, saf hesablaşma verilənlər bazasında da quraşdırılır və işləyir.
Bundan sonra: Mühasibat → Müştərilər → Fakturalar (və ya Təchizatçılar → Fakturalar), iki və ya daha çox qaralamanı işarələyin, dişli çarx menyusu → Qaralama fakturaları birləşdir. Əməliyyat Hesablaşma / Fakturalaşdırma qrupuna aid bütün istifadəçilərə açıqdır.
Modulun əvvəlki versiyasından yeniləyən kəs, dəyişdirilmiş sahə adlarının alman tərcüməsinə çatması üçün bir dəfə -u account_invoice_merge_draft --i18n-overwrite ilə yeniləməlidir. Yeni quraşdırmaya bu təsir etmir.
Developerlər üçün: API və hook-lar
Birləşdirməni öz kodunuzdan da çağırmaq olar:
python
merged = draft_moves.merge_draft_moves(
extra_vals={"invoice_date": date(2026, 3, 31), "ref": "Q1"},
source_handling="cancel", # "delete" və ya "keep"
add_source_sections=True, # Başlıqlar; standart True
)
merge_draft_moves seçim birləşdirilə bilmirsə, bütün rədd səbəbləri ilə UserError atır. _merge_draft_get_errors() eyni səbəbləri exception olmadan siyahı şəklində qaytarır.
account.move üzərində öz geri istinadları olan kəs _merge_draft_relink-i override edir:
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}
)
Faktura mövqeyində geri istinadı olan kəsə bu modul ümumiyyətlə lazım deyil: Odoo-nun öz account.move.line._copy_data_extend_business_fields hook-u kifayətdir və sahə birləşdirmə, ləğvetmə və dublikat zamanı eyni şəkildə köçürülür. Digər Helpdesk modulları və ya başlıqların başqa formulası üçün _merge_draft_get_source_tickets() və _merge_draft_section_name() var.
İstehsal məlumatlarında işləməzdən əvvəl sınaqdan keçirilib
48 test qarışıq statusları, fərqli tərəfdaşları, valyutaları və sənəd növlərini, satış və ya satınalma sifarişi olan və olmayan mövqeləri, vergiləri, bölmələri və qeydləri, xərc mərkəzi bölgülərini, vaxt uçotunun keçirilməsini, mənbə fakturaları üçün bütün üç seçimi, köməkçini və başlıqları əhatə edir – onların standart olaraq aktiv olduğunu, söndürülmələrinin köhnə nəticəni qəpiyinə qədər təkrar istehsal etdiyini, başlığın məbləğ və ya hesab daşımadığını, bir mənbənin mövqelərinin bir yerdə qaldığını, tiketin öz nömrəsi ilə və heç vaxt verilənlər bazası ID-si ilə görünmədiyini.
Test məlumatları AccountTestInvoicingCommon üzərində deyil, aktiv şirkətin mövcud hesablar planı üzərində qurulur – bu helper miqrasiya olunmuş istehsal verilənlər bazalarında tez-tez işə düşmür, modulun işləməli olduğu yer isə məhz belələridir.
odoo-bin -d <db> -u account_invoice_merge_draft --test-enable \
--test-tags /account_invoice_merge_draft --stop-after-init
Mühasibat sahəsindəki hər genişlənmədə olduğu kimi, quraşdırmanı əvvəlcə öz verilənlər bazasının surəti ilə test mühitində yoxlamağı tövsiyə edirik.
Odoo Community üçün pulsuz və açıq mənbə
Biz Biricon IT Services GmbH-də həlləri əvvəlcə öz fəaliyyətimizdəki konkret tələblər üçün hazırlayırıq. Bundan ümumi istifadə oluna bilən modul yaranarsa, onu tək bir quraşdırmada gizlətmək istəmirik.
Merge Draft Invoices buna görə pulsuz açıq mənbəli layihə kimi təqdim olunur. Mənbə kodu AGPL-3 lisenziyası çərçivəsində nəzərdən keçirilə, yoxlana, uyğunlaşdırıla və inkişaf etdirilə bilər.
Məqsədimiz mümkün qədər qısa faktura deyildi, bir ildən sonra da hər mövqenin öz sifarişinə, tiketinə və vaxt qeydinə aparan faktura idi.
Layihə, mənbə kodu və əməkdaşlıq
Tam mənbə kodu, quraşdırma qeydləri və texniki sənədləşmə GitHub-da mövcuddur:
GitHub-da Odoo 19 Merge Draft Invoices-i açın
Praktik təcrübələrə, xəta hesabatlarına, təkmilləşdirmə təkliflərinə və Odoo İcmasından gələn töhfələrə şad olarıq.
Pulsuz. İzlənilə bilən. Açıq mənbə. Odoo 19 Community üçün.