Files
account_do/tests/test_module.py
T
José Arturo García 1e05afd8bb Complete Dominican IFRS base localization
Align the Dominican chart with the reviewed NIIF documentation by typing impairment and control accounts correctly, adding off-balance closing/control account types, and documenting the structural IFRS coverage boundary. Extend tests with fiscal audit matrices, IFRS account/type coverage, policy coverage, tax code signs, date-sensitive rules, and real chart validations.
2026-08-09 13:13:22 -04:00

793 lines
36 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import unittest
import datetime
from collections import Counter
from decimal import Decimal
from pathlib import Path
from xml.etree import ElementTree as ET
from trytond.modules.account_do.tax import (
DGII_FISCAL_STATUS, TAX_APPLICATION, TAX_FISCAL_TYPE, TAX_KIND)
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
TAX_TEMPLATE_AUDIT = {
'do_tax_itbis_18_venta': ('do_account_21020101', 'itbis',
'itbis_sale_18', 'sale_invoice', 'current', '', ''),
'do_tax_itbis_16_venta': ('do_account_21020102', 'itbis',
'itbis_sale_16', 'sale_invoice', 'special', '', ''),
'do_tax_itbis_9_venta': ('do_account_21020103', 'itbis',
'itbis_sale_9', 'sale_invoice', 'special', '', ''),
'do_tax_itbis_18_compra': ('do_account_11040101', 'itbis',
'itbis_purchase_18', 'purchase_invoice', 'current', '', ''),
'do_tax_itbis_16_compra': ('do_account_11040102', 'itbis',
'itbis_purchase_16', 'purchase_invoice', 'special', '', ''),
'do_tax_itbis_9_compra': ('do_account_11040103', 'itbis',
'itbis_purchase_9', 'purchase_invoice', 'special', '', ''),
'do_tax_itbis_8_venta': ('do_account_21020104', 'itbis',
'itbis_sale_8', 'sale_invoice', 'special', '', ''),
'do_tax_itbis_8_compra': ('do_account_11040104', 'itbis',
'itbis_purchase_8', 'purchase_invoice', 'special', '', ''),
'do_tax_itbis_exento': ('', 'itbis',
'itbis_exempt', 'sale_invoice', 'current', '', ''),
'do_tax_itbis_tasa_cero': ('do_account_21020105', 'itbis',
'itbis_zero_rate', 'sale_invoice', 'current', '', ''),
'do_tax_ret_itbis_30': ('do_account_21021101', 'itbis_withholding',
'itbis_withholding_30', 'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_2_adq': ('do_account_11040601',
'itbis_withholding_acquirer', 'itbis_withholding_acquirer_2',
'payment_withholding', 'current', '', ''),
'do_tax_ret_isr_hon_5': ('do_account_21021301', 'isr_withholding',
'isr_legal_entity_services_5', 'purchase_invoice', 'current', '', ''),
'do_tax_ret_isr_serv_10': ('do_account_21021302', 'isr_withholding',
'isr_individual_services_10', 'purchase_invoice', 'current', '', ''),
'do_tax_ret_isr_div_10': ('do_account_21020601', 'isr_withholding',
'isr_dividends_10', 'payment_withholding', 'current', '', ''),
'do_tax_ret_isr_int_10': ('do_account_21021501', 'isr_withholding',
'isr_interest_individual_10', 'payment_withholding', 'current', '', ''),
'do_tax_ret_isr_alq_10': ('do_account_21021401', 'isr_withholding',
'isr_rent_10', 'purchase_invoice', 'current', '', ''),
'do_tax_ret_isr_est_15': ('do_account_11040801', 'isr_withholding',
'isr_state_1_5', 'sale_invoice', 'current', '', ''),
'do_tax_ret_isr_est_5': ('do_account_11040802', 'isr_withholding',
'isr_state_5', 'sale_invoice', 'current', '', ''),
'do_tax_ret_isr_bovine_1': ('do_account_21021801', 'isr_withholding',
'isr_bovine_meat_1', 'purchase_invoice', 'current', '', ''),
'do_tax_ret_isr_exporter_25': ('do_account_11040803', 'isr_withholding',
'isr_exporter_sales_2_5', 'sale_invoice', 'current', '', ''),
'do_tax_ret_isr_int_pj_1': ('do_account_21021502', 'isr_withholding',
'isr_interest_legal_entity_1', 'payment_withholding', 'current', '', ''),
'do_tax_ret_isr_premios_25': ('do_account_21021701', 'isr_withholding',
'isr_prizes_25', 'payment_withholding', 'current', '', ''),
'do_tax_ret_isr_premios_10': ('do_account_21021702', 'isr_withholding',
'isr_prizes_10', 'payment_withholding', 'current', '', ''),
'do_tax_ret_isr_premios_15': ('do_account_21021703', 'isr_withholding',
'isr_prizes_15', 'payment_withholding', 'current', '', ''),
'do_tax_ret_isr_tragamonedas_10': ('do_account_21021704',
'isr_withholding', 'isr_slot_machine_prizes_10',
'payment_withholding', 'current', '', ''),
'do_tax_ret_isr_other_income_10': ('do_account_21020301',
'isr_withholding', 'isr_other_income_10', 'purchase_invoice',
'current', '', ''),
'do_tax_ret_isr_ext_27': ('do_account_21020701', 'isr_withholding',
'isr_foreign_services_27', 'purchase_invoice', 'current', '', ''),
'do_tax_ret_isr_ext_10': ('do_account_21020702', 'isr_withholding',
'isr_foreign_interest_10', 'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_100_inf': ('do_account_21020201',
'itbis_withholding', 'itbis_withholding_100_services',
'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_75_inf': ('do_account_21021201',
'itbis_withholding', 'itbis_withholding_75_informal',
'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_75_inf_16': ('do_account_21021202',
'itbis_withholding', 'itbis_withholding_75_informal_16',
'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_100_goods_18': ('do_account_21021203',
'itbis_withholding', 'itbis_withholding_100_informal_goods_18',
'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_100_goods_16': ('do_account_21021204',
'itbis_withholding', 'itbis_withholding_100_informal_goods_16',
'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_rst_18': ('do_account_21020202',
'itbis_withholding', 'itbis_withholding_rst_18',
'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_rst_16': ('do_account_21020203',
'itbis_withholding', 'itbis_withholding_rst_16',
'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_insurance_100': ('do_account_21020204',
'itbis_withholding', 'itbis_withholding_insurance_100',
'purchase_invoice', 'current', '', ''),
'do_tax_ret_itbis_airline_100': ('do_account_11040701',
'itbis_withholding', 'itbis_withholding_airline_100',
'sale_invoice', 'current', '', ''),
'do_tax_ret_itbis_society_30_suf': ('do_account_11040702',
'itbis_withholding', 'itbis_withholding_society_30_suffered',
'sale_invoice', 'current', '', ''),
'do_tax_ret_itbis_hotel_100': ('do_account_11040703',
'itbis_withholding', 'itbis_withholding_hotel_100',
'sale_invoice', 'current', '', ''),
'do_tax_ret_itbis_state_100': ('do_account_11040704',
'itbis_withholding', 'itbis_withholding_state_100',
'sale_invoice', 'current', '', ''),
'do_tax_isc_bebidas_alc': ('do_account_21020801', 'isc',
'isc_alcohol_10', 'sale_invoice', 'current', '', ''),
'do_tax_isc_tabaco': ('do_account_21020802', 'isc',
'isc_tobacco_20', 'sale_invoice', 'current', '', ''),
'do_tax_isc_telecom': ('do_account_21020803', 'isc',
'isc_telecom_10', 'sale_invoice', 'current', '', ''),
'do_tax_isc_combustibles_16': ('do_account_21020804', 'isc',
'isc_fossil_fuel_16', 'sale_invoice', 'current', '', ''),
'do_tax_isc_avtur_65': ('do_account_21020807', 'isc',
'isc_avtur_6_5', 'sale_invoice', 'current', '', ''),
'do_tax_isc_fuel_rd2_gallon': ('do_account_21020808', 'isc',
'isc_fuel_rd2_gallon', 'sale_invoice', 'current', '', ''),
'do_tax_ret_isc_insurance_100': ('do_account_21020806', 'isc',
'isc_insurance_withholding_100', 'purchase_invoice', 'current', '', ''),
'do_tax_isc_vehiculos': ('do_account_21020805', 'isc',
'isc_vehicle_17', 'asset_transfer', 'current', '', ''),
'do_tax_cdt_indotel': ('do_account_21020901', 'cdt',
'cdt_indotel_2', 'sale_invoice', 'current', '', ''),
'do_tax_propina_10': ('do_account_21020501', 'tip',
'legal_tip_10', 'sale_invoice', 'current', '', ''),
'do_tax_cheques_015': ('do_account_21021901', 'others',
'check_transfer_tax_015', 'bank_charge', 'historical', '',
'datetime.date(2026, 7, 2)'),
'do_tax_cheques_020': ('do_account_21021902', 'others',
'check_transfer_tax_020', 'bank_charge', 'current',
'datetime.date(2026, 7, 3)', ''),
'do_tax_activos_1': ('do_account_21020502', 'others',
'asset_tax_1', 'annual_declaration', 'current', '', ''),
'do_tax_iti_3': ('do_account_21021001', 'others',
'real_estate_transfer_3', 'asset_transfer', 'current', '', ''),
}
TAX_CODE_LINE_AUDIT = {
'do_tcl_itbis18v_inv': '+',
'do_tcl_itbis18v_cr': '-',
'do_tcl_itbis18c_inv': '-',
'do_tcl_itbis18c_cr': '+',
'do_tcl_ret_itbis_inv': '-',
'do_tcl_ret_itbis_cr': '+',
'do_tcl_ret_itbis_adq_inv': '+',
'do_tcl_ret_itbis_adq_cr': '-',
'do_tcl_ret_itbis_inf75_inv': '-',
'do_tcl_ret_itbis_inf75_cr': '+',
'do_tcl_isr_hon_inv': '-',
'do_tcl_isr_hon_cr': '+',
'do_tcl_isr_est_inv': '+',
'do_tcl_isr_est_cr': '-',
'do_tcl_isc_comb_inv': '+',
'do_tcl_isc_comb_cr': '-',
'do_tcl_chq_inv': '+',
'do_tcl_chq_cr': '-',
'do_tcl_chq020_inv': '+',
'do_tcl_chq020_cr': '-',
}
IFRS_REQUIRED_ACCOUNT_CODES = {
'1', '11', '12',
'1101', '1102', '1103', '1104', '1105', '1106', '1107', '1110',
'110101', '110103', '110104', '110201', '110205', '110301',
'110305', '110601', '110701', '110702', '110703', '111001',
'111002',
'1201', '1205', '1206', '1207', '1208', '1209',
'120101', '120191', '120192', '120501', '120591', '120592',
'120601', '120701', '120702', '120703', '120801', '120891',
'120892', '120901', '120991', '120992',
'2', '21', '22', '23',
'2101', '2104', '2105', '2106', '2201', '2301', '2302', '2303',
'2304',
'210101', '210401', '210501', '210601', '220101', '230201',
'230202', '230301', '230401',
'3', '31', '3101', '3104', '3105', '3106', '310601', '310604',
'4', '41', '42', '4101', '4102', '4103', '4104', '4201', '4208',
'4209', '4210',
'5', '51', '5101', '5102', '5106',
'6', '61', '62', '63', '6101', '6103', '6111', '6112', '6115',
'6116', '6117', '6118', '6119', '6120', '6201', '6203', '6206',
'6207', '6301', '6302', '6303',
'7', '7101', '7102',
}
IFRS_ACCOUNT_TYPE_AUDIT = {
'111002': 'do_type_current_asset',
'120192': 'do_type_fixed_asset',
'120292': 'do_type_fixed_asset',
'120392': 'do_type_fixed_asset',
'120591': 'do_type_rou_asset',
'120592': 'do_type_rou_asset',
'120891': 'do_type_investment_property',
'120892': 'do_type_investment_property',
'120992': 'do_type_intangible',
'7101': 'do_type_control',
'7102': 'do_type_control',
}
IFRS_POLICY_COVERAGE = {
'NIC 1': {'11', '12', '21', '23', '3106', '7101', '7102'},
'NIC 2': {'1103', '110305', '5101', '5106'},
'NIIF 9': {'110205', '110701', '110702', '110703', '120701',
'120702', '120703', '4208', '6206', '310604'},
'NIIF 15': {'110601', '210501', '4101', '4102', '4103', '4104'},
'NIIF 16': {'120501', '120591', '120592', '230201', '230202',
'6112', '6203'},
'NIC 12': {'120601', '230301', '6301', '6302', '6303'},
'NIC 16': {'120101', '120191', '120192', '6110', '6116'},
'NIC 36': {'111002', '120192', '120292', '120392', '120592',
'120892', '120992', '6116', '6117', '4206'},
'NIC 37': {'220101', '230401', '6118', '4207'},
'NIC 38': {'120901', '120991', '120992', '6111', '6117'},
'NIC 40': {'120801', '120891', '120892', '4209', '6207'},
'NIIF 5': {'111001', '111002', '210601', '4210', '6120'},
}
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')
TaxCodeLine = pool.get('account.tax.code.line')
TaxRule = pool.get('account.tax.rule')
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 [
'111002', '120192', '120292', '120392', '120591',
'120592', '120891', '120892', '120992', '7101', '7102',
'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']:
with self.subTest(code=code):
self.assertTrue(Account.search([
('company', '=', company.id),
('code', '=', code),
('closed', '!=', True),
], limit=1))
company_ifrs_types = {
'111002': 'Activos corrientes',
'120591': 'Activos por derecho de uso',
'120592': 'Activos por derecho de uso',
'120891': 'Propiedades de inversión',
'120892': 'Propiedades de inversión',
'120992': 'Activos intangibles',
'7101': 'Cuentas de cierre y control',
'7102': 'Cuentas de cierre y control',
}
for code, account_type in company_ifrs_types.items():
with self.subTest(code=code, account_type=account_type):
account, = Account.search([
('company', '=', company.id),
('code', '=', code),
('closed', '!=', True),
], limit=1)
self.assertEqual(account.type.name, account_type)
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))
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'),
('tax_fiscal_type', '=', 'itbis_withholding_30'),
('rate', '=', Decimal('-0.054')),
], limit=1))
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))
check_015, = Tax.search([
('company', '=', company.id),
('description', '=', 'Impuesto Cheques y Transferencias 0.15%'),
], limit=1)
check_020, = Tax.search([
('company', '=', company.id),
('description', '=', 'Impuesto Cheques y Transferencias 0.20%'),
], limit=1)
bank_rule, = TaxRule.search([
('company', '=', company.id),
('name', '=', (
'Regla Bancaria Cheques / Transferencias '
'Electrónicas (RD)')),
], limit=1)
self.assertEqual(check_015.end_date, datetime.date(2026, 7, 2))
self.assertEqual(check_015.dgii_fiscal_status, 'historical')
self.assertEqual(check_020.start_date, datetime.date(2026, 7, 3))
self.assertEqual(check_020.dgii_fiscal_status, 'current')
self.assertEqual(
bank_rule.apply(check_015, {
'date': datetime.date(2026, 7, 2),
}),
[check_015.id])
self.assertEqual(
bank_rule.apply(check_015, {
'date': datetime.date(2026, 7, 3),
}),
[check_020.id])
real_tax_code_signs = {
('ITBIS 18% Ventas', 'invoice'): '+',
('ITBIS 18% Ventas', 'credit'): '-',
('ITBIS 18% Compras', 'invoice'): '-',
('ITBIS 18% Compras', 'credit'): '+',
('Retención ITBIS Gran Contribuyente 30%', 'invoice'): '-',
('Retención ITBIS Gran Contribuyente 30%', 'credit'): '+',
('Retención ISR Persona Física 10%', 'invoice'): '-',
('Retención ISR Persona Física 10%', 'credit'): '+',
('Retención ISR Estado 1.5%', 'invoice'): '+',
('Retención ISR Estado 1.5%', 'credit'): '-',
('Impuesto Cheques y Transferencias 0.20%', 'invoice'): '+',
('Impuesto Cheques y Transferencias 0.20%', 'credit'): '-',
}
for (description, line_type), operator in real_tax_code_signs.items():
with self.subTest(description=description, line_type=line_type):
tax, = Tax.search([
('company', '=', company.id),
('description', '=', description),
], limit=1)
line, = TaxCodeLine.search([
('tax', '=', tax.id),
('type', '=', line_type),
('amount', '=', 'tax'),
], limit=1)
self.assertEqual(line.operator, operator)
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_ifrs_chart_is_complete_and_typed(self):
accounts = {
values['code']: values
for _, _, model, values in _iter_xml_records(
'account_chart_do.xml')
if model == 'account.account.template' and values.get('code')
}
types = {
record_id: values
for _, record_id, model, values in _iter_xml_records(
'account_chart_do.xml')
if model == 'account.account.type.template'
}
self.assertLessEqual(IFRS_REQUIRED_ACCOUNT_CODES, set(accounts))
self.assertEqual(types['do_type_control']['statement'], 'off-balance')
self.assertEqual(
types['do_type_deferred_tax_asset']['statement'], 'balance')
self.assertEqual(
types['do_type_deferred_tax_liability']['statement'], 'balance')
self.assertEqual(types['do_type_rou_asset']['statement'], 'balance')
self.assertEqual(
types['do_type_investment_property']['statement'], 'balance')
self.assertEqual(types['do_type_intangible']['statement'], 'balance')
missing_type = [
(code, values['name'])
for code, values in accounts.items()
if values.get('closed') != 'True' and not values.get('type')
]
self.assertEqual(missing_type, [])
for code, account_type in IFRS_ACCOUNT_TYPE_AUDIT.items():
with self.subTest(code=code):
self.assertEqual(accounts[code]['type'], account_type)
def test_ifrs_policy_matrix_is_represented_in_chart(self):
accounts = {
values['code']
for _, _, model, values in _iter_xml_records(
'account_chart_do.xml')
if model == 'account.account.template' and values.get('code')
}
for standard, codes in IFRS_POLICY_COVERAGE.items():
with self.subTest(standard=standard):
self.assertLessEqual(codes, accounts)
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'
}
accounts = {
record_id: values
for _, record_id, model, values in _iter_xml_records(
'account_chart_do.xml')
if model == 'account.account.template'
}
tax_kind_codes = {code for code, _ in TAX_KIND}
fiscal_type_codes = {code for code, _ in TAX_FISCAL_TYPE}
application_codes = {code for code, _ in TAX_APPLICATION}
fiscal_status_codes = {code for code, _ in DGII_FISCAL_STATUS}
self.assertEqual(len(taxes), 55)
self.assertEqual(set(taxes), set(TAX_TEMPLATE_AUDIT))
for record_id, expected in TAX_TEMPLATE_AUDIT.items():
account_id, tax_kind, fiscal_type, application, status, start, end = (
expected)
with self.subTest(record_id=record_id):
values = taxes[record_id]
self.assertEqual(values.get('invoice_account', ''), account_id)
self.assertEqual(
values.get('credit_note_account', ''), account_id)
if account_id:
self.assertIn(account_id, accounts)
else:
self.assertEqual(values['type'], 'none')
self.assertFalse(values.get('rate'))
self.assertEqual(values['tax_kind'], tax_kind)
self.assertEqual(values['tax_fiscal_type'], fiscal_type)
self.assertEqual(values['tax_application'], application)
self.assertEqual(values['dgii_fiscal_status'], status)
self.assertEqual(values.get('start_date', ''), start)
self.assertEqual(values.get('end_date', ''), end)
self.assertIn(tax_kind, tax_kind_codes)
self.assertIn(fiscal_type, fiscal_type_codes)
self.assertIn(application, application_codes)
self.assertIn(status, fiscal_status_codes)
self.assertTrue(values.get('dgii_legal_reference'))
self.assertTrue(values.get('dgii_legal_article'))
self.assertTrue(values.get('dgii_form_hint'))
self.assertTrue(values.get('legal_notice'))
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'])
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')
self.assertEqual(
taxes['do_tax_cheques_020']['tax_kind'], 'others')
self.assertEqual(
taxes['do_tax_cheques_015']['end_date'],
'datetime.date(2026, 7, 2)')
self.assertEqual(
taxes['do_tax_cheques_015']['dgii_fiscal_status'],
'historical')
self.assertEqual(
taxes['do_tax_cheques_020']['start_date'],
'datetime.date(2026, 7, 3)')
self.assertEqual(
taxes['do_tax_cheques_020']['dgii_fiscal_status'],
'current')
self.assertEqual(
taxes['do_tax_cheques_020']['invoice_account'],
'do_account_21021902')
self.assertIn(
"Decimal('0.20')/100",
taxes['do_tax_cheques_020']['rate'])
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')
for record_id, operator in TAX_CODE_LINE_AUDIT.items():
with self.subTest(record_id=record_id):
self.assertEqual(lines[record_id]['operator'], operator)
self.assertEqual(lines['do_tcl_itbis18v_inv']['operator'], '+')
self.assertEqual(lines['do_tcl_itbis18c_inv']['operator'], '-')
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'], '+')
self.assertEqual(lines['do_tcl_prop_inv']['code'], 'do_tc_others_tip')
def test_tax_rule_templates_include_date_sensitive_bank_tax(self):
rules = {
record_id: values
for _, record_id, model, values in _iter_xml_records(
'tax_rule_do.xml')
if model == 'account.tax.rule.template'
}
lines = {
record_id: values
for _, record_id, model, values in _iter_xml_records(
'tax_rule_do.xml')
if model == 'account.tax.rule.line.template'
}
self.assertIn('do_tax_rule_bank_check_transfer', rules)
self.assertEqual(
lines['do_trline_bank_check_transfer_015']['origin_tax'],
'do_tax_cheques_015')
self.assertEqual(
lines['do_trline_bank_check_transfer_015']['tax'],
'do_tax_cheques_015')
self.assertEqual(
lines['do_trline_bank_check_transfer_015']['end_date'],
'datetime.date(2026, 7, 2)')
self.assertEqual(
lines['do_trline_bank_check_transfer_020']['origin_tax'],
'do_tax_cheques_015')
self.assertEqual(
lines['do_trline_bank_check_transfer_020']['tax'],
'do_tax_cheques_020')
self.assertEqual(
lines['do_trline_bank_check_transfer_020']['start_date'],
'datetime.date(2026, 7, 3)')
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)))
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]
status_codes = [code for code, _ in DGII_FISCAL_STATUS]
self.assertEqual(len(fiscal_codes), len(set(fiscal_codes)))
self.assertEqual(len(application_codes), len(set(application_codes)))
self.assertEqual(len(status_codes), len(set(status_codes)))
del ModuleTestCase