Slovenian Tax Addons — Technical Guide
l10n_si_tax_addons provides Slovenian VAT reporting for Odoo 18 Community:
DDV-O returns, KIR/KPR VAT books, PD-O supplies, RP-O recapitulative statements,
Tax Balance integration, and controlled correction workflows.
This guide describes the current module architecture, reporting rules, and extension points. For accountant workflows and screen-level instructions, see the user manual and module overview.
Contents
- Architecture and dependencies
- Reporting dates and accounting locks
- Tags and report mappings
- DDV-O contribution service
- VAT books and prepayment reporting
- Reports and exports
- Correction workflows
- Persistent VAT review
- Access and company isolation
- Extension points and reporting constraints
Architecture and dependencies
The module separates accounting evidence, report routing, contribution calculation, and output formatting:
Posted journal items + Tax Dates + tax tags + prepayment source links
|
+-- DDV-O contribution service --> DDV-O PDF/XML and tag-based Tax Balance
| +--> PD-O issued-base contributions
|
+-- VAT-book mappings + SQL views --> KIR/KPR XML, XLSX, charged/deducted exports
|
+-- Issued-book mappings --> RP-O partner totals
Explicitly recorded findings --> VAT review evidence --> append-only decisions
The manifest declares these dependencies:
| Dependency | Role |
|---|---|
pmis_account_dates |
Shared header and journal-item accounting dates |
account |
Journal entries, taxes, tax tags, and repartitions |
l10n_si2, l10n_si_config |
Slovenian accounting configuration and tax definitions |
account_fiscal_month |
Fiscal-month periods |
account_tax_balance, account_financial_report |
Accounting report and Tax Balance integration |
report_xlsx |
Spreadsheet report output |
l10n_si_prepayment_invoice |
Advance VAT, settlement links, and reporting allocations |
Slovenian date behavior is enabled by res.company.l10n_si_accounting.
Report routing also depends on tax tags, tax repartitions, and country-specific
mappings; enabling the company option alone does not define report destinations.
The package imports models, wizards, and reports through their respective
__init__.py files. The post-install hook initializes DDV-O
mappings, installs VAT-book reference mappings, prepares eligible draft dates,
and refreshes reporting allocations for linked posted outgoing invoices.
These are installation side effects, separate from report calculation.
Reporting dates and accounting locks
The canonical account.move.tax_date and account.move.line.tax_date fields
come from pmis_account_dates. The
journal-entry extension adds:
invoice_date_received: vendor document receipt date.l10n_si_tax_date: editable related alias of the headertax_date.l10n_si_tax_date_manual: tracks an independently selected date on eligible ordinary journal entries.l10n_si_obravnava,l10n_si_obdobje88, andl10n_si_davek88: correction treatment metadata.
Conflicting values supplied for tax_date and its related alias are rejected.
Date selection and propagation
For Slovenian invoices and receipts, the default Tax Date uses:
| Document | Default Tax Date |
|---|---|
| Customer invoice, receipt, or credit note | Fiscal Date, falling back to accounting date |
| Vendor bill, receipt, or credit note | Date Received, then Fiscal Date, then accounting date |
| Ordinary general journal entry | Header Tax Date, initially following accounting date |
A selected header Tax Date is used when preparing eligible documents for posting. Posting propagates it to accountable journal items, excluding sections and notes. Generated prepayment entries use their dedicated date preparation. Date-driver updates keep default-following values synchronized while preserving independently selected dates.
Copies clear inherited journal-item Tax Dates. Slovenian invoice copies and reversals default their Fiscal Date from their own accounting date unless the caller explicitly supplies one.
The Settings Administrator server actions in
data/server_actions.xml initialize or realign
drafts only. Their entry point is
account.move._l10n_si_tax_addons_initialize_dates(force=False).
Explicit selections are validated before writing; finalized records cannot be
changed through these initializers.
Locks and report selection
The journal-item extension protects posted VAT evidence when dates or relevant accounting fields change. Posting validates the selected dates against applicable accounting locks. Controlled corrections have their own authorization checks, described below.
DDV-O selects posted journal items by their actual tax_date; items without
one are excluded. The VAT-book SQL views expose fallback dates when source Tax
Dates are absent: KIR uses accounting date, while KPR uses the available receipt
or accounting date. These view values do not populate missing journal-item dates.
Tags and report mappings
DDV-O and VAT books use separate routing models:
| Model | Purpose | Source |
|---|---|---|
account.tax.ddvo.tag.map |
Tax tag to DDV-O box, with optional country and active flag | account_tax_ddvo_map.py |
account.tax.book.tag.map |
Tax tag to issued/received book field, with optional country and active flag | account_tax_book_tag_map.py |
account.tax.book.fields |
Column definitions with type I (issued) or P (received) and position |
account_tax_book_fields.py |
account.report.line extension |
tax_book_issued_id and tax_book_received_id links |
account_tax_report_line.py |
DDV-O routing
hooks.DDVO_BOX_TO_TAGS defines canonical Slovenian tag-code destinations.
The contribution service combines these with active explicit mappings as a set
of (tag, box) destinations. Duplicate routes count once; one tag can
intentionally contribute to several boxes.
Eligible tags must be active and tax-applicable. Tags and mappings are restricted
to the company's effective fiscal country
(account_fiscal_country_id, falling back to country_id) or global scope.
Canonical Slovenian routes apply only for an effective Slovenian country.
A company without an effective country can use only global destinations.
VAT-book defaults and tag lookup
data/tax_book_defaults.csv supplies the reference
VAT-book routes. _install_reference_defaults() adds missing mappings while
preserving archived mappings and custom destinations. Installation calls this
method directly.
_generate_from_tax_reports() also supports deriving additional routes from
report-line tax_tags expressions and linked book fields. It is a configuration
helper, separate from the report readers.
Tax-tag names are translatable. Canonical code lookup uses
with_context(lang="en_US") to resolve signed names consistently regardless of
the user's language. Keep that context local to tag lookup.
DDV-O contribution service
The abstract model l10n_si.ddvo.contribution.service in
ddvo_contribution.py centralizes tag routing,
prepayment source resolution, contribution signs, aggregation, and rounding.
Contribution amounts
For a ledger contribution to one tag and destination:
amount = line.balance
× (-1 if line.tax_tag_invert else +1)
× (-1 if tag.tax_negate else +1)
tax_tag_invert is Odoo's ledger-to-tax-grid normalization; tax_negate
belongs to the individual tag. Journal type and refund move type do not add
separate ordinary sign multipliers.
Advance base contributions use:
amount = line.tax_base_amount × (-1 if base_tag.tax_negate else +1)
The stored tax base already includes reporting inversion. Applying
tax_tag_invert again would invert it twice. Invoice/refund base destinations
come from the source tax repartition, including on general entries. Missing
source references are resolved only when company-scoped evidence is unambiguous.
Service interfaces
| Method | Result and caller responsibility |
|---|---|
get_contributions(lines, company=None, include_prepayment_base=True, tag_destinations=None) |
Structured contributions for the selected company; callers select the reporting population |
aggregate_boxes(lines, company=None) |
Decimal box totals with settlement grouping and applicable caps |
round_report_boxes(lines, company=None) |
Totals for dated lines, rounded once for the complete population |
round_boxes(box_totals) |
Whole-euro box values and calculated payable/refundable difference |
aggregate_tax_balances(taxes, lines, round_int=False) |
Tax/base and regular/refund amounts routed to target taxes |
scalar_values(lines) |
Per-line scalar values and ambiguity warnings for drill-down |
Each contribution contains the line, tag, destination box, source kind and amount, native/tag factors, signed Decimal amount, source-tax information, deduplication identity, and diagnostic classification. The service filters by company; the low-level contribution method does not itself impose posted state or a reporting date range.
Amounts are converted through decimal string representations. Report totals use
Decimal and ROUND_HALF_UP, with rounding after aggregation. Boxes 51 and
52 are mutually exclusive non-negative differences between output and deductible
VAT.
Prepayments and settlement caps
prepayment_tax_base_key identifies a shared source base within a move.
Advance components sharing that identity contribute once per tag and destination;
different source lines remain distinct. Conflicting amounts for the same shared
base raise an error. Lines without a shared identity are treated separately.
Settlement applications linked to an originating invoice are grouped with that invoice before capping eligible box totals at zero. Refund moves and standalone settlement/neutralizer groups retain their signed amounts. Consumers requiring report totals must use the aggregation interface so this population-level rule is included.
Tax Balance and journal-item diagnostics
The Tax Balance extension supports standard tax-ID calculation and DDV-O tag calculation. The Open Taxes wizard defaults to DDV-O tags, Tax Date selection, and whole-euro rounding.
Relevant context keys are tax_balance_use_tags,
tax_balance_date_field, tax_balance_round_int, and
tax_balance_drilldown_ddvo_view. Tag mode delegates to the contribution
service and deduplicates a tag routed to several boxes for each target tax.
Tax Balance includes tax-exigibility filtering; the DDV-O wizard selects posted
dated items without that additional filter.
account.move.line.ddvo_balance is a diagnostic scalar, populated only when
a line has one distinct tag/box contribution. Ambiguous lines return zero with
ddvo_contribution_warning. Standard field aggregation is disabled.
The specialized ungrouped read_group supports sums, including Odoo aliases,
and rejects ambiguous populations; grouped scalar aggregation is rejected.
Use structured contributions for grouping by destination.
VAT books and prepayment reporting
The read-only ORM models
account.tax.records.issued and
account.tax.records.received
use SQL views (_auto = False). Their init() methods define the views.
Rows aggregate posted evidence by reporting dimensions and expose document,
partner, period, correction metadata, and monetary columns.
Active VAT-book mappings determine column inclusion. The views support invoice
and receipt evidence, mapped ordinary general entries, and dedicated prepayment
paths. An ordinary general entry can appear in KIR, KPR, or both according to its
tags. For that path, signs use tax_tag_invert and each tag's direction.
Partnerless mapped general entries remain reportable, with empty partner details
in XML/XLSX. KPR uses the entry number when an ordinary entry has no reference,
and accounting date when it has no receipt date.
account.fiscal.position.partner_outside_eu supplies a non-EU reporting marker.
KIR derives advance bases from source repartitions and deduplicates shared
prepayment_tax_base_key destinations. Durable allocations from
pmis.prepayment.reporting.allocation.service reduce follow-up invoice amounts
already covered by advances. Raw settlement lines are not counted again in KIR.
The combined KIR/KPR export refreshes period reporting allocations before reading the views. This updates derived allocation records; it does not rewrite posted accounting amounts. The SQL views themselves are read-only.
Reports and exports
Report wizards prepare data and return Odoo report or download actions. PDF adapters and QWeb templates live in reports/; bundled XML schemas live in xsd/. Generating files does not submit them to eDavki or amend previously submitted artifacts.
| Output | Entry points | Data path |
|---|---|---|
| DDV-O PDF/XML | account_tax_ddvo_report.py: prepare_dict(), action_print_pdf(), action_generate_xml() |
Posted items for the active company and Tax Date range → contribution service → rounded boxes |
| KIR/KPR XML ZIP and XLSX | account_tax_kir_kpr_report.py: _get_export_data(), create_report(), action_export_xlsx() |
Period allocation refresh → SQL views → shared prepared rows |
| PD-O PDF/XML | account_tax_pdo_report.py: prepare_pdo(), create_export() |
Issued-book position 8 → contribution service with explicit destinations → commercial-partner VAT totals |
| RP-O PDF/XML | account_tax_rpo_report.py: _prepare_rpo_data(), create_export() |
Issued-book positions 10.a, 10.b, 11, 10.d, and 10.c → partner/category totals |
| Charged VAT text | account_tax_charged_export.py: create_export() |
Issued VAT-book rows |
| Deducted VAT text | account_tax_deducted_export.py: create_export() |
Received VAT-book rows |
KIR/KPR XML is validated against DDV_KIR_KPR_1.xsd and packaged as
kir_kpr_report.xml in a ZIP. XLSX uses the same prepared report data.
PD-O includes signed advance bases and settlement offsets; it does not subtract
durable allocations again. RP-O restricts routing to issued-book mappings, so
received-book columns with identical position numbers do not enter its totals.
The separate tax-period clearance wizard aggregates posted Tax Date balances on accounts from the journal company's tax repartitions. It creates a draft period-end entry with contra-lines and an optional balancing account. Posting and reconciliation remain explicit accounting operations.
Correction workflows
The module exposes distinct actions with different effects:
| Workflow | Scope and effects | Implementation |
|---|---|---|
| Change Tax Date | Reviewed date-only correction on posted documents; changes accountable line dates and header tracking while preserving accounting amounts and reconciliations | l10n_si_tax_date_change.py |
| Correct Omitted Output VAT | Reschedules a whole eligible output-VAT document and records Article 88.b metadata and chatter | omitted_vat_correction.py |
| Legacy-prepayment VAT correction | Previews a reclassification proposal and creates a separate draft correction entry | legacy_prepayment_vat_correction.py |
| Prepayment adjustment date | Extends the dependency's adjustment-date wizard to update accountable Tax Dates on reposting | pmis_prepayment_neutralizer_date.py |
| VAT Correction and Internal Document Options | Opens existing correction metadata for the implemented option; other choices display guidance | slovenian_vat_correction_options.py |
Date-only corrections
The Tax Date wizard requires Accounting Manager access, a reason, confirmation of reporting review, and a reviewed source snapshot. Mixed line dates require explicit confirmation. Changed inputs or source evidence invalidate the review; the selection applies atomically.
Missing dates or tax-locked dates require a Settings Administrator who also has Accounting Manager access to review and authorize their own wizard. Authorization creates a native user-specific Tax Return Lock exception lasting at most one hour, revoked after successful application. While active, that exception can affect other operations by the same user. Hard locks cannot be excepted. Other applicable locks still require their own native authorization.
Omitted output VAT and correction metadata
The omitted-VAT action accepts eligible posted customer invoices, receipts, and advance VAT-on-receipt entries. It requires one register row, a consistent original Tax Date, confirmed output VAT, an original monthly or quarterly period, and a new open-period Tax Date. Unsupported partial omissions, existing correction treatment, and invoices with posted settlement applications are rejected.
The action sets OBRAVNAVA=2, OBDOBJE88, and DAVEK88 together with
journal-item Tax Dates. It preserves posted accounting amounts, dates, tax tags,
and reconciliation. DDV-O XML groups correction components by original period.
Treatment 1 is ordinary reporting; treatment 2 represents a prior-period
correction with interest; treatment 3 represents interest only when the
underlying correction is already represented. Supported treatment 2/3 documents
require an eight-digit OBDOBJE88 and signed nonzero DAVEK88.
These values describe correction treatment; contribution signs continue to
follow source amounts and tags. The module does not create an interest
accounting entry.
Prepayment reclassification
The correction wizard requires a preview, reason, and explicit accountant
confirmation. Execution checks a source/proposal fingerprint, serializes the
correction identity, and rejects stale, duplicate, or blocked proposals.
It creates a draft neutralizer correction with
prepayment_correction_origin_ids and records the reviewed fingerprint and
reason in chatter. Original invoices are not rewritten.
Persistent VAT review
l10n_si.vat.review stores findings linked to
journal items, with an analysis identity, category, reason, DDV-O boxes,
canonical JSON snapshot/hash, capture timing, and company-checked source links.
Authorized callers supply findings explicitly; ordinary report generation does
not automatically record a finding for every item.
_record_evidence(values) is the private idempotent recording interface.
The identity is (company_id, line_id, analysis_key, category). Identical
evidence returns the existing finding; conflicting evidence requires a new
analysis revision. A company/analysis transaction lock serializes ingestion.
l10n_si.vat.review.event stores append-only decisions and maintenance
events. The server assigns actor and time. The latest human decision determines
the outcome: pending, accepted, correction required, or corrected. Repair events
do not constitute accountant acceptance. Withdrawal removes a finding from the
outstanding worklist while preserving evidence and human decisions.
Evidence and event editing/deletion are prohibited through the ORM, including
superuser calls. This is an application-level boundary. Decisions use the
review wizard without changing journal items.
Journal-item indicators use batched nonstored computation; stored indexed
outstanding and withdrawn fields support filtering.
Access and company isolation
ACLs and record rules define access alongside method checks:
- Accounting users can generate reports and read VAT-book rows and mappings. Accounting Managers can maintain book-field definitions and create/delete mappings; mapping write access is not granted by the shipped ACLs.
- Accounting Managers can use tax-period clearance and the omitted-VAT and date-only correction wizards.
- Fiscal Operator and Fiscal Manager, under Accounting / SI Taxes in user access rights, have legacy-prepayment correction ACLs. Manager implies Operator.
- Accounting read-only users and accountants can inspect VAT review evidence; accountants append decisions, and Accounting Managers can create findings. Repair/withdrawal events require maintenance access.
- Global company rules restrict VAT-book rows, VAT review evidence/history, and correction wizards. Source access and company ownership are independently checked by the guarded workflows.
Extension points and reporting constraints
- Reuse
l10n_si.ddvo.contribution.servicefor DDV-O signs and rounding. Supply the intended company, date range, and posted/exigibility policy before calling its low-level interfaces. - Use explicit
tag_destinationsfor a specialized contribution consumer, as PD-O does. They replace the normal DDV-O destinations for that call. - Keep VAT-book type and position together when selecting mappings. Issued and received books can reuse position numbers.
- Preserve prepayment source references and shared-base identities when extending generated entries. Report aggregation depends on those links.
- Use the guarded date/correction workflows for posted evidence. Draft initialization and generic ORM context flags do not grant correction authority.
- Compare reports using equivalent source populations. DDV-O, Tax Balance, and VAT books have distinct routing, date fallbacks, and aggregation rules; one journal-item scalar cannot represent all report destinations.