dont write to immutable-dict

This commit is contained in:
Frederik Jaeckel 2025-01-22 14:38:07 +01:00
parent 0d31e60772
commit 6b32c610f5
2 changed files with 46 additions and 27 deletions

View file

@ -429,10 +429,10 @@ class Incoming(metaclass=PoolMeta):
config = Configuration.get_singleton() config = Configuration.get_singleton()
if not hasattr(self, 'parsed_data'): p_data = {}
self.parsed_data = {} if hasattr(self, 'parsed_data'):
if not isinstance(self.parsed_data, dict): if isinstance(self.parsed_data, dict):
self.parsed_data = {} p_data.update(self.parsed_data)
# rsm:CrossIndustryInvoice # rsm:CrossIndustryInvoice
xpath_cross_ind = ['rsm:CrossIndustryInvoice'] xpath_cross_ind = ['rsm:CrossIndustryInvoice']
@ -449,7 +449,7 @@ class Incoming(metaclass=PoolMeta):
msg='invalid type-code: %(code)s (expect: 380, 381)' % { msg='invalid type-code: %(code)s (expect: 380, 381)' % {
'code': str(inv_code)})) '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']) xmltree, xpath_exchg_doc + ['ram:ID'])
# invoice-date # invoice-date
@ -461,7 +461,7 @@ class Incoming(metaclass=PoolMeta):
'document_incoming_invoice_xml.msg_convert_error', 'document_incoming_invoice_xml.msg_convert_error',
msg='invalid date-format: %(code)s (expect: 102)' % { msg='invalid date-format: %(code)s (expect: 102)' % {
'code': str(date_format)})) '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)) self._readxml_getvalue(xmltree, date_path))
# IncludedNote, 1st line --> 'description', 2nd ff. --> 'comment' # IncludedNote, 1st line --> 'description', 2nd ff. --> 'comment'
@ -479,7 +479,7 @@ class Incoming(metaclass=PoolMeta):
for y in ['Content', 'ContentCode', 'SubjectCode'] for y in ['Content', 'ContentCode', 'SubjectCode']
}) })
if note_list: if note_list:
self.parsed_data['note_list'] = note_list p_data['note_list'] = note_list
# rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction # rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction
xpath_suppl_chain = xpath_cross_ind + [ xpath_suppl_chain = xpath_cross_ind + [
@ -496,14 +496,14 @@ class Incoming(metaclass=PoolMeta):
xmltree, xpath_appl_head_agree + ['ram:SellerTradeParty'], xmltree, xpath_appl_head_agree + ['ram:SellerTradeParty'],
create_party=add_party) create_party=add_party)
if seller_party: if seller_party:
self.parsed_data['seller_party'] = seller_party p_data['seller_party'] = seller_party
# company party # company party
buyer_party = self._readxml_party_data( buyer_party = self._readxml_party_data(
xmltree, xpath_appl_head_agree + ['ram:BuyerTradeParty'], xmltree, xpath_appl_head_agree + ['ram:BuyerTradeParty'],
create_party=False) create_party=False)
if buyer_party: if buyer_party:
self.parsed_data['buyer_party'] = buyer_party p_data['buyer_party'] = buyer_party
# invoice - lines # invoice - lines
# rsm:CrossIndustryInvoice/ # rsm:CrossIndustryInvoice/
@ -519,15 +519,15 @@ class Incoming(metaclass=PoolMeta):
lines_data.append( lines_data.append(
self._readxml_invoice_line(xmltree, xpath_line_item, x)) self._readxml_invoice_line(xmltree, xpath_line_item, x))
if lines_data: if lines_data:
self.parsed_data['lines_data'] = lines_data p_data['lines_data'] = lines_data
# payment data # payment data
xpath_payment = xpath_suppl_chain + [ xpath_payment = xpath_suppl_chain + [
'ram:ApplicableHeaderTradeSettlement'] 'ram:ApplicableHeaderTradeSettlement']
self.parsed_data['payment'] = {} p_data['payment'] = {}
self.parsed_data['payment']['reference'] = self._readxml_getvalue( p_data['payment']['reference'] = self._readxml_getvalue(
xmltree, xpath_payment + ['ram:PaymentReference']) 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']) xmltree, xpath_payment + ['ram:InvoiceCurrencyCode'])
# num bank accounts # num bank accounts
@ -578,7 +578,7 @@ class Incoming(metaclass=PoolMeta):
for x in bank_account.keys() for x in bank_account.keys()
if bank_account[x]}) if bank_account[x]})
if bank_accounts: if bank_accounts:
self.parsed_data['payment']['bank'] = bank_accounts p_data['payment']['bank'] = bank_accounts
# invoice-taxes # invoice-taxes
xpath_invoice_taxes = xpath_payment + ['ram:ApplicableTradeTax'] xpath_invoice_taxes = xpath_payment + ['ram:ApplicableTradeTax']
@ -595,7 +595,7 @@ class Incoming(metaclass=PoolMeta):
('ram:DueDateTypeCode', 'duecode'), ('ram:DueDateTypeCode', 'duecode'),
('ram:RateApplicablePercent', 'percent', Decimal)]) ('ram:RateApplicablePercent', 'percent', Decimal)])
if taxes: if taxes:
self.parsed_data['payment']['taxes'] = taxes p_data['payment']['taxes'] = taxes
xpath_payterms = xpath_payment + ['ram:SpecifiedTradePaymentTerms'] xpath_payterms = xpath_payment + ['ram:SpecifiedTradePaymentTerms']
xpath_discount = ['ram:ApplicableTradePaymentDiscountTerms'] xpath_discount = ['ram:ApplicableTradePaymentDiscountTerms']
@ -617,7 +617,7 @@ class Incoming(metaclass=PoolMeta):
'discount_amount', Decimal) 'discount_amount', Decimal)
]) ])
if pay_terms: if pay_terms:
self.parsed_data['payment']['terms'] = pay_terms p_data['payment']['terms'] = pay_terms
# total # total
xpath_total = xpath_payment + [ xpath_total = xpath_payment + [
@ -634,7 +634,8 @@ class Incoming(metaclass=PoolMeta):
('ram:DuePayableAmount', 'duepayable', Decimal), ('ram:DuePayableAmount', 'duepayable', Decimal),
]) ])
if total: 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): def _readxml_getinvoiceline(self, invoice, line_data):
""" create invoice line in memory """ create invoice line in memory

