Round Dominican invoice taxes independently
Publish Package / publish (push) Successful in 1m20s

This commit is contained in:
2026-08-30 21:29:56 -04:00
parent c07f98508f
commit c4765f1469
4 changed files with 105 additions and 4 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from . import tax
from . import invoice, tax
__all__ = ['tax']
__all__ = ['invoice', 'tax']
+39
View File
@@ -0,0 +1,39 @@
"""Dominican invoice tax rounding policy.
Tryton's generic taxable mixin compensates the aggregate currency-rounding
remainder on the first non-zero tax. That keeps the rounded aggregate equal
to the aggregate of the unrounded taxes, but it can change the reported value
of a specific Dominican tax (ITBIS, ISC or CDT).
Dominican fiscal documents state every tax in currency precision. Each tax
must therefore retain its own rounded result; no residual is redistributed
between different tax liabilities or tax credits.
"""
from trytond.model import fields
from trytond.pool import PoolMeta
def round_taxes_independently(currency, taxes):
"""Round every tax amount without reallocating the aggregate residual."""
if not currency:
return
for taxline in taxes.values():
taxline.amount = currency.round(taxline.amount)
class IndependentTaxRoundingMixin:
__slots__ = ()
@fields.depends('currency')
def _round_taxes(self, taxes):
round_taxes_independently(self.currency, taxes)
class Invoice(IndependentTaxRoundingMixin, metaclass=PoolMeta):
__name__ = 'account.invoice'
class InvoiceLine(IndependentTaxRoundingMixin, metaclass=PoolMeta):
__name__ = 'account.invoice.line'
+61 -2
View File
@@ -4,12 +4,15 @@ from collections import Counter
from configparser import ConfigParser
from decimal import Decimal
from pathlib import Path
from types import SimpleNamespace
from xml.etree import ElementTree as ET
from trytond.pool import Pool
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
from trytond.transaction import Transaction
from trytond.modules.account_do.invoice import round_taxes_independently
MODULE_DIR = Path(__file__).resolve().parent.parent
TAX_CODE_LINE_AUDIT = {
@@ -125,6 +128,56 @@ class AccountDoTestCase(ModuleTestCase):
'account_stock_continental',
]
@with_transaction()
def test_invoice_taxes_round_independently(self):
"""A rounding residual must not change ITBIS, ISC or CDT."""
pool = Pool()
Currency = pool.get('currency.currency')
currency, = Currency.create([{
'name': 'Peso dominicano',
'code': 'DOP',
'symbol': 'RD$',
'digits': 2,
'rounding': Decimal('0.01'),
}])
taxes = {
'itbis': SimpleNamespace(amount=Decimal('91.8036')),
'isc': SimpleNamespace(amount=Decimal('51.0020')),
'cdt': SimpleNamespace(amount=Decimal('9.9000')),
}
round_taxes_independently(currency, taxes)
self.assertEqual(taxes['itbis'].amount, Decimal('91.80'))
self.assertEqual(taxes['isc'].amount, Decimal('51.00'))
self.assertEqual(taxes['cdt'].amount, Decimal('9.90'))
self.assertEqual(
sum(tax.amount for tax in taxes.values()), Decimal('152.70'))
@with_transaction()
def test_invoice_credit_note_taxes_round_independently(self):
"""The same policy applies symmetrically to credit notes."""
pool = Pool()
Currency = pool.get('currency.currency')
currency, = Currency.create([{
'name': 'Peso dominicano',
'code': 'DOP',
'symbol': 'RD$',
'digits': 2,
'rounding': Decimal('0.01'),
}])
taxes = {
'itbis': SimpleNamespace(amount=Decimal('-91.8036')),
'isc': SimpleNamespace(amount=Decimal('-51.0020')),
'cdt': SimpleNamespace(amount=Decimal('-9.9000')),
}
round_taxes_independently(currency, taxes)
self.assertEqual(taxes['itbis'].amount, Decimal('-91.80'))
self.assertEqual(taxes['isc'].amount, Decimal('-51.00'))
self.assertEqual(taxes['cdt'].amount, Decimal('-9.90'))
@with_transaction()
def test_chart_template_is_loaded_by_default(self):
'Test English Dominican chart is loaded in an English database'
@@ -571,7 +624,7 @@ class AccountDoUnitTestCase(unittest.TestCase):
self.assertEqual(config.get('tryton', 'version'), '8.0.5')
self.assertEqual(
set(lines('tryton', 'depends')),
{'account', 'ir'})
{'account', 'account_invoice', 'ir'})
self.assertEqual(
lines('tryton', 'xml'),
[
@@ -587,7 +640,13 @@ class AccountDoUnitTestCase(unittest.TestCase):
])
self.assertEqual(
lines('register', 'model'),
['ir.ModelData', 'tax.TaxTemplate', 'tax.Tax'])
[
'ir.ModelData',
'invoice.Invoice',
'invoice.InvoiceLine',
'tax.TaxTemplate',
'tax.Tax',
])
self.assertEqual(lines('register', 'wizard'), ['account.CreateChart'])
for filename in lines('tryton', 'xml'):
self.assertTrue((MODULE_DIR / filename).is_file())
+3
View File
@@ -2,6 +2,7 @@
version=8.0.5
depends:
account
account_invoice
ir
xml:
account_chart_do_en.xml
@@ -17,6 +18,8 @@ xml:
[register]
model:
ir.ModelData
invoice.Invoice
invoice.InvoiceLine
tax.TaxTemplate
tax.Tax
wizard: