İçereği Atla
Rasard Dönüşüm — l10n_tr Modül Referansı
Türkiye Yerelleştirmesi · Odoo 18 Türkiye Localization · Odoo 18

Odoo'nun Türkiye'de bıraktığı boşlukları kapatan modüller

Rasard Dönüşüm paketinin Türkiye'ye özgü modülleri — Nilvera e-Fatura/e-İrsaliye, TCMB kur ve bordro. Her modülün kod seviyesinde ne yaptığı ve Odoo standardının yapmadığı somut nokta.

Modules that close the gaps Odoo leaves in Türkiye

The Türkiye-specific modules of the Rasard Dönüşüm package — Nilvera e-Invoice/e-Dispatch, TCMB FX rates and payroll. What each module does at code level and the concrete thing standard Odoo doesn't do.

0
Paketteki modül
Modules in package
0
l10n_tr modülü
l10n_tr modules
0
İşlevsel grup
Functional groups
A · Nilvera

e-Fatura Çekirdeği

e-Invoice Core

l10n_tr_nilvera_einvoice + account_edi_ubl_cii → extended_extensions → {send_draft · einvoice_pdf · extract_data_xml · defence_industry}
A1

l10n_tr_nilvera_einvoice_extended_extensions

Paketin e-fatura kalbi — GİB/Nilvera gerçeğine uyum katmanı
The e-invoice heart of the package — the GİB/Nilvera compliance layer

Odoo'nun resmî e-fatura + UBL katmanını GİB/Nilvera'nın gerçekte beklediği davranışa uyduran en kapsamlı modül.

