Skip to content

Allow 1-cent rounding on line VAT, use line totals as the VAT base, fix the ITEM_BASED check - #62

Open
ahmedm10 wants to merge 2 commits into
halfbyte:mainfrom
konvenit:MP-54008-line-vat-tolerance
Open

ahmedm10 wants to merge 2 commits into
halfbyte:mainfrom
konvenit:MP-54008-line-vat-tolerance

Conversation

@ahmedm10

@ahmedm10 ahmedm10 commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Problem

When the gross price of a line is fixed and net and VAT are derived from it (common for hotel and event invoices in Germany), the VAT can be one cent off net × rate. Example: 8 nights at 52.00 gross → net 388.79, VAT 27.21, while 388.79 × 7 % rounds to 27.22.

LineItem#valid? requires exact equality, so such an invoice is refused, and the only way through is to let the gem recalculate the VAT (:VERTICAL) — which makes the XML say 27.22 / 416.01 while the human-readable invoice says 27.21 / 416.00. EN 16931 itself tolerates this rounding (BR-CO-17).

Second, the VAT base (BT-116) is summed from net_amount × billed_quantity rather than from the line totals. With unit prices stored to four decimals the two drift apart: two lines of 120 × 41.6667 (5,000.00 each) give a base of 10000.008, written as 10000.01 next to line totals of 5000.00 + 5000.00 — the XML then violates BR-CO-10 and BR-S-08. Once the line totals are rounded to cents, the invoice is refused instead ("Base amount and summed tax base amount deviate").

Third, the :ITEM_BASED check in Invoice#valid? compares tax_amount with the summed line tax without converting either side, so a total passed as a string never matches. It records an error message but does not return false, so the invoice is still reported as valid — with a misleading entry in errors.

Change

  • LineItem#valid?: a line's VAT may differ from net × rate by at most one cent (LINE_TAX_ROUNDING_TOLERANCE). Larger differences are still refused. The invoice-level checks stay exact.
  • Invoice#taxes: the VAT base is the sum of the line totals (LineItem#signed_charge_amount — negative for a negative quantity, the same rule #valid? already uses when it checks that the lines add up to the basis).
  • Invoice#valid? (:ITEM_BASED): compares the values as BigDecimal, returns false on a mismatch, and prints the amounts in plain notation.

Tests

Five new tests in test/invoice_test.rb: the gross-leading invoice is accepted and its XML carries 27.21 / 416.00; a line two cents off is still refused; item-based totals passed as strings leave no error; an item-based total that differs from its lines is refused; two lines of 120 × 41.6667 give a VAT base of 10000.00. The full suite passes.

Related

The VAT-base change is the same idea as #45 (tax base from charge_amount), keeping the sign for negative quantities; #45's contact fields and to_xml changes are not included. It also covers what #51 addresses: summing the line totals means each line is already rounded before the sum.

A line's VAT may differ from net x rate by one cent when net and VAT
  are derived from a fixed gross price. The item-based tax check now
  compares numbers and fails on a mismatch instead of only noting it.
@ahmedm10 ahmedm10 changed the title Allow 1-cent rounding on line VAT and fix the ITEM_BASED tax check Allow 1-cent rounding on line VAT, use line totals as the VAT base, fix the ITEM_BASED check Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant