# -*- coding: utf-8 -*- # This file is part of the document-incoming-invoice-xml-module # from m-ds for Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import os.path import copy from decimal import Decimal from datetime import date from trytond.tests.test_tryton import with_transaction from trytond.pool import Pool from trytond.exceptions import UserError from trytond.modules.company.tests import create_company, set_company from trytond.modules.account.tests import create_chart, get_fiscalyear parsed_data_facturx = { 'invoice_number': 'RE2024.01234', 'invoice_date': date(2024, 6, 17), 'note_list': [{ 'Content': 'Description of invoice', 'ContentCode': None, 'SubjectCode': None, }, { 'Content': 'Some notes to the customer.', 'ContentCode': '1', 'SubjectCode': None, }, { 'Content': 'Goes to field comment.', 'ContentCode': '22', 'SubjectCode': '42'}], 'seller_party': { 'name': 'Name of the Supplier', 'postal_code': '12345', 'street': 'Street of Supplier No 1', 'city': 'Berlin'}, 'buyer_party': { 'name': 'Our Company', 'postal_code': '23456', 'street': 'Address Line 1\nAddress Line 2', 'city': 'Potsdam'}, 'lines_data': [{ 'line_no': '1', 'name': 'Name of Product 1', 'description': 'Description of Product 1', 'unit_net_price': {'amount': Decimal('1350.00')}, 'quantity': {'billed': Decimal('1.0')}, 'taxes': [{ 'type': 'VAT', 'category_code': 'S', 'percent': Decimal('19.00')}], 'total': {'amount': Decimal('1350.00')}, }, { 'convert_note': [ 'skip: /rsm:CrossIndustryInvoice/' + 'rsm:SupplyChainTradeTransaction/' + 'ram:IncludedSupplyChainTradeLineItem[2]/' + 'ram:SpecifiedLineTradeDelivery/' + 'ram:ActualDeliverySupplyChainEvent'], 'line_no': '2', 'line_note': 'Description of Line 2\n' + 'Description of Line 2, line 2', 'prod_id': '2', 'glob_id': '3', 'seller_id': '4', 'buyer_id': '5', 'industy_id': '6', 'model_id': '7', 'name': 'Name of Product 2', 'description': 'Description of Product 2', 'lot': 'batch23', 'brand_name': 'Brand-Name', 'model_name': 'Model-Name', 'trade_country': 'DE', 'attributes': [{ 'code': '123', 'description': 'Kilogram', 'uom': 'kg', 'value': '23'}], 'classification': [{ 'code': '3c', 'name': 'product-class 1'}], 'serialno': [{'lot': '22', 'serial': '1234'}], 'refprod': [{ 'id': '1', 'global_id': '2', 'seller_id': '3', 'buyer_id': '4', 'name': 'ref-prod-1', 'description': 'description of ref-prod-1', 'quantity': Decimal('1.0')}], 'unit_net_price': { 'amount': Decimal('800.00'), 'basequantity': Decimal('1.0')}, 'unit_gross_price': { 'amount': Decimal('950.00'), 'basequantity': Decimal('1.0')}, 'quantity': { 'billed': Decimal('1.5'), 'package': Decimal('1.5')}, 'taxes': [{ 'type': 'VAT', 'category_code': 'S', 'percent': Decimal('19.00')}], 'total': {'amount': Decimal('1200.00')}, }, { 'line_no': '3', 'name': 'Name of Product 3', 'description': 'Description of Product 3', 'unit_net_price': {'amount': Decimal('150.00')}, 'quantity': {'billed': Decimal('2.0')}, 'taxes': [{ 'type': 'VAT', 'category_code': 'S', 'percent': Decimal('7.00')}], 'total': {'amount': Decimal('300.00')}, }], 'payment': { 'reference': 'RE2024.01234', 'currency': 'EUR', 'bank': [{ 'info': 'Wire transfer', 'type': '30', 'debitor_iban': 'DE02300209000106531065', 'creditor_iban': 'DE02300209000106531065', 'creditor_name': 'mbs', 'card_id': 'DE02300209000106531065', 'card_holder_name': 'Card Holder', 'institution': 'WELADED1PMB'}], 'taxes': [{ 'amount': Decimal('484.5'), 'type': 'VAT', 'base': Decimal('2550.0'), 'category_code': 'S', 'percent': Decimal('19.00'), }, { 'amount': Decimal('21.0'), 'type': 'VAT', 'base': Decimal('300.0'), 'category_code': 'S', 'percent': Decimal('7.00')}], 'terms': [{ 'description': 'Payment description', 'duedate': date(2024, 7, 1), 'mandat_id': 'mandat id', 'amount': Decimal('3355.50'), 'discount_date': date(2024, 7, 2), 'discount_measure': Decimal('10.0'), 'discount_base': Decimal('3355.0'), 'discount_perc': Decimal('2.0'), 'discount_amount': Decimal('70.0')}]}, 'total': { 'amount': Decimal('1350.00'), 'taxbase': Decimal('2850.00'), 'taxtotal': Decimal('505.5'), 'grand': Decimal('3355.50'), 'duepayable': Decimal('3355.50')}} def set_invoice_sequences(fiscalyear): pool = Pool() Sequence = pool.get('ir.sequence.strict') SequenceType = pool.get('ir.sequence.type') InvoiceSequence = pool.get('account.fiscalyear.invoice_sequence') ModelData = pool.get('ir.model.data') sequence = Sequence( name=fiscalyear.name, sequence_type=SequenceType(ModelData.get_id( 'account_invoice', 'sequence_type_account_invoice')), company=fiscalyear.company, ) sequence.save() fiscalyear.invoice_sequences = [] invoice_sequence = InvoiceSequence() invoice_sequence.fiscalyear = fiscalyear invoice_sequence.in_invoice_sequence = sequence invoice_sequence.in_credit_note_sequence = sequence invoice_sequence.out_invoice_sequence = sequence invoice_sequence.out_credit_note_sequence = sequence invoice_sequence.save() return fiscalyear class DocumentTestCase(object): """ check import of xml + pdf files """ def prep_incomingdoc_run_worker(self): """ run tasks from queue """ Queue = Pool().get('ir.queue') while True: tasks = Queue.search([]) if not tasks: break for task in tasks: task.run() Queue.delete(tasks) def prep_fiscalyear(self, company1): """ prepare fiscal year, sequences... """ pool = Pool() FiscalYear = pool.get('account.fiscalyear') fisc_year = get_fiscalyear(company1, today=date(2025, 1, 15)) set_invoice_sequences(fisc_year) fisc_year.save() FiscalYear.create_period([fisc_year]) def prep_prodcat_category(self, company): """ create product category """ pool = Pool() ProdCat = pool.get('product.category') Account = pool.get('account.account') Tax = pool.get('account.tax') # get accounts expense/revenue acc_exp, acc_rev, acc_tax, = Account.search([ ('name', 'in', ['Main Revenue', 'Main Expense', 'Main Tax']) ], order=[('name', 'ASC')]) self.assertEqual(acc_exp.name, 'Main Expense') self.assertEqual(acc_rev.name, 'Main Revenue') self.assertEqual(acc_tax.name, 'Main Tax') # check tax tax, = Tax.search([]) self.assertEqual(tax.name, '20% VAT') self.assertEqual(tax.invoice_account.name, 'Main Tax') self.assertEqual(tax.credit_note_account.name, 'Main Tax') tax_19, = Tax.copy([tax], { 'name': '19% VAT', 'rate': Decimal('0.19')}) tax_7, = Tax.copy([tax], { 'name': '7% VAT', 'rate': Decimal('0.07')}) p_cat, p_cat_19, tax_7, = ProdCat.create([{ 'name': 'Accounting', 'accounting': True, 'account_parent': False, 'account_expense': acc_exp.id, 'account_revenue': acc_rev.id, 'taxes_parent': False, 'customer_taxes': [('add', [tax.id])], 'supplier_taxes': [('add', [tax.id])], }, { 'name': 'Accounting 19%', 'accounting': True, 'account_parent': False, 'account_expense': acc_exp.id, 'account_revenue': acc_rev.id, 'taxes_parent': False, 'customer_taxes': [('add', [tax_19.id])], 'supplier_taxes': [('add', [tax_19.id])], }, { 'name': 'Accounting 7%', 'accounting': True, 'account_parent': False, 'account_expense': acc_exp.id, 'account_revenue': acc_rev.id, 'taxes_parent': False, 'customer_taxes': [('add', [tax_7.id])], 'supplier_taxes': [('add', [tax_7.id])], }]) self.assertEqual(p_cat.name, 'Accounting') self.assertEqual(p_cat.accounting, True) self.assertEqual(p_cat.account_parent, False) self.assertEqual(p_cat.taxes_parent, False) self.assertEqual(p_cat.account_expense.name, 'Main Expense') self.assertEqual(p_cat.account_revenue.name, 'Main Revenue') self.assertEqual(p_cat.customer_taxes[0].name, '20% VAT') self.assertEqual(p_cat.supplier_taxes[0].name, '20% VAT') return [p_cat, p_cat_19, tax_7] @with_transaction() def test_xmldoc_check_xml_read_facturx_extended(self): """ add incoming-dcument in memory, read xml into 'parsed_data' """ pool = Pool() IncDocument = pool.get('document.incoming') with open(os.path.join( os.path.split(__file__)[0], 'facturx-extended.xml'), 'rb') as fhdl: xml_txt = fhdl.read() incoming = IncDocument(data=xml_txt) (xsdtype, funcname, xml_data) = incoming._facturx_detect_content() self.assertEqual(xsdtype, 'Factur-X extended') self.assertEqual(funcname, 'facturx_extended') incoming._readxml_facturx_extended(xml_data) self.assertEqual(incoming.parsed_data, parsed_data_facturx) @with_transaction() def test_xmldoc_import_facturx(self): """ create incoming-document, load xml, detect type """ pool = Pool() IncDocument = pool.get('document.incoming') Configuration = pool.get('document.incoming.configuration') Party = pool.get('party.party') IrAttachment = pool.get('ir.attachment') company = create_company('m-ds') with set_company(company): create_chart(company=company, tax=True) self.prep_fiscalyear(company) product_categories = self.prep_prodcat_category(company) config = Configuration( product_category=product_categories) config.save() self.assertEqual(config.create_supplier, True) self.assertEqual(config.accept_other_company, False) self.assertEqual(config.number_target, 'reference') self.assertEqual(len(config.product_category), 3) self.assertEqual(config.product_category[0].name, 'Accounting') self.assertEqual(config.product_category[1].name, 'Accounting 19%') self.assertEqual(config.product_category[2].name, 'Accounting 7%') to_create = [] with open(os.path.join( os.path.split(__file__)[0], 'facturx-extended.xml'), 'rb') as fhdl: to_create.append({ 'data': fhdl.read(), 'name': 'facturx-extended.xml', 'type': 'supplier_invoice'}) document, = IncDocument.create(to_create) self.assertEqual(document.mime_type, 'application/xml') self.assertEqual(document.company.id, company.id) self.assertTrue(document.data.startswith( b'\n' + b'