bus-vat — VAT computation, reporting, and export (SDD)

bus-vat — VAT computation, reporting, and export

Introduction and Overview

Bus VAT computes VAT totals per reporting period, validates VAT code and rate mappings against reference data, and reconciles invoice VAT with ledger postings. It owns the definition of VAT period boundaries: the actual sequence of reporting periods (start and end dates) used for allocation and reporting. That sequence can include transitions when the period length changes within a year (e.g. monthly → yearly → quarterly), transition periods (e.g. 4 months), and non-standard first or last periods (e.g. 18-month first period after registration). Bus-vat uses workspace-level inputs from bus-config — current vat_reporting_period, vat_timing, and optional vat_registration_start / vat_registration_end — and may maintain a period-definition dataset or logic to produce the authoritative list of periods. The canonical definition of those configuration keys and allowed values is in bus-config and Workspace configuration.

Some bookkeeping sources are journal-first and do not have complete invoice master datasets. VAT workflows that emphasize invoice data as the primary source can block migration and parity workflows for such sources. The module therefore supports a journal-driven VAT mode: computation of VAT period totals from journal postings plus VAT-related account and tax mappings, with deterministic period allocation and traceable diagnostics. That mode enables VAT reporting in migrations where invoice masters are incomplete and improves parity for historical datasets while preserving auditability and deterministic outputs.

Requirements

FR-VAT-001 VAT computations. The module MUST compute VAT summaries from invoice and journal data. Acceptance criteria: VAT report outputs are deterministic and traceable to source postings.

FR-VAT-002 VAT export outputs. The module MUST write VAT summary and export files as repository data. Acceptance criteria: export outputs are recorded in datasets such as vat-reports.csv and vat-returns.csv.

FR-VAT-003 CLI surface for VAT baseline. The module MUST provide an init command that creates the VAT baseline datasets and schemas (e.g. vat-rates.csv, vat-reports.csv, vat-returns.csv and their schemas) when they are absent. When they already exist in full, init MUST print a warning to standard error and exit 0 without modifying anything. When they exist only partially, init MUST fail with a clear error and not write any file (see bus-init FR-INIT-004). Acceptance criteria: bus vat init is available; idempotent and partial-state behavior as specified.

FR-VAT-004 Journal-driven VAT mode. The module MUST support computing VAT period totals from journal postings and VAT-related account/tax mappings when invoice master data is incomplete or absent. Acceptance criteria: period allocation is deterministic; diagnostics are traceable to source postings and mappings; report and export outputs remain append-only and audit-ready; behavior is equivalent in auditability and determinism to the invoice-based path where both sources exist.

FR-VAT-005 Filed VAT import and deterministic period diff. The module MUST support importing externally filed VAT evidence with provenance and computing a deterministic period diff against replay VAT totals (output/input/net). Acceptance criteria: filed-import writes canonical period evidence plus provenance (source_path, source_sha256), filed-diff emits machine-readable deterministic output, and threshold-based non-zero exit is supported for CI gating.

FR-VAT-006 Reconcile cash coverage diagnostics and strict gating. The module MUST emit deterministic coverage diagnostics for --source reconcile --basis cash and support optional strict failure when coverage is below configured thresholds. Acceptance criteria: report/export include machine-readable coverage metrics and source refs; partial coverage emits explicit warning in non-strict mode; strict mode exits non-zero when thresholds are not met.

FR-VAT-007 FI filing payload/explain/profile tooling. The module MUST provide one-command FI filing payload output, row-level FI field explain output, strict reverse-charge marker validation, and named period profile import/list/selection. Acceptance criteria: fi-file emits machine-consumable filing payload with deterministic formulas and calculation version metadata; explain emits deterministic row-level field trace; --strict-fi-eu-rc can fail unresolved classification markers; period-profile import|list exists and --period-profile can be used in period-scoped VAT commands.

FR-VAT-008 Authority-support review packet. The module MUST provide a deterministic review packet per period that includes VAT summary totals, row-level explain trace, and coverage diagnostics when --source reconcile --basis cash is used, and MUST support PDF output for archival. Acceptance criteria: review outputs packet data in TSV/JSON, --format pdf produces deterministic PDF output, and --section summary|explain|coverage can emit machine-readable CSV when requested.

NFR-VAT-003 Decimal-safe money arithmetic. All VAT money calculations (base amounts, VAT amounts, totals, export values, and thresholds) MUST use decimal-safe arithmetic and MUST NOT rely on binary floating-point. Acceptance criteria: computations use exact decimal-safe representations (scaled cents or exact decimal/rational types), rounding behavior is explicit and deterministic, and repeated runs produce byte-identical monetary outputs for the same inputs.

NFR-VAT-001 Auditability. VAT corrections MUST be append-only and traceable to original records. Acceptance criteria: corrections create new records that reference originals.

NFR-VAT-002 Path exposure via Go library. The module MUST expose a Go library API that returns the workspace-relative path(s) to its owned data file(s) (e.g. vat-rates, vat-reports, vat-returns, and any period-definition or period-scoped files and their schemas). Other modules that need read-only access to VAT raw file(s) MUST obtain the path(s) from this module’s library, not by hardcoding file names. The API MUST be designed so that future dynamic path configuration can be supported without breaking consumers. Acceptance criteria: the library provides path accessor(s) for the VAT datasets; consumers use these accessors for read-only access; no consumer hardcodes VAT file names outside this module.