Override
account.move (action_post, button_draft, create, _need_ubl_cii_xml, senaryo/tip compute'ları) · account.edi.xml.ubl.tr (_export_invoice, _export_invoice_vals, _get_note_vals_list, döviz kuru) · account.move.send · yeni account.move.sequence · ret wizard'ı
Anahtar mantık

· Fatura Serisi: şirket+tip bazında ayrı ir.sequence + hesap atamaları; post anında 16 haneli GİB belge no üretir.
· İade faturası: <CreditNote> yerine <Invoice> + InvoiceTypeCode=IADE üretir; BillingReference orijinal 16 haneli belge no'yu kullanır.
· Gelen iade tespiti: GET /einvoice/Purchase/{UUID}/Details → IADE ise saatlik cron faturayı out_refund'a çevirir.
· Onay/Ret: POST /einvoice/Purchase/SendAnswer.
· Senaryo/tip alanlarını gönderim sonrası silinmekten korur; narration'ı tek Note'ta birleştirir.

The most extensive module, aligning Odoo's official e-invoice + UBL layer with what GİB/Nilvera actually expect.

Override
account.move (action_post, button_draft, create, _need_ubl_cii_xml, scenario/type computes) · account.edi.xml.ubl.tr (_export_invoice, _export_invoice_vals, _get_note_vals_list, FX rate) · account.move.send · new account.move.sequence · reject wizard
Key logic

· Invoice series: per company+type ir.sequence + account defaults; mints the 16-digit GİB document number on post.
· Return invoice: emits <Invoice> + InvoiceTypeCode=IADE instead of <CreditNote>; BillingReference uses the original 16-digit number.
· Inbound return detection: GET /einvoice/Purchase/{UUID}/Details → if IADE, an hourly cron flips the move to out_refund.
· Approve/Reject: POST /einvoice/Purchase/SendAnswer.
· Protects scenario/type fields from being cleared after sending; merges narration into one Note.

Odoo bunu yapmıyor
Odoo doesn't do this

Bağımsız GİB belge no yönetimi yok; iade <CreditNote> olarak üretilir (Nilvera 2017 hatasıyla reddeder); senaryo alanı gönderim sonrası silinir; gelen faturanın iade niteliği sorgulanmaz.

No independent GİB number management; returns are emitted as <CreditNote> (Nilvera rejects with error 2017); the scenario field is wiped after sending; an inbound invoice's return status is never queried.

A2

l10n_tr_nilvera_send_draft

Göndermeden önce taslak önizleme + PDF
Draft preview + PDF before final send
Override
account.move._l10n_tr_nilvera_submit_einvoice / _submit_earchive / _submit_document

nilvera_preview=True context'inde gerçek gönderim yerine POST /einvoice/Upload ile taslak yükler, UUID saklar. Yeni taslaktan önce eskisini DELETE /einvoice/Draft ile siler ("canlıda taslak var" hatasını önler). Partner template_uuid varsa taslak PDF = gerçek şablon.

Override
account.move._l10n_tr_nilvera_submit_einvoice / _submit_earchive / _submit_document

With nilvera_preview=True context it uploads a draft via POST /einvoice/Upload instead of sending, storing the UUID. Deletes the old draft (DELETE /einvoice/Draft) before a new one. If the partner has a template_uuid, the draft PDF matches the real template.

Odoo bunu yapmıyor
Odoo doesn't do this

UBL'i göndermeden önce önizleme/taslak görme akışı yoktur.

There is no preview/draft step before the UBL is actually sent.

A3

l10n_tr_nilvera_einvoice_pdf

Doğru PDF eki (base bug fix) + toplu mail
Correct PDF attach (base bug fix) + bulk email

Base modül /pdf yanıtındaki base64'ü doğrudan raw'a koyduğundan PDF bozuk açılır. Bu modül %PDF- magic kontrolüyle gerekirse decode eder. Tekil/çoklu PDF indirme ve fatura başına mail.mail ile toplu e-posta; listede iki server action.

The base module puts the /pdf base64 straight into raw, so the PDF opens corrupted. This module checks the %PDF- magic and decodes when needed. Single/bulk PDF download and bulk email via per-invoice mail.mail; two list server actions.

Odoo bunu yapmıyor
Odoo doesn't do this

Nilvera PDF'ini doğru biçimde faturaya bağlamaz; toplu PDF e-posta yoktur.

Doesn't attach the Nilvera PDF correctly; there is no bulk PDF email.

A4

l10n_tr_nilvera_extract_data_xml

Ham GİB e-fatura XML'ini faturaya aktarır
Imports raw GİB e-invoice XML into a move

ORM-dışı NilveraParser (namespace-agnostic lxml): satırlar, parti, birim fiyat, miktar, iskonto (ChargeIndicator=false → yüzde), vergi ve ürün kodlarını çıkarır. Wizard XML'i yükler → cari VKN/isimle bulur/oluşturur → satırları kurar.

An ORM-free NilveraParser (namespace-agnostic lxml) extracts lines, party, unit price, quantity, discount (ChargeIndicator=false → percent), tax and product codes. The wizard loads the XML → finds/creates the partner by VKN/name → builds the lines.

Odoo bunu yapmıyor
Odoo doesn't do this

Standart UBL import yalnızca Odoo-uyumlu UBL 2.0/2.1 işler; ham GİB XML'ini faturaya parse etmez.

Standard UBL import only handles Odoo-compatible UBL 2.0/2.1; it doesn't parse raw GİB XML into a move.

A5

l10n_tr_nilvera_purchase_pagination

Gelen alış faturalarını tarihe göre sayfalı çeker
Paginated fetch of incoming purchase invoices by date

İki base bug'ı patch'ler: response.get('Content') or [] ile None gelince TypeError engellenir; if not last_fetched_date ile çekim tarihi her seferinde sıfırlanmaz. Her UUID ayrı cr.commit().

Patches two base bugs: response.get('Content') or [] prevents a TypeError when None is returned; if not last_fetched_date stops the fetch date being reset each run. Each UUID gets its own cr.commit().

Odoo bunu yapmıyor
Odoo doesn't do this

Base modül Content=None'da patlar ve fetch tarihini geri sıfırlar; toplu çekimde sayfalama güvenli değil.

The base crashes on Content=None and resets the fetch date; bulk fetch pagination isn't safe.

A6

l10n_tr_nilvera_credit_status

Nilvera kontör bakiyesini şirket bazında izler
Tracks Nilvera credit balance per company

Yeni nilvera.credit modeli. GET /general/Credits → şirket vatTaxNumber ile eşleştirilir → module_id bazında upsert. Saatlik cron her API key'li şirket için çalışır; renkli kontör kartı (kanban/SCSS).

New nilvera.credit model. GET /general/Credits → company vat matched to TaxNumber → upsert by module_id. An hourly cron runs per API-keyed company; colored credit card (kanban/SCSS).

Odoo bunu yapmıyor
Odoo doesn't do this

Nilvera kontörünü hiç göstermez; kontör bitince gönderim sessizce durur.

Never surfaces Nilvera credit; when it runs out, sending silently stops.

A7

l10n_tr_nilvera_defence_industry

Savunma sanayii (ASELSAN vb.) için zorunlu UBL alanları
Mandatory UBL fields for defence industry (ASELSAN etc.)

Alanlar: partner template_uuid, is_aselsan; satırda sas_no, alici_kodu, local_rate, buyers_item_code; faturada is_kobi, eydep_bilgisi. TemplateUUID gönderim endpoint'ine ?TemplateUUID= ekler; KOBİ/EYDEP → <AdditionalDocumentReference>; satır kodları <BuyersItemIdentification>'a basılır, SO→fatura→stock.move boyunca yayılır.

Fields: partner template_uuid, is_aselsan; on lines sas_no, alici_kodu, local_rate, buyers_item_code; on the move is_kobi, eydep_bilgisi. TemplateUUID appends ?TemplateUUID= to the send endpoint; KOBİ/EYDEP → <AdditionalDocumentReference>; line codes go to <BuyersItemIdentification>, propagated SO→invoice→stock.move.

Odoo bunu yapmıyor
Odoo doesn't do this

UBL'de KOBİ/EYDEP, SAS kalem no, alıcı ürün kodu, Nilvera şablon seçimi kavramları yoktur.

UBL has no concept of KOBİ/EYDEP, SAS item no, buyer item code, or Nilvera template selection.

B · Nilvera

e-İrsaliye

e-Dispatch

l10n_tr_nilvera_edispatch (XML üretir) → e_dispatch_sender (gönderir) → {dispatch_series · dispatch_pdf · account_lot_informations}
B1

l10n_tr_nilvera_e_dispatch_sender

e-İrsaliye XML'ini Nilvera'ya gönderim katmanı
The layer that sends e-dispatch XML to Nilvera

Alanlar: send_status (draft/sending/sent/error), response_uuid, ettn, delivery_notes. İki endpoint: POST /edespatch/Send/Xml (gerçek) ve /edespatch/Upload (taslak+PDF). Mükellef değilse sabit GİB posta kutusu yazılır. Cron (varsayılan pasif): done+to_send irsaliyeler, 30 dk, limit 50.

Fields: send_status (draft/sending/sent/error), response_uuid, ettn, delivery_notes. Two endpoints: POST /edespatch/Send/Xml (real) and /edespatch/Upload (draft+PDF). For non-registered partners a fixed GİB mailbox is written. Cron (off by default): done+to_send dispatches, 30 min, limit 50.

Odoo bunu yapmıyor
Odoo doesn't do this

Base modül XML üretir ama Nilvera'ya gönderim katmanı yoktur.

The base module generates XML but has no layer to send it to Nilvera.

B2

l10n_tr_nilvera_dispatch_series

Operasyon tipinden bağımsız özel <cbc:ID> serisi
Custom <cbc:ID> series independent of operation type

Yeni l10n.tr.nilvera.dispatch.series (3 karakter, şirket bazlı unique). UBL'de <cbc:ID> = series_id.code or picking_type.sequence_code. Gönderim öncesi seri boşsa UserError.

New l10n.tr.nilvera.dispatch.series (3 chars, unique per company). In UBL <cbc:ID> = series_id.code or picking_type.sequence_code. UserError if the series is empty before sending.

Odoo bunu yapmıyor
Odoo doesn't do this

Seri picking_type.sequence_code'a sabittir; şirket bazlı serbest seri seçilemez.

The series is fixed to picking_type.sequence_code; no free per-company series.

B3

l10n_tr_nilvera_dispatch_pdf

GİB onaylı e-irsaliye PDF'ini API'den çeker
Fetches the GİB-approved e-dispatch PDF from the API

GET /edespatch/Sale/{uuid}/pdfir.attachment (Eirsaliye-{name}.pdf) + chatter + tarayıcı indirme. Buton send_status in (sent, succeed, waiting) iken görünür.

GET /edespatch/Sale/{uuid}/pdfir.attachment (Eirsaliye-{name}.pdf) + chatter + browser download. Button shows when send_status in (sent, succeed, waiting).

Odoo bunu yapmıyor
Odoo doesn't do this

GİB onaylı e-irsaliye PDF'ini çekmez (yalnızca XML üretir).

Doesn't fetch the GİB-approved e-dispatch PDF (only generates XML).

B4

account_lot_informations

Lot/seri bilgisini UBL irsaliyeye köprüler
Bridges lot/serial info into the UBL dispatch

stock.picking.button_validate override: onaydan sonra lot'lu satırları ürün bazında gruplayıp delivery_notes'a yazar → sender template'i üzerinden <cbc:Note>'a dönüşür. "Lot Bilgileri" varsa tekrar eklemez (idempotent).

Overrides stock.picking.button_validate: after validation it groups lot lines by product into delivery_notes → becomes <cbc:Note> via the sender template. Won't re-add if "Lot Bilgileri" already present (idempotent).

Odoo bunu yapmıyor
Odoo doesn't do this

Standart transfer onayı lot/seri bilgisini UBL irsaliyeye taşımaz.

Standard transfer validation doesn't carry lot/serial info into the UBL dispatch.

C · TCMB

Döviz Kuru

FX Rate

C1

l10n_tr_tcmb_currency_type_rs

Şirket bazında TCMB kur tipi seçimi (efektif dahil)
Per-company TCMB rate-type selection (incl. banknote)

Override res.company._parse_tcmb_data. Yeni alan tr_currency_type: ForexBuying / ForexSelling / BanknoteBuying / BanknoteSelling. XML'den currency.find(company.tr_currency_type) ile seçili tip alınır.

Overrides res.company._parse_tcmb_data. New field tr_currency_type: ForexBuying / ForexSelling / BanknoteBuying / BanknoteSelling. The chosen type is read via currency.find(company.tr_currency_type) from the XML.

Odoo bunu yapmıyor
Odoo doesn't do this

Standart parse sabit (ForexBuying+ForexSelling)/2 ortalaması alır; tip seçilemez, efektif kurlar desteklenmez.

The standard parse takes a fixed (ForexBuying+ForexSelling)/2 average; no type choice, banknote rates unsupported.

Dikkat: run_update_currency override'ında currency_next_execution_date <= today domain filtresi kaldırılmış — her cron'da tüm şirketler güncelleme kuyruğuna girer. İstenmeyen davranışsa gözden geçirilmeli. Heads-up: the run_update_currency override drops the currency_next_execution_date <= today domain filter — every cron run enqueues all companies. Review if that's not intended.
D · HR

Türkiye Bordrosu

Türkiye Payroll

l10n_tr_hr_payroll (+ _account) → payroll_tr_rasard → payroll_tr_rasard_arge
D1

l10n_payroll_tr_rasard

Kümülatif gelir vergisi + net→brüt + TDHP muhasebe
Cumulative income tax + net→gross + TDHP accounting

İki yapı: TRRASARD (aylık ücret), TRKIDEM (kıdem/ihbar). Tüm rule'lar tek _l10n_tr_compute_components() sözlüğünü okur — hesap drift'i yok.

Kümülatif GV (KGVM)

_l10n_tr_prev_cumulative_base() yıl başından bu aya kadar onaylı bordroların GVMATRAH'ını _sum() ile toplar; marjinal vergi = income_tax(önceki+matrah) − income_tax(önceki). Asgari ücret istisnası da kümülatif → Temmuz zammı ve dilim geçişi doğru.

Net → Brüt

_l10n_tr_gross_from_net() bisection, [net, net×3], 200 iterasyon, 0.005 TL hassasiyet.

Muhasebe
770 gider / 335 net / 360 vergi / 361 SGK; departman bazlı gider hesabı; post_init_hook hesap eşlemesini otomatik kurar.

Two structures: TRRASARD (monthly wage), TRKIDEM (severance/notice). All rules read one _l10n_tr_compute_components() dict — no calculation drift.

Cumulative income tax

_l10n_tr_prev_cumulative_base() sums GVMATRAH of confirmed payslips from year start to this month via _sum(); marginal tax = income_tax(prev+base) − income_tax(prev). The minimum-wage exemption is also cumulative → the July raise and bracket crossing are correct.

Net → Gross

_l10n_tr_gross_from_net() bisection, [net, net×3], 200 iterations, 0.005 TL precision.

Accounting
770 expense / 335 net / 360 tax / 361 SSI; per-department expense account; post_init_hook auto-maps the accounts.
Odoo bunu yapmıyor
Odoo doesn't do this

Resmî modül gelir vergisini her ay sıfırdan hesaplar → yıl içi dilim geçişleri ve Temmuz asgari ücret zammı yanlış çıkar.

The official module computes income tax from zero each month → in-year bracket crossings and the July minimum-wage raise come out wrong.

D2

l10n_payroll_tr_rasard_arge

5746 Ar-Ge/Tasarım bordro teşvikleri
Law 5746 R&D/Design payroll incentives

TRRASARD'a 4 rule ekler. _l10n_tr_arge(gross): terkin oranı eğitime göre (%95 doktora / %90 yüksek / %80 diğer), 40× asgari ücret tavanı (7555 s.K., 01.08.2025), aylık Ar-Ge çalışma oranı, SGK işveren %50 Hazine desteği.

RuleNet etki
ARGEGVTERKIN+ terkin (ayara bağlı net'e yansır)
ARGEDAMGAIST+ damga istisnası
ARGESGKDESTEK− %50 işveren SGK (net'i etkilemez)

Net sözleşmeli Ar-Ge personelinde çözücü teşvik-bilinçli: hedef net = net + terkin + damga.

Adds 4 rules to TRRASARD. _l10n_tr_arge(gross): abatement rate by education (95% PhD / 90% masters / 80% other), 40× minimum-wage cap (Law 7555, 2025-08-01), monthly R&D work ratio, employer SSI 50% Treasury support.

RuleNet effect
ARGEGVTERKIN+ abatement (reflects to net per setting)
ARGEDAMGAIST+ stamp duty exemption
ARGESGKDESTEK− 50% employer SSI (no net effect)

For net-contract R&D staff the solver is incentive-aware: target net = net + abatement + stamp.

Odoo bunu yapmıyor
Odoo doesn't do this

Odoo'da Ar-Ge/Tasarım merkezi teşvikleri (5746) tamamen yoktur.

Odoo has no R&D/Design center incentives (Law 5746) at all.

D3

l10n_tr_leave_public_holidays

2025–2030 Türkiye resmî ve dini tatilleri
Türkiye public & religious holidays, 2025–2030

Model değişikliği yok; resource.calendar.leaves data (noupdate=1). Her yıl 7 ulusal + 3 gün Ramazan + 4 gün Kurban; tam/yarım gün.

No model change; resource.calendar.leaves data (noupdate=1). Each year 7 national + 3-day Ramadan + 4-day Sacrifice holidays; full/half day.

Odoo bunu yapmıyor
Odoo doesn't do this

Odoo'da TR resmî tatil takvimi gelmez; elle girilir.

Odoo ships no TR public-holiday calendar; it must be entered by hand.

★ En kritik fark
★ The most critical difference

Bordroda gelir vergisi her ay değil, kümülatif

Payroll income tax is cumulative, not monthly-from-zero

Resmî l10n_tr_hr_payroll gelir vergisini her ay sıfırdan hesaplar — yıl içi dilim geçişleri ve Temmuz asgari ücret zammı yanlış çıkar. Bu paket kümülatif matrah (_sum('GVMATRAH')), kümülatif asgari ücret istisnası, net→brüt çözücü, 5746 Ar-Ge teşvikleri, TDHP muhasebe (335/360/361/770) ve 2024–2026 güncel parametrelerle bunu mevzuata uydurur.

The official l10n_tr_hr_payroll computes income tax from zero each month — in-year bracket crossings and the July minimum-wage raise come out wrong. This package fixes it to the law with a cumulative base (_sum('GVMATRAH')), cumulative minimum-wage exemption, a net→gross solver, Law 5746 R&D incentives, TDHP accounting (335/360/361/770) and up-to-date 2024–2026 parameters.

Rasard Dönüşüm · Odoo 18 · 28 modül, 14 l10n_tr modülü kod seviyesinde incelendi. Rasard Dönüşüm · Odoo 18 · 28 modules, 14 l10n_tr modules reviewed at code level.