Skip to Content

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

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 header tax_date.
  • l10n_si_tax_date_manual: tracks an independently selected date on eligible ordinary journal entries.
  • l10n_si_obravnava, l10n_si_obdobje88, and l10n_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.service for DDV-O signs and rounding. Supply the intended company, date range, and posted/exigibility policy before calling its low-level interfaces.
  • Use explicit tag_destinations for 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.