System Architecture

Bus VAT reads invoice and journal datasets and optional VAT reference datasets to compute reports and exports. It integrates with filing workflows and reporting outputs. Period boundaries (including transitions and non-standard lengths) are defined within the VAT module, e.g. via a period-definition dataset or logic that consumes workspace config.

Key Decisions

KD-VAT-001 VAT outputs are stored as repository data. VAT summaries and exports remain reviewable and exportable.

KD-VAT-002 VAT period boundaries are owned by bus-vat. The sequence of VAT reporting periods (including changes within a year from monthly to yearly to quarterly, 4-month transition periods, 18-month first period, and partial first or last periods from registration dates) is defined or computed by bus-vat. Workspace config in bus-config supplies the current period length and registration start/end dates as inputs; bus-vat is the single place that produces the actual list of (start_date, end_date) periods for reporting and allocation.

KD-VAT-003 Path exposure for read-only consumption. The module exposes path accessors in its Go library so that other modules can resolve the location of VAT datasets for read-only access. Write access and all VAT business logic remain in this module.

KD-VAT-004 Journal-driven mode supports migration and legacy scenarios. Where invoice master data is incomplete or absent, VAT period totals are computed from journal postings and VAT-related account/tax mappings. The same period boundaries, allocation rules, and output formats apply as for the invoice-based path; only the input source differs. The binding is --source journal on bus vat validate|report|export.

Component Design and Interfaces

Interface IF-VAT-001 (module CLI). The module exposes bus vat with subcommands init, validate, report, export, fi-file, explain, review, period-profile, filed-import, and filed-diff and follows BusDK CLI conventions for deterministic output and diagnostics.

The init command creates the baseline VAT datasets and schemas (e.g. vat-rates.csv, vat-reports.csv, vat-returns.csv and their beside-the-table schemas) when they are absent. If all owned VAT datasets and schemas already exist and are consistent, init prints a warning to standard error and exits 0 without modifying anything. If the data exists only partially, init fails with a clear error to standard error, does not write any file, and exits non-zero (see bus-init FR-INIT-004).

Documented parameters include bus vat report --period <period>, bus vat export --period <period>, bus vat fi-file --period <period> [--payload-format json|csv|tsv], bus vat explain --period <period> [--format tsv|json], bus vat --format <fmt> review --period <period> [--section packet|summary|explain|coverage], bus vat period-profile import --file <path>, bus vat period-profile list, bus vat filed-import --period <period> --file <path>, and bus vat filed-diff --period <period> [--threshold-cents <int>]. Period selection supports --period, --from/--to, and --period-profile <id> for period-scoped VAT commands. Journal-driven VAT mode (FR-VAT-004) is invoked with --source journal on bus vat validate|report|export|filed-diff|fi-file|explain|review.

Interface IF-VAT-002 (path accessors, Go library). The module exposes Go library functions that return the workspace-relative path(s) to its owned data file(s) (vat-rates, vat-reports, vat-returns, and any period-definition or period-scoped files and their schemas). Given a workspace root path and optionally a period identifier, the library returns the relevant path(s); resolution MUST allow future override from workspace or data package configuration. Other modules use these accessors for read-only access only; all writes and VAT logic remain in this module.

Usage examples:

bus vat report --period 2026Q1
bus vat export --period 2026Q1
bus vat --format pdf --output vat-review-2026Q1.pdf review --period 2026Q1

Data Design

The module reads invoice data and journal postings and writes VAT summaries, export data, and filed evidence. It owns the definition of VAT period boundaries; that definition may be stored in a period-definition dataset (e.g. vat-periods.csv) at the workspace root or computed from workspace config and rules. VAT master/index data (vat-rates.csv, vat-reports.csv, vat-returns.csv, vat-filed.csv and their schemas) is stored in the workspace root only; the module does not create or use a vat/ or other subdirectory for those datasets. When period-specific report/return/filed data is written to its own file (rather than only appended to root index datasets), that file is also stored at the workspace root with a date prefix, for example vat-reports-2026Q1.csv, vat-returns-2026Q1.csv, or vat-filed-2026Q1.csv, not under a subdirectory such as 2026/vat-reports/. The index datasets at root record which period files exist and where they live.

In journal-driven VAT mode (FR-VAT-004), inputs are journal postings and VAT-related account/tax mappings (e.g. chart-of-accounts or mapping tables that identify which accounts and tax codes contribute to VAT). Period boundaries and allocation rules are unchanged; outputs (vat-reports, vat-returns, vat-filed diffs) use the same deterministic period semantics so that migration and parity workflows produce reviewable, deterministic results.

Other modules that need read-only access to VAT datasets MUST obtain the path(s) from this module’s Go library (IF-VAT-002). All writes and VAT-domain logic remain in this module.

Assumptions and Dependencies

