dont write to immutable-dict
This commit is contained in:
parent
0d31e60772
commit
6b32c610f5
2 changed files with 46 additions and 27 deletions
35
document.py
35
document.py
|
@ -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
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
Loading…
Reference in a new issue