340 lines
15 KiB
Python
340 lines
15 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from lxml import etree
|
|
from textwrap import dedent
|
|
|
|
|
|
from odoo import Command
|
|
from odoo.tests import tagged
|
|
from odoo.addons.account_reports.tests.common import TestAccountReportsCommon
|
|
|
|
@tagged('post_install_l10n', 'post_install', '-at_install')
|
|
class TestBEIntrastatReport(TestAccountReportsCommon):
|
|
|
|
@classmethod
|
|
@TestAccountReportsCommon.setup_country('be')
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
italy = cls.env.ref('base.it')
|
|
cls.company_data['company'].company_registry = '0123456789'
|
|
cls.report = cls.env.ref('account_intrastat.intrastat_report')
|
|
cls.report_goods_handler = cls.env['account.intrastat.goods.report.handler']
|
|
cls.report_services_handler = cls.env['account.intrastat.services.be.report.handler']
|
|
cls.partner_a = cls.env['res.partner'].create({
|
|
'name': "Miskatonic University",
|
|
'country_id': italy.id,
|
|
})
|
|
|
|
cls.product_aeroplane = cls.env['product.product'].create({
|
|
'name': 'Dornier Aeroplane',
|
|
'intrastat_code_id': cls.env.ref('account_intrastat.commodity_code_2018_88023000').id,
|
|
'intrastat_supplementary_unit_amount': 1,
|
|
'weight': 3739,
|
|
})
|
|
cls.product_samples = cls.env['product.product'].create({
|
|
'name': 'Interesting Antarctic Rock and Soil Specimens',
|
|
'intrastat_code_id': cls.env.ref('account_intrastat.commodity_code_2023_25309050').id,
|
|
'weight': 19,
|
|
})
|
|
cls.product_water = cls.env['product.product'].create({
|
|
'name': 'Bottle of water',
|
|
'intrastat_code_id': cls.env.ref('account_intrastat.commodity_code_2018_1022130').id,
|
|
'weight': 1,
|
|
})
|
|
cls.inwards_vendor_bill = cls.env['account.move'].create({
|
|
'move_type': 'in_invoice',
|
|
'partner_id': cls.partner_a.id,
|
|
'invoice_date': '2022-05-15',
|
|
'date': '2022-05-15',
|
|
'intrastat_country_id': italy.id,
|
|
'company_id': cls.company_data['company'].id,
|
|
'invoice_line_ids': [Command.create({
|
|
'product_uom_id': cls.env.ref('uom.product_uom_unit').id,
|
|
'intrastat_transaction_id': cls.env.ref('account_intrastat.account_intrastat_transaction_11').id,
|
|
'product_id': cls.product_samples.id,
|
|
'quantity': 42,
|
|
'price_unit': 555.44,
|
|
})]
|
|
})
|
|
cls.outwards_customer_invoice = cls.env['account.move'].create({
|
|
'move_type': 'out_invoice',
|
|
'partner_id': cls.partner_a.id,
|
|
'invoice_date': '2022-05-15',
|
|
'date': '2022-05-15',
|
|
'intrastat_country_id': italy.id,
|
|
'company_id': cls.company_data['company'].id,
|
|
'invoice_line_ids': [
|
|
Command.create({
|
|
'product_uom_id': cls.env.ref('uom.product_uom_unit').id,
|
|
'product_id': cls.product_aeroplane.id,
|
|
'intrastat_transaction_id': cls.env.ref('account_intrastat.account_intrastat_transaction_11').id,
|
|
'quantity': 4,
|
|
'price_unit': 234000,
|
|
}),
|
|
# line wo product should be excluded
|
|
Command.create({
|
|
'intrastat_transaction_id': cls.env.ref('account_intrastat.account_intrastat_transaction_11').id,
|
|
'quantity': 4,
|
|
'price_unit': 1234,
|
|
}),
|
|
]
|
|
})
|
|
cls.product_service_a = cls.env['product.product'].create({
|
|
'name': 'Service A',
|
|
'intrastat_code_id': cls.env.ref('l10n_be_intrastat.service_code_2022_B2001').id,
|
|
'type': 'service',
|
|
})
|
|
cls.product_service_b = cls.env['product.product'].create({
|
|
'name': 'Service B',
|
|
'intrastat_code_id': cls.env.ref('l10n_be_intrastat.service_code_2022_B2101').id,
|
|
'type': 'service',
|
|
})
|
|
cls.outwards_service_customer_invoice = cls.env['account.move'].create({
|
|
'move_type': 'out_invoice',
|
|
'partner_id': cls.partner_a.id,
|
|
'invoice_date': '2022-05-15',
|
|
'date': '2022-05-15',
|
|
'intrastat_country_id': italy.id,
|
|
'company_id': cls.company_data['company'].id,
|
|
'invoice_line_ids': [
|
|
Command.create({
|
|
'product_uom_id': cls.env.ref('uom.product_uom_unit').id,
|
|
'intrastat_transaction_id': cls.env.ref(
|
|
'account_intrastat.account_intrastat_transaction_11'
|
|
).id,
|
|
'product_id': cls.product_service_a.id,
|
|
'quantity': 4,
|
|
'price_unit': 250,
|
|
}),
|
|
Command.create({
|
|
'product_uom_id': cls.env.ref('uom.product_uom_unit').id,
|
|
'intrastat_transaction_id': cls.env.ref(
|
|
'account_intrastat.account_intrastat_transaction_11'
|
|
).id,
|
|
'product_id': cls.product_service_b.id,
|
|
'quantity': 5,
|
|
'price_unit': 100,
|
|
}),
|
|
],
|
|
})
|
|
cls.in_refund_service = cls.env["account.move"].create({
|
|
"move_type": "in_refund",
|
|
"partner_id": cls.partner_a.id,
|
|
"invoice_date": "2022-05-15",
|
|
"date": "2022-05-15",
|
|
"intrastat_country_id": italy.id,
|
|
"company_id": cls.company_data["company"].id,
|
|
"invoice_line_ids": [Command.create({
|
|
"product_uom_id": cls.env.ref("uom.product_uom_unit").id,
|
|
"intrastat_transaction_id": cls.env.ref(
|
|
"account_intrastat.account_intrastat_transaction_11"
|
|
).id,
|
|
"product_id": cls.product_service_a.id,
|
|
"quantity": 4,
|
|
"price_unit": 100,
|
|
})],
|
|
})
|
|
cls.out_refund_service = cls.env["account.move"].create({
|
|
"move_type": "out_refund",
|
|
"partner_id": cls.partner_a.id,
|
|
"invoice_date": "2022-05-15",
|
|
"date": "2022-05-15",
|
|
"intrastat_country_id": italy.id,
|
|
"company_id": cls.company_data["company"].id,
|
|
"invoice_line_ids": [Command.create({
|
|
"product_uom_id": cls.env.ref("uom.product_uom_unit").id,
|
|
"intrastat_transaction_id": cls.env.ref(
|
|
"account_intrastat.account_intrastat_transaction_11"
|
|
).id,
|
|
"product_id": cls.product_service_a.id,
|
|
"quantity": 4,
|
|
"price_unit": 100,
|
|
})],
|
|
})
|
|
|
|
cls.vendor_bill_discount_100 = cls.env['account.move'].create({
|
|
'move_type': 'in_invoice',
|
|
'partner_id': cls.partner_a.id,
|
|
'invoice_date': '2022-05-15',
|
|
'date': '2022-05-15',
|
|
'intrastat_country_id': italy.id,
|
|
'company_id': cls.company_data['company'].id,
|
|
'invoice_line_ids': [(0, 0, {
|
|
'product_uom_id': cls.env.ref('uom.product_uom_unit').id,
|
|
'intrastat_transaction_id': cls.env.ref('account_intrastat.account_intrastat_transaction_11').id,
|
|
'product_id': cls.product_water.id,
|
|
'quantity': 44,
|
|
'price_unit': 555.44,
|
|
'discount': 100,
|
|
})]
|
|
})
|
|
|
|
# This tree represents the export with both kinds of reports (the extended version)
|
|
cls.expected_content_all = b'''
|
|
<DeclarationReport xmlns="http://www.onegate.eu/2010-01-01">
|
|
<Administration>
|
|
<From declarerType="KBO">0123456789</From>
|
|
<To>NBB</To>
|
|
<Domain>SXX</Domain>
|
|
</Administration>
|
|
<Report action="replace" code="EX19E" date="2022-05">
|
|
<Data close="true" form="EXF19E">
|
|
<Item>
|
|
<Dim prop="EXTRF">19</Dim>
|
|
<Dim prop="EXCNT">IT</Dim>
|
|
<Dim prop="EXTTA">11</Dim>
|
|
<Dim prop="EXTGO">25309050</Dim>
|
|
<Dim prop="EXTXVAL">23328.48</Dim>
|
|
<Dim prop="EXWEIGHT">798.00</Dim>
|
|
<Dim prop="EXTPC"></Dim>
|
|
<Dim prop="EXDELTRM"></Dim>
|
|
</Item>
|
|
</Data>
|
|
</Report>
|
|
<Report action="replace" code="INTRASTAT_X_E" date="2022-05">
|
|
<Data close="true" form="INTRASTAT_X_EF">
|
|
<Item>
|
|
<Dim prop="EXTRF">29</Dim>
|
|
<Dim prop="EXCNT">IT</Dim>
|
|
<Dim prop="EXTTA">11</Dim>
|
|
<Dim prop="EXTGO">88023000</Dim>
|
|
<Dim prop="EXTXVAL">936000.00</Dim>
|
|
<Dim prop="EXWEIGHT">14956.00</Dim>
|
|
<Dim prop="EXUNITS">4.0</Dim>
|
|
<Dim prop="EXCNTORI">QU</Dim>
|
|
<Dim prop="PARTNERID">QV999999999999</Dim>
|
|
<Dim prop="EXTPC"></Dim>
|
|
<Dim prop="EXDELTRM"></Dim>
|
|
</Item>
|
|
</Data>
|
|
</Report>
|
|
</DeclarationReport>
|
|
'''
|
|
|
|
def _set_options(self, options, arrivals=False, dispatches=False):
|
|
options['intrastat_type'][0]['selected'] = arrivals
|
|
options['intrastat_type'][1]['selected'] = dispatches
|
|
|
|
def test_dispatches_only(self):
|
|
""" Test generating an XML export containing only dispatches (when only the dispatches options is checked) """
|
|
self.inwards_vendor_bill.action_post()
|
|
self.outwards_customer_invoice.action_post()
|
|
|
|
options = self._generate_options(self.report, '2022-05-01', '2022-05-31')
|
|
self._set_options(options, dispatches=True)
|
|
|
|
dispatches_only_tree = etree.fromstring(
|
|
self.report_goods_handler.be_intrastat_export_to_xml(options)['file_content']
|
|
)
|
|
expected_tree = self.with_applied_xpath(
|
|
etree.fromstring(self.expected_content_all),
|
|
'''
|
|
<xpath expr="//{http://www.onegate.eu/2010-01-01}Report[@code='EX19E']" position="replace"></xpath>
|
|
'''
|
|
)
|
|
self.assertXmlTreeEqual(dispatches_only_tree, expected_tree)
|
|
|
|
def test_arrivals_only(self):
|
|
""" Test generating an XML export containing only arrivals (when only the arrivals options is checked) """
|
|
self.inwards_vendor_bill.action_post()
|
|
self.outwards_customer_invoice.action_post()
|
|
|
|
options = self._generate_options(self.report, '2022-05-01', '2022-05-31')
|
|
self._set_options(options, arrivals=True)
|
|
arrivals_only_tree = etree.fromstring(
|
|
self.report_goods_handler.be_intrastat_export_to_xml(options)['file_content']
|
|
)
|
|
expected_tree = self.with_applied_xpath(
|
|
etree.fromstring(self.expected_content_all),
|
|
'''
|
|
<xpath expr="//{http://www.onegate.eu/2010-01-01}Report[@code='INTRASTAT_X_E']" position="replace"></xpath>
|
|
'''
|
|
)
|
|
self.assertXmlTreeEqual(arrivals_only_tree, expected_tree)
|
|
|
|
def test_csv_goods_export(self):
|
|
self.inwards_vendor_bill.action_post()
|
|
self.outwards_customer_invoice.action_post()
|
|
options = self._generate_options(self.report, '2022-05-01', '2022-05-31')
|
|
self._set_options(options, arrivals=True)
|
|
csv = self.report_goods_handler.be_intrastat_export_to_csv(options)['file_content']
|
|
expected = '19;IT;11;;25309050;798.0;;23328;;\n'
|
|
self.assertEqual(csv, expected)
|
|
|
|
def test_csv_service_f02cms_export(self):
|
|
self.outwards_service_customer_invoice.action_post()
|
|
self.out_refund_service.action_post()
|
|
self.in_refund_service.action_post()
|
|
options = self._generate_options(self.report, '2022-05-01', '2022-05-31')
|
|
csv = self.report_services_handler.be_intrastat_export_to_csv(options)['file_content']
|
|
expected = dedent('''\
|
|
B2001;IT;EUR;1400;400
|
|
B2101;IT;EUR;500;0
|
|
''')
|
|
self.assertEqual(csv, expected)
|
|
|
|
def test_csv_service_non_intra_country_f02cms_export(self):
|
|
self.partner_a.country_id = self.env.ref('base.us').id
|
|
invoices = (
|
|
self.outwards_service_customer_invoice +
|
|
self.out_refund_service +
|
|
self.in_refund_service
|
|
)
|
|
invoices.intrastat_country_id = None
|
|
invoices.action_post()
|
|
options = self._generate_options(self.report, '2022-05-01', '2022-05-31')
|
|
csv = self.report_services_handler.be_intrastat_export_to_csv(options)['file_content']
|
|
expected = dedent('''\
|
|
B2001;US;EUR;1400;400
|
|
B2101;US;EUR;500;0
|
|
''')
|
|
self.assertEqual(csv, expected)
|
|
|
|
def test_csv_service_f01dgs_export(self):
|
|
self.outwards_service_customer_invoice.action_post()
|
|
self.out_refund_service.action_post()
|
|
self.in_refund_service.action_post()
|
|
report = self.env.ref('l10n_be_intrastat.intrastat_report_services_f01dgs')
|
|
options = self._generate_options(report, '2022-05-01', '2022-05-31')
|
|
csv = self.report_services_handler.be_intrastat_export_to_csv(options)['file_content']
|
|
expected = dedent('''\
|
|
B2001;IT;EUR;1400;400
|
|
B2001CN;IT;EUR;400;400
|
|
B2101;IT;EUR;500;0
|
|
''')
|
|
self.assertEqual(csv, expected)
|
|
|
|
def test_full_export(self):
|
|
""" Test generating an XML export for the whole """
|
|
options = self._generate_options(self.report, '2022-05-01', '2022-05-31', {'hide_0_lines': True})
|
|
arrivals, dispatches = options['intrastat_type']
|
|
arrivals['selected'], dispatches['selected'] = False, False
|
|
options = self.report.get_options(options)
|
|
|
|
# Both reports should be present, but they should be absent of items (until we post)
|
|
full_export_tree = etree.fromstring(self.report_goods_handler.be_intrastat_export_to_xml(options)['file_content'])
|
|
expected_tree = self.with_applied_xpath(
|
|
etree.fromstring(self.expected_content_all),
|
|
'''
|
|
<xpath expr="//{http://www.onegate.eu/2010-01-01}Report[@code='INTRASTAT_X_E']" position="attributes">
|
|
<attribute name="action">nihil</attribute>
|
|
</xpath>
|
|
<xpath expr="//{http://www.onegate.eu/2010-01-01}Data[@form='INTRASTAT_X_EF']/*" position="replace"></xpath>
|
|
<xpath expr="//{http://www.onegate.eu/2010-01-01}Report[@code='EX19E']" position="attributes">
|
|
<attribute name="action">nihil</attribute>
|
|
</xpath>
|
|
<xpath expr="//{http://www.onegate.eu/2010-01-01}Data[@form='EXF19E']/*" position="replace"></xpath>
|
|
'''
|
|
)
|
|
self.assertXmlTreeEqual(full_export_tree, expected_tree)
|
|
|
|
self.inwards_vendor_bill.action_post()
|
|
self.outwards_customer_invoice.action_post()
|
|
self.vendor_bill_discount_100.action_post()
|
|
|
|
self.assertXmlTreeEqual(
|
|
etree.fromstring(self.report_goods_handler.be_intrastat_export_to_xml(options)['file_content']),
|
|
etree.fromstring(self.expected_content_all),
|
|
)
|