From 6b32c610f5bbe7125c3ed4990fb752ce90e9834e Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Wed, 22 Jan 2025 14:38:07 +0100 Subject: [PATCH] dont write to immutable-dict --- document.py | 35 ++++++++++++++++++----------------- tests/document.py | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/document.py b/document.py index 1c8f3f6..8389c98 100644 --- a/document.py +++ b/document.py @@ -429,10 +429,10 @@ class Incoming(metaclass=PoolMeta): config = Configuration.get_singleton() - if not hasattr(self, 'parsed_data'): - self.parsed_data = {} - if not isinstance(self.parsed_data, dict): - self.parsed_data = {} + p_data = {} + if hasattr(self, 'parsed_data'): + if isinstance(self.parsed_data, dict): + p_data.update(self.parsed_data) # rsm:CrossIndustryInvoice xpath_cross_ind = ['rsm:CrossIndustryInvoice'] @@ -449,7 +449,7 @@ class Incoming(metaclass=PoolMeta): msg='invalid type-code: %(code)s (expect: 380, 381)' % { 'code': str(inv_code)})) - self.parsed_data['invoice_number'] = self._readxml_getvalue( + p_data['invoice_number'] = self._readxml_getvalue( xmltree, xpath_exchg_doc + ['ram:ID']) # invoice-date @@ -461,7 +461,7 @@ class Incoming(metaclass=PoolMeta): 'document_incoming_invoice_xml.msg_convert_error', msg='invalid date-format: %(code)s (expect: 102)' % { 'code': str(date_format)})) - self.parsed_data['invoice_date'] = self._readxml_convertdate( + p_data['invoice_date'] = self._readxml_convertdate( self._readxml_getvalue(xmltree, date_path)) # IncludedNote, 1st line --> 'description', 2nd ff. --> 'comment' @@ -479,7 +479,7 @@ class Incoming(metaclass=PoolMeta): for y in ['Content', 'ContentCode', 'SubjectCode'] }) if note_list: - self.parsed_data['note_list'] = note_list + p_data['note_list'] = note_list # rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction xpath_suppl_chain = xpath_cross_ind + [ @@ -496,14 +496,14 @@ class Incoming(metaclass=PoolMeta): xmltree, xpath_appl_head_agree + ['ram:SellerTradeParty'], create_party=add_party) if seller_party: - self.parsed_data['seller_party'] = seller_party + p_data['seller_party'] = seller_party # company party buyer_party = self._readxml_party_data( xmltree, xpath_appl_head_agree + ['ram:BuyerTradeParty'], create_party=False) if buyer_party: - self.parsed_data['buyer_party'] = buyer_party + p_data['buyer_party'] = buyer_party # invoice - lines # rsm:CrossIndustryInvoice/ @@ -519,15 +519,15 @@ class Incoming(metaclass=PoolMeta): lines_data.append( self._readxml_invoice_line(xmltree, xpath_line_item, x)) if lines_data: - self.parsed_data['lines_data'] = lines_data + p_data['lines_data'] = lines_data # payment data xpath_payment = xpath_suppl_chain + [ 'ram:ApplicableHeaderTradeSettlement'] - self.parsed_data['payment'] = {} - self.parsed_data['payment']['reference'] = self._readxml_getvalue( + p_data['payment'] = {} + p_data['payment']['reference'] = self._readxml_getvalue( xmltree, xpath_payment + ['ram:PaymentReference']) - self.parsed_data['payment']['currency'] = self._readxml_getvalue( + p_data['payment']['currency'] = self._readxml_getvalue( xmltree, xpath_payment + ['ram:InvoiceCurrencyCode']) # num bank accounts @@ -578,7 +578,7 @@ class Incoming(metaclass=PoolMeta): for x in bank_account.keys() if bank_account[x]}) if bank_accounts: - self.parsed_data['payment']['bank'] = bank_accounts + p_data['payment']['bank'] = bank_accounts # invoice-taxes xpath_invoice_taxes = xpath_payment + ['ram:ApplicableTradeTax'] @@ -595,7 +595,7 @@ class Incoming(metaclass=PoolMeta): ('ram:DueDateTypeCode', 'duecode'), ('ram:RateApplicablePercent', 'percent', Decimal)]) if taxes: - self.parsed_data['payment']['taxes'] = taxes + p_data['payment']['taxes'] = taxes xpath_payterms = xpath_payment + ['ram:SpecifiedTradePaymentTerms'] xpath_discount = ['ram:ApplicableTradePaymentDiscountTerms'] @@ -617,7 +617,7 @@ class Incoming(metaclass=PoolMeta): 'discount_amount', Decimal) ]) if pay_terms: - self.parsed_data['payment']['terms'] = pay_terms + p_data['payment']['terms'] = pay_terms # total xpath_total = xpath_payment + [ @@ -634,7 +634,8 @@ class Incoming(metaclass=PoolMeta): ('ram:DuePayableAmount', 'duepayable', Decimal), ]) if total: - self.parsed_data['total'] = total[0] + p_data['total'] = total[0] + self.parsed_data = p_data def _readxml_getinvoiceline(self, invoice, line_data): """ create invoice line in memory diff --git a/tests/document.py b/tests/document.py index 81917f0..3ba1074 100644 --- a/tests/document.py +++ b/tests/document.py @@ -14,7 +14,7 @@ from trytond.modules.company.tests import create_company, set_company from trytond.modules.account.tests import create_chart, get_fiscalyear -parsed_data_facturx = { +parsed_data_facturx_extended = { 'invoice_number': 'RE2024.01234', 'invoice_date': date(2024, 6, 17), 'note_list': [{ @@ -44,7 +44,7 @@ parsed_data_facturx = { 'name': 'Name of Product 1', 'description': 'Description of Product 1', 'unit_net_price': {'amount': Decimal('1350.00')}, - 'quantity': {'billed': Decimal('1.0')}, + 'quantity': {'billed': Decimal('1.0'), 'unit_code': 'KGM'}, 'taxes': [{ 'type': 'VAT', 'category_code': 'S', @@ -76,7 +76,7 @@ parsed_data_facturx = { 'code': '123', 'description': 'Kilogram', 'uom': 'kg', - 'value': '23'}], + 'value': Decimal('123.0')}], 'classification': [{ 'code': '3c', 'name': 'product-class 1'}], 'serialno': [{'lot': '22', 'serial': '1234'}], @@ -96,6 +96,7 @@ parsed_data_facturx = { 'basequantity': Decimal('1.0')}, 'quantity': { 'billed': Decimal('1.5'), + 'unit_code': 'KGM', 'package': Decimal('1.5')}, 'taxes': [{ 'type': 'VAT', @@ -107,7 +108,7 @@ parsed_data_facturx = { 'name': 'Name of Product 3', 'description': 'Description of Product 3', 'unit_net_price': {'amount': Decimal('150.00')}, - 'quantity': {'billed': Decimal('2.0')}, + 'quantity': {'billed': Decimal('2.0'), 'unit_code': 'MTR'}, 'taxes': [{ 'type': 'VAT', 'category_code': 'S', @@ -184,6 +185,20 @@ def set_invoice_sequences(fiscalyear): class DocumentTestCase(object): """ check import of xml + pdf files """ + def prep_sorted_dict(self, data): + """ sort dict by keys, + konvert tuple to list to revert changes by self.parsed_data + + Args: + data (dict): dict-data + """ + return { + k: ( + self.prep_sorted_dict(v) if isinstance(v, dict) + else list(v) if isinstance(v, tuple) + else v) + for k, v in sorted(data.items(), key=lambda item: item[0])} + def prep_incomingdoc_run_worker(self): """ run tasks from queue """ @@ -290,10 +305,10 @@ class DocumentTestCase(object): self.assertEqual(funcname, 'facturx_extended') incoming._readxml_facturx_extended(xml_data) - self.assertEqual(incoming.parsed_data, parsed_data_facturx) + self.assertEqual(incoming.parsed_data, parsed_data_facturx_extended) @with_transaction() - def test_xmldoc_import_facturx(self): + def test_xmldoc_import_facturx_extended(self): """ create incoming-document, load xml, detect type """ pool = Pool() @@ -371,7 +386,8 @@ class DocumentTestCase(object): # check target of incoming invoice number invoice = document._process_supplier_invoice() self.assertEqual(invoice.number, 'RE2024.01234') - self.assertTrue(not hasattr(invoice, 'reference')) + self.assertEqual(document.xsd_type, 'Factur-X extended') + self.assertEqual(invoice.reference, None) config.number_target = 'reference' config.save() @@ -379,7 +395,7 @@ class DocumentTestCase(object): invoice = document._process_supplier_invoice() self.assertEqual(invoice.type, 'in') self.assertEqual(invoice.reference, 'RE2024.01234') - self.assertTrue(not hasattr(invoice, 'number')) + self.assertEqual(invoice.number, None) self.assertEqual(invoice.invoice_date, date(2024, 6, 17)) self.assertEqual(invoice.currency.name, 'usd') self.assertEqual(invoice.company.rec_name, 'm-ds') @@ -407,9 +423,11 @@ class DocumentTestCase(object): # seller-party was already created by 'invoice.save()' # a few lines above, # the party-id in 'seller_party' means: dont create this party - parsed_ori = copy.deepcopy(parsed_data_facturx) + parsed_ori = copy.deepcopy(parsed_data_facturx_extended) parsed_ori['seller_party']['party'] = invoice.party.id - self.assertEqual(document.parsed_data, parsed_ori) + self.assertEqual( + self.prep_sorted_dict(document.parsed_data), + self.prep_sorted_dict(parsed_ori)) attachment, = IrAttachment.search([ ('resource.party', '=', invoice.party, 'account.invoice'),