From 2c5c891a05438bc6ef499d5bdde63c16c285825d Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Feb 2026 16:21:03 +0100 Subject: [PATCH 1/2] fix rounding error caused by item quantity when applying the line item quantity causes sub-cent amounts, the total needs to be rounded to 2 digits again. fix https://github.com/halfbyte/ruby-secretariat/issues/46 --- lib/secretariat/invoice.rb | 4 ++-- test/invoice_test.rb | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/secretariat/invoice.rb b/lib/secretariat/invoice.rb index 94826e3..140627b 100644 --- a/lib/secretariat/invoice.rb +++ b/lib/secretariat/invoice.rb @@ -121,12 +121,12 @@ def valid? @errors = [] tax = BigDecimal(tax_amount) basis = BigDecimal(basis_amount) - summed_tax_amount = taxes.sum(&:tax_amount) + summed_tax_amount = taxes.sum(&:tax_amount).round(2) if tax != summed_tax_amount @errors << "Tax amount and summed tax amounts deviate: #{tax_amount} / #{summed_tax_amount}" return false end - summed_tax_base_amount = taxes.sum(&:base_amount) + summed_tax_base_amount = taxes.sum(&:base_amount).round(2) if basis != summed_tax_base_amount @errors << "Base amount and summed tax base amount deviate: #{basis} / #{summed_tax_base_amount}" return false diff --git a/test/invoice_test.rb b/test/invoice_test.rb index f6e1923..6ceaa6a 100644 --- a/test/invoice_test.rb +++ b/test/invoice_test.rb @@ -791,5 +791,20 @@ def test_invoice_object_extensions assert_match(/#{invoice.payment_reference}<\/ram:PaymentReference>/, xml) assert_match(%r{\s*Max Mustermann\s*}, xml) end + + def test_invoice_with_quantity_causing_sub_cent_amounts + invoice = make_de_invoice + invoice.tax_calculation_method = :ITEM_BASED + invoice.line_items.first.net_amount = BigDecimal('10.12') + invoice.line_items.first.billed_quantity = BigDecimal('0.1') + invoice.line_items.first.charge_amount = BigDecimal('1.01') + invoice.line_items.first.tax_amount = BigDecimal('0.19') + invoice.basis_amount = BigDecimal('1.01') # 1.012 rounded + invoice.tax_amount = BigDecimal('0.19') + invoice.grand_total_amount = BigDecimal('1.2') + + invoice.valid? + assert_equal [], invoice.errors + end end end From 855fae67192e474c0dc1dab7735022f841f05e61 Mon Sep 17 00:00:00 2001 From: Alexander Lang Date: Mon, 2 Feb 2026 16:41:31 +0100 Subject: [PATCH 2/2] also apply rounding in line item --- lib/secretariat/line_item.rb | 2 +- test/invoice_test.rb | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/secretariat/line_item.rb b/lib/secretariat/line_item.rb index 9235fbb..4aea6b3 100644 --- a/lib/secretariat/line_item.rb +++ b/lib/secretariat/line_item.rb @@ -74,7 +74,7 @@ def valid? gross_price = BigDecimal(gross_amount) charge_price = BigDecimal(charge_amount) tax = BigDecimal(tax_amount) - unit_price = net_price * BigDecimal(billed_quantity.abs) + unit_price = (net_price * BigDecimal(billed_quantity.abs)).round(2) if charge_price != unit_price @errors << "charge price and gross price times quantity deviate: #{charge_price} / #{unit_price}" diff --git a/test/invoice_test.rb b/test/invoice_test.rb index 6ceaa6a..4e54ec1 100644 --- a/test/invoice_test.rb +++ b/test/invoice_test.rb @@ -793,9 +793,13 @@ def test_invoice_object_extensions end def test_invoice_with_quantity_causing_sub_cent_amounts + errors = [] + invoice = make_de_invoice invoice.tax_calculation_method = :ITEM_BASED invoice.line_items.first.net_amount = BigDecimal('10.12') + invoice.line_items.first.gross_amount = BigDecimal('10.12') + invoice.line_items.first.discount_amount = BigDecimal('0') invoice.line_items.first.billed_quantity = BigDecimal('0.1') invoice.line_items.first.charge_amount = BigDecimal('1.01') invoice.line_items.first.tax_amount = BigDecimal('0.19') @@ -803,8 +807,13 @@ def test_invoice_with_quantity_causing_sub_cent_amounts invoice.tax_amount = BigDecimal('0.19') invoice.grand_total_amount = BigDecimal('1.2') - invoice.valid? - assert_equal [], invoice.errors + begin + invoice.to_xml(version: 2) + rescue ValidationError => e + errors = e.errors + pp e.errors + end + assert_equal [], errors end end end