2026-07-22 19:12:44 -04:00
|
|
|
|
import unittest
|
|
|
|
|
|
from collections import Counter
|
2026-08-09 11:42:00 -04:00
|
|
|
|
from datetime import date
|
2026-07-22 19:12:44 -04:00
|
|
|
|
from decimal import Decimal
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
from xml.etree import ElementTree as ET
|
|
|
|
|
|
|
2026-08-08 20:56:32 -04:00
|
|
|
|
from trytond.modules.account_do.tax import (
|
|
|
|
|
|
TAX_APPLICATION, TAX_FISCAL_TYPE, TAX_KIND)
|
2026-07-22 19:12:44 -04:00
|
|
|
|
from trytond.pool import Pool
|
|
|
|
|
|
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
|
|
|
|
|
|
from trytond.transaction import Transaction
|
|
|
|
|
|
|
|
|
|
|
|
MODULE_DIR = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _iter_xml_records(*filenames):
|
|
|
|
|
|
for filename in filenames:
|
|
|
|
|
|
path = MODULE_DIR / filename
|
|
|
|
|
|
root = ET.parse(path).getroot()
|
|
|
|
|
|
for record in root.findall('.//record'):
|
|
|
|
|
|
values = {
|
|
|
|
|
|
field.get('name'): (
|
|
|
|
|
|
field.get('ref') or field.get('eval') or field.text or '')
|
|
|
|
|
|
for field in record.findall('field')
|
|
|
|
|
|
}
|
|
|
|
|
|
yield filename, record.get('id'), record.get('model'), values
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AccountDoTestCase(ModuleTestCase):
|
|
|
|
|
|
"Test account_do module"
|
|
|
|
|
|
module = 'account_do'
|
|
|
|
|
|
|
|
|
|
|
|
@with_transaction()
|
|
|
|
|
|
def test_chart_template_is_loaded_by_default(self):
|
|
|
|
|
|
'Test Dominican chart template is loaded without Spanish language setup'
|
|
|
|
|
|
pool = Pool()
|
|
|
|
|
|
ModelData = pool.get('ir.model.data')
|
|
|
|
|
|
|
|
|
|
|
|
self.assertTrue(ModelData.get_id('account_do', 'do_account_root'))
|
|
|
|
|
|
|
|
|
|
|
|
@with_transaction()
|
|
|
|
|
|
def test_chart_creates_company_accounts_and_taxes(self):
|
|
|
|
|
|
'Test Dominican chart creates usable accounts and taxes'
|
|
|
|
|
|
pool = Pool()
|
|
|
|
|
|
Account = pool.get('account.account')
|
|
|
|
|
|
AccountTemplate = pool.get('account.account.template')
|
|
|
|
|
|
Company = pool.get('company.company')
|
|
|
|
|
|
Currency = pool.get('currency.currency')
|
|
|
|
|
|
ModelData = pool.get('ir.model.data')
|
|
|
|
|
|
Party = pool.get('party.party')
|
|
|
|
|
|
Tax = pool.get('account.tax')
|
|
|
|
|
|
TaxCode = pool.get('account.tax.code')
|
|
|
|
|
|
TaxRule = pool.get('account.tax.rule')
|
2026-08-09 11:42:00 -04:00
|
|
|
|
DgiiTaxMapping = pool.get('account.do.dgii.tax.mapping')
|
2026-07-22 19:12:44 -04:00
|
|
|
|
CreateChart = pool.get('account.create_chart', type='wizard')
|
|
|
|
|
|
|
|
|
|
|
|
currency, = Currency.create([{
|
|
|
|
|
|
'name': 'Dominican Peso',
|
|
|
|
|
|
'code': 'DOP',
|
|
|
|
|
|
'symbol': 'RD$',
|
|
|
|
|
|
'digits': 2,
|
|
|
|
|
|
'rounding': '0.01',
|
|
|
|
|
|
}])
|
|
|
|
|
|
party, = Party.create([{
|
|
|
|
|
|
'name': 'Empresa Dominicana',
|
|
|
|
|
|
}])
|
|
|
|
|
|
company, = Company.create([{
|
|
|
|
|
|
'party': party.id,
|
|
|
|
|
|
'currency': currency.id,
|
|
|
|
|
|
}])
|
|
|
|
|
|
template = AccountTemplate(ModelData.get_id(
|
|
|
|
|
|
'account_do', 'do_account_root'))
|
|
|
|
|
|
|
|
|
|
|
|
session_id, _start, _end = CreateChart.create()
|
|
|
|
|
|
chart = CreateChart(session_id)
|
|
|
|
|
|
chart.account.account_template = template
|
|
|
|
|
|
chart.account.company = company
|
|
|
|
|
|
chart.transition_create_account()
|
|
|
|
|
|
|
|
|
|
|
|
receivable, = Account.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
('code', '=', '110201'),
|
|
|
|
|
|
('type.receivable', '=', True),
|
|
|
|
|
|
('party_required', '=', True),
|
|
|
|
|
|
('closed', '!=', True),
|
|
|
|
|
|
], limit=1)
|
|
|
|
|
|
payable, = Account.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
('code', '=', '210101'),
|
|
|
|
|
|
('type.payable', '=', True),
|
|
|
|
|
|
('party_required', '=', True),
|
|
|
|
|
|
('closed', '!=', True),
|
|
|
|
|
|
], limit=1)
|
|
|
|
|
|
for code in [
|
2026-08-08 20:56:32 -04:00
|
|
|
|
'110401', '110406', '110407', '110408',
|
|
|
|
|
|
'11040101', '11040102', '11040103', '11040104',
|
|
|
|
|
|
'11040601', '11040801', '11040802', '11040803',
|
|
|
|
|
|
'210201', '210202', '210203', '210206', '210207',
|
|
|
|
|
|
'210208', '210209', '210210', '210211', '210212',
|
|
|
|
|
|
'210213', '210214', '210215', '210216', '210217',
|
|
|
|
|
|
'210218', '210219',
|
|
|
|
|
|
'21020101', '21020102', '21020103', '21020104',
|
|
|
|
|
|
'21020105', '21020201', '21020501', '21020502',
|
|
|
|
|
|
'21020601', '21020701', '21020702', '21020801',
|
|
|
|
|
|
'21020802', '21020803', '21020804', '21020805',
|
|
|
|
|
|
'21020901', '21021001', '21021101', '21021201',
|
|
|
|
|
|
'21021301', '21021302', '21021401', '21021501',
|
|
|
|
|
|
'21021502', '21021701', '21021801', '21021901',
|
|
|
|
|
|
'21021902', '6208']:
|
2026-07-22 19:12:44 -04:00
|
|
|
|
with self.subTest(code=code):
|
|
|
|
|
|
self.assertTrue(Account.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
('code', '=', code),
|
|
|
|
|
|
('closed', '!=', True),
|
|
|
|
|
|
], limit=1))
|
|
|
|
|
|
|
|
|
|
|
|
self.assertGreaterEqual(len(Account.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
])), 200)
|
|
|
|
|
|
self.assertGreaterEqual(len(Tax.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
])), 25)
|
|
|
|
|
|
self.assertTrue(TaxCode.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
('name', '=', 'ITBIS — Balance Neto (Débito − Crédito)'),
|
|
|
|
|
|
], limit=1))
|
|
|
|
|
|
self.assertTrue(TaxRule.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
('kind', '=', 'sale'),
|
|
|
|
|
|
], limit=1))
|
|
|
|
|
|
self.assertTrue(TaxRule.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
('kind', '=', 'purchase'),
|
|
|
|
|
|
], limit=1))
|
2026-08-09 11:42:00 -04:00
|
|
|
|
self.assertEqual(DgiiTaxMapping.search_count([]), 55)
|
|
|
|
|
|
self.assertTrue(DgiiTaxMapping.search([
|
|
|
|
|
|
('tax_template', '=', ModelData.get_id(
|
|
|
|
|
|
'account_do', 'do_tax_cheques_020')),
|
|
|
|
|
|
('form', '=', 'ir2'),
|
|
|
|
|
|
('box', '=', 'financial_expenses_check_transfer_tax_020'),
|
|
|
|
|
|
('effective_from', '=', date(2026, 7, 3)),
|
|
|
|
|
|
], limit=1))
|
2026-07-22 19:12:44 -04:00
|
|
|
|
self.assertTrue(Tax.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
('description', '=', 'ITBIS 18% Ventas'),
|
|
|
|
|
|
('tax_kind', '=', 'itbis'),
|
|
|
|
|
|
('rate', '=', Decimal('0.18')),
|
|
|
|
|
|
], limit=1))
|
|
|
|
|
|
self.assertTrue(Tax.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
('description', '=', 'Retención ITBIS Gran Contribuyente 30%'),
|
|
|
|
|
|
('tax_kind', '=', 'itbis_withholding'),
|
2026-08-08 20:56:32 -04:00
|
|
|
|
('tax_fiscal_type', '=', 'itbis_withholding_30'),
|
2026-07-22 19:12:44 -04:00
|
|
|
|
('rate', '=', Decimal('-0.054')),
|
|
|
|
|
|
], limit=1))
|
2026-08-08 20:56:32 -04:00
|
|
|
|
self.assertTrue(Tax.search([
|
|
|
|
|
|
('company', '=', company.id),
|
|
|
|
|
|
('description', '=', 'Retención ITBIS Proveedor Informal 75%'),
|
|
|
|
|
|
('tax_kind', '=', 'itbis_withholding'),
|
|
|
|
|
|
('tax_fiscal_type', '=', 'itbis_withholding_75_informal'),
|
|
|
|
|
|
('rate', '=', Decimal('-0.135')),
|
|
|
|
|
|
], limit=1))
|
2026-07-22 19:12:44 -04:00
|
|
|
|
|
|
|
|
|
|
chart.properties.company = company
|
|
|
|
|
|
chart.properties.account_receivable = receivable
|
|
|
|
|
|
chart.properties.account_payable = payable
|
|
|
|
|
|
with Transaction().set_context(company=company.id):
|
|
|
|
|
|
chart.transition_create_properties()
|
|
|
|
|
|
CreateChart.delete(session_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AccountDoUnitTestCase(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
|
|
def test_xml_references_are_resolved_inside_module(self):
|
|
|
|
|
|
records = list(_iter_xml_records(
|
|
|
|
|
|
'account_chart_do.xml',
|
|
|
|
|
|
'tax_do.xml',
|
|
|
|
|
|
'tax_code_do.xml',
|
|
|
|
|
|
'tax_rule_do.xml',
|
|
|
|
|
|
))
|
|
|
|
|
|
ids = {record_id for _, record_id, _, _ in records}
|
|
|
|
|
|
missing = []
|
|
|
|
|
|
for filename in [
|
|
|
|
|
|
'account_chart_do.xml',
|
|
|
|
|
|
'tax_do.xml',
|
|
|
|
|
|
'tax_code_do.xml',
|
|
|
|
|
|
'tax_rule_do.xml',
|
|
|
|
|
|
]:
|
|
|
|
|
|
root = ET.parse(MODULE_DIR / filename).getroot()
|
|
|
|
|
|
for record in root.findall('.//record'):
|
|
|
|
|
|
for field in record.findall('field'):
|
|
|
|
|
|
ref = field.get('ref')
|
|
|
|
|
|
if ref and '.' not in ref and ref not in ids:
|
|
|
|
|
|
missing.append(
|
|
|
|
|
|
(filename, record.get('id'), field.get('name'), ref))
|
|
|
|
|
|
self.assertEqual(missing, [])
|
|
|
|
|
|
|
|
|
|
|
|
def test_chart_template_codes_are_unique(self):
|
|
|
|
|
|
accounts = [
|
|
|
|
|
|
values for _, _, model, values in _iter_xml_records(
|
|
|
|
|
|
'account_chart_do.xml')
|
|
|
|
|
|
if model == 'account.account.template'
|
|
|
|
|
|
]
|
|
|
|
|
|
codes = [values['code'] for values in accounts if values.get('code')]
|
|
|
|
|
|
duplicates = [
|
|
|
|
|
|
code for code, count in Counter(codes).items() if count > 1]
|
|
|
|
|
|
self.assertEqual(duplicates, [])
|
|
|
|
|
|
|
|
|
|
|
|
def test_chart_root_and_statement_classification(self):
|
|
|
|
|
|
accounts = {
|
|
|
|
|
|
record_id: values
|
|
|
|
|
|
for _, record_id, model, values in _iter_xml_records(
|
|
|
|
|
|
'account_chart_do.xml')
|
|
|
|
|
|
if model == 'account.account.template'
|
|
|
|
|
|
}
|
|
|
|
|
|
types = {
|
|
|
|
|
|
record_id: values
|
|
|
|
|
|
for _, record_id, model, values in _iter_xml_records(
|
|
|
|
|
|
'account_chart_do.xml')
|
|
|
|
|
|
if model == 'account.account.type.template'
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.assertEqual([
|
|
|
|
|
|
accounts[f'do_account_{code}']['code']
|
|
|
|
|
|
for code in range(1, 8)
|
|
|
|
|
|
], ['1', '2', '3', '4', '5', '6', '7'])
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
types['do_type_retained_earnings']['statement'], 'balance')
|
|
|
|
|
|
self.assertEqual(types['do_type_revenue']['statement'], 'income')
|
|
|
|
|
|
self.assertEqual(types['do_type_expense']['statement'], 'income')
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
accounts['do_account_110201']['type'], 'do_type_receivable')
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
accounts['do_account_210101']['type'], 'do_type_payable')
|
|
|
|
|
|
|
|
|
|
|
|
def test_no_spanish_technical_other_tax_ids_remain(self):
|
|
|
|
|
|
ids = {
|
|
|
|
|
|
record_id
|
|
|
|
|
|
for _, record_id, _, _ in _iter_xml_records(
|
|
|
|
|
|
'tax_do.xml', 'tax_code_do.xml')
|
|
|
|
|
|
}
|
|
|
|
|
|
self.assertFalse([record_id for record_id in ids if 'otros' in record_id])
|
|
|
|
|
|
|
|
|
|
|
|
def test_tax_templates_are_classified(self):
|
|
|
|
|
|
taxes = {
|
|
|
|
|
|
record_id: values
|
|
|
|
|
|
for _, record_id, model, values in _iter_xml_records('tax_do.xml')
|
|
|
|
|
|
if model == 'account.tax.template'
|
|
|
|
|
|
}
|
2026-08-08 20:56:32 -04:00
|
|
|
|
self.assertEqual(len(taxes), 55)
|
2026-07-22 19:12:44 -04:00
|
|
|
|
self.assertFalse([
|
|
|
|
|
|
record_id for record_id, values in taxes.items()
|
|
|
|
|
|
if not values.get('tax_kind')])
|
2026-08-08 20:56:32 -04:00
|
|
|
|
self.assertFalse([
|
|
|
|
|
|
record_id for record_id, values in taxes.items()
|
|
|
|
|
|
if not values.get('tax_fiscal_type')])
|
|
|
|
|
|
self.assertFalse([
|
|
|
|
|
|
record_id for record_id, values in taxes.items()
|
|
|
|
|
|
if not values.get('tax_application')])
|
2026-07-22 19:12:44 -04:00
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes['do_tax_itbis_18_venta']['invoice_account'],
|
2026-08-08 20:56:32 -04:00
|
|
|
|
'do_account_21020101')
|
2026-07-22 19:12:44 -04:00
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes['do_tax_itbis_18_compra']['invoice_account'],
|
2026-08-08 20:56:32 -04:00
|
|
|
|
'do_account_11040101')
|
|
|
|
|
|
expected_accounts = {
|
|
|
|
|
|
'do_tax_itbis_18_venta': 'do_account_21020101',
|
|
|
|
|
|
'do_tax_itbis_16_venta': 'do_account_21020102',
|
|
|
|
|
|
'do_tax_itbis_9_venta': 'do_account_21020103',
|
|
|
|
|
|
'do_tax_itbis_8_venta': 'do_account_21020104',
|
|
|
|
|
|
'do_tax_itbis_tasa_cero': 'do_account_21020105',
|
|
|
|
|
|
'do_tax_itbis_18_compra': 'do_account_11040101',
|
|
|
|
|
|
'do_tax_itbis_16_compra': 'do_account_11040102',
|
|
|
|
|
|
'do_tax_itbis_9_compra': 'do_account_11040103',
|
|
|
|
|
|
'do_tax_itbis_8_compra': 'do_account_11040104',
|
|
|
|
|
|
'do_tax_ret_itbis_2_adq': 'do_account_11040601',
|
|
|
|
|
|
'do_tax_ret_itbis_30': 'do_account_21021101',
|
|
|
|
|
|
'do_tax_ret_itbis_100_inf': 'do_account_21020201',
|
|
|
|
|
|
'do_tax_ret_itbis_75_inf': 'do_account_21021201',
|
|
|
|
|
|
'do_tax_ret_itbis_75_inf_16': 'do_account_21021202',
|
|
|
|
|
|
'do_tax_ret_itbis_100_goods_18': 'do_account_21021203',
|
|
|
|
|
|
'do_tax_ret_itbis_100_goods_16': 'do_account_21021204',
|
|
|
|
|
|
'do_tax_ret_itbis_rst_18': 'do_account_21020202',
|
|
|
|
|
|
'do_tax_ret_itbis_rst_16': 'do_account_21020203',
|
|
|
|
|
|
'do_tax_ret_itbis_insurance_100': 'do_account_21020204',
|
|
|
|
|
|
'do_tax_ret_itbis_airline_100': 'do_account_11040701',
|
|
|
|
|
|
'do_tax_ret_itbis_society_30_suf': 'do_account_11040702',
|
|
|
|
|
|
'do_tax_ret_itbis_hotel_100': 'do_account_11040703',
|
|
|
|
|
|
'do_tax_ret_itbis_state_100': 'do_account_11040704',
|
|
|
|
|
|
'do_tax_ret_isr_hon_5': 'do_account_21021301',
|
|
|
|
|
|
'do_tax_ret_isr_serv_10': 'do_account_21021302',
|
|
|
|
|
|
'do_tax_ret_isr_div_10': 'do_account_21020601',
|
|
|
|
|
|
'do_tax_ret_isr_int_10': 'do_account_21021501',
|
|
|
|
|
|
'do_tax_ret_isr_int_pj_1': 'do_account_21021502',
|
|
|
|
|
|
'do_tax_ret_isr_alq_10': 'do_account_21021401',
|
|
|
|
|
|
'do_tax_ret_isr_est_15': 'do_account_11040801',
|
|
|
|
|
|
'do_tax_ret_isr_est_5': 'do_account_11040802',
|
|
|
|
|
|
'do_tax_ret_isr_exporter_25': 'do_account_11040803',
|
|
|
|
|
|
'do_tax_ret_isr_bovine_1': 'do_account_21021801',
|
|
|
|
|
|
'do_tax_ret_isr_premios_25': 'do_account_21021701',
|
|
|
|
|
|
'do_tax_ret_isr_premios_10': 'do_account_21021702',
|
|
|
|
|
|
'do_tax_ret_isr_premios_15': 'do_account_21021703',
|
|
|
|
|
|
'do_tax_ret_isr_tragamonedas_10': 'do_account_21021704',
|
|
|
|
|
|
'do_tax_ret_isr_other_income_10': 'do_account_21020301',
|
|
|
|
|
|
'do_tax_ret_isr_ext_27': 'do_account_21020701',
|
|
|
|
|
|
'do_tax_ret_isr_ext_10': 'do_account_21020702',
|
|
|
|
|
|
'do_tax_isc_bebidas_alc': 'do_account_21020801',
|
|
|
|
|
|
'do_tax_isc_tabaco': 'do_account_21020802',
|
|
|
|
|
|
'do_tax_isc_telecom': 'do_account_21020803',
|
|
|
|
|
|
'do_tax_isc_combustibles_16': 'do_account_21020804',
|
|
|
|
|
|
'do_tax_isc_avtur_65': 'do_account_21020807',
|
|
|
|
|
|
'do_tax_isc_fuel_rd2_gallon': 'do_account_21020808',
|
|
|
|
|
|
'do_tax_ret_isc_insurance_100': 'do_account_21020806',
|
|
|
|
|
|
'do_tax_isc_vehiculos': 'do_account_21020805',
|
|
|
|
|
|
'do_tax_cdt_indotel': 'do_account_21020901',
|
|
|
|
|
|
'do_tax_propina_10': 'do_account_21020501',
|
|
|
|
|
|
'do_tax_cheques_015': 'do_account_21021901',
|
|
|
|
|
|
'do_tax_cheques_020': 'do_account_21021902',
|
|
|
|
|
|
'do_tax_activos_1': 'do_account_21020502',
|
|
|
|
|
|
'do_tax_iti_3': 'do_account_21021001',
|
|
|
|
|
|
}
|
|
|
|
|
|
for record_id, account_id in expected_accounts.items():
|
|
|
|
|
|
with self.subTest(record_id=record_id):
|
|
|
|
|
|
self.assertEqual(taxes[record_id]['invoice_account'], account_id)
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes[record_id]['credit_note_account'], account_id)
|
2026-07-22 19:12:44 -04:00
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes['do_tax_ret_itbis_30']['tax_kind'],
|
|
|
|
|
|
'itbis_withholding')
|
|
|
|
|
|
self.assertIn(
|
|
|
|
|
|
"Decimal('-5.4')/100",
|
|
|
|
|
|
taxes['do_tax_ret_itbis_30']['rate'])
|
2026-08-08 20:56:32 -04:00
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes['do_tax_ret_itbis_75_inf']['tax_fiscal_type'],
|
|
|
|
|
|
'itbis_withholding_75_informal')
|
|
|
|
|
|
self.assertIn(
|
|
|
|
|
|
"Decimal('-13.5')/100",
|
|
|
|
|
|
taxes['do_tax_ret_itbis_75_inf']['rate'])
|
|
|
|
|
|
for record_id in [
|
|
|
|
|
|
'do_tax_ret_isr_hon_5',
|
|
|
|
|
|
'do_tax_ret_isr_serv_10',
|
|
|
|
|
|
'do_tax_ret_isr_alq_10',
|
|
|
|
|
|
'do_tax_ret_isr_est_5',
|
|
|
|
|
|
'do_tax_ret_isr_bovine_1',
|
|
|
|
|
|
'do_tax_ret_isr_exporter_25',
|
|
|
|
|
|
'do_tax_ret_isr_ext_27',
|
|
|
|
|
|
]:
|
|
|
|
|
|
self.assertIn("Decimal('-", taxes[record_id]['rate'])
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes['do_tax_itbis_9_venta']['tax_fiscal_type'],
|
|
|
|
|
|
'itbis_sale_9')
|
|
|
|
|
|
self.assertIn(
|
|
|
|
|
|
"Decimal('9')/100",
|
|
|
|
|
|
taxes['do_tax_itbis_9_compra']['rate'])
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes['do_tax_isc_bebidas_alc']['tax_fiscal_type'],
|
|
|
|
|
|
'isc_alcohol_10')
|
|
|
|
|
|
self.assertIn(
|
|
|
|
|
|
"Decimal('10')/100",
|
|
|
|
|
|
taxes['do_tax_isc_bebidas_alc']['rate'])
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes['do_tax_isc_combustibles_16']['tax_fiscal_type'],
|
|
|
|
|
|
'isc_fossil_fuel_16')
|
2026-07-22 19:12:44 -04:00
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes['do_tax_cheques_020']['tax_kind'], 'others')
|
2026-08-08 20:56:32 -04:00
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
taxes['do_tax_cheques_020']['invoice_account'],
|
|
|
|
|
|
'do_account_21021902')
|
2026-07-22 19:12:44 -04:00
|
|
|
|
self.assertIn(
|
|
|
|
|
|
"Decimal('0.20')/100",
|
|
|
|
|
|
taxes['do_tax_cheques_020']['rate'])
|
|
|
|
|
|
|
2026-08-09 11:42:00 -04:00
|
|
|
|
def test_dgii_tax_mapping_formalizes_every_tax_template(self):
|
|
|
|
|
|
taxes = {
|
|
|
|
|
|
record_id: values
|
|
|
|
|
|
for _, record_id, model, values in _iter_xml_records('tax_do.xml')
|
|
|
|
|
|
if model == 'account.tax.template'
|
|
|
|
|
|
}
|
|
|
|
|
|
mappings = {
|
|
|
|
|
|
record_id: values
|
|
|
|
|
|
for _, record_id, model, values in _iter_xml_records(
|
|
|
|
|
|
'dgii_tax_mapping_data.xml')
|
|
|
|
|
|
if model == 'account.do.dgii.tax.mapping'
|
|
|
|
|
|
}
|
|
|
|
|
|
mapped_taxes = {
|
|
|
|
|
|
values['tax_template'] for values in mappings.values()}
|
|
|
|
|
|
|
|
|
|
|
|
self.assertEqual(len(mappings), 55)
|
|
|
|
|
|
self.assertEqual(mapped_taxes, set(taxes))
|
|
|
|
|
|
for record_id, values in mappings.items():
|
|
|
|
|
|
with self.subTest(record_id=record_id):
|
|
|
|
|
|
self.assertTrue(values.get('form'))
|
|
|
|
|
|
self.assertTrue(values.get('box'))
|
|
|
|
|
|
self.assertTrue(values.get('box_label'))
|
|
|
|
|
|
self.assertTrue(values.get('amount_source'))
|
|
|
|
|
|
self.assertIn(values.get('operator'), {'+', '-', 'info'})
|
|
|
|
|
|
self.assertTrue(values.get('flow'))
|
|
|
|
|
|
self.assertTrue(values.get('legal_basis'))
|
|
|
|
|
|
tax = taxes[values['tax_template']]
|
|
|
|
|
|
if tax.get('type') != 'none':
|
|
|
|
|
|
self.assertTrue(values.get('account_template'))
|
|
|
|
|
|
|
|
|
|
|
|
by_tax = {
|
|
|
|
|
|
values['tax_template']: values
|
|
|
|
|
|
for values in mappings.values()
|
|
|
|
|
|
}
|
|
|
|
|
|
self.assertEqual(by_tax['do_tax_itbis_18_venta']['form'], 'it1')
|
|
|
|
|
|
self.assertEqual(by_tax['do_tax_itbis_18_venta']['box'], '16')
|
|
|
|
|
|
self.assertEqual(by_tax['do_tax_itbis_18_compra']['box'], '22')
|
|
|
|
|
|
self.assertEqual(by_tax['do_tax_itbis_exento']['form'], 'it1_annex_a')
|
|
|
|
|
|
self.assertEqual(by_tax['do_tax_itbis_exento']['box'], '04')
|
|
|
|
|
|
self.assertEqual(by_tax['do_tax_ret_itbis_75_inf']['box'], '56')
|
|
|
|
|
|
self.assertEqual(by_tax['do_tax_ret_isr_ext_27']['form'], '609')
|
|
|
|
|
|
self.assertEqual(by_tax['do_tax_cheques_015']['effective_to'],
|
|
|
|
|
|
'2026-07-02')
|
|
|
|
|
|
self.assertEqual(by_tax['do_tax_cheques_020']['effective_from'],
|
|
|
|
|
|
'2026-07-03')
|
|
|
|
|
|
|
2026-07-22 19:12:44 -04:00
|
|
|
|
def test_tax_code_templates_use_expected_signs(self):
|
|
|
|
|
|
codes = {
|
|
|
|
|
|
record_id: values
|
|
|
|
|
|
for _, record_id, model, values in _iter_xml_records(
|
|
|
|
|
|
'tax_code_do.xml')
|
|
|
|
|
|
if model == 'account.tax.code.template'
|
|
|
|
|
|
}
|
|
|
|
|
|
lines = {
|
|
|
|
|
|
record_id: values
|
|
|
|
|
|
for _, record_id, model, values in _iter_xml_records(
|
|
|
|
|
|
'tax_code_do.xml')
|
|
|
|
|
|
if model == 'account.tax.code.line.template'
|
|
|
|
|
|
}
|
|
|
|
|
|
for record_id in [
|
|
|
|
|
|
'do_tc_itbis',
|
|
|
|
|
|
'do_tc_isr',
|
|
|
|
|
|
'do_tc_isc',
|
|
|
|
|
|
'do_tc_cdt',
|
|
|
|
|
|
'do_tc_others',
|
|
|
|
|
|
]:
|
|
|
|
|
|
self.assertEqual(codes[record_id].get('parent'), 'None')
|
|
|
|
|
|
self.assertEqual(codes['do_tc_isr']['name'], 'ISR - Retenciones')
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
lines['do_tcl_isr_int_pf_inv']['code'],
|
|
|
|
|
|
'do_tc_isr_intereses_pf')
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
lines['do_tcl_isr_int_pf_cr']['code'],
|
|
|
|
|
|
'do_tc_isr_intereses_pf')
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
lines['do_tcl_isr_int_pj_inv']['code'],
|
|
|
|
|
|
'do_tc_isr_intereses')
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
lines['do_tcl_isr_int_pj_cr']['code'],
|
|
|
|
|
|
'do_tc_isr_intereses')
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
lines['do_tcl_chq020_inv']['code'],
|
|
|
|
|
|
'do_tc_others_checks_020')
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
|
lines['do_tcl_chq020_cr']['code'],
|
|
|
|
|
|
'do_tc_others_checks_020')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_itbis18v_inv']['operator'], '+')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_itbis18c_inv']['operator'], '-')
|
2026-08-08 20:56:32 -04:00
|
|
|
|
self.assertEqual(lines['do_tcl_itbis9v_inv']['operator'], '+')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_itbis9c_inv']['operator'], '-')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_ret_itbis_inv']['operator'], '-')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_ret_itbis_adq_inv']['operator'], '+')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_ret_itbis_inf75_inv']['operator'], '-')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_isr_hon_inv']['operator'], '-')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_isr_est_inv']['operator'], '+')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_isr_est5_inv']['operator'], '+')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_isr_bovine_inv']['operator'], '-')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_isr_exporter_inv']['operator'], '+')
|
|
|
|
|
|
self.assertEqual(lines['do_tcl_isc_comb_inv']['operator'], '+')
|
2026-07-22 19:12:44 -04:00
|
|
|
|
self.assertEqual(lines['do_tcl_prop_inv']['code'], 'do_tc_others_tip')
|
|
|
|
|
|
|
|
|
|
|
|
def test_tax_kind_contains_dominican_tax_categories(self):
|
|
|
|
|
|
codes = {code for code, _ in TAX_KIND}
|
|
|
|
|
|
self.assertEqual(codes, {
|
|
|
|
|
|
'',
|
|
|
|
|
|
'itbis',
|
|
|
|
|
|
'itbis_withholding',
|
|
|
|
|
|
'itbis_withholding_acquirer',
|
|
|
|
|
|
'isr_withholding',
|
|
|
|
|
|
'isc',
|
|
|
|
|
|
'cdt',
|
|
|
|
|
|
'tip',
|
|
|
|
|
|
'others',
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
def test_tax_kind_codes_are_unique(self):
|
|
|
|
|
|
codes = [code for code, _ in TAX_KIND]
|
|
|
|
|
|
self.assertEqual(len(codes), len(set(codes)))
|
|
|
|
|
|
|
2026-08-08 20:56:32 -04:00
|
|
|
|
def test_fiscal_classification_codes_are_unique(self):
|
|
|
|
|
|
fiscal_codes = [code for code, _ in TAX_FISCAL_TYPE]
|
|
|
|
|
|
application_codes = [code for code, _ in TAX_APPLICATION]
|
|
|
|
|
|
self.assertEqual(len(fiscal_codes), len(set(fiscal_codes)))
|
|
|
|
|
|
self.assertEqual(len(application_codes), len(set(application_codes)))
|
|
|
|
|
|
|
2026-07-22 19:12:44 -04:00
|
|
|
|
|
|
|
|
|
|
del ModuleTestCase
|