Bus VAT depends on invoice and journal datasets and on VAT reference datasets such as vat-rates.csv. It reads accounting entity settings from the workspace datapackage.json (maintained by bus-config): vat_registered, vat_reporting_period (current/default period length), vat_timing, and optionally vat_registration_start and vat_registration_end. The VAT module owns the authoritative list of period boundaries; it uses those workspace settings as inputs and may maintain a period-definition dataset (e.g. vat-periods.csv) or logic to produce periods that can include transitions and non-standard lengths. The VAT engine uses that period list for allocation and reporting, and vat_timing to choose the allocation date (performance, invoice, or payment date). Missing datasets or schemas result in deterministic diagnostics.

Security Considerations

VAT data is repository data and should be protected by repository access controls. Evidence references remain intact for auditability.

Observability and Logging

Command results are written to standard output, and diagnostics are written to standard error with deterministic references to dataset paths and identifiers.

Error Handling and Resilience

Invalid usage exits with a non-zero status and a concise usage error. Schema or VAT mapping violations exit non-zero without modifying datasets.

Testing Strategy

Unit tests cover VAT computations and mapping validation, and command-level tests exercise report, export, explain, and review against fixture workspaces.

Deployment and Operations

Not Applicable. The module ships as a BusDK CLI component and relies on the standard workspace layout.

Migration/Rollout

Not Applicable. Schema evolution is handled through the standard schema migration workflow for workspace datasets.

Risks

Not Applicable. Module-specific risks are not enumerated beyond the general need for deterministic VAT outputs.

Glossary and Terminology

VAT report: a computed summary of VAT totals for a reporting period.
VAT export: a repository data output intended for filing or archiving.
Journal-driven VAT mode: computation of VAT period totals from journal postings and VAT-related account/tax mappings instead of (or in addition to) invoice master data; used when invoice masters are incomplete or absent (e.g. migration or legacy sources).

Implementation status (journal-driven mode)

Journal-driven mode is implemented on bus vat validate|report|export --source journal. Invoice source and journal source (with direction resolvable) work. Direction fallback is deterministic: row direction (sale/purchase), then vat-account-mapping.csv direction by account_id, then accounts.csv account type (income => sale, expense => purchase). VAT rate fallback is deterministic: row vat_rate_bp first, then row vat_rate/vat_percent, then vat-account-mapping.csv (vat_rate_bp/rate_bp/vat_rate/vat_percent) for account_id. Legacy fallbacks: (1) when mapping provides direction for a VAT account but no rate, the posting amount is treated as VAT amount (net set to 0); (2) when mapping is missing, sided debit/credit rows on likely VAT accounts (for example 293x) are interpreted as VAT-amount rows with inferred direction. Opening-balance rows are excluded from journal-source VAT totals, including rows identified via opening voucher/source kind or opening-style source identifiers (for example opening:*). For cash basis date resolution, bank evidence references such as bank_row:<id>:journal:<n> are normalized to candidate bank transaction ids (including erp-bank-<id>) before lookup in bank-transactions.csv. If direction remains unresolved, commands fail with deterministic diagnostics that identify the row/account and required normalization input (e.g. journal-2023.csv row N: missing direction (need direction column value sale|purchase, vat-account-mapping.csv direction for account_id "XXXX", or accounts.csv type income/expense for account_id "XXXX")).

Reconcile-evidence cash mode is implemented on bus vat report|export --source reconcile --basis cash, including deterministic coverage diagnostics (COVERAGE output line with matched sales share, matched purchase share, unmatched cash rows, and source refs), partial-coverage warning in non-strict mode, and strict gating via --strict-coverage, --min-sales-coverage, and --min-purchase-coverage.

FI filing tooling is implemented:

  • bus vat fi-file produces one-command FI filing payload values with deterministic formulas/provenance and calculation_version.
  • bus vat explain produces deterministic row-level FI field traces (tsv|json).
  • strict marker validation is available via --strict-fi-eu-rc.
  • named period profiles are supported via bus vat period-profile import|list and --period-profile <id> selection in period-scoped VAT commands.

In workspaces where journal posts to asset/liability VAT accounts (e.g. 293x) or other non–income/expense accounts without a direction column, --source journal can fail because neither the row nor accounts.csv type supplies direction; adding a mapping in vat-account-mapping.csv for those account_ids would resolve it. Still to do: (1) Document the direction fallback and the optional vat-account-mapping.csv format (columns, semantics) so legacy workspaces can add mapping for asset/liability VAT accounts. (2) Optionally extend the fallback (e.g. treat known VAT account code ranges as purchase/sale by convention) or ship a default mapping for common Finnish VAT accounts. Goal: --source journal usable for journal-first workspaces without adding a direction column to legacy journal CSVs. No SDD change is required; the implementation status and module docs will be updated to document vat-account-mapping.csv format and any optional default mapping when that documentation is added.

Open Questions

None. OQ-VAT-001 (journal-driven mode binding) is resolved: the binding is --source journal on bus vat validate|report|export.

Document control

Title: bus-vat module SDD
Project: BusDK
Document ID: BUSDK-MOD-VAT
Version: 2026-02-20
Status: Draft
Last updated: 2026-02-20
Owner: BusDK development team