diff --git a/addons/account_edi_ubl_cii/data/cii_22_templates.xml b/addons/account_edi_ubl_cii/data/cii_22_templates.xml index 2bc3c38a11cc62886f9843f87c6e29549911f6ca..6cdad207459380bc86b54ce968df1cda0b838985 100644 --- a/addons/account_edi_ubl_cii/data/cii_22_templates.xml +++ b/addons/account_edi_ubl_cii/data/cii_22_templates.xml @@ -69,9 +69,21 @@ </ram:ApplicableTradeTax> </t> + <!-- Allowance/Charge on the line --> + <t t-foreach="line_vals.get('allowance_charge_vals_list')" t-as="allowance_charge_vals"> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator t-esc="allowance_charge_vals['indicator']"/> + </ram:ChargeIndicator> + <ram:ActualAmount t-esc="format_monetary(allowance_charge_vals['amount'], 2)"/> + <ram:ReasonCode t-esc="allowance_charge_vals['reason_code']"/> + <ram:Reason t-esc="allowance_charge_vals['reason']"/> + </ram:SpecifiedTradeAllowanceCharge> + </t> + <!-- Subtotal. --> <ram:SpecifiedTradeSettlementLineMonetarySummation> - <ram:LineTotalAmount t-out="format_monetary(line.price_subtotal, 2)"/> + <ram:LineTotalAmount t-esc="format_monetary(line_vals['line_total_amount'], 2)"/> </ram:SpecifiedTradeSettlementLineMonetarySummation> </ram:SpecifiedLineTradeSettlement> @@ -275,12 +287,12 @@ <!-- Summary. --> <ram:SpecifiedTradeSettlementHeaderMonetarySummation> <ram:LineTotalAmount - t-out="format_monetary(record.amount_untaxed, 2)"/> + t-esc="format_monetary(tax_basis_total_amount, 2)"/> <ram:TaxBasisTotalAmount - t-out="format_monetary(record.amount_untaxed, 2)"/> + t-esc="format_monetary(tax_basis_total_amount, 2)"/> <ram:TaxTotalAmount t-att-currencyID="currency.name" - t-out="format_monetary(record.amount_tax, 2)"/> + t-esc="format_monetary(tax_total_amount, 2)"/> <ram:GrandTotalAmount t-out="format_monetary(record.amount_total, 2)"/> <ram:TotalPrepaidAmount diff --git a/addons/account_edi_ubl_cii/models/account_edi_common.py b/addons/account_edi_ubl_cii/models/account_edi_common.py index e0f057ca8a66c9ada4fbf2e2107af4cd534a9215..6e6a501158c02b1630d036d8d508f5849a6b0f69 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_common.py +++ b/addons/account_edi_ubl_cii/models/account_edi_common.py @@ -572,6 +572,7 @@ class AccountEdiCommon(models.AbstractModel): product_uom_id = self.env.ref(uom_infered_xmlid[0], raise_if_not_found=False) # allow_charge_amount + fixed_taxes_list = [] allow_charge_amount = 0 # if positive: it's a discount, if negative: it's a charge allow_charge_nodes = tree.findall(xpath_dict['allowance_charge']) for allow_charge_el in allow_charge_nodes: @@ -581,8 +582,17 @@ class AccountEdiCommon(models.AbstractModel): else: discount_factor = -1 # it's a charge amount = allow_charge_el.find(xpath_dict['allowance_charge_amount']) + reason_code = allow_charge_el.find(xpath_dict['allowance_charge_reason_code']) + reason = allow_charge_el.find(xpath_dict['allowance_charge_reason']) if amount is not None: - allow_charge_amount += float(amount.text) * discount_factor + if reason_code is not None and reason_code.text == 'AEO' and reason is not None: + # Handle Fixed Taxes: when exporting from Odoo, we use the allowance_charge node + fixed_taxes_list.append({ + 'tax_name': reason.text, + 'tax_amount': float(amount.text), + }) + else: + allow_charge_amount += float(amount.text) * discount_factor # line_net_subtotal (mandatory) price_subtotal = None @@ -607,8 +617,9 @@ class AccountEdiCommon(models.AbstractModel): # discount discount = 0 + amount_fixed_taxes = sum(d['tax_amount'] for d in fixed_taxes_list) if billed_qty * price_unit != 0 and price_subtotal is not None: - discount = 100 * (1 - price_subtotal / (billed_qty * price_unit)) + discount = 100 * (1 - (price_subtotal - amount_fixed_taxes) / (billed_qty * price_unit)) # Sometimes, the xml received is very bad: unit price = 0, qty = 1, but price_subtotal = -200 # for instance, when filling a down payment as an invoice line. The equation in the docstring is not @@ -621,8 +632,31 @@ class AccountEdiCommon(models.AbstractModel): 'price_unit': price_unit, 'discount': discount, 'product_uom_id': product_uom_id, + 'fixed_taxes_list': fixed_taxes_list, } + def _import_retrieve_fixed_tax(self, invoice_line_form, fixed_tax_vals): + """ Retrieve the fixed tax at import, iteratively search for a tax: + 1. not price_include matching the name and the amount + 2. not price_include matching the amount + 3. price_include matching the name and the amount + 4. price_include matching the amount + """ + base_domain = [ + ('company_id', '=', invoice_line_form.company_id.id), + ('amount_type', '=', 'fixed'), + ('amount', '=', fixed_tax_vals['tax_amount']), + ] + for price_include in (False, True): + for name in (fixed_tax_vals['tax_name'], False): + domain = base_domain + [('price_include', '=', price_include)] + if name: + domain.append(('name', '=', name)) + tax = self.env['account.tax'].search(domain, limit=1) + if tax: + return tax + return self.env['account.tax'] + def _import_fill_invoice_line_taxes(self, journal, tax_nodes, invoice_line_form, inv_line_vals, logs): # Taxes: all amounts are tax excluded, so first try to fetch price_include=False taxes, # if no results, try to fetch the price_include=True taxes. If results, need to adapt the price_unit. @@ -644,6 +678,19 @@ class AccountEdiCommon(models.AbstractModel): inv_line_vals['price_unit'] *= (1 + tax_incl.amount / 100) else: logs.append(_("Could not retrieve the tax: %s %% for line '%s'.", amount, invoice_line_form.name)) + + # Handle Fixed Taxes + for fixed_tax_vals in inv_line_vals['fixed_taxes_list']: + tax = self._import_retrieve_fixed_tax(invoice_line_form, fixed_tax_vals) + if not tax: + # Nothing found: fix the price_unit s.t. line subtotal is matching the original invoice + inv_line_vals['price_unit'] += fixed_tax_vals['tax_amount'] + elif tax.price_include: + inv_line_vals['taxes'].append(tax.id) + inv_line_vals['price_unit'] += tax.amount + else: + inv_line_vals['taxes'].append(tax.id) + # Set the values on the line_form invoice_line_form.quantity = inv_line_vals['quantity'] if inv_line_vals.get('product_uom_id'): diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py b/addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py index 5e451139fbe5ac5b3d7406a92bc00c17ac1baeee..8a5eb4dfb4a95a12eba70209635aaaece10327fa 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py +++ b/addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py @@ -125,11 +125,16 @@ class AccountEdiXmlCII(models.AbstractModel): def grouping_key_generator(base_line, tax_values): tax = tax_values['tax_repartition_line'].tax_id - return { + grouping_key = { **self._get_tax_unece_codes(invoice, tax), 'amount': tax.amount, 'amount_type': tax.amount_type, } + # If the tax is fixed, we want to have one group per tax + # s.t. when the invoice is imported, we can try to guess the fixed taxes + if tax.amount_type == 'fixed': + grouping_key['tax_name'] = tax.name + return grouping_key # Validate the structure of the taxes self._validate_taxes(invoice) @@ -137,6 +142,18 @@ class AccountEdiXmlCII(models.AbstractModel): # Create file content. tax_details = invoice._prepare_edi_tax_details(grouping_key_generator=grouping_key_generator) + # Fixed Taxes: filter them on the document level, and adapt the totals + # Fixed taxes are not supposed to be taxes in real live. However, this is the way in Odoo to manage recupel + # taxes in Belgium. Since only one tax is allowed, the fixed tax is removed from totals of lines but added + # as an extra charge/allowance. + fixed_taxes_keys = [k for k in tax_details['tax_details'] if k['amount_type'] == 'fixed'] + for key in fixed_taxes_keys: + fixed_tax_details = tax_details['tax_details'].pop(key) + tax_details['tax_amount_currency'] -= fixed_tax_details['tax_amount_currency'] + tax_details['tax_amount'] -= fixed_tax_details['tax_amount'] + tax_details['base_amount_currency'] += fixed_tax_details['tax_amount_currency'] + tax_details['base_amount'] += fixed_tax_details['tax_amount'] + if 'siret' in invoice.company_id._fields and invoice.company_id.siret: seller_siret = invoice.company_id.siret else: @@ -195,6 +212,24 @@ class AccountEdiXmlCII(models.AbstractModel): else: template_values['document_context_id'] = "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended" + # Fixed taxes: add them as charges on the invoice lines + for line_vals in template_values['invoice_line_vals_list']: + line_vals['allowance_charge_vals_list'] = [] + for grouping_key, tax_detail in tax_details['tax_details_per_record'][line_vals['line']]['tax_details'].items(): + if grouping_key['amount_type'] == 'fixed': + line_vals['allowance_charge_vals_list'].append({ + 'indicator': 'true', + 'reason': tax_detail['tax_name'], + 'reason_code': 'AEO', + 'amount': tax_detail['tax_amount_currency'], + }) + sum_fixed_taxes = sum(x['amount'] for x in line_vals['allowance_charge_vals_list']) + line_vals['line_total_amount'] = line_vals['line'].price_subtotal + sum_fixed_taxes + + # Fixed taxes: set the total adjusted amounts on the document level + template_values['tax_basis_total_amount'] = tax_details['base_amount_currency'] + template_values['tax_total_amount'] = tax_details['tax_amount_currency'] + return template_values def _export_invoice(self, invoice): @@ -337,8 +372,10 @@ class AccountEdiXmlCII(models.AbstractModel): 'net_price_unit': './{*}SpecifiedLineTradeAgreement/{*}NetPriceProductTradePrice/{*}ChargeAmount', 'billed_qty': './{*}SpecifiedLineTradeDelivery/{*}BilledQuantity', 'allowance_charge': './/{*}SpecifiedLineTradeSettlement/{*}SpecifiedTradeAllowanceCharge', - 'allowance_charge_indicator': './{*}ChargeIndicator/{*}Indicator', # below allowance_charge node - 'allowance_charge_amount': './{*}ActualAmount', # below allowance_charge node + 'allowance_charge_indicator': './{*}ChargeIndicator/{*}Indicator', + 'allowance_charge_amount': './{*}ActualAmount', + 'allowance_charge_reason': './{*}Reason', + 'allowance_charge_reason_code': './{*}ReasonCode', 'line_total_amount': './{*}SpecifiedLineTradeSettlement/{*}SpecifiedTradeSettlementLineMonetarySummation/{*}LineTotalAmount', } inv_line_vals = self._import_fill_invoice_line_values(tree, xpath_dict, invoice_line, qty_factor) diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py index 2fcdff0dc7b54ad8911c01272a2855a33c9c787a..b0d6742a4b9cefff4faec5725a5d358d932c0ef2 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py +++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py @@ -170,19 +170,23 @@ class AccountEdiXmlUBL20(models.AbstractModel): return [] def _get_invoice_tax_totals_vals_list(self, invoice, taxes_vals): - return [{ + tax_totals_vals = { 'currency': invoice.currency_id, 'currency_dp': invoice.currency_id.decimal_places, 'tax_amount': taxes_vals['tax_amount_currency'], - 'tax_subtotal_vals': [{ - 'currency': invoice.currency_id, - 'currency_dp': invoice.currency_id.decimal_places, - 'taxable_amount': vals['base_amount_currency'], - 'tax_amount': vals['tax_amount_currency'], - 'percent': vals['_tax_category_vals_']['percent'], - 'tax_category_vals': vals['_tax_category_vals_'], - } for vals in taxes_vals['tax_details'].values()], - }] + 'tax_subtotal_vals': [], + } + for grouping_key, vals in taxes_vals['tax_details'].items(): + if grouping_key['tax_amount_type'] != 'fixed': + tax_totals_vals['tax_subtotal_vals'].append({ + 'currency': invoice.currency_id, + 'currency_dp': invoice.currency_id.decimal_places, + 'taxable_amount': vals['base_amount_currency'], + 'tax_amount': vals['tax_amount_currency'], + 'percent': vals['_tax_category_vals_']['percent'], + 'tax_category_vals': vals['_tax_category_vals_'], + }) + return [tax_totals_vals] def _get_invoice_line_item_vals(self, line, taxes_vals): """ Method used to fill the cac:InvoiceLine/cac:Item node. @@ -194,7 +198,7 @@ class AccountEdiXmlUBL20(models.AbstractModel): """ product = line.product_id - taxes = line.tax_ids.flatten_taxes_hierarchy() + taxes = line.tax_ids.flatten_taxes_hierarchy().filtered(lambda t: t.amount_type != 'fixed') tax_category_vals_list = self._get_tax_category_list(line.move_id, taxes) description = line.name and line.name.replace('\n', ', ') @@ -215,26 +219,10 @@ class AccountEdiXmlUBL20(models.AbstractModel): def _get_document_allowance_charge_vals_list(self, invoice): """ https://docs.peppol.eu/poacc/billing/3.0/bis/#_document_level_allowance_or_charge - The aim is to transform the ecotax/récupel into a charge at the document level. - Warning, as the charge is transformed into an allowance, we have to make sure no tax is created on the line - level, otherwise, the TaxInclusiveAmount, will be wrong. """ - vals_list = [] - #for line in invoice.line_ids: - # for tax in line.tax_ids: - # if tax.amount_type == 'fixed': - # total_amount += tax.amount - # vals_list.append({ - # 'charge_indicator': 'true', - # 'allowance_charge_reason_code': 'AEO', # "Collection and recycling" - # 'allowance_charge_reason': 'Collection and recycling', - # 'amount': float(tax.amount), - # 'currency_name': line.currency_id.name, - # 'currency_dp': line.currency_id.decimal_places, - # }) - return vals_list - - def _get_invoice_line_allowance_vals_list(self, line): + return [] + + def _get_invoice_line_allowance_vals_list(self, line, tax_values_list=None): """ Method used to fill the cac:InvoiceLine>cac:AllowanceCharge node. Allowances are distinguished from charges using the ChargeIndicator node with 'false' as value. @@ -245,8 +233,20 @@ class AccountEdiXmlUBL20(models.AbstractModel): :param line: An invoice line. :return: A list of python dictionaries. """ + fixed_tax_charge_vals_list = [] + for grouping_key, tax_details in tax_values_list['tax_details'].items(): + if grouping_key['tax_amount_type'] == 'fixed': + fixed_tax_charge_vals_list.append({ + 'currency_name': line.currency_id.name, + 'currency_dp': line.currency_id.decimal_places, + 'charge_indicator': 'true', + 'allowance_charge_reason_code': 'AEO', + 'allowance_charge_reason': tax_details['tax_name'], + 'amount': tax_details['tax_amount_currency'], + }) + if not line.discount: - return [] + return fixed_tax_charge_vals_list # Price subtotal without discount: net_price_subtotal = line.price_subtotal @@ -272,7 +272,7 @@ class AccountEdiXmlUBL20(models.AbstractModel): 'amount': gross_price_subtotal - net_price_subtotal, } - return [allowance_vals] + return [allowance_vals] + fixed_tax_charge_vals_list def _get_invoice_line_price_vals(self, line): """ Method used to fill the cac:InvoiceLine/cac:Price node. @@ -314,10 +314,14 @@ class AccountEdiXmlUBL20(models.AbstractModel): :param line: An invoice line. :return: A python dictionary. """ - allowance_charge_vals_list = self._get_invoice_line_allowance_vals_list(line) + allowance_charge_vals_list = self._get_invoice_line_allowance_vals_list(line, tax_values_list=taxes_vals) uom = super()._get_uom_unece_code(line) - + total_fixed_tax_amount = sum( + vals['amount'] + for vals in allowance_charge_vals_list + if vals['allowance_charge_reason_code'] == 'AEO' + ) return { 'currency': line.currency_id, 'currency_dp': line.currency_id.decimal_places, @@ -328,7 +332,7 @@ class AccountEdiXmlUBL20(models.AbstractModel): 'invoiced_quantity': line.quantity, 'invoiced_quantity_attrs': {'unitCode': uom}, - 'line_extension_amount': line.price_subtotal, + 'line_extension_amount': line.price_subtotal + total_fixed_tax_amount, 'allowance_charge_vals': allowance_charge_vals_list, 'tax_total_vals': self._get_invoice_tax_totals_vals_list(line.move_id, taxes_vals), @@ -340,11 +344,17 @@ class AccountEdiXmlUBL20(models.AbstractModel): def grouping_key_generator(base_line, tax_values): tax = tax_values['tax_repartition_line'].tax_id tax_category_vals = self._get_tax_category_list(invoice, tax)[0] - return { + grouping_key = { 'tax_category_id': tax_category_vals['id'], 'tax_category_percent': tax_category_vals['percent'], '_tax_category_vals_': tax_category_vals, + 'tax_amount_type': tax.amount_type, } + # If the tax is fixed, we want to have one group per tax + # s.t. when the invoice is imported, we can try to guess the fixed taxes + if tax.amount_type == 'fixed': + grouping_key['tax_name'] = tax.name + return grouping_key # Validate the structure of the taxes self._validate_taxes(invoice) @@ -352,6 +362,18 @@ class AccountEdiXmlUBL20(models.AbstractModel): # Compute the tax details for the whole invoice and each invoice line separately. taxes_vals = invoice._prepare_edi_tax_details(grouping_key_generator=grouping_key_generator) + # Fixed Taxes: filter them on the document level, and adapt the totals + # Fixed taxes are not supposed to be taxes in real live. However, this is the way in Odoo to manage recupel + # taxes in Belgium. Since only one tax is allowed, the fixed tax is removed from totals of lines but added + # as an extra charge/allowance. + fixed_taxes_keys = [k for k in taxes_vals['tax_details'] if k['tax_amount_type'] == 'fixed'] + for key in fixed_taxes_keys: + fixed_tax_details = taxes_vals['tax_details'].pop(key) + taxes_vals['tax_amount_currency'] -= fixed_tax_details['tax_amount_currency'] + taxes_vals['tax_amount'] -= fixed_tax_details['tax_amount'] + taxes_vals['base_amount_currency'] += fixed_tax_details['tax_amount_currency'] + taxes_vals['base_amount'] += fixed_tax_details['tax_amount'] + # Compute values for invoice lines. line_extension_amount = 0.0 @@ -424,7 +446,7 @@ class AccountEdiXmlUBL20(models.AbstractModel): 'currency': invoice.currency_id, 'currency_dp': invoice.currency_id.decimal_places, 'line_extension_amount': line_extension_amount, - 'tax_exclusive_amount': invoice.amount_untaxed, + 'tax_exclusive_amount': taxes_vals['base_amount_currency'], 'tax_inclusive_amount': invoice.amount_total, 'allowance_total_amount': allowance_total_amount or None, 'prepaid_amount': invoice.amount_total - invoice.amount_residual, @@ -606,8 +628,10 @@ class AccountEdiXmlUBL20(models.AbstractModel): 'net_price_unit': './{*}Price/{*}PriceAmount', 'billed_qty': './{*}InvoicedQuantity' if invoice.move_type in ('in_invoice', 'out_invoice') or qty_factor == -1 else './{*}CreditedQuantity', 'allowance_charge': './/{*}AllowanceCharge', - 'allowance_charge_indicator': './{*}ChargeIndicator', # below allowance_charge node - 'allowance_charge_amount': './{*}Amount', # below allowance_charge node + 'allowance_charge_indicator': './{*}ChargeIndicator', + 'allowance_charge_amount': './{*}Amount', + 'allowance_charge_reason': './{*}AllowanceChargeReason', + 'allowance_charge_reason_code': './{*}AllowanceChargeReasonCode', 'line_total_amount': './{*}LineExtensionAmount', } self._import_fill_invoice_line_values(tree, xpath_dict, invoice_line, qty_factor) diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py index f1155b0d3e9a9b70267820e14a5a91b1d04ecd0d..4ef1aeceb3f88c40427237a345d1886d6679b820 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py +++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py @@ -236,9 +236,9 @@ class AccountEdiXmlUBLBIS3(models.AbstractModel): return vals_list - def _get_invoice_line_allowance_vals_list(self, line): + def _get_invoice_line_allowance_vals_list(self, line, tax_values_list=None): # EXTENDS account.edi.xml.ubl_21 - vals_list = super()._get_invoice_line_allowance_vals_list(line) + vals_list = super()._get_invoice_line_allowance_vals_list(line, tax_values_list=tax_values_list) for vals in vals_list: vals['currency_dp'] = 2 @@ -352,7 +352,7 @@ class AccountEdiXmlUBLBIS3(models.AbstractModel): } for line in invoice.invoice_line_ids: - if len(line.tax_ids.filtered(lambda t: t.amount_type != 'fixed')) != 1: + if len(line.tax_ids.flatten_taxes_hierarchy().filtered(lambda t: t.amount_type != 'fixed')) != 1: # [UBL-SR-48]-Invoice lines shall have one and only one classified tax category. # /!\ exception: possible to have any number of ecotaxes (fixed tax) with a regular percentage tax constraints.update({'cen_en16931_tax_line': _("Each invoice line shall have one and only one tax.")}) diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_nlcius.py b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_nlcius.py index 005049c96ad991ef2c11282909aa4ef2574930f1..9ddbc8d38feb05f96cec57a3a8976dbd78e02d76 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_nlcius.py +++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_nlcius.py @@ -55,9 +55,9 @@ class AccountEdiXmlUBLNL(models.AbstractModel): vals.pop('country_subentity') return vals - def _get_invoice_line_allowance_vals_list(self, line): + def _get_invoice_line_allowance_vals_list(self, line, tax_values_list=None): # EXTENDS account.edi.xml.ubl_bis3 - vals_list = super()._get_invoice_line_allowance_vals_list(line) + vals_list = super()._get_invoice_line_allowance_vals_list(line, tax_values_list=tax_values_list) # [BR-NL-32] Use of Discount reason code ( AllowanceChargeReasonCode ) is not recommended. # [BR-EN-34] Use of Charge reason code ( AllowanceChargeReasonCode ) is not recommended. # Careful ! [BR-42]-Each Invoice line allowance (BG-27) shall have an Invoice line allowance reason (BT-139) diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/common.py b/addons/l10n_account_edi_ubl_cii_tests/tests/common.py index f913cfdfae8530421e6089a6f382931f992d8de6..c473f1dbf5c7226006e10b520e6a187ac555ad2b 100644 --- a/addons/l10n_account_edi_ubl_cii_tests/tests/common.py +++ b/addons/l10n_account_edi_ubl_cii_tests/tests/common.py @@ -30,6 +30,22 @@ class TestUBLCommon(AccountEdiTestCommon): cls.tax_armageddon.children_tax_ids.unlink() cls.tax_armageddon.unlink() + # Fixed Taxes + cls.recupel = cls.env['account.tax'].create({ + 'name': "RECUPEL", + 'amount_type': 'fixed', + 'amount': 1, + 'include_base_amount': True, + 'sequence': 1, + }) + cls.auvibel = cls.env['account.tax'].create({ + 'name': "AUVIBEL", + 'amount_type': 'fixed', + 'amount': 1, + 'include_base_amount': True, + 'sequence': 2, + }) + @classmethod def setup_company_data(cls, company_name, chart_template=None, **kwargs): # OVERRIDE to force the company with EUR currency. @@ -95,6 +111,11 @@ class TestUBLCommon(AccountEdiTestCommon): # Create empty account.move, then update a file if move_type == 'in_invoice': invoice = self._create_empty_vendor_bill() + elif move_type == 'out_invoice': + invoice = self.env['account.move'].create({ + 'move_type': move_type, + 'journal_id': self.company_data['default_journal_sale'].id, + }) else: invoice = self.env['account.move'].create({ 'move_type': move_type, diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case1.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case1.xml new file mode 100644 index 0000000000000000000000000000000000000000..ae8a5781ef4ec328118da5b1f6d6e20536d4cb33 --- /dev/null +++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case1.xml @@ -0,0 +1,132 @@ +<?xml version='1.0' encoding='UTF-8'?> +<Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" + xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" + xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"> + <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0 + </cbc:CustomizationID> + <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID> + <cbc:ID>___ignore___</cbc:ID> + <cbc:IssueDate>2017-01-01</cbc:IssueDate> + <cbc:DueDate>2017-02-28</cbc:DueDate> + <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode> + <cbc:Note>test narration</cbc:Note> + <cbc:DocumentCurrencyCode>USD</cbc:DocumentCurrencyCode> + <cbc:BuyerReference>ref_partner_2</cbc:BuyerReference> + <cac:OrderReference> + <cbc:ID>___ignore___</cbc:ID> + </cac:OrderReference> + <cac:AccountingSupplierParty> + <cac:Party> + <cbc:EndpointID schemeID="9925">BE0202239951</cbc:EndpointID> + <cac:PartyName> + <cbc:Name>partner_1</cbc:Name> + </cac:PartyName> + <cac:PostalAddress> + <cbc:StreetName>Chaussée de Namur 40</cbc:StreetName> + <cbc:CityName>Ramillies</cbc:CityName> + <cbc:PostalZone>1367</cbc:PostalZone> + <cac:Country> + <cbc:IdentificationCode>BE</cbc:IdentificationCode> + </cac:Country> + </cac:PostalAddress> + <cac:PartyTaxScheme> + <cbc:CompanyID>BE0202239951</cbc:CompanyID> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:PartyTaxScheme> + <cac:PartyLegalEntity> + <cbc:RegistrationName>partner_1</cbc:RegistrationName> + <cbc:CompanyID>BE0202239951</cbc:CompanyID> + </cac:PartyLegalEntity> + <cac:Contact> + <cbc:Name>partner_1</cbc:Name> + </cac:Contact> + </cac:Party> + </cac:AccountingSupplierParty> + <cac:AccountingCustomerParty> + <cac:Party> + <cbc:EndpointID schemeID="9925">BE0477472701</cbc:EndpointID> + <cac:PartyName> + <cbc:Name>partner_2</cbc:Name> + </cac:PartyName> + <cac:PostalAddress> + <cbc:StreetName>Rue des Bourlottes 9</cbc:StreetName> + <cbc:CityName>Ramillies</cbc:CityName> + <cbc:PostalZone>1367</cbc:PostalZone> + <cac:Country> + <cbc:IdentificationCode>BE</cbc:IdentificationCode> + </cac:Country> + </cac:PostalAddress> + <cac:PartyTaxScheme> + <cbc:CompanyID>BE0477472701</cbc:CompanyID> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:PartyTaxScheme> + <cac:PartyLegalEntity> + <cbc:RegistrationName>partner_2</cbc:RegistrationName> + <cbc:CompanyID>BE0477472701</cbc:CompanyID> + </cac:PartyLegalEntity> + <cac:Contact> + <cbc:Name>partner_2</cbc:Name> + </cac:Contact> + </cac:Party> + </cac:AccountingCustomerParty> + <cac:PaymentMeans> + <cbc:PaymentMeansCode name="credit transfer">30</cbc:PaymentMeansCode> + <cbc:PaymentID>___ignore___</cbc:PaymentID> + <cac:PayeeFinancialAccount> + <cbc:ID>BE15001559627230</cbc:ID> + </cac:PayeeFinancialAccount> + </cac:PaymentMeans> + <cac:PaymentTerms> + <cbc:Note>30% Advance End of Following Month</cbc:Note> + </cac:PaymentTerms> + <cac:TaxTotal> + <cbc:TaxAmount currencyID="USD">21.00</cbc:TaxAmount> + <cac:TaxSubtotal> + <cbc:TaxableAmount currencyID="USD">100.00</cbc:TaxableAmount> + <cbc:TaxAmount currencyID="USD">21.00</cbc:TaxAmount> + <cac:TaxCategory> + <cbc:ID>S</cbc:ID> + <cbc:Percent>21.0</cbc:Percent> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:TaxCategory> + </cac:TaxSubtotal> + </cac:TaxTotal> + <cac:LegalMonetaryTotal> + <cbc:LineExtensionAmount currencyID="USD">100.00</cbc:LineExtensionAmount> + <cbc:TaxExclusiveAmount currencyID="USD">100.00</cbc:TaxExclusiveAmount> + <cbc:TaxInclusiveAmount currencyID="USD">121.00</cbc:TaxInclusiveAmount> + <cbc:PrepaidAmount currencyID="USD">0.00</cbc:PrepaidAmount> + <cbc:PayableAmount currencyID="USD">121.00</cbc:PayableAmount> + </cac:LegalMonetaryTotal> + <cac:InvoiceLine> + <cbc:ID>___ignore___</cbc:ID> + <cbc:InvoicedQuantity unitCode="C62">1.0</cbc:InvoicedQuantity> + <cbc:LineExtensionAmount currencyID="USD">100.00</cbc:LineExtensionAmount> + <cac:AllowanceCharge> + <cbc:ChargeIndicator>true</cbc:ChargeIndicator> + <cbc:AllowanceChargeReasonCode>AEO</cbc:AllowanceChargeReasonCode> + <cbc:AllowanceChargeReason>RECUPEL</cbc:AllowanceChargeReason> + <cbc:Amount currencyID="USD">1.00</cbc:Amount> + </cac:AllowanceCharge> + <cac:Item> + <cbc:Description>product_a</cbc:Description> + <cbc:Name>product_a</cbc:Name> + <cac:ClassifiedTaxCategory> + <cbc:ID>S</cbc:ID> + <cbc:Percent>21.0</cbc:Percent> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:ClassifiedTaxCategory> + </cac:Item> + <cac:Price> + <cbc:PriceAmount currencyID="USD">99.00</cbc:PriceAmount> + </cac:Price> + </cac:InvoiceLine> +</Invoice> diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case2.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case2.xml new file mode 100644 index 0000000000000000000000000000000000000000..578fd806a65ce71216ce6aaec458b00960bcc64f --- /dev/null +++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case2.xml @@ -0,0 +1,138 @@ +<?xml version='1.0' encoding='UTF-8'?> +<Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" + xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" + xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"> + <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0 + </cbc:CustomizationID> + <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID> + <cbc:ID>___ignore___</cbc:ID> + <cbc:IssueDate>2017-01-01</cbc:IssueDate> + <cbc:DueDate>2017-02-28</cbc:DueDate> + <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode> + <cbc:Note>test narration</cbc:Note> + <cbc:DocumentCurrencyCode>USD</cbc:DocumentCurrencyCode> + <cbc:BuyerReference>ref_partner_2</cbc:BuyerReference> + <cac:OrderReference> + <cbc:ID>___ignore___</cbc:ID> + </cac:OrderReference> + <cac:AccountingSupplierParty> + <cac:Party> + <cbc:EndpointID schemeID="9925">BE0202239951</cbc:EndpointID> + <cac:PartyName> + <cbc:Name>partner_1</cbc:Name> + </cac:PartyName> + <cac:PostalAddress> + <cbc:StreetName>Chaussée de Namur 40</cbc:StreetName> + <cbc:CityName>Ramillies</cbc:CityName> + <cbc:PostalZone>1367</cbc:PostalZone> + <cac:Country> + <cbc:IdentificationCode>BE</cbc:IdentificationCode> + </cac:Country> + </cac:PostalAddress> + <cac:PartyTaxScheme> + <cbc:CompanyID>BE0202239951</cbc:CompanyID> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:PartyTaxScheme> + <cac:PartyLegalEntity> + <cbc:RegistrationName>partner_1</cbc:RegistrationName> + <cbc:CompanyID>BE0202239951</cbc:CompanyID> + </cac:PartyLegalEntity> + <cac:Contact> + <cbc:Name>partner_1</cbc:Name> + </cac:Contact> + </cac:Party> + </cac:AccountingSupplierParty> + <cac:AccountingCustomerParty> + <cac:Party> + <cbc:EndpointID schemeID="9925">BE0477472701</cbc:EndpointID> + <cac:PartyName> + <cbc:Name>partner_2</cbc:Name> + </cac:PartyName> + <cac:PostalAddress> + <cbc:StreetName>Rue des Bourlottes 9</cbc:StreetName> + <cbc:CityName>Ramillies</cbc:CityName> + <cbc:PostalZone>1367</cbc:PostalZone> + <cac:Country> + <cbc:IdentificationCode>BE</cbc:IdentificationCode> + </cac:Country> + </cac:PostalAddress> + <cac:PartyTaxScheme> + <cbc:CompanyID>BE0477472701</cbc:CompanyID> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:PartyTaxScheme> + <cac:PartyLegalEntity> + <cbc:RegistrationName>partner_2</cbc:RegistrationName> + <cbc:CompanyID>BE0477472701</cbc:CompanyID> + </cac:PartyLegalEntity> + <cac:Contact> + <cbc:Name>partner_2</cbc:Name> + </cac:Contact> + </cac:Party> + </cac:AccountingCustomerParty> + <cac:PaymentMeans> + <cbc:PaymentMeansCode name="credit transfer">30</cbc:PaymentMeansCode> + <cbc:PaymentID>___ignore___</cbc:PaymentID> + <cac:PayeeFinancialAccount> + <cbc:ID>BE15001559627230</cbc:ID> + </cac:PayeeFinancialAccount> + </cac:PaymentMeans> + <cac:PaymentTerms> + <cbc:Note>30% Advance End of Following Month</cbc:Note> + </cac:PaymentTerms> + <cac:TaxTotal> + <cbc:TaxAmount currencyID="USD">21.00</cbc:TaxAmount> + <cac:TaxSubtotal> + <cbc:TaxableAmount currencyID="USD">100.00</cbc:TaxableAmount> + <cbc:TaxAmount currencyID="USD">21.00</cbc:TaxAmount> + <cac:TaxCategory> + <cbc:ID>S</cbc:ID> + <cbc:Percent>21.0</cbc:Percent> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:TaxCategory> + </cac:TaxSubtotal> + </cac:TaxTotal> + <cac:LegalMonetaryTotal> + <cbc:LineExtensionAmount currencyID="USD">100.00</cbc:LineExtensionAmount> + <cbc:TaxExclusiveAmount currencyID="USD">100.00</cbc:TaxExclusiveAmount> + <cbc:TaxInclusiveAmount currencyID="USD">121.00</cbc:TaxInclusiveAmount> + <cbc:PrepaidAmount currencyID="USD">0.00</cbc:PrepaidAmount> + <cbc:PayableAmount currencyID="USD">121.00</cbc:PayableAmount> + </cac:LegalMonetaryTotal> + <cac:InvoiceLine> + <cbc:ID>___ignore___</cbc:ID> + <cbc:InvoicedQuantity unitCode="C62">1.0</cbc:InvoicedQuantity> + <cbc:LineExtensionAmount currencyID="USD">100.00</cbc:LineExtensionAmount> + <cac:AllowanceCharge> + <cbc:ChargeIndicator>true</cbc:ChargeIndicator> + <cbc:AllowanceChargeReasonCode>AEO</cbc:AllowanceChargeReasonCode> + <cbc:AllowanceChargeReason>RECUPEL</cbc:AllowanceChargeReason> + <cbc:Amount currencyID="USD">1.00</cbc:Amount> + </cac:AllowanceCharge> + <cac:AllowanceCharge> + <cbc:ChargeIndicator>true</cbc:ChargeIndicator> + <cbc:AllowanceChargeReasonCode>AEO</cbc:AllowanceChargeReasonCode> + <cbc:AllowanceChargeReason>AUVIBEL</cbc:AllowanceChargeReason> + <cbc:Amount currencyID="USD">1.00</cbc:Amount> + </cac:AllowanceCharge> + <cac:Item> + <cbc:Description>product_a</cbc:Description> + <cbc:Name>product_a</cbc:Name> + <cac:ClassifiedTaxCategory> + <cbc:ID>S</cbc:ID> + <cbc:Percent>21.0</cbc:Percent> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:ClassifiedTaxCategory> + </cac:Item> + <cac:Price> + <cbc:PriceAmount currencyID="USD">98.00</cbc:PriceAmount> + </cac:Price> + </cac:InvoiceLine> +</Invoice> diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case3.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case3.xml new file mode 100644 index 0000000000000000000000000000000000000000..3d13eec982797ff9c59c46ed3f92b2805167657c --- /dev/null +++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case3.xml @@ -0,0 +1,132 @@ +<?xml version='1.0' encoding='UTF-8'?> +<Invoice xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" + xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" + xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"> + <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0 + </cbc:CustomizationID> + <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID> + <cbc:ID>___ignore___</cbc:ID> + <cbc:IssueDate>2017-01-01</cbc:IssueDate> + <cbc:DueDate>2017-02-28</cbc:DueDate> + <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode> + <cbc:Note>test narration</cbc:Note> + <cbc:DocumentCurrencyCode>USD</cbc:DocumentCurrencyCode> + <cbc:BuyerReference>ref_partner_2</cbc:BuyerReference> + <cac:OrderReference> + <cbc:ID>___ignore___</cbc:ID> + </cac:OrderReference> + <cac:AccountingSupplierParty> + <cac:Party> + <cbc:EndpointID schemeID="9925">BE0202239951</cbc:EndpointID> + <cac:PartyName> + <cbc:Name>partner_1</cbc:Name> + </cac:PartyName> + <cac:PostalAddress> + <cbc:StreetName>Chaussée de Namur 40</cbc:StreetName> + <cbc:CityName>Ramillies</cbc:CityName> + <cbc:PostalZone>1367</cbc:PostalZone> + <cac:Country> + <cbc:IdentificationCode>BE</cbc:IdentificationCode> + </cac:Country> + </cac:PostalAddress> + <cac:PartyTaxScheme> + <cbc:CompanyID>BE0202239951</cbc:CompanyID> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:PartyTaxScheme> + <cac:PartyLegalEntity> + <cbc:RegistrationName>partner_1</cbc:RegistrationName> + <cbc:CompanyID>BE0202239951</cbc:CompanyID> + </cac:PartyLegalEntity> + <cac:Contact> + <cbc:Name>partner_1</cbc:Name> + </cac:Contact> + </cac:Party> + </cac:AccountingSupplierParty> + <cac:AccountingCustomerParty> + <cac:Party> + <cbc:EndpointID schemeID="9925">BE0477472701</cbc:EndpointID> + <cac:PartyName> + <cbc:Name>partner_2</cbc:Name> + </cac:PartyName> + <cac:PostalAddress> + <cbc:StreetName>Rue des Bourlottes 9</cbc:StreetName> + <cbc:CityName>Ramillies</cbc:CityName> + <cbc:PostalZone>1367</cbc:PostalZone> + <cac:Country> + <cbc:IdentificationCode>BE</cbc:IdentificationCode> + </cac:Country> + </cac:PostalAddress> + <cac:PartyTaxScheme> + <cbc:CompanyID>BE0477472701</cbc:CompanyID> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:PartyTaxScheme> + <cac:PartyLegalEntity> + <cbc:RegistrationName>partner_2</cbc:RegistrationName> + <cbc:CompanyID>BE0477472701</cbc:CompanyID> + </cac:PartyLegalEntity> + <cac:Contact> + <cbc:Name>partner_2</cbc:Name> + </cac:Contact> + </cac:Party> + </cac:AccountingCustomerParty> + <cac:PaymentMeans> + <cbc:PaymentMeansCode name="credit transfer">30</cbc:PaymentMeansCode> + <cbc:PaymentID>___ignore___</cbc:PaymentID> + <cac:PayeeFinancialAccount> + <cbc:ID>BE15001559627230</cbc:ID> + </cac:PayeeFinancialAccount> + </cac:PaymentMeans> + <cac:PaymentTerms> + <cbc:Note>30% Advance End of Following Month</cbc:Note> + </cac:PaymentTerms> + <cac:TaxTotal> + <cbc:TaxAmount currencyID="USD">21.00</cbc:TaxAmount> + <cac:TaxSubtotal> + <cbc:TaxableAmount currencyID="USD">100.00</cbc:TaxableAmount> + <cbc:TaxAmount currencyID="USD">21.00</cbc:TaxAmount> + <cac:TaxCategory> + <cbc:ID>S</cbc:ID> + <cbc:Percent>21.0</cbc:Percent> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:TaxCategory> + </cac:TaxSubtotal> + </cac:TaxTotal> + <cac:LegalMonetaryTotal> + <cbc:LineExtensionAmount currencyID="USD">100.00</cbc:LineExtensionAmount> + <cbc:TaxExclusiveAmount currencyID="USD">100.00</cbc:TaxExclusiveAmount> + <cbc:TaxInclusiveAmount currencyID="USD">121.00</cbc:TaxInclusiveAmount> + <cbc:PrepaidAmount currencyID="USD">0.00</cbc:PrepaidAmount> + <cbc:PayableAmount currencyID="USD">121.00</cbc:PayableAmount> + </cac:LegalMonetaryTotal> + <cac:InvoiceLine> + <cbc:ID>___ignore___</cbc:ID> + <cbc:InvoicedQuantity unitCode="C62">1.0</cbc:InvoicedQuantity> + <cbc:LineExtensionAmount currencyID="USD">100.00</cbc:LineExtensionAmount> + <cac:AllowanceCharge> + <cbc:ChargeIndicator>true</cbc:ChargeIndicator> + <cbc:AllowanceChargeReasonCode>AEO</cbc:AllowanceChargeReasonCode> + <cbc:AllowanceChargeReason>RECUPEL</cbc:AllowanceChargeReason> + <cbc:Amount currencyID="USD">1.00</cbc:Amount> + </cac:AllowanceCharge> + <cac:Item> + <cbc:Description>product_a</cbc:Description> + <cbc:Name>product_a</cbc:Name> + <cac:ClassifiedTaxCategory> + <cbc:ID>S</cbc:ID> + <cbc:Percent>21.0</cbc:Percent> + <cac:TaxScheme> + <cbc:ID>VAT</cbc:ID> + </cac:TaxScheme> + </cac:ClassifiedTaxCategory> + </cac:Item> + <cac:Price> + <cbc:PriceAmount currencyID="USD">99.00</cbc:PriceAmount> + </cac:Price> + </cac:InvoiceLine> +</Invoice> diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case1.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case1.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e21005f3881901d6821b1bc2e7f931157f7f890 --- /dev/null +++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case1.xml @@ -0,0 +1,152 @@ +<?xml version='1.0' encoding='UTF-8'?> +<rsm:CrossIndustryInvoice xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" + xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" + xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"> + <rsm:ExchangedDocumentContext> + <ram:GuidelineSpecifiedDocumentContextParameter> + <ram:ID>urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended</ram:ID> + </ram:GuidelineSpecifiedDocumentContextParameter> + </rsm:ExchangedDocumentContext> + <rsm:ExchangedDocument> + <ram:ID>___ignore___</ram:ID> + <ram:TypeCode>380</ram:TypeCode> + <ram:IssueDateTime> + <udt:DateTimeString format="102">20170101</udt:DateTimeString> + </ram:IssueDateTime> + <ram:IncludedNote> + <ram:Content>test narration</ram:Content> + </ram:IncludedNote> + </rsm:ExchangedDocument> + <rsm:SupplyChainTradeTransaction> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>1</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedTradeProduct> + <ram:Name>product_a</ram:Name> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount>99.00</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount>99.00</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">1.0</ram:BilledQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>21.0</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>true</udt:Indicator> + </ram:ChargeIndicator> + <ram:ActualAmount>1.00</ram:ActualAmount> + <ram:ReasonCode>AEO</ram:ReasonCode> + <ram:Reason>RECUPEL</ram:Reason> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount>100.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:ApplicableHeaderTradeAgreement> + <ram:BuyerReference>ref_partner_2</ram:BuyerReference> + <ram:SellerTradeParty> + <ram:Name>partner_1</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>partner_1</ram:PersonName> + <ram:TelephoneUniversalCommunication> + <ram:CompleteNumber>+1 (650) 555-0111</ram:CompleteNumber> + </ram:TelephoneUniversalCommunication> + <ram:EmailURIUniversalCommunication> + <ram:URIID schemeID="SMTP">partner1@yourcompany.com</ram:URIID> + </ram:EmailURIUniversalCommunication> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>75000</ram:PostcodeCode> + <ram:LineOne>Rue Jean Jaurès, 42</ram:LineOne> + <ram:CityName>Paris</ram:CityName> + <ram:CountryID>FR</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">FR05677404089</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:SellerTradeParty> + <ram:BuyerTradeParty> + <ram:Name>partner_2</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>partner_2</ram:PersonName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>52330</ram:PostcodeCode> + <ram:LineOne>Rue Charles de Gaulle</ram:LineOne> + <ram:CityName>Colombey-les-Deux-Églises</ram:CityName> + <ram:CountryID>FR</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">FR35562153452</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:BuyerTradeParty> + <ram:BuyerOrderReferencedDocument> + <ram:IssuerAssignedID>___ignore___</ram:IssuerAssignedID> + </ram:BuyerOrderReferencedDocument> + </ram:ApplicableHeaderTradeAgreement> + <ram:ApplicableHeaderTradeDelivery> + <ram:ShipToTradeParty> + <ram:Name>partner_2</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>partner_2</ram:PersonName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>52330</ram:PostcodeCode> + <ram:LineOne>Rue Charles de Gaulle</ram:LineOne> + <ram:CityName>Colombey-les-Deux-Églises</ram:CityName> + <ram:CountryID>FR</ram:CountryID> + </ram:PostalTradeAddress> + </ram:ShipToTradeParty> + <ram:ActualDeliverySupplyChainEvent> + <ram:OccurrenceDateTime> + <udt:DateTimeString format="102">20170101</udt:DateTimeString> + </ram:OccurrenceDateTime> + </ram:ActualDeliverySupplyChainEvent> + </ram:ApplicableHeaderTradeDelivery> + <ram:ApplicableHeaderTradeSettlement> + <ram:PaymentReference>___ignore___</ram:PaymentReference> + <ram:InvoiceCurrencyCode>USD</ram:InvoiceCurrencyCode> + <ram:SpecifiedTradeSettlementPaymentMeans> + <ram:TypeCode>42</ram:TypeCode> + <ram:PayeePartyCreditorFinancialAccount> + <ram:ProprietaryID>FR15001559627230</ram:ProprietaryID> + </ram:PayeePartyCreditorFinancialAccount> + </ram:SpecifiedTradeSettlementPaymentMeans> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount>21.00</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount>100.00</ram:BasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:DueDateTypeCode>5</ram:DueDateTypeCode> + <ram:RateApplicablePercent>21.0</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradePaymentTerms> + <ram:Description>30% Advance End of Following Month</ram:Description> + <ram:DueDateDateTime> + <udt:DateTimeString format="102">20170228</udt:DateTimeString> + </ram:DueDateDateTime> + </ram:SpecifiedTradePaymentTerms> + <ram:SpecifiedTradeSettlementHeaderMonetarySummation> + <ram:LineTotalAmount>100.00</ram:LineTotalAmount> + <ram:TaxBasisTotalAmount>100.00</ram:TaxBasisTotalAmount> + <ram:TaxTotalAmount currencyID="USD">21.00</ram:TaxTotalAmount> + <ram:GrandTotalAmount>121.00</ram:GrandTotalAmount> + <ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount> + <ram:DuePayableAmount>121.00</ram:DuePayableAmount> + </ram:SpecifiedTradeSettlementHeaderMonetarySummation> + </ram:ApplicableHeaderTradeSettlement> + </rsm:SupplyChainTradeTransaction> +</rsm:CrossIndustryInvoice> diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case2.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case2.xml new file mode 100644 index 0000000000000000000000000000000000000000..aa6224056dcfdf0dfc9476082c8c95658668e1fc --- /dev/null +++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case2.xml @@ -0,0 +1,160 @@ +<?xml version='1.0' encoding='UTF-8'?> +<rsm:CrossIndustryInvoice xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" + xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" + xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"> + <rsm:ExchangedDocumentContext> + <ram:GuidelineSpecifiedDocumentContextParameter> + <ram:ID>urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended</ram:ID> + </ram:GuidelineSpecifiedDocumentContextParameter> + </rsm:ExchangedDocumentContext> + <rsm:ExchangedDocument> + <ram:ID>___ignore___</ram:ID> + <ram:TypeCode>380</ram:TypeCode> + <ram:IssueDateTime> + <udt:DateTimeString format="102">20170101</udt:DateTimeString> + </ram:IssueDateTime> + <ram:IncludedNote> + <ram:Content>test narration</ram:Content> + </ram:IncludedNote> + </rsm:ExchangedDocument> + <rsm:SupplyChainTradeTransaction> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>1</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedTradeProduct> + <ram:Name>product_a</ram:Name> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount>98.00</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount>98.00</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">1.0</ram:BilledQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>21.0</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>true</udt:Indicator> + </ram:ChargeIndicator> + <ram:ActualAmount>1.00</ram:ActualAmount> + <ram:ReasonCode>AEO</ram:ReasonCode> + <ram:Reason>RECUPEL</ram:Reason> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>true</udt:Indicator> + </ram:ChargeIndicator> + <ram:ActualAmount>1.00</ram:ActualAmount> + <ram:ReasonCode>AEO</ram:ReasonCode> + <ram:Reason>AUVIBEL</ram:Reason> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount>100.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:ApplicableHeaderTradeAgreement> + <ram:BuyerReference>ref_partner_2</ram:BuyerReference> + <ram:SellerTradeParty> + <ram:Name>partner_1</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>partner_1</ram:PersonName> + <ram:TelephoneUniversalCommunication> + <ram:CompleteNumber>+1 (650) 555-0111</ram:CompleteNumber> + </ram:TelephoneUniversalCommunication> + <ram:EmailURIUniversalCommunication> + <ram:URIID schemeID="SMTP">partner1@yourcompany.com</ram:URIID> + </ram:EmailURIUniversalCommunication> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>75000</ram:PostcodeCode> + <ram:LineOne>Rue Jean Jaurès, 42</ram:LineOne> + <ram:CityName>Paris</ram:CityName> + <ram:CountryID>FR</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">FR05677404089</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:SellerTradeParty> + <ram:BuyerTradeParty> + <ram:Name>partner_2</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>partner_2</ram:PersonName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>52330</ram:PostcodeCode> + <ram:LineOne>Rue Charles de Gaulle</ram:LineOne> + <ram:CityName>Colombey-les-Deux-Églises</ram:CityName> + <ram:CountryID>FR</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">FR35562153452</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:BuyerTradeParty> + <ram:BuyerOrderReferencedDocument> + <ram:IssuerAssignedID>___ignore___</ram:IssuerAssignedID> + </ram:BuyerOrderReferencedDocument> + </ram:ApplicableHeaderTradeAgreement> + <ram:ApplicableHeaderTradeDelivery> + <ram:ShipToTradeParty> + <ram:Name>partner_2</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>partner_2</ram:PersonName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>52330</ram:PostcodeCode> + <ram:LineOne>Rue Charles de Gaulle</ram:LineOne> + <ram:CityName>Colombey-les-Deux-Églises</ram:CityName> + <ram:CountryID>FR</ram:CountryID> + </ram:PostalTradeAddress> + </ram:ShipToTradeParty> + <ram:ActualDeliverySupplyChainEvent> + <ram:OccurrenceDateTime> + <udt:DateTimeString format="102">20170101</udt:DateTimeString> + </ram:OccurrenceDateTime> + </ram:ActualDeliverySupplyChainEvent> + </ram:ApplicableHeaderTradeDelivery> + <ram:ApplicableHeaderTradeSettlement> + <ram:PaymentReference>___ignore___</ram:PaymentReference> + <ram:InvoiceCurrencyCode>USD</ram:InvoiceCurrencyCode> + <ram:SpecifiedTradeSettlementPaymentMeans> + <ram:TypeCode>42</ram:TypeCode> + <ram:PayeePartyCreditorFinancialAccount> + <ram:ProprietaryID>FR15001559627230</ram:ProprietaryID> + </ram:PayeePartyCreditorFinancialAccount> + </ram:SpecifiedTradeSettlementPaymentMeans> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount>21.00</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount>100.00</ram:BasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:DueDateTypeCode>5</ram:DueDateTypeCode> + <ram:RateApplicablePercent>21.0</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradePaymentTerms> + <ram:Description>30% Advance End of Following Month</ram:Description> + <ram:DueDateDateTime> + <udt:DateTimeString format="102">20170228</udt:DateTimeString> + </ram:DueDateDateTime> + </ram:SpecifiedTradePaymentTerms> + <ram:SpecifiedTradeSettlementHeaderMonetarySummation> + <ram:LineTotalAmount>100.00</ram:LineTotalAmount> + <ram:TaxBasisTotalAmount>100.00</ram:TaxBasisTotalAmount> + <ram:TaxTotalAmount currencyID="USD">21.00</ram:TaxTotalAmount> + <ram:GrandTotalAmount>121.00</ram:GrandTotalAmount> + <ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount> + <ram:DuePayableAmount>121.00</ram:DuePayableAmount> + </ram:SpecifiedTradeSettlementHeaderMonetarySummation> + </ram:ApplicableHeaderTradeSettlement> + </rsm:SupplyChainTradeTransaction> +</rsm:CrossIndustryInvoice> diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case3.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case3.xml new file mode 100644 index 0000000000000000000000000000000000000000..6c6a41a46be6a6893a34b35e7ab5b7c6871f9617 --- /dev/null +++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case3.xml @@ -0,0 +1,152 @@ +<?xml version='1.0' encoding='UTF-8'?> +<rsm:CrossIndustryInvoice xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" + xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" + xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"> + <rsm:ExchangedDocumentContext> + <ram:GuidelineSpecifiedDocumentContextParameter> + <ram:ID>urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended</ram:ID> + </ram:GuidelineSpecifiedDocumentContextParameter> + </rsm:ExchangedDocumentContext> + <rsm:ExchangedDocument> + <ram:ID>___ignore___</ram:ID> + <ram:TypeCode>380</ram:TypeCode> + <ram:IssueDateTime> + <udt:DateTimeString format="102">20170101</udt:DateTimeString> + </ram:IssueDateTime> + <ram:IncludedNote> + <ram:Content>test narration</ram:Content> + </ram:IncludedNote> + </rsm:ExchangedDocument> + <rsm:SupplyChainTradeTransaction> + <ram:IncludedSupplyChainTradeLineItem> + <ram:AssociatedDocumentLineDocument> + <ram:LineID>1</ram:LineID> + </ram:AssociatedDocumentLineDocument> + <ram:SpecifiedTradeProduct> + <ram:Name>product_a</ram:Name> + </ram:SpecifiedTradeProduct> + <ram:SpecifiedLineTradeAgreement> + <ram:GrossPriceProductTradePrice> + <ram:ChargeAmount>99.00</ram:ChargeAmount> + </ram:GrossPriceProductTradePrice> + <ram:NetPriceProductTradePrice> + <ram:ChargeAmount>99.00</ram:ChargeAmount> + </ram:NetPriceProductTradePrice> + </ram:SpecifiedLineTradeAgreement> + <ram:SpecifiedLineTradeDelivery> + <ram:BilledQuantity unitCode="C62">1.0</ram:BilledQuantity> + </ram:SpecifiedLineTradeDelivery> + <ram:SpecifiedLineTradeSettlement> + <ram:ApplicableTradeTax> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:RateApplicablePercent>21.0</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradeAllowanceCharge> + <ram:ChargeIndicator> + <udt:Indicator>true</udt:Indicator> + </ram:ChargeIndicator> + <ram:ActualAmount>1.00</ram:ActualAmount> + <ram:ReasonCode>AEO</ram:ReasonCode> + <ram:Reason>RECUPEL</ram:Reason> + </ram:SpecifiedTradeAllowanceCharge> + <ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:LineTotalAmount>100.00</ram:LineTotalAmount> + </ram:SpecifiedTradeSettlementLineMonetarySummation> + </ram:SpecifiedLineTradeSettlement> + </ram:IncludedSupplyChainTradeLineItem> + <ram:ApplicableHeaderTradeAgreement> + <ram:BuyerReference>ref_partner_2</ram:BuyerReference> + <ram:SellerTradeParty> + <ram:Name>partner_1</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>partner_1</ram:PersonName> + <ram:TelephoneUniversalCommunication> + <ram:CompleteNumber>+1 (650) 555-0111</ram:CompleteNumber> + </ram:TelephoneUniversalCommunication> + <ram:EmailURIUniversalCommunication> + <ram:URIID schemeID="SMTP">partner1@yourcompany.com</ram:URIID> + </ram:EmailURIUniversalCommunication> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>75000</ram:PostcodeCode> + <ram:LineOne>Rue Jean Jaurès, 42</ram:LineOne> + <ram:CityName>Paris</ram:CityName> + <ram:CountryID>FR</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">FR05677404089</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:SellerTradeParty> + <ram:BuyerTradeParty> + <ram:Name>partner_2</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>partner_2</ram:PersonName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>52330</ram:PostcodeCode> + <ram:LineOne>Rue Charles de Gaulle</ram:LineOne> + <ram:CityName>Colombey-les-Deux-Églises</ram:CityName> + <ram:CountryID>FR</ram:CountryID> + </ram:PostalTradeAddress> + <ram:SpecifiedTaxRegistration> + <ram:ID schemeID="VA">FR35562153452</ram:ID> + </ram:SpecifiedTaxRegistration> + </ram:BuyerTradeParty> + <ram:BuyerOrderReferencedDocument> + <ram:IssuerAssignedID>___ignore___</ram:IssuerAssignedID> + </ram:BuyerOrderReferencedDocument> + </ram:ApplicableHeaderTradeAgreement> + <ram:ApplicableHeaderTradeDelivery> + <ram:ShipToTradeParty> + <ram:Name>partner_2</ram:Name> + <ram:DefinedTradeContact> + <ram:PersonName>partner_2</ram:PersonName> + </ram:DefinedTradeContact> + <ram:PostalTradeAddress> + <ram:PostcodeCode>52330</ram:PostcodeCode> + <ram:LineOne>Rue Charles de Gaulle</ram:LineOne> + <ram:CityName>Colombey-les-Deux-Églises</ram:CityName> + <ram:CountryID>FR</ram:CountryID> + </ram:PostalTradeAddress> + </ram:ShipToTradeParty> + <ram:ActualDeliverySupplyChainEvent> + <ram:OccurrenceDateTime> + <udt:DateTimeString format="102">20170101</udt:DateTimeString> + </ram:OccurrenceDateTime> + </ram:ActualDeliverySupplyChainEvent> + </ram:ApplicableHeaderTradeDelivery> + <ram:ApplicableHeaderTradeSettlement> + <ram:PaymentReference>___ignore___</ram:PaymentReference> + <ram:InvoiceCurrencyCode>USD</ram:InvoiceCurrencyCode> + <ram:SpecifiedTradeSettlementPaymentMeans> + <ram:TypeCode>42</ram:TypeCode> + <ram:PayeePartyCreditorFinancialAccount> + <ram:ProprietaryID>FR15001559627230</ram:ProprietaryID> + </ram:PayeePartyCreditorFinancialAccount> + </ram:SpecifiedTradeSettlementPaymentMeans> + <ram:ApplicableTradeTax> + <ram:CalculatedAmount>21.00</ram:CalculatedAmount> + <ram:TypeCode>VAT</ram:TypeCode> + <ram:BasisAmount>100.00</ram:BasisAmount> + <ram:CategoryCode>S</ram:CategoryCode> + <ram:DueDateTypeCode>5</ram:DueDateTypeCode> + <ram:RateApplicablePercent>21.0</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> + <ram:SpecifiedTradePaymentTerms> + <ram:Description>30% Advance End of Following Month</ram:Description> + <ram:DueDateDateTime> + <udt:DateTimeString format="102">20170228</udt:DateTimeString> + </ram:DueDateDateTime> + </ram:SpecifiedTradePaymentTerms> + <ram:SpecifiedTradeSettlementHeaderMonetarySummation> + <ram:LineTotalAmount>100.00</ram:LineTotalAmount> + <ram:TaxBasisTotalAmount>100.00</ram:TaxBasisTotalAmount> + <ram:TaxTotalAmount currencyID="USD">21.00</ram:TaxTotalAmount> + <ram:GrandTotalAmount>121.00</ram:GrandTotalAmount> + <ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount> + <ram:DuePayableAmount>121.00</ram:DuePayableAmount> + </ram:SpecifiedTradeSettlementHeaderMonetarySummation> + </ram:ApplicableHeaderTradeSettlement> + </rsm:SupplyChainTradeTransaction> +</rsm:CrossIndustryInvoice> diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_cii_fr.py b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_cii_fr.py index d0cbee2a0a2d136288a1191f55a1603c1b306cca..14ef99c69b725623a0ffaf18160ea1b23e488f8d 100644 --- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_cii_fr.py +++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_cii_fr.py @@ -43,6 +43,7 @@ class TestCIIFR(TestUBLCommon): 'amount': 21, 'type_tax_use': 'sale', 'country_id': cls.env.ref('base.fr').id, + 'sequence': 10, }) cls.tax_12 = cls.env['account.tax'].create({ @@ -288,6 +289,64 @@ class TestCIIFR(TestUBLCommon): def test_encoding_in_attachment_facturx(self): self._test_encoding_in_attachment('facturx_1_0_05', 'factur-x.xml') + def test_export_with_fixed_taxes_case1(self): + # CASE 1: simple invoice with a recupel tax + invoice = self._generate_move( + self.partner_1, + self.partner_2, + move_type='out_invoice', + invoice_line_ids=[ + { + 'product_id': self.product_a.id, + 'quantity': 1, + 'price_unit': 99, + 'tax_ids': [(6, 0, [self.recupel.id, self.tax_21.id])], + } + ], + ) + self.assertEqual(invoice.amount_total, 121) + self._assert_invoice_attachment(invoice, None, 'from_odoo/facturx_ecotaxes_case1.xml') + + def test_export_with_fixed_taxes_case2(self): + # CASE 2: Same but with several ecotaxes + invoice = self._generate_move( + self.partner_1, + self.partner_2, + move_type='out_invoice', + invoice_line_ids=[ + { + 'product_id': self.product_a.id, + 'quantity': 1, + 'price_unit': 98, + 'tax_ids': [(6, 0, [self.recupel.id, self.auvibel.id, self.tax_21.id])], + } + ], + ) + self.assertEqual(invoice.amount_total, 121) + self._assert_invoice_attachment(invoice, None, 'from_odoo/facturx_ecotaxes_case2.xml') + + def test_export_with_fixed_taxes_case3(self): + # CASE 3: same as Case 1 but taxes are Price Included + self.recupel.price_include = True + self.tax_21.price_include = True + + # Price TTC = 121 = (99 + 1 ) * 1.21 + invoice = self._generate_move( + self.partner_1, + self.partner_2, + move_type='out_invoice', + invoice_line_ids=[ + { + 'product_id': self.product_a.id, + 'quantity': 1, + 'price_unit': 121, + 'tax_ids': [(6, 0, [self.recupel.id, self.tax_21.id])], + } + ], + ) + self.assertEqual(invoice.amount_total, 121) + self._assert_invoice_attachment(invoice, None, 'from_odoo/facturx_ecotaxes_case3.xml') + #################################################### # Test import #################################################### @@ -413,3 +472,25 @@ class TestCIIFR(TestUBLCommon): # source: Facture_F20220029_EN_16931_K.pdf, credit note labelled as an invoice with negative amounts self._assert_imported_invoice_from_file(subfolder=subfolder, filename='facturx_invoice_negative_amounts.xml', amount_total=100, amount_tax=0, list_line_subtotals=[-5, 10, 60, 30, 5], move_type='in_refund') + + def test_import_fixed_taxes(self): + """ Tests whether we correctly decode the xml attachments created using fixed taxes. + See the tests above to create these xml attachments ('test_export_with_fixed_taxes_case_[X]'). + NB: use move_type = 'out_invoice' s.t. we can retrieve the taxes used to create the invoices. + """ + subfolder = "tests/test_files/from_odoo" + self._assert_imported_invoice_from_file( + subfolder=subfolder, filename='facturx_ecotaxes_case1.xml', amount_total=121, amount_tax=22, + list_line_subtotals=[99], currency_id=self.currency_data['currency'].id, list_line_price_unit=[99], + list_line_discount=[0], list_line_taxes=[self.tax_21+self.recupel], move_type='out_invoice', + ) + self._assert_imported_invoice_from_file( + subfolder=subfolder, filename='facturx_ecotaxes_case2.xml', amount_total=121, amount_tax=23, + list_line_subtotals=[98], currency_id=self.currency_data['currency'].id, list_line_price_unit=[98], + list_line_discount=[0], list_line_taxes=[self.tax_21+self.recupel+self.auvibel], move_type='out_invoice', + ) + self._assert_imported_invoice_from_file( + subfolder=subfolder, filename='facturx_ecotaxes_case3.xml', amount_total=121, amount_tax=22, + list_line_subtotals=[99], currency_id=self.currency_data['currency'].id, list_line_price_unit=[99], + list_line_discount=[0], list_line_taxes=[self.tax_21+self.recupel], move_type='out_invoice', + ) diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py index 56cdd1bf96e522b3686064190a4f97c4e962495f..b452f9283320d8e83495130619d21be9924f30b2 100644 --- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py +++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py @@ -51,6 +51,7 @@ class TestUBLBE(TestUBLCommon): 'amount': 21, 'type_tax_use': 'sale', 'country_id': cls.env.ref('base.be').id, + 'sequence': 10, }) cls.tax_15 = cls.env['account.tax'].create({ @@ -282,7 +283,65 @@ class TestUBLBE(TestUBLCommon): } ], ) - self._assert_invoice_attachment(invoice, xpaths=None, expected_file='from_odoo/bis3_out_invoice_rounding.xml') + self._assert_invoice_attachment(invoice, None, 'from_odoo/bis3_out_invoice_rounding.xml') + + def test_export_with_fixed_taxes_case1(self): + # CASE 1: simple invoice with a recupel tax + invoice = self._generate_move( + self.partner_1, + self.partner_2, + move_type='out_invoice', + invoice_line_ids=[ + { + 'product_id': self.product_a.id, + 'quantity': 1, + 'price_unit': 99, + 'tax_ids': [(6, 0, [self.recupel.id, self.tax_21.id])], + } + ], + ) + self.assertEqual(invoice.amount_total, 121) + self._assert_invoice_attachment(invoice, None, 'from_odoo/bis3_ecotaxes_case1.xml') + + def test_export_with_fixed_taxes_case2(self): + # CASE 2: Same but with several ecotaxes + invoice = self._generate_move( + self.partner_1, + self.partner_2, + move_type='out_invoice', + invoice_line_ids=[ + { + 'product_id': self.product_a.id, + 'quantity': 1, + 'price_unit': 98, + 'tax_ids': [(6, 0, [self.recupel.id, self.auvibel.id, self.tax_21.id])], + } + ], + ) + self.assertEqual(invoice.amount_total, 121) + self._assert_invoice_attachment(invoice, None, 'from_odoo/bis3_ecotaxes_case2.xml') + + def test_export_with_fixed_taxes_case3(self): + # CASE 3: same as Case 1 but taxes are Price Included + self.recupel.price_include = True + self.tax_21.price_include = True + + # Price TTC = 121 = (99 + 1 ) * 1.21 + invoice = self._generate_move( + self.partner_1, + self.partner_2, + move_type='out_invoice', + invoice_line_ids=[ + { + 'product_id': self.product_a.id, + 'quantity': 1, + 'price_unit': 121, + 'tax_ids': [(6, 0, [self.recupel.id, self.tax_21.id])], + } + ], + ) + self.assertEqual(invoice.amount_total, 121) + self._assert_invoice_attachment(invoice, None, 'from_odoo/bis3_ecotaxes_case3.xml') #################################################### # Test import @@ -417,3 +476,27 @@ class TestUBLBE(TestUBLCommon): invoice, ) self.assertRecordValues(invoice, [{'move_type': 'out_refund', 'amount_total': 3164.22}]) + + def test_import_fixed_taxes(self): + """ Tests whether we correctly decode the xml attachments created using fixed taxes. + See the tests above to create these xml attachments ('test_export_with_fixed_taxes_case_[X]'). + NB: use move_type = 'out_invoice' s.t. we can retrieve the taxes used to create the invoices. + """ + subfolder = "tests/test_files/from_odoo" + # The tax 21% from l10n_be is retrieved since it's a duplicate of self.tax_21 + tax_21 = self.env.ref(f'l10n_be.{self.env.company.id}_attn_VAT-OUT-21-L') + self._assert_imported_invoice_from_file( + subfolder=subfolder, filename='bis3_ecotaxes_case1.xml', amount_total=121, amount_tax=22, + list_line_subtotals=[99], currency_id=self.currency_data['currency'].id, list_line_price_unit=[99], + list_line_discount=[0], list_line_taxes=[tax_21+self.recupel], move_type='out_invoice', + ) + self._assert_imported_invoice_from_file( + subfolder=subfolder, filename='bis3_ecotaxes_case2.xml', amount_total=121, amount_tax=23, + list_line_subtotals=[98], currency_id=self.currency_data['currency'].id, list_line_price_unit=[98], + list_line_discount=[0], list_line_taxes=[tax_21+self.recupel+self.auvibel], move_type='out_invoice', + ) + self._assert_imported_invoice_from_file( + subfolder=subfolder, filename='bis3_ecotaxes_case3.xml', amount_total=121, amount_tax=22, + list_line_subtotals=[99], currency_id=self.currency_data['currency'].id, list_line_price_unit=[99], + list_line_discount=[0], list_line_taxes=[tax_21+self.recupel], move_type='out_invoice', + )