View file

@ -14,7 +14,7 @@ from trytond.modules.company.tests import create_company, set_company
from trytond.modules.account.tests import create_chart, get_fiscalyear from trytond.modules.account.tests import create_chart, get_fiscalyear
parsed_data_facturx = { parsed_data_facturx_extended = {
'invoice_number': 'RE2024.01234', 'invoice_number': 'RE2024.01234',
'invoice_date': date(2024, 6, 17), 'invoice_date': date(2024, 6, 17),
'note_list': [{ 'note_list': [{
@ -44,7 +44,7 @@ parsed_data_facturx = {
'name': 'Name of Product 1', 'name': 'Name of Product 1',
'description': 'Description of Product 1', 'description': 'Description of Product 1',
'unit_net_price': {'amount': Decimal('1350.00')}, 'unit_net_price': {'amount': Decimal('1350.00')},
'quantity': {'billed': Decimal('1.0')}, 'quantity': {'billed': Decimal('1.0'), 'unit_code': 'KGM'},
'taxes': [{ 'taxes': [{
'type': 'VAT', 'type': 'VAT',
'category_code': 'S', 'category_code': 'S',
@ -76,7 +76,7 @@ parsed_data_facturx = {
'code': '123', 'code': '123',
'description': 'Kilogram', 'description': 'Kilogram',
'uom': 'kg', 'uom': 'kg',
'value': '23'}], 'value': Decimal('123.0')}],
'classification': [{ 'classification': [{
'code': '3c', 'name': 'product-class 1'}], 'code': '3c', 'name': 'product-class 1'}],
'serialno': [{'lot': '22', 'serial': '1234'}], 'serialno': [{'lot': '22', 'serial': '1234'}],
@ -96,6 +96,7 @@ parsed_data_facturx = {
'basequantity': Decimal('1.0')}, 'basequantity': Decimal('1.0')},
'quantity': { 'quantity': {
'billed': Decimal('1.5'), 'billed': Decimal('1.5'),
'unit_code': 'KGM',
'package': Decimal('1.5')}, 'package': Decimal('1.5')},
'taxes': [{ 'taxes': [{
'type': 'VAT', 'type': 'VAT',
@ -107,7 +108,7 @@ parsed_data_facturx = {
'name': 'Name of Product 3', 'name': 'Name of Product 3',
'description': 'Description of Product 3', 'description': 'Description of Product 3',
'unit_net_price': {'amount': Decimal('150.00')}, 'unit_net_price': {'amount': Decimal('150.00')},
'quantity': {'billed': Decimal('2.0')}, 'quantity': {'billed': Decimal('2.0'), 'unit_code': 'MTR'},
'taxes': [{ 'taxes': [{
'type': 'VAT', 'type': 'VAT',
'category_code': 'S', 'category_code': 'S',
@ -184,6 +185,20 @@ def set_invoice_sequences(fiscalyear):
class DocumentTestCase(object): class DocumentTestCase(object):
""" check import of xml + pdf files """ 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): def prep_incomingdoc_run_worker(self):
""" run tasks from queue """ run tasks from queue
""" """
@ -290,10 +305,10 @@ class DocumentTestCase(object):
self.assertEqual(funcname, 'facturx_extended') self.assertEqual(funcname, 'facturx_extended')
incoming._readxml_facturx_extended(xml_data) 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() @with_transaction()
def test_xmldoc_import_facturx(self): def test_xmldoc_import_facturx_extended(self):
""" create incoming-document, load xml, detect type """ create incoming-document, load xml, detect type
""" """
pool = Pool() pool = Pool()
@ -371,7 +386,8 @@ class DocumentTestCase(object):
# check target of incoming invoice number # check target of incoming invoice number
invoice = document._process_supplier_invoice() invoice = document._process_supplier_invoice()
self.assertEqual(invoice.number, 'RE2024.01234') 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.number_target = 'reference'
config.save() config.save()
@ -379,7 +395,7 @@ class DocumentTestCase(object):
invoice = document._process_supplier_invoice() invoice = document._process_supplier_invoice()
self.assertEqual(invoice.type, 'in') self.assertEqual(invoice.type, 'in')
self.assertEqual(invoice.reference, 'RE2024.01234') 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.invoice_date, date(2024, 6, 17))
self.assertEqual(invoice.currency.name, 'usd') self.assertEqual(invoice.currency.name, 'usd')
self.assertEqual(invoice.company.rec_name, 'm-ds') self.assertEqual(invoice.company.rec_name, 'm-ds')
@ -407,9 +423,11 @@ class DocumentTestCase(object):
# seller-party was already created by 'invoice.save()' # seller-party was already created by 'invoice.save()'
# a few lines above, # a few lines above,
# the party-id in 'seller_party' means: dont create this party # 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 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([ attachment, = IrAttachment.search([
('resource.party', '=', invoice.party, 'account.invoice'), ('resource.party', '=', invoice.party, 'account.invoice'),