Odoo'da siparişlerden, Helpdesk taleplerinden ve zaman kayıtlarından faturalandıranlar sonucu bilir: Bir müşteri ay sonunda tek bir fatura değil, beş fatura alır. Her biri farklı bir siparişten veya taleptan geliyor, her biri içerik olarak doğru – ve yine de müşteri bunların tek bir belgeye sığıp sığmayacağını soruyor.
Odoo 19 Community'de tam da bunun için temiz bir çözüm yok. Bilinen OCA modülü account_invoice_merge Odoo 19 için henüz yayımlanmadı ve sorunu, hizmet sağlayıcılar için ciddi bir risk oluşturan bir şekilde çözüyor: Aynı kalemler birleştiriliyor ve böylece siparişe, göreve ve kaydedilen zamana geri giden bağlantı kayboluyor.
Bu yüzden kendi Odoo 19 Community kurulumumuz için Merge Draft Invoices modülünü geliştirdik. Bu sorun yalnızca bizi ilgilendirmediği için modülü özgür AGPL-3 lisansı altında GitHub'da ücretsiz olarak sunuyoruz.
GitHub'daki projeye git:
Neden OCA çözümü yerine kendi modülümüz?
OCA, account_invoice_merge'i uzun yıllardır OCA/account-invoicing deposunda sürdürüyor. Bu yazının yazıldığı sırada 19.0'a geçiş orada hâlâ açık bir pull request olup yayımlanmış bir modül değil.
Ancak daha önemlisi, iki modülün farklı şeyler yapmasıdır:
| OCA account_invoice_merge | Merge Draft Invoices | |
|---|---|---|
| Sonuç | seçilen faturalardan birine birleştirilir | her zaman yeni bir fatura |
| Kalemler | aynı kalemler birleştirilir, miktarlar toplanır | her kalem bire bir devralınır |
| Kaynak | invoice_origin / payment_reference başlıkta birbirine eklenir | kaynak alanları, her kalem için Odoo'nun kendi _copy_data_extend_business_fields hook'u üzerinden kopyalanır |
| Zaman kaydı | dikkate alınmaz | timesheet_invoice_id yeni faturaya aktarılır |
| Müşteri için okunabilir | hiçbir şey | her kaynağın kalemlerinin üzerinde sipariş ve talep bilgisini içeren bir başlık |
| Kaynak faturalar | iptal edilir | iptal etme (varsayılan), silme veya koruma – sonuçları açıkça belirtilmiş şekilde |
Aynı kalemlerin birleştirilmesi belirleyici farktır. Birleştirilmiş bir kalem yalnızca tek bir kaynak taşıyabilir. İki farklı siparişten gelen iki satır aynı göründüğü anda, faturadan siparişe, göreve ve zaman kaydına geri giden bağlantı kaybolur. Faturalandırmanın talep → zaman kaydı → fatura zinciriyle yürüdüğü bir hizmet işletmesinde bu, aynı saatlerin iki kez faturalandırılması veya kaybolması anlamına gelir.
Bu nedenle modülümüz prensip olarak hiçbir şeyi birleştirmez. Birleştirilmiş faturanın kalem sayısı, kaynaklarının toplam kalem sayısına tam olarak eşittir.
OCA modülünden hiçbir kod devralınmadı. Her iki modül de AGPL-3 altındadır.
Modül ne yapar
Fatura listesi görünümünde iki veya daha fazla taslağı işaretleyin, eylem menüsünden Taslak faturaları birleştir'i seçin – bir sihirbaz seçimi, kontrolleri ve kaynak faturalar için seçenekleri gösterir. Onayladıktan sonra doğrudan yeni faturaya gelinir.
Birleştirmeden önce modül kontrol eder ve tüm maddeleri tek seferde kontrol eder; böylece her düzeltmeden sonra bir sonraki hatayı görmek zorunda kalınmaz:
- en az iki fatura seçilmiş olmalı
- hepsi Taslak durumunda olmalı
- hiçbiri hiç kaydedilmemiş olmalı (taslağa geri alınmış bir belge kayıt geçmişini korur ve reddedilir)
- hiçbiri daha önce birleştirilmemiş olmalı
- hepsi fatura, tedarikçi faturası, alacak dekontu veya makbuz olmalı – salt yevmiye kayıtları olmamalı
- aynı iş ortağı, belge türü, şirket, para birimi ve yevmiye defteri
Ödeme koşulu, vergi eşlemesi, teslimat adresi, banka hesabı veya satış temsilcisindeki farklılıklar engellemez. Sihirbaz uyarır ve seçilen en eski faturanın değerini devralır.
Neler korunur
Modülün özü, bir fatura kaleminin kaynağıyla sahip olduğu her bağlantının yeni faturada da mevcut olmasıdır:
| Bağlantı | İşlem şekli |
|---|---|
| Satış siparişi kalemleri (sale_line_ids) | her kalem için Odoo'nun _copy_data_extend_business_fields'ı üzerinden kopyalanır |
| Satın alma siparişi kalemleri (purchase_line_id) | aynı şekilde |
| Maliyet merkezi dağılımı (analytic_distribution) | her kalem için kopyalanır |
| kalem başına diğer kaynak alanları | sağlayan modül belgelenmiş Odoo hook'unu uygularsa otomatik olarak |
| Fatura başlığındaki kaynak ve referans | birleştirilir, yinelenenler ayıklanır, sihirbazda düzenlenebilir |
| Satış siparişi: invoice_ids, invoice_status, qty_invoiced | kalemlerden hesaplanır – sipariş yeni faturayı kendiliğinden tanır |
| Zaman kaydı (timesheet_invoice_id) | kaynaklar geçersiz hale gelmeden önce yeni faturaya aktarılır |
| Helpdesk talebi | zaman kaydına bağlıdır ve böylece otomatik olarak yeni faturayı gösterir |
| Chatter | yeni faturada tüm kaynakları içeren bir mesaj, her kaynakta yeni faturaya bağlantı içeren bir mesaj |
| merged_into_move_id / merged_from_move_ids | her iki yönde kaydedilen bağlantı |
Vergi satırları, ödeme koşulu satırları, yuvarlama ve iskonto satırları kopyalanmaz; Odoo tarafından içerikten yeniden hesaplanır. Dolayısıyla birleştirilmiş faturada her kaynak için değil, her vergi oranı için bir vergi satırı bulunur. Numarasız bir taslak olarak oluşturulur; birleştirmenin kendisi bir belge numarası tüketmez.
Başlıklar: Müşteri her kalemin nereden geldiğini görür
Günlük kullanımda fark yaratan işlev budur. Modül, her kaynak faturanın kalemlerinin üzerine bir bölüm satırı ekler – Odoo'nun kendisinin “Peşinatlar” bölümü için kullandığı öğenin aynısı:
BE10181 <- Başlık
22,500 x Teknisyen saati 3.577,50
Ara toplam 3.577,50
BE10182 · Talep: HT00219 <- Başlık
3,000 x Teknisyen saati 477,00
Ara toplam 477,00
NET TUTAR 4.054,50
Başlık, müşterinin alacağı belgeye basılır ve Odoo'nun standart fatura raporu kendiliğinden her bölüm için bir ara toplam ekler. Böylece müşteri her bölümün maliyetini de görür.
Etiket, kaynağın gerçekte sahip olduğu bilgilerden oluşturulur:
- siparişler, doğrudan kalem bağlantılarından – adlar bu nedenle tam olarak doğrudur; sipariş bağlantıları eksikse invoice_origin içindeki serbest metin kullanılır
- talepler, zaman kaydı üzerinden belirlenir – Ticket: HT00219 veya Tickets: … olarak çıktılanır, beş ile sınırlıdır ve ardından “ve N tane daha” eklenir
- ikisi de yoksa: kaynak faturanın numarası, ardından referansı
- hiçbiri yoksa: nötr bir “Diğer kalemler”; böylece bir kaynağın satırları hiçbir zaman sessizce üstteki blokta kaybolmaz
Eksik olan atlanır, uydurulmaz. Talep, kendi numarasıyla basılır – helpdesk_mgmt numarası, Enterprise ticket_ref veya modelin görünen adı – asla veritabanı kimliğiyle (ID) değil.
Başlıklar, Odoo'nun siparişlerden fatura oluştururken yaptığı gibi müşterinin dilinde yazılır. Chatter, kullanıcının dilinde kalır.
Bir başlık ürün, miktar, fiyat, vergi, hesap veya maliyet merkezi dağılımı taşımaz. Toplamları, vergi matrahını ve maliyet hesaplamasını etkileyemez. Başlıkları sihirbazda kapatan, bu işlev olmadan oluşacak faturanın tıpatıp aynısını alır – bir test iki sonucu kuruşu kuruşuna karşılaştırır.
Kaynak faturalara ne olur
Sihirbaz üç seçenek sunar:
- İptal et (varsayılan, önerilen). Bir taslağı iptal etmenin sonucu yoktur: belge numarası yok, kayıt yok. Faturalar, sohbet geçmişi (chatter) ve yeni faturaya bağlantıyla birlikte iptal edilmiş belgeler olarak veritabanında kalır. Satış siparişindeki qty_invoiced iptal edilmiş belgeleri atlar, hiçbir şey iki kez sayılmaz. Altı ay sonra bile izlenebilir kalan seçenek budur.
- Sil. Geri alınamaz. Chatter ve geri başvuru kayıtla birlikte yok olur; yalnızca yeni faturadaki mesaj kalır. Kimsenin bir daha görmesini istemediği atılabilir taslaklar için anlamlıdır.
- Taslak olarak bırak. Kaynaklar açık kalır. Bu durumda satış siparişleri kaynağı ve yeni faturayı faturalanmış sayar – iş, biri taslakları elle temizleyene kadar iki kez faturalanmış gibi görünür. Karar vermeden önce karşılaştırma yapmak istenen nadir durum için tasarlanmıştır. Bir test tam olarak bu çift sayımı kayda geçirir, böylece kimseyi şaşırtmaz.
Sınırlar – modülün bilinçli olarak yapmadıkları
Lütfen canlı kullanımdan önce okuyun:
- Yalnızca taslaklar. Kaydedilmiş faturalar birleştirilmez. Bu bir alacak dekontu işidir, kopyalama işlemi değil.
- Bir kez kaydedilip geri alınmış taslaklar reddedilir. Bunların bir numarası ve kayıt geçmişi vardır; bunu başka bir belgenin içinde gizlemek, bir toplu işlemin sessizce halletmesi gereken bir şey değildir.
- Farklı iş ortakları, para birimleri, şirketler veya yevmiye defterleri arasında birleştirme yapılmaz. Bunun için anlamlı tek bir değer yoktur; bu yüzden modül tahmin yürütmek yerine reddeder.
- payment_reference devralınmaz. Yapılandırılmış ödeme referansları bir belgeyi tanımlar; birbirine eklenmiş iki referans bankada hiçbir şeyle eşleşmez. Yeni fatura, kaydedilirken kendi referansını alır.
- Peşinat kalemleri diğer kalemler gibi kopyalanır. Kaynaklar sale modülünden peşinat satırları içeriyorsa, sonuç kayıttan önce kontrol edilmelidir.
- Yalnızca timesheet_invoice_id otomatik olarak aktarılır. account.move'a Many2one alanı olan diğer her model (kendi faturalama çalıştırmaları, abonelik bağlantıları, EDI iletimleri) kaynağı göstermeye devam eder. Bunun için _merge_draft_relink hook'u vardır.
- Aynı kalemlerin birleştirilmemesi – bilerek. Kısa, derli toplu bir fatura isteyen kişi burada yanlış yerdedir ve bunun bedelini kaynak bağlantılarıyla öderdi.
- Başlıklar yalnızca birleştirme sırasında bir kez oluşturulur. Sonrasında normal bölüm satırlarıdır: düzenlenebilir, silinebilir ve sipariş veya talep sonradan yeniden adlandırılırsa güncellenmez.
- Bir başlık, tek tek kalemin değil, kaynak faturanın tamamının taleplerini belirtir.
Odoo 19 Community'de kurulum
Kurulum, olağan bir Odoo ek modülünde olduğu gibi yapılır:
- Modül klasörünü yapılandırılmış bir addons yoluna kopyalayın.
- Odoo'daki uygulama listesini güncelleyin.
- account_invoice_merge_draft modülünü kurun.
Modül yalnızca account'a bağlıdır. sale, purchase, project, hr_timesheet, sale_timesheet veya bir Helpdesk modülü hakkında bildiği her şey çalışma zamanında belirlenir – saf bir faturalama veritabanında da kurulur ve çalışır.
Sonrasında: Muhasebe → Müşteriler → Faturalar (veya Tedarikçiler → Faturalar), iki veya daha fazla taslağı işaretleyin, dişli menüsü → Taslak faturaları birleştir. Eylem, Faturalama / Fatura düzenleme grubuna sahip tüm kullanıcılar tarafından kullanılabilir.
Modülün önceki bir sürümünden güncelleme yapanlar, değişen alan etiketlerinin Almanca çeviriye yansıması için bir kez -u account_invoice_merge_draft --i18n-overwrite ile güncelleme yapmalıdır. Yeni kurulum bundan etkilenmez.
Geliştiriciler için: API ve hook'lar
Birleştirme kendi kodunuzdan da çağrılabilir:
python
merged = draft_moves.merge_draft_moves(
extra_vals={"invoice_date": date(2026, 3, 31), "ref": "Q1"},
source_handling="cancel", # "delete" veya "keep"
add_source_sections=True, # başlıklar; varsayılan True
)
merge_draft_moves, seçim birleştirilemiyorsa tüm ret gerekçelerini içeren bir UserError fırlatır. _merge_draft_get_errors() aynı gerekçeleri istisna (exception) oluşturmadan liste olarak döndürür.
account.move'a kendi geri başvurularınız varsa, _merge_draft_relink'i geçersiz kılın (override):
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}
)
Fatura kaleminde bir geri başvurusu olanların bu modüle hiç ihtiyacı yoktur: Odoo'nun kendi hook'u account.move.line._copy_data_extend_business_fields yeterlidir ve alan birleştirmede, iptalde ve çoğaltmada aynı şekilde devralınır. Diğer Helpdesk modülleri veya başlıkların farklı bir ifadesi için _merge_draft_get_source_tickets() ve _merge_draft_section_name() mevcuttur.
Canlı verilerde çalışmadan önce test edildi
48 test; karışık durumları, farklı iş ortaklarını, para birimlerini ve belge türlerini, satış veya satın alma siparişi olan ve olmayan kalemleri, vergileri, bölümleri ve notları, maliyet merkezi dağılımlarını, zaman kaydının aktarılmasını, kaynak faturalar için her üç seçeneği, sihirbazı ve başlıkları kapsar – başlıkların varsayılan olarak etkin olduğunu, kapatılmalarının eski sonucu kuruşu kuruşuna yeniden ürettiğini, bir başlığın tutar veya hesap taşımadığını, bir kaynağın kalemlerinin bir arada kaldığını, talebin numarasıyla göründüğünü ve asla veritabanı kimliğiyle (ID) görünmediğini.
Test verileri, AccountTestInvoicingCommon üzerine değil, etkin şirketin mevcut hesap planı üzerine kuruludur – bu yardımcı sınıf, taşınmış canlı veritabanlarında çoğu zaman başlamaz ve modülün çalışması gereken yer tam olarak bu tür veritabanlarıdır.
odoo-bin -d <db> -u account_invoice_merge_draft --test-enable \
--test-tags /account_invoice_merge_draft --stop-after-init
Muhasebe alanındaki her eklentide olduğu gibi, kurulumu önce kendi veritabanınızın bir kopyasıyla bir test ortamında denemenizi öneririz.
Odoo Community için ücretsiz ve açık kaynak
Biricon IT Services GmbH olarak çözümleri önce kendi işletmemizdeki somut gereksinimler için geliştiriyoruz. Bundan genel olarak kullanılabilir bir modül çıkarsa, onu tek bir kurulumun içinde saklamak istemiyoruz.
Merge Draft Invoices bu nedenle ücretsiz bir açık kaynak projesi olarak sunulmaktadır. Kaynak kodu incelenebilir, denetlenebilir, uyarlanabilir ve AGPL-3 lisansı çerçevesinde geliştirilmeye devam edilebilir.
Amacımız mümkün olan en kısa fatura değil, bir yıl sonra bile her kalemin siparişine, talebine ve zaman kaydına geri götürdüğü bir fatura oluşturmaktı.
Proje, kaynak kodu ve katkı
Kaynak kodunun tamamı, kurulum notları ve teknik belgeler GitHub'da mevcuttur:
Odoo 19 Merge Draft Invoices'ı GitHub'da aç
Pratik deneyimlere, hata raporlarına, iyileştirme önerilerine ve Odoo Community'den gelen katkılara açığız.
Ücretsiz. İzlenebilir. Açık kaynak. Odoo 19 Community için.