from types import SimpleNamespace import inspect import unittest from trytond.modules.ncf_manager.ncf_manager import ( NCFManager, NCFManagerSequences) from trytond.modules.ncf_manager.sequence import Sequence from trytond.modules.ncf_manager.importer import ( normalize_dgii_row, parse_dgii_authorizations) from trytond.modules.ncf_manager.invoice import Invoice from trytond.modules.ncf_manager.party import Party, PartyNcfType class NcfManagerUnitTestCase(unittest.TestCase): HEADERS = ( 'NUM_SOL,NUM_AUTOR,FECHA_AUTOR,COMP,OBSERVACIONES,NUMERO_DESDE,' 'NUMERO_HASTA,CANTIDAD,CODTIPO,FECHA_SOLICITUD,ESTATUS,' 'CANTIDAD_SOLICITADA,TIPO_USO,RNC_IMPRENTA,IMPRENTA,' 'CANTIDAD_APROBADA,FECHA_VIGENCIA,DETALLE_LOG') ROW = ( '6009912073,6005423851,07/08/2026 13:45:02,CRÉDITO ELECTRÓNICO,' 'SOLUTEMA SRL,E310000000001,E310000000100,,31,' '07/08/2026 13:36:23,APROBADA,1000,ELECTRÓNICA,,,100,' '31/12/2027 0:00:00,Aviso, con comas') def test_manager_defaults_and_rec_name(self): self.assertEqual(NCFManager.default_state(), 'draft') manager = SimpleNamespace() manager.id = 42 manager.company = SimpleNamespace(rec_name='ACME') manager.app_number = 'APP001' self.assertEqual(NCFManager.get_rec_name(manager, 'name'), 'ACME - APP001') def test_sequence_defaults_and_rec_name(self): self.assertEqual(NCFManagerSequences.default_state(), 'draft') sequence = SimpleNamespace() sequence.ncf_type_string = 'Factura de Credito Fiscal - B01' self.assertEqual( NCFManagerSequences.get_rec_name(sequence, 'name'), 'Factura de Credito Fiscal ') def test_ir_sequence_on_change_values_for_ncf_type(self): sequence = SimpleNamespace() sequence.sequence_type = SimpleNamespace(name='Factura de Consumo') self.assertEqual(Sequence.on_change_with_prefix(sequence), 'B02') self.assertEqual(Sequence.on_change_with_padding(sequence), 8) self.assertEqual(Sequence.on_change_with_name(sequence), 'Factura de Consumo') def test_ir_sequence_quantities(self): sequence = SimpleNamespace() sequence.from_number = 10 sequence.until_number = 20 sequence.number_next = 12 self.assertEqual(Sequence.on_change_with_approved_qty(sequence), 11) self.assertEqual(Sequence.on_change_with_remaining_qty(sequence), 9) def test_unknown_ncf_type_has_empty_sequence_defaults(self): sequence = SimpleNamespace() sequence.sequence_type = SimpleNamespace(name='Unknown') self.assertIsNone(Sequence.on_change_with_prefix(sequence)) self.assertEqual(Sequence.on_change_with_padding(sequence), 0) def test_decomposed_electronic_sequence_name_is_supported(self): sequence = SimpleNamespace() sequence.sequence_type = SimpleNamespace(name='Compras Electro\u0301nico') self.assertEqual(Sequence.on_change_with_prefix(sequence), 'E41') self.assertEqual(Sequence.on_change_with_padding(sequence), 10) def test_amount_searcher_filters_the_requested_product_type(self): source = inspect.getsource( Invoice._search_amount_invoiced_by_product_type) self.assertIn('template.type == product_type', source) self.assertIn("line.type == 'line'", source) def test_party_ncf_type_is_stored_per_party_and_company(self): self.assertIn('ncf_types', Party._fields) self.assertEqual( Party._fields['ncf_types'].model_name, 'party.party.ncf_type') self.assertIn('party', PartyNcfType._fields) self.assertIn('company', PartyNcfType._fields) def test_csv_parser_preserves_unquoted_detail(self): source_format, rows = parse_dgii_authorizations( f'{self.HEADERS}\r\n{self.ROW}\r\n'.encode()) self.assertEqual(source_format, 'csv') self.assertEqual(rows[0]['NUM_AUTOR'], '6005423851') self.assertEqual(rows[0]['DETALLE_LOG'], 'Aviso, con comas') normalized = normalize_dgii_row(rows[0]) self.assertEqual(normalized['from_number'], 1) self.assertEqual(normalized['until_number'], 100) def test_html_xls_parser(self): cells = ''.join(f'