"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "A payment of %s was detected."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Articles 226 items 11 to 15 Directive 2006/112/EN"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "At least one of the following fields %s is required on %s."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_account_edi_xml_ubl_de
+msgid "BIS3 DE (XRechnung)"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_account_edi_common
+msgid ""
+"Common functions for EDI documents: generate the data, the constraints, etc"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "ConformanceLevel"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py:0
+#, python-format
+msgid ""
+"Could not retrieve currency: %s. Did you enable the multicurrency option and"
+" activate the currency ?"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py:0
+#, python-format
+msgid "Could not retrieve the %s."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Could not retrieve the tax: %s %% for line '%s'."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Could not retrieve the unit of measure for line with label '%s'."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "DocumentFileName"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "DocumentType"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Down Payment"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Down Payments"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_account_edi_xml_ubl_efff
+msgid "E-FFF (BE)"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_account_edi_format
+msgid "EDI format"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "EN 16931"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#, python-format
+msgid "Each invoice line shall have one and only one tax."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Each invoice line should have at least one tax."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"Errors occured while creating the EDI document (format: %s). The receiver "
+"might refuse it."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Export outside the EU"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "Factur-X PDFA Extension Schema"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_account_edi_xml_cii
+msgid "Factur-x/XRechnung CII 2.2.0"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#, python-format
+msgid ""
+"For intracommunity supply, the actual delivery date or the invoicing period "
+"should be included."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#, python-format
+msgid "For intracommunity supply, the delivery address should be included."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "INVOICE"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Intra-Community supply"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "Invoice generated by Odoo"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#, python-format
+msgid "No Electronic Address Scheme (EAS) could be found for %s."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid ""
+"No gross price, net price nor line subtotal amount found for line in xml"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "Odoo"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Output VAT, reduced rate, low"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Output VAT, reduced rate, middle"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Output VAT, reduced rate, raw fish"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Output VAT, regular rate"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_ir_actions_report
+msgid "Report Action"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "Tax '%s' is invalid: %s"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_account_edi_xml_ubl_nl
+msgid "SI-UBL 2.0 (NLCIUS)"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "Text"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#, python-format
+msgid ""
+"The VAT number of the supplier does not seem to be valid. It should be of "
+"the form: NO179728982MVA."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "The actual version of the Factur-X XML schema"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "The conformance level of the embedded Factur-X data"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py:0
+#, python-format
+msgid "The currency '%s' is not active."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#, python-format
+msgid "The customer %s must have a KVK or OIN number."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "The element %s is required on %s."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_common.py:0
+#, python-format
+msgid "The field %s is required on %s."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py:0
+#, python-format
+msgid ""
+"The field 'Sanitized Account Number' is required on the Recipient Bank."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py:0
+#, python-format
+msgid ""
+"The invoice has been converted into a credit note and the quantities have "
+"been reverted."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#, python-format
+msgid "The supplier %s must have a Bronnoysund company registry."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py:0
+#, python-format
+msgid "The supplier %s must have a KVK or OIN number."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_account_edi_xml_ubl_20
+msgid "UBL 2.0"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_account_edi_xml_ubl_21
+msgid "UBL 2.1"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model:ir.model,name:account_edi_ubl_cii.model_account_edi_xml_ubl_bis3
+msgid "UBL BIS Billing 3.0.12"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_facturx_export_22
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_line_facturx_export_22
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.ubl_20_TaxCategoryType
+msgid "VAT"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "Version"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py:0
+#, python-format
+msgid ""
+"When the Canary Island General Indirect Tax (IGIC) applies, the tax rate on "
+"each invoice line should be greater than 0."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py:0
+#, python-format
+msgid ""
+"You should include at least one tax per invoice line. [BR-CO-04]-Each "
+"Invoice line (BG-25) shall be categorized with an Invoiced item VAT category"
+" code (BT-151)."
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py:0
+#, python-format
+msgid "customer"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "external"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "factur-x.xml"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_line_facturx_export_22
+msgid "false"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "fx"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "name of the embedded XML invoice file"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: model_terms:ir.ui.view,arch_db:account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata
+msgid "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#"
+msgstr ""
+
+#. module: account_edi_ubl_cii
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py:0
+#: code:addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py:0
+#, python-format
+msgid "vendor"
+msgstr ""
diff --git a/addons/account_edi_ubl_cii/models/__init__.py b/addons/account_edi_ubl_cii/models/__init__.py
new file mode 100644
index 0000000000..8581d7783b
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/__init__.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+
+from . import account_edi_common
+from . import account_edi_format
+from . import account_edi_xml_cii_facturx
+from . import account_edi_xml_ubl_20
+from . import account_edi_xml_ubl_21
+from . import account_edi_xml_ubl_bis3
+from . import account_edi_xml_ubl_xrechnung
+from . import account_edi_xml_ubl_efff
+from . import ir_actions_report
diff --git a/addons/account_edi_ubl_cii/models/account_edi_common.py b/addons/account_edi_ubl_cii/models/account_edi_common.py
new file mode 100644
index 0000000000..e69c3ca0a7
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/account_edi_common.py
@@ -0,0 +1,739 @@
+# -*- coding: utf-8 -*-
+
+from flectra import _, models
+from flectra.tools import float_repr
+from flectra.tests.common import Form
+from flectra.exceptions import UserError, ValidationError
+from flectra.tools.float_utils import float_round
+from flectra.tools.misc import formatLang
+
+from zeep import Client
+
+# -------------------------------------------------------------------------
+# UNIT OF MEASURE
+# -------------------------------------------------------------------------
+UOM_TO_UNECE_CODE = {
+ 'uom.product_uom_unit': 'C62',
+ 'uom.product_uom_dozen': 'DZN',
+ 'uom.product_uom_kgm': 'KGM',
+ 'uom.product_uom_gram': 'GRM',
+ 'uom.product_uom_day': 'DAY',
+ 'uom.product_uom_hour': 'HUR',
+ 'uom.product_uom_ton': 'TNE',
+ 'uom.product_uom_meter': 'MTR',
+ 'uom.product_uom_km': 'KTM',
+ 'uom.product_uom_cm': 'CMT',
+ 'uom.product_uom_litre': 'LTR',
+ 'uom.product_uom_cubic_meter': 'MTQ',
+ 'uom.product_uom_lb': 'LBR',
+ 'uom.product_uom_oz': 'ONZ',
+ 'uom.product_uom_inch': 'INH',
+ 'uom.product_uom_foot': 'FOT',
+ 'uom.product_uom_mile': 'SMI',
+ 'uom.product_uom_floz': 'OZA',
+ 'uom.product_uom_qt': 'QT',
+ 'uom.product_uom_gal': 'GLL',
+ 'uom.product_uom_cubic_inch': 'INQ',
+ 'uom.product_uom_cubic_foot': 'FTQ',
+}
+
+# -------------------------------------------------------------------------
+# ELECTRONIC ADDRESS SCHEME (EAS), see https://docs.peppol.eu/poacc/billing/3.0/codelist/eas/
+# -------------------------------------------------------------------------
+COUNTRY_EAS = {
+ 'HU': 9910,
+ 'AT': 9915,
+ 'ES': 9920,
+ 'AD': 9922,
+ 'AL': 9923,
+ 'BA': 9924,
+ 'BE': 9925,
+ 'BG': 9926,
+ 'CH': 9927,
+ 'CY': 9928,
+ 'CZ': 9929,
+ 'DE': 9930,
+ 'DK': '0184',
+ 'EE': 9931,
+ 'GB': 9932,
+ 'GR': 9933,
+ 'HR': 9934,
+ 'IE': 9935,
+ 'IT': '0211',
+ 'LI': 9936,
+ 'LT': 9937,
+ 'LU': 9938,
+ 'LV': 9939,
+ 'MC': 9940,
+ 'ME': 9941,
+ 'MK': 9942,
+ 'MT': 9943,
+ 'NL': 9944,
+ 'PL': 9945,
+ 'PT': 9946,
+ 'RO': 9947,
+ 'RS': 9948,
+ 'SI': 9949,
+ 'SK': 9950,
+ 'SM': 9951,
+ 'TR': 9952,
+ 'VA': 9953,
+ 'SE': 9955,
+ 'FR': 9957,
+ 'NO': '0192',
+ 'SG': '0195',
+ 'AU': '0151',
+ 'FI': '0213',
+}
+
+
+class AccountEdiCommon(models.AbstractModel):
+ _name = "account.edi.common"
+ _description = "Common functions for EDI documents: generate the data, the constraints, etc"
+
+ # -------------------------------------------------------------------------
+ # HELPERS
+ # -------------------------------------------------------------------------
+
+ def format_float(self, amount, precision_digits):
+ if amount is None:
+ return None
+ return float_repr(float_round(amount, precision_digits), precision_digits)
+
+ def _get_uom_unece_code(self, line):
+ """
+ list of codes: https://docs.peppol.eu/poacc/billing/3.0/codelist/UNECERec20/
+ or https://unece.org/fileadmin/DAM/cefact/recommendations/bkup_htm/add2c.htm (sorted by letter)
+ """
+ xmlid = line.product_uom_id.get_external_id()
+ if xmlid and line.product_uom_id.id in xmlid:
+ return UOM_TO_UNECE_CODE.get(xmlid[line.product_uom_id.id], 'C62')
+ return 'C62'
+
+ # -------------------------------------------------------------------------
+ # TAXES
+ # -------------------------------------------------------------------------
+
+ def _validate_taxes(self, invoice):
+ """ Validate the structure of the tax repartition lines (invalid structure could lead to unexpected results)
+ """
+ for tax in invoice.invoice_line_ids.tax_ids:
+ try:
+ tax._validate_repartition_lines()
+ except ValidationError as e:
+ error_msg = _("Tax '%s' is invalid: %s", tax.name, e.args[0]) # args[0] gives the error message
+ raise ValidationError(error_msg)
+
+ def _get_tax_unece_codes(self, invoice, tax):
+ """
+ Source: doc of Peppol (but the CEF norm is also used by factur-x, yet not detailed)
+ https://docs.peppol.eu/poacc/billing/3.0/syntax/ubl-invoice/cac-TaxTotal/cac-TaxSubtotal/cac-TaxCategory/cbc-TaxExemptionReasonCode/
+ https://docs.peppol.eu/poacc/billing/3.0/codelist/vatex/
+ https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/
+ :returns: {
+ tax_category_code: str,
+ tax_exemption_reason_code: str,
+ tax_exemption_reason: str,
+ }
+ """
+ def create_dict(tax_category_code=None, tax_exemption_reason_code=None, tax_exemption_reason=None):
+ return {
+ 'tax_category_code': tax_category_code,
+ 'tax_exemption_reason_code': tax_exemption_reason_code,
+ 'tax_exemption_reason': tax_exemption_reason,
+ }
+
+ supplier = invoice.company_id.partner_id.commercial_partner_id
+ customer = invoice.commercial_partner_id
+
+ # add Norway, Iceland, Liechtenstein
+ european_economic_area = self.env.ref('base.europe').country_ids.mapped('code') + ['NO', 'IS', 'LI']
+
+ if customer.country_id.code == 'ES' and customer.zip:
+ if customer.zip[:2] in ('35', '38'): # Canary
+ # [BR-IG-10]-A VAT breakdown (BG-23) with VAT Category code (BT-118) "IGIC" shall not have a VAT
+ # exemption reason code (BT-121) or VAT exemption reason text (BT-120).
+ return create_dict(tax_category_code='L')
+ if customer.zip[:2] in ('51', '52'):
+ return create_dict(tax_category_code='M') # Ceuta & Mellila
+
+ # see: https://anskaffelser.dev/postaward/g3/spec/current/billing-3.0/norway/#_value_added_tax_norwegian_mva
+ if customer.country_id.code == 'NO':
+ if tax.amount == 25:
+ return create_dict(tax_category_code='S', tax_exemption_reason=_('Output VAT, regular rate'))
+ if tax.amount == 15:
+ return create_dict(tax_category_code='S', tax_exemption_reason=_('Output VAT, reduced rate, middle'))
+ if tax.amount == 11.11:
+ return create_dict(tax_category_code='S', tax_exemption_reason=_('Output VAT, reduced rate, raw fish'))
+ if tax.amount == 12:
+ return create_dict(tax_category_code='S', tax_exemption_reason=_('Output VAT, reduced rate, low'))
+
+ if supplier.country_id == customer.country_id:
+ if not tax or tax.amount == 0:
+ # in theory, you should indicate the precise law article
+ return create_dict(tax_category_code='E', tax_exemption_reason=_('Articles 226 items 11 to 15 Directive 2006/112/EN'))
+ else:
+ return create_dict(tax_category_code='S') # standard VAT
+
+ if supplier.country_id.code in european_economic_area:
+ if tax.amount != 0:
+ # otherwise, the validator will complain because G and K code should be used with 0% tax
+ return create_dict(tax_category_code='S')
+ if customer.country_id.code not in european_economic_area:
+ return create_dict(
+ tax_category_code='G',
+ tax_exemption_reason_code='VATEX-EU-G',
+ tax_exemption_reason=_('Export outside the EU'),
+ )
+ if customer.country_id.code in european_economic_area:
+ return create_dict(
+ tax_category_code='K',
+ tax_exemption_reason_code='VATEX-EU-IC',
+ tax_exemption_reason=_('Intra-Community supply'),
+ )
+
+ if tax.amount != 0:
+ return create_dict(tax_category_code='S')
+ else:
+ return create_dict(tax_category_code='E', tax_exemption_reason=_('Articles 226 items 11 to 15 Directive 2006/112/EN'))
+
+ def _get_tax_category_list(self, invoice, taxes):
+ """ Full list: https://unece.org/fileadmin/DAM/trade/untdid/d16b/tred/tred5305.htm
+ Subset: https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5305/
+
+ :param taxes: account.tax records.
+ :return: A list of values to fill the TaxCategory foreach template.
+ """
+ res = []
+ for tax in taxes:
+ tax_unece_codes = self._get_tax_unece_codes(invoice, tax)
+ res.append({
+ 'id': tax_unece_codes.get('tax_category_code'),
+ 'percent': tax.amount if tax.amount_type == 'percent' else False,
+ 'name': tax_unece_codes.get('tax_exemption_reason'),
+ **tax_unece_codes,
+ })
+ return res
+
+ # -------------------------------------------------------------------------
+ # CONSTRAINTS
+ # -------------------------------------------------------------------------
+
+ def _check_required_fields(self, record, field_names, custom_warning_message=""):
+ """
+ This function check that a field exists on a record or dictionaries
+ returns a generic error message if it's not the case or a custom one if specified
+ """
+ if not record:
+ return custom_warning_message or _("The element %s is required on %s.", record, ', '.join(field_names))
+
+ if not isinstance(field_names, list):
+ field_names = [field_names]
+
+ has_values = any(record[field_name] for field_name in field_names)
+ # field is present
+ if has_values:
+ return
+
+ # field is not present
+ if custom_warning_message or isinstance(record, dict):
+ return custom_warning_message or _("The element %s is required on %s.", record, ', '.join(field_names))
+
+ display_field_names = record.fields_get(field_names)
+ if len(field_names) == 1:
+ display_field = f"'{display_field_names[field_names[0]]['string']}'"
+ return _("The field %s is required on %s.", display_field, record.display_name)
+ else:
+ display_fields = ', '.join(f"'{display_field_names[x]['string']}'" for x in display_field_names)
+ return _("At least one of the following fields %s is required on %s.", display_fields, record.display_name)
+
+ # -------------------------------------------------------------------------
+ # COMMON CONSTRAINTS
+ # -------------------------------------------------------------------------
+
+ def _invoice_constraints_common(self, invoice):
+ # check that there is a tax on each line
+ for line in invoice.invoice_line_ids.filtered(lambda x: not x.display_type):
+ if not line.tax_ids:
+ return {'tax_on_line': _("Each invoice line should have at least one tax.")}
+ return {}
+
+ # -------------------------------------------------------------------------
+ # Import invoice
+ # -------------------------------------------------------------------------
+
+ def _import_invoice(self, journal, filename, tree, existing_invoice=None):
+ move_types, qty_factor = self._get_import_document_amount_sign(filename, tree)
+ if not move_types:
+ return
+ if journal.type == 'purchase':
+ move_type = move_types[0]
+ elif journal.type == 'sale':
+ move_type = move_types[1]
+ else:
+ return
+ if existing_invoice and existing_invoice.move_type != move_type:
+ # with an email alias to create account_move, first the move is created (using alias_defaults, which
+ # contains move_type = 'out_invoice') then the attachment is decoded, if it represents a credit note,
+ # the move type needs to be changed to 'out_refund'
+ types = {move_type, existing_invoice.move_type}
+ if types == {'out_invoice', 'out_refund'} or types == {'in_invoice', 'in_refund'}:
+ existing_invoice.move_type = move_type
+ else:
+ return
+
+ invoice = existing_invoice or self.env['account.move']
+ invoice_form = Form(invoice.with_context(
+ account_predictive_bills_disable_prediction=True,
+ default_move_type=move_type,
+ default_journal_id=journal.id,
+ ))
+ invoice_form, logs = self._import_fill_invoice_form(journal, tree, invoice_form, qty_factor)
+ invoice = invoice_form.save()
+ if invoice:
+ if logs:
+ body = _(
+ "Format used to import the invoice: %s
%s
",
+ str(self._description), "
".join(logs)
+ )
+ else:
+ body = _("Format used to import the invoice: %s", str(self._description))
+ invoice.with_context(no_new_invoice=True).message_post(body=body)
+
+ # === Import the embedded PDF in the xml if some are found ===
+
+ attachments = self.env['ir.attachment']
+ additional_docs = tree.findall('./{*}AdditionalDocumentReference')
+ for document in additional_docs:
+ attachment_name = document.find('{*}ID')
+ attachment_data = document.find('{*}Attachment/{*}EmbeddedDocumentBinaryObject')
+ if attachment_name is not None \
+ and attachment_data is not None \
+ and attachment_data.attrib.get('mimeCode') == 'application/pdf':
+ text = attachment_data.text
+ # Normalize the name of the file : some e-fff emitters put the full path of the file
+ # (Windows or Linux style) and/or the name of the xml instead of the pdf.
+ # Get only the filename with a pdf extension.
+ name = attachment_name.text.split('\\')[-1].split('/')[-1].split('.')[0] + '.pdf'
+ attachment = self.env['ir.attachment'].create({
+ 'name': name,
+ 'res_id': invoice.id,
+ 'res_model': 'account.move',
+ 'datas': text + '=' * (len(text) % 3), # Fix incorrect padding
+ 'type': 'binary',
+ 'mimetype': 'application/pdf',
+ })
+ # Upon receiving an email (containing an xml) with a configured alias to create invoice, the xml is
+ # set as the main_attachment. To be rendered in the form view, the pdf should be the main_attachment.
+ if invoice.message_main_attachment_id and \
+ invoice.message_main_attachment_id.name.endswith('.xml') and \
+ 'pdf' not in invoice.message_main_attachment_id.mimetype:
+ invoice.message_main_attachment_id = attachment
+ attachments |= attachment
+ if attachments:
+ invoice.with_context(no_new_invoice=True).message_post(attachment_ids=attachments.ids)
+
+ return invoice
+
+ def _import_retrieve_and_fill_partner(self, invoice, name, phone, mail, vat):
+ """ Retrieve the partner, if no matching partner is found, create it (only if he has a vat and a name)
+ """
+ invoice.partner_id = self.env['account.edi.format']._retrieve_partner(name=name, phone=phone, mail=mail, vat=vat)
+ if not invoice.partner_id and name and vat:
+ invoice.partner_id = self.env['res.partner'].create({'name': name, 'email': mail, 'phone': phone})
+ # an invalid VAT will throw a ValidationError (see 'check_vat' in base_vat)
+ try:
+ invoice.partner_id.vat = vat
+ except ValidationError:
+ invoice.partner_id.vat = False
+
+ def _import_fill_invoice_allowance_charge(self, tree, invoice_form, journal, qty_factor):
+ logs = []
+ if '{urn:oasis:names:specification:ubl:schema:xsd' in tree.tag:
+ is_ubl = True
+ elif '{urn:un:unece:uncefact:data:standard:' in tree.tag:
+ is_ubl = False
+ else:
+ return
+
+ xpath = './{*}AllowanceCharge' if is_ubl else './{*}SupplyChainTradeTransaction/{*}ApplicableHeaderTradeSettlement/{*}SpecifiedTradeAllowanceCharge'
+ allowance_charge_nodes = tree.findall(xpath)
+ for allow_el in allowance_charge_nodes:
+ with invoice_form.invoice_line_ids.new() as invoice_line_form:
+ invoice_line_form.sequence = 0 # be sure to put these lines above the 'real' invoice lines
+
+ charge_factor = -1 # factor is -1 for discount, 1 for charge
+ if is_ubl:
+ charge_indicator_node = allow_el.find('./{*}ChargeIndicator')
+ else:
+ charge_indicator_node = allow_el.find('./{*}ChargeIndicator/{*}Indicator')
+ if charge_indicator_node is not None:
+ charge_factor = -1 if charge_indicator_node.text == 'false' else 1
+
+ name = ""
+ reason_code_node = allow_el.find('./{*}AllowanceChargeReasonCode' if is_ubl else './{*}ReasonCode')
+ if reason_code_node is not None:
+ name += reason_code_node.text + " "
+ reason_node = allow_el.find('./{*}AllowanceChargeReason' if is_ubl else './{*}Reason')
+ if reason_node is not None:
+ name += reason_node.text
+ invoice_line_form.name = name
+
+ amount_node = allow_el.find('./{*}Amount' if is_ubl else './{*}ActualAmount')
+ base_amount_node = allow_el.find('./{*}BaseAmount' if is_ubl else './{*}BasisAmount')
+ # Since there is no quantity associated for the allowance/charge on document level,
+ # if we have an invoice with negative amounts, the price was multiplied by -1 and not the quantity
+ # See the file in test_files: 'base-negative-inv-correction.xml' VS 'base-example.xml' for 'Insurance'
+ if base_amount_node is not None:
+ invoice_line_form.price_unit = float(base_amount_node.text) * charge_factor * qty_factor
+ percent_node = allow_el.find('./{*}MultiplierFactorNumeric' if is_ubl else './{*}CalculationPercent')
+ if percent_node is not None:
+ invoice_line_form.quantity = float(percent_node.text) / 100
+ elif amount_node is not None:
+ invoice_line_form.price_unit = float(amount_node.text) * charge_factor * qty_factor
+
+ invoice_line_form.tax_ids.clear() # clear the default taxes applied to the line
+ tax_xpath = './{*}TaxCategory/{*}Percent' if is_ubl else './{*}CategoryTradeTax/{*}RateApplicablePercent'
+ for tax_categ_percent_el in allow_el.findall(tax_xpath):
+ tax = self.env['account.tax'].search([
+ ('company_id', '=', journal.company_id.id),
+ ('amount', '=', float(tax_categ_percent_el.text)),
+ ('amount_type', '=', 'percent'),
+ ('type_tax_use', '=', journal.type),
+ ], limit=1)
+ if tax:
+ invoice_line_form.tax_ids.add(tax)
+ else:
+ logs.append(
+ _("Could not retrieve the tax: %s %% for line '%s'.",
+ float(tax_categ_percent_el.text),
+ name)
+ )
+ return logs
+
+ def _import_fill_invoice_down_payment(self, invoice_form, prepaid_node, qty_factor):
+ """
+ DEPRECATED: removed in master
+ Creates a down payment line on the invoice at import if prepaid_node (TotalPrepaidAmount in CII,
+ PrepaidAmount in UBL) exists.
+ qty_factor -1 if the xml is labelled as an invoice but has negative amounts -> conversion into a credit note
+ needed, so we need this multiplier. Otherwise, qty_factor is 1.
+ """
+ if prepaid_node is not None and float(prepaid_node.text) != 0:
+ # create a section
+ with invoice_form.invoice_line_ids.new() as invoice_line_form:
+ invoice_line_form.sequence = 998
+ invoice_line_form.display_type = 'line_section'
+ invoice_line_form.name = _("Down Payments")
+ invoice_line_form.price_unit = 0
+ invoice_line_form.quantity = 0
+ invoice_line_form.account_id = self.env['account.account']
+ # create the line with the down payment
+ with invoice_form.invoice_line_ids.new() as invoice_line_form:
+ invoice_line_form.sequence = 999
+ invoice_line_form.name = _("Down Payment")
+ invoice_line_form.price_unit = float(prepaid_node.text)
+ invoice_line_form.quantity = qty_factor * -1
+ invoice_line_form.tax_ids.clear()
+
+ def _import_log_prepaid_amount(self, invoice_form, prepaid_node, qty_factor):
+ """
+ Log a message in the chatter at import if prepaid_node (TotalPrepaidAmount in CII, PrepaidAmount in UBL) exists.
+ """
+ prepaid_amount = float(prepaid_node.text) if prepaid_node is not None else 0.0
+ if not invoice_form.currency_id.is_zero(prepaid_amount):
+ amount = prepaid_amount * qty_factor
+ formatted_amount = formatLang(self.env, amount, currency_obj=invoice_form.currency_id)
+ return [
+ _("A payment of %s was detected.", formatted_amount)
+ ]
+ return []
+
+ def _import_fill_invoice_line_values(self, tree, xpath_dict, invoice_line_form, qty_factor):
+ """
+ Read the xml invoice, extract the invoice line values, compute the flectra values
+ to fill an invoice line form: quantity, price_unit, discount, product_uom_id.
+
+ The way of computing invoice line is quite complicated:
+ https://docs.peppol.eu/poacc/billing/3.0/bis/#_calculation_on_line_level (same as in factur-x documentation)
+
+ line_net_subtotal = ( gross_unit_price - rebate ) * (billed_qty / basis_qty) - allow_charge_amount
+
+ with (UBL | CII):
+ * net_unit_price = 'Price/PriceAmount' | 'NetPriceProductTradePrice' (mandatory) (BT-146)
+ * gross_unit_price = 'Price/AllowanceCharge/BaseAmount' | 'GrossPriceProductTradePrice' (optional) (BT-148)
+ * basis_qty = 'Price/BaseQuantity' | 'BasisQuantity' (optional, either below net_price node or
+ gross_price node) (BT-149)
+ * billed_qty = 'InvoicedQuantity' | 'BilledQuantity' (mandatory) (BT-129)
+ * allow_charge_amount = sum of 'AllowanceCharge' | 'SpecifiedTradeAllowanceCharge' (same level as Price)
+ ON THE LINE level (optional) (BT-136 / BT-141)
+ * line_net_subtotal = 'LineExtensionAmount' | 'LineTotalAmount' (mandatory) (BT-131)
+ * rebate = 'Price/AllowanceCharge' | 'AppliedTradeAllowanceCharge' below gross_price node ! (BT-147)
+ "item price discount" which is different from the usual allow_charge_amount
+ gross_unit_price (BT-148) - rebate (BT-147) = net_unit_price (BT-146)
+
+ In Flectra, we obtain:
+ (1) = price_unit = gross_price_unit / basis_qty = (net_price_unit + rebate) / basis_qty
+ (2) = quantity = billed_qty
+ (3) = discount (converted into a percentage) = 100 * (1 - price_subtotal / (billed_qty * price_unit))
+ (4) = price_subtotal
+
+ Alternatively, we could also set: quantity = billed_qty/basis_qty
+
+ WARNING, the basis quantity parameter is annoying, for instance, an invoice with a line:
+ item A | price per unit of measure/unit price: 30 | uom = 3 pieces | billed qty = 3 | rebate = 2 | untaxed total = 28
+ Indeed, 30 $ / 3 pieces = 10 $ / piece => 10 * 3 (billed quantity) - 2 (rebate) = 28
+
+ UBL ROUNDING: "the result of Item line net
+ amount = ((Item net price (BT-146)÷Item price base quantity (BT-149))×(Invoiced Quantity (BT-129))
+ must be rounded to two decimals, and the allowance/charge amounts are also rounded separately."
+ It is not possible to do it in Flectra.
+
+ :params tree
+ :params xpath_dict dict: {
+ 'basis_qty': list of str,
+ 'gross_price_unit': str,
+ 'rebate': str,
+ 'net_price_unit': str,
+ 'billed_qty': str,
+ 'allowance_charge': str, to be used in a findall !,
+ 'allowance_charge_indicator': str, relative xpath from allowance_charge,
+ 'allowance_charge_amount': str, relative xpath from allowance_charge,
+ 'line_total_amount': str,
+ }
+ :params: invoice_line_form
+ :params: qty_factor
+ :returns: {
+ 'quantity': float,
+ 'product_uom_id': (optional) uom.uom,
+ 'price_unit': float,
+ 'discount': float,
+ }
+ """
+ # basis_qty (optional)
+ basis_qty = 1
+ for xpath in xpath_dict['basis_qty']:
+ basis_quantity_node = tree.find(xpath)
+ if basis_quantity_node is not None:
+ basis_qty = float(basis_quantity_node.text)
+
+ # gross_price_unit (optional)
+ gross_price_unit = None
+ gross_price_unit_node = tree.find(xpath_dict['gross_price_unit'])
+ if gross_price_unit_node is not None:
+ gross_price_unit = float(gross_price_unit_node.text)
+
+ # rebate (optional)
+ # Discount. /!\ as no percent discount can be set on a line, need to infer the percentage
+ # from the amount of the actual amount of the discount (the allowance charge)
+ rebate = 0
+ rebate_node = tree.find(xpath_dict['rebate'])
+ net_price_unit_node = tree.find(xpath_dict['net_price_unit'])
+ if rebate_node is not None:
+ rebate = float(rebate_node.text)
+ elif net_price_unit_node is not None and gross_price_unit_node is not None:
+ rebate = float(gross_price_unit_node.text) - float(net_price_unit_node.text)
+
+ # net_price_unit (mandatory)
+ net_price_unit = None
+ if net_price_unit_node is not None:
+ net_price_unit = float(net_price_unit_node.text)
+
+ # billed_qty (mandatory)
+ billed_qty = 1
+ product_uom_id = None
+ quantity_node = tree.find(xpath_dict['billed_qty'])
+ if quantity_node is not None:
+ billed_qty = float(quantity_node.text)
+ uom_xml = quantity_node.attrib.get('unitCode')
+ if uom_xml:
+ uom_infered_xmlid = [
+ flectra_xmlid for flectra_xmlid, uom_unece in UOM_TO_UNECE_CODE.items() if uom_unece == uom_xml
+ ]
+ if uom_infered_xmlid:
+ 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:
+ charge_indicator = allow_charge_el.find(xpath_dict['allowance_charge_indicator'])
+ if charge_indicator.text and charge_indicator.text.lower() == 'false':
+ discount_factor = 1 # it's a discount
+ 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:
+ if reason_code is not None and reason_code.text == 'AEO' and reason is not None:
+ # Handle Fixed Taxes: when exporting from Flectra, 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
+ line_total_amount_node = tree.find(xpath_dict['line_total_amount'])
+ if line_total_amount_node is not None:
+ price_subtotal = float(line_total_amount_node.text)
+
+ ####################################################
+ # Setting the values on the invoice_line_form
+ ####################################################
+
+ # quantity
+ quantity = billed_qty * qty_factor
+
+ # price_unit
+ if gross_price_unit is not None:
+ price_unit = gross_price_unit / basis_qty
+ elif net_price_unit is not None:
+ price_unit = (net_price_unit + rebate) / basis_qty
+ elif price_subtotal is not None:
+ price_unit = (price_subtotal + allow_charge_amount) / billed_qty
+ else:
+ raise UserError(_("No gross price, net price nor line subtotal amount found for line in xml"))
+
+ # 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 - 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
+ # respected, and the result will not be correct, so we just follow the simple rule below:
+ if net_price_unit == 0 and price_subtotal != net_price_unit * (billed_qty / basis_qty) - allow_charge_amount:
+ price_unit = price_subtotal / (billed_qty or 1)
+
+ return {
+ 'quantity': quantity,
+ '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.
+ inv_line_vals['taxes'] = []
+ for tax_node in tax_nodes:
+ amount = float(tax_node.text)
+ domain = [
+ ('company_id', '=', journal.company_id.id),
+ ('amount_type', '=', 'percent'),
+ ('type_tax_use', '=', journal.type),
+ ('amount', '=', amount),
+ ]
+ tax_excl = self.env['account.tax'].search(domain + [('price_include', '=', False)], limit=1)
+ tax_incl = self.env['account.tax'].search(domain + [('price_include', '=', True)], limit=1)
+ if tax_excl:
+ inv_line_vals['taxes'].append(tax_excl)
+ elif tax_incl:
+ inv_line_vals['taxes'].append(tax_incl)
+ 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)
+ inv_line_vals['price_unit'] += tax.amount
+ else:
+ inv_line_vals['taxes'].append(tax)
+
+ # Set the values on the line_form
+ invoice_line_form.quantity = inv_line_vals['quantity']
+ if inv_line_vals.get('product_uom_id'):
+ invoice_line_form.product_uom_id = inv_line_vals['product_uom_id']
+ else:
+ logs.append(
+ _("Could not retrieve the unit of measure for line with label '%s'.", invoice_line_form.name))
+ invoice_line_form.price_unit = inv_line_vals['price_unit']
+ invoice_line_form.discount = inv_line_vals['discount']
+ invoice_line_form.tax_ids.clear()
+ for tax in inv_line_vals['taxes']:
+ invoice_line_form.tax_ids.add(tax)
+ return logs
+
+ # -------------------------------------------------------------------------
+ # Check xml using the free API from Ph. Helger, don't abuse it !
+ # -------------------------------------------------------------------------
+
+ def _check_xml_ecosio(self, invoice, xml_content, ecosio_formats):
+ # see https://peppol.helger.com/public/locale-en_US/menuitem-validation-ws2
+ if not ecosio_formats:
+ return
+ soap_client = Client('https://peppol.helger.com/wsdvs?wsdl')
+ if invoice.move_type == 'out_invoice':
+ ecosio_format = ecosio_formats['invoice']
+ elif invoice.move_type == 'out_refund':
+ ecosio_format = ecosio_formats['credit_note']
+ else:
+ invoice.with_context(no_new_invoice=True).message_post(
+ body="ECOSIO: could not validate xml, formats only exist for invoice or credit notes"
+ )
+ return
+ if not ecosio_format:
+ return
+ response = soap_client.service.validate(xml_content, ecosio_format)
+
+ report = []
+ errors_cnt = 0
+ for item in response['Result']:
+ if item['artifactPath']:
+ report.append(
+ "
" + item['artifactPath'] + "
")
+ for detail in item['Item']:
+ if detail['errorLevel'] == 'WARN':
+ errors_cnt += 1
+ report.append(
+ "
")
+
+ if errors_cnt == 0:
+ invoice.with_context(no_new_invoice=True).message_post(
+ body=f"ECOSIO: All clear for format {ecosio_format}!"
+ )
+ else:
+ invoice.with_context(no_new_invoice=True).message_post(
+ body=f"ECOSIO ERRORS/WARNINGS for format {ecosio_format}:
"
+ + "\n".join(report) + "
"
+ )
+ return response
diff --git a/addons/account_edi_ubl_cii/models/account_edi_format.py b/addons/account_edi_ubl_cii/models/account_edi_format.py
new file mode 100644
index 0000000000..57b2af27db
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/account_edi_format.py
@@ -0,0 +1,205 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import models, fields, _
+from flectra.tools import str2bool
+from flectra.addons.account_edi_ubl_cii.models.account_edi_common import COUNTRY_EAS
+
+import logging
+
+_logger = logging.getLogger(__name__)
+
+FORMAT_CODES = [
+ 'facturx_1_0_05',
+ 'ubl_bis3',
+ 'ubl_de',
+ 'nlcius_1',
+ 'efff_1',
+ 'ubl_2_1',
+ 'ehf_3',
+]
+
+
+class AccountEdiFormat(models.Model):
+ _inherit = 'account.edi.format'
+
+ ####################################################
+ # Helpers
+ ####################################################
+
+ def _infer_xml_builder_from_tree(self, tree):
+ self.ensure_one()
+ ubl_version = tree.find('{*}UBLVersionID')
+ customization_id = tree.find('{*}CustomizationID')
+ if tree.tag == '{urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100}CrossIndustryInvoice':
+ return self.env['account.edi.xml.cii']
+ if ubl_version is not None:
+ if ubl_version.text == '2.0':
+ return self.env['account.edi.xml.ubl_20']
+ if ubl_version.text in ('2.1', '2.2', '2.3'):
+ return self.env['account.edi.xml.ubl_21']
+ if customization_id is not None:
+ if 'xrechnung' in customization_id.text:
+ return self.env['account.edi.xml.ubl_de']
+ if customization_id.text == 'urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0':
+ return self.env['account.edi.xml.ubl_nl']
+ # Allow to parse any format derived from the european semantic norm EN16931
+ if 'urn:cen.eu:en16931:2017' in customization_id.text:
+ return self.env['account.edi.xml.ubl_bis3']
+ return
+
+ def _get_xml_builder(self, company):
+ # see https://communaute.chorus-pro.gouv.fr/wp-content/uploads/2017/08/20170630_Solution-portail_Dossier_Specifications_Fournisseurs_Chorus_Facture_V.1.pdf
+ # page 45 -> ubl 2.1 for France seems also supported
+ if self.code == 'facturx_1_0_05':
+ return self.env['account.edi.xml.cii']
+ # if the company's country is not in the EAS mapping, nothing is generated
+ if self.code == 'ubl_bis3' and company.country_id.code in COUNTRY_EAS:
+ return self.env['account.edi.xml.ubl_bis3']
+ # the EDI option will only appear on the journal of german companies
+ if self.code == 'ubl_de' and company.country_id.code == 'DE':
+ return self.env['account.edi.xml.ubl_de']
+ # the EDI option will only appear on the journal of belgian companies
+ if self.code == 'efff_1' and company.country_id.code == 'BE':
+ return self.env['account.edi.xml.ubl_efff']
+
+ def _is_ubl_cii_available(self, company):
+ """
+ Returns a boolean indicating whether it is possible to generate an xml file using one of the formats from this
+ module or not
+ """
+ return self._get_xml_builder(company) is not None
+
+ ####################################################
+ # Export: Account.edi.format override
+ ####################################################
+
+ def _is_required_for_invoice(self, invoice):
+ # EXTENDS account_edi
+ self.ensure_one()
+ if self.code not in FORMAT_CODES:
+ return super()._is_required_for_invoice(invoice)
+
+ return self._is_ubl_cii_available(invoice.company_id) and invoice.move_type in ('out_invoice', 'out_refund')
+
+ def _is_compatible_with_journal(self, journal):
+ # EXTENDS account_edi
+ # the formats appear on the journal only if they are compatible (e.g. NLCIUS only appear for dutch companies)
+ self.ensure_one()
+ if self.code not in FORMAT_CODES:
+ return super()._is_compatible_with_journal(journal)
+ return self._is_ubl_cii_available(journal.company_id) and journal.type == 'sale'
+
+ def _is_enabled_by_default_on_journal(self, journal):
+ # EXTENDS account_edi
+ # only facturx is enabled by default, the other formats aren't
+ self.ensure_one()
+ if self.code not in FORMAT_CODES:
+ return super()._is_enabled_by_default_on_journal(journal)
+ return self.code == 'facturx_1_0_05'
+
+ def _post_invoice_edi(self, invoices, test_mode=False):
+ # EXTENDS account_edi
+ self.ensure_one()
+
+ if self.code not in FORMAT_CODES:
+ return super()._post_invoice_edi(invoices, test_mode=test_mode)
+
+ res = {}
+ for invoice in invoices:
+ builder = self._get_xml_builder(invoice.company_id)
+ # For now, the errors are not displayed anywhere, don't want to annoy the user
+ xml_content, errors = builder._export_invoice(invoice)
+
+ # DEBUG: send directly to the test platform (the one used by ecosio)
+ #response = self.env['account.edi.common']._check_xml_ecosio(invoice, xml_content, builder._export_invoice_ecosio_schematrons())
+
+ attachment_create_vals = {
+ 'name': builder._export_invoice_filename(invoice),
+ 'raw': xml_content,
+ 'mimetype': 'application/xml',
+ }
+ # we don't want the Factur-X, E-FFF and NLCIUS xml to appear in the attachment of the invoice when confirming it
+ # E-FFF and NLCIUS will appear after the pdf is generated, Factur-X will never appear (it's contained in the PDF)
+ if self.code not in ['facturx_1_0_05', 'efff_1', 'nlcius_1']:
+ attachment_create_vals.update({'res_id': invoice.id, 'res_model': 'account.move'})
+
+ attachment = self.env['ir.attachment'].create(attachment_create_vals)
+ res[invoice] = {
+ 'success': True,
+ 'attachment': attachment,
+ }
+
+ return res
+
+ def _is_embedding_to_invoice_pdf_needed(self):
+ # EXTENDS account_edi
+ self.ensure_one()
+
+ if self.code == 'facturx_1_0_05':
+ return True
+ return super()._is_embedding_to_invoice_pdf_needed()
+
+ def _prepare_invoice_report(self, pdf_writer, edi_document):
+ # EXTENDS account_edi
+ self.ensure_one()
+ if self.code != 'facturx_1_0_05':
+ return super()._prepare_invoice_report(pdf_writer, edi_document)
+ if not edi_document.attachment_id:
+ return
+
+ pdf_writer.embed_flectra_attachment(edi_document.attachment_id, subtype='text/xml')
+ if not pdf_writer.is_pdfa and str2bool(
+ self.env['ir.config_parameter'].sudo().get_param('edi.use_pdfa', 'False')):
+ try:
+ pdf_writer.convert_to_pdfa()
+ except Exception as e:
+ _logger.exception("Error while converting to PDF/A: %s", e)
+ metadata_template = self.env.ref('account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata',
+ raise_if_not_found=False)
+ if metadata_template:
+ content = self.env['ir.qweb']._render('account_edi_ubl_cii.account_invoice_pdfa_3_facturx_metadata', {
+ 'title': edi_document.move_id.name,
+ 'date': fields.Date.context_today(self),
+ })
+ pdf_writer.add_file_metadata(content)
+
+ ####################################################
+ # Import: Account.edi.format override
+ ####################################################
+
+ def _create_invoice_from_xml_tree(self, filename, tree, journal=None):
+ # EXTENDS account_edi
+ self.ensure_one()
+
+ journal = journal or self.env['account.move']._get_default_journal()
+
+ if not self._is_ubl_cii_available(journal.company_id):
+ return super()._create_invoice_from_xml_tree(filename, tree, journal=journal)
+
+ # infer the xml builder
+ invoice_xml_builder = self._infer_xml_builder_from_tree(tree)
+
+ if invoice_xml_builder is not None:
+ invoice = invoice_xml_builder._import_invoice(journal, filename, tree)
+ if invoice:
+ return invoice
+
+ return super()._create_invoice_from_xml_tree(filename, tree, journal=journal)
+
+ def _update_invoice_from_xml_tree(self, filename, tree, invoice):
+ # EXTENDS account_edi
+ self.ensure_one()
+
+ if not self._is_ubl_cii_available(invoice.company_id):
+ return super()._update_invoice_from_xml_tree(filename, tree, invoice)
+
+ # infer the xml builder
+ invoice_xml_builder = self._infer_xml_builder_from_tree(tree)
+
+ if invoice_xml_builder is not None:
+ invoice = invoice_xml_builder._import_invoice(invoice.journal_id, filename, tree, invoice)
+ if invoice:
+ return invoice
+
+ return super()._update_invoice_from_xml_tree(filename, tree, invoice)
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
new file mode 100644
index 0000000000..6a74112733
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py
@@ -0,0 +1,402 @@
+# -*- coding: utf-8 -*-
+from flectra import models, _
+from flectra.tools import DEFAULT_SERVER_DATE_FORMAT, float_repr, is_html_empty, html2plaintext, cleanup_xml_node
+from lxml import etree
+
+from datetime import datetime
+
+import logging
+
+_logger = logging.getLogger(__name__)
+
+DEFAULT_FACTURX_DATE_FORMAT = '%Y%m%d'
+
+
+class AccountEdiXmlCII(models.AbstractModel):
+ _name = "account.edi.xml.cii"
+ _inherit = 'account.edi.common'
+ _description = "Factur-x/XRechnung CII 2.2.0"
+
+ def _export_invoice_filename(self, invoice):
+ return "factur-x.xml"
+
+ def _export_invoice_ecosio_schematrons(self):
+ return {
+ 'invoice': 'de.xrechnung:cii:2.2.0',
+ 'credit_note': 'de.xrechnung:cii:2.2.0',
+ }
+
+ def _export_invoice_constraints(self, invoice, vals):
+ constraints = self._invoice_constraints_common(invoice)
+ constraints.update({
+ # [BR-08]-An Invoice shall contain the Seller postal address (BG-5).
+ # [BR-09]-The Seller postal address (BG-5) shall contain a Seller country code (BT-40).
+ 'seller_postal_address': self._check_required_fields(
+ vals['record']['company_id']['partner_id']['commercial_partner_id'], 'country_id'
+ ),
+ # [BR-DE-9] The element "Buyer post code" (BT-53) must be transmitted. (only mandatory in Germany ?)
+ 'buyer_postal_address': self._check_required_fields(
+ vals['record']['commercial_partner_id'], 'zip'
+ ),
+ # [BR-DE-4] The element "Seller post code" (BT-38) must be transmitted. (only mandatory in Germany ?)
+ 'seller_post_code': self._check_required_fields(
+ vals['record']['company_id']['partner_id']['commercial_partner_id'], 'zip'
+ ),
+ # [BR-CO-26]-In order for the buyer to automatically identify a supplier, the Seller identifier (BT-29),
+ # the Seller legal registration identifier (BT-30) and/or the Seller VAT identifier (BT-31) shall be present.
+ 'seller_identifier': self._check_required_fields(
+ vals['record']['company_id'], ['vat'] # 'siret'
+ ),
+ # [BR-DE-1] An Invoice must contain information on "PAYMENT INSTRUCTIONS" (BG-16)
+ # first check that a partner_bank_id exists, then check that there is an account number
+ 'seller_payment_instructions_1': self._check_required_fields(
+ vals['record'], 'partner_bank_id'
+ ),
+ 'seller_payment_instructions_2': self._check_required_fields(
+ vals['record']['partner_bank_id'], 'sanitized_acc_number',
+ _("The field 'Sanitized Account Number' is required on the Recipient Bank.")
+ ),
+ # [BR-DE-6] The element "Seller contact telephone number" (BT-42) must be transmitted.
+ 'seller_phone': self._check_required_fields(
+ vals['record']['company_id']['partner_id']['commercial_partner_id'], ['phone', 'mobile'],
+ ),
+ # [BR-DE-7] The element "Seller contact email address" (BT-43) must be transmitted.
+ 'seller_email': self._check_required_fields(
+ vals['record']['company_id'], 'email'
+ ),
+ # [BR-CO-04]-Each Invoice line (BG-25) shall be categorized with an Invoiced item VAT category code (BT-151).
+ 'tax_invoice_line': self._check_required_tax(vals),
+ # [BR-IC-02]-An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151)
+ # is "Intra-community supply" shall contain the Seller VAT Identifier (BT-31) or the Seller tax representative
+ # VAT identifier (BT-63) and the Buyer VAT identifier (BT-48).
+ 'intracom_seller_vat': self._check_required_fields(vals['record']['company_id'], 'vat') if vals['intracom_delivery'] else None,
+ 'intracom_buyer_vat': self._check_required_fields(vals['record']['commercial_partner_id'], 'vat') if vals['intracom_delivery'] else None,
+ # [BR-IG-05]-In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is "IGIC" the
+ # invoiced item VAT rate (BT-152) shall be greater than 0 (zero).
+ 'igic_tax_rate': self._check_non_0_rate_tax(vals)
+ if vals['record']['commercial_partner_id']['country_id']['code'] == 'ES'
+ and vals['record']['commercial_partner_id']['zip']
+ and vals['record']['commercial_partner_id']['zip'][:2] in ['35', '38'] else None,
+ })
+ return constraints
+
+ def _check_required_tax(self, vals):
+ for line_vals in vals['invoice_line_vals_list']:
+ line = line_vals['line']
+ if not vals['tax_details']['invoice_line_tax_details'][line]['tax_details']:
+ return _("You should include at least one tax per invoice line. [BR-CO-04]-Each Invoice line (BG-25) "
+ "shall be categorized with an Invoiced item VAT category code (BT-151).")
+
+ def _check_non_0_rate_tax(self, vals):
+ for line_vals in vals['invoice_line_vals_list']:
+ tax_rate_list = line_vals['line'].tax_ids.flatten_taxes_hierarchy().mapped("amount")
+ if not any([rate > 0 for rate in tax_rate_list]):
+ return _("When the Canary Island General Indirect Tax (IGIC) applies, the tax rate on "
+ "each invoice line should be greater than 0.")
+
+ def _get_scheduled_delivery_time(self, invoice):
+ # don't create a bridge only to get line.sale_line_ids.order_id.picking_ids.date_done
+ # line.sale_line_ids.order_id.picking_ids.scheduled_date or line.sale_line_ids.order_id.commitment_date
+ return invoice.invoice_date
+
+ def _get_invoicing_period(self, invoice):
+ # get the Invoicing period (BG-14): a list of dates covered by the invoice
+ # don't create a bridge to get the date range from the timesheet_ids
+ return [invoice.invoice_date]
+
+ def _get_exchanged_document_vals(self, invoice):
+ return {
+ 'id': invoice.name,
+ 'type_code': '380' if invoice.move_type == 'out_invoice' else '381',
+ 'issue_date_time': invoice.invoice_date,
+ 'included_note': html2plaintext(invoice.narration) if invoice.narration else "",
+ }
+
+ def _export_invoice_vals(self, invoice):
+
+ def format_date(dt):
+ # Format the date in the Factur-x standard.
+ dt = dt or datetime.now()
+ return dt.strftime(DEFAULT_FACTURX_DATE_FORMAT)
+
+ def format_monetary(number, decimal_places=2):
+ # Facturx requires the monetary values to be rounded to 2 decimal values
+ return float_repr(number, decimal_places)
+
+ def grouping_key_generator(tax_values):
+ tax = tax_values['tax_id']
+ 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)
+
+ # 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 Flectra 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:
+ seller_siret = invoice.company_id.company_registry
+
+ buyer_siret = False
+ if 'siret' in invoice.commercial_partner_id._fields and invoice.commercial_partner_id.siret:
+ buyer_siret = invoice.commercial_partner_id.siret
+ template_values = {
+ **invoice._prepare_edi_vals_to_export(),
+ 'tax_details': tax_details,
+ 'format_date': format_date,
+ 'format_monetary': format_monetary,
+ 'is_html_empty': is_html_empty,
+ 'scheduled_delivery_time': self._get_scheduled_delivery_time(invoice),
+ 'intracom_delivery': False,
+ 'ExchangedDocument_vals': self._get_exchanged_document_vals(invoice),
+ 'seller_specified_legal_organization': seller_siret,
+ 'buyer_specified_legal_organization': buyer_siret,
+ 'ship_to_trade_party': invoice.partner_shipping_id if 'partner_shipping_id' in invoice._fields and invoice.partner_shipping_id
+ else invoice.commercial_partner_id,
+ # Chorus Pro fields
+ 'buyer_reference': invoice.buyer_reference if 'buyer_reference' in invoice._fields
+ and invoice.buyer_reference else invoice.commercial_partner_id.ref,
+ 'purchase_order_reference': invoice.purchase_order_reference if 'purchase_order_reference' in invoice._fields
+ and invoice.purchase_order_reference else invoice.ref or invoice.name,
+ 'contract_reference': invoice.contract_reference if 'contract_reference' in invoice._fields
+ and invoice.contract_reference else '',
+ }
+
+ # data used for IncludedSupplyChainTradeLineItem / SpecifiedLineTradeSettlement
+ for line_vals in template_values['invoice_line_vals_list']:
+ line = line_vals['line']
+ line_vals['unece_uom_code'] = self._get_uom_unece_code(line)
+
+ # data used for ApplicableHeaderTradeSettlement / ApplicableTradeTax (at the end of the xml)
+ for tax_detail_vals in template_values['tax_details']['tax_details'].values():
+ # /!\ -0.0 == 0.0 in python but not in XSLT, so it can raise a fatal error when validating the XML
+ # if 0.0 is expected and -0.0 is given.
+ amount_currency = tax_detail_vals['tax_amount_currency']
+ tax_detail_vals['calculated_amount'] = template_values['balance_multiplicator'] * amount_currency \
+ if not invoice.currency_id.is_zero(amount_currency) else 0
+
+ if tax_detail_vals.get('tax_category_code') == 'K':
+ template_values['intracom_delivery'] = True
+ # [BR - IC - 11] - In an Invoice with a VAT breakdown (BG-23) where the VAT category code (BT-118) is
+ # "Intra-community supply" the Actual delivery date (BT-72) or the Invoicing period (BG-14) shall not be blank.
+ if tax_detail_vals.get('tax_category_code') == 'K' and not template_values['scheduled_delivery_time']:
+ date_range = self._get_invoicing_period(invoice)
+ template_values['billing_start'] = min(date_range)
+ template_values['billing_end'] = max(date_range)
+
+ # One of the difference between XRechnung and Facturx is the following. Submitting a Facturx to XRechnung
+ # validator raises a warning, but submitting a XRechnung to Facturx raises an error.
+ supplier = invoice.company_id.partner_id.commercial_partner_id
+ if supplier.country_id.code == 'DE':
+ template_values['document_context_id'] = "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2"
+ 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
+ balance_sign = -1 if invoice.is_inbound() else 1
+ for line_vals in template_values['invoice_line_vals_list']:
+ line_vals['allowance_charge_vals_list'] = []
+ for grouping_key, tax_detail in tax_details['invoice_line_tax_details'][line_vals['line']]['tax_details'].items():
+ if grouping_key['amount_type'] == 'fixed':
+ line_vals['allowance_charge_vals_list'].append({
+ 'indicator': 'true',
+ 'reason': tax_detail['group_tax_details'][0]['tax_id'].name,
+ 'reason_code': 'AEO',
+ 'amount': balance_sign * 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'] = balance_sign * tax_details['base_amount_currency']
+ template_values['tax_total_amount'] = balance_sign * tax_details['tax_amount_currency']
+
+ return template_values
+
+ def _export_invoice(self, invoice):
+ vals = self._export_invoice_vals(invoice)
+ errors = [constraint for constraint in self._export_invoice_constraints(invoice, vals).values() if constraint]
+ xml_content = self.env['ir.qweb']._render('account_edi_ubl_cii.account_invoice_facturx_export_22', vals)
+ return etree.tostring(cleanup_xml_node(xml_content), xml_declaration=True, encoding='UTF-8'), set(errors)
+
+ # -------------------------------------------------------------------------
+ # IMPORT
+ # -------------------------------------------------------------------------
+
+ def _import_fill_invoice_form(self, journal, tree, invoice_form, qty_factor):
+
+ def _find_value(xpath, element=tree):
+ return self.env['account.edi.format']._find_value(xpath, element, tree.nsmap)
+
+ logs = []
+
+ if qty_factor == -1:
+ logs.append(_("The invoice has been converted into a credit note and the quantities have been reverted."))
+
+ # ==== partner_id ====
+
+ role = invoice_form.journal_id.type == 'purchase' and 'SellerTradeParty' or 'BuyerTradeParty'
+ name = _find_value(f"//ram:{role}/ram:Name")
+ mail = _find_value(f"//ram:{role}//ram:URIID[@schemeID='SMTP']")
+ vat = _find_value(f"//ram:{role}/ram:SpecifiedTaxRegistration/ram:ID")
+ phone = _find_value(f"//ram:{role}/ram:DefinedTradeContact/ram:TelephoneUniversalCommunication/ram:CompleteNumber")
+ self._import_retrieve_and_fill_partner(invoice_form, name=name, phone=phone, mail=mail, vat=vat)
+
+ # ==== currency_id ====
+
+ currency_code_node = tree.find('.//{*}InvoiceCurrencyCode')
+ if currency_code_node is not None:
+ currency = self.env['res.currency'].with_context(active_test=False).search([
+ ('name', '=', currency_code_node.text),
+ ], limit=1)
+ if currency:
+ if not currency.active:
+ logs.append(_("The currency '%s' is not active.", currency.name))
+ invoice_form.currency_id = currency
+ else:
+ logs.append(_("Could not retrieve currency: %s. Did you enable the multicurrency option and "
+ "activate the currency ?", currency_code_node.text))
+
+ # ==== Reference ====
+
+ ref_node = tree.find('./{*}ExchangedDocument/{*}ID')
+ if ref_node is not None:
+ invoice_form.ref = ref_node.text
+
+ # === Note/narration ====
+
+ narration = ""
+ note_node = tree.find('./{*}ExchangedDocument/{*}IncludedNote/{*}Content')
+ if note_node is not None and note_node.text:
+ narration += note_node.text + "\n"
+
+ payment_terms_node = tree.find('.//{*}SpecifiedTradePaymentTerms/{*}Description')
+ if payment_terms_node is not None and payment_terms_node.text:
+ narration += payment_terms_node.text + "\n"
+
+ invoice_form.narration = narration
+
+ # ==== payment_reference ====
+
+ payment_reference_node = tree.find('.//{*}BuyerOrderReferencedDocument/{*}IssuerAssignedID')
+ if payment_reference_node is not None:
+ invoice_form.payment_reference = payment_reference_node.text
+
+ # ==== invoice_date ====
+
+ invoice_date_node = tree.find('./{*}ExchangedDocument/{*}IssueDateTime/{*}DateTimeString')
+ if invoice_date_node is not None and invoice_date_node.text:
+ date_str = invoice_date_node.text
+ date_obj = datetime.strptime(date_str, DEFAULT_FACTURX_DATE_FORMAT)
+ invoice_form.invoice_date = date_obj.strftime(DEFAULT_SERVER_DATE_FORMAT)
+
+ # ==== invoice_date_due ====
+
+ invoice_date_due_node = tree.find('.//{*}SpecifiedTradePaymentTerms/{*}DueDateDateTime/{*}DateTimeString')
+ if invoice_date_due_node is not None and invoice_date_due_node.text:
+ date_str = invoice_date_due_node.text
+ date_obj = datetime.strptime(date_str, DEFAULT_FACTURX_DATE_FORMAT)
+ invoice_form.invoice_date_due = date_obj.strftime(DEFAULT_SERVER_DATE_FORMAT)
+
+ # ==== invoice_line_ids: AllowanceCharge (document level) ====
+
+ logs += self._import_fill_invoice_allowance_charge(tree, invoice_form, journal, qty_factor)
+
+ # ==== Prepaid amount ====
+
+ prepaid_node = tree.find('.//{*}ApplicableHeaderTradeSettlement/'
+ '{*}SpecifiedTradeSettlementHeaderMonetarySummation/{*}TotalPrepaidAmount')
+ logs += self._import_log_prepaid_amount(invoice_form, prepaid_node, qty_factor)
+
+ # ==== invoice_line_ids ====
+
+ line_nodes = tree.findall('./{*}SupplyChainTradeTransaction/{*}IncludedSupplyChainTradeLineItem')
+ if line_nodes is not None:
+ for i, invl_el in enumerate(line_nodes):
+ with invoice_form.invoice_line_ids.new() as invoice_line_form:
+ invoice_line_form.sequence = i
+ invl_logs = self._import_fill_invoice_line_form(journal, invl_el, invoice_form, invoice_line_form, qty_factor)
+ logs += invl_logs
+
+ return invoice_form, logs
+
+ def _import_fill_invoice_line_form(self, journal, tree, invoice_form, invoice_line_form, qty_factor):
+ logs = []
+
+ def _find_value(xpath, element=tree):
+ return self.env['account.edi.format']._find_value(xpath, element, tree.nsmap)
+
+ # Product.
+ name = _find_value('.//ram:SpecifiedTradeProduct/ram:Name', tree)
+ invoice_line_form.product_id = self.env['account.edi.format']._retrieve_product(
+ default_code=_find_value('.//ram:SpecifiedTradeProduct/ram:SellerAssignedID', tree),
+ name=_find_value('.//ram:SpecifiedTradeProduct/ram:Name', tree),
+ barcode=_find_value('.//ram:SpecifiedTradeProduct/ram:GlobalID', tree)
+ )
+ # force original line description instead of the one copied from product's Sales Description
+ if name:
+ invoice_line_form.name = name
+
+ xpath_dict = {
+ 'basis_qty': [
+ './{*}SpecifiedLineTradeAgreement/{*}GrossPriceProductTradePrice/{*}BasisQuantity',
+ './{*}SpecifiedLineTradeAgreement/{*}NetPriceProductTradePrice/{*}BasisQuantity'
+ ],
+ 'gross_price_unit': './{*}SpecifiedLineTradeAgreement/{*}GrossPriceProductTradePrice/{*}ChargeAmount',
+ 'rebate': './{*}SpecifiedLineTradeAgreement/{*}GrossPriceProductTradePrice/{*}AppliedTradeAllowanceCharge/{*}ActualAmount',
+ 'net_price_unit': './{*}SpecifiedLineTradeAgreement/{*}NetPriceProductTradePrice/{*}ChargeAmount',
+ 'billed_qty': './{*}SpecifiedLineTradeDelivery/{*}BilledQuantity',
+ 'allowance_charge': './/{*}SpecifiedLineTradeSettlement/{*}SpecifiedTradeAllowanceCharge',
+ '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_form, qty_factor)
+ # retrieve tax nodes
+ tax_nodes = tree.findall('.//{*}ApplicableTradeTax/{*}RateApplicablePercent')
+ return self._import_fill_invoice_line_taxes(journal, tax_nodes, invoice_line_form, inv_line_vals, logs)
+
+ # -------------------------------------------------------------------------
+ # IMPORT : helpers
+ # -------------------------------------------------------------------------
+
+ def _get_import_document_amount_sign(self, filename, tree):
+ """
+ In factur-x, an invoice has code 380 and a credit note has code 381. However, a credit note can be expressed
+ as an invoice with negative amounts. For this case, we need a factor to take the opposite of each quantity
+ in the invoice.
+ """
+ move_type_code = tree.find('.//{*}ExchangedDocument/{*}TypeCode')
+ if move_type_code is None:
+ return None, None
+ if move_type_code.text == '381':
+ return ('in_refund', 'out_refund'), 1
+ if move_type_code.text == '380':
+ amount_node = tree.find('.//{*}SpecifiedTradeSettlementHeaderMonetarySummation/{*}TaxBasisTotalAmount')
+ if amount_node is not None and float(amount_node.text) < 0:
+ return ('in_refund', 'out_refund'), -1
+ return ('in_invoice', 'out_invoice'), 1
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
new file mode 100644
index 0000000000..981a013abf
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py
@@ -0,0 +1,726 @@
+# -*- coding: utf-8 -*-
+
+from flectra import models, _
+from flectra.osv import expression
+from flectra.tools import html2plaintext, cleanup_xml_node
+from lxml import etree
+
+
+class AccountEdiXmlUBL20(models.AbstractModel):
+ _name = "account.edi.xml.ubl_20"
+ _inherit = 'account.edi.common'
+ _description = "UBL 2.0"
+
+ # -------------------------------------------------------------------------
+ # EXPORT
+ # -------------------------------------------------------------------------
+
+ def _export_invoice_filename(self, invoice):
+ return f"{invoice.name.replace('/', '_')}_ubl_20.xml"
+
+ def _export_invoice_ecosio_schematrons(self):
+ return {
+ 'invoice': 'org.oasis-open:invoice:2.0',
+ 'credit_note': 'org.oasis-open:creditnote:2.0',
+ }
+
+ def _get_country_vals(self, country):
+ return {
+ 'country': country,
+
+ 'identification_code': country.code,
+ 'name': country.name,
+ }
+
+ def _get_partner_party_identification_vals_list(self, partner):
+ return []
+
+ def _get_partner_address_vals(self, partner):
+ return {
+ 'street_name': partner.street,
+ 'additional_street_name': partner.street2,
+ 'city_name': partner.city,
+ 'postal_zone': partner.zip,
+ 'country_subentity': partner.state_id.name,
+ 'country_subentity_code': partner.state_id.code,
+ 'country_vals': self._get_country_vals(partner.country_id),
+ }
+
+ def _get_partner_party_tax_scheme_vals_list(self, partner, role):
+ return [{
+ 'registration_name': partner.name,
+ 'company_id': partner.vat,
+ 'registration_address_vals': self._get_partner_address_vals(partner),
+ 'TaxScheme_vals': {},
+ 'tax_scheme_id': 'VAT',
+ }]
+
+ def _get_partner_party_legal_entity_vals_list(self, partner):
+ commercial_partner = partner.commercial_partner_id
+
+ return [{
+ 'commercial_partner': commercial_partner,
+
+ 'registration_name': commercial_partner.name,
+ 'company_id': commercial_partner.vat,
+ 'registration_address_vals': self._get_partner_address_vals(commercial_partner),
+ }]
+
+ def _get_partner_contact_vals(self, partner):
+ return {
+ 'id': partner.id,
+ 'name': partner.name,
+ 'telephone': partner.phone or partner.mobile,
+ 'electronic_mail': partner.email,
+ }
+
+ def _get_partner_party_vals(self, partner, role):
+ return {
+ 'partner': partner,
+ 'party_identification_vals': self._get_partner_party_identification_vals_list(partner),
+ 'party_name_vals': [{'name': partner.name}],
+ 'postal_address_vals': self._get_partner_address_vals(partner),
+ 'party_tax_scheme_vals': self._get_partner_party_tax_scheme_vals_list(partner, role),
+ 'party_legal_entity_vals': self._get_partner_party_legal_entity_vals_list(partner),
+ 'contact_vals': self._get_partner_contact_vals(partner),
+ }
+
+ def _get_invoice_period_vals_list(self, invoice):
+ """
+ For now, we cannot fill this data from an invoice
+ This corresponds to the 'delivery or invoice period'. For UBL Bis 3, in the case of intra-community supply,
+ the Actual delivery date (BT-72) or the Invoicing period (BG-14) should be present under the form:
+ {
+ 'start_date': str,
+ 'end_date': str,
+ }.
+ """
+ return []
+
+ def _get_delivery_vals_list(self, invoice):
+ # the data is optional, except for ubl bis3 (see the override, where we need to set a default delivery address)
+ if 'partner_shipping_id' in invoice._fields:
+ return [{
+ 'actual_delivery_date': None,
+ 'delivery_location_vals': {
+ 'delivery_address_vals': self._get_partner_address_vals(invoice.partner_shipping_id),
+ },
+ }]
+ else:
+ return []
+
+ def _get_bank_address_vals(self, bank):
+ return {
+ 'street_name': bank.street,
+ 'additional_street_name': bank.street2,
+ 'city_name': bank.city,
+ 'postal_zone': bank.zip,
+ 'country_subentity': bank.state.name,
+ 'country_subentity_code': bank.state.code,
+ 'country_vals': self._get_country_vals(bank.country),
+ }
+
+ def _get_financial_institution_vals(self, bank):
+ return {
+ 'bank': bank,
+ 'id': bank.bic,
+ 'id_attrs': {'schemeID': 'BIC'},
+ 'name': bank.name,
+ 'address_vals': self._get_bank_address_vals(bank),
+ }
+
+ def _get_financial_institution_branch_vals(self, bank):
+ return {
+ 'bank': bank,
+ 'id': bank.bic,
+ 'id_attrs': {'schemeID': 'BIC'},
+ 'financial_institution_vals': self._get_financial_institution_vals(bank),
+ }
+
+ def _get_financial_account_vals(self, partner_bank):
+ vals = {
+ 'bank_account': partner_bank,
+ 'id': partner_bank.acc_number.replace(' ', ''),
+ }
+
+ if partner_bank.bank_id:
+ vals['financial_institution_branch_vals'] = self._get_financial_institution_branch_vals(partner_bank.bank_id)
+
+ return vals
+
+ def _get_invoice_payment_means_vals_list(self, invoice):
+ vals = {
+ 'payment_means_code': 30,
+ 'payment_means_code_attrs': {'name': 'credit transfer'},
+ 'payment_due_date': invoice.invoice_date_due or invoice.invoice_date,
+ 'instruction_id': invoice.payment_reference,
+ 'payment_id_vals': [invoice.payment_reference or invoice.name],
+ }
+
+ if invoice.partner_bank_id:
+ vals['payee_financial_account_vals'] = self._get_financial_account_vals(invoice.partner_bank_id)
+
+ return [vals]
+
+ def _get_invoice_payment_terms_vals_list(self, invoice):
+ payment_term = invoice.invoice_payment_term_id
+ if payment_term:
+ return [{'note_vals': [payment_term.name]}]
+ else:
+ return []
+
+ def _get_invoice_tax_totals_vals_list(self, invoice, taxes_vals):
+ balance_sign = -1 if invoice.is_inbound() else 1
+ tax_totals_vals = {
+ 'currency': invoice.currency_id,
+ 'currency_dp': invoice.currency_id.decimal_places,
+ 'tax_amount': balance_sign * taxes_vals['tax_amount_currency'],
+ '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': balance_sign * vals['base_amount_currency'],
+ 'tax_amount': balance_sign * 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.
+ It provides information about what the product you are selling.
+
+ :param line: An invoice line.
+ :param taxes_vals: The tax details for the current invoice line.
+ :return: A python dictionary.
+
+ """
+ product = line.product_id
+ 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', ', ')
+
+ return {
+ # Simple description about what you are selling.
+ 'description': description,
+
+ # The name of the item.
+ 'name': product.name,
+
+ # Identifier of the product.
+ 'sellers_item_identification_vals': {'id': product.code},
+
+ # The main tax applied. Only one is allowed.
+ 'classified_tax_category_vals': tax_category_vals_list,
+ }
+
+ def _get_document_allowance_charge_vals_list(self, invoice):
+ """
+ https://docs.peppol.eu/poacc/billing/3.0/bis/#_document_level_allowance_or_charge
+ """
+ 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.
+
+ Note that allowance charges do not exist for credit notes in UBL 2.0, so if we apply discount in Flectra
+ the net price will not be consistent with the unit price, but we cannot do anything about it
+
+ :param line: An invoice line.
+ :return: A list of python dictionaries.
+ """
+ fixed_tax_charge_vals_list = []
+ balance_sign = -1 if line.move_id.is_inbound() else 1
+ 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['group_tax_details'][0]['tax_id'].name,
+ 'amount': balance_sign * tax_details['tax_amount_currency'],
+ })
+
+ if not line.discount:
+ return fixed_tax_charge_vals_list
+
+ # Price subtotal without discount:
+ net_price_subtotal = line.price_subtotal
+ # Price subtotal with discount:
+ if line.discount == 100.0:
+ gross_price_subtotal = 0.0
+ else:
+ gross_price_subtotal = line.currency_id.round(net_price_subtotal / (1.0 - (line.discount or 0.0) / 100.0))
+
+ allowance_vals = {
+ 'currency_name': line.currency_id.name,
+ 'currency_dp': line.currency_id.decimal_places,
+
+ # Must be 'false' since this method is for allowances.
+ 'charge_indicator': 'false',
+
+ # A reason should be provided. In Flectra, we only manage discounts.
+ # Full code list is available here:
+ # https://docs.peppol.eu/poacc/billing/3.0/codelist/UNCL5189/
+ 'allowance_charge_reason_code': 95,
+
+ # The discount should be provided as an amount.
+ 'amount': gross_price_subtotal - net_price_subtotal,
+ }
+
+ 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.
+ It provides information about the price applied for the goods and services invoiced.
+
+ :param line: An invoice line.
+ :return: A python dictionary.
+ """
+ # Price subtotal without discount:
+ net_price_subtotal = line.price_subtotal
+ # Price subtotal with discount:
+ if line.discount == 100.0:
+ gross_price_subtotal = 0.0
+ else:
+ gross_price_subtotal = net_price_subtotal / (1.0 - (line.discount or 0.0) / 100.0)
+ # Price subtotal with discount / quantity:
+ gross_price_unit = gross_price_subtotal / line.quantity if line.quantity else 0.0
+
+ uom = super()._get_uom_unece_code(line)
+
+ return {
+ 'currency': line.currency_id,
+ 'currency_dp': line.currency_id.decimal_places,
+
+ # The price of an item, exclusive of VAT, after subtracting item price discount.
+ 'price_amount': gross_price_unit,
+ 'product_price_dp': self.env['decimal.precision'].precision_get('Product Price'),
+
+ # The number of item units to which the price applies.
+ # setting to None -> the xml will not comprise the BaseQuantity (it's not mandatory)
+ 'base_quantity': None,
+ 'base_quantity_attrs': {'unitCode': uom},
+ }
+
+ def _get_invoice_line_vals(self, line, taxes_vals):
+ """ Method used to fill the cac:InvoiceLine node.
+ It provides information about the invoice line.
+
+ :param line: An invoice line.
+ :return: A python dictionary.
+ """
+ allowance_charge_vals_list = self._get_invoice_line_allowance_vals_list(line, 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,
+
+ # The requirement is the id has to be unique by invoice line.
+ 'id': line.id,
+
+ 'invoiced_quantity': line.quantity,
+ 'invoiced_quantity_attrs': {'unitCode': uom},
+
+ '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),
+ 'item_vals': self._get_invoice_line_item_vals(line, taxes_vals),
+ 'price_vals': self._get_invoice_line_price_vals(line),
+ }
+
+ def _export_invoice_vals(self, invoice):
+ def grouping_key_generator(tax_values):
+ tax = tax_values['tax_id']
+ tax_category_vals = self._get_tax_category_list(invoice, tax)[0]
+ 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)
+
+ # 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 Flectra 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
+
+ invoice_lines = invoice.invoice_line_ids.filtered(lambda line: not line.display_type)
+ document_allowance_charge_vals_list = self._get_document_allowance_charge_vals_list(invoice)
+ invoice_line_vals_list = []
+ for line in invoice_lines:
+ line_taxes_vals = taxes_vals['invoice_line_tax_details'][line]
+ line_vals = self._get_invoice_line_vals(line, line_taxes_vals)
+ invoice_line_vals_list.append(line_vals)
+
+ line_extension_amount += line_vals['line_extension_amount']
+
+ # Compute the total allowance/charge amounts.
+ allowance_total_amount = 0.0
+ for allowance_charge_vals in document_allowance_charge_vals_list:
+ if allowance_charge_vals['charge_indicator'] == 'false':
+ allowance_total_amount += allowance_charge_vals['amount']
+
+ supplier = invoice.company_id.partner_id.commercial_partner_id
+ customer = invoice.commercial_partner_id
+
+ # OrderReference/SalesOrderID (sales_order_id) is optional
+ sales_order_id = 'sale_line_ids' in invoice.invoice_line_ids._fields \
+ and ",".join(invoice.invoice_line_ids.sale_line_ids.order_id.mapped('name'))
+ # OrderReference/ID (order_reference) is mandatory inside the OrderReference node !
+ order_reference = invoice.ref or invoice.name if sales_order_id else invoice.ref
+
+ balance_sign = -1 if invoice.is_inbound() else 1
+ vals = {
+ 'builder': self,
+ 'invoice': invoice,
+ 'supplier': supplier,
+ 'customer': customer,
+
+ 'taxes_vals': taxes_vals,
+
+ 'format_float': self.format_float,
+ 'AddressType_template': 'account_edi_ubl_cii.ubl_20_AddressType',
+ 'ContactType_template': 'account_edi_ubl_cii.ubl_20_ContactType',
+ 'PartyType_template': 'account_edi_ubl_cii.ubl_20_PartyType',
+ 'PaymentMeansType_template': 'account_edi_ubl_cii.ubl_20_PaymentMeansType',
+ 'TaxCategoryType_template': 'account_edi_ubl_cii.ubl_20_TaxCategoryType',
+ 'TaxTotalType_template': 'account_edi_ubl_cii.ubl_20_TaxTotalType',
+ 'AllowanceChargeType_template': 'account_edi_ubl_cii.ubl_20_AllowanceChargeType',
+ 'InvoiceLineType_template': 'account_edi_ubl_cii.ubl_20_InvoiceLineType',
+ 'InvoiceType_template': 'account_edi_ubl_cii.ubl_20_InvoiceType',
+
+ 'vals': {
+ 'ubl_version_id': 2.0,
+ 'id': invoice.name,
+ 'issue_date': invoice.invoice_date,
+ 'due_date': invoice.invoice_date_due,
+ 'note_vals': [html2plaintext(invoice.narration)] if invoice.narration else [],
+ 'order_reference': order_reference,
+ 'sales_order_id': sales_order_id,
+ 'accounting_supplier_party_vals': {
+ 'party_vals': self._get_partner_party_vals(supplier, role='supplier'),
+ },
+ 'accounting_customer_party_vals': {
+ 'party_vals': self._get_partner_party_vals(customer, role='customer'),
+ },
+ 'invoice_period_vals_list': self._get_invoice_period_vals_list(invoice),
+ 'delivery_vals_list': self._get_delivery_vals_list(invoice),
+ 'payment_means_vals_list': self._get_invoice_payment_means_vals_list(invoice),
+ 'payment_terms_vals': self._get_invoice_payment_terms_vals_list(invoice),
+ # allowances at the document level, the allowances on invoices (eg. discount) are on invoice_line_vals
+ 'allowance_charge_vals': document_allowance_charge_vals_list,
+ 'tax_total_vals': self._get_invoice_tax_totals_vals_list(invoice, taxes_vals),
+ 'legal_monetary_total_vals': {
+ 'currency': invoice.currency_id,
+ 'currency_dp': invoice.currency_id.decimal_places,
+ 'line_extension_amount': line_extension_amount,
+ 'tax_exclusive_amount': balance_sign * 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,
+ 'payable_amount': invoice.amount_residual,
+ },
+ 'invoice_line_vals': invoice_line_vals_list,
+ 'currency_dp': invoice.currency_id.decimal_places, # currency decimal places
+ },
+ }
+
+ if invoice.move_type == 'out_invoice':
+ vals['main_template'] = 'account_edi_ubl_cii.ubl_20_Invoice'
+ vals['vals']['invoice_type_code'] = 380
+ else:
+ vals['main_template'] = 'account_edi_ubl_cii.ubl_20_CreditNote'
+ vals['vals']['credit_note_type_code'] = 381
+
+ return vals
+
+ def _export_invoice_constraints(self, invoice, vals):
+ constraints = self._invoice_constraints_common(invoice)
+ constraints.update({
+ 'ubl20_supplier_name_required': self._check_required_fields(vals['supplier'], 'name'),
+ 'ubl20_customer_name_required': self._check_required_fields(vals['customer'], 'name'),
+ 'ubl20_commercial_customer_name_required': self._check_required_fields(vals['customer'].commercial_partner_id, 'name'),
+ 'ubl20_invoice_name_required': self._check_required_fields(invoice, 'name'),
+ 'ubl20_invoice_date_required': self._check_required_fields(invoice, 'invoice_date'),
+ })
+ return constraints
+
+ def _export_invoice(self, invoice):
+ vals = self._export_invoice_vals(invoice)
+ errors = [constraint for constraint in self._export_invoice_constraints(invoice, vals).values() if constraint]
+ xml_content = self.env['ir.qweb']._render(vals['main_template'], vals)
+ return etree.tostring(cleanup_xml_node(xml_content), xml_declaration=True, encoding='UTF-8'), set(errors)
+
+ # -------------------------------------------------------------------------
+ # IMPORT
+ # -------------------------------------------------------------------------
+
+ def _import_fill_invoice_form(self, journal, tree, invoice_form, qty_factor):
+
+ def _find_value(xpath, element=tree):
+ # avoid 'TypeError: empty namespace prefix is not supported in XPath'
+ nsmap = {k: v for k, v in tree.nsmap.items() if k is not None}
+ return self.env['account.edi.format']._find_value(xpath, element, nsmap)
+
+ logs = []
+
+ if qty_factor == -1:
+ logs.append(_("The invoice has been converted into a credit note and the quantities have been reverted."))
+
+ # ==== partner_id ====
+
+ role = "Customer" if invoice_form.journal_id.type == 'sale' else "Supplier"
+ vat = _find_value(f'//cac:Accounting{role}Party/cac:Party//cbc:CompanyID')
+ phone = _find_value(f'//cac:Accounting{role}Party/cac:Party//cbc:Telephone')
+ mail = _find_value(f'//cac:Accounting{role}Party/cac:Party//cbc:ElectronicMail')
+ name = _find_value(f'//cac:Accounting{role}Party/cac:Party//cbc:Name')
+ self._import_retrieve_and_fill_partner(invoice_form, name=name, phone=phone, mail=mail, vat=vat)
+
+ # ==== currency_id ====
+
+ currency_code_node = tree.find('.//{*}DocumentCurrencyCode')
+ if currency_code_node is not None:
+ currency = self.env['res.currency'].with_context(active_test=False).search([
+ ('name', '=', currency_code_node.text),
+ ], limit=1)
+ if currency:
+ if not currency.active:
+ logs.append(_("The currency '%s' is not active.", currency.name))
+ invoice_form.currency_id = currency
+ else:
+ logs.append(_("Could not retrieve currency: %s. Did you enable the multicurrency option "
+ "and activate the currency ?", currency_code_node.text))
+
+ # ==== Reference ====
+
+ ref_node = tree.find('./{*}ID')
+ if ref_node is not None:
+ invoice_form.ref = ref_node.text
+
+ # === Note/narration ====
+
+ narration = ""
+ note_node = tree.find('./{*}Note')
+ if note_node is not None and note_node.text:
+ narration += note_node.text + "\n"
+
+ payment_terms_node = tree.find('./{*}PaymentTerms/{*}Note') # e.g. 'Payment within 10 days, 2% discount'
+ if payment_terms_node is not None and payment_terms_node.text:
+ narration += payment_terms_node.text + "\n"
+
+ invoice_form.narration = narration
+
+ # ==== payment_reference ====
+
+ payment_reference_node = tree.find('./{*}PaymentMeans/{*}PaymentID')
+ if payment_reference_node is not None:
+ invoice_form.payment_reference = payment_reference_node.text
+
+ # ==== invoice_date ====
+
+ invoice_date_node = tree.find('./{*}IssueDate')
+ if invoice_date_node is not None:
+ invoice_form.invoice_date = invoice_date_node.text
+
+ # ==== invoice_date_due ====
+
+ for xpath in ('./{*}DueDate', './/{*}PaymentDueDate'):
+ invoice_date_due_node = tree.find(xpath)
+ if invoice_date_due_node is not None:
+ invoice_form.invoice_date_due = invoice_date_due_node.text
+ break
+
+ # ==== invoice_incoterm_id ====
+
+ incoterm_code_node = tree.find('./{*}TransportExecutionTerms/{*}DeliveryTerms/{*}ID')
+ if incoterm_code_node is not None:
+ incoterm = self.env['account.incoterms'].search([('code', '=', incoterm_code_node.text)], limit=1)
+ if incoterm:
+ invoice_form.invoice_incoterm_id = incoterm
+
+ # ==== invoice_line_ids: AllowanceCharge (document level) ====
+
+ logs += self._import_fill_invoice_allowance_charge(tree, invoice_form, journal, qty_factor)
+
+ # ==== Prepaid amount ====
+
+ prepaid_node = tree.find('./{*}LegalMonetaryTotal/{*}PrepaidAmount')
+ logs += self._import_log_prepaid_amount(invoice_form, prepaid_node, qty_factor)
+
+ # ==== invoice_line_ids: InvoiceLine/CreditNoteLine ====
+
+ invoice_line_tag = 'InvoiceLine' if invoice_form.move_type in ('in_invoice', 'out_invoice') or qty_factor == -1 else 'CreditNoteLine'
+ for i, invl_el in enumerate(tree.findall('./{*}' + invoice_line_tag)):
+ with invoice_form.invoice_line_ids.new() as invoice_line_form:
+ invoice_line_form.sequence = i
+ invl_logs = self._import_fill_invoice_line_form(journal, invl_el, invoice_form, invoice_line_form, qty_factor)
+ logs += invl_logs
+
+ return invoice_form, logs
+
+ def _import_fill_invoice_line_form(self, journal, tree, invoice_form, invoice_line_form, qty_factor):
+ logs = []
+
+ # Product
+ product = self._import_retrieve_info_from_map(
+ tree,
+ self._import_retrieve_product_map(journal),
+ )
+ if product is not None:
+ invoice_line_form.product_id = product
+
+ # Description
+ description_node = tree.find('./{*}Item/{*}Description')
+ name_node = tree.find('./{*}Item/{*}Name')
+ if description_node is not None:
+ invoice_line_form.name = description_node.text
+ elif name_node is not None:
+ invoice_line_form.name = name_node.text # Fallback on Name if Description is not found.
+
+ xpath_dict = {
+ 'basis_qty': [
+ './{*}Price/{*}BaseQuantity',
+ ],
+ 'gross_price_unit': './{*}Price/{*}AllowanceCharge/{*}BaseAmount',
+ 'rebate': './{*}Price/{*}AllowanceCharge/{*}Amount',
+ 'net_price_unit': './{*}Price/{*}PriceAmount',
+ 'billed_qty': './{*}InvoicedQuantity' if invoice_form.move_type in ('in_invoice', 'out_invoice') or qty_factor == -1 else './{*}CreditedQuantity',
+ 'allowance_charge': './/{*}AllowanceCharge',
+ 'allowance_charge_indicator': './{*}ChargeIndicator',
+ 'allowance_charge_amount': './{*}Amount',
+ 'allowance_charge_reason': './{*}AllowanceChargeReason',
+ 'allowance_charge_reason_code': './{*}AllowanceChargeReasonCode',
+ 'line_total_amount': './{*}LineExtensionAmount',
+ }
+ inv_line_vals = self._import_fill_invoice_line_values(tree, xpath_dict, invoice_line_form, qty_factor)
+ # retrieve tax nodes
+ tax_nodes = tree.findall('.//{*}Item/{*}ClassifiedTaxCategory/{*}Percent')
+ if not tax_nodes:
+ for elem in tree.findall('.//{*}TaxTotal'):
+ tax_nodes += elem.findall('.//{*}TaxSubtotal/{*}Percent')
+ return self._import_fill_invoice_line_taxes(journal, tax_nodes, invoice_line_form, inv_line_vals, logs)
+
+ # -------------------------------------------------------------------------
+ # IMPORT : helpers
+ # -------------------------------------------------------------------------
+
+ def _get_import_document_amount_sign(self, filename, tree):
+ """
+ In UBL, an invoice has tag 'Invoice' and a credit note has tag 'CreditNote'. However, a credit note can be
+ expressed as an invoice with negative amounts. For this case, we need a factor to take the opposite
+ of each quantity in the invoice.
+ """
+ if tree.tag == '{urn:oasis:names:specification:ubl:schema:xsd:Invoice-2}Invoice':
+ amount_node = tree.find('.//{*}LegalMonetaryTotal/{*}TaxExclusiveAmount')
+ if amount_node is not None and float(amount_node.text) < 0:
+ return ('in_refund', 'out_refund'), -1
+ return ('in_invoice', 'out_invoice'), 1
+ if tree.tag == '{urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2}CreditNote':
+ return ('in_refund', 'out_refund'), 1
+ return None, None
+
+ def _import_retrieve_partner_map(self, company, move_type='purchase'):
+ role = "Customer" if move_type == 'sale' else "Supplier"
+
+ def with_vat(tree, extra_domain):
+ vat_node = tree.find(f'.//{{*}}Accounting{role}Party/{{*}}Party//{{*}}CompanyID')
+ vat = None if vat_node is None else vat_node.text
+ return self.env['account.edi.format']._retrieve_partner_with_vat(vat, extra_domain)
+
+ def with_phone_mail(tree, extra_domain):
+ phone_node = tree.find(f'.//{{*}}Accounting{role}Party/{{*}}Party//{{*}}Telephone')
+ mail_node = tree.find(f'.//{{*}}Accounting{role}Party/{{*}}Party//{{*}}ElectronicMail')
+
+ phone = None if phone_node is None else phone_node.text
+ mail = None if mail_node is None else mail_node.text
+ return self.env['account.edi.format']._retrieve_partner_with_phone_mail(phone, mail, extra_domain)
+
+ def with_name(tree, extra_domain):
+ name_node = tree.find(f'.//{{*}}Accounting{role}Party/{{*}}Party//{{*}}Name')
+ name = None if name_node is None else name_node.text
+ return self.env['account.edi.format']._retrieve_partner_with_name(name, extra_domain)
+
+ return {
+ 10: lambda tree: with_vat(tree, [('company_id', '=', company.id)]),
+ 20: lambda tree: with_vat(tree, []),
+ 30: lambda tree: with_phone_mail(tree, [('company_id', '=', company.id)]),
+ 40: lambda tree: with_phone_mail(tree, []),
+ 50: lambda tree: with_name(tree, [('company_id', '=', company.id)]),
+ 60: lambda tree: with_name(tree, []),
+ }
+
+ def _import_retrieve_product_map(self, company):
+
+ def with_code_barcode(tree, extra_domain):
+ domains = []
+
+ default_code_node = tree.find('./{*}Item/{*}SellersItemIdentification/{*}ID')
+ if default_code_node is not None:
+ domains.append([('default_code', '=', default_code_node.text)])
+
+ barcode_node = tree.find("./{*}Item/{*}StandardItemIdentification/{*}ID[@schemeID='0160']")
+ if barcode_node is not None:
+ domains.append([('barcode', '=', barcode_node.text)])
+
+ if not domains:
+ return None
+
+ return self.env['product.product'].search(extra_domain + expression.OR(domains), limit=1)
+
+ def with_name(tree, extra_domain):
+ name_node = tree.find('./{*}Item/{*}Name')
+
+ if name_node is None:
+ return None
+
+ return self.env['product.product'].search(extra_domain + [('name', 'ilike', name_node.text)], limit=1)
+
+ return {
+ 10: lambda tree: with_code_barcode(tree, [('company_id', '=', company.id)]),
+ 20: lambda tree: with_code_barcode(tree, []),
+ 30: lambda tree: with_name(tree, [('company_id', '=', company.id)]),
+ 40: lambda tree: with_name(tree, []),
+ }
+
+ def _import_retrieve_info_from_map(self, tree, import_method_map):
+ for key in sorted(import_method_map.keys()):
+ record = import_method_map[key](tree)
+ if record:
+ return record
+
+ return None
diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_21.py b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_21.py
new file mode 100644
index 0000000000..9a3c9a2448
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_21.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+from flectra import models
+
+
+class AccountEdiXmlUBL21(models.AbstractModel):
+ _name = "account.edi.xml.ubl_21"
+ _inherit = 'account.edi.xml.ubl_20'
+ _description = "UBL 2.1"
+
+ # -------------------------------------------------------------------------
+ # EXPORT
+ # -------------------------------------------------------------------------
+
+ def _export_invoice_filename(self, invoice):
+ return f"{invoice.name.replace('/', '_')}_ubl_21.xml"
+
+ def _export_invoice_ecosio_schematrons(self):
+ return {
+ 'invoice': 'org.oasis-open:invoice:2.1',
+ 'credit_note': 'org.oasis-open:creditnote:2.1',
+ }
+
+ def _export_invoice_vals(self, invoice):
+ # EXTENDS account.edi.xml.ubl_20
+ vals = super()._export_invoice_vals(invoice)
+
+ vals.update({
+ 'InvoiceType_template': 'account_edi_ubl_cii.ubl_21_InvoiceType',
+ 'InvoiceLineType_template': 'account_edi_ubl_cii.ubl_21_InvoiceLineType',
+ })
+
+ vals['vals'].update({
+ 'ubl_version_id': 2.1,
+ 'buyer_reference': invoice.commercial_partner_id.ref,
+ })
+
+ return vals
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
new file mode 100644
index 0000000000..92beed5f0d
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_bis3.py
@@ -0,0 +1,455 @@
+# -*- coding: utf-8 -*-
+
+from flectra import models, _
+from flectra.addons.account_edi_ubl_cii.models.account_edi_common import COUNTRY_EAS
+
+from stdnum.no import mva
+
+
+class AccountEdiXmlUBLBIS3(models.AbstractModel):
+ _name = "account.edi.xml.ubl_bis3"
+ _inherit = 'account.edi.xml.ubl_21'
+ _description = "UBL BIS Billing 3.0.12"
+
+ """
+ * Documentation of EHF Billing 3.0: https://anskaffelser.dev/postaward/g3/
+ * EHF 2.0 is no longer used:
+ https://anskaffelser.dev/postaward/g2/announcement/2019-11-14-removal-old-invoicing-specifications/
+ * Official doc for EHF Billing 3.0 is the OpenPeppol BIS 3 doc +
+ https://anskaffelser.dev/postaward/g3/spec/current/billing-3.0/norway/
+
+ "Based on work done in PEPPOL BIS Billing 3.0, Difi has included Norwegian rules in PEPPOL BIS Billing 3.0 and
+ does not see a need to implement a different CIUS targeting the Norwegian market. Implementation of EHF Billing
+ 3.0 is therefore done by implementing PEPPOL BIS Billing 3.0 without extensions or extra rules."
+
+ Thus, EHF 3 and Bis 3 are actually the same format. The specific rules for NO defined in Bis 3 are added in Bis 3.
+ """
+
+ # -------------------------------------------------------------------------
+ # EXPORT
+ # -------------------------------------------------------------------------
+
+ def _export_invoice_filename(self, invoice):
+ return f"{invoice.name.replace('/', '_')}_ubl_bis3.xml"
+
+ def _export_invoice_ecosio_schematrons(self):
+ return {
+ 'invoice': 'eu.peppol.bis3:invoice:3.13.0',
+ 'credit_note': 'eu.peppol.bis3:creditnote:3.13.0',
+ }
+
+ def _get_country_vals(self, country):
+ # EXTENDS account.edi.xml.ubl_21
+ vals = super()._get_country_vals(country)
+
+ vals.pop('name', None)
+
+ return vals
+
+ def _get_partner_party_tax_scheme_vals_list(self, partner, role):
+ # EXTENDS account.edi.xml.ubl_21
+ vals_list = super()._get_partner_party_tax_scheme_vals_list(partner, role)
+
+ if not partner.vat:
+ return []
+
+ for vals in vals_list:
+ vals.pop('registration_name', None)
+ vals.pop('registration_address_vals', None)
+
+ # /!\ For Australian companies, the ABN is encoded on the VAT field, but doesn't have the 2 digits prefix,
+ # causing a validation error
+ if partner.country_id.code == "AU" and partner.vat and not partner.vat.upper().startswith("AU"):
+ vals['company_id'] = "AU" + partner.vat
+
+ if partner.country_id.code == "LU" and 'l10n_lu_peppol_identifier' in partner._fields and partner.l10n_lu_peppol_identifier:
+ vals['company_id'] = partner.l10n_lu_peppol_identifier
+
+ # sources:
+ # https://anskaffelser.dev/postaward/g3/spec/current/billing-3.0/norway/#_applying_foretaksregisteret
+ # https://docs.peppol.eu/poacc/billing/3.0/bis/#national_rules (NO-R-002 (warning))
+ if partner.country_id.code == "NO" and role == 'supplier':
+ vals_list.append({
+ 'company_id': "Foretaksregisteret",
+ 'tax_scheme_id': "TAX",
+ })
+
+ return vals_list
+
+ def _get_partner_party_legal_entity_vals_list(self, partner):
+ # EXTENDS account.edi.xml.ubl_21
+ vals_list = super()._get_partner_party_legal_entity_vals_list(partner)
+
+ for vals in vals_list:
+ vals.pop('registration_address_vals', None)
+ if partner.country_id.code == 'NL' and 'l10n_nl_oin' in partner._fields:
+ endpoint = partner.l10n_nl_oin or partner.l10n_nl_kvk
+ scheme = '0190' if partner.l10n_nl_oin else '0106'
+ vals.update({
+ 'company_id': endpoint,
+ 'company_id_attrs': {'schemeID': scheme},
+ })
+ if partner.country_id.code == "LU" and 'l10n_lu_peppol_identifier' in partner._fields and partner.l10n_lu_peppol_identifier:
+ vals['company_id'] = partner.l10n_lu_peppol_identifier
+ if partner.country_id.code == 'DK':
+ # DK-R-014: For Danish Suppliers it is mandatory to specify schemeID as "0184" (DK CVR-number) when
+ # PartyLegalEntity/CompanyID is used for AccountingSupplierParty
+ vals['company_id_attrs'] = {'schemeID': '0184'}
+
+ return vals_list
+
+ def _get_partner_contact_vals(self, partner):
+ # EXTENDS account.edi.xml.ubl_21
+ vals = super()._get_partner_contact_vals(partner)
+
+ vals.pop('id', None)
+
+ return vals
+
+ def _get_partner_party_vals(self, partner, role):
+ # EXTENDS account.edi.xml.ubl_21
+ vals = super()._get_partner_party_vals(partner, role)
+
+ vals['endpoint_id'] = partner.vat
+ vals['endpoint_id_attrs'] = {'schemeID': COUNTRY_EAS.get(partner.country_id.code)}
+
+ if partner.country_id.code == 'NO' and 'l10n_no_bronnoysund_number' in partner._fields:
+ vals.update({
+ 'endpoint_id': partner.l10n_no_bronnoysund_number,
+ 'endpoint_id_attrs': {'schemeID': '0192'},
+ })
+ # [BR-NL-1] Dutch supplier registration number ( AccountingSupplierParty/Party/PartyLegalEntity/CompanyID );
+ # With a Dutch supplier (NL), SchemeID may only contain 106 (Chamber of Commerce number) or 190 (OIN number).
+ # [BR-NL-10] At a Dutch supplier, for a Dutch customer ( AccountingCustomerParty ) the customer registration
+ # number must be filled with Chamber of Commerce or OIN. SchemeID may only contain 106 (Chamber of
+ # Commerce number) or 190 (OIN number).
+ if partner.country_id.code == 'NL' and 'l10n_nl_oin' in partner._fields:
+ if partner.l10n_nl_oin:
+ vals.update({
+ 'endpoint_id': partner.l10n_nl_oin,
+ 'endpoint_id_attrs': {'schemeID': '0190'},
+ })
+ elif partner.l10n_nl_kvk:
+ vals.update({
+ 'endpoint_id': partner.l10n_nl_kvk,
+ 'endpoint_id_attrs': {'schemeID': '0106'},
+ })
+ if partner.country_id.code == 'SG' and 'l10n_sg_unique_entity_number' in partner._fields:
+ vals.update({
+ 'endpoint_id': partner.l10n_sg_unique_entity_number,
+ 'endpoint_id_attrs': {'schemeID': '0195'},
+ })
+ if partner.country_id.code == "LU" and 'l10n_lu_peppol_identifier' in partner._fields and partner.l10n_lu_peppol_identifier:
+ vals['endpoint_id'] = partner.l10n_lu_peppol_identifier
+
+ return vals
+
+ def _get_partner_party_identification_vals_list(self, partner):
+ # EXTENDS account.edi.xml.ubl_21
+ vals = super()._get_partner_party_identification_vals_list(partner)
+
+ if partner.country_id.code == 'NL' and 'l10n_nl_oin' in partner._fields:
+ endpoint = partner.l10n_nl_oin or partner.l10n_nl_kvk
+ vals.append({
+ 'id': endpoint,
+ })
+ return vals
+
+ def _get_delivery_vals_list(self, invoice):
+ # EXTENDS account.edi.xml.ubl_21
+ supplier = invoice.company_id.partner_id.commercial_partner_id
+ customer = invoice.commercial_partner_id
+
+ economic_area = self.env.ref('base.europe').country_ids.mapped('code') + ['NO']
+ intracom_delivery = (customer.country_id.code in economic_area
+ and supplier.country_id.code in economic_area
+ and supplier.country_id != customer.country_id)
+
+ if not intracom_delivery:
+ return []
+
+ # [BR-IC-12]-In an Invoice with a VAT breakdown (BG-23) where the VAT category code (BT-118) is
+ # "Intra-community supply" the Deliver to country code (BT-80) shall not be blank.
+
+ # [BR-IC-11]-In an Invoice with a VAT breakdown (BG-23) where the VAT category code (BT-118) is
+ # "Intra-community supply" the Actual delivery date (BT-72) or the Invoicing period (BG-14)
+ # shall not be blank.
+
+ if 'partner_shipping_id' in invoice._fields:
+ partner_shipping = invoice.partner_shipping_id
+ else:
+ partner_shipping = customer
+
+ return [{
+ 'actual_delivery_date': invoice.invoice_date,
+ 'delivery_location_vals': {
+ 'delivery_address_vals': self._get_partner_address_vals(partner_shipping),
+ },
+ }]
+
+ def _get_partner_address_vals(self, partner):
+ # EXTENDS account.edi.xml.ubl_21
+ vals = super()._get_partner_address_vals(partner)
+ # schematron/openpeppol/3.13.0/xslt/CEN-EN16931-UBL.xslt
+ # [UBL-CR-225]-A UBL invoice should not include the AccountingCustomerParty Party PostalAddress CountrySubentityCode
+ vals.pop('country_subentity_code', None)
+ return vals
+
+ def _get_financial_institution_branch_vals(self, bank):
+ # EXTENDS account.edi.xml.ubl_21
+ vals = super()._get_financial_institution_branch_vals(bank)
+ # schematron/openpeppol/3.13.0/xslt/CEN-EN16931-UBL.xslt
+ # [UBL-CR-664]-A UBL invoice should not include the FinancialInstitutionBranch FinancialInstitution
+ # xpath test: not(//cac:FinancialInstitution)
+ vals.pop('id_attrs', None)
+ vals.pop('financial_institution_vals', None)
+ return vals
+
+ def _get_invoice_payment_means_vals_list(self, invoice):
+ # EXTENDS account.edi.xml.ubl_21
+ vals_list = super()._get_invoice_payment_means_vals_list(invoice)
+
+ for vals in vals_list:
+ vals.pop('payment_due_date', None)
+ vals.pop('instruction_id', None)
+ if vals.get('payment_id_vals'):
+ vals['payment_id_vals'] = vals['payment_id_vals'][:1]
+
+ return vals_list
+
+ def _get_tax_category_list(self, invoice, taxes):
+ # EXTENDS account.edi.xml.ubl_21
+ vals_list = super()._get_tax_category_list(invoice, taxes)
+
+ for vals in vals_list:
+ vals.pop('name')
+ # [UBL-CR-601]-A UBL invoice should not include the InvoiceLine Item ClassifiedTaxCategory TaxExemptionReason
+ #vals.pop('tax_exemption_reason')
+
+ return vals_list
+
+ def _get_invoice_tax_totals_vals_list(self, invoice, taxes_vals):
+ # EXTENDS account.edi.xml.ubl_21
+ vals_list = super()._get_invoice_tax_totals_vals_list(invoice, taxes_vals)
+
+ for vals in vals_list:
+ vals['currency_dp'] = 2
+ for subtotal_vals in vals.get('tax_subtotal_vals', []):
+ subtotal_vals.pop('percent', None)
+ subtotal_vals['currency_dp'] = 2
+
+ return vals_list
+
+ def _get_invoice_line_allowance_vals_list(self, line, tax_values_list):
+ # EXTENDS account.edi.xml.ubl_21
+ vals_list = super()._get_invoice_line_allowance_vals_list(line, tax_values_list)
+
+ for vals in vals_list:
+ vals['currency_dp'] = 2
+
+ return vals_list
+
+ def _get_invoice_line_vals(self, line, taxes_vals):
+ # EXTENDS account.edi.xml.ubl_21
+ vals = super()._get_invoice_line_vals(line, taxes_vals)
+
+ vals.pop('tax_total_vals', None)
+
+ vals['currency_dp'] = 2
+ vals['price_vals']['currency_dp'] = 2
+
+ return vals
+
+ def _export_invoice_vals(self, invoice):
+ # EXTENDS account.edi.xml.ubl_21
+ vals = super()._export_invoice_vals(invoice)
+
+ vals['vals'].update({
+ 'customization_id': 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0',
+ 'profile_id': 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
+ 'currency_dp': 2,
+ 'ubl_version_id': None,
+ })
+ vals['vals']['legal_monetary_total_vals']['currency_dp'] = 2
+
+ # [NL-R-001] For suppliers in the Netherlands, if the document is a creditnote, the document MUST
+ # contain an invoice reference (cac:BillingReference/cac:InvoiceDocumentReference/cbc:ID)
+ if vals['supplier'].country_id.code == 'NL' and 'refund' in invoice.move_type:
+ vals['vals'].update({
+ 'billing_reference_vals': {
+ 'id': invoice.ref,
+ 'issue_date': None,
+ }
+ })
+
+ return vals
+
+ def _export_invoice_constraints(self, invoice, vals):
+ # EXTENDS account.edi.xml.ubl_21
+ constraints = super()._export_invoice_constraints(invoice, vals)
+ constraints.update(
+ self._invoice_constraints_peppol_en16931_ubl(invoice, vals)
+ )
+ constraints.update(
+ self._invoice_constraints_cen_en16931_ubl(invoice, vals)
+ )
+
+ return constraints
+
+ def _invoice_constraints_cen_en16931_ubl(self, invoice, vals):
+ """
+ corresponds to the errors raised by ' schematron/openpeppol/3.13.0/xslt/CEN-EN16931-UBL.xslt' for invoices.
+ This xslt was obtained by transforming the corresponding sch
+ https://docs.peppol.eu/poacc/billing/3.0/files/CEN-EN16931-UBL.sch.
+ """
+ eu_countries = self.env.ref('base.europe').country_ids
+ intracom_delivery = (vals['customer'].country_id in eu_countries
+ and vals['supplier'].country_id in eu_countries
+ and vals['customer'].country_id != vals['supplier'].country_id)
+
+ constraints = {
+ # [BR-S-02]-An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code
+ # (BT-151) is "Standard rated" shall contain the Seller VAT Identifier (BT-31), the Seller tax registration
+ # identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63).
+ # ---
+ # [BR-CO-26]-In order for the buyer to automatically identify a supplier, the Seller identifier (BT-29),
+ # the Seller legal registration identifier (BT-30) and/or the Seller VAT identifier (BT-31) shall be present.
+ 'cen_en16931_seller_vat_identifier': self._check_required_fields(
+ vals['supplier'], 'vat' # this check is larger than the rules above
+ ),
+ # [BR-61]-If the Payment means type code (BT-81) means SEPA credit transfer, Local credit transfer or
+ # Non-SEPA international credit transfer, the Payment account identifier (BT-84) shall be present.
+ # note: Payment account identifier is
+ # note: no need to check account_number, because it's a required field for a partner_bank
+ 'cen_en16931_payment_account_identifier': self._check_required_fields(
+ invoice, 'partner_bank_id'
+ ) if vals['vals']['payment_means_vals_list'][0]['payment_means_code'] in (30, 58) else None,
+ # [BR-62]-The Seller electronic address (BT-34) shall have a Scheme identifier.
+ # if this fails, it might just be a missing country when mapping the country to the EAS code
+ 'cen_en16931_seller_EAS': self._check_required_fields(
+ vals['vals']['accounting_supplier_party_vals']['party_vals']['endpoint_id_attrs'], 'schemeID',
+ _("No Electronic Address Scheme (EAS) could be found for %s.", vals['customer'].name)
+ ),
+ # [BR-63]-The Buyer electronic address (BT-49) shall have a Scheme identifier.
+ # if this fails, it might just be a missing country when mapping the country to the EAS code
+ 'cen_en16931_buyer_EAS': self._check_required_fields(
+ vals['vals']['accounting_customer_party_vals']['party_vals']['endpoint_id_attrs'], 'schemeID',
+ _("No Electronic Address Scheme (EAS) could be found for %s.", vals['customer'].name)
+ ),
+ # [BR-IC-12]-In an Invoice with a VAT breakdown (BG-23) where the VAT category code (BT-118) is
+ # "Intra-community supply" the Deliver to country code (BT-80) shall not be blank.
+ 'cen_en16931_delivery_country_code': self._check_required_fields(
+ vals['vals']['delivery_vals_list'][0], 'delivery_location_vals',
+ _("For intracommunity supply, the delivery address should be included.")
+ ) if intracom_delivery else None,
+
+ # [BR-IC-11]-In an Invoice with a VAT breakdown (BG-23) where the VAT category code (BT-118) is
+ # "Intra-community supply" the Actual delivery date (BT-72) or the Invoicing period (BG-14)
+ # shall not be blank.
+ 'cen_en16931_delivery_date_invoicing_period': self._check_required_fields(
+ vals['vals']['delivery_vals_list'][0], 'actual_delivery_date',
+ _("For intracommunity supply, the actual delivery date or the invoicing period should be included.")
+ ) and self._check_required_fields(
+ vals['vals']['invoice_period_vals_list'][0], ['start_date', 'end_date'],
+ _("For intracommunity supply, the actual delivery date or the invoicing period should be included.")
+ ) if intracom_delivery else None,
+ }
+
+ for line in invoice.invoice_line_ids.filtered(lambda x: x.display_type not in ('line_note', 'line_section')):
+ 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.")})
+
+ return constraints
+
+ def _invoice_constraints_peppol_en16931_ubl(self, invoice, vals):
+ """
+ corresponds to the errors raised by 'schematron/openpeppol/3.13.0/xslt/PEPPOL-EN16931-UBL.xslt' for
+ invoices in ecosio. This xslt was obtained by transforming the corresponding sch
+ https://docs.peppol.eu/poacc/billing/3.0/files/PEPPOL-EN16931-UBL.sch.
+
+ The national rules (https://docs.peppol.eu/poacc/billing/3.0/bis/#national_rules) are included in this file.
+ They always refer to the supplier's country.
+ """
+ constraints = {
+ # PEPPOL-EN16931-R020: Seller electronic address MUST be provided
+ 'peppol_en16931_ubl_seller_endpoint': self._check_required_fields(
+ vals['supplier'], 'vat'
+ ),
+ # PEPPOL-EN16931-R010: Buyer electronic address MUST be provided
+ 'peppol_en16931_ubl_buyer_endpoint': self._check_required_fields(
+ vals['customer'], 'vat'
+ ),
+ # PEPPOL-EN16931-R003: A buyer reference or purchase order reference MUST be provided.
+ 'peppol_en16931_ubl_buyer_ref_po_ref':
+ "A buyer reference or purchase order reference must be provided." if self._check_required_fields(
+ vals['vals'], 'buyer_reference'
+ ) and self._check_required_fields(vals['vals'], 'order_reference') else None,
+ }
+
+ if vals['supplier'].country_id.code == 'NL':
+ constraints.update({
+ # [NL-R-001] For suppliers in the Netherlands, if the document is a creditnote, the document MUST contain
+ # an invoice reference (cac:BillingReference/cac:InvoiceDocumentReference/cbc:ID)
+ 'nl_r_001': self._check_required_fields(invoice, 'ref') if 'refund' in invoice.move_type else '',
+
+ # [NL-R-002] For suppliers in the Netherlands the supplier’s address (cac:AccountingSupplierParty/cac:Party
+ # /cac:PostalAddress) MUST contain street name (cbc:StreetName), city (cbc:CityName) and post code (cbc:PostalZone)
+ 'nl_r_002_street': self._check_required_fields(vals['supplier'], 'street'),
+ 'nl_r_002_zip': self._check_required_fields(vals['supplier'], 'zip'),
+ 'nl_r_002_city': self._check_required_fields(vals['supplier'], 'city'),
+
+ # [NL-R-003] For suppliers in the Netherlands, the legal entity identifier MUST be either a
+ # KVK or OIN number (schemeID 0106 or 0190)
+ 'nl_r_003': _(
+ "The supplier %s must have a KVK or OIN number.",
+ vals['supplier'].display_name
+ ) if 'l10n_nl_oin' not in vals['supplier']._fields or 'l10n_nl_kvk' not in vals['supplier']._fields else '',
+
+ # [NL-R-007] For suppliers in the Netherlands, the supplier MUST provide a means of payment
+ # (cac:PaymentMeans) if the payment is from customer to supplier
+ 'nl_r_007': self._check_required_fields(invoice, 'partner_bank_id')
+ })
+
+ if vals['customer'].country_id.code == 'NL':
+ constraints.update({
+ # [NL-R-004] For suppliers in the Netherlands, if the customer is in the Netherlands, the customer
+ # address (cac:AccountingCustomerParty/cac:Party/cac:PostalAddress) MUST contain the street name
+ # (cbc:StreetName), the city (cbc:CityName) and post code (cbc:PostalZone)
+ 'nl_r_004_street': self._check_required_fields(vals['customer'], 'street'),
+ 'nl_r_004_city': self._check_required_fields(vals['customer'], 'city'),
+ 'nl_r_004_zip': self._check_required_fields(vals['customer'], 'zip'),
+
+ # [NL-R-005] For suppliers in the Netherlands, if the customer is in the Netherlands,
+ # the customer’s legal entity identifier MUST be either a KVK or OIN number (schemeID 0106 or 0190)
+ 'nl_r_005': _(
+ "The customer %s must have a KVK or OIN number.",
+ vals['customer'].display_name
+ ) if 'l10n_nl_oin' not in vals['customer']._fields or 'l10n_nl_kvk' not in vals['customer']._fields else '',
+ })
+
+ if vals['supplier'].country_id.code == 'NO':
+ vat = vals['supplier'].vat
+ constraints.update({
+ # NO-R-001: For Norwegian suppliers, a VAT number MUST be the country code prefix NO followed by a
+ # valid Norwegian organization number (nine numbers) followed by the letters MVA.
+ # Note: mva.is_valid("179728982MVA") is True while it lacks the NO prefix
+ 'no_r_001': _(
+ "The VAT number of the supplier does not seem to be valid. It should be of the form: NO179728982MVA."
+ ) if not mva.is_valid(vat) or len(vat) != 14 or vat[:2] != 'NO' or vat[-3:] != 'MVA' else "",
+
+ 'no_supplier_bronnoysund': _(
+ "The supplier %s must have a Bronnoysund company registry.",
+ vals['supplier'].display_name
+ ) if 'l10n_no_bronnoysund_number' not in vals['supplier']._fields or not vals['supplier'].l10n_no_bronnoysund_number else "",
+ })
+ if vals['customer'].country_id.code == 'NO':
+ constraints.update({
+ 'no_customer_bronnoysund': _(
+ "The supplier %s must have a Bronnoysund company registry.",
+ vals['customer'].display_name
+ ) if 'l10n_no_bronnoysund_number' not in vals['customer']._fields or not vals['customer'].l10n_no_bronnoysund_number else "",
+ })
+
+ return constraints
diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_efff.py b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_efff.py
new file mode 100644
index 0000000000..ace5f84a9f
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_efff.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+
+from flectra import models
+
+import re
+
+
+class AccountEdiXmlUBLEFFF(models.AbstractModel):
+ _inherit = "account.edi.xml.ubl_20"
+ _name = 'account.edi.xml.ubl_efff'
+ _description = "E-FFF (BE)"
+
+ # -------------------------------------------------------------------------
+ # EXPORT
+ # -------------------------------------------------------------------------
+
+ def _export_invoice_filename(self, invoice):
+ # official naming convention
+ vat = invoice.company_id.partner_id.commercial_partner_id.vat
+ return 'efff_%s%s%s.xml' % (vat or '', '_' if vat else '', re.sub(r'[\W_]', '', invoice.name))
+
+ def _export_invoice_ecosio_schematrons(self):
+ return None
diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_xrechnung.py b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_xrechnung.py
new file mode 100644
index 0000000000..d91f1ea109
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_xrechnung.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+from flectra import models
+
+
+class AccountEdiXmlUBLDE(models.AbstractModel):
+ _inherit = "account.edi.xml.ubl_bis3"
+ _name = 'account.edi.xml.ubl_de'
+ _description = "BIS3 DE (XRechnung)"
+
+ # -------------------------------------------------------------------------
+ # EXPORT
+ # -------------------------------------------------------------------------
+
+ def _export_invoice_filename(self, invoice):
+ return f"{invoice.name.replace('/', '_')}_ubl_de.xml"
+
+ def _export_invoice_ecosio_schematrons(self):
+ return {
+ 'invoice': 'de.xrechnung:ubl-invoice:2.2.0',
+ 'credit_note': 'de.xrechnung:ubl-creditnote:2.2.0',
+ }
+
+ def _export_invoice_vals(self, invoice):
+ # EXTENDS account.edi.xml.ubl_bis3
+ vals = super()._export_invoice_vals(invoice)
+
+ vals['vals'].update({
+ 'customization_id': 'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2#conformant#urn:xoev-de:kosit:extension:xrechnung_2.2',
+ })
+
+ return vals
+
+ def _export_invoice_constraints(self, invoice, vals):
+ # EXTENDS account.edi.xml.ubl_bis3
+ constraints = super()._export_invoice_constraints(invoice, vals)
+
+ constraints.update({
+ 'bis3_de_supplier_telephone_required': self._check_required_fields(vals['supplier'], ['phone', 'mobile']),
+ 'bis3_de_supplier_electronic_mail_required': self._check_required_fields(vals['supplier'], 'email'),
+ })
+
+ return constraints
diff --git a/addons/account_edi_ubl_cii/models/ir_actions_report.py b/addons/account_edi_ubl_cii/models/ir_actions_report.py
new file mode 100644
index 0000000000..d76279f1b9
--- /dev/null
+++ b/addons/account_edi_ubl_cii/models/ir_actions_report.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import models
+from flectra.tools import cleanup_xml_node
+
+from lxml import etree
+import base64
+from xml.sax.saxutils import escape, quoteattr
+
+
+class IrActionsReport(models.Model):
+ _inherit = 'ir.actions.report'
+
+ def _postprocess_pdf_report(self, record, buffer):
+ """
+ EXTENDS account
+ Add the pdf report in XML as base64 string.
+ """
+ result = super()._postprocess_pdf_report(record, buffer)
+
+ if record._name == 'account.move':
+ # exclude efff because it's handled by l10n_be_edi
+ format_codes = ['ubl_bis3', 'ubl_de', 'nlcius_1']
+ edi_attachments = record.edi_document_ids.filtered(lambda d: d.edi_format_id.code in format_codes).attachment_id
+ for edi_attachment in edi_attachments:
+ old_xml = base64.b64decode(edi_attachment.with_context(bin_size=False).datas, validate=True)
+ tree = etree.fromstring(old_xml)
+ anchor_elements = tree.xpath("//*[local-name()='AccountingSupplierParty']")
+ additional_document_elements = tree.xpath("//*[local-name()='AdditionalDocumentReference']")
+ # with this clause, we ensure the xml are only postprocessed once (even when the invoice is reset to
+ # draft then validated again)
+ if anchor_elements and not additional_document_elements:
+ pdf = base64.b64encode(buffer.getvalue()).decode()
+ pdf_name = '%s.pdf' % record.name.replace('/', '_')
+ to_inject = '''
+
+ %s
+
+
+ %s
+
+
+
+ ''' % (escape(pdf_name), quoteattr(pdf_name), pdf)
+
+ anchor_index = tree.index(anchor_elements[0])
+ tree.insert(anchor_index, etree.fromstring(to_inject))
+ new_xml = etree.tostring(cleanup_xml_node(tree), xml_declaration=True, encoding='UTF-8')
+ edi_attachment.write({
+ 'res_model': 'account.move',
+ 'res_id': record.id,
+ 'datas': base64.b64encode(new_xml),
+ 'mimetype': 'application/xml',
+ })
+
+ return result
diff --git a/addons/crm_flectra/__init__.py b/addons/crm_flectra/__init__.py
index 3c89b511ad..7eb1309519 100644
--- a/addons/crm_flectra/__init__.py
+++ b/addons/crm_flectra/__init__.py
@@ -1,2 +1,2 @@
# -*- coding: utf-8 -*-
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
diff --git a/addons/crm_flectra/__manifest__.py b/addons/crm_flectra/__manifest__.py
index c96fa55f48..8b525e749b 100644
--- a/addons/crm_flectra/__manifest__.py
+++ b/addons/crm_flectra/__manifest__.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
{
diff --git a/addons/hw_drivers/controllers/driver.py b/addons/hw_drivers/controllers/driver.py
old mode 100644
new mode 100755
diff --git a/addons/l10n_account_edi_ubl_cii_tests/__init__.py b/addons/l10n_account_edi_ubl_cii_tests/__init__.py
new file mode 100644
index 0000000000..7eb1309519
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
diff --git a/addons/l10n_account_edi_ubl_cii_tests/__manifest__.py b/addons/l10n_account_edi_ubl_cii_tests/__manifest__.py
new file mode 100644
index 0000000000..fc886a925e
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/__manifest__.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+{
+ 'name': "Testing the Import/Export invoices with UBL/CII",
+ 'version': '1.0',
+ 'category': 'Hidden/Tests',
+ 'description': """
+ This module tests the module 'account_edi_ubl_cii', it is separated since dependencies to some
+ localizations were required. Its name begins with 'l10n' to not overload runbot.
+
+ The test files are separated by sources, they were taken from:
+
+ * the factur-x doc (form the FNFE)
+ * the peppol-bis-invoice-3 doc (the github repository: https://github.com/OpenPEPPOL/peppol-bis-invoice-3/tree/master/rules/examples contains examples)
+ * flectra, these files pass all validation tests (using ecosio or the FNFE validator)
+
+ We test that the external examples are correctly imported (currency, total amount and total tax match).
+ We also test that generating xml from flectra with given parameters gives exactly the same xml as the expected,
+ valid ones.
+ """,
+ 'depends': [
+ 'l10n_generic_coa',
+ 'account_edi_ubl_cii',
+ 'l10n_fr',
+ 'l10n_be',
+ 'l10n_de',
+ ],
+ 'installable': True,
+ 'application': False,
+ 'auto_install': False,
+ 'license': 'LGPL-3',
+}
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/__init__.py b/addons/l10n_account_edi_ubl_cii_tests/tests/__init__.py
new file mode 100644
index 0000000000..2e04ccf6d1
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+from . import test_xml_ubl_be
+from . import test_xml_ubl_de
+from . import test_xml_cii_fr
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/common.py b/addons/l10n_account_edi_ubl_cii_tests/tests/common.py
new file mode 100644
index 0000000000..8ede4548b8
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/common.py
@@ -0,0 +1,241 @@
+# -*- coding: utf-8 -*-
+import base64
+
+from freezegun import freeze_time
+
+from flectra.addons.account_edi.tests.common import AccountEdiTestCommon
+from flectra import fields
+from flectra.modules.module import get_resource_path
+from flectra.tests import tagged
+from lxml import etree
+
+
+@tagged('post_install_l10n', 'post_install', '-at_install')
+class TestUBLCommon(AccountEdiTestCommon):
+
+ @classmethod
+ def setUpClass(cls, chart_template_ref=None, edi_format_ref=None):
+ super().setUpClass(chart_template_ref=chart_template_ref, edi_format_ref=edi_format_ref)
+
+ # Ensure the testing currency is using a valid ISO code.
+ real_usd = cls.env.ref('base.USD')
+ real_usd.name = 'FUSD'
+ real_usd.flush(['name'])
+ cls.currency_data['currency'].name = 'USD'
+
+ # remove this tax, otherwise, at import, this tax with children taxes can be selected and the total is wrong
+ 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.
+ eur = cls.env.ref('base.EUR')
+ if not eur.active:
+ eur.active = True
+
+ res = super().setup_company_data(company_name, chart_template=chart_template, **kwargs)
+ res['company'].currency_id = eur
+ return res
+
+ def assert_same_invoice(self, invoice1, invoice2, **invoice_kwargs):
+ self.assertEqual(len(invoice1.invoice_line_ids), len(invoice2.invoice_line_ids))
+ self.assertRecordValues(invoice2, [{
+ 'partner_id': invoice1.partner_id.id,
+ 'invoice_date': fields.Date.from_string(invoice1.date),
+ 'currency_id': invoice1.currency_id.id,
+ 'amount_untaxed': invoice1.amount_untaxed,
+ 'amount_tax': invoice1.amount_tax,
+ 'amount_total': invoice1.amount_total,
+ **invoice_kwargs,
+ }])
+
+ default_invoice_line_kwargs_list = [{}] * len(invoice1.invoice_line_ids)
+ invoice_line_kwargs_list = invoice_kwargs.get('invoice_line_ids', default_invoice_line_kwargs_list)
+ self.assertRecordValues(invoice2.invoice_line_ids, [{
+ 'quantity': line.quantity,
+ 'price_unit': line.price_unit,
+ 'discount': line.discount,
+ 'product_id': line.product_id.id,
+ 'product_uom_id': line.product_uom_id.id,
+ **invoice_line_kwargs,
+ } for line, invoice_line_kwargs in zip(invoice1.invoice_line_ids, invoice_line_kwargs_list)])
+
+ # -------------------------------------------------------------------------
+ # IMPORT HELPERS
+ # -------------------------------------------------------------------------
+
+ @freeze_time('2017-01-01')
+ def _assert_imported_invoice_from_etree(self, invoice, xml_etree, xml_filename):
+ """
+ Create an account.move directly from an xml file, asserts the invoice obtained is the same as the expected
+ invoice.
+ """
+ new_invoice = self.edi_format._create_invoice_from_xml_tree(
+ xml_filename,
+ xml_etree,
+ # /!\ use the same journal as the invoice's one to import the xml !
+ invoice.journal_id,
+ )
+
+ self.assertTrue(new_invoice)
+ self.assert_same_invoice(invoice, new_invoice)
+
+ def _assert_imported_invoice_from_file(self, subfolder, filename, amount_total, amount_tax, list_line_subtotals,
+ list_line_price_unit=None, list_line_discount=None, list_line_taxes=None,
+ move_type='in_invoice', currency_id=None):
+ """
+ Create an empty account.move, update the file to fill its fields, asserts the currency, total and tax amounts
+ are as expected.
+ """
+ if not currency_id:
+ currency_id = self.env.ref('base.EUR').id
+
+ # 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,
+ 'journal_id': self.company_data['default_journal_purchase'].id,
+ })
+ invoice_count = len(self.env['account.move'].search([]))
+
+ # Import the file to fill the empty invoice
+ self.update_invoice_from_file('l10n_account_edi_ubl_cii_tests', subfolder, filename, invoice)
+
+ # Checks
+ self.assertEqual(len(self.env['account.move'].search([])), invoice_count)
+ self.assertRecordValues(invoice, [{
+ 'amount_total': amount_total,
+ 'amount_tax': amount_tax,
+ 'currency_id': currency_id,
+ }])
+ if list_line_price_unit:
+ self.assertEqual(invoice.invoice_line_ids.mapped('price_unit'), list_line_price_unit)
+ if list_line_discount:
+ self.assertEqual(invoice.invoice_line_ids.mapped('discount'), list_line_discount)
+ if list_line_taxes:
+ for line, taxes in zip(invoice.invoice_line_ids, list_line_taxes):
+ self.assertEqual(line.tax_ids, taxes)
+ self.assertEqual(invoice.invoice_line_ids.mapped('price_subtotal'), list_line_subtotals)
+
+ # -------------------------------------------------------------------------
+ # EXPORT HELPERS
+ # -------------------------------------------------------------------------
+
+ @freeze_time('2017-01-01')
+ def _generate_move(self, seller, buyer, **invoice_kwargs):
+ """
+ Create and post an account.move.
+ """
+ # Setup the seller.
+ self.env.company.write({
+ 'partner_id': seller.id,
+ 'name': seller.name,
+ 'street': seller.street,
+ 'zip': seller.zip,
+ 'city': seller.city,
+ 'vat': seller.vat,
+ 'country_id': seller.country_id.id,
+ })
+
+ move_type = invoice_kwargs['move_type']
+ account_move = self.env['account.move'].create({
+ 'partner_id': buyer.id,
+ 'partner_bank_id': (seller if move_type == 'out_invoice' else buyer).bank_ids[:1].id,
+ 'invoice_payment_term_id': self.pay_terms_b.id,
+ 'invoice_date': '2017-01-01',
+ 'date': '2017-01-01',
+ 'currency_id': self.currency_data['currency'].id,
+ 'narration': 'test narration',
+ 'ref': 'ref_move',
+ **invoice_kwargs,
+ 'invoice_line_ids': [
+ (0, 0, {
+ 'sequence': i,
+ **invoice_line_kwargs,
+ })
+ for i, invoice_line_kwargs in enumerate(invoice_kwargs.get('invoice_line_ids', []))
+ ],
+ })
+ # this is needed for formats not enabled by default on the journal
+ account_move.journal_id.edi_format_ids += self.edi_format
+ account_move.action_post()
+ return account_move
+
+ def _assert_invoice_attachment(self, invoice, xpaths, expected_file):
+ """
+ Get attachment from a posted account.move, and asserts it's the same as the expected xml file.
+ """
+ attachment = invoice._get_edi_attachment(self.edi_format)
+ self.assertTrue(attachment)
+ xml_filename = attachment.name
+ xml_content = base64.b64decode(attachment.with_context(bin_size=False).datas)
+ xml_etree = self.get_xml_tree_from_string(xml_content)
+
+ expected_file_path = get_resource_path('l10n_account_edi_ubl_cii_tests', 'tests/test_files', expected_file)
+ expected_etree = etree.parse(expected_file_path).getroot()
+
+ modified_etree = self.with_applied_xpath(
+ expected_etree,
+ xpaths
+ )
+
+ self.assertXmlTreeEqual(
+ xml_etree,
+ modified_etree,
+ )
+
+ return xml_etree, xml_filename
+
+ def _import_invoice_attachment(self, invoice, edi_code, journal):
+ """ Extract the attachment from the invoice and import it on the given journal.
+ """
+ # Get the attachment from the invoice
+ edi_attachment = invoice.edi_document_ids.filtered(
+ lambda doc: doc.edi_format_id.code == edi_code).attachment_id
+ edi_etree = self.get_xml_tree_from_string(edi_attachment.raw)
+
+ # import the attachment and return the resulting invoice
+ return self.edi_format._create_invoice_from_xml_tree(
+ filename='test_filename',
+ tree=edi_etree,
+ journal=journal,
+ )
+
+ def _test_encoding_in_attachment(self, edi_code, filename):
+ """
+ Generate an invoice, assert that the tag '' is present in the attachment
+ """
+ invoice = self._generate_move(
+ seller=self.partner_1,
+ buyer=self.partner_2,
+ move_type='out_invoice',
+ invoice_line_ids=[{'product_id': self.product_a.id}],
+ )
+ edi_attachment = invoice.edi_document_ids.filtered(
+ lambda doc: doc.edi_format_id.code == edi_code).attachment_id
+ self.assertEqual(edi_attachment.name, filename)
+ self.assertIn(b"", edi_attachment.raw)
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_credit_note_type380.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_credit_note_type380.xml
new file mode 100644
index 0000000000..b7474a41e5
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_credit_note_type380.xml
@@ -0,0 +1,193 @@
+
+
+
+
+ urn:cen.eu:en16931:2017
+
+
+
+ AV-2017-0005
+ 380
+
+ 20171116
+
+
+ Avoir suite à bidon 10L d'huile d'olive percé et carton de nougat renversé
+
+
+
+
+
+ 1
+
+
+ 3518370400049
+ NOUG250
+ Nougat de l'Abbaye 250g
+
+
+
+ 4.55
+
+
+ false
+
+ -0.45
+
+
+
+ 4.10
+
+
+
+ -5.000
+
+
+
+ VAT
+ S
+ 20.00
+
+
+ -20.48
+
+
+
+
+
+ 2
+
+
+ HOLANCL
+ Huile d'olive à l'ancienne
+
+
+
+ 19.80
+
+
+ 19.80
+
+
+
+ -10.000
+
+
+
+ VAT
+ S
+ 5.50
+
+
+ -198.00
+
+
+
+
+
+ Au bon moulin
+
+ 99999999800010
+
+
+ Tony Dubois
+
+ +33 4 72 07 08 56
+
+
+ tony.dubois@aubonmoulin.fr
+
+
+
+ 84340
+ 1242 chemin de l'olive
+ Malaucène
+ FR
+
+
+ FR11999999998
+
+
+
+ Ma jolie boutique
+
+ 78787878400035
+
+
+ Alexandre Payet
+
+ +33 4 72 07 08 67
+
+
+ alexandre.payet@majolieboutique.net
+
+
+
+ 69001
+ 35 rue de la République
+ Lyon
+ FR
+
+
+ FR19787878784
+
+
+
+ PO445
+
+
+ MSPE2017
+
+
+
+
+
+ 69001
+ 35 rue de la République
+ Lyon
+ FR
+
+
+
+
+ AV-2017-0005
+ EUR
+
+ -4.10
+ VAT
+ -20.48
+ S
+ 5
+ 20.00
+
+
+ -10.89
+ VAT
+ -198.00
+ S
+ 5
+ 5.50
+
+
+ Paiement immédiat
+
+ 20171116
+
+
+
+ -218.48
+ -218.48
+ -14.99
+ -233.47
+ -0.00
+ -233.47
+
+
+ FA-2017-0010
+
+ 20171113
+
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_credit_note_type381.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_credit_note_type381.xml
new file mode 100644
index 0000000000..d4dfeff6ac
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_credit_note_type381.xml
@@ -0,0 +1,193 @@
+
+
+
+
+ urn:cen.eu:en16931:2017
+
+
+
+ AV-2017-0005
+ 381
+
+ 20171116
+
+
+ Avoir suite à bidon 10L d'huile d'olive percé et carton de nougat renversé
+
+
+
+
+
+ 1
+
+
+ 3518370400049
+ NOUG250
+ Nougat de l'Abbaye 250g
+
+
+
+ 4.55
+
+
+ false
+
+ 0.45
+
+
+
+ 4.10
+
+
+
+ 5.000
+
+
+
+ VAT
+ S
+ 20.00
+
+
+ 20.48
+
+
+
+
+
+ 2
+
+
+ HOLANCL
+ Huile d'olive à l'ancienne
+
+
+
+ 19.80
+
+
+ 19.80
+
+
+
+ 10.000
+
+
+
+ VAT
+ S
+ 5.50
+
+
+ 198.00
+
+
+
+
+
+ Au bon moulin
+
+ 99999999800010
+
+
+ Tony Dubois
+
+ +33 4 72 07 08 56
+
+
+ tony.dubois@aubonmoulin.fr
+
+
+
+ 84340
+ 1242 chemin de l'olive
+ Malaucène
+ FR
+
+
+ FR11999999998
+
+
+
+ Ma jolie boutique
+
+ 78787878400035
+
+
+ Alexandre Payet
+
+ +33 4 72 07 08 67
+
+
+ alexandre.payet@majolieboutique.net
+
+
+
+ 69001
+ 35 rue de la République
+ Lyon
+ FR
+
+
+ FR19787878784
+
+
+
+ PO445
+
+
+ MSPE2017
+
+
+
+
+
+ 69001
+ 35 rue de la République
+ Lyon
+ FR
+
+
+
+
+ AV-2017-0005
+ EUR
+
+ 4.10
+ VAT
+ 20.48
+ S
+ 5
+ 20.00
+
+
+ 10.89
+ VAT
+ 198.00
+ S
+ 5
+ 5.50
+
+
+ Paiement immédiat
+
+ 20171116
+
+
+
+ 218.48
+ 218.48
+ 14.99
+ 233.47
+ 0.00
+ 233.47
+
+
+ FA-2017-0010
+
+ 20171113
+
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_invoice_basis_quantity.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_invoice_basis_quantity.xml
new file mode 100644
index 0000000000..bc34a19bb3
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_invoice_basis_quantity.xml
@@ -0,0 +1,441 @@
+
+
+
+
+ A1
+
+
+ urn:cen.eu:en16931:2017
+
+
+
+ F20220024
+ 380
+
+ 20220131
+
+
+ FOURNISSEUR F SARL au capital de 50 000 EUR
+ REG
+
+
+ RCS MAVILLE 123 456 782
+ ABL
+
+
+ 35 ma rue a moi, code postal Ville Pays – contact@masociete.fr - www.masociete.fr – N° TVA : FR32 123 456 789
+ AAI
+
+
+ Tout retard de paiement engendre une pénalité exigible à compter de la date d'échéance, calculée sur la base de trois fois le taux d'intérêt légal.
+ PMD
+
+
+ Indemnité forfaitaire pour frais de recouvrement en cas de retard de paiement : 40 €.
+ PMT
+
+
+ Les réglements reçus avant la date d'échéance ne donneront pas lieu à escompte.
+ AAB
+
+
+
+
+
+ 1
+
+
+ 598785412598745
+ PRESTATION SUPPORT
+ Description
+
+
+
+ 1
+
+
+ 60.0000
+ 1.0000
+
+
+
+ 1.0000
+
+
+
+ VAT
+ E
+ 0.00
+
+
+
+ false
+
+ 1.00
+ 71
+ REMISE VOLUME
+
+
+
+ false
+
+ 1.00
+ 71
+ REMISE VOLUME
+
+
+
+ false
+
+ 1.00
+ 71
+ REMISE VOLUME
+
+
+
+ false
+
+ 1.00
+ 100
+
+
+
+ true
+
+ 1.00
+ ADL
+
+
+
+ true
+
+ 1.00
+ FRAIS PALETTE
+
+
+
+ true
+
+ 1.00
+ ADL
+
+
+
+ true
+
+ 1.00
+ ADL
+
+
+ 60.00
+
+
+
+
+
+ 2
+
+
+ FOURNITURES DIVERSES
+ Description
+
+
+
+ 3
+
+
+ 30.0000
+ 3.0000
+
+
+
+ 3.0000
+
+
+
+ VAT
+ S
+ 20.00
+
+
+
+ false
+
+ 2.00
+ 71
+ REMISE VOLUME
+
+
+
+ false
+
+ 1.00
+ 71
+ REMISE VOLUME
+
+
+
+ false
+
+ 1.00
+ 71
+ REMISE VOLUME
+
+
+
+ false
+
+ 1.00
+ 100
+
+
+
+ true
+
+ 1.00
+ ADL
+
+
+
+ true
+
+ 1.00
+ ADL
+
+
+
+ true
+
+ 1.00
+ ADL
+
+
+ 28.00
+
+
+
+
+
+ 3
+
+
+ APPEL
+ Description
+
+
+
+ 2
+
+
+ 7.0000
+
+
+
+ 1.0000
+
+
+
+ VAT
+ S
+ 20.00
+
+
+ 7.00
+
+
+
+
+ SERVEXEC
+
+ 123
+ 587451236587
+ LE FOURNISSEUR
+
+ 123456782
+ SELLER TRADE NAME
+
+
+ M. CONTACT
+ DEP SELLER
+
+ 01 02 03 54 87
+
+
+ seller@seller.com
+
+
+
+ 75018
+ 35 rue d'ici
+ Seller line 2
+ Seller line 3
+ PARIS
+ FR
+
+
+ moi@seller.com
+
+
+ FR11123456782
+
+
+
+ 3654789851
+ LE CLIENT
+
+ 987654321
+
+
+ Buyer contact name
+ Buyer dep
+
+ 01 01 25 45 87
+
+
+ buyer@buyer.com
+
+
+
+ 06000
+ 58 rue de la mer
+ Buyer line 2
+ Buyer line 3
+ NICE
+ FR
+
+
+ me@buyer.com
+
+
+ FR 05 987 654 321
+
+
+
+ SELLER TAX REP
+
+ 75018
+ 35 rue d'ici
+ Seller line 2
+ Seller line 3
+ PARIS
+ FR
+
+
+ FR 05 987 654 321
+
+
+
+ PO201925478
+
+
+ CT2018120802
+
+
+
+
+
+ 20220128
+
+
+
+ DESPADV002
+
+
+ RECEIV-ADV002
+
+
+
+ CREDID
+ F20180023BUYER
+ EUR
+
+ 123
+ PAYEE NAME
+
+ 123456782
+
+
+
+ 30
+
+ FRDEBIT
+
+
+ FR76 1254 2547 2569 8542 5874 698
+ LOC BANK ACCOUNT
+
+
+
+ 8.00
+ VAT
+ 40.00
+ S
+ 72
+ 20.00
+
+
+ 0.00
+ VAT
+ VAT EXEMP
+ 60.00
+ E
+ VATEX-EU-D
+ 72
+ 0.00
+
+
+
+ false
+
+ 5.00
+ 100.00
+ 5.00
+ 95
+ REMISE COMMERCIALE
+
+ VAT
+ S
+ 20.00
+
+
+
+
+ true
+
+ 10.00
+ 100.00
+ 10.00
+ FC
+ FRAIS DEPLACEMENT
+
+ VAT
+ S
+ 20.00
+
+
+
+
+ 20220302
+
+ MANDATE PT
+
+
+ 95.00
+ 10.00
+ 5.00
+ 100.00
+ 8.00
+ 108.00
+ 0.00
+ 108.00
+
+
+ BUYER ACCOUNT REF
+
+
+
+
\ No newline at end of file
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_invoice_negative_amounts.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_invoice_negative_amounts.xml
new file mode 100644
index 0000000000..489c785b48
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_factur-x_doc/facturx_invoice_negative_amounts.xml
@@ -0,0 +1,325 @@
+
+
+
+
+ A1
+
+
+ urn:cen.eu:en16931:2017
+
+
+
+ F20220029
+ 380
+
+ 20220131
+
+
+ FOURNISSEUR F SARL au capital de 50 000 EUR
+ REG
+
+
+ RCS MAVILLE 123 456 782
+ ABL
+
+
+ 35 ma rue a moi, code postal Ville Pays – contact@masociete.fr - www.masociete.fr – N° TVA : FR32 123 456 789
+ AAI
+
+
+ Tout retard de paiement engendre une pénalité exigible à compter de la date d'échéance, calculée sur la base de trois fois le taux d'intérêt légal.
+ PMD
+
+
+ Indemnité forfaitaire pour frais de recouvrement en cas de retard de paiement : 40 €.
+ PMT
+
+
+ Les réglements reçus avant la date d'échéance ne donneront pas lieu à escompte.
+ AAB
+
+
+
+
+
+ 1
+
+
+ 598785412598745
+ PRESTATION SUPPORT
+ Description
+
+
+
+ 1
+
+
+ 60.0000
+ 1.0000
+
+
+
+ -1.0000
+
+
+
+ VAT
+ K
+ 0.00
+
+
+
+ 20220101
+
+
+ 20220131
+
+
+
+ -60.00
+
+
+
+
+
+ 2
+
+
+ FOURNITURES DIVERSES
+ Description
+
+
+
+ 3
+
+
+ 10.0000
+
+
+
+ -3.0000
+
+
+
+ VAT
+ K
+ 0.00
+
+
+
+ 20220101
+
+
+
+ -30.00
+
+
+
+
+
+ 3
+
+
+ APPEL
+ Description
+
+
+
+ 5.0000
+
+
+
+ -1.0000
+
+
+
+ VAT
+ K
+ 0.00
+
+
+
+ 20220131
+
+
+
+ -5.00
+
+
+
+
+ SERVEXEC
+
+ 587451236587
+ LE FOURNISSEUR
+
+ 123456782
+ SELLER TRADE NAME
+
+
+ 75018
+ 35 rue d'ici
+ Seller line 2
+ PARIS
+ FR
+
+
+ moi@seller.com
+
+
+ FR11123456782
+
+
+
+ 3654789851
+ LE CLIENT
+
+ 987654321
+
+
+ 06000
+ 58 rue de la mer
+ Buyer line 2
+ NICE
+ DE
+
+
+ me@buyer.com
+
+
+ FR 05 987 654 321
+
+
+
+ SALES REF 2547
+
+
+ PO201925478
+
+
+ CT2018120802
+
+
+ SUPPort doc
+ url:gffter
+ 916
+ support descript
+
+
+ TENDER-002
+ 50
+
+
+ REFCLI0215
+ 130
+
+
+ PROJET2547
+ Project reference
+
+
+
+
+ 3654789851
+ DEL Name
+
+ 06000
+ DEL 58 rue de la mer
+ DEL line 2
+ BERLIN
+ DE
+
+
+
+
+ 20220128
+
+
+
+ DESPADV002
+
+
+ RECEIV-ADV002
+
+
+
+ F20180023BUYER
+ EUR
+
+ 30
+
+ FR76 1254 2547 2569 8542 5874 698
+
+
+
+ 0.00
+ VAT
+ -100.00
+ K
+ VATEX-EU-IC
+ 72
+ 0.00
+
+
+
+ 20220101
+
+
+ 20221231
+
+
+
+
+ false
+
+ -5.00
+ REMISE COMMERCIALE
+
+ VAT
+ K
+ 0.00
+
+
+
+
+ true
+
+ -10.00
+ FRAIS DEPLACEMENT
+
+ VAT
+ K
+ 0.00
+
+
+
+
+ 20220302
+
+
+
+ -95.00
+ -10.00
+ -5.00
+ -100.00
+ 0.00
+ -100.00
+ -10.00
+ -90.00
+
+
+ F20220003
+
+ 20220101
+
+
+
+ BUYER ACCOUNT REF
+
+
+
+
\ No newline at end of file
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 0000000000..ae8a5781ef
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case1.xml
@@ -0,0 +1,132 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ ___ignore___
+ 2017-01-01
+ 2017-02-28
+ 380
+ test narration
+ USD
+ ref_partner_2
+
+ ___ignore___
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+ BE0477472701
+
+ partner_2
+
+
+ Rue des Bourlottes 9
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0477472701
+
+ VAT
+
+
+
+ partner_2
+ BE0477472701
+
+
+ partner_2
+
+
+
+
+ 30
+ ___ignore___
+
+ BE15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ 21.00
+
+ 100.00
+ 21.00
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+
+ 100.00
+ 100.00
+ 121.00
+ 0.00
+ 121.00
+
+
+ ___ignore___
+ 1.0
+ 100.00
+
+ true
+ AEO
+ RECUPEL
+ 1.00
+
+
+ product_a
+ product_a
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 99.00
+
+
+
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 0000000000..578fd806a6
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case2.xml
@@ -0,0 +1,138 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ ___ignore___
+ 2017-01-01
+ 2017-02-28
+ 380
+ test narration
+ USD
+ ref_partner_2
+
+ ___ignore___
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+ BE0477472701
+
+ partner_2
+
+
+ Rue des Bourlottes 9
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0477472701
+
+ VAT
+
+
+
+ partner_2
+ BE0477472701
+
+
+ partner_2
+
+
+
+
+ 30
+ ___ignore___
+
+ BE15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ 21.00
+
+ 100.00
+ 21.00
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+
+ 100.00
+ 100.00
+ 121.00
+ 0.00
+ 121.00
+
+
+ ___ignore___
+ 1.0
+ 100.00
+
+ true
+ AEO
+ RECUPEL
+ 1.00
+
+
+ true
+ AEO
+ AUVIBEL
+ 1.00
+
+
+ product_a
+ product_a
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 98.00
+
+
+
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 0000000000..3d13eec982
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_ecotaxes_case3.xml
@@ -0,0 +1,132 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ ___ignore___
+ 2017-01-01
+ 2017-02-28
+ 380
+ test narration
+ USD
+ ref_partner_2
+
+ ___ignore___
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+ BE0477472701
+
+ partner_2
+
+
+ Rue des Bourlottes 9
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0477472701
+
+ VAT
+
+
+
+ partner_2
+ BE0477472701
+
+
+ partner_2
+
+
+
+
+ 30
+ ___ignore___
+
+ BE15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ 21.00
+
+ 100.00
+ 21.00
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+
+ 100.00
+ 100.00
+ 121.00
+ 0.00
+ 121.00
+
+
+ ___ignore___
+ 1.0
+ 100.00
+
+ true
+ AEO
+ RECUPEL
+ 1.00
+
+
+ product_a
+ product_a
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 99.00
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice.xml
new file mode 100644
index 0000000000..8d6c91c053
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice.xml
@@ -0,0 +1,177 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ INV/2017/01/0002
+ 2017-01-01
+ 2017-02-28
+ 380
+ test narration
+ USD
+ ref_partner_2
+
+ ref_move
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+ BE0477472701
+
+ partner_2
+
+
+ Rue des Bourlottes 9
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0477472701
+
+ VAT
+
+
+
+ partner_2
+ BE0477472701
+
+
+ partner_2
+
+
+
+
+ 30
+ +++000/0000/26268+++
+
+ BE15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ 482.22
+
+ 1782.00
+ 374.22
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 900.00
+ 108.00
+
+ S
+ 12.0
+
+ VAT
+
+
+
+
+
+ 2682.00
+ 2682.00
+ 3164.22
+ 0.00
+ 3164.22
+
+
+ 901
+ 2.0
+ 1782.00
+
+ false
+ 95
+ 198.00
+
+
+ product_a
+ product_a
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 990.00
+
+
+
+ 902
+ 10.0
+ 1000.00
+
+ product_b
+ product_b
+
+ S
+ 12.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
+ 903
+ -1.0
+ -100.00
+
+ product_b
+ product_b
+
+ S
+ 12.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice_no_prices.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice_no_prices.xml
new file mode 100644
index 0000000000..6936362d26
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice_no_prices.xml
@@ -0,0 +1,168 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ INV/2017/01/0002
+ 2017-01-01
+ 2017-02-28
+ 380
+ test narration
+ USD
+ ref_partner_2
+
+ ref_move
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+ BE0477472701
+
+ partner_2
+
+
+ Rue des Bourlottes 9
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0477472701
+
+ VAT
+
+
+
+ partner_2
+ BE0477472701
+
+
+ partner_2
+
+
+
+
+ 30
+ +++000/0000/26268+++
+
+ BE15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ 482.22
+
+ 1782.00
+ 374.22
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 900.00
+ 108.00
+
+ S
+ 12.0
+
+ VAT
+
+
+
+
+
+ 2682.00
+ 2682.00
+ 3164.22
+ 0.00
+ 3164.22
+
+
+ 901
+ 2.0
+ 1782.00
+
+ false
+ 95
+ 198.00
+
+
+ product_a
+ product_a
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+
+ 902
+ 10.0
+ 1000.00
+
+ product_b
+ product_b
+
+ S
+ 12.0
+
+ VAT
+
+
+
+
+
+ 903
+ -1.0
+ -100.00
+
+ product_b
+ product_b
+
+ S
+ 12.0
+
+ VAT
+
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice_public_admin.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice_public_admin.xml
new file mode 100644
index 0000000000..6a6ac669ff
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice_public_admin.xml
@@ -0,0 +1,115 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ INV/2017/01/0002
+ 2017-01-01
+ 2017-02-28
+ 380
+ test narration
+ USD
+ ref_partner_2
+
+ ref_move
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+
+ partner_2
+
+
+ Rue des Bourlottes 9
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ partner_2
+
+
+ partner_2
+
+
+
+
+ 30
+ +++000/0000/05959+++
+
+ BE15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ 42.00
+
+ 200.00
+ 42.00
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+
+ 200.00
+ 200.00
+ 242.00
+ 0.00
+ 242.00
+
+
+ 234
+ 2.0
+ 200.00
+
+ product_a
+ product_a
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice_rounding.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice_rounding.xml
new file mode 100644
index 0000000000..ec166a0fe9
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice_rounding.xml
@@ -0,0 +1,126 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ INV/2017/01/0002
+ 2017-01-01
+ 2017-02-28
+ 380
+ test narration
+ USD
+ ref_partner_2
+
+ ___ignore___
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+ BE0477472701
+
+ partner_2
+
+
+ Rue des Bourlottes 9
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0477472701
+
+ VAT
+
+
+
+ partner_2
+ BE0477472701
+
+
+ partner_2
+
+
+
+
+ 30
+ ___ignore___
+
+ BE15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ 959.07
+
+ 4567.00
+ 959.07
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+
+ 4567.00
+ 4567.00
+ 5526.07
+ 0.00
+ 5526.07
+
+
+ ___ignore___
+ 10000.0
+ 4567.00
+
+ product_a
+ product_a
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 0.4567
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_refund.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_refund.xml
new file mode 100644
index 0000000000..286b4c4f74
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_refund.xml
@@ -0,0 +1,176 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ RINV/2017/01/0001
+ 2017-01-01
+ 381
+ test narration
+ USD
+ ref_partner_2
+
+ ref_move
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+ BE0477472701
+
+ partner_2
+
+
+ Rue des Bourlottes 9
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0477472701
+
+ VAT
+
+
+
+ partner_2
+ BE0477472701
+
+
+ partner_2
+
+
+
+
+ 30
+ RINV/2017/01/0001
+
+ BE90735788866632
+
+
+
+ 30% Advance End of Following Month
+
+
+ 482.22
+
+ 1782.00
+ 374.22
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 900.00
+ 108.00
+
+ S
+ 12.0
+
+ VAT
+
+
+
+
+
+ 2682.00
+ 2682.00
+ 3164.22
+ 0.00
+ 3164.22
+
+
+ 966
+ 2.0
+ 1782.00
+
+ false
+ 95
+ 198.00
+
+
+ product_a
+ product_a
+
+ S
+ 21.0
+
+ VAT
+
+
+
+
+ 990.00
+
+
+
+ 967
+ 10.0
+ 1000.00
+
+ product_b
+ product_b
+
+ S
+ 12.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
+ 968
+ -1.0
+ -100.00
+
+ product_b
+ product_b
+
+ S
+ 12.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
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 0000000000..7e21005f38
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case1.xml
@@ -0,0 +1,152 @@
+
+
+
+
+ urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
+ ___ignore___
+ 380
+
+ 20170101
+
+
+ test narration
+
+
+
+
+
+ 1
+
+
+ product_a
+
+
+
+ 99.00
+
+
+ 99.00
+
+
+
+ 1.0
+
+
+
+ VAT
+ S
+ 21.0
+
+
+
+ true
+
+ 1.00
+ AEO
+ RECUPEL
+
+
+ 100.00
+
+
+
+
+ ref_partner_2
+
+ partner_1
+
+ partner_1
+
+ +1 (650) 555-0111
+
+
+ partner1@yourcompany.com
+
+
+
+ 75000
+ Rue Jean Jaurès, 42
+ Paris
+ FR
+
+
+ FR05677404089
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+ FR35562153452
+
+
+
+ ___ignore___
+
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+
+
+ 20170101
+
+
+
+
+ ___ignore___
+ USD
+
+ 42
+
+ FR15001559627230
+
+
+
+ 21.00
+ VAT
+ 100.00
+ S
+ 5
+ 21.0
+
+
+ 30% Advance End of Following Month
+
+ 20170228
+
+
+
+ 100.00
+ 100.00
+ 21.00
+ 121.00
+ 0.00
+ 121.00
+
+
+
+
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 0000000000..aa6224056d
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case2.xml
@@ -0,0 +1,160 @@
+
+
+
+
+ urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
+ ___ignore___
+ 380
+
+ 20170101
+
+
+ test narration
+
+
+
+
+
+ 1
+
+
+ product_a
+
+
+
+ 98.00
+
+
+ 98.00
+
+
+
+ 1.0
+
+
+
+ VAT
+ S
+ 21.0
+
+
+
+ true
+
+ 1.00
+ AEO
+ RECUPEL
+
+
+
+ true
+
+ 1.00
+ AEO
+ AUVIBEL
+
+
+ 100.00
+
+
+
+
+ ref_partner_2
+
+ partner_1
+
+ partner_1
+
+ +1 (650) 555-0111
+
+
+ partner1@yourcompany.com
+
+
+
+ 75000
+ Rue Jean Jaurès, 42
+ Paris
+ FR
+
+
+ FR05677404089
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+ FR35562153452
+
+
+
+ ___ignore___
+
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+
+
+ 20170101
+
+
+
+
+ ___ignore___
+ USD
+
+ 42
+
+ FR15001559627230
+
+
+
+ 21.00
+ VAT
+ 100.00
+ S
+ 5
+ 21.0
+
+
+ 30% Advance End of Following Month
+
+ 20170228
+
+
+
+ 100.00
+ 100.00
+ 21.00
+ 121.00
+ 0.00
+ 121.00
+
+
+
+
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 0000000000..6c6a41a46b
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_ecotaxes_case3.xml
@@ -0,0 +1,152 @@
+
+
+
+
+ urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
+ ___ignore___
+ 380
+
+ 20170101
+
+
+ test narration
+
+
+
+
+
+ 1
+
+
+ product_a
+
+
+
+ 99.00
+
+
+ 99.00
+
+
+
+ 1.0
+
+
+
+ VAT
+ S
+ 21.0
+
+
+
+ true
+
+ 1.00
+ AEO
+ RECUPEL
+
+
+ 100.00
+
+
+
+
+ ref_partner_2
+
+ partner_1
+
+ partner_1
+
+ +1 (650) 555-0111
+
+
+ partner1@yourcompany.com
+
+
+
+ 75000
+ Rue Jean Jaurès, 42
+ Paris
+ FR
+
+
+ FR05677404089
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+ FR35562153452
+
+
+
+ ___ignore___
+
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+
+
+ 20170101
+
+
+
+
+ ___ignore___
+ USD
+
+ 42
+
+ FR15001559627230
+
+
+
+ 21.00
+ VAT
+ 100.00
+ S
+ 5
+ 21.0
+
+
+ 30% Advance End of Following Month
+
+ 20170228
+
+
+
+ 100.00
+ 100.00
+ 21.00
+ 121.00
+ 0.00
+ 121.00
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice.xml
new file mode 100644
index 0000000000..767017b09c
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice.xml
@@ -0,0 +1,214 @@
+
+
+
+
+ urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
+ INV/2017/01/0002
+ 380
+
+ 20170101
+
+
+ test narration
+
+
+
+
+
+ 1
+
+
+ product_a
+
+
+
+ 990.00
+
+
+ false
+
+ 99.00
+
+
+
+ 891.00
+
+
+
+ 2.0
+
+
+
+ VAT
+ S
+ 21.0
+
+
+ 1782.00
+
+
+
+
+
+ 2
+
+
+ product_b
+
+
+
+ 100.00
+
+
+ 100.00
+
+
+
+ 10.0
+
+
+
+ VAT
+ S
+ 12.0
+
+
+ 1000.00
+
+
+
+
+
+ 3
+
+
+ product_b
+
+
+
+ 100.00
+
+
+ 100.00
+
+
+
+ -1.0
+
+
+
+ VAT
+ S
+ 12.0
+
+
+ -100.00
+
+
+
+
+ ref_partner_2
+
+ partner_1
+
+ partner_1
+
+ +1 (650) 555-0111
+
+
+ partner1@yourcompany.com
+
+
+
+ 75000
+ Rue Jean Jaurès, 42
+ Paris
+ FR
+
+
+ FR05677404089
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+ FR35562153452
+
+
+
+ INV/2017/01/0002: INV/2017/01/0002
+
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+
+
+ 20170101
+
+
+
+
+ INV/2017/01/0002
+ USD
+
+ 42
+
+ FR15001559627230
+
+
+
+ 374.22
+ VAT
+ 1782.00
+ S
+ 5
+ 21.0
+
+
+ 108.00
+ VAT
+ 900.00
+ S
+ 5
+ 12.0
+
+
+ 30% Advance End of Following Month
+
+ 20170228
+
+
+
+ 2682.00
+ 2682.00
+ 482.22
+ 3164.22
+ 0.00
+ 3164.22
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice_tax_incl.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice_tax_incl.xml
new file mode 100644
index 0000000000..987c21bc67
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice_tax_incl.xml
@@ -0,0 +1,241 @@
+
+
+
+
+ urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
+ INV/2017/01/0001
+ 380
+
+ 20170101
+
+
+ test narration
+
+
+
+
+
+ 1
+
+
+ product_a
+
+
+
+ 95.24
+
+
+ 95.24
+
+
+
+ 1.0
+
+
+
+ VAT
+ S
+ 5.0
+
+
+ 95.24
+
+
+
+
+
+ 2
+
+
+ product_a
+
+
+
+ 100.00
+
+
+ 100.00
+
+
+
+ 1.0
+
+
+
+ VAT
+ S
+ 5.0
+
+
+ 100.00
+
+
+
+
+
+ 3
+
+
+ product_a
+
+
+
+ 190.48
+
+
+ false
+
+ 19.05
+
+
+
+ 171.43
+
+
+
+ 1.0
+
+
+
+ VAT
+ S
+ 5.0
+
+
+ 171.43
+
+
+
+
+
+ 4
+
+
+ product_a
+
+
+
+ 200.00
+
+
+ false
+
+ 20.00
+
+
+
+ 180.00
+
+
+
+ 1.0
+
+
+
+ VAT
+ S
+ 5.0
+
+
+ 180.00
+
+
+
+
+ ref_partner_2
+
+ partner_1
+
+ partner_1
+
+ +1 (650) 555-0111
+
+
+ partner1@yourcompany.com
+
+
+
+ 75000
+ Rue Jean Jaurès, 42
+ Paris
+ FR
+
+
+ FR05677404089
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+ FR35562153452
+
+
+
+ INV/2017/01/0001
+
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+
+
+ 20170101
+
+
+
+
+ INV/2017/01/0001
+ USD
+
+ 42
+
+ FR15001559627230
+
+
+
+ 27.33
+ VAT
+ 546.67
+ S
+ 5
+ 5.0
+
+
+ 30% Advance End of Following Month
+
+ 20170228
+
+
+
+ 546.67
+ 546.67
+ 27.33
+ 574.00
+ 0.00
+ 574.00
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_refund.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_refund.xml
new file mode 100644
index 0000000000..84352926b3
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_refund.xml
@@ -0,0 +1,213 @@
+
+
+
+
+ urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
+ RINV/2017/01/0001
+ 381
+
+ 20170101
+
+
+ test narration
+
+
+
+
+
+ 1
+
+
+ product_a
+
+
+
+ 990.00
+
+
+ false
+
+ 99.00
+
+
+
+ 891.00
+
+
+
+ 2.0
+
+
+
+ VAT
+ S
+ 21.0
+
+
+ 1782.00
+
+
+
+
+
+ 2
+
+
+ product_b
+
+
+
+ 100.00
+
+
+ 100.00
+
+
+
+ 10.0
+
+
+
+ VAT
+ S
+ 12.0
+
+
+ 1000.00
+
+
+
+
+
+ 3
+
+
+ product_b
+
+
+
+ 100.00
+
+
+ 100.00
+
+
+
+ -1.0
+
+
+
+ VAT
+ S
+ 12.0
+
+
+ -100.00
+
+
+
+
+ ref_partner_2
+
+ partner_1
+
+ partner_1
+
+ +1 (650) 555-0111
+
+
+ partner1@yourcompany.com
+
+
+
+ 75000
+ Rue Jean Jaurès, 42
+ Paris
+ FR
+
+
+ FR05677404089
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+ FR35562153452
+
+
+
+ RINV/2017/01/0001
+
+
+
+
+ partner_2
+
+ partner_2
+
+
+ 52330
+ Rue Charles de Gaulle
+ Colombey-les-Deux-Églises
+ FR
+
+
+
+
+ 20170101
+
+
+
+
+ USD
+
+ 42
+
+ FR90735788866632
+
+
+
+ 374.22
+ VAT
+ 1782.00
+ S
+ 5
+ 21.0
+
+
+ 108.00
+ VAT
+ 900.00
+ S
+ 5
+ 12.0
+
+
+ 30% Advance End of Following Month
+
+ 20170228
+
+
+
+ 2682.00
+ 2682.00
+ 482.22
+ 3164.22
+ 0.00
+ 3164.22
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_test_import_partner.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_test_import_partner.xml
new file mode 100644
index 0000000000..f215361302
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_test_import_partner.xml
@@ -0,0 +1,127 @@
+
+
+
+
+ urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
+ INV/2017/01/0001
+ 380
+
+ 20170101
+
+
+ test narration
+
+
+
+
+
+ 1
+
+
+ product_a
+
+
+
+ 0.00
+
+
+ 0.00
+
+
+
+ 1.0
+
+
+
+ 0.00
+
+
+
+
+
+ partner_1
+
+ partner_1
+
+ +1 (650) 555-0111
+
+
+ partner1@yourcompany.com
+
+
+
+ 75000
+ Rue Jean Jaurès, 42
+ Paris
+ FR
+
+
+ FR05677404089
+
+
+
+ Buyer
+
+ Buyer
+
+ 1111
+
+
+ buyer@yahoo.com
+
+
+
+ 2222
+
+
+
+ INV/2017/01/0001
+
+
+
+
+ Buyer
+
+ Buyer
+
+ 1111
+
+
+ buyer@yahoo.com
+
+
+
+
+
+ 20170101
+
+
+
+
+ INV/2017/01/0001
+ USD
+
+ 42
+
+ FR15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_invoice.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_invoice.xml
new file mode 100644
index 0000000000..8d9cc0866e
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_invoice.xml
@@ -0,0 +1,185 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ INV/2017/00002
+ 2017-01-01
+ 2017-02-28
+ 380
+ test narration
+ USD
+ ref_partner_2
+
+ ref_move
+
+
+
+ 77777677
+
+ 77777677
+
+
+ partner_1
+
+
+ Kunststraat, 3
+ Amsterdam
+ 1000
+
+ NL
+
+
+
+ NL000099998B57
+
+ VAT
+
+
+
+ partner_1
+ 77777677
+
+
+ partner_1
+ +31 180 6 225789
+ info@outlook.nl
+
+
+
+
+
+ 1234567
+
+ 1234567
+
+
+ partner_2
+
+
+ Europaweg, 2
+ Rotterdam
+ 1200
+
+ NL
+
+
+
+ NL000041452B11
+
+ VAT
+
+
+
+ partner_2
+ 1234567
+
+
+ partner_2
+
+
+
+
+ 30
+ INV/2017/00002
+
+ NL000099998B57
+
+
+
+ 30% Advance End of Following Month
+
+
+ 401.58
+
+ 1782.00
+ 338.58
+
+ S
+ 19.0
+
+ VAT
+
+
+
+
+ 900.00
+ 63.00
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+
+ 2682.00
+ 2682.00
+ 3083.58
+ 0.00
+ 3083.58
+
+
+ 1359
+ 2.0
+ 1782.00
+
+ false
+ 95
+ 198.00
+
+
+ product_a
+ product_a
+
+ S
+ 19.0
+
+ VAT
+
+
+
+
+ 990.00
+
+
+
+ 1360
+ 10.0
+ 1000.00
+
+ product_b
+ product_b
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
+ 1361
+ -1.0
+ -100.00
+
+ product_b
+ product_b
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_refund.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_refund.xml
new file mode 100644
index 0000000000..49eaa9b3fd
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_refund.xml
@@ -0,0 +1,184 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ RINV/2017/00001
+ 2017-01-01
+ 381
+ test narration
+ USD
+ ref_partner_2
+
+ ref_move
+
+
+
+ 77777677
+
+ 77777677
+
+
+ partner_1
+
+
+ Kunststraat, 3
+ Amsterdam
+ 1000
+
+ NL
+
+
+
+ NL000099998B57
+
+ VAT
+
+
+
+ partner_1
+ 77777677
+
+
+ partner_1
+ +31 180 6 225789
+ info@outlook.nl
+
+
+
+
+
+ 1234567
+
+ 1234567
+
+
+ partner_2
+
+
+ Europaweg, 2
+ Rotterdam
+ 1200
+
+ NL
+
+
+
+ NL000041452B11
+
+ VAT
+
+
+
+ partner_2
+ 1234567
+
+
+ partner_2
+
+
+
+
+ 30
+ RINV/2017/00001
+
+ NL93999574162167
+
+
+
+ 30% Advance End of Following Month
+
+
+ 401.58
+
+ 1782.00
+ 338.58
+
+ S
+ 19.0
+
+ VAT
+
+
+
+
+ 900.00
+ 63.00
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+
+ 2682.00
+ 2682.00
+ 3083.58
+ 0.00
+ 3083.58
+
+
+ 1405
+ 2.0
+ 1782.00
+
+ false
+ 95
+ 198.00
+
+
+ product_a
+ product_a
+
+ S
+ 19.0
+
+ VAT
+
+
+
+
+ 990.00
+
+
+
+ 1406
+ 10.0
+ 1000.00
+
+ product_b
+ product_b
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
+ 1407
+ -1.0
+ -100.00
+
+ product_b
+ product_b
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/ubl_test_import_partner.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/ubl_test_import_partner.xml
new file mode 100644
index 0000000000..11107f9da3
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/ubl_test_import_partner.xml
@@ -0,0 +1,101 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ INV/2017/01/0002
+ 2017-01-01
+ 380
+ test narration
+ USD
+ Buyer
+
+ test invoice origin
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+ 2222
+
+ Buyer
+
+
+ 2222
+
+ VAT
+
+
+
+ Buyer
+ 2222
+
+
+ Buyer
+ 1111
+ buyer@yahoo.com
+
+
+
+
+ 30
+ +++000/0000/08282+++
+
+ BE15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ -0.00
+
+
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+
+
+ 259
+ 1.0
+ 0.00
+
+ product_a
+ product_a
+
+
+ 0.00
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_invoice.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_invoice.xml
new file mode 100644
index 0000000000..f613ce0df7
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_invoice.xml
@@ -0,0 +1,179 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2#conformant#urn:xoev-de:kosit:extension:xrechnung_2.2
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ INV/2017/01/0002
+ 2017-01-01
+ 2017-02-28
+ 380
+ test narration
+ USD
+ ref_partner_2
+
+ ref_move
+
+
+
+ DE257486969
+
+ partner_1
+
+
+ Legoland-Allee 3
+ Günzburg
+ 89312
+
+ DE
+
+
+
+ DE257486969
+
+ VAT
+
+
+
+ partner_1
+ DE257486969
+
+
+ partner_1
+ +49 180 6 225789
+ info@legoland.de
+
+
+
+
+
+ DE186775212
+
+ partner_2
+
+
+ Europa-Park-Straße 2
+ Rust
+ 77977
+
+ DE
+
+
+
+ DE186775212
+
+ VAT
+
+
+
+ partner_2
+ DE186775212
+
+
+ partner_2
+
+
+
+
+ 30
+ INV/2017/01/0002
+
+ DE48500105176424548921
+
+
+
+ 30% Advance End of Following Month
+
+
+ 401.58
+
+ 1782.00
+ 338.58
+
+ S
+ 19.0
+
+ VAT
+
+
+
+
+ 900.00
+ 63.00
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+
+ 2682.00
+ 2682.00
+ 3083.58
+ 0.00
+ 3083.58
+
+
+ 1708
+ 2.0
+ 1782.00
+
+ false
+ 95
+ 198.00
+
+
+ product_a
+ product_a
+
+ S
+ 19.0
+
+ VAT
+
+
+
+
+ 990.00
+
+
+
+ 1709
+ 10.0
+ 1000.00
+
+ product_b
+ product_b
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
+ 1710
+ -1.0
+ -100.00
+
+ product_b
+ product_b
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_refund.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_refund.xml
new file mode 100644
index 0000000000..9e16d9adba
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_refund.xml
@@ -0,0 +1,178 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2#conformant#urn:xoev-de:kosit:extension:xrechnung_2.2
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ RINV/2017/01/0001
+ 2017-01-01
+ 381
+ test narration
+ USD
+ ref_partner_2
+
+ ref_move
+
+
+
+ DE257486969
+
+ partner_1
+
+
+ Legoland-Allee 3
+ Günzburg
+ 89312
+
+ DE
+
+
+
+ DE257486969
+
+ VAT
+
+
+
+ partner_1
+ DE257486969
+
+
+ partner_1
+ +49 180 6 225789
+ info@legoland.de
+
+
+
+
+
+ DE186775212
+
+ partner_2
+
+
+ Europa-Park-Straße 2
+ Rust
+ 77977
+
+ DE
+
+
+
+ DE186775212
+
+ VAT
+
+
+
+ partner_2
+ DE186775212
+
+
+ partner_2
+
+
+
+
+ 30
+ RINV/2017/01/0001
+
+ DE50500105175653254743
+
+
+
+ 30% Advance End of Following Month
+
+
+ 401.58
+
+ 1782.00
+ 338.58
+
+ S
+ 19.0
+
+ VAT
+
+
+
+
+ 900.00
+ 63.00
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+
+ 2682.00
+ 2682.00
+ 3083.58
+ 0.00
+ 3083.58
+
+
+ 1754
+ 2.0
+ 1782.00
+
+ false
+ 95
+ 198.00
+
+
+ product_a
+ product_a
+
+ S
+ 19.0
+
+ VAT
+
+
+
+
+ 990.00
+
+
+
+ 1755
+ 10.0
+ 1000.00
+
+ product_b
+ product_b
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
+ 1756
+ -1.0
+ -100.00
+
+ product_b
+ product_b
+
+ S
+ 7.0
+
+ VAT
+
+
+
+
+ 100.00
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_allowance.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_allowance.xml
new file mode 100644
index 0000000000..a7e137d265
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_allowance.xml
@@ -0,0 +1,370 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ Snippet1
+ 2017-11-13
+ 2017-12-01
+ 380
+ Please note we have a new phone number: 22 22 22 22
+ 2017-12-01
+ EUR
+ SEK
+ 4025:123:4343
+ 0150abc
+
+ 2017-12-01
+ 2017-12-31
+
+
+ framework no 1
+
+
+ DR35141
+ 130
+
+
+ ts12345
+ Technical specification
+
+
+ www.techspec.no
+
+
+
+
+
+ 7300010000001
+
+ 99887766
+
+
+ SupplierTradingName Ltd.
+
+
+ Main street 1
+ Postbox 123
+ London
+ GB 123 EW
+
+ GB
+
+
+
+ GB1232434
+
+ VAT
+
+
+
+
+ SupplierOfficialName Ltd
+ GB983294
+ AdditionalLegalInformation
+
+
+
+
+
+
+
+ 4598375937
+
+ 4598375937
+
+
+ BuyerTradingName AS
+
+
+ Hovedgatan 32
+ Po box 878
+ Stockholm
+ 456 34
+ Södermalm
+
+
+ SE
+
+
+
+ SE4598375937
+
+ VAT
+
+
+
+ Buyer Official Name
+ 39937423947
+
+
+ Lisa Johnson
+ 23434234
+ lj@buyer.se
+
+
+
+
+ 2017-11-01
+
+ 7300010000001
+
+ Delivery street 2
+ Building 56
+ Stockholm
+ 21234
+ Södermalm
+
+ Gate 15
+
+
+ SE
+
+
+
+
+
+ Delivery party Name
+
+
+
+
+ 30
+ Snippet1
+
+ IBAN32423940
+ AccountName
+
+ BIC324098
+
+
+
+
+ Payment within 10 days, 2% discount
+
+
+
+ true
+ CG
+ Cleaning
+ 20
+ 200
+ 1000
+
+ S
+ 25
+
+ VAT
+
+
+
+
+
+ false
+ 95
+ Discount
+ 200
+
+ S
+ 25
+
+ VAT
+
+
+
+
+
+ 1225.00
+
+ 4900.0
+ 1225
+
+ S
+ 25
+
+ VAT
+
+
+
+
+ 1000.0
+ 0
+
+ E
+ 0
+ Reason for tax exempt
+
+ VAT
+
+
+
+
+
+ 9324.00
+
+
+
+ 5900
+ 5900
+ 7125
+ 200
+ 200
+ 1000
+ 6125.00
+
+
+
+ 1
+ Testing note on line level
+ 10
+ 4000.00
+ Konteringsstreng
+
+ true
+ CG
+ Cleaning
+ 1
+ 1
+ 100
+
+
+ false
+ 95
+ Discount
+ 101
+
+
+ Description of item A
+ item name
+
+
+ 97iugug876
+
+
+ NO
+
+
+ 09348023
+
+
+ S
+ 25.0
+
+ VAT
+
+
+
+
+
+
+ 410
+ 1
+
+ false
+ 40
+ 450
+
+
+
+
+
+ 2
+ Testing note on line level
+
+ 10
+ 1000.00
+
+ Konteringsstreng
+
+ 2017-12-01
+ 2017-12-05
+
+
+ 124
+
+
+
+ Description of item B
+ item name
+
+ 97iugug876
+
+
+ 86776
+
+
+ E
+ 0.0
+
+ VAT
+
+
+
+ AdditionalItemName
+ AdditionalItemValue
+
+
+
+ 200
+ 2
+
+
+
+ 3
+ Testing note on line level
+ 10
+ 900.00
+ Konteringsstreng
+
+ 2017-12-01
+ 2017-12-05
+
+
+ 124
+
+
+
+ true
+ CG
+ Charge
+ 1
+ 1
+ 100
+
+
+ false
+ 95
+ Discount
+ 101
+
+
+
+ Description of item C
+ item name
+
+ 97iugug876
+
+
+
+ 86776
+
+
+ S
+ 25.0
+
+ VAT
+
+
+
+ AdditionalItemName
+ AdditionalItemValue
+
+
+
+
+ 100
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_credit_note.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_credit_note.xml
new file mode 100644
index 0000000000..66c67d3dc9
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_credit_note.xml
@@ -0,0 +1,224 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ Snippet1
+ 2017-11-13
+ 381
+ Please note we have a new phone number: 22 22 22 22
+ EUR
+ 4025:123:4343
+ 0150abc
+
+
+ Snippet1
+
+
+
+
+
+ 9482348239847239874
+
+ 99887766
+
+
+ SupplierTradingName Ltd.
+
+
+ Main street 1
+ Postbox 123
+ London
+ GB 123 EW
+
+ GB
+
+
+
+ GB1232434
+
+ VAT
+
+
+
+ SupplierOfficialName Ltd
+ GB983294
+
+
+
+
+
+
+ FR23342
+
+ FR23342
+
+
+ BuyerTradingName AS
+
+
+ Hovedgatan 32
+ Po box 878
+ Stockholm
+ 456 34
+
+ SE
+
+
+
+ SE4598375937
+
+ VAT
+
+
+
+ Buyer Official Name
+ 39937423947
+
+
+ Lisa Johnson
+ 23434234
+ lj@buyer.se
+
+
+
+
+
+ 2017-11-01
+
+ 9483759475923478
+
+ Delivery street 2
+ Building 56
+ Stockholm
+ 21234
+
+ SE
+
+
+
+
+
+ Delivery party Name
+
+
+
+
+
+ 30
+ Snippet1
+
+ IBAN32423940
+ AccountName
+
+ BIC324098
+
+
+
+
+
+ Payment within 10 days, 2% discount
+
+
+
+ true
+ Insurance
+ 25
+
+ S
+ 25.0
+
+ VAT
+
+
+
+
+
+ 331.25
+
+ 1325
+ 331.25
+
+ S
+ 25.0
+
+ VAT
+
+
+
+
+
+
+ 1300
+ 1325
+ 1656.25
+ 25
+ 1656.25
+
+
+
+ 1
+ 7
+ 2800
+ Konteringsstreng
+
+ 123
+
+
+ Description of item
+ item name
+
+ 21382183120983
+
+
+ NO
+
+
+ 09348023
+
+
+ S
+ 25.0
+
+ VAT
+
+
+
+
+ 400
+
+
+
+
+ 2
+ -3
+ -1500
+
+ 123
+
+
+ Description 2
+ item name 2
+
+ 21382183120983
+
+
+ NO
+
+
+ 09348023
+
+
+ S
+ 25.0
+
+ VAT
+
+
+
+
+ 500
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_invoice_negative_amounts.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_invoice_negative_amounts.xml
new file mode 100644
index 0000000000..65024ebc5e
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_invoice_negative_amounts.xml
@@ -0,0 +1,224 @@
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ Correction1
+ 2017-11-13
+ 2017-12-01
+ 380
+ EUR
+ 4025:123:4343
+ 0150abc
+
+
+ Snippet1
+
+
+
+
+
+ 9482348239847239874
+
+ 99887766
+
+
+ SupplierTradingName Ltd.
+
+
+ Main street 1
+ Postbox 123
+ London
+ GB 123 EW
+
+ GB
+
+
+
+ GB1232434
+
+ VAT
+
+
+
+ SupplierOfficialName Ltd
+ GB983294
+
+
+
+
+
+
+ FR23342
+
+ FR23342
+
+
+ BuyerTradingName AS
+
+
+ Hovedgatan 32
+ Po box 878
+ Stockholm
+ 456 34
+
+ SE
+
+
+
+ SE4598375937
+
+ VAT
+
+
+
+ Buyer Official Name
+ 39937423947
+
+
+ Lisa Johnson
+ 23434234
+ lj@buyer.se
+
+
+
+
+
+ 2017-11-01
+
+ 9483759475923478
+
+ Delivery street 2
+ Building 56
+ Stockholm
+ 21234
+
+ SE
+
+
+
+
+
+ Delivery party Name
+
+
+
+
+
+ 30
+ Snippet1
+
+ IBAN32423940
+ AccountName
+
+ BIC324098
+
+
+
+
+
+ Payment within 10 days, 2% discount
+
+
+
+ true
+ Insurance
+ -25
+
+ S
+ 25.0
+
+ VAT
+
+
+
+
+
+ -331.25
+
+ -1325
+ -331.25
+
+ S
+ 25.0
+
+ VAT
+
+
+
+
+
+
+ -1300
+ -1325
+ -1656.25
+ -25
+ -1656.25
+
+
+
+ 1
+ -7
+ -2800
+ Konteringsstreng
+
+ 123
+
+
+ Description of item
+ item name
+
+ 21382183120983
+
+
+ NO
+
+
+ 09348023
+
+
+ S
+ 25.0
+
+ VAT
+
+
+
+
+ 400
+
+
+
+
+ 2
+ 3
+ 1500
+
+ 123
+
+
+ Description 2
+ item name 2
+
+ 21382183120983
+
+
+ NO
+
+
+ 09348023
+
+
+ S
+ 25.0
+
+ VAT
+
+
+
+
+ 500
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_tax_exempt_gbp.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_tax_exempt_gbp.xml
new file mode 100644
index 0000000000..9458699447
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_peppol-bis-invoice-3_doc/bis3_tax_exempt_gbp.xml
@@ -0,0 +1,114 @@
+
+
+
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ Vat-Z
+ 2018-08-30
+ 380
+ GBP
+ test reference
+
+
+ 7300010000001
+
+ 7300010000001
+
+
+ Main street 2, Building 4
+ Big city
+ 54321
+
+ GB
+
+
+
+ GB928741974
+
+ VAT
+
+
+
+ The Sellercompany Incorporated
+
+
+
+
+
+ DK12345678
+
+ Anystreet 8
+ Back door
+ Anytown
+ 101
+ RegionB
+
+ DK
+
+
+
+ The Buyercompany
+
+
+
+
+ 30
+
+ SE1212341234123412
+
+ SEXDABCD
+
+
+
+
+ Payment within 30 days
+
+
+ 0.00
+
+ 1200.00
+ 0.00
+
+ E
+ 0
+ VATEX-EU-F
+
+ VAT
+
+
+
+
+
+ 1200.00
+ 1200.00
+ 1200.00
+ 1200.00
+
+
+ 1
+ 10
+ 1200.00
+
+ 1
+
+
+ Test item, category Z
+
+ 192387129837129873
+
+
+ E
+ 0
+
+ VAT
+
+
+
+
+ 120.00
+
+
+
+
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
new file mode 100644
index 0000000000..fb77091d7f
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_cii_fr.py
@@ -0,0 +1,465 @@
+# -*- coding: utf-8 -*-
+
+from flectra.addons.l10n_account_edi_ubl_cii_tests.tests.common import TestUBLCommon
+from flectra.tests import tagged
+
+@tagged('post_install_l10n', 'post_install', '-at_install')
+class TestCIIFR(TestUBLCommon):
+
+ @classmethod
+ def setUpClass(cls,
+ chart_template_ref="l10n_fr.l10n_fr_pcg_chart_template",
+ edi_format_ref="account_edi_facturx.edi_facturx_1_0_05",
+ ):
+ """
+ this test will fail if account_edi_facturx is not installed. In order not to duplicate the
+ account.edi.format already installed, we use the existing ones (comprising
+ account_edi_facturx.facturx_1_0_05).
+ """
+ super().setUpClass(chart_template_ref=chart_template_ref, edi_format_ref=edi_format_ref)
+
+ cls.partner_1 = cls.env['res.partner'].create({
+ 'name': "partner_1",
+ 'street': "Rue Jean Jaurès, 42",
+ 'zip': "75000",
+ 'city': "Paris",
+ 'vat': 'FR05677404089',
+ 'country_id': cls.env.ref('base.fr').id,
+ 'bank_ids': [(0, 0, {'acc_number': 'FR15001559627230'})],
+ 'phone': '+1 (650) 555-0111',
+ 'email': "partner1@yourcompany.com",
+ 'ref': 'ref_partner_1',
+ })
+
+ cls.partner_2 = cls.env['res.partner'].create({
+ 'name': "partner_2",
+ 'street': "Rue Charles de Gaulle",
+ 'zip': "52330",
+ 'city': "Colombey-les-Deux-Églises",
+ 'vat': 'FR35562153452',
+ 'country_id': cls.env.ref('base.fr').id,
+ 'bank_ids': [(0, 0, {'acc_number': 'FR90735788866632'})],
+ 'ref': 'ref_partner_2',
+ })
+
+ cls.tax_21 = cls.env['account.tax'].create({
+ 'name': 'tax_21',
+ 'amount_type': 'percent',
+ 'amount': 21,
+ 'type_tax_use': 'sale',
+ 'sequence': 10,
+ })
+
+ cls.tax_12 = cls.env['account.tax'].create({
+ 'name': 'tax_12',
+ 'amount_type': 'percent',
+ 'amount': 12,
+ 'type_tax_use': 'sale',
+ })
+
+ cls.tax_21_purchase = cls.env['account.tax'].create({
+ 'name': 'tax_21',
+ 'amount_type': 'percent',
+ 'amount': 21,
+ 'type_tax_use': 'purchase',
+ })
+
+ cls.tax_12_purchase = cls.env['account.tax'].create({
+ 'name': 'tax_12',
+ 'amount_type': 'percent',
+ 'amount': 12,
+ 'type_tax_use': 'purchase',
+ })
+
+ cls.tax_5_purchase = cls.env['account.tax'].create({
+ 'name': 'tax_5',
+ 'amount_type': 'percent',
+ 'amount': 5,
+ 'type_tax_use': 'purchase',
+ })
+
+ cls.tax_5 = cls.env['account.tax'].create({
+ 'name': 'tax_5',
+ 'amount_type': 'percent',
+ 'amount': 5,
+ 'type_tax_use': 'sale',
+ })
+
+ cls.tax_5_incl = cls.env['account.tax'].create({
+ 'name': 'tax_5_incl',
+ 'amount_type': 'percent',
+ 'amount': 5,
+ 'type_tax_use': 'sale',
+ 'price_include': True,
+ })
+
+ @classmethod
+ def setup_company_data(cls, company_name, chart_template):
+ # OVERRIDE
+ # to force the company to be french
+ res = super().setup_company_data(
+ company_name,
+ chart_template=chart_template,
+ country_id=cls.env.ref("base.fr").id,
+ phone='+1 (650) 555-0111', # [BR-DE-6] "Seller contact telephone number" (BT-42) is required
+ email="info@yourcompany.com", # [BR-DE-7] The element "Seller contact email address" (BT-43) is required
+ )
+ return res
+
+ ####################################################
+ # Test export - import
+ ####################################################
+
+ def test_export_pdf(self):
+ acc_bank = self.env['res.partner.bank'].create({
+ 'acc_number': 'FR15001559627231',
+ 'partner_id': self.company_data['company'].partner_id.id,
+ })
+ invoice = self.env['account.move'].create({
+ 'move_type': 'out_invoice',
+ 'journal_id': self.journal.id,
+ 'partner_id': self.partner_1.id,
+ 'partner_bank_id': acc_bank,
+ 'invoice_date': '2017-01-01',
+ 'date': '2017-01-01',
+ 'currency_id': self.currency_data['currency'].id,
+ 'invoice_line_ids': [(0, 0, {
+ 'product_id': self.product_a.id,
+ 'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
+ 'price_unit': 275.0,
+ 'quantity': 5,
+ 'discount': 20.0,
+ 'tax_ids': [(6, 0, self.tax_21.ids)],
+ })],
+ })
+ invoice.action_post()
+ pdf_attachment = invoice._get_edi_attachment(self.edi_format)
+ self.assertEqual(pdf_attachment['name'], 'factur-x.xml')
+
+ def test_export_import_invoice(self):
+ invoice = self._generate_move(
+ self.partner_1,
+ self.partner_2,
+ move_type='out_invoice',
+ invoice_line_ids=[
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 2.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
+ 'price_unit': 990.0,
+ 'discount': 10.0,
+ 'tax_ids': [(6, 0, self.tax_21.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': 10.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_12.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': -1.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_12.ids)],
+ },
+ ],
+ )
+ xml_etree, xml_filename = self._assert_invoice_attachment(
+ invoice,
+ xpaths='''
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+ ''',
+ expected_file='from_flectra/facturx_out_invoice.xml',
+ )
+ self.assertEqual(xml_filename, "factur-x.xml")
+ self._assert_imported_invoice_from_etree(invoice, xml_etree, xml_filename)
+
+ def test_export_import_refund(self):
+ refund = self._generate_move(
+ self.partner_1,
+ self.partner_2,
+ move_type='out_refund',
+ invoice_line_ids=[
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 2.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
+ 'price_unit': 990.0,
+ 'discount': 10.0,
+ 'tax_ids': [(6, 0, self.tax_21.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': 10.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_12.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': -1.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_12.ids)],
+ },
+ ],
+ )
+ xml_etree, xml_filename = self._assert_invoice_attachment(
+ refund,
+ xpaths='''
+
+ ___ignore___
+
+
+ ___ignore___
+
+ ''',
+ expected_file='from_flectra/facturx_out_refund.xml'
+ )
+ self.assertEqual(xml_filename, "factur-x.xml")
+ self._assert_imported_invoice_from_etree(refund, xml_etree, xml_filename)
+
+ def test_export_tax_included(self):
+ """
+ Tests whether the tax included price_units are correctly converted to tax excluded
+ amounts in the exported xml
+ """
+ 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': 100,
+ 'tax_ids': [(6, 0, self.tax_5_incl.ids)],
+ },
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 1,
+ 'price_unit': 100,
+ 'tax_ids': [(6, 0, self.tax_5.ids)],
+ },
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 1,
+ 'price_unit': 200,
+ 'discount': 10,
+ 'tax_ids': [(6, 0, self.tax_5_incl.ids)],
+ },
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 1,
+ 'price_unit': 200,
+ 'discount': 10,
+ 'tax_ids': [(6, 0, self.tax_5.ids)],
+ },
+ ],
+ )
+ self._assert_invoice_attachment(
+ invoice,
+ xpaths='''
+
+ ___ignore___
+
+
+ ___ignore___
+
+ ''',
+ expected_file='from_flectra/facturx_out_invoice_tax_incl.xml'
+ )
+
+ 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_flectra/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_flectra/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_flectra/facturx_ecotaxes_case3.xml')
+
+ ####################################################
+ # Test import
+ ####################################################
+
+ def test_import_partner_facturx(self):
+ """
+ Given an invoice where partner_1 is the vendor and partner_2 is the customer with an EDI attachment.
+ * Uploading the attachment as an invoice should create an invoice with the buyer = partner_2.
+ * Uploading the attachment as a vendor bill should create a bill with the vendor = partner_1.
+ """
+ invoice = self._generate_move(
+ seller=self.partner_1,
+ buyer=self.partner_2,
+ move_type='out_invoice',
+ invoice_line_ids=[{'product_id': self.product_a.id}],
+ )
+ new_invoice = self._import_invoice_attachment(invoice, 'facturx_1_0_05', self.company_data['default_journal_sale'])
+ self.assertEqual(self.partner_2, new_invoice.partner_id)
+
+ new_invoice = self._import_invoice_attachment(invoice, 'facturx_1_0_05', self.company_data['default_journal_purchase'])
+ self.assertEqual(self.partner_1, new_invoice.partner_id)
+
+ def test_import_and_create_partner_facturx(self):
+ """ Tests whether the partner is created at import if no match is found when decoding the EDI attachment
+ """
+ partner_vals = {
+ 'name': "Buyer",
+ 'mail': "buyer@yahoo.com",
+ 'phone': "1111",
+ 'vat': "2222",
+ }
+ # assert there is no matching partner
+ partner_match = self.env['account.edi.format']._retrieve_partner(**partner_vals)
+ self.assertFalse(partner_match)
+
+ # Import attachment as an invoice
+ invoice = self.env['account.move'].create({
+ 'move_type': 'out_invoice',
+ 'journal_id': self.company_data['default_journal_sale'].id,
+ })
+ self.update_invoice_from_file(
+ module_name='l10n_account_edi_ubl_cii_tests',
+ subfolder='tests/test_files/from_flectra',
+ filename='facturx_test_import_partner.xml',
+ invoice=invoice)
+
+ # assert a new partner has been created
+ partner_vals['email'] = partner_vals.pop('mail')
+ self.assertRecordValues(invoice.partner_id, [partner_vals])
+
+ def test_import_tax_included(self):
+ """
+ Tests whether the tax included / tax excluded are correctly decoded when
+ importing a document. The imported xml represents the following invoice:
+
+ Description Quantity Unit Price Disc (%) Taxes Amount
+ --------------------------------------------------------------------------------
+ Product A 1 100 0 5% (incl) 95.24
+ Product A 1 100 0 5% (not incl) 100
+ Product A 2 200 10 5% (incl) 171.43
+ Product A 2 200 10 5% (not incl) 180
+ -----------------------
+ Untaxed Amount: 546.67
+ Taxes: 27.334
+ -----------------------
+ Total: 574.004
+ """
+ self._assert_imported_invoice_from_file(
+ subfolder='tests/test_files/from_flectra',
+ filename='facturx_out_invoice_tax_incl.xml',
+ amount_total=574.004,
+ amount_tax=27.334,
+ list_line_subtotals=[95.24, 100, 171.43, 180],
+ # /!\ The price_unit are different for taxes with price_include, because all amounts in Factur-X should be
+ # tax excluded. At import, the tax included amounts are thus converted into tax excluded ones.
+ # Yet, the line subtotals and total will be the same (if an equivalent tax exist with price_include = False)
+ list_line_price_unit=[95.24, 100, 190.48, 200],
+ list_line_discount=[0, 0, 10, 10],
+ # Again, all taxes in the imported invoice are price_include = False
+ list_line_taxes=[self.tax_5_purchase]*4,
+ move_type='in_invoice',
+ currency_id=self.env['res.currency'].search([('name', '=', 'USD')], limit=1).id,
+ )
+
+ def test_import_fnfe_examples(self):
+ # Source: official documentation of the FNFE (subdirectory: "5. FACTUR-X 1.0.06 - Examples")
+ subfolder = 'tests/test_files/from_factur-x_doc'
+ # the 2 following files have the same pdf but one is labelled as an invoice and the other as a refund
+ # source: Avoir_FR_type380_EN16931.pdf
+ self._assert_imported_invoice_from_file(subfolder=subfolder, filename='facturx_credit_note_type380.xml',
+ amount_total=233.47, amount_tax=14.99, list_line_subtotals=[20.48, 198], move_type='in_refund')
+ # source: Avoir_FR_type381_EN16931.pdf
+ self._assert_imported_invoice_from_file(subfolder=subfolder, filename='facturx_credit_note_type381.xml',
+ amount_total=233.47, amount_tax=14.99, list_line_subtotals=[20.48, 198], move_type='in_refund')
+ # source: Facture_F20220024_EN_16931_basis_quantity, basis quantity != 1 for one of the lines
+ self._assert_imported_invoice_from_file(subfolder=subfolder, filename='facturx_invoice_basis_quantity.xml',
+ amount_total=108, amount_tax=8, list_line_subtotals=[-5, 10, 60, 28, 7])
+ # 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_flectra"
+ 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
new file mode 100644
index 0000000000..5d24e5c281
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py
@@ -0,0 +1,484 @@
+# -*- coding: utf-8 -*-
+from flectra.addons.l10n_account_edi_ubl_cii_tests.tests.common import TestUBLCommon
+from flectra.tests import tagged
+import base64
+
+@tagged('post_install_l10n', 'post_install', '-at_install')
+class TestUBLBE(TestUBLCommon):
+
+ @classmethod
+ def setUpClass(cls,
+ chart_template_ref="l10n_be.l10nbe_chart_template",
+ edi_format_ref="account_edi_ubl_cii.ubl_bis3",
+ ):
+ super().setUpClass(chart_template_ref=chart_template_ref, edi_format_ref=edi_format_ref)
+
+ # seller
+ cls.partner_1 = cls.env['res.partner'].create({
+ 'name': "partner_1",
+ 'street': "Chaussée de Namur 40",
+ 'zip': "1367",
+ 'city': "Ramillies",
+ 'vat': 'BE0202239951',
+ 'country_id': cls.env.ref('base.be').id,
+ 'bank_ids': [(0, 0, {'acc_number': 'BE15001559627230'})],
+ 'ref': 'ref_partner_1',
+ })
+
+ # buyer
+ cls.partner_2 = cls.env['res.partner'].create({
+ 'name': "partner_2",
+ 'street': "Rue des Bourlottes 9",
+ 'zip': "1367",
+ 'city': "Ramillies",
+ 'vat': 'BE0477472701',
+ 'country_id': cls.env.ref('base.be').id,
+ 'bank_ids': [(0, 0, {'acc_number': 'BE90735788866632'})],
+ 'ref': 'ref_partner_2',
+ })
+
+ cls.tax_25 = cls.env['account.tax'].create({
+ 'name': 'tax_25',
+ 'amount_type': 'percent',
+ 'amount': 25,
+ 'type_tax_use': 'purchase',
+ })
+
+ cls.tax_21 = cls.env['account.tax'].create({
+ 'name': 'tax_21',
+ 'amount_type': 'percent',
+ 'amount': 21,
+ 'type_tax_use': 'sale',
+ 'sequence': 10,
+ })
+
+ cls.tax_15 = cls.env['account.tax'].create({
+ 'name': 'tax_15',
+ 'amount_type': 'percent',
+ 'amount': 15,
+ 'type_tax_use': 'sale',
+ })
+
+ cls.tax_12 = cls.env['account.tax'].create({
+ 'name': 'tax_12',
+ 'amount_type': 'percent',
+ 'amount': 12,
+ 'type_tax_use': 'sale',
+ })
+
+ cls.acc_bank = cls.env['res.partner.bank'].create({
+ 'acc_number': 'BE15001559627231',
+ 'partner_id': cls.company_data['company'].partner_id.id,
+ })
+
+ cls.invoice = cls.env['account.move'].create({
+ 'move_type': 'out_invoice',
+ 'journal_id': cls.journal.id,
+ 'partner_id': cls.partner_1.id,
+ 'partner_bank_id': cls.acc_bank,
+ 'invoice_date': '2017-01-01',
+ 'date': '2017-01-01',
+ 'currency_id': cls.currency_data['currency'].id,
+ 'invoice_line_ids': [(0, 0, {
+ 'product_id': cls.product_a.id,
+ 'product_uom_id': cls.env.ref('uom.product_uom_dozen').id,
+ 'price_unit': 275.0,
+ 'quantity': 5,
+ 'discount': 20.0,
+ 'tax_ids': [(6, 0, cls.tax_21.ids)],
+ })],
+ })
+
+ @classmethod
+ def setup_company_data(cls, company_name, chart_template):
+ # OVERRIDE
+ # to force the company to be belgian
+ res = super().setup_company_data(
+ company_name,
+ chart_template=chart_template,
+ country_id=cls.env.ref("base.be").id,
+ vat="BE0246697724")
+ return res
+
+ ####################################################
+ # Test export - import
+ ####################################################
+
+ def test_export_import_invoice(self):
+ invoice = self._generate_move(
+ self.partner_1,
+ self.partner_2,
+ move_type='out_invoice',
+ invoice_line_ids=[
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 2.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
+ 'price_unit': 990.0,
+ 'discount': 10.0,
+ 'tax_ids': [(6, 0, self.tax_21.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': 10.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_12.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': -1.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_12.ids)],
+ },
+ ],
+ )
+ xml_etree, xml_filename = self._assert_invoice_attachment(
+ invoice,
+ xpaths='''
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+ ''',
+ expected_file='from_flectra/bis3_out_invoice.xml',
+ )
+ self.assertEqual(xml_filename[-12:], "ubl_bis3.xml") # ensure we test the right format !
+ self._assert_imported_invoice_from_etree(invoice, xml_etree, xml_filename)
+
+ def test_export_import_refund(self):
+ refund = self._generate_move(
+ self.partner_1,
+ self.partner_2,
+ move_type='out_refund',
+ invoice_line_ids=[
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 2.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
+ 'price_unit': 990.0,
+ 'discount': 10.0,
+ 'tax_ids': [(6, 0, self.tax_21.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': 10.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_12.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': -1.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_12.ids)],
+ },
+ ],
+ )
+ xml_etree, xml_filename = self._assert_invoice_attachment(
+ refund,
+ xpaths='''
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+ ''',
+ expected_file='from_flectra/bis3_out_refund.xml',
+ )
+ self.assertEqual(xml_filename[-12:], "ubl_bis3.xml")
+ self._assert_imported_invoice_from_etree(refund, xml_etree, xml_filename)
+
+ def test_encoding_in_attachment_ubl(self):
+ self._test_encoding_in_attachment('ubl_bis3', 'INV_2017_01_0002_ubl_bis3.xml')
+
+ def test_sending_to_public_admin(self):
+ """ A public administration has no VAT, but has an arbitrary number (see:
+ https://pch.gouvernement.lu/fr/peppol.html). When a partner has no VAT, the node PartyTaxScheme should
+ not appear.
+ NB: The `EndpointID` node should be filled with this arbitrary number, that is why `l10n_lu_peppol_id`
+ module was created. However we cannot use it here because it would require adding it to the dependencies of
+ `l10n_account_edi_ubl_cii_tests` in stable.
+ """
+ self.partner_2.vat = None
+ invoice = self._generate_move(
+ self.partner_1,
+ self.partner_2,
+ move_type='out_invoice',
+ invoice_line_ids=[
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 2,
+ 'price_unit': 100,
+ 'tax_ids': [(6, 0, self.tax_21.ids)],
+ }
+ ],
+ )
+ self._assert_invoice_attachment(
+ invoice,
+ xpaths='''
+
+ ___ignore___
+
+
+ ___ignore___
+
+ ''',
+ expected_file='from_flectra/bis3_out_invoice_public_admin.xml',
+ )
+
+ def test_rounding_price_unit(self):
+ """ OpenPeppol states that:
+ * All document level amounts shall be rounded to two decimals for accounting
+ * Invoice line net amount shall be rounded to two decimals
+ See: https://docs.peppol.eu/poacc/billing/3.0/bis/#_rounding
+ Do not round the unit prices. It allows to obtain the correct line amounts when prices have more than 2
+ digits.
+ """
+ # Set the allowed number of digits for the price_unit
+ decimal_precision = self.env['decimal.precision'].search([('name', '=', 'Product Price')], limit=1)
+ self.assertTrue(bool(decimal_precision), "The decimal precision for Product Price is required for this test")
+ decimal_precision.digits = 4
+
+ invoice = self._generate_move(
+ self.partner_1,
+ self.partner_2,
+ move_type='out_invoice',
+ invoice_line_ids=[
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 10000,
+ 'price_unit': 0.4567,
+ 'tax_ids': [(6, 0, self.tax_21.ids)],
+ }
+ ],
+ )
+ self._assert_invoice_attachment(invoice, None, 'from_flectra/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_flectra/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_flectra/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_flectra/bis3_ecotaxes_case3.xml')
+
+ ####################################################
+ # Test import
+ ####################################################
+
+ def test_import_partner_ubl(self):
+ """
+ Given an invoice where partner_1 is the vendor and partner_2 is the customer with an EDI attachment.
+ * Uploading the attachment as an invoice should create an invoice with the buyer = partner_2.
+ * Uploading the attachment as a vendor bill should create a bill with the vendor = partner_1.
+ """
+ invoice = self._generate_move(
+ seller=self.partner_1,
+ buyer=self.partner_2,
+ move_type='out_invoice',
+ invoice_line_ids=[{'product_id': self.product_a.id}],
+ )
+ new_invoice = self._import_invoice_attachment(invoice, 'ubl_bis3', self.company_data['default_journal_sale'])
+ self.assertEqual(self.partner_2, new_invoice.partner_id)
+
+ new_invoice = self._import_invoice_attachment(invoice, 'ubl_bis3', self.company_data['default_journal_purchase'])
+ self.assertEqual(self.partner_1, new_invoice.partner_id)
+
+ def test_import_and_create_partner_ubl(self):
+ """ Tests whether the partner is created at import if no match is found when decoding the EDI attachment
+ """
+ partner_vals = {
+ 'name': "Buyer",
+ 'mail': "buyer@yahoo.com",
+ 'phone': "1111",
+ 'vat': "2222",
+ }
+ # assert there is no matching partner
+ partner_match = self.env['account.edi.format']._retrieve_partner(**partner_vals)
+ self.assertFalse(partner_match)
+
+ # Import attachment as an invoice
+ invoice = self.env['account.move'].create({
+ 'move_type': 'out_invoice',
+ 'journal_id': self.company_data['default_journal_sale'].id,
+ })
+ self.update_invoice_from_file(
+ module_name='l10n_account_edi_ubl_cii_tests',
+ subfolder='tests/test_files/from_flectra',
+ filename='ubl_test_import_partner.xml',
+ invoice=invoice)
+
+ # assert a new partner has been created
+ partner_vals['email'] = partner_vals.pop('mail')
+ self.assertRecordValues(invoice.partner_id, [partner_vals])
+
+ def test_import_export_invoice_xml(self):
+ """
+ Test whether the elements only specific to ubl_be are correctly exported
+ and imported in the xml file
+ """
+ self.invoice.action_post()
+ attachment = self.invoice._get_edi_attachment(self.edi_format)
+ self.assertTrue(attachment)
+ xml_content = base64.b64decode(attachment.with_context(bin_size=False).datas)
+ xml_etree = self.get_xml_tree_from_string(xml_content)
+
+ self.assertEqual(
+ xml_etree.find('{*}ProfileID').text,
+ 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0'
+ )
+ self.assertEqual(
+ xml_etree.find('{*}CustomizationID').text,
+ 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0'
+ )
+ # Export: in bis3, under Country, the Name element should not appear, but IdentificationCode still should
+ self.assertIsNotNone(xml_etree.find('.//{*}Country/{*}IdentificationCode'))
+ self.assertIsNone(xml_etree.find('.//{*}Country/{*}Name'))
+
+ # Import:
+ created_bill = self.env['account.move'].create({'move_type': 'in_invoice'})
+ created_bill.message_post(attachment_ids=[attachment.id])
+ self.assertTrue(created_bill)
+
+ def test_import_invoice_xml(self):
+ kwargs = {
+ 'subfolder': 'tests/test_files/from_flectra',
+ 'amount_total': 3164.22,
+ 'amount_tax': 482.22,
+ 'list_line_subtotals': [1782, 1000, -100],
+ 'list_line_price_unit': [990, 100, 100],
+ 'list_line_discount': [10, 0, 0],
+ 'currency_id': self.currency_data['currency'].id,
+ }
+ self._assert_imported_invoice_from_file(filename='bis3_out_invoice.xml', **kwargs)
+ # same as the file above, but the are missing in the invoice lines
+ self._assert_imported_invoice_from_file(filename='bis3_out_invoice_no_prices.xml', **kwargs)
+
+ def test_import_invoice_xml_open_peppol_examples(self):
+ # Source: https://github.com/OpenPEPPOL/peppol-bis-invoice-3/tree/master/rules/examples
+ subfolder = 'tests/test_files/from_peppol-bis-invoice-3_doc'
+ # source: Allowance-example.xml
+ self._assert_imported_invoice_from_file(subfolder=subfolder, filename='bis3_allowance.xml', amount_total=7125,
+ amount_tax=1225, list_line_subtotals=[200, -200, 4000, 1000, 900])
+ # source: base-creditnote-correction.xml
+ self._assert_imported_invoice_from_file(subfolder=subfolder, filename='bis3_credit_note.xml',
+ amount_total=1656.25, amount_tax=331.25, list_line_subtotals=[25, 2800, -1500], move_type='in_refund')
+ # source: base-negative-inv-correction.xml
+ self._assert_imported_invoice_from_file(subfolder=subfolder, filename='bis3_invoice_negative_amounts.xml',
+ amount_total=1656.25, amount_tax=331.25, list_line_subtotals=[25, 2800, -1500], move_type='in_refund')
+ # source: vat-category-E.xml
+ self._assert_imported_invoice_from_file(subfolder=subfolder, filename='bis3_tax_exempt_gbp.xml',
+ amount_total=1200, amount_tax=0, list_line_subtotals=[1200], currency_id=self.env.ref('base.GBP').id)
+
+ def test_import_existing_invoice_flip_move_type(self):
+ """ Tests whether the move_type of an existing invoice can be flipped when importing an attachment
+ For instance: with an email alias to create account_move, first the move is created (using alias_defaults,
+ which contains move_type = 'out_invoice') then the attachment is decoded, if it represents a credit note,
+ the move type needs to be changed to 'out_refund'
+ """
+ invoice = self.env['account.move'].create({'move_type': 'out_invoice'})
+ self.update_invoice_from_file(
+ 'l10n_account_edi_ubl_cii_tests',
+ 'tests/test_files/from_flectra',
+ 'bis3_out_refund.xml',
+ 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_flectra"
+ # 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',
+ )
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_de.py b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_de.py
new file mode 100644
index 0000000000..b51439e352
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_de.py
@@ -0,0 +1,232 @@
+# -*- coding: utf-8 -*-
+from flectra.addons.l10n_account_edi_ubl_cii_tests.tests.common import TestUBLCommon
+from flectra.tests import tagged
+import base64
+
+
+@tagged('post_install_l10n', 'post_install', '-at_install')
+class TestUBLDE(TestUBLCommon):
+
+ @classmethod
+ def setUpClass(cls,
+ chart_template_ref="l10n_de_skr03.l10n_de_chart_template",
+ edi_format_ref="account_edi_ubl_cii.ubl_de",
+ ):
+ super().setUpClass(chart_template_ref=chart_template_ref, edi_format_ref=edi_format_ref)
+
+ cls.partner_1 = cls.env['res.partner'].create({
+ 'name': "partner_1",
+ 'street': "Legoland-Allee 3",
+ 'zip': "89312",
+ 'city': "Günzburg",
+ 'vat': 'DE257486969',
+ 'phone': '+49 180 6 225789',
+ 'email': 'info@legoland.de',
+ 'country_id': cls.env.ref('base.de').id,
+ 'bank_ids': [(0, 0, {'acc_number': 'DE48500105176424548921'})],
+ 'ref': 'ref_partner_1',
+ })
+
+ cls.partner_2 = cls.env['res.partner'].create({
+ 'name': "partner_2",
+ 'street': "Europa-Park-Straße 2",
+ 'zip': "77977",
+ 'city': "Rust",
+ 'vat': 'DE186775212',
+ 'country_id': cls.env.ref('base.de').id,
+ 'bank_ids': [(0, 0, {'acc_number': 'DE50500105175653254743'})],
+ 'ref': 'ref_partner_2',
+ })
+
+ cls.tax_19 = cls.env['account.tax'].create({
+ 'name': 'tax_19',
+ 'amount_type': 'percent',
+ 'amount': 19,
+ 'type_tax_use': 'sale',
+ })
+
+ cls.tax_7 = cls.env['account.tax'].create({
+ 'name': 'tax_7',
+ 'amount_type': 'percent',
+ 'amount': 7,
+ 'type_tax_use': 'sale',
+ })
+
+ @classmethod
+ def setup_company_data(cls, company_name, chart_template):
+ # OVERRIDE
+ # to force the company to be german + add phone and email
+ res = super().setup_company_data(
+ company_name,
+ chart_template=chart_template,
+ country_id=cls.env.ref("base.de").id,
+ phone="+49(0) 30 227-0",
+ email="test@xrechnung@com",
+ )
+ return res
+
+ ####################################################
+ # Test export - import
+ ####################################################
+
+ def test_export_import_invoice(self):
+ invoice = self._generate_move(
+ self.partner_1,
+ self.partner_2,
+ move_type='out_invoice',
+ invoice_line_ids=[
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 2.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
+ 'price_unit': 990.0,
+ 'discount': 10.0,
+ 'tax_ids': [(6, 0, self.tax_19.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': 10.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_7.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': -1.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_7.ids)],
+ },
+ ],
+ )
+ xml_etree, xml_filename = self._assert_invoice_attachment(
+ invoice,
+ xpaths='''
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+ ''',
+ expected_file='from_flectra/xrechnung_ubl_out_invoice.xml',
+ )
+ self.assertEqual(xml_filename[-10:], "ubl_de.xml")
+ self._assert_imported_invoice_from_etree(invoice, xml_etree, xml_filename)
+
+ def test_export_import_refund(self):
+ refund = self._generate_move(
+ self.partner_1,
+ self.partner_2,
+ move_type='out_refund',
+ invoice_line_ids=[
+ {
+ 'product_id': self.product_a.id,
+ 'quantity': 2.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
+ 'price_unit': 990.0,
+ 'discount': 10.0,
+ 'tax_ids': [(6, 0, self.tax_19.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': 10.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_7.ids)],
+ },
+ {
+ 'product_id': self.product_b.id,
+ 'quantity': -1.0,
+ 'product_uom_id': self.env.ref('uom.product_uom_unit').id,
+ 'price_unit': 100.0,
+ 'tax_ids': [(6, 0, self.tax_7.ids)],
+ },
+ ],
+ )
+ xml_etree, xml_filename = self._assert_invoice_attachment(
+ refund,
+ xpaths='''
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+
+ ___ignore___
+
+ ''',
+ expected_file='from_flectra/xrechnung_ubl_out_refund.xml',
+ )
+ self.assertEqual(xml_filename[-10:], "ubl_de.xml")
+ self._assert_imported_invoice_from_etree(refund, xml_etree, xml_filename)
+
+ ####################################################
+ # Test import
+ ####################################################
+
+ def test_import_invoice_xml(self):
+ self._assert_imported_invoice_from_file(subfolder='tests/test_files/from_flectra',
+ filename='xrechnung_ubl_out_invoice.xml', amount_total=3083.58, amount_tax=401.58,
+ list_line_subtotals=[1782, 1000, -100], currency_id=self.currency_data['currency'].id)
+
+ def test_import_export_invoice_xml(self):
+ """
+ Test whether the elements which are only specific to ubl_de are correctly exported
+ and imported in the xml file
+ """
+ acc_bank = self.env['res.partner.bank'].create({
+ 'acc_number': 'BE15001559627232',
+ 'partner_id': self.company_data['company'].partner_id.id,
+ })
+ invoice = self.env['account.move'].create({
+ 'move_type': 'out_invoice',
+ 'journal_id': self.journal.id,
+ 'partner_id': self.partner_1.id,
+ 'partner_bank_id': acc_bank,
+ 'invoice_date': '2017-01-01',
+ 'date': '2017-01-01',
+ 'currency_id': self.currency_data['currency'].id,
+ 'invoice_line_ids': [(0, 0, {
+ 'product_id': self.product_a.id,
+ 'product_uom_id': self.env.ref('uom.product_uom_dozen').id,
+ 'price_unit': 275.0,
+ 'quantity': 5,
+ 'discount': 20.0,
+ 'tax_ids': [(6, 0, self.tax_19.ids)],
+ })],
+ })
+
+ partner = invoice.commercial_partner_id
+ invoice.action_post()
+ attachment = invoice._get_edi_attachment(self.edi_format)
+ self.assertTrue(attachment)
+ xml_content = base64.b64decode(attachment.with_context(bin_size=False).datas)
+ xml_etree = self.get_xml_tree_from_string(xml_content)
+
+ # Export: BuyerReference is in the out_invoice xml
+ self.assertEqual(xml_etree.find('{*}BuyerReference').text, partner.ref)
+ self.assertEqual(
+ xml_etree.find('{*}CustomizationID').text,
+ 'urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2#conformant#urn:xoev-de:kosit:extension:xrechnung_2.2'
+ )
+
+ created_bill = self.env['account.move'].create({'move_type': 'in_invoice'})
+ created_bill.message_post(attachment_ids=[attachment.id])
+ self.assertTrue(created_bill)
diff --git a/addons/l10n_dz/__init__.py b/addons/l10n_dz/__init__.py
old mode 100644
new mode 100755
diff --git a/addons/l10n_dz/__manifest__.py b/addons/l10n_dz/__manifest__.py
old mode 100644
new mode 100755
diff --git a/addons/l10n_dz/i18n/ar.po b/addons/l10n_dz/i18n/ar.po
new file mode 100644
index 0000000000..50c9b62813
--- /dev/null
+++ b/addons/l10n_dz/i18n/ar.po
@@ -0,0 +1,35 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_dz
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-11-29 13:57+0000\n"
+"PO-Revision-Date: 2022-11-29 13:57+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_dz
+#: model_terms:ir.ui.view,arch_db:l10n_dz.invoice_report_amount_in_words_inherit
+msgid "Arranged the present invoice in the amount of :"
+msgstr "رتبت هذه الفاتورة بمبلغ: "
+
+#. module: l10n_dz
+#: model:ir.model.fields,field_description:l10n_dz.field_account_bank_statement_line__amount_sentence
+#: model:ir.model.fields,field_description:l10n_dz.field_account_move__amount_sentence
+#: model:ir.model.fields,field_description:l10n_dz.field_account_payment__amount_sentence
+msgid "Arranged the present invoice in the amount of : "
+msgstr "رتبت هذه الفاتورة بمبلغ: "
+
+#. module: l10n_dz
+#: model:ir.model.fields,help:l10n_dz.field_account_bank_statement_line__amount_sentence
+#: model:ir.model.fields,help:l10n_dz.field_account_move__amount_sentence
+#: model:ir.model.fields,help:l10n_dz.field_account_payment__amount_sentence
+msgid "The amount is automatically generated by the software"
+msgstr "يتم إنشاء المبلغ تلقائيًا بواسطة البرنامج"
diff --git a/addons/l10n_dz/i18n/fr.po b/addons/l10n_dz/i18n/fr.po
new file mode 100644
index 0000000000..ad22047c9d
--- /dev/null
+++ b/addons/l10n_dz/i18n/fr.po
@@ -0,0 +1,35 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_dz
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-11-29 13:57+0000\n"
+"PO-Revision-Date: 2022-11-29 13:57+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_dz
+#: model_terms:ir.ui.view,arch_db:l10n_dz.invoice_report_amount_in_words_inherit
+msgid "Arranged the present invoice in the amount of :"
+msgstr "Arrêtée la présente facture à la somme de : "
+
+#. module: l10n_dz
+#: model:ir.model.fields,field_description:l10n_dz.field_account_bank_statement_line__amount_sentence
+#: model:ir.model.fields,field_description:l10n_dz.field_account_move__amount_sentence
+#: model:ir.model.fields,field_description:l10n_dz.field_account_payment__amount_sentence
+msgid "Arranged the present invoice in the amount of : "
+msgstr "Arrêtée la présente facture à la somme de : "
+
+#. module: l10n_dz
+#: model:ir.model.fields,help:l10n_dz.field_account_bank_statement_line__amount_sentence
+#: model:ir.model.fields,help:l10n_dz.field_account_move__amount_sentence
+#: model:ir.model.fields,help:l10n_dz.field_account_payment__amount_sentence
+msgid "The amount is automatically generated by the software"
+msgstr "Le montant est automatiquement généré par le programme"
diff --git a/addons/l10n_dz/i18n/l10n_dz.pot b/addons/l10n_dz/i18n/l10n_dz.pot
new file mode 100644
index 0000000000..18f788471e
--- /dev/null
+++ b/addons/l10n_dz/i18n/l10n_dz.pot
@@ -0,0 +1,35 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_dz
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-11-29 14:39+0000\n"
+"PO-Revision-Date: 2022-11-29 14:39+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_dz
+#: model_terms:ir.ui.view,arch_db:l10n_dz.invoice_report_amount_in_words_inherit
+msgid "Arranged the present invoice in the amount of :"
+msgstr ""
+
+#. module: l10n_dz
+#: model:ir.model.fields,field_description:l10n_dz.field_account_bank_statement_line__amount_sentence
+#: model:ir.model.fields,field_description:l10n_dz.field_account_move__amount_sentence
+#: model:ir.model.fields,field_description:l10n_dz.field_account_payment__amount_sentence
+msgid "Arranged the present invoice in the amount of : "
+msgstr ""
+
+#. module: l10n_dz
+#: model:ir.model.fields,help:l10n_dz.field_account_bank_statement_line__amount_sentence
+#: model:ir.model.fields,help:l10n_dz.field_account_move__amount_sentence
+#: model:ir.model.fields,help:l10n_dz.field_account_payment__amount_sentence
+msgid "The amount is automatically generated by the software"
+msgstr ""
diff --git a/addons/l10n_fi_sale/__init__.py b/addons/l10n_fi_sale/__init__.py
new file mode 100644
index 0000000000..c9660ecfb2
--- /dev/null
+++ b/addons/l10n_fi_sale/__init__.py
@@ -0,0 +1,4 @@
+#-*- coding:utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import models
diff --git a/addons/l10n_fi_sale/__manifest__.py b/addons/l10n_fi_sale/__manifest__.py
new file mode 100644
index 0000000000..48fbe12532
--- /dev/null
+++ b/addons/l10n_fi_sale/__manifest__.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'Finland - Sale',
+ 'version': '1.0',
+ 'description': """Finland Sale""",
+ 'category': 'Localization',
+ 'depends': [
+ 'l10n_fi',
+ 'sale',
+ ],
+ 'installable': True,
+ 'application': False,
+ 'auto_install': True,
+ 'license': 'LGPL-3',
+}
diff --git a/addons/l10n_fi_sale/i18n/fi.po b/addons/l10n_fi_sale/i18n/fi.po
new file mode 100644
index 0000000000..4f1102ec88
--- /dev/null
+++ b/addons/l10n_fi_sale/i18n/fi.po
@@ -0,0 +1,27 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_fi_sale
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 13.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-04-04 12:50+0000\n"
+"PO-Revision-Date: 2022-04-04 12:50+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_fi_sale
+#: code:addons/l10n_fi_sale/models/sale.py:0
+#, python-format
+msgid "Reference must contain numeric characters"
+msgstr "Viitteen tulee sisältää numeerisia merkkejä"
+
+#. module: l10n_fi_sale
+#: model:ir.model,name:l10n_fi_sale.model_sale_order
+msgid "Sales Order"
+msgstr "Myyntitilaus"
diff --git a/addons/l10n_fi_sale/i18n/l10n_fi_sale.pot b/addons/l10n_fi_sale/i18n/l10n_fi_sale.pot
new file mode 100644
index 0000000000..1fbec34996
--- /dev/null
+++ b/addons/l10n_fi_sale/i18n/l10n_fi_sale.pot
@@ -0,0 +1,27 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_fi_sale
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 13.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-04-04 12:50+0000\n"
+"PO-Revision-Date: 2022-04-04 12:50+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_fi_sale
+#: code:addons/l10n_fi_sale/models/sale.py:0
+#, python-format
+msgid "Reference must contain numeric characters"
+msgstr ""
+
+#. module: l10n_fi_sale
+#: model:ir.model,name:l10n_fi_sale.model_sale_order
+msgid "Sales Order"
+msgstr ""
diff --git a/addons/l10n_fi_sale/models/__init__.py b/addons/l10n_fi_sale/models/__init__.py
new file mode 100644
index 0000000000..cc5d123aa4
--- /dev/null
+++ b/addons/l10n_fi_sale/models/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding:utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import sale
diff --git a/addons/l10n_fi_sale/models/sale.py b/addons/l10n_fi_sale/models/sale.py
new file mode 100644
index 0000000000..1997b61283
--- /dev/null
+++ b/addons/l10n_fi_sale/models/sale.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+import re
+from flectra import api, models, _
+from flectra.exceptions import UserError
+
+
+class SaleOrder(models.Model):
+ _inherit = "sale.order"
+
+ def write(self, values):
+ # We compute the l10n_fi/SaleOrder.reference from itself the same way
+ # we compute the l10n_fi/AccountMove.invoice_payment_ref from its name.
+ reference = values.get('reference', False)
+ if reference:
+ values['reference'] = self.compute_payment_reference_finnish(reference)
+ return super().write(values)
+
+ @api.model
+ def number2numeric(self, number):
+ so_number = re.sub(r'\D', '', number)
+ if so_number == '' or so_number is False:
+ raise UserError(_('Reference must contain numeric characters'))
+
+ # Make sure the base number is 3...19 characters long
+ if len(so_number) < 3:
+ so_number = ('11' + so_number)[-3:]
+ elif len(so_number) > 19:
+ so_number = so_number[:19]
+
+ return so_number
+
+ @api.model
+ def get_finnish_check_digit(self, base_number):
+ # Multiply digits from end to beginning with 7, 3 and 1 and
+ # calculate the sum of the products
+ total = sum((7, 3, 1)[idx % 3] * int(val) for idx, val in
+ enumerate(base_number[::-1]))
+ # Subtract the sum from the next decade. 10 = 0
+ return str((10 - (total % 10)) % 10)
+
+ @api.model
+ def compute_payment_reference_finnish(self, number):
+ # Drop all non-numeric characters
+ so_number = self.number2numeric(number)
+ # Calculate the Finnish check digit
+ check_digit = self.get_finnish_check_digit(so_number)
+ return so_number + check_digit
diff --git a/addons/l10n_fi_sale/static/description/icon.png b/addons/l10n_fi_sale/static/description/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..0d38212600315ec7e202aec242d56dee91ebc334
GIT binary patch
literal 615
zcmeAS@N?(olHy`uVBq!ia0vp^cR-kf4M<8yoo@tEY)RhkE)4%caKYZ?lYt_f1s;*b
z3=G`DAk4@xYmNj^kiEpy*OmP~rvSI0fI;6|MFs}OFP<)rAr-gY-rb++6ex1w;pZoU
zx=d!8x=bruwoLL-V08DGDVP&%(U`(yUeK_kVV85zvP*7CDqRJeTPCzW|E*^6{XBnO
zxiZjjg5ZHt=+Y^Zaxd<^XtK}je(%iZANPr$zS(_yhQn#Gh6fG>FsxwVPyoRKG71(5
z%)uuh1Hmlp9DE4e#LU7D!3PfZB15ZvYdSUt?G&W~}oQH6hO3>c*c9;Hs{QJkM|LwcwhM&LW=ReB*^TbRofM5RI
zCEZ=Mq2^ih-j%8w&1+UyMb?SULrt4m2`K^j9gDkxekT|OKm`wM{xQs~Rg!AD&VCZ4
N-qY33Wt~$(699jItfl|}
literal 0
HcmV?d00001
diff --git a/addons/l10n_fr_facturx_chorus_pro/__init__.py b/addons/l10n_fr_facturx_chorus_pro/__init__.py
new file mode 100644
index 0000000000..013872cc0d
--- /dev/null
+++ b/addons/l10n_fr_facturx_chorus_pro/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import models
diff --git a/addons/l10n_fr_facturx_chorus_pro/__manifest__.py b/addons/l10n_fr_facturx_chorus_pro/__manifest__.py
new file mode 100644
index 0000000000..bd514d9635
--- /dev/null
+++ b/addons/l10n_fr_facturx_chorus_pro/__manifest__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'France - Factur-X integration with Chorus Pro',
+ 'version': '1.0',
+ 'category': 'Accounting/Localizations/EDI',
+ 'description': """
+Add supports to fill three optional fields used when using Chorus Pro, especially when invoicing public services.
+""",
+ 'depends': [
+ 'account',
+ 'account_edi_facturx',
+ 'l10n_fr'
+ ],
+ 'data': [
+ 'views/account_move_views.xml',
+ ],
+ 'license': 'LGPL-3',
+}
diff --git a/addons/l10n_fr_facturx_chorus_pro/i18n/fr.po b/addons/l10n_fr_facturx_chorus_pro/i18n/fr.po
new file mode 100644
index 0000000000..b9f7e80eb0
--- /dev/null
+++ b/addons/l10n_fr_facturx_chorus_pro/i18n/fr.po
@@ -0,0 +1,83 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_fr_facturx_chorus_pro
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-06-07 11:33+0000\n"
+"PO-Revision-Date: 2022-06-07 11:33+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__purchase_order_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_move__purchase_order_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_payment__purchase_order_reference
+msgid "'Engagement Juridique' in Chorus PRO."
+msgstr "'Engagement Juridique' dans Chorus PRO."
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__buyer_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_move__buyer_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_payment__buyer_reference
+msgid "'Service Exécutant' in Chorus PRO."
+msgstr "'Service Exécutant' dans Chorus PRO."
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__contract_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_move__contract_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_payment__contract_reference
+msgid "'Numéro de Marché' in Chorus PRO."
+msgstr "'Numéro de Marché' dans Chorus PRO."
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__buyer_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__buyer_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_payment__buyer_reference
+msgid "Buyer reference"
+msgstr "Service Exécutant"
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model_terms:ir.ui.view,arch_db:l10n_fr_facturx_chorus_pro.view_move_form_inherit_chorus_pro
+msgid "Chorus Pro"
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__contract_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__contract_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_payment__contract_reference
+msgid "Contract Reference"
+msgstr "Numéro de Marché"
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__display_name
+msgid "Display Name"
+msgstr "Nom affiché"
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__id
+msgid "ID"
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model,name:l10n_fr_facturx_chorus_pro.model_account_move
+msgid "Journal Entry"
+msgstr "Pièce comptable"
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move____last_update
+msgid "Last Modified on"
+msgstr "Dernière modification le"
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__purchase_order_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__purchase_order_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_payment__purchase_order_reference
+msgid "Purchase order reference"
+msgstr "Engagement Juridique"
diff --git a/addons/l10n_fr_facturx_chorus_pro/i18n/l10n_fr_facturx_chorus_pro.pot b/addons/l10n_fr_facturx_chorus_pro/i18n/l10n_fr_facturx_chorus_pro.pot
new file mode 100644
index 0000000000..b402faedec
--- /dev/null
+++ b/addons/l10n_fr_facturx_chorus_pro/i18n/l10n_fr_facturx_chorus_pro.pot
@@ -0,0 +1,83 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_fr_facturx_chorus_pro
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-06-07 11:31+0000\n"
+"PO-Revision-Date: 2022-06-07 11:31+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__purchase_order_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_move__purchase_order_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_payment__purchase_order_reference
+msgid "'Engagement Juridique' in Chorus PRO."
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__buyer_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_move__buyer_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_payment__buyer_reference
+msgid "'Service Exécutant' in Chorus PRO."
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__contract_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_move__contract_reference
+#: model:ir.model.fields,help:l10n_fr_facturx_chorus_pro.field_account_payment__contract_reference
+msgid "'Numéro de Marché' in Chorus PRO."
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__buyer_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__buyer_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_payment__buyer_reference
+msgid "Buyer reference"
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model_terms:ir.ui.view,arch_db:l10n_fr_facturx_chorus_pro.view_move_form_inherit_chorus_pro
+msgid "Chorus Pro"
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__contract_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__contract_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_payment__contract_reference
+msgid "Contract Reference"
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__id
+msgid "ID"
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model,name:l10n_fr_facturx_chorus_pro.model_account_move
+msgid "Journal Entry"
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: l10n_fr_facturx_chorus_pro
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_bank_statement_line__purchase_order_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_move__purchase_order_reference
+#: model:ir.model.fields,field_description:l10n_fr_facturx_chorus_pro.field_account_payment__purchase_order_reference
+msgid "Purchase order reference"
+msgstr ""
diff --git a/addons/l10n_fr_facturx_chorus_pro/models/__init__.py b/addons/l10n_fr_facturx_chorus_pro/models/__init__.py
new file mode 100644
index 0000000000..c78cc1912f
--- /dev/null
+++ b/addons/l10n_fr_facturx_chorus_pro/models/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import account_move
diff --git a/addons/l10n_fr_facturx_chorus_pro/models/account_move.py b/addons/l10n_fr_facturx_chorus_pro/models/account_move.py
new file mode 100644
index 0000000000..6583c86255
--- /dev/null
+++ b/addons/l10n_fr_facturx_chorus_pro/models/account_move.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+from flectra import fields, models
+
+
+class AccountMove(models.Model):
+ _inherit = "account.move"
+
+ buyer_reference = fields.Char(help="'Service Exécutant' in Chorus PRO.")
+ contract_reference = fields.Char(help="'Numéro de Marché' in Chorus PRO.")
+ purchase_order_reference = fields.Char(help="'Engagement Juridique' in Chorus PRO.")
diff --git a/addons/l10n_fr_facturx_chorus_pro/views/account_move_views.xml b/addons/l10n_fr_facturx_chorus_pro/views/account_move_views.xml
new file mode 100644
index 0000000000..8974ca8cc7
--- /dev/null
+++ b/addons/l10n_fr_facturx_chorus_pro/views/account_move_views.xml
@@ -0,0 +1,19 @@
+
+
+
+
+ account.move.form.inherit.chorus.pro
+ account.move
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/l10n_it_edi/i18n/it.po b/addons/l10n_it_edi/i18n/it.po
new file mode 100644
index 0000000000..4a169fd08c
--- /dev/null
+++ b/addons/l10n_it_edi/i18n/it.po
@@ -0,0 +1,1151 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_it_edi
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-03-29 14:31+0000\n"
+"PO-Revision-Date: 2022-03-29 14:31+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s has an amount of 0.0, you must indicate the kind of exoneration."
+msgstr "%s ha valore di 0.0, devi indicare il tipo di esenzione."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid ""
+"%s isn't in a right state. It must be in a 'Not yet send' or 'Invalid' "
+"state."
+msgstr "%s non è uno stato corretto. Lo stato dev'essere 'Non ancora inviato' o 'Errato'."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a VAT number"
+msgstr "%s deve avere una Partita IVA"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a city."
+msgstr "%s deve avere una Cittá."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a codice fiscale number"
+msgstr "%s deve avere un Codice Fiscale"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a country"
+msgstr "%s deve avere una Nazione"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a country."
+msgstr "%s deve avere una Nazione."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a post code of length 5."
+msgstr "%s deve avere un CAP di lunghezza 5."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a post code."
+msgstr "%s deve avere un CAP."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a street."
+msgstr "%s deve avere un Indirizzo."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid ""
+"'Scissione dei pagamenti' is not compatible with exoneration of kind 'N6'"
+msgstr "'Scissione dei pagamenti' non è compatibile con l'esenzione di tipo 'N6'"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_company.py:0
+#, python-format
+msgid ""
+"All fields about the Economic and Administrative Index must be completed."
+msgstr "Tutti i campi che riguardano l'Indice Economico e Amministrativo devono essere completati."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Attachment from XML"
+msgstr "Allegato dall'XML"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Bank account not found, useful informations from XML file:"
+msgstr "Conto bancario non trovato, informazioni utili dal file XML:"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_codice_fiscale
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__l10n_it_codice_fiscale
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_users__l10n_it_codice_fiscale
+msgid "Codice Fiscale"
+msgstr "Codice Fiscale"
+
+#. module: l10n_it_edi
+#: model:ir.model.constraint,message:l10n_it_edi.constraint_res_partner_l10n_it_codice_fiscale
+msgid "Codice fiscale must have between 11 and 16 characters."
+msgstr "Il Codice Fiscale deve avere fra 11 e 16 caratteri."
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_res_company
+msgid "Companies"
+msgstr "Aziende"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_address_send_fatturapa
+msgid "Company PEC-mail"
+msgstr "Indirizzo PEC aziendale"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Company have a tax representative"
+msgstr "L'azienda ha un rappresentante fiscale"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Company listed on the register of companies"
+msgstr "L'azienda compare nel Registro delle Imprese"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_mail_pec_server_id
+msgid "Configure your PEC-mail server to send electronic invoices."
+msgstr "Configura il server mail PEC per inviare le Fatture Elettroniche."
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_res_partner
+msgid "Contact"
+msgstr "Contatto"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__create_uid
+msgid "Created by"
+msgstr "Creato da"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__create_date
+msgid "Created on"
+msgstr "Creato il"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_ddt_id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_ddt_id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_ddt_id
+#: model:ir.ui.menu,name:l10n_it_edi.menu_action_ddt_account
+msgid "DDT"
+msgstr "DDT"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__date
+msgid "Data DDT"
+msgstr "Data DDT"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_stamp_duty
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_stamp_duty
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_stamp_duty
+msgid "Dati Bollo"
+msgstr "Dati Bollo"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__failed_delivery
+msgid ""
+"Delivery impossible, ES certify that it has received the invoice and that "
+"the file could not be delivered to the addressee"
+msgstr "Consegna non riuscita, il SdI certifica che ha ricevuto la fattura "
+"e che non è stato possibile consegnare il file al destinatario"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_edi_format__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_ir_mail_server__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__display_name
+msgid "Display Name"
+msgstr "Nome visualizzato"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "E-Invoice is delivery to the destinatory: %s"
+msgstr "La Fattura Elettronica è stata consegnata al destinatario: %s"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "E-Invoice is generated on %s by %s"
+msgstr "La Fattura Elettronica è stata generata il %s da %s"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_line_it_FatturaPA
+msgid "EAN"
+msgstr "EAN"
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_account_edi_format
+msgid "EDI format"
+msgstr "Formato EDI"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid ""
+"ES certify that it has received the invoice and that the file"
+" could not be delivered to the addressee. %s"
+msgstr "Il SdI certifica che ha ricevuto la Fattura e che non è stato possibile "
+"consegnare il file al destinatario. %s"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Economic and Administrative Index"
+msgstr "Indice Economico e Amministrativo"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_form_l10n_it
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Electronic Invoicing"
+msgstr "Fatturazione Elettronica"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_einvoice_id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_einvoice_id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_einvoice_id
+msgid "Electronic invoice"
+msgstr "Fattura Elettronica"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_address_recipient_fatturapa
+msgid "Enter Government PEC-mail address. Ex: sdi01@pec.fatturapa.it"
+msgstr "Inserire l'indirizzo PEC statale, Es: sdi01@pec.fatturapa.it"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_address_send_fatturapa
+msgid "Enter your company PEC-mail address. Ex: yourcompany@pec.mail.it"
+msgstr "Inserire il proprio indirizzo PEC. Es: miaazienda@pec.mail.it"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Error when sending mail with E-Invoice: %s"
+msgstr "Errore nell'invio della mail con la Fattura Elettronica: %s"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid ""
+"Error when sending mail with E-Invoice: Your company must have a mail PEC "
+"server and must indicate the mail PEC that will send electronic invoice."
+msgstr "Errore nell'invio della mail con la Fattura Elettronica: la tua "
+"azienda deve avere un server email PEC e deve indicare l'indirizzo da "
+"cui spedire"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Errors in the E-Invoice : %s"
+msgstr "Errori nella Fattura Elettronica: %s"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__l10n_it_kind_exoneration
+msgid "Exoneration"
+msgstr "Esenzione"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_account_tax__l10n_it_kind_exoneration
+msgid "Exoneration type"
+msgstr "Tipo esenzione"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid ""
+"Expiration of the maximum term for communication of acceptance/refusal:"
+" %s %s"
+msgstr "Termine massimo di decorrenza per l'accettazione o il rifiuto della comunicazione:"
+" %s %s"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_send_state
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_send_state
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_send_state
+msgid "FatturaPA Send State"
+msgstr "Stato di invio della FatturaPA"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_codice_fiscale
+msgid "Fiscal code of your company"
+msgstr "Codice Fiscale dell'azienda"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_address_recipient_fatturapa
+msgid "Government PEC-mail"
+msgstr "Indirizzo PEC statale"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__l10n_it_has_exoneration
+msgid "Has exoneration of tax (Italy)"
+msgstr "Esente dalle tasse (Italia)"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_edi_format__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_ir_mail_server__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__id
+msgid "ID"
+msgstr "ID"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_line_it_FatturaPA
+msgid "INTERNAL"
+msgstr "INTERNO"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_fetchmail_server__l10n_it_is_pec
+msgid ""
+"If PEC Server, only mail from '...@pec.fatturapa.it' will be processed."
+msgstr "Se è un server PEC, solo le email da '...@pec.fatturapa.it' verranno prese in carico."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid ""
+"If the tax has exoneration, you must enter a kind of exoneration, a law "
+"reference and the amount of the tax must be 0.0."
+msgstr "Se l'Imposta risulta essere un'Esenzione, bisogna compilare il Tipo "
+"di Esenzione e il suo valore dev'essere 0.0."
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_fetchmail_server
+msgid "Incoming Mail Server"
+msgstr "Server Email in ingresso"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_partner.py:0
+#, python-format
+msgid ""
+"Invalid Codice Fiscale '%s': should be like 'MRTMTT91D08F205J' for physical "
+"person and '12345678901' or 'IT12345678901' for businesses."
+msgstr "Codice Fiscale non valido '%s': dev'essere come 'MRTMTT91D08F205J' per "
+"persone fisiche e '12345678901' o 'IT12345678901' per le aziende"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Invalid configuration:"
+msgstr "Configurazione non valida:"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__invoice_id
+msgid "Invoice Reference"
+msgstr "Riferimento Fattura"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"Invoices for PA are not managed by Odoo, you can download the document and "
+"send it on your own."
+msgstr "Le Fatture verso la PA non sono gestite da Odoo, puoi scaricare il "
+"documento ed inviarlo manualmente."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Italian invoice: %s"
+msgstr "Fattura italiana: %s"
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_account_move
+msgid "Journal Entry"
+msgstr "Movimento Contabile"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_einvoice_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_einvoice_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_einvoice_name
+msgid "L10N It Einvoice Name"
+msgstr "Nome Fattura Elettronica"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_has_eco_index
+msgid "L10N It Has Eco Index"
+msgstr "Ha indice Eco"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_has_tax_representative
+msgid "L10N It Has Tax Representative"
+msgstr "Ha rappresentante fiscale"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_edi_format____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_ir_mail_server____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner____last_update
+msgid "Last Modified on"
+msgstr "Ultima modifica il"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__write_uid
+msgid "Last Updated by"
+msgstr "Ultimo aggiornamento di"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__write_date
+msgid "Last Updated on"
+msgstr "Ultimo aggiornamento il"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server__l10n_it_last_uid
+msgid "Last message UID"
+msgstr "UID ultimo messaggio"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__l10n_it_law_reference
+msgid "Law Reference"
+msgstr "Riferimento alla Legge"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_liquidation_state
+msgid "Liquidation state"
+msgstr "Stato Liquidazione"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "MP05"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_ir_mail_server
+msgid "Mail Server"
+msgstr "Server Email"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Mail sent on %s by %s"
+msgstr "Email inviata a %s da %s"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_eco_index_share_capital
+msgid ""
+"Mandatory if the seller/provider is a company with share capital "
+"(SpA, SApA, Srl), this field must contain the amount of share capital"
+" actually paid up as resulting from the last financial statement"
+msgstr "Obbligatorio se il venditore/fornitore è una azienda con capitale "
+"sociale (SpA, SApA, Srl), rappresenta l'ammontare del capitale sociale "
+"attuale come risulta dall'ultimo rendiconto finanziario."
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_partner__l10n_it_pa_index
+#: model:ir.model.fields,help:l10n_it_edi.field_res_users__l10n_it_pa_index
+msgid ""
+"Must contain the 6-character (or 7) code, present in the PA "
+"Index in the information relative to the electronic invoicing service,"
+" associated with the office which, within the addressee "
+"administration, deals with receiving (and processing) the "
+"invoice."
+msgstr "Deve contenere il codice da 6-7 caratteri presente nell'indice della PA "
+"nelle informazioni relative al servizio di Fatturazione Elettronica, "
+"associato all'ufficio dell'amministrazione che riceverá (ed elaborerá) la Fattura."
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__new
+msgid "New"
+msgstr "Nuova"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_sole_shareholder__no
+msgid "Not a limited liability company"
+msgstr "Non è una Societá a Responsabilitá Limitata"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__to_send
+msgid "Not yet send"
+msgstr "Non ancora inviata"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_number
+msgid "Number in register of companies"
+msgstr "Numero nel Registro delle Imprese"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__name
+msgid "Numero DDT"
+msgstr "Numero DDT"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Original E-invoice XML file"
+msgstr "File XML Fattura Elettronica originale"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__other
+msgid "Other"
+msgstr "Altro"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Outcome notice: %s %s"
+msgstr "Notifica esito: %s %s"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__l10n_it_pa_index
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_users__l10n_it_pa_index
+msgid "PA index"
+msgstr "Codice univoco"
+
+#. module: l10n_it_edi
+#: model:ir.model.constraint,message:l10n_it_edi.constraint_res_partner_l10n_it_pa_index
+msgid "PA index must have between 6 and 7 characters."
+msgstr "Il codice univoco deve avere 6/7 caratteri"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "PDF"
+msgstr "PDF"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__l10n_it_pec_email
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_users__l10n_it_pec_email
+msgid "PEC e-mail"
+msgstr "Email PEC"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "PEC mail server must be of type IMAP."
+msgstr "Il server email PEC deve essere di tipo IMAP."
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server__l10n_it_is_pec
+msgid "PEC server"
+msgstr "Server PEC"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_sole_shareholder__sm
+msgid "Più soci"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Please configure Government PEC-mail\tin company settings"
+msgstr "Per favore, configurare l'email PEC statale \n"
+"nelle impostazioni della Societá"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Please configure Username for this Server PEC"
+msgstr "Per favore, configurare il Nome Utente per questo server email PEC"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_tax_system
+msgid "Please select the Tax system to which you are subjected."
+msgstr "Per favore, selezionare il Sistema Fiscale a cui si è soggetti."
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_office
+msgid "Province of the register-of-companies office"
+msgstr "Provincia dell'ufficio del Registro delle Imprese"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "SI"
+msgstr "SI"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Sending file: %s"
+msgstr "Invio file: %s"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Sending file: %s to ES: %s"
+msgstr "Invio file in corso: %s all'SdI: %s"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__invalid
+msgid "Sent, but invalid"
+msgstr "Inviata, ma non corretta"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__sent
+msgid "Sent, waiting for response"
+msgstr "Inviata, in attesa di risposta"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_mail_pec_server_id
+msgid "Server PEC"
+msgstr "Server PEC"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_share_capital
+msgid "Share capital actually paid up"
+msgstr "Capitale sociale investito"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_sole_shareholder
+msgid "Shareholder"
+msgstr "Socio"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_sole_shareholder__su
+msgid "Socio unico"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "TP01"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "TP02"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_account_tax
+msgid "Tax"
+msgstr "Imposta"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_tax_system
+msgid "Tax System"
+msgstr "Sistema Fiscale"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_account_tax__l10n_it_has_exoneration
+msgid "Tax has a tax exoneration."
+msgstr "La tassa ha un'Esenzione."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"Tax not found with percentage: %s and exoneration %s for the article: %s"
+msgstr "L'imposta con percentuale: %s e Esenzione %s per il prodotto: %s non è stata trovata."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Tax not found with percentage: %s for the article: %s"
+msgstr "L'imposta con percentuale: %s per il prodotto: %s non è stata trovata"
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Tax representative"
+msgstr "Rappresentante fiscale"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_tax_representative_partner_id
+msgid "Tax representative partner"
+msgstr "Rappresentante fiscale del partner"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Tax representative partner %s of %s must have a tax number."
+msgstr "Il rappresentante fiscale del partner %s di %s deve avere un codice fiscale."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid ""
+"The E-invoice is not delivered to the addressee. The Exchange System is"
+" unable to deliver the file to the Public Administration. The"
+" Exchange System will contact the PA to report the problem "
+"and request that they provide a solution. During the "
+"following 15 days, the Exchange System will try to forward the FatturaPA"
+" file to the Administration in question again. More "
+"information: %s"
+msgstr "La Fattura Elettronica non è stata consegnata al destinatario. "
+"Il Sistema d'Interscambio non ha potuto consegnare il file alla Pubblica "
+"Amministrazione. Il Sistema di Interscambio contatterá la PA per far presente "
+"il problema e richiedere una soluzione. Durante i successivi 15 giorni, il "
+"Sistema di Interscambio proverá a re-inoltrare la Fattura all'Amministrazione "
+"in questione: %s"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"The buyer, %s, or his company must have either a VAT number either a tax "
+"code (Codice Fiscale)."
+msgstr "L'acquirente, %s, o la sua azienda devono avere la Partita IVA "
+"o il Codice Fiscale compilato."
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_liquidation_state__ls
+msgid "The company is in a state of liquidation"
+msgstr "La compagnia è in stato di liquidazione"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_liquidation_state__ln
+msgid "The company is not in a state of liquidation"
+msgstr "La compagnia non è in stato di liquidazione"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"The maximum length for VAT number is 30. %s have a VAT number too long: %s."
+msgstr "La lunghezza minima per la Partita IVA è 30. %s ha una Partita IVA troppo lunga: %s."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "The seller must have a bank account."
+msgstr "Il venditore deve avere un conto bancario."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "The seller's company must have a tax system."
+msgstr "L'azienda del venditore deve avere specificato un Sistema Fiscale."
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid ""
+"The seller/provider is a company listed on the register of companies and as\n"
+" such must also indicate the registration data on all documents (art. 2250, Italian\n"
+" Civil Code)"
+msgstr "Il venditore/fornitore è un'azienda presente nel Registro delle Imprese\n"
+"e come tale deve indicare i dati di registrazione su tutti i documenti\n"
+"(art. 2250 del Codice Civile)"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_has_eco_index
+msgid ""
+"The seller/provider is a company listed on the register of companies and as"
+" such must also indicate the registration data on all documents (art."
+" 2250, Italian Civil Code)"
+msgstr "Il venditore/fornitore è un'azienda presente nel Registro delle Imprese"
+"e come tale deve indicare i dati di registrazione su tutti i documenti\n"
+"(art. 2250 del Codice Civile)"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_has_tax_representative
+msgid ""
+"The seller/provider is a non-resident subject which carries out "
+"transactions in Italy with relevance for VAT purposes and which takes"
+" avail of a tax representative in Italy"
+msgstr "Il venditore/fornitore è un soggetto non-residente che svolge "
+"le sue transazioni in Italia con rilevanza fiscale e che fa riferimento "
+" a un rappresentante fiscale in Italia."
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid ""
+"The seller/provider is a non-resident subject which carries out transactions in Italy\n"
+" with relevance for VAT purposes and which takes avail of a tax representative in Italy"
+msgstr "Il venditore/fornitore è un soggetto non-residente che svolge "
+"le sue transazioni in Italia con rilevanza fiscale e che fa riferimento "
+" a un rappresentante fiscale in Italia."
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_eco_index_number
+msgid ""
+"This field must contain the number under which the seller/provider is"
+" listed on the register of companies."
+msgstr "Questo campo deve contenere il numero sotto il quale è presente "
+"nel Registro delle Imprese"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__delivered
+msgid "This invoice is delivered"
+msgstr "Questa Fattura è consegnata"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__delivered_accepted
+msgid "This invoice is delivered and accepted by destinatory"
+msgstr "Questa fattura è consegnata e accettata dal destinatario"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__delivered_expired
+msgid ""
+"This invoice is delivered and expired (expiry of the maximum term for "
+"communication of acceptance/refusal)"
+msgstr "Questa fattura è consegnata e scaduta (è passato il termine "
+"massimo per la comunicazione dell'accettazione/rifiuto)"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__delivered_refused
+msgid "This invoice is delivered and refused by destinatory"
+msgstr "Questa fattura è consegnata e rifiutata dal destinatario"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Total amount from the XML File: %s"
+msgstr "Valore totale del file XML: %s"
+
+#. module: l10n_it_edi
+#: model:ir.actions.act_window,name:l10n_it_edi.action_ddt_account
+#: model:ir.model,name:l10n_it_edi.model_l10n_it_ddt
+msgid "Transport Document"
+msgstr "Documento Di Trasporto"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_l10n_it_ddt__date
+msgid "Transport document date"
+msgstr "Data Documento Di Trasporto"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_l10n_it_ddt__name
+msgid "Transport document number"
+msgstr "Numero Documento Di Trasporto"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Transport informations from XML file:"
+msgstr "Informazioni di Trasporto dal file XML:"
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__l10n_it_vat_due_date
+msgid "VAT due date"
+msgstr "Data scadenza IVA"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Vendor not found, useful informations from XML file:"
+msgstr "Fornitore non trovato, informazioni dal file XML:"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"You can't regenerate an E-Invoice when the first one is sent and there are "
+"no errors"
+msgstr "Non puoi rigenerare una Fattura Elettronica se è giá stata inviata senza errori."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_company.py:0
+#, python-format
+msgid "You must select a tax representative."
+msgstr "Devi selezionare un rappresentante fiscale"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "You must select one and only one tax by line."
+msgstr "Devi selezionare una e solo una imposta per linea."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_company.py:0
+#, python-format
+msgid "Your tax representative partner must have a country."
+msgstr "Il tuo rappresentante fiscale deve avere una Nazione."
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_company.py:0
+#, python-format
+msgid "Your tax representative partner must have a tax number."
+msgstr "Il tuo rappresentante fiscale deve avere un Codice Fiscale."
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_vat_due_date__d
+msgid "[D] IVA ad esigibilità differita"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_vat_due_date__i
+msgid "[I] IVA ad esigibilità immediata"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n1
+msgid "[N1] Escluse ex art. 15"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n2_1
+msgid ""
+"[N2.1] Non soggette ad IVA ai sensi degli artt. Da 7 a 7-septies del DPR "
+"633/72"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n2_2
+msgid "[N2.2] Non soggette – altri casi"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n2
+msgid "[N2] Non soggette"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_1
+msgid "[N3.1] Non imponibili – esportazioni"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_2
+msgid "[N3.2] Non imponibili – cessioni intracomunitarie"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_3
+msgid "[N3.3] Non imponibili – cessioni verso San Marino"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_4
+msgid ""
+"[N3.4] Non imponibili – operazioni assimilate alle cessioni all’esportazione"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_5
+msgid "[N3.5] Non imponibili – a seguito di dichiarazioni d’intento"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_6
+msgid ""
+"[N3.6] Non imponibili – altre operazioni che non concorrono alla formazione "
+"del plafond"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3
+msgid "[N3] Non imponibili"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n4
+msgid "[N4] Esenti"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n5
+msgid "[N5] Regime del margine / IVA non esposta in fattura"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_1
+msgid ""
+"[N6.1] Inversione contabile – cessione di rottami e altri materiali di "
+"recupero"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_2
+msgid "[N6.2] Inversione contabile – cessione di oro e argento puro"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_3
+msgid "[N6.3] Inversione contabile – subappalto nel settore edile"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_4
+msgid "[N6.4] Inversione contabile – cessione di fabbricati"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_5
+msgid "[N6.5] Inversione contabile – cessione di telefoni cellulari"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_6
+msgid "[N6.6] Inversione contabile – cessione di prodotti elettronici"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_7
+msgid ""
+"[N6.7] Inversione contabile – prestazioni comparto edile esettori connessi"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_8
+msgid "[N6.8] Inversione contabile – operazioni settore energetico"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_9
+msgid "[N6.9] Inversione contabile – altri casi"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6
+msgid ""
+"[N6] Inversione contabile (per le operazioni in reverse charge ovvero nei "
+"casi di autofatturazione per acquisti extra UE di servizi ovvero per "
+"importazioni di beni nei soli casi previsti)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n7
+msgid ""
+"[N7] IVA assolta in altro stato UE (vendite a distanza ex art. 40 c. 3 e 4 e"
+" art. 41 c. 1 lett. b, DL 331/93; prestazione di servizi di "
+"telecomunicazioni, tele-radiodiffusione ed elettronici ex art. 7-sexies "
+"lett. f, g, art. 74-sexies DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf01
+msgid "[RF01] Ordinario"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf02
+msgid "[RF02] Contribuenti minimi (art.1, c.96-117, L. 244/07)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf04
+msgid ""
+"[RF04] Agricoltura e attività connesse e pesca (artt.34 e 34-bis, DPR "
+"633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf05
+msgid "[RF05] Vendita sali e tabacchi (art.74, c.1, DPR. 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf06
+msgid "[RF06] Commercio fiammiferi (art.74, c.1, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf07
+msgid "[RF07] Editoria (art.74, c.1, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf08
+msgid "[RF08] Gestione servizi telefonia pubblica (art.74, c.1, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf09
+msgid ""
+"[RF09] Rivendita documenti di trasporto pubblico e di sosta (art.74, c.1, "
+"DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf10
+msgid ""
+"[RF10] Intrattenimenti, giochi e altre attività di cui alla tariffa allegata"
+" al DPR 640/72 (art.74, c.6, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf11
+msgid "[RF11] Agenzie viaggi e turismo (art.74-ter, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf12
+msgid "[RF12] Agriturismo (art.5, c.2, L. 413/91)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf13
+msgid "[RF13] Vendite a domicilio (art.25-bis, c.6, DPR 600/73)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf14
+msgid ""
+"[RF14] Rivendita beni usati, oggetti d’arte, d’antiquariato o da collezione "
+"(art.36, DL 41/95)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf15
+msgid ""
+"[RF15] Agenzie di vendite all’asta di oggetti d’arte, antiquariato o da "
+"collezione (art.40-bis, DL 41/95)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf16
+msgid "[RF16] IVA per cassa P.A. (art.6, c.5, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf17
+msgid "[RF17] IVA per cassa (art. 32-bis, DL 83/2012)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf18
+msgid "[RF18] Altro"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf19
+msgid "[RF19] Regime forfettario (art.1, c.54-89, L. 190/2014)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_vat_due_date__s
+msgid "[S] Scissione dei pagamenti"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "from XML file:"
+msgstr "dal file XML:"
diff --git a/addons/l10n_it_edi/i18n/l10n_it_edi.pot b/addons/l10n_it_edi/i18n/l10n_it_edi.pot
new file mode 100644
index 0000000000..418a8d6df1
--- /dev/null
+++ b/addons/l10n_it_edi/i18n/l10n_it_edi.pot
@@ -0,0 +1,1122 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_it_edi
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-03-29 14:31+0000\n"
+"PO-Revision-Date: 2022-03-29 14:31+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s has an amount of 0.0, you must indicate the kind of exoneration."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid ""
+"%s isn't in a right state. It must be in a 'Not yet send' or 'Invalid' "
+"state."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a VAT number"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a city."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a codice fiscale number"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a country"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a country."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a post code of length 5."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a post code."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "%s must have a street."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid ""
+"'Scissione dei pagamenti' is not compatible with exoneration of kind 'N6'"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_company.py:0
+#, python-format
+msgid ""
+"All fields about the Economic and Administrative Index must be completed."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Attachment from XML"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Bank account not found, useful informations from XML file:"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_codice_fiscale
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__l10n_it_codice_fiscale
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_users__l10n_it_codice_fiscale
+msgid "Codice Fiscale"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.constraint,message:l10n_it_edi.constraint_res_partner_l10n_it_codice_fiscale
+msgid "Codice fiscale must have between 11 and 16 characters."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_res_company
+msgid "Companies"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_address_send_fatturapa
+msgid "Company PEC-mail"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Company have a tax representative"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Company listed on the register of companies"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_mail_pec_server_id
+msgid "Configure your PEC-mail server to send electronic invoices."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_res_partner
+msgid "Contact"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__create_uid
+msgid "Created by"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__create_date
+msgid "Created on"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_ddt_id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_ddt_id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_ddt_id
+#: model:ir.ui.menu,name:l10n_it_edi.menu_action_ddt_account
+msgid "DDT"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__date
+msgid "Data DDT"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_stamp_duty
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_stamp_duty
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_stamp_duty
+msgid "Dati Bollo"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__failed_delivery
+msgid ""
+"Delivery impossible, ES certify that it has received the invoice and that "
+"the file could not be delivered to the addressee"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_edi_format__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_ir_mail_server__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__display_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "E-Invoice is delivery to the destinatory: %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "E-Invoice is generated on %s by %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_line_it_FatturaPA
+msgid "EAN"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_account_edi_format
+msgid "EDI format"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid ""
+"ES certify that it has received the invoice and that the file"
+" could not be delivered to the addressee. %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Economic and Administrative Index"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_form_l10n_it
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Electronic Invoicing"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_einvoice_id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_einvoice_id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_einvoice_id
+msgid "Electronic invoice"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_address_recipient_fatturapa
+msgid "Enter Government PEC-mail address. Ex: sdi01@pec.fatturapa.it"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_address_send_fatturapa
+msgid "Enter your company PEC-mail address. Ex: yourcompany@pec.mail.it"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Error when sending mail with E-Invoice: %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid ""
+"Error when sending mail with E-Invoice: Your company must have a mail PEC "
+"server and must indicate the mail PEC that will send electronic invoice."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Errors in the E-Invoice : %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__l10n_it_kind_exoneration
+msgid "Exoneration"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_account_tax__l10n_it_kind_exoneration
+msgid "Exoneration type"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid ""
+"Expiration of the maximum term for communication of acceptance/refusal:"
+" %s %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_send_state
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_send_state
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_send_state
+msgid "FatturaPA Send State"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_codice_fiscale
+msgid "Fiscal code of your company"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_address_recipient_fatturapa
+msgid "Government PEC-mail"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__l10n_it_has_exoneration
+msgid "Has exoneration of tax (Italy)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_edi_format__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_ir_mail_server__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__id
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__id
+msgid "ID"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_line_it_FatturaPA
+msgid "INTERNAL"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_fetchmail_server__l10n_it_is_pec
+msgid ""
+"If PEC Server, only mail from '...@pec.fatturapa.it' will be processed."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid ""
+"If the tax has exoneration, you must enter a kind of exoneration, a law "
+"reference and the amount of the tax must be 0.0."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_fetchmail_server
+msgid "Incoming Mail Server"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_partner.py:0
+#, python-format
+msgid ""
+"Invalid Codice Fiscale '%s': should be like 'MRTMTT91D08F205J' for physical "
+"person and '12345678901' or 'IT12345678901' for businesses."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Invalid configuration:"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__invoice_id
+msgid "Invoice Reference"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"Invoices for PA are not managed by Odoo, you can download the document and "
+"send it on your own."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Italian invoice: %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_account_move
+msgid "Journal Entry"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_bank_statement_line__l10n_it_einvoice_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move__l10n_it_einvoice_name
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_payment__l10n_it_einvoice_name
+msgid "L10N It Einvoice Name"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_has_eco_index
+msgid "L10N It Has Eco Index"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_has_tax_representative
+msgid "L10N It Has Tax Representative"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_edi_format____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_move____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_ir_mail_server____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company____last_update
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__write_uid
+msgid "Last Updated by"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__write_date
+msgid "Last Updated on"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server__l10n_it_last_uid
+msgid "Last message UID"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__l10n_it_law_reference
+msgid "Law Reference"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_liquidation_state
+msgid "Liquidation state"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "MP05"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_ir_mail_server
+msgid "Mail Server"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Mail sent on %s by %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_eco_index_share_capital
+msgid ""
+"Mandatory if the seller/provider is a company with share capital "
+"(SpA, SApA, Srl), this field must contain the amount of share capital"
+" actually paid up as resulting from the last financial statement"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_partner__l10n_it_pa_index
+#: model:ir.model.fields,help:l10n_it_edi.field_res_users__l10n_it_pa_index
+msgid ""
+"Must contain the 6-character (or 7) code, present in the PA "
+"Index in the information relative to the electronic invoicing service,"
+" associated with the office which, within the addressee "
+"administration, deals with receiving (and processing) the "
+"invoice."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__new
+msgid "New"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_sole_shareholder__no
+msgid "Not a limited liability company"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__to_send
+msgid "Not yet send"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_number
+msgid "Number in register of companies"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_l10n_it_ddt__name
+msgid "Numero DDT"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Original E-invoice XML file"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__other
+msgid "Other"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Outcome notice: %s %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__l10n_it_pa_index
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_users__l10n_it_pa_index
+msgid "PA index"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.constraint,message:l10n_it_edi.constraint_res_partner_l10n_it_pa_index
+msgid "PA index must have between 6 and 7 characters."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "PDF"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_partner__l10n_it_pec_email
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_users__l10n_it_pec_email
+msgid "PEC e-mail"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "PEC mail server must be of type IMAP."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_fetchmail_server__l10n_it_is_pec
+msgid "PEC server"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_sole_shareholder__sm
+msgid "Più soci"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Please configure Government PEC-mail\tin company settings"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid "Please configure Username for this Server PEC"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_tax_system
+msgid "Please select the Tax system to which you are subjected."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_office
+msgid "Province of the register-of-companies office"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "SI"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Sending file: %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_invoice.py:0
+#, python-format
+msgid "Sending file: %s to ES: %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__invalid
+msgid "Sent, but invalid"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__sent
+msgid "Sent, waiting for response"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_mail_pec_server_id
+msgid "Server PEC"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_share_capital
+msgid "Share capital actually paid up"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_eco_index_sole_shareholder
+msgid "Shareholder"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_sole_shareholder__su
+msgid "Socio unico"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "TP01"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.account_invoice_it_FatturaPA_export
+msgid "TP02"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model,name:l10n_it_edi.model_account_tax
+msgid "Tax"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_tax_system
+msgid "Tax System"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_account_tax__l10n_it_has_exoneration
+msgid "Tax has a tax exoneration."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"Tax not found with percentage: %s and exoneration %s for the article: %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Tax not found with percentage: %s for the article: %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid "Tax representative"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_res_company__l10n_it_tax_representative_partner_id
+msgid "Tax representative partner"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Tax representative partner %s of %s must have a tax number."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/ir_mail_server.py:0
+#, python-format
+msgid ""
+"The E-invoice is not delivered to the addressee. The Exchange System is"
+" unable to deliver the file to the Public Administration. The"
+" Exchange System will contact the PA to report the problem "
+"and request that they provide a solution. During the "
+"following 15 days, the Exchange System will try to forward the FatturaPA"
+" file to the Administration in question again. More "
+"information: %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"The buyer, %s, or his company must have either a VAT number either a tax "
+"code (Codice Fiscale)."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_liquidation_state__ls
+msgid "The company is in a state of liquidation"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_eco_index_liquidation_state__ln
+msgid "The company is not in a state of liquidation"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"The maximum length for VAT number is 30. %s have a VAT number too long: %s."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "The seller must have a bank account."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "The seller's company must have a tax system."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid ""
+"The seller/provider is a company listed on the register of companies and as\n"
+" such must also indicate the registration data on all documents (art. 2250, Italian\n"
+" Civil Code)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_has_eco_index
+msgid ""
+"The seller/provider is a company listed on the register of companies and as"
+" such must also indicate the registration data on all documents (art."
+" 2250, Italian Civil Code)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_has_tax_representative
+msgid ""
+"The seller/provider is a non-resident subject which carries out "
+"transactions in Italy with relevance for VAT purposes and which takes"
+" avail of a tax representative in Italy"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model_terms:ir.ui.view,arch_db:l10n_it_edi.res_company_form_l10n_it
+msgid ""
+"The seller/provider is a non-resident subject which carries out transactions in Italy\n"
+" with relevance for VAT purposes and which takes avail of a tax representative in Italy"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_res_company__l10n_it_eco_index_number
+msgid ""
+"This field must contain the number under which the seller/provider is"
+" listed on the register of companies."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__delivered
+msgid "This invoice is delivered"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__delivered_accepted
+msgid "This invoice is delivered and accepted by destinatory"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__delivered_expired
+msgid ""
+"This invoice is delivered and expired (expiry of the maximum term for "
+"communication of acceptance/refusal)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_move__l10n_it_send_state__delivered_refused
+msgid "This invoice is delivered and refused by destinatory"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Total amount from the XML File: %s"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.actions.act_window,name:l10n_it_edi.action_ddt_account
+#: model:ir.model,name:l10n_it_edi.model_l10n_it_ddt
+msgid "Transport Document"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_l10n_it_ddt__date
+msgid "Transport document date"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,help:l10n_it_edi.field_l10n_it_ddt__name
+msgid "Transport document number"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Transport informations from XML file:"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields,field_description:l10n_it_edi.field_account_tax__l10n_it_vat_due_date
+msgid "VAT due date"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "Vendor not found, useful informations from XML file:"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid ""
+"You can't regenerate an E-Invoice when the first one is sent and there are "
+"no errors"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_company.py:0
+#, python-format
+msgid "You must select a tax representative."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "You must select one and only one tax by line."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_company.py:0
+#, python-format
+msgid "Your tax representative partner must have a country."
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/res_company.py:0
+#, python-format
+msgid "Your tax representative partner must have a tax number."
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_vat_due_date__d
+msgid "[D] IVA ad esigibilità differita"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_vat_due_date__i
+msgid "[I] IVA ad esigibilità immediata"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n1
+msgid "[N1] Escluse ex art. 15"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n2_1
+msgid ""
+"[N2.1] Non soggette ad IVA ai sensi degli artt. Da 7 a 7-septies del DPR "
+"633/72"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n2_2
+msgid "[N2.2] Non soggette – altri casi"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n2
+msgid "[N2] Non soggette"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_1
+msgid "[N3.1] Non imponibili – esportazioni"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_2
+msgid "[N3.2] Non imponibili – cessioni intracomunitarie"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_3
+msgid "[N3.3] Non imponibili – cessioni verso San Marino"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_4
+msgid ""
+"[N3.4] Non imponibili – operazioni assimilate alle cessioni all’esportazione"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_5
+msgid "[N3.5] Non imponibili – a seguito di dichiarazioni d’intento"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3_6
+msgid ""
+"[N3.6] Non imponibili – altre operazioni che non concorrono alla formazione "
+"del plafond"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n3
+msgid "[N3] Non imponibili"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n4
+msgid "[N4] Esenti"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n5
+msgid "[N5] Regime del margine / IVA non esposta in fattura"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_1
+msgid ""
+"[N6.1] Inversione contabile – cessione di rottami e altri materiali di "
+"recupero"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_2
+msgid "[N6.2] Inversione contabile – cessione di oro e argento puro"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_3
+msgid "[N6.3] Inversione contabile – subappalto nel settore edile"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_4
+msgid "[N6.4] Inversione contabile – cessione di fabbricati"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_5
+msgid "[N6.5] Inversione contabile – cessione di telefoni cellulari"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_6
+msgid "[N6.6] Inversione contabile – cessione di prodotti elettronici"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_7
+msgid ""
+"[N6.7] Inversione contabile – prestazioni comparto edile esettori connessi"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_8
+msgid "[N6.8] Inversione contabile – operazioni settore energetico"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6_9
+msgid "[N6.9] Inversione contabile – altri casi"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n6
+msgid ""
+"[N6] Inversione contabile (per le operazioni in reverse charge ovvero nei "
+"casi di autofatturazione per acquisti extra UE di servizi ovvero per "
+"importazioni di beni nei soli casi previsti)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_kind_exoneration__n7
+msgid ""
+"[N7] IVA assolta in altro stato UE (vendite a distanza ex art. 40 c. 3 e 4 e"
+" art. 41 c. 1 lett. b, DL 331/93; prestazione di servizi di "
+"telecomunicazioni, tele-radiodiffusione ed elettronici ex art. 7-sexies "
+"lett. f, g, art. 74-sexies DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf01
+msgid "[RF01] Ordinario"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf02
+msgid "[RF02] Contribuenti minimi (art.1, c.96-117, L. 244/07)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf04
+msgid ""
+"[RF04] Agricoltura e attività connesse e pesca (artt.34 e 34-bis, DPR "
+"633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf05
+msgid "[RF05] Vendita sali e tabacchi (art.74, c.1, DPR. 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf06
+msgid "[RF06] Commercio fiammiferi (art.74, c.1, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf07
+msgid "[RF07] Editoria (art.74, c.1, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf08
+msgid "[RF08] Gestione servizi telefonia pubblica (art.74, c.1, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf09
+msgid ""
+"[RF09] Rivendita documenti di trasporto pubblico e di sosta (art.74, c.1, "
+"DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf10
+msgid ""
+"[RF10] Intrattenimenti, giochi e altre attività di cui alla tariffa allegata"
+" al DPR 640/72 (art.74, c.6, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf11
+msgid "[RF11] Agenzie viaggi e turismo (art.74-ter, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf12
+msgid "[RF12] Agriturismo (art.5, c.2, L. 413/91)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf13
+msgid "[RF13] Vendite a domicilio (art.25-bis, c.6, DPR 600/73)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf14
+msgid ""
+"[RF14] Rivendita beni usati, oggetti d’arte, d’antiquariato o da collezione "
+"(art.36, DL 41/95)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf15
+msgid ""
+"[RF15] Agenzie di vendite all’asta di oggetti d’arte, antiquariato o da "
+"collezione (art.40-bis, DL 41/95)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf16
+msgid "[RF16] IVA per cassa P.A. (art.6, c.5, DPR 633/72)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf17
+msgid "[RF17] IVA per cassa (art. 32-bis, DL 83/2012)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf18
+msgid "[RF18] Altro"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__res_company__l10n_it_tax_system__rf19
+msgid "[RF19] Regime forfettario (art.1, c.54-89, L. 190/2014)"
+msgstr ""
+
+#. module: l10n_it_edi
+#: model:ir.model.fields.selection,name:l10n_it_edi.selection__account_tax__l10n_it_vat_due_date__s
+msgid "[S] Scissione dei pagamenti"
+msgstr ""
+
+#. module: l10n_it_edi
+#: code:addons/l10n_it_edi/models/account_edi_format.py:0
+#, python-format
+msgid "from XML file:"
+msgstr ""
diff --git a/addons/l10n_it_stock_ddt/i18n/it.po b/addons/l10n_it_stock_ddt/i18n/it.po
new file mode 100644
index 0000000000..feb292e734
--- /dev/null
+++ b/addons/l10n_it_stock_ddt/i18n/it.po
@@ -0,0 +1,315 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_it_stock_ddt
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-01-11 14:02+0000\n"
+"PO-Revision-Date: 2022-01-11 14:02+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.actions.report,print_report_name:l10n_it_stock_ddt.action_report_ddt
+msgid ""
+"'DDT - %s - %s' % (object.partner_id.name or '', object.l10n_it_ddt_number)"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Note:"
+msgstr "Nota:"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Total:"
+msgstr "Totale:"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Transportation Method Details: "
+msgstr "Dettagli metodo di trasporto"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Customer Address:"
+msgstr "Indirizzo Cliente:"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Warehouse Address:"
+msgstr "Indirizzo Magazzino:"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Carrier Signature"
+msgstr "Firma Corriere"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Company Signature"
+msgstr "Firma Azienda"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Customer Signature"
+msgstr "Firma Cliente"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Product"
+msgstr "Prodotto"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Quantity"
+msgstr "Quantità"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Total Value"
+msgstr "Valore Totale"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__attemped_sale
+msgid "Attempted Sale"
+msgstr "Tentata Vendita"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Carrier"
+msgstr "Corriere"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Carrier Condition"
+msgstr "Termini di Resa"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_country_code
+msgid "Country Code"
+msgstr "Codice Nazione"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_method__courier
+msgid "Courier service"
+msgstr "Servizio Corriere"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.view_picking_form_inherit_l10n_it_ddt
+msgid "DDT Information"
+msgstr "Informazioni DDT"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_ddt_number
+msgid "DDT Number"
+msgstr "Numero DDT"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.actions.report,name:l10n_it_stock_ddt.action_report_ddt
+msgid "DDT report"
+msgstr "DDT"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.account_invoice_view_form_inherit_ddt
+msgid "DDTs"
+msgstr "DDT"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move__display_name
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__display_name
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking_type__display_name
+msgid "Display Name"
+msgstr "Nome visualizzato"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Documento di Trasporto"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__evaluation
+msgid "Evaluation"
+msgstr "Valutazione"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__gift
+msgid "Gift"
+msgstr "Regalo"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Gross Weight (kg)"
+msgstr "Peso lordo (kg)"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move__id
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__id
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking_type__id
+msgid "ID"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model,name:l10n_it_stock_ddt.model_account_move
+msgid "Journal Entry"
+msgstr "Registrazione contabile"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_bank_statement_line__l10n_it_ddt_ids
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move__l10n_it_ddt_ids
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_payment__l10n_it_ddt_ids
+msgid "L10N It Ddt"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_bank_statement_line__l10n_it_ddt_count
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move__l10n_it_ddt_count
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_payment__l10n_it_ddt_count
+msgid "L10N It Ddt Count"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking_type__l10n_it_ddt_sequence_id
+msgid "L10N It Ddt Sequence"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move____last_update
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking____last_update
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking_type____last_update
+msgid "Last Modified on"
+msgstr "Ultima modifica il"
+
+#. module: l10n_it_stock_ddt
+#: code:addons/l10n_it_stock_ddt/models/account_invoice.py:0
+#, python-format
+msgid "Linked deliveries"
+msgstr "Spedizioni associate"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__loaned_use
+msgid "Loaned for Use"
+msgstr "Comodato d'uso"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Order"
+msgstr "Ordine"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__outsourcing
+msgid "Outsourcing"
+msgstr "Conto Lavorazione"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_parcels
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Parcels"
+msgstr "Colli"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Picking Number"
+msgstr "Numero prelievo"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model,name:l10n_it_stock_ddt.model_stock_picking_type
+msgid "Picking Type"
+msgstr "Tipologia prelievo"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.view_picking_form_inherit_l10n_it_ddt
+msgid "Print"
+msgstr "Stampa"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_method__recipient
+msgid "Recipient"
+msgstr "Destinatario"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__repair
+msgid "Repair"
+msgstr "Conto Riparazione"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__sale
+msgid "Sale"
+msgstr "Vendita"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_method__sender
+msgid "Sender"
+msgstr "Mittente"
+
+#. module: l10n_it_stock_ddt
+#: code:addons/l10n_it_stock_ddt/models/stock_picking.py:0
+#, python-format
+msgid "Sequence"
+msgstr "Sequenza"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Shipping Date"
+msgstr "Data transporto"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__substitution
+msgid "Substitution"
+msgstr "Sostituzione"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,help:l10n_it_stock_ddt.field_stock_picking__l10n_it_country_code
+msgid ""
+"The ISO country code in two chars. \n"
+"You can use this field for quick search."
+msgstr ""
+"Il codice ISO nazionale in 2 caratteri. \n"
+"Puoi usare questo campo per la ricerca veloce."
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model,name:l10n_it_stock_ddt.model_stock_picking
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__transfer
+msgid "Transfer"
+msgstr "Trasferimento"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_transport_method
+msgid "Transport Method"
+msgstr "Metodo di trasporto"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_transport_method_details
+msgid "Transport Note"
+msgstr "Nota di trasporto"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_transport_reason
+msgid "Transport Reason"
+msgstr "Ragione trasporto"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Transportation Method"
+msgstr "Metodo di trasporto"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Transportation Reason"
+msgstr "Ragione trasporto"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "VAT"
+msgstr "Pta IVA"
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "VAT:"
+msgstr "Pta IVA:"
diff --git a/addons/l10n_it_stock_ddt/i18n/l10n_it_stock_ddt.pot b/addons/l10n_it_stock_ddt/i18n/l10n_it_stock_ddt.pot
new file mode 100644
index 0000000000..9044e08fc1
--- /dev/null
+++ b/addons/l10n_it_stock_ddt/i18n/l10n_it_stock_ddt.pot
@@ -0,0 +1,314 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * l10n_it_stock_ddt
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-01-10 15:18+0000\n"
+"PO-Revision-Date: 2022-01-10 15:18+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: l10n_it_stock_ddt
+#: model:ir.actions.report,print_report_name:l10n_it_stock_ddt.action_report_ddt
+msgid ""
+"'DDT - %s - %s' % (object.partner_id.name or '', object.l10n_it_ddt_number)"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Note:"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Total:"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Transportation Method Details: "
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Customer Address:"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Warehouse Address:"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Carrier Signature"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Company Signature"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Customer Signature"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Product"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Quantity"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Total Value"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__attemped_sale
+msgid "Attempted Sale"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Carrier"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Carrier Condition"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_country_code
+msgid "Country Code"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_method__courier
+msgid "Courier service"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.view_picking_form_inherit_l10n_it_ddt
+msgid "DDT Information"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_ddt_number
+msgid "DDT Number"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.actions.report,name:l10n_it_stock_ddt.action_report_ddt
+msgid "DDT report"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.account_invoice_view_form_inherit_ddt
+msgid "DDTs"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move__display_name
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__display_name
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking_type__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Documento di Trasporto"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__evaluation
+msgid "Evaluation"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__gift
+msgid "Gift"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Gross Weight (kg)"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move__id
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__id
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking_type__id
+msgid "ID"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model,name:l10n_it_stock_ddt.model_account_move
+msgid "Journal Entry"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_bank_statement_line__l10n_it_ddt_ids
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move__l10n_it_ddt_ids
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_payment__l10n_it_ddt_ids
+msgid "L10N It Ddt"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_bank_statement_line__l10n_it_ddt_count
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move__l10n_it_ddt_count
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_payment__l10n_it_ddt_count
+msgid "L10N It Ddt Count"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking_type__l10n_it_ddt_sequence_id
+msgid "L10N It Ddt Sequence"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_account_move____last_update
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking____last_update
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking_type____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: code:addons/l10n_it_stock_ddt/models/account_invoice.py:0
+#, python-format
+msgid "Linked deliveries"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__loaned_use
+msgid "Loaned for Use"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Order"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__outsourcing
+msgid "Outsourcing"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_parcels
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Parcels"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Picking Number"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model,name:l10n_it_stock_ddt.model_stock_picking_type
+msgid "Picking Type"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.view_picking_form_inherit_l10n_it_ddt
+msgid "Print"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_method__recipient
+msgid "Recipient"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__repair
+msgid "Repair"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__sale
+msgid "Sale"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_method__sender
+msgid "Sender"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: code:addons/l10n_it_stock_ddt/models/stock_picking.py:0
+#: code:addons/l10n_it_stock_ddt/models/stock_picking.py:0
+#, python-format
+msgid "Sequence"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Shipping Date"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__substitution
+msgid "Substitution"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,help:l10n_it_stock_ddt.field_stock_picking__l10n_it_country_code
+msgid ""
+"The ISO country code in two chars. \n"
+"You can use this field for quick search."
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model,name:l10n_it_stock_ddt.model_stock_picking
+#: model:ir.model.fields.selection,name:l10n_it_stock_ddt.selection__stock_picking__l10n_it_transport_reason__transfer
+msgid "Transfer"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_transport_method
+msgid "Transport Method"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_transport_method_details
+msgid "Transport Note"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model:ir.model.fields,field_description:l10n_it_stock_ddt.field_stock_picking__l10n_it_transport_reason
+msgid "Transport Reason"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Transportation Method"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "Transportation Reason"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "VAT"
+msgstr ""
+
+#. module: l10n_it_stock_ddt
+#: model_terms:ir.ui.view,arch_db:l10n_it_stock_ddt.report_ddt_view
+msgid "VAT:"
+msgstr ""
diff --git a/addons/l10n_lu_peppol_id/__init__.py b/addons/l10n_lu_peppol_id/__init__.py
new file mode 100644
index 0000000000..013872cc0d
--- /dev/null
+++ b/addons/l10n_lu_peppol_id/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import models
diff --git a/addons/l10n_lu_peppol_id/__manifest__.py b/addons/l10n_lu_peppol_id/__manifest__.py
new file mode 100644
index 0000000000..8ee0957711
--- /dev/null
+++ b/addons/l10n_lu_peppol_id/__manifest__.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': "Luxembourg - Peppol Identifier",
+ 'version': '1.0',
+ 'description': """
+ Some Luxembourg public institutions do not have a VAT number but have been assigned an arbitrary number
+ (see: https://pch.gouvernement.lu/fr/peppol.html). Thus, this module adds the Peppol Identifier field on
+ the account.move form view. If this field is set, it is then read when exporting electronic invoicing formats.
+ """,
+ 'depends': ['l10n_lu', 'account_edi_ubl_cii'],
+ 'data': [
+ 'views/partner_view.xml',
+ ],
+ 'license': 'LGPL-3',
+}
diff --git a/addons/l10n_lu_peppol_id/models/__init__.py b/addons/l10n_lu_peppol_id/models/__init__.py
new file mode 100644
index 0000000000..2e63ffe6df
--- /dev/null
+++ b/addons/l10n_lu_peppol_id/models/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import res_partner
diff --git a/addons/l10n_lu_peppol_id/models/res_partner.py b/addons/l10n_lu_peppol_id/models/res_partner.py
new file mode 100644
index 0000000000..be2868ff29
--- /dev/null
+++ b/addons/l10n_lu_peppol_id/models/res_partner.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import fields, models
+
+
+class ResPartner(models.Model):
+ _inherit = 'res.partner'
+
+ country_code = fields.Char(related='country_id.code')
+ l10n_lu_peppol_identifier = fields.Char("Peppol Unique Identifier")
diff --git a/addons/l10n_lu_peppol_id/views/partner_view.xml b/addons/l10n_lu_peppol_id/views/partner_view.xml
new file mode 100644
index 0000000000..5bf4c132e1
--- /dev/null
+++ b/addons/l10n_lu_peppol_id/views/partner_view.xml
@@ -0,0 +1,14 @@
+
+
+
+ res.partner.form.inherit.l10n_lu_peppol_id
+ res.partner
+
+
+
+
+
+
+
+
+
diff --git a/addons/l10n_ph/__init__.py b/addons/l10n_ph/__init__.py
new file mode 100644
index 0000000000..b1ce048f55
--- /dev/null
+++ b/addons/l10n_ph/__init__.py
@@ -0,0 +1,4 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import models
+from . import wizard
diff --git a/addons/l10n_ph/__manifest__.py b/addons/l10n_ph/__manifest__.py
new file mode 100644
index 0000000000..1a059412b1
--- /dev/null
+++ b/addons/l10n_ph/__manifest__.py
@@ -0,0 +1,35 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+{
+ "name": "Philippines - Accounting",
+ "summary": """
+ This is the module to manage the accounting chart for The Philippines.
+ """,
+ "category": "Accounting/Localizations/Account Charts",
+ "version": "1.0",
+ "author": "Flectra PS",
+ "website": "https://flectrahq.com",
+ "depends": [
+ "account",
+ "base_vat",
+ "l10n_multilang",
+ ],
+ "data": [
+ "data/account_chart_template_data.xml",
+ "data/account.account.template.csv",
+ "data/account_chart_template_post_data.xml",
+ "data/account_tax_group.xml",
+ "data/account_tax_template.xml",
+ "data/account_fiscal_position_template.xml",
+ "data/account_fiscal_position_tax_template.xml",
+ "data/account_chart_template_configure_data.xml",
+ "wizard/generate_2307_wizard_views.xml",
+ "views/account_move_views.xml",
+ "views/account_payment_views.xml",
+ "views/account_tax_views.xml",
+ "views/res_partner_views.xml",
+ "security/ir.model.access.csv",
+ ],
+ "license": "LGPL-3",
+ "icon": "/base/static/img/country_flags/ph.png",
+}
diff --git a/addons/l10n_ph/data/account.account.template.csv b/addons/l10n_ph/data/account.account.template.csv
new file mode 100644
index 0000000000..6b34eda4e0
--- /dev/null
+++ b/addons/l10n_ph/data/account.account.template.csv
@@ -0,0 +1,98 @@
+id,name,code,user_type_id/id,chart_template_id/id,reconcile
+l10n_ph_100000,Bank Suspense Account,100000,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110000,Accounts Receivable,110000,account.data_account_type_receivable,l10n_ph_chart_template,True
+l10n_ph_110003,Accounts Receivable (POS),110003,account.data_account_type_receivable,l10n_ph_chart_template,True
+l10n_ph_110100,Advances to Suppliers,110100,account.data_account_type_prepayments,l10n_ph_chart_template,False
+l10n_ph_110101,Deposits,110101,account.data_account_type_prepayments,l10n_ph_chart_template,False
+l10n_ph_110102,Employees Receivable-Cash Advance,110102,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110103,Employees Receivable-Loan,110103,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110104,ER - Others,110104,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110105,Prepaid Insurance,110105,account.data_account_type_prepayments,l10n_ph_chart_template,False
+l10n_ph_110106,Prepaid Pension - contribution,110106,account.data_account_type_prepayments,l10n_ph_chart_template,False
+l10n_ph_110200,Prepaid Tax - Tax Credit Certificate,110200,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110201,Input VAT 12%,110201,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110202,Deferred Input VAT 12%,110202,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110203,Deferred Tax Asset,110203,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110205,Creditable Income Tax,110205,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110206,Tax Withheld by Customer,110206,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110207,Deferred Tax Withheld by Customer,110207,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110300,Inventory,110300,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110301,Purchases,110301,account.data_account_type_current_assets,l10n_ph_chart_template,False
+l10n_ph_110302,Stock Interim (Received),110302,account.data_account_type_current_assets,l10n_ph_chart_template,True
+l10n_ph_110303,Stock Interim (Delivered),110303,account.data_account_type_current_assets,l10n_ph_chart_template,True
+l10n_ph_110304,Stock Interim (Production),110304,account.data_account_type_current_assets,l10n_ph_chart_template,True
+l10n_ph_110400,Other Non-current Asset,110400,account.data_account_type_non_current_assets,l10n_ph_chart_template,False
+l10n_ph_110500,Building and Leasehold Improvements,110500,account.data_account_type_fixed_assets,l10n_ph_chart_template,False
+l10n_ph_110501,"Furniture, Fixtures and Equipment",110501,account.data_account_type_fixed_assets,l10n_ph_chart_template,False
+l10n_ph_110502,Vehicles,110502,account.data_account_type_fixed_assets,l10n_ph_chart_template,False
+l10n_ph_110503,Computers,110503,account.data_account_type_fixed_assets,l10n_ph_chart_template,False
+l10n_ph_110504,Accum Depreciation-Bldg & Leasehold Imp,110504,account.data_account_type_fixed_assets,l10n_ph_chart_template,False
+l10n_ph_110505,"Accum Depreciation-Furniture, Fixtures and Equipment",110505,account.data_account_type_fixed_assets,l10n_ph_chart_template,False
+l10n_ph_110506,Accum Depreciation-Vehicles,110506,account.data_account_type_fixed_assets,l10n_ph_chart_template,False
+l10n_ph_110507,Accum Depreciation-Computers,110507,account.data_account_type_fixed_assets,l10n_ph_chart_template,False
+l10n_ph_200000,Accounts Payable,200000,account.data_account_type_payable,l10n_ph_chart_template,True
+l10n_ph_200200,Dividends Payable - Common Shares,200200,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200201,Unearned Revenue,200201,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200202,Customer Deposits Received,200202,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200300,Output VAT 12% - Actual,200300,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200301,Deferred Output VAT 12% - Actual,200301,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200302,Tax Payable-Withholding Tax Compensation,200302,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200303,Tax Pay-Withholding Tax Source,200303,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200304,Deferred Tax Pay-Withholding Tax Source,200304,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200305,Taxes Payable-Final Withholding Tax,200305,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200306,Tax Payable-Withholding Tax at Source (Accrual),200306,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200307,Income Tax Payable,200307,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200308,Accrued Fringe Benefit Tax,200308,account.data_account_type_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_200400,Other Non-current Liability,200400,account.data_account_type_non_current_liabilities,l10n_ph_chart_template,False
+l10n_ph_300000,Capital Stock,300000,account.data_account_type_equity,l10n_ph_chart_template,False
+l10n_ph_300001,Additional Paid in Capital,300001,account.data_account_type_equity,l10n_ph_chart_template,False
+l10n_ph_300002,Retained Earnings,300002,account.data_account_type_equity,l10n_ph_chart_template,False
+l10n_ph_430400,Sales/Revenues,430400,account.data_account_type_revenue,l10n_ph_chart_template,False
+l10n_ph_510000,Cost of Goods Sold,510000,account.data_account_type_direct_costs,l10n_ph_chart_template,False
+l10n_ph_511100,COGS - Purchases,511100,account.data_account_type_direct_costs,l10n_ph_chart_template,False
+l10n_ph_511600,COGS - Freight Costs,511600,account.data_account_type_direct_costs,l10n_ph_chart_template,False
+l10n_ph_511700,COGS - Direct Labor,511700,account.data_account_type_direct_costs,l10n_ph_chart_template,False
+l10n_ph_511800,COGS - Factory/Processing Overhead,511800,account.data_account_type_direct_costs,l10n_ph_chart_template,False
+l10n_ph_620000,Admin Expense,620000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_620001,Marketing Expense,620001,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_620100,Lease-Corporate Offices,620100,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_621000,Insurance Expenses,621000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_622000,Repairs & Maintenance,622000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623000,Salaries & Wages,623000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623001,Overtime Pay,623001,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623002,SSS Contribution,623002,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623003,HDMF Contribution,623003,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623004,PHIC Contribution,623004,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623005,Meal Allowance,623005,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623006,Other Allowance,623006,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623007,13th Month Pay,623007,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623008,Retirement Expenses,623008,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623009,Training and Webinar,623009,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623014,Sick Leave Expenses,623014,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_623015,Vacation Leave Expenses,623015,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_624000,Taxes and Licenses,624000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_625000,Utilities Expenses,625000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_626000,Security Services,626000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_626001,Professional Fees,626001,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_627000,Travel and Transportation,627000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_628000,Advertising and Promotion,628000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_629000,Depreciation Expense,629000,account.data_account_type_depreciation,l10n_ph_chart_template,False
+l10n_ph_632000,Commission Expense,632000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_633000,Supplies Expenses,633000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_634000,Miscellaneous Expenses,634000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_634001,Bank Fees,634001,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_635000,Prov DA-Billed Accts,635000,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_635001,Prov-Probable Expenses,635001,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_635002,Prov for Inc Tax - Creditable,635002,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_635003,Provision for Tax - Final,635003,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_710100,Forex Gain,710100,account.data_account_type_other_income,l10n_ph_chart_template,False
+l10n_ph_710101,Forex Loss,710101,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_710102,Cash Difference Gain,710102,account.data_account_type_other_income,l10n_ph_chart_template,False
+l10n_ph_710103,Cash Difference Loss,710103,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_710200,Gain/Loss- Sale FA,710200,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_710201,Loss on FA Disposal,710201,account.data_account_type_expenses,l10n_ph_chart_template,False
+l10n_ph_710300,Interest Inc-Savings,710300,account.data_account_type_other_income,l10n_ph_chart_template,False
+l10n_ph_710301,Interest Income-Savings Local,710301,account.data_account_type_other_income,l10n_ph_chart_template,False
+l10n_ph_710400,Other Income,710400,account.data_account_type_other_income,l10n_ph_chart_template,False
+l10n_ph_710500,Interest Expense-Suppliers' Credit Local,710500,account.data_account_type_other_income,l10n_ph_chart_template,False
+l10n_ph_999999,Undistributed Profits/Losses,999999,account.data_unaffected_earnings,l10n_ph_chart_template,False
diff --git a/addons/l10n_ph/data/account_chart_template_configure_data.xml b/addons/l10n_ph/data/account_chart_template_configure_data.xml
new file mode 100644
index 0000000000..5491471329
--- /dev/null
+++ b/addons/l10n_ph/data/account_chart_template_configure_data.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/addons/l10n_ph/data/account_chart_template_data.xml b/addons/l10n_ph/data/account_chart_template_data.xml
new file mode 100644
index 0000000000..38963bce15
--- /dev/null
+++ b/addons/l10n_ph/data/account_chart_template_data.xml
@@ -0,0 +1,13 @@
+
+
+
+ Philippines Account Template
+ 1000
+ 1001
+ 1002
+ 6
+
+
+
+
+
diff --git a/addons/l10n_ph/data/account_chart_template_post_data.xml b/addons/l10n_ph/data/account_chart_template_post_data.xml
new file mode 100644
index 0000000000..261ac0cf3c
--- /dev/null
+++ b/addons/l10n_ph/data/account_chart_template_post_data.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/l10n_ph/data/account_fiscal_position_tax_template.xml b/addons/l10n_ph/data/account_fiscal_position_tax_template.xml
new file mode 100644
index 0000000000..7687b40fff
--- /dev/null
+++ b/addons/l10n_ph/data/account_fiscal_position_tax_template.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/l10n_ph/data/account_fiscal_position_template.xml b/addons/l10n_ph/data/account_fiscal_position_template.xml
new file mode 100644
index 0000000000..81f92ed57c
--- /dev/null
+++ b/addons/l10n_ph/data/account_fiscal_position_template.xml
@@ -0,0 +1,18 @@
+
+
+
+ 1
+ VAT Registered
+
+
+
+
+
+
+ 2
+ VAT Exempt
+
+
+
+
+
diff --git a/addons/l10n_ph/data/account_tax_group.xml b/addons/l10n_ph/data/account_tax_group.xml
new file mode 100644
index 0000000000..c516031126
--- /dev/null
+++ b/addons/l10n_ph/data/account_tax_group.xml
@@ -0,0 +1,27 @@
+
+
+
+ VAT 12%
+
+
+ VAT Exempt
+
+
+ WHT 0.5%
+
+
+ WHT 1%
+
+
+ WHT 2%
+
+
+ WHT 5%
+
+
+ WHT 10%
+
+
+ WHT 15%
+
+
diff --git a/addons/l10n_ph/data/account_tax_template.xml b/addons/l10n_ph/data/account_tax_template.xml
new file mode 100644
index 0000000000..c8731be235
--- /dev/null
+++ b/addons/l10n_ph/data/account_tax_template.xml
@@ -0,0 +1,1049 @@
+
+
+
+ 10
+
+ 12% VAT
+ 12% VAT
+ sale
+ 12
+ percent
+
+
+
+
+
+ 10
+
+ VAT Exempt
+ VAT Exempt
+ sale
+ 0
+ percent
+
+
+
+
+
+ 20
+
+ 12% VAT
+ 12% VAT
+ purchase
+ 12
+ percent
+
+
+
+
+
+ 20
+
+ VAT Exempt
+ VAT Exempt
+ purchase
+ 0
+ percent
+
+
+
+
+
+ 30
+
+ 5% WI010 - Prof Fees
+ Prof Fees
+ WI010
+ purchase
+ -5
+ percent
+
+
+
+
+
+ 30
+
+ 10% WI011 - Prof Fees
+ Prof Fees
+ WI011
+ purchase
+ -10
+ percent
+
+
+
+
+
+ 40
+
+ 5% WI100 - Gross rental of property
+ Gross rental of property
+ WI100
+ purchase
+ -5
+ percent
+
+
+
+
+
+ 50
+
+ 2% WI120 - Contractors
+ Contractors
+ WI120
+ purchase
+ -2
+ percent
+
+
+
+
+
+ 60
+
+ 5% WI139 - Commission of service fees
+ Commission of service fees
+ WI139
+ purchase
+ -5
+ percent
+
+
+
+
+
+ 60
+
+ 10% WI140 - Commission of service fees
+ Commission of service fees
+ WI140
+ purchase
+ -10
+ percent
+
+
+
+
+
+ 70
+
+ 0.5% WI158 - Credit card companies
+ Credit card companies
+ WI158
+ purchase
+ -0.5
+ percent
+
+
+
+
+
+ 80
+
+ 1% WI640 - Supplier of goods
+ Supplier of goods
+ WI640
+ purchase
+ -1
+ percent
+
+
+
+
+
+ 80
+
+ 2% WI157 - Supplier of services
+ Supplier of services
+ WI157
+ purchase
+ -2
+ percent
+
+
+
+
+
+ 90
+
+ 1% WI158 - Supplier of goods by top w/holding agents
+ Supplier of goods by top w/holding agents
+ WI158
+ purchase
+ -1
+ percent
+
+
+
+
+
+ 90
+
+ 2% WI160 - Supplier of goods by top w/holding agents
+ Supplier of goods by top w/holding agents
+ WI160
+ purchase
+ -2
+ percent
+
+
+
+
+
+ 100
+
+ 5% WI515 - Commission, rebates, discounts
+ Commission, rebates, discounts
+ WI515
+ purchase
+ -5
+ percent
+
+
+
+
+
+ 100
+
+ 10% WI516 - Commission, rebates, discounts
+ Commission, rebates, discounts
+ WI516
+ purchase
+ -10
+ percent
+
+
+
+
+
+ 110
+
+ 10% WC010 - Prof Fees
+ Prof Fees
+ WC010
+ purchase
+ -10
+ percent
+
+
+
+
+
+ 110
+
+ 15% WC011 - Prof Fees
+ Prof Fees
+ WC011
+ purchase
+ -15
+ percent
+
+
+
+
+
+ 120
+
+ 5% WC100 - Gross rental of property
+ Gross rental of property
+ WC100
+ purchase
+ -5
+ percent
+
+
+
+
+
+ 130
+
+ 2% WC120 - Contractors
+ Contractors
+ WC120
+ purchase
+ -2
+ percent
+
+
+
+
+
+ 140
+
+ 10% WC139 - Commission of service fees
+ Commission of service fees
+ WC139
+ purchase
+ -10
+ percent
+
+
+
+
+
+ 140
+
+ 15% WC140 - Commission of service fees
+ Commission of service fees
+ WC140
+ purchase
+ -15
+ percent
+
+
+
+
+
+ 150
+
+ 0.5% WC158 - Credit card companies
+ Credit card companies
+ WC158
+ purchase
+ -0.5
+ percent
+
+
+
+
+
+ 160
+
+ 1% WC640 - Supplier of goods
+ Supplier of goods
+ WC640
+ purchase
+ -1
+ percent
+
+
+
+
+
+ 160
+
+ 2% WC157 - Supplier of services
+ Supplier of services
+ WC157
+ purchase
+ -2
+ percent
+
+
+
+
+
+ 170
+
+ 1% WC158 - Supplier of goods by top w/holding agents
+ Supplier of goods by top w/holding agents
+ WC158
+ purchase
+ -1
+ percent
+
+
+
+
+
+ 170
+
+ 2% WC160 - Supplier of goods by top w/holding agents
+ Supplier of goods by top w/holding agents
+ WC160
+ purchase
+ -2
+ percent
+
+
+
+
+
+ 180
+
+ 5% WC515 - Commission, rebates, discounts
+ Commission, rebates, discounts
+ WC515
+ purchase
+ -5
+ percent
+
+
+
+
+
+ 180
+
+ 10% WC516 - Commission, rebates, discounts
+ Commission, rebates, discounts
+ WC516
+ purchase
+ -10
+ percent
+
+
+
+
+
diff --git a/addons/l10n_ph/models/__init__.py b/addons/l10n_ph/models/__init__.py
new file mode 100644
index 0000000000..66c0eed44f
--- /dev/null
+++ b/addons/l10n_ph/models/__init__.py
@@ -0,0 +1,7 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import res_partner
+from . import account_move
+from . import account_payment
+from . import account_tax
+from . import account_tax_template
diff --git a/addons/l10n_ph/models/account_move.py b/addons/l10n_ph/models/account_move.py
new file mode 100644
index 0000000000..5e25ccaa87
--- /dev/null
+++ b/addons/l10n_ph/models/account_move.py
@@ -0,0 +1,19 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import _, models
+from flectra.exceptions import UserError
+
+
+class AccountMove(models.Model):
+ _inherit = "account.move"
+
+ def action_open_l10n_ph_2307_wizard(self):
+ vendor_bills = self.filtered_domain([('move_type', '=', 'in_invoice')])
+ if vendor_bills:
+ wizard_action = self.env["ir.actions.act_window"]._for_xml_id("l10n_ph.view_l10n_ph_2307_wizard_act_window")
+ wizard_action.update({
+ 'context': {'default_moves_to_export': vendor_bills.ids}
+ })
+ return wizard_action
+ else:
+ raise UserError(_('Only Vendor Bills are available.'))
diff --git a/addons/l10n_ph/models/account_payment.py b/addons/l10n_ph/models/account_payment.py
new file mode 100644
index 0000000000..371d1e22e4
--- /dev/null
+++ b/addons/l10n_ph/models/account_payment.py
@@ -0,0 +1,19 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import _, models
+from flectra.exceptions import UserError
+
+
+class AccountPayment(models.Model):
+ _inherit = "account.payment"
+
+ def action_open_l10n_ph_2307_wizard(self):
+ self.ensure_one()
+ if self.payment_type == 'outbound':
+ wizard_action = self.env["ir.actions.act_window"]._for_xml_id("l10n_ph.view_l10n_ph_2307_wizard_act_window")
+ wizard_action.update({
+ 'context': {'default_moves_to_export': self.reconciled_bill_ids.ids}
+ })
+ return wizard_action
+ else:
+ raise UserError(_('Only Outbound Payment is available.'))
diff --git a/addons/l10n_ph/models/account_tax.py b/addons/l10n_ph/models/account_tax.py
new file mode 100644
index 0000000000..d64dc8db90
--- /dev/null
+++ b/addons/l10n_ph/models/account_tax.py
@@ -0,0 +1,9 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import fields, models
+
+
+class AccountTax(models.Model):
+ _inherit = "account.tax"
+
+ l10n_ph_atc = fields.Char("Philippines ATC")
diff --git a/addons/l10n_ph/models/account_tax_template.py b/addons/l10n_ph/models/account_tax_template.py
new file mode 100644
index 0000000000..df79f90160
--- /dev/null
+++ b/addons/l10n_ph/models/account_tax_template.py
@@ -0,0 +1,14 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import fields, models
+
+
+class AccountTaxTemplate(models.Model):
+ _inherit = "account.tax.template"
+
+ l10n_ph_atc = fields.Char("Philippines ATC")
+
+ def _get_tax_vals(self, company, tax_template_to_tax):
+ val = super()._get_tax_vals(company, tax_template_to_tax)
+ val.update({"l10n_ph_atc": self.l10n_ph_atc})
+ return val
diff --git a/addons/l10n_ph/models/res_partner.py b/addons/l10n_ph/models/res_partner.py
new file mode 100644
index 0000000000..76112e6b0f
--- /dev/null
+++ b/addons/l10n_ph/models/res_partner.py
@@ -0,0 +1,25 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import fields, api, models
+
+
+class ResPartner(models.Model):
+ _inherit = "res.partner"
+
+ branch_code = fields.Char("Branch Code", default='000', compute='_compute_branch_code', store=True)
+ first_name = fields.Char("First Name")
+ middle_name = fields.Char("Middle Name")
+ last_name = fields.Char("Last Name")
+
+ @api.model
+ def _commercial_fields(self):
+ return super()._commercial_fields() + ['branch_code']
+
+ @api.depends('vat', 'country_id')
+ def _compute_branch_code(self):
+ for partner in self:
+ branch_code = '000'
+ if partner.country_id.code == 'PH' and partner.vat:
+ match = partner.__check_vat_ph_re.match(partner.vat)
+ branch_code = match and match.group(1) and match.group(1)[1:] or branch_code
+ partner.branch_code = branch_code
diff --git a/addons/l10n_ph/security/ir.model.access.csv b/addons/l10n_ph/security/ir.model.access.csv
new file mode 100644
index 0000000000..3f1e3cafb4
--- /dev/null
+++ b/addons/l10n_ph/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+generate_2307_wizard,access_generate_2307_wizard,model_l10n_ph_2307_wizard,account.group_account_invoice,1,1,1,1
diff --git a/addons/l10n_ph/views/account_move_views.xml b/addons/l10n_ph/views/account_move_views.xml
new file mode 100644
index 0000000000..c0f5d1cd47
--- /dev/null
+++ b/addons/l10n_ph/views/account_move_views.xml
@@ -0,0 +1,12 @@
+
+
+
+ Download BIR 2307 XLS
+
+
+
+ list,form
+ code
+ action = records.action_open_l10n_ph_2307_wizard()
+
+
diff --git a/addons/l10n_ph/views/account_payment_views.xml b/addons/l10n_ph/views/account_payment_views.xml
new file mode 100644
index 0000000000..85a450b4f4
--- /dev/null
+++ b/addons/l10n_ph/views/account_payment_views.xml
@@ -0,0 +1,12 @@
+
+
+
+ Download BIR 2307 XLS
+
+
+
+ form
+ code
+ action = record.action_open_l10n_ph_2307_wizard()
+
+
diff --git a/addons/l10n_ph/views/account_tax_views.xml b/addons/l10n_ph/views/account_tax_views.xml
new file mode 100644
index 0000000000..cd403ed6d5
--- /dev/null
+++ b/addons/l10n_ph/views/account_tax_views.xml
@@ -0,0 +1,19 @@
+
+
+
+ account.tax.view.form.inherit.l10n_ph
+ account.tax
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/l10n_ph/views/res_partner_views.xml b/addons/l10n_ph/views/res_partner_views.xml
new file mode 100644
index 0000000000..cd99d5c83b
--- /dev/null
+++ b/addons/l10n_ph/views/res_partner_views.xml
@@ -0,0 +1,16 @@
+
+
+
+ res.partner.form.inherit.l10n_ph_bir
+ res.partner
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/l10n_ph/wizard/__init__.py b/addons/l10n_ph/wizard/__init__.py
new file mode 100644
index 0000000000..f00bb7d16b
--- /dev/null
+++ b/addons/l10n_ph/wizard/__init__.py
@@ -0,0 +1,3 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import generate_2307_wizard
diff --git a/addons/l10n_ph/wizard/generate_2307_wizard.py b/addons/l10n_ph/wizard/generate_2307_wizard.py
new file mode 100644
index 0000000000..e5d2f36d97
--- /dev/null
+++ b/addons/l10n_ph/wizard/generate_2307_wizard.py
@@ -0,0 +1,93 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+import base64
+import io
+import re
+import xlwt
+
+from flectra import fields, models
+from flectra.tools.misc import format_date
+
+
+COLUMN_HEADER_MAP = {
+ "Reporting_Month": "invoice_date",
+ "Vendor_TIN": "vat",
+ "branchCode": "branch_code",
+ "companyName": "company_name",
+ "surName": "last_name",
+ "firstName": "first_name",
+ "middleName": "middle_name",
+ "address": "address",
+ "nature": "product_name",
+ "ATC": "atc",
+ "income_payment": "price_subtotal",
+ "ewt_rate": "amount",
+ "tax_amount": "tax_amount",
+}
+
+class Generate2307Wizard(models.TransientModel):
+ _name = "l10n_ph_2307.wizard"
+ _description = "Exports 2307 data to a XLS file."
+
+ moves_to_export = fields.Many2many("account.move", string="Joural To Include")
+ generate_xls_file = fields.Binary(
+ "Generated file",
+ help="Technical field used to temporarily hold the generated XLS file before its downloaded."
+ )
+
+ def _write_single_row(self, worksheet, worksheet_row, values):
+ for index, field in enumerate(COLUMN_HEADER_MAP.values()):
+ worksheet.write(worksheet_row, index, label=values[field])
+
+ def _write_rows(self, worksheet, moves):
+ worksheet_row = 0
+ for move in moves:
+ worksheet_row += 1
+ partner = move.partner_id
+ partner_address_info = [partner.street, partner.street2, partner.city, partner.state_id.name, partner.country_id.name]
+ values = {
+ 'invoice_date': format_date(self.env, move.invoice_date, date_format="MM/dd/yyyy"),
+ 'vat': re.sub(r'\-', '', partner.vat)[:9] if partner.vat else '',
+ 'branch_code': partner.branch_code or '000',
+ 'company_name': partner.commercial_partner_id.name,
+ 'first_name': partner.first_name or '',
+ 'middle_name': partner.middle_name or '',
+ 'last_name': partner.last_name or '',
+ 'address': ', '.join([val for val in partner_address_info if val])
+ }
+ for invoice_line in move.invoice_line_ids.filtered(lambda l: not l.display_type):
+ for tax in invoice_line.tax_ids.filtered(lambda x: x.l10n_ph_atc):
+ values['product_name'] = re.sub(r'[\(\)]', '', invoice_line.product_id.name)
+ values['atc'] = tax.l10n_ph_atc
+ values['price_subtotal'] = invoice_line.price_subtotal
+ values['amount'] = tax.amount
+ values['tax_amount'] = tax._compute_amount(invoice_line.price_subtotal, invoice_line.price_unit)
+ self._write_single_row(worksheet, worksheet_row, values)
+ worksheet_row += 1
+
+ def action_generate(self):
+ """ Generate a xls format file for importing to
+ https://bir-excel-uploader.com/excel-file-to-bir-dat-format/#bir-form-2307-settings.
+ This website will then generate a BIR 2307 format excel file for uploading to the
+ PH government.
+ """
+ self.ensure_one()
+
+ file_data = io.BytesIO()
+ workbook = xlwt.Workbook(encoding='utf-8')
+ worksheet = workbook.add_sheet('Form2307')
+
+ for index, col_header in enumerate(COLUMN_HEADER_MAP.keys()):
+ worksheet.write(0, index, label=col_header)
+
+ self._write_rows(worksheet, self.moves_to_export)
+
+ workbook.save(file_data)
+ file_data.seek(0)
+ self.generate_xls_file = base64.b64encode(file_data.read())
+
+ return {
+ "type": "ir.actions.act_url",
+ "target": "self",
+ "url": "/web/content?model=l10n_ph_2307.wizard&download=true&field=generate_xls_file&filename=Form_2307.xls&id={}".format(self.id),
+ }
diff --git a/addons/l10n_ph/wizard/generate_2307_wizard_views.xml b/addons/l10n_ph/wizard/generate_2307_wizard_views.xml
new file mode 100644
index 0000000000..3d15969570
--- /dev/null
+++ b/addons/l10n_ph/wizard/generate_2307_wizard_views.xml
@@ -0,0 +1,36 @@
+
+
+
+ l10n_ph_2307.wizard.form
+ l10n_ph_2307.wizard
+
+
+
+
+
+ BIR 2307 Report
+ l10n_ph_2307.wizard
+ form
+ new
+
+
diff --git a/addons/mail/static/scripts/flectra-mailgate.py b/addons/mail/static/scripts/flectra-mailgate.py
old mode 100644
new mode 100755
diff --git a/addons/payment_adyen_paybylink/__init__.py b/addons/payment_adyen_paybylink/__init__.py
new file mode 100644
index 0000000000..2ee3b53474
--- /dev/null
+++ b/addons/payment_adyen_paybylink/__init__.py
@@ -0,0 +1,17 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra import api, SUPERUSER_ID
+
+from . import models
+from . import controllers
+
+def _post_init_hook(cr, registry):
+ """ Disable the acquirer because new mandatory fields are added in this module. """
+ env = api.Environment(cr, SUPERUSER_ID, {})
+ acquirers = env['payment.acquirer'].search([
+ ('provider', '=', 'adyen'),
+ ('state', '!=', 'disabled'),
+ ])
+ acquirers.write({
+ 'state': 'disabled',
+ })
diff --git a/addons/payment_adyen_paybylink/__manifest__.py b/addons/payment_adyen_paybylink/__manifest__.py
new file mode 100644
index 0000000000..02b5b8711c
--- /dev/null
+++ b/addons/payment_adyen_paybylink/__manifest__.py
@@ -0,0 +1,18 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+{
+ 'name': "Adyen Payment Acquirer/Pay by Link Patch",
+ 'category': 'Accounting/Payment',
+ 'summary': "Payment Acquirer: Adyen Pay by Link Patch",
+ 'version': '1.0',
+ 'description': """
+This module migrates the Adyen implementation from the Hosted Payment Pages API to the Pay by Link
+API.
+ """,
+ 'depends': ['payment_adyen'],
+ 'data': [
+ 'views/payment_views.xml',
+ ],
+ 'post_init_hook': '_post_init_hook',
+ 'auto_install': True,
+ 'license': 'LGPL-3'
+}
diff --git a/addons/payment_adyen_paybylink/const.py b/addons/payment_adyen_paybylink/const.py
new file mode 100644
index 0000000000..7f2e96cd72
--- /dev/null
+++ b/addons/payment_adyen_paybylink/const.py
@@ -0,0 +1,7 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+# Endpoints of the API.
+# See https://docs.adyen.com/api-explorer/#/CheckoutService/v68/overview for Checkout API
+API_ENDPOINT_VERSIONS = {
+ '/paymentLinks': 68, # Checkout API
+}
diff --git a/addons/payment_adyen_paybylink/controllers/__init__.py b/addons/payment_adyen_paybylink/controllers/__init__.py
new file mode 100644
index 0000000000..e066a53a05
--- /dev/null
+++ b/addons/payment_adyen_paybylink/controllers/__init__.py
@@ -0,0 +1,3 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import main
diff --git a/addons/payment_adyen_paybylink/controllers/main.py b/addons/payment_adyen_paybylink/controllers/main.py
new file mode 100644
index 0000000000..08106d7f36
--- /dev/null
+++ b/addons/payment_adyen_paybylink/controllers/main.py
@@ -0,0 +1,135 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+import base64
+import binascii
+import hashlib
+import hmac
+import logging
+import pprint
+
+from werkzeug.exceptions import Forbidden
+
+from flectra.exceptions import ValidationError
+from flectra.http import request, route
+
+from flectra.addons.payment_adyen.controllers.main import AdyenController
+
+_logger = logging.getLogger(__name__)
+
+
+class AdyenPayByLinkController(AdyenController):
+
+ @route()
+ def adyen_notification(self, **post):
+ """ Process the data sent by Adyen to the webhook based on the event code.
+
+ See https://docs.adyen.com/development-resources/webhooks/understand-notifications for the
+ exhaustive list of event codes.
+
+ :return: The '[accepted]' string to acknowledge the notification
+ :rtype: str
+ """
+ _logger.info(
+ "notification received from Adyen with data:\n%s", pprint.pformat(post)
+ )
+ try:
+ # Check the integrity of the notification
+ tx_sudo = request.env['payment.transaction'].sudo()._adyen_form_get_tx_from_data(post)
+ self._verify_notification_signature(post, tx_sudo)
+
+ # Check whether the event of the notification succeeded and reshape the notification
+ # data for parsing
+ event_code = post['eventCode']
+ if event_code == 'AUTHORISATION' and post['success'] == 'true':
+ post['authResult'] = 'AUTHORISED'
+
+ # Handle the notification data
+ request.env['payment.transaction'].sudo().form_feedback(post, 'adyen')
+ except ValidationError: # Acknowledge the notification to avoid getting spammed
+ _logger.exception("unable to handle the notification data; skipping to acknowledge")
+
+ return '[accepted]' # Acknowledge the notification
+
+ @staticmethod
+ def _verify_notification_signature(notification_data, tx_sudo):
+ """ Check that the received signature matches the expected one.
+
+ :param dict notification_data: The notification payload containing the received signature
+ :param recordset tx_sudo: The sudoed transaction referenced by the notification data, as a
+ `payment.transaction` record
+ :return: None
+ :raise: :class:`werkzeug.exceptions.Forbidden` if the signatures don't match
+ """
+ # Retrieve the received signature from the payload
+ received_signature = notification_data.get('additionalData.hmacSignature')
+ if not received_signature:
+ _logger.warning("received notification with missing signature")
+ raise Forbidden()
+
+ # Compare the received signature with the expected signature computed from the payload
+ hmac_key = tx_sudo.acquirer_id.adyen_hmac_key
+ expected_signature = AdyenPayByLinkController._compute_signature(
+ notification_data, hmac_key
+ )
+ if not hmac.compare_digest(received_signature, expected_signature):
+ _logger.warning("received notification with invalid signature")
+ raise Forbidden()
+
+ @staticmethod
+ def _compute_signature(payload, hmac_key):
+ """ Compute the signature from the payload.
+
+ See https://docs.adyen.com/development-resources/webhooks/verify-hmac-signatures
+
+ :param dict payload: The notification payload
+ :param str hmac_key: The HMAC key of the acquirer handling the transaction
+ :return: The computed signature
+ :rtype: str
+ """
+ def _flatten_dict(_value, _path_base='', _separator='.'):
+ """ Recursively generate a flat representation of a dict.
+
+ :param Object _value: The value to flatten. A dict or an already flat value
+ :param str _path_base: They base path for keys of _value, including preceding separators
+ :param str _separator: The string to use as a separator in the key path
+ """
+ if isinstance(_value, dict): # The inner value is a dict, flatten it
+ _path_base = _path_base if not _path_base else _path_base + _separator
+ for _key in _value:
+ yield from _flatten_dict(_value[_key], _path_base + str(_key))
+ else: # The inner value cannot be flattened, yield it
+ yield _path_base, _value
+
+ def _to_escaped_string(_value):
+ """ Escape payload values that are using illegal symbols and cast them to string.
+
+ String values containing `\\` or `:` are prefixed with `\\`.
+ Empty values (`None`) are replaced by an empty string.
+
+ :param Object _value: The value to escape
+ :return: The escaped value
+ :rtype: string
+ """
+ if isinstance(_value, str):
+ return _value.replace('\\', '\\\\').replace(':', '\\:')
+ elif _value is None:
+ return ''
+ else:
+ return str(_value)
+
+ signature_keys = [
+ 'pspReference', 'originalReference', 'merchantAccountCode', 'merchantReference',
+ 'value', 'currency', 'eventCode', 'success'
+ ]
+ # Build the list of signature values as per the list of required signature keys
+ signature_values = [payload.get(key) for key in signature_keys]
+ # Escape values using forbidden symbols
+ escaped_values = [_to_escaped_string(value) for value in signature_values]
+ # Concatenate values together with ':' as delimiter
+ signing_string = ':'.join(escaped_values)
+ # Convert the HMAC key to the binary representation
+ binary_hmac_key = binascii.a2b_hex(hmac_key.encode('ascii'))
+ # Calculate the HMAC with the binary representation of the signing string with SHA-256
+ binary_hmac = hmac.new(binary_hmac_key, signing_string.encode('utf-8'), hashlib.sha256)
+ # Calculate the signature by encoding the result with Base64
+ return base64.b64encode(binary_hmac.digest()).decode()
diff --git a/addons/payment_adyen_paybylink/i18n/payment_adyen_paybylink.pot b/addons/payment_adyen_paybylink/i18n/payment_adyen_paybylink.pot
new file mode 100644
index 0000000000..c67213d6c6
--- /dev/null
+++ b/addons/payment_adyen_paybylink/i18n/payment_adyen_paybylink.pot
@@ -0,0 +1,122 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * payment_adyen_paybylink
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 14.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2022-06-27 11:46+0000\n"
+"PO-Revision-Date: 2022-06-27 11:46+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: payment_adyen_paybylink
+#: code:addons/payment_adyen_paybylink/models/payment_transaction.py:0
+#, python-format
+msgid "; multiple order found"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: code:addons/payment_adyen_paybylink/models/payment_transaction.py:0
+#, python-format
+msgid "; no order found"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_acquirer__adyen_api_key
+msgid "API Key"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: code:addons/payment_adyen_paybylink/models/payment_transaction.py:0
+#, python-format
+msgid "Adyen: received data for reference %s"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: code:addons/payment_adyen_paybylink/models/payment_transaction.py:0
+#, python-format
+msgid ""
+"Adyen: received data with missing reference (%s) or missing pspReference "
+"(%s)"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_acquirer__adyen_checkout_api_url
+msgid "Checkout API URL"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: code:addons/payment_adyen_paybylink/models/payment_acquirer.py:0
+#, python-format
+msgid "Could not establish the connection to the API."
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_acquirer__display_name
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_transaction__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_acquirer__adyen_hmac_key
+msgid "HMAC Key"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_acquirer__id
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_transaction__id
+msgid "ID"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_acquirer____last_update
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_transaction____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model,name:payment_adyen_paybylink.model_payment_acquirer
+msgid "Payment Acquirer"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model,name:payment_adyen_paybylink.model_payment_transaction
+msgid "Payment Transaction"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_acquirer__adyen_skin_code
+msgid "Skin Code"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,field_description:payment_adyen_paybylink.field_payment_acquirer__adyen_skin_hmac_key
+msgid "Skin HMAC Key"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,help:payment_adyen_paybylink.field_payment_acquirer__adyen_api_key
+msgid "The API key of the webservice user"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,help:payment_adyen_paybylink.field_payment_acquirer__adyen_hmac_key
+msgid "The HMAC key of the webhook"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: model:ir.model.fields,help:payment_adyen_paybylink.field_payment_acquirer__adyen_checkout_api_url
+msgid "The base URL for the Checkout API endpoints"
+msgstr ""
+
+#. module: payment_adyen_paybylink
+#: code:addons/payment_adyen_paybylink/models/payment_acquirer.py:0
+#, python-format
+msgid "The communication with the API failed."
+msgstr ""
diff --git a/addons/payment_adyen_paybylink/models/__init__.py b/addons/payment_adyen_paybylink/models/__init__.py
new file mode 100644
index 0000000000..ac8870d7b2
--- /dev/null
+++ b/addons/payment_adyen_paybylink/models/__init__.py
@@ -0,0 +1,4 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import payment_acquirer
+from . import payment_transaction
diff --git a/addons/payment_adyen_paybylink/models/payment_acquirer.py b/addons/payment_adyen_paybylink/models/payment_acquirer.py
new file mode 100644
index 0000000000..83176d1fef
--- /dev/null
+++ b/addons/payment_adyen_paybylink/models/payment_acquirer.py
@@ -0,0 +1,179 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+import logging
+import re
+import requests
+
+from werkzeug import urls
+
+from flectra import _, api, fields, models
+from flectra.exceptions import ValidationError
+
+from flectra.addons.payment_adyen_paybylink import utils as adyen_utils
+from flectra.addons.payment_adyen_paybylink.const import API_ENDPOINT_VERSIONS
+
+
+_logger = logging.getLogger(__name__)
+
+
+class PaymentAcquirer(models.Model):
+ _inherit = 'payment.acquirer'
+
+ adyen_api_key = fields.Char(
+ string="API Key",
+ help="The API key of the webservice user",
+ required_if_provider='adyen',
+ groups='base.group_user',
+ )
+ adyen_hmac_key = fields.Char(
+ string="HMAC Key",
+ help="The HMAC key of the webhook",
+ required_if_provider='adyen',
+ groups='base.group_user',
+ )
+ adyen_checkout_api_url = fields.Char(
+ string="Checkout API URL",
+ help="The base URL for the Checkout API endpoints",
+ required_if_provider='adyen',
+ )
+ # We set a default for the now unused key fields rather than making them not required to avoid
+ # the error log at DB init when the ORM tries to set the 'NOT NULL' constraint on those fields.
+ adyen_skin_code = fields.Char(default="Do not use this field")
+ adyen_skin_hmac_key = fields.Char(default="Do not use this field")
+
+ @api.model_create_multi
+ def create(self, values_list):
+ for values in values_list:
+ self._adyen_trim_api_urls(values)
+ return super().create(values_list)
+
+ def write(self, values):
+ self._adyen_trim_api_urls(values)
+ # We set a default for the now unused key fields rather than making them not required to
+ # avoid the error log at DB init when the ORM tries to set the 'NOT NULL' constraint on
+ # those fields.
+ values.update(
+ adyen_skin_code="Do not use this field",
+ adyen_skin_hmac_key="Do not use this field",
+ )
+ return super().write(values)
+
+ @api.model
+ def _adyen_trim_api_urls(self, values):
+ """ Remove the version and the endpoint from the url of Adyen API fields.
+
+ :param dict values: The create or write values
+ :return: None
+ """
+ # Test the value in case we're duplicating an acquirer
+ if values.get('adyen_checkout_api_url'):
+ values['adyen_checkout_api_url'] = re.sub(
+ r'[vV]\d+(/.*)?', '', values['adyen_checkout_api_url']
+ )
+
+ def adyen_form_generate_values(self, values):
+ base_url = self.get_base_url()
+
+ payment_amount = self._adyen_convert_amount(values['amount'], values['currency'])
+ values['adyen_paybylink_data'] = {
+ 'reference': values['reference'],
+ 'amount': {
+ 'value': '%d' % payment_amount,
+ 'currency': values['currency'] and values['currency'].name or '',
+ },
+ 'merchantAccount': self.adyen_merchant_account,
+ 'shopperLocale': values.get('partner_lang', ''),
+ 'returnUrl': urls.url_join(base_url, '/payment/process'),
+ 'shopperEmail': values.get('partner_email') or values.get('billing_partner_email', ''),
+ 'shopperReference': self._adyen_compute_shopper_reference(values.get('partner_id')),
+ 'shopperName': {
+ 'firstName': values.get('partner_first_name'),
+ 'lastName': values.get('partner_last_name'),
+ },
+ 'telephoneNumber': values.get('partner_phone'),
+ 'billingAddress': adyen_utils.format_partner_address(values.get('billing_partner')),
+ 'deliveryAddress': adyen_utils.format_partner_address(values.get('partner')),
+ }
+
+ return values
+
+ def adyen_get_form_action_url(self):
+ """ Override of adyen_get_form_action_url """
+ form_action_url_values = self._context.get('form_action_url_values')
+ if form_action_url_values:
+ return self._adyen_get_paybylink(form_action_url_values['adyen_paybylink_data'])
+ return False
+
+ def _adyen_get_paybylink(self, data):
+ paybylink_response = self._adyen_make_request(
+ url_field_name='adyen_checkout_api_url',
+ endpoint='/paymentLinks',
+ payload=data,
+ )
+ return paybylink_response['url']
+
+ def _adyen_make_request(
+ self, url_field_name, endpoint, endpoint_param=None, payload=None, method='POST'
+ ):
+ """ Make a request to Adyen API at the specified endpoint.
+
+ Note: self.ensure_one()
+
+ :param str url_field_name: The name of the field holding the base URL for the request
+ :param str endpoint: The endpoint to be reached by the request
+ :param str endpoint_param: A variable required by some endpoints which are interpolated with
+ it if provided. For example, the acquirer reference of the source
+ transaction for the '/payments/{}/refunds' endpoint.
+ :param dict payload: The payload of the request
+ :param str method: The HTTP method of the request
+ :return: The JSON-formatted content of the response
+ :rtype: dict
+ :raise: ValidationError if an HTTP error occurs
+ """
+
+ def _build_url(_base_url, _version, _endpoint):
+ """ Build an API URL by appending the version and endpoint to a base URL.
+
+ The final URL follows this pattern: `<_base>/V<_version>/<_endpoint>`.
+
+ :param str _base_url: The base of the url prefixed with `https://`
+ :param int _version: The version of the endpoint
+ :param str _endpoint: The endpoint of the URL.
+ :return: The final URL
+ :rtype: str
+ """
+ _base = _base_url.rstrip('/') # Remove potential trailing slash
+ _endpoint = _endpoint.lstrip('/') # Remove potential leading slash
+ return f'{_base}/V{_version}/{_endpoint}'
+
+ self.ensure_one()
+
+ base_url = self[url_field_name] # Restrict request URL to the stored API URL fields
+ version = API_ENDPOINT_VERSIONS[endpoint]
+ endpoint = endpoint if not endpoint_param else endpoint.format(endpoint_param)
+ url = _build_url(base_url, version, endpoint)
+ headers = {'X-API-Key': self.adyen_api_key}
+ try:
+ response = requests.request(method, url, json=payload, headers=headers, timeout=60)
+ response.raise_for_status()
+ except requests.exceptions.ConnectionError:
+ _logger.exception("unable to reach endpoint at %s", url)
+ raise ValidationError("Adyen: " + _("Could not establish the connection to the API."))
+ except requests.exceptions.HTTPError as error:
+ _logger.exception(
+ "invalid API request at %s with data %s: %s", url, payload, error.response.text
+ )
+ raise ValidationError("Adyen: " + _("The communication with the API failed."))
+ return response.json()
+
+ def _adyen_compute_shopper_reference(self, partner_id):
+ """ Compute a unique reference of the partner for Adyen.
+
+ This is used for the `shopperReference` field in communications with Adyen and stored in the
+ `adyen_shopper_reference` field on `payment.token` if the payment method is tokenized.
+
+ :param recordset partner_id: The partner making the transaction, as a `res.partner` id
+ :return: The unique reference for the partner
+ :rtype: str
+ """
+ return 'FLECTRA_PARTNER_{partner_id}'.format(partner_id=partner_id)
diff --git a/addons/payment_adyen_paybylink/models/payment_transaction.py b/addons/payment_adyen_paybylink/models/payment_transaction.py
new file mode 100644
index 0000000000..d7edd3bf13
--- /dev/null
+++ b/addons/payment_adyen_paybylink/models/payment_transaction.py
@@ -0,0 +1,61 @@
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+import logging
+
+from flectra import _, api, fields, models
+from flectra.exceptions import ValidationError
+
+
+_logger = logging.getLogger(__name__)
+
+
+class PaymentTransaction(models.Model):
+ _inherit = 'payment.transaction'
+
+ @api.model
+ def adyen_create(self, values):
+ """
+ When the customer lands on the `/payment/process` route, `/payment/process/poll` try to find
+ the transaction whose `date` field is between yesterday and now.
+
+ Since the `date` field is only set when the state of the transaction is changed, if the
+ customer comes back before the webhook, he will see a "transaction not found" page because
+ the value of the `date` field would be `False`.
+ """
+ return dict(date=fields.Datetime.now())
+
+ # --------------------------------------------------
+ # FORM RELATED METHODS
+ # --------------------------------------------------
+
+ @api.model
+ def _adyen_form_get_tx_from_data(self, data):
+ """ Override of _adyen_form_get_tx_from_data """
+ reference, psp_reference = data.get('merchantReference'), data.get('pspReference')
+ if not reference or not psp_reference:
+ error_msg = _(
+ "Adyen: received data with missing reference (%s) or missing pspReference (%s)"
+ ) % (reference, psp_reference)
+ _logger.info(error_msg)
+ raise ValidationError(error_msg)
+
+ tx = self.env['payment.transaction'].search([
+ ('reference', '=', reference), ('provider', '=', 'adyen')
+ ])
+ if not tx or len(tx) > 1:
+ error_msg = _("Adyen: received data for reference %s") % reference
+ if not tx:
+ error_msg += _("; no order found")
+ else:
+ error_msg += _("; multiple order found")
+ _logger.info(error_msg)
+ raise ValidationError(error_msg)
+
+ return tx
+
+ def _adyen_form_get_invalid_parameters(self, data):
+ """ Override of _adyen_form_get_invalid_parameters to disable this method.
+
+ The pay-by-link implementation doesn't need or want to check for invalid parameters.
+ """
+ return []
diff --git a/addons/payment_adyen_paybylink/utils.py b/addons/payment_adyen_paybylink/utils.py
new file mode 100644
index 0000000000..c62e56f975
--- /dev/null
+++ b/addons/payment_adyen_paybylink/utils.py
@@ -0,0 +1,72 @@
+import re
+
+from flectra import _
+from flectra.exceptions import UserError
+
+
+def format_partner_address(partner):
+ """ Format the partner address to comply with the payload structure of the API request.
+ :param res.partner partner: The partner making the payment.
+ :return: The formatted partner address.
+ :rtype: dict
+ """
+ STREET_FORMAT = '%(street_number)s/%(street_number2)s %(street_name)s'
+ street_data = split_street_with_params(partner.street, STREET_FORMAT)
+ return {
+ 'city': partner.city,
+ 'country': partner.country_id.code or 'ZZ', # 'ZZ' if the country is not known.
+ 'stateOrProvince': partner.state_id.code,
+ 'postalCode': partner.zip,
+ 'street': street_data['street_name'],
+ 'houseNumberOrName': street_data['street_number'],
+ }
+
+
+# The method is copy-pasted from `base_address_extended` with small modifications.
+def split_street_with_params(street_raw, street_format):
+ street_fields = ['street_name', 'street_number', 'street_number2']
+ vals = {}
+ previous_pos = 0
+ field_name = None
+ # iter on fields in street_format, detected as '%()s'
+ for re_match in re.finditer(r'%\(\w+\)s', street_format):
+ field_pos = re_match.start()
+ if not field_name:
+ #first iteration: remove the heading chars
+ street_raw = street_raw[field_pos:]
+
+ # get the substring between 2 fields, to be used as separator
+ separator = street_format[previous_pos:field_pos]
+ field_value = None
+ if separator and field_name:
+ #maxsplit set to 1 to unpack only the first element and let the rest untouched
+ tmp = street_raw.split(separator, 1)
+ if previous_greedy in vals:
+ # attach part before space to preceding greedy field
+ append_previous, sep, tmp[0] = tmp[0].rpartition(' ')
+ street_raw = separator.join(tmp)
+ vals[previous_greedy] += sep + append_previous
+ if len(tmp) == 2:
+ field_value, street_raw = tmp
+ vals[field_name] = field_value
+ if field_value or not field_name:
+ previous_greedy = None
+ if field_name == 'street_name' and separator == ' ':
+ previous_greedy = field_name
+ # select next field to find (first pass OR field found)
+ # [2:-2] is used to remove the extra chars '%(' and ')s'
+ field_name = re_match.group()[2:-2]
+ else:
+ # value not found: keep looking for the same field
+ pass
+ if field_name not in street_fields:
+ raise UserError(_("Unrecognized field %s in street format.", field_name))
+ previous_pos = re_match.end()
+
+ # last field value is what remains in street_raw minus trailing chars in street_format
+ trailing_chars = street_format[previous_pos:]
+ if trailing_chars and street_raw.endswith(trailing_chars):
+ vals[field_name] = street_raw[:-len(trailing_chars)]
+ else:
+ vals[field_name] = street_raw
+ return vals
diff --git a/addons/payment_adyen_paybylink/views/payment_views.xml b/addons/payment_adyen_paybylink/views/payment_views.xml
new file mode 100644
index 0000000000..ce67699504
--- /dev/null
+++ b/addons/payment_adyen_paybylink/views/payment_views.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+ acquirer.form.adyen
+ payment.acquirer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/point_of_sale/tools/posbox/configuration/connect_to_server.sh b/addons/point_of_sale/tools/posbox/configuration/connect_to_server.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/configuration/connect_to_server_wifi.sh b/addons/point_of_sale/tools/posbox/configuration/connect_to_server_wifi.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/configuration/connect_to_wifi.sh b/addons/point_of_sale/tools/posbox/configuration/connect_to_wifi.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/configuration/keep_wifi_alive.sh b/addons/point_of_sale/tools/posbox/configuration/keep_wifi_alive.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/configuration/led_status.sh b/addons/point_of_sale/tools/posbox/configuration/led_status.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/configuration/posbox_update.sh b/addons/point_of_sale/tools/posbox/configuration/posbox_update.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh b/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/configuration/upgrade.sh b/addons/point_of_sale/tools/posbox/configuration/upgrade.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/configuration/wireless_ap.sh b/addons/point_of_sale/tools/posbox/configuration/wireless_ap.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/cron.daily/flectra b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/cron.daily/flectra
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/rc.local b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/rc.local
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/flectra b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/flectra
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/timesyncd b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/timesyncd
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/rc.local b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/rc.local
old mode 100644
new mode 100755
diff --git a/addons/point_of_sale/tools/posbox/posbox_create_image.sh b/addons/point_of_sale/tools/posbox/posbox_create_image.sh
old mode 100644
new mode 100755
diff --git a/addons/project_billing_options/__init__.py b/addons/project_billing_options/__init__.py
index a7abb51635..9ede2bf743 100644
--- a/addons/project_billing_options/__init__.py
+++ b/addons/project_billing_options/__init__.py
@@ -1,4 +1,4 @@
# coding: utf-8
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import models
\ No newline at end of file
diff --git a/addons/project_billing_options/__manifest__.py b/addons/project_billing_options/__manifest__.py
index e7b90e952f..4dfb7abd9d 100644
--- a/addons/project_billing_options/__manifest__.py
+++ b/addons/project_billing_options/__manifest__.py
@@ -1,5 +1,5 @@
# coding: utf-8
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Project Billing Options',
'summary': 'Manage Timesheets and Calculate Profitability '
diff --git a/addons/project_billing_options/models/__init__.py b/addons/project_billing_options/models/__init__.py
index d312a156ff..6ec57ccc0d 100644
--- a/addons/project_billing_options/models/__init__.py
+++ b/addons/project_billing_options/models/__init__.py
@@ -1,5 +1,5 @@
# coding: utf-8
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import hr_timesheet_invoice_factor
from . import project
\ No newline at end of file
diff --git a/addons/project_billing_options/models/hr_timesheet_invoice_factor.py b/addons/project_billing_options/models/hr_timesheet_invoice_factor.py
index ed1dad5181..f6563138f9 100644
--- a/addons/project_billing_options/models/hr_timesheet_invoice_factor.py
+++ b/addons/project_billing_options/models/hr_timesheet_invoice_factor.py
@@ -1,5 +1,5 @@
# coding: utf-8
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import models, fields, api
from flectra.tools import float_round
from dateutil.relativedelta import relativedelta
diff --git a/addons/project_billing_options/models/project.py b/addons/project_billing_options/models/project.py
index afde77b929..ad7e1abc85 100644
--- a/addons/project_billing_options/models/project.py
+++ b/addons/project_billing_options/models/project.py
@@ -1,5 +1,5 @@
# coding: utf-8
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import models, fields, api, _
from flectra.osv import expression
from flectra.addons.web.controllers.main import clean_action
diff --git a/addons/project_scrum/__init__.py b/addons/project_scrum/__init__.py
index 5bd335ccc7..aaea41f08e 100755
--- a/addons/project_scrum/__init__.py
+++ b/addons/project_scrum/__init__.py
@@ -1,3 +1,3 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import models
diff --git a/addons/project_scrum/__manifest__.py b/addons/project_scrum/__manifest__.py
index 6cb08b41d7..5f1048acbb 100755
--- a/addons/project_scrum/__manifest__.py
+++ b/addons/project_scrum/__manifest__.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Project Scrum',
diff --git a/addons/project_scrum/models/__init__.py b/addons/project_scrum/models/__init__.py
index 161e1a7a99..04d8738893 100755
--- a/addons/project_scrum/models/__init__.py
+++ b/addons/project_scrum/models/__init__.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import project_sprint
from . import project_story
diff --git a/addons/project_scrum/models/project_sprint.py b/addons/project_scrum/models/project_sprint.py
index 4806a8c8cb..6ad28d38b6 100755
--- a/addons/project_scrum/models/project_sprint.py
+++ b/addons/project_scrum/models/project_sprint.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import models, fields, api, _
from flectra.exceptions import ValidationError
diff --git a/addons/project_scrum/models/project_story.py b/addons/project_scrum/models/project_story.py
index 8eea4046f1..4670bdd4b3 100755
--- a/addons/project_scrum/models/project_story.py
+++ b/addons/project_scrum/models/project_story.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import fields, models, api, _
diff --git a/addons/project_scrum/models/project_team.py b/addons/project_scrum/models/project_team.py
index e687baa421..4f626a6810 100755
--- a/addons/project_scrum/models/project_team.py
+++ b/addons/project_scrum/models/project_team.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import models, fields
diff --git a/addons/project_scrum/models/release_planning.py b/addons/project_scrum/models/release_planning.py
index ca80109a74..532f5e256f 100755
--- a/addons/project_scrum/models/release_planning.py
+++ b/addons/project_scrum/models/release_planning.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import models, fields
diff --git a/addons/project_scrum/models/retrospective.py b/addons/project_scrum/models/retrospective.py
index ec9971c9ab..53375fb3f1 100755
--- a/addons/project_scrum/models/retrospective.py
+++ b/addons/project_scrum/models/retrospective.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import models, fields, api
diff --git a/addons/project_scrum/models/retrospective_method.py b/addons/project_scrum/models/retrospective_method.py
index 6709d4f961..3695a5c993 100755
--- a/addons/project_scrum/models/retrospective_method.py
+++ b/addons/project_scrum/models/retrospective_method.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import models, fields
diff --git a/addons/project_scrum/tests/__init__.py b/addons/project_scrum/tests/__init__.py
index 4ae6d49f23..4f0a3ce743 100755
--- a/addons/project_scrum/tests/__init__.py
+++ b/addons/project_scrum/tests/__init__.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from .test_scrum_common import TestScrumCommon
from .test_scrum_team import TestScrumTeam
diff --git a/addons/project_scrum/tests/test_scrum_common.py b/addons/project_scrum/tests/test_scrum_common.py
index a2c5b76ea1..7ccd9bedf4 100644
--- a/addons/project_scrum/tests/test_scrum_common.py
+++ b/addons/project_scrum/tests/test_scrum_common.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra.tests import common
diff --git a/addons/project_scrum/tests/test_scrum_release_planning.py b/addons/project_scrum/tests/test_scrum_release_planning.py
index cd1e5e4dbc..6b0d99acaf 100644
--- a/addons/project_scrum/tests/test_scrum_release_planning.py
+++ b/addons/project_scrum/tests/test_scrum_release_planning.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from logging import info
diff --git a/addons/project_scrum/tests/test_scrum_sprint.py b/addons/project_scrum/tests/test_scrum_sprint.py
index 751c456605..ad05055820 100644
--- a/addons/project_scrum/tests/test_scrum_sprint.py
+++ b/addons/project_scrum/tests/test_scrum_sprint.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from logging import info
diff --git a/addons/project_scrum/tests/test_scrum_story.py b/addons/project_scrum/tests/test_scrum_story.py
index c3adbaafd0..e26471e71b 100644
--- a/addons/project_scrum/tests/test_scrum_story.py
+++ b/addons/project_scrum/tests/test_scrum_story.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from logging import info
diff --git a/addons/project_scrum/tests/test_scrum_task.py b/addons/project_scrum/tests/test_scrum_task.py
index d2f7665616..8e7c790fbb 100644
--- a/addons/project_scrum/tests/test_scrum_task.py
+++ b/addons/project_scrum/tests/test_scrum_task.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from logging import info
diff --git a/addons/project_scrum/tests/test_scrum_team.py b/addons/project_scrum/tests/test_scrum_team.py
index d667e6b103..9e0a773af9 100644
--- a/addons/project_scrum/tests/test_scrum_team.py
+++ b/addons/project_scrum/tests/test_scrum_team.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from logging import info
diff --git a/addons/recurring/tests/test_recurring.py b/addons/recurring/tests/test_recurring.py
index 7861ea421f..08cc0b24f6 100644
--- a/addons/recurring/tests/test_recurring.py
+++ b/addons/recurring/tests/test_recurring.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import _
from flectra.exceptions import UserError
diff --git a/addons/recurring_account/__init__.py b/addons/recurring_account/__init__.py
index 5bd335ccc7..aaea41f08e 100644
--- a/addons/recurring_account/__init__.py
+++ b/addons/recurring_account/__init__.py
@@ -1,3 +1,3 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import models
diff --git a/addons/recurring_account/__manifest__.py b/addons/recurring_account/__manifest__.py
index cd53102d12..f31b470df2 100644
--- a/addons/recurring_account/__manifest__.py
+++ b/addons/recurring_account/__manifest__.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Account Invoice Recurrings',
diff --git a/addons/recurring_account/models/__init__.py b/addons/recurring_account/models/__init__.py
index 382e28b9e2..abc6fa0999 100644
--- a/addons/recurring_account/models/__init__.py
+++ b/addons/recurring_account/models/__init__.py
@@ -1,3 +1,3 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import account_invoice
diff --git a/addons/recurring_purchase/__init__.py b/addons/recurring_purchase/__init__.py
index 5bd335ccc7..aaea41f08e 100644
--- a/addons/recurring_purchase/__init__.py
+++ b/addons/recurring_purchase/__init__.py
@@ -1,3 +1,3 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import models
diff --git a/addons/recurring_purchase/__manifest__.py b/addons/recurring_purchase/__manifest__.py
index 43f7453485..1c5002ec21 100644
--- a/addons/recurring_purchase/__manifest__.py
+++ b/addons/recurring_purchase/__manifest__.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Purchase Order Recurring',
diff --git a/addons/recurring_purchase/models/__init__.py b/addons/recurring_purchase/models/__init__.py
index f7ae479d76..1265038d5f 100644
--- a/addons/recurring_purchase/models/__init__.py
+++ b/addons/recurring_purchase/models/__init__.py
@@ -1,3 +1,3 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import purchase
diff --git a/addons/recurring_purchase/models/purchase.py b/addons/recurring_purchase/models/purchase.py
index c263ef2011..436199e4fc 100644
--- a/addons/recurring_purchase/models/purchase.py
+++ b/addons/recurring_purchase/models/purchase.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import api, models, fields
diff --git a/addons/recurring_purchase/tests/__init__.py b/addons/recurring_purchase/tests/__init__.py
index 6bebbbee10..1371c97f17 100644
--- a/addons/recurring_purchase/tests/__init__.py
+++ b/addons/recurring_purchase/tests/__init__.py
@@ -1,3 +1,3 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import test_puchase_recurring
diff --git a/addons/recurring_purchase/tests/test_puchase_recurring.py b/addons/recurring_purchase/tests/test_puchase_recurring.py
index 604a50b85e..acb9720ea6 100644
--- a/addons/recurring_purchase/tests/test_puchase_recurring.py
+++ b/addons/recurring_purchase/tests/test_puchase_recurring.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra.tests.common import TransactionCase
diff --git a/addons/recurring_sale/__init__.py b/addons/recurring_sale/__init__.py
index 5bd335ccc7..aaea41f08e 100644
--- a/addons/recurring_sale/__init__.py
+++ b/addons/recurring_sale/__init__.py
@@ -1,3 +1,3 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import models
diff --git a/addons/recurring_sale/__manifest__.py b/addons/recurring_sale/__manifest__.py
index 505804dfc4..992dd05efa 100644
--- a/addons/recurring_sale/__manifest__.py
+++ b/addons/recurring_sale/__manifest__.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Sale Order Recurring',
diff --git a/addons/recurring_sale/models/__init__.py b/addons/recurring_sale/models/__init__.py
index 55c8294e8d..b5543da16f 100644
--- a/addons/recurring_sale/models/__init__.py
+++ b/addons/recurring_sale/models/__init__.py
@@ -1,3 +1,3 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import sale
diff --git a/addons/recurring_sale/models/sale.py b/addons/recurring_sale/models/sale.py
index ef20d51798..b04a7c06a8 100644
--- a/addons/recurring_sale/models/sale.py
+++ b/addons/recurring_sale/models/sale.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra import api, models, fields
diff --git a/addons/recurring_sale/tests/__init__.py b/addons/recurring_sale/tests/__init__.py
index 9c31452d74..d60b35cb1a 100644
--- a/addons/recurring_sale/tests/__init__.py
+++ b/addons/recurring_sale/tests/__init__.py
@@ -1,3 +1,3 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import test_sale_recurring
diff --git a/addons/recurring_sale/tests/test_sale_recurring.py b/addons/recurring_sale/tests/test_sale_recurring.py
index 97ec2e3b37..868ece8cc4 100644
--- a/addons/recurring_sale/tests/test_sale_recurring.py
+++ b/addons/recurring_sale/tests/test_sale_recurring.py
@@ -1,4 +1,4 @@
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra.tests.common import TransactionCase
diff --git a/addons/sale_mrp_margin/__init__.py b/addons/sale_mrp_margin/__init__.py
new file mode 100644
index 0000000000..7eb1309519
--- /dev/null
+++ b/addons/sale_mrp_margin/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
diff --git a/addons/sale_mrp_margin/__manifest__.py b/addons/sale_mrp_margin/__manifest__.py
new file mode 100644
index 0000000000..31037ebf90
--- /dev/null
+++ b/addons/sale_mrp_margin/__manifest__.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+{
+ 'name': "Sale Mrp Margin",
+ 'category': 'Sales/Sales',
+ 'version': '0.1',
+ 'description': 'Handle BoM prices to compute sale margin.',
+ 'depends': ['sale_mrp', 'sale_stock_margin'],
+ 'license': 'LGPL-3',
+}
diff --git a/addons/sale_mrp_margin/tests/__init__.py b/addons/sale_mrp_margin/tests/__init__.py
new file mode 100644
index 0000000000..a69498b588
--- /dev/null
+++ b/addons/sale_mrp_margin/tests/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from . import test_sale_mrp_flow
diff --git a/addons/sale_mrp_margin/tests/test_sale_mrp_flow.py b/addons/sale_mrp_margin/tests/test_sale_mrp_flow.py
new file mode 100644
index 0000000000..877cb25672
--- /dev/null
+++ b/addons/sale_mrp_margin/tests/test_sale_mrp_flow.py
@@ -0,0 +1,52 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
+
+from flectra.addons.sale_mrp.tests import test_sale_mrp_flow
+from flectra.tests import common, Form
+
+
+@common.tagged('post_install', '-at_install')
+class TestSaleMrpFlow(test_sale_mrp_flow.TestSaleMrpFlow):
+
+ def test_kit_cost_calculation(self):
+ """ Check that the average cost price is computed correctly after SO confirmation:
+ BOM 1:
+ - 1 unit of “super kit”:
+ - 2 units of “component a”
+ BOM 2:
+ - 1 unit of “component a”:
+ - 3 units of "component b"
+ 1 unit of "component b" = $10
+ 1 unit of "super kit" = 2 * 3 * $10 = *$60
+ """
+ super_kit = self._cls_create_product('Super Kit', self.uom_unit)
+ (super_kit + self.component_a + self.component_b).categ_id.property_cost_method = 'average'
+ self.env['mrp.bom'].create({
+ 'product_tmpl_id': self.component_a.product_tmpl_id.id,
+ 'product_qty': 1.0,
+ 'type': 'phantom',
+ 'bom_line_ids': [(0, 0, {
+ 'product_id': self.component_b.id,
+ 'product_qty': 3.0,
+ })]
+ })
+ self.env['mrp.bom'].create({
+ 'product_tmpl_id': super_kit.product_tmpl_id.id,
+ 'product_qty': 1.0,
+ 'type': 'phantom',
+ 'bom_line_ids': [(0, 0, {
+ 'product_id': self.component_a.id,
+ 'product_qty': 2.0,
+ })]
+ })
+ self.component_b.standard_price = 10
+ self.component_a.button_bom_cost()
+ super_kit.button_bom_cost()
+ so_form = Form(self.env['sale.order'])
+ so_form.partner_id = self.partner_a
+ with so_form.order_line.new() as line:
+ line.product_id = super_kit
+ so = so_form.save()
+ self.assertEqual(so.order_line.purchase_price, 60)
+ so.action_confirm()
+ self.assertEqual(so.order_line.purchase_price, 60)
diff --git a/addons/web/static/img/favicon.ico b/addons/web/static/img/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..ec39d4dd5348d3f2431717cced0361e1883c0bc0
GIT binary patch
literal 5430
zcmeHL&1(}u6rUI+6e+1l2&D&esS3rDh=`QbgCOdy$$licc+#tQDn;=kA~tC^`_V)Z
zPlBF27XJV}DC$APLs8MxCYq+nX7fo8<8QVtr0GVoF{wzh@XOA;eQ(~!%)a+FggD4P
zGBQGN`N*~XgdAlf-{$-&=rPcaW6D?<*gO#IF2@TbI41L`W^EqMVYriFV}I{m8|Uw&VgbwA(2E$Qqk%D97Fcbp*A~MR
zb?s3v^jNLAw!oc34Jntj5M?!`fUy-{FKF*(FP^VFh|tnv$gGFV_msr%neQue(;i(D
zPr~PMT@lAomyi9DxI?}0btM)U#s2!C$8TsMe=QmDm$lGDK@mKNzXvog#@=4&M*np>
zuZo7DZpImQH1|^G-ZMISGEX;cC@gS?S+4~DcImXRLoX_Vt6TbC&0cV3=7XQB$#6Tm
zO&+{^W8Kov*2ycv4BoBl@b!Qd>Z*meytA4f4?r8(0kM@CDx`N9@?pDKE~=%L?-T_P$~MyrhZC
z$jN#-7U=4`Xk}w28g!=TgU`ySL2N$|k1S%DW@iC5eS|$K^70kbh7;dA_*S#hIiL;t
R>A@NJzt2F!UjhGQ_#44bsXPDx
literal 0
HcmV?d00001
diff --git a/addons/web/static/img/flectra_logo_tiny.png b/addons/web/static/img/flectra_logo_tiny.png
new file mode 100644
index 0000000000000000000000000000000000000000..2b463cde549488ea9c35146df02aaea8860dbd96
GIT binary patch
literal 3207
zcmbVP2{@GbA0M%$atyh$VvH_gE@osH=Llu6j$%>fc!$YcW`-FmMLD8_XA7IFrS_k(
z
zWEzJ8AVe%Kh=xFH>_l8LH5?GYC_pHKO@L32wkBRITJB-+Z#3W>rXF&HxtVaAVU3&
zjARNYQb2%%ntn2Y#a*Ul^FO-@bQn@Z<|5Gul+2_hAdR|=<3{qBOTuYXB)|k%09(KZ
zvFK$iH;g0T@WVL&g?jn;-vofJC6Sh8{G~1|*0Kn`z&Q#ufX|8K
zQ32;DP)#G5HC((C4mCN1#u4(3|8M~yk_7+(E{mEO
z7&4TlFBml}4v)6lhQi{_QJk}Wjf$spcq}q#FoQ)7
z1&~~JC>*xzM!XY;$>D*5LG8@{xbNoVHsh0M=GTk^cP|WwrH<0~?6YV^>PI
z>MB!`YeOsiYMmXudN+J?i$`BDx0aIh6v{3>Z@qH>YfqWp9Z|2L-K#9DFAuA_mfmo?
zw-nyykr@*T?K6-5P4T$Ns&
zDcbA-KUL~r`q8qsQArIJ_`ISZP1#sAP189ztvmjvq^+T&TNG+HyiHtwoHed3?C6$e
zlj$h?{EzYx&2$qr<|~VzIvr6qT}O^=N;^yMZ&j01X=h8@BZ}{jiL1Dm_s|D5-Qdo0
z4GHqoM;9f$vbLrY?T4a>Ess>TuNhzc`dHQ)Hd%S-t8m>wj
zt8#pH`ABj_8vU@>3qsDpkJ#=H0|7Rp!Qt|_+uqI^_kVtV*!oN`=0zh9n314ElNHaC
zm4ftJ=-S(7(TaDc-KSt
z6jSLpTQvlv@n2i#iiyF$^c{CtZ5TqA)Q*|MW9lJ{1i93t*C}az)mNVEPDhH&%v
z$hC(`BLavbymCUS;Am{JnBz0>UDq%6#MuB`)MU?5;A^Dg)d1pzcUNkA?v+xsxua6P
zR(d_F}~
zll*8unvUJN4r_+ql%I%gOtvvBvpvQgsPIYhUL0ySAA(UI!GMmg+bg-x5ealz%)ix*Pq(89W3x>T}57}r$l`$i_T
z;-AsYk{Z~tPH%cw7Afv&dp0a$xgV99;I$VhPtOgyZYmHp%qyC${MV>r-ceunmbK4+R%
z*eOz-g20V3-dv%5PcQWHm82-rPi3FiWkBfT=6cY_4eFq+Wg8U>
z(kCBvOuskOnKm9LmU<&nhBu95YO=Y*y`AOhHAsQB{_B|qRd*7JWtt)i
z^y}Hx!W7y^b@f0)K1$`^#x$5U8yxQKTDPv4ZPLc87kkKiHtugaU9M33HMa6svVmxN
zw%T*=g!(UpX@IX4`=l}qD2p2QYG&Q6Q?Y!M@BSC2Tu<@lls*mCbfPT
z%cy7Vn56%4*O2pqC%(l9{kLRFRi*hpQBLeoOmn21N6EU(J<;%}MI>;|@{^y8|Rq{PE=)2L3()w^FFmHjHX
MIeQRG9Yf-O2kz!c-2eap
literal 0
HcmV?d00001
diff --git a/addons/web/static/lib/select2/release.sh b/addons/web/static/lib/select2/release.sh
old mode 100644
new mode 100755
diff --git a/addons/website_flectra/__init__.py b/addons/website_flectra/__init__.py
index 3c89b511ad..7eb1309519 100644
--- a/addons/website_flectra/__init__.py
+++ b/addons/website_flectra/__init__.py
@@ -1,2 +1,2 @@
# -*- coding: utf-8 -*-
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
diff --git a/addons/website_flectra/__manifest__.py b/addons/website_flectra/__manifest__.py
index d9d0f35786..6b786f7edf 100644
--- a/addons/website_flectra/__manifest__.py
+++ b/addons/website_flectra/__manifest__.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-# Part of Flectra. See LICENSE file for full copyright and licensing details.
+# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
{
diff --git a/addons/website_google_map/static/src/lib/markerclusterer.js b/addons/website_google_map/static/src/lib/markerclusterer.js
old mode 100644
new mode 100755
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644
index 0000000000..f4fe0a583d
--- /dev/null
+++ b/debian/README.Debian
@@ -0,0 +1,12 @@
+Printing pages from Flectra result in missing footer and header, as per #977534
+and #885833. There is currently no Debian-supported workaround for that, as
+Debian does not ship a wkhtmltopdf version built against a patched version of
+qt.
+
+wkhtmltopdf's upstream proposes a package[0] that has been briefly
+tested and proved to work with 14.0.0+dfsg.2-1 in sid, it is still
+still officially considered as unsupported.
+
+[0] https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.buster_amd64.deb
+
+ -- Sebastien Delafond , Wed, 16 Dec 2020 08:17:10 +0100
diff --git a/debian/changelog b/debian/changelog
index 61ce0e97d9..d8c9865d01 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,26 +1,33 @@
-odoo (14.0.0) unstable; urgency=medium
+flectra (14.0.0+dfsg.2-1) unstable; urgency=medium
- * 14.0.0 (Closes: #638720)
+ * Add missing sources, remove sourceless parts, and add lintian
+ overrides where needed (Closes: #973603, #973605)
+
+ -- Sebastien Delafond Tue, 15 Dec 2020 10:28:49 +0100
+
+flectra (14.0.0+dfsg-1) unstable; urgency=medium
+
+ * 14.0.0-1 (Closes: #638720)
-- Sebastien Delafond Mon, 12 Oct 2020 14:02:16 +0200
-odoo (13.0.0) unstable; urgency=medium
+flectra (13.0.0) unstable; urgency=medium
* 13.0.0
-- Sebastien Delafond Thu, 11 Jun 2020 13:13:40 +0200
-odoo (8.0.0) stable; urgency=low
+flectra (8.0.0) stable; urgency=low
* Renamed package
- -- Simon Lejeune Wed, 17 Sep 2014 15:40:00 +0100
+ -- Simon Lejeune Wed, 17 Sep 2014 15:40:00 +0100
openerp (8.0.0~rc1-0) testing; urgency=low
* Refactored packaging
- -- Simon Lejeune Wed, 23 Jul 2014 14:59:00 +0100
+ -- Simon Lejeune Wed, 23 Jul 2014 14:59:00 +0100
openerp (6.1-1) testing; urgency=low
diff --git a/debian/control b/debian/control
index 98912485df..b09e7dfc47 100644
--- a/debian/control
+++ b/debian/control
@@ -1,13 +1,13 @@
Source: flectra
Section: net
Priority: optional
-Maintainer: FlectraHQ
-Uploaders: Aaron Bohy , Simon Lejeune
+Maintainer: FlectraHQ, Inc.
+Uploaders: Aaron Bohy , Simon Lejeune
Build-Depends: debhelper-compat (= 12), dh-python, python3, rsync, python3-setuptools
Standards-Version: 4.5.0
Homepage: http://www.flectrahq.com/
-Vcs-Git: https://gitlab.com/flectrahq/flectra
-Vcs-Browser: https://gitlab.com/flectrahq/flectra
+Vcs-Git: https://github.com/flectra/flectra
+Vcs-Browser: https://github.com/flectra/flectra
Package: flectra
Architecture: all
@@ -26,9 +26,7 @@ Depends:
python3-dateutil,
python3-decorator,
python3-docutils,
- python3-feedparser,
python3-freezegun,
- python3-html2text,
python3-pil,
python3-jinja2,
python3-libsass,
@@ -41,14 +39,12 @@ Depends:
python3-psutil,
python3-psycopg2,
python3-pydot,
- python3-pyparsing,
python3-pypdf2,
python3-qrcode,
python3-renderpm,
python3-reportlab,
python3-requests,
python3-stdnum,
- python3-suds,
python3-tz,
python3-vobject,
python3-werkzeug,
diff --git a/debian/copyright b/debian/copyright
index b1b2bdf45d..e7ff276cd2 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,8 +1,8 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Contact: FlectraHQ
+Upstream-Contact: Flectra
Files: *
-Copyright: Copyright (C) 2004-2015 Odoo SA. (www.odoo.com)
+Copyright: Copyright (C) 2004-2015 Flectra SA. (www.flectrahq.com)
License: LGPL-3+
Files: flectra/tools/appdirs.py
@@ -82,7 +82,7 @@ Copyright: 2010-TODAY ClearCorp S.A.
License: BSD-2
Files: addons/l10n_dk/*
-Copyright: 2018 Odoo House ApS
+Copyright: 2018 Flectra House ApS
License: LGPL-3+
Files: addons/l10n_do/*
@@ -398,10 +398,6 @@ Files: addons/web/static/src/fonts/lato/*
Copyright: 2010-2011 tyPoland Lukasz Dziedzic
License: SIL-Open-Font-License
-Files: addons/web/static/src/fonts/mnmliconsv21-webfont.*
-Copyright: Carlos Elas
-License: MIT
-
Files: addons/web/static/src/js/core/mixins.js
Copyright: 2010-2012 Jeremy Ashkenas
License: MIT
diff --git a/debian/lintian-overrides b/debian/lintian-overrides
index e7b109469c..ee3139c0a6 100644
--- a/debian/lintian-overrides
+++ b/debian/lintian-overrides
@@ -23,9 +23,9 @@ flectra: truetype-font-prohibits-installable-embedding [preview/print only] usr/
# only present in emails sent from the "digest" addon, and are not
# served from the flectra instance itself. This addon is only enabled
# when the user explicitely activates it after install.
-flectra: privacy-breach-generic usr/lib/python3/dist-packages/flectra/addons/digest/data/digest_data.xml [] (https://www.flectra.com/digest/static/src/img/app_store.png)
-flectra: privacy-breach-generic usr/lib/python3/dist-packages/flectra/addons/digest/data/digest_data.xml [] (https://www.flectra.com/digest/static/src/img/google_play.png)
-flectra: privacy-breach-generic usr/lib/python3/dist-packages/flectra/addons/digest/data/digest_data.xml [] (https://www.flectra.com/web/image/24717933/flectra-mobile.png)
+flectra: privacy-breach-generic usr/lib/python3/dist-packages/flectra/addons/digest/data/digest_data.xml [] (https://www.flectrahq.com/digest/static/src/img/app_store.png)
+flectra: privacy-breach-generic usr/lib/python3/dist-packages/flectra/addons/digest/data/digest_data.xml [] (https://www.flectrahq.com/digest/static/src/img/google_play.png)
+flectra: privacy-breach-generic usr/lib/python3/dist-packages/flectra/addons/digest/data/digest_data.xml [] (https://www.flectrahq.com/web/image/24717933/flectra-mobile.png)
# only present in emails sent from the "event" addon, and are not
# served from the flectra instance itself. This addon is only enabled
diff --git a/debian/rules b/debian/rules
old mode 100644
new mode 100755
diff --git a/doc/cla/corporate/26house.md b/doc/cla/corporate/26house.md
new file mode 100644
index 0000000000..1503746e90
--- /dev/null
+++ b/doc/cla/corporate/26house.md
@@ -0,0 +1,29 @@
+Slovakia, 11.12.2020
+
+26HOUSE agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Dominik Kertys dominik.kertys@26house.com https://github.com/dominikkertys
+
+List of contributors:
+
+Dominik Kertys dominik.kertys@26house.com https://github.com/dominikkertys
+
+Peter Dovičovič peter.dovicovic@26house.com https://github.com/peterdovicovic
+
+Patrik Fejda patrik.fejda@gmail.com https://github.com/patrikfejda
+
+Andrej Nagy andrej.nagy@vdp.sk https://github.com/AndrejNagy
+
+Tomáš Mačaj tomas.macaj@26house.com https://github.com/tom-m-26h
+
+Martin Širáň matosiro4@gmail.com https://github.com/MartinSiran
+
+Shared account github@26house.com https://github.com/26houseRobot
+
+Shared account private email 56382927+26houseRobot@users.noreply.github.com https://github.com/26houseRobot
diff --git a/doc/cla/corporate/abstractive.md b/doc/cla/corporate/abstractive.md
new file mode 100644
index 0000000000..735e05944b
--- /dev/null
+++ b/doc/cla/corporate/abstractive.md
@@ -0,0 +1,19 @@
+Belgium, 2022-10-25
+
+Abstractive BV agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Vincent Baggerman vincent.baggerman@abstractive.be https://github.com/vincentius
+
+
+List of contributors:
+
+Vincent Baggerman vincent.baggerman@abstractive.be https://github.com/vincentius
+Sibert Aerts sibert.aerts@abstractive.be https://github.com/Sibert-Aerts
+Bart D'haese bart.dhaese@abstractive.be https://github.com/Bart-dh
+
diff --git a/doc/cla/corporate/aerospacelab.md b/doc/cla/corporate/aerospacelab.md
new file mode 100644
index 0000000000..3f19e73fc8
--- /dev/null
+++ b/doc/cla/corporate/aerospacelab.md
@@ -0,0 +1,16 @@
+Belgium, 2022-11-03
+
+Aerospacelab S.A. agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Thibault Libioulle thibault.libioulle@aerospacelab.be https://github.com/tli-asl
+
+List of contributors:
+
+Thibault Libioulle thibault.libioulle@aerospacelab.be https://github.com/tli-asl
+Rémi Chauvenne remi.chauvenne@aerospacelab.be https://github.com/rch-asl
diff --git a/doc/cla/corporate/aktivsoftware.md b/doc/cla/corporate/aktivsoftware.md
new file mode 100644
index 0000000000..621d488fea
--- /dev/null
+++ b/doc/cla/corporate/aktivsoftware.md
@@ -0,0 +1,13 @@
+India 2021-10-14
+
+Aktiv Software Pvt. Ltd. agrees to the terms of the Flectra Corporate Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Aktiv Software flectra@aktivsoftware.com https://github.com/flectraaktiv/flectra
+
+List of contributors:
+
+Aktiv Software flectra@aktivsoftware.com https://github.com/flectraaktiv/flectra
diff --git a/doc/cla/corporate/allegro-it.md b/doc/cla/corporate/allegro-it.md
new file mode 100644
index 0000000000..0d6ca9877d
--- /dev/null
+++ b/doc/cla/corporate/allegro-it.md
@@ -0,0 +1,16 @@
+Latvia, 2022-07-22
+
+Allegro IT agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Arnis Putniņš arnis@allegro.lv https://github.com/Allegro-IT
+
+List of contributors:
+
+Arnis Putniņš arnis@allegro.lv https://github.com/Allegro-IT
+Santa Ašmane santa@allegro.lv https://github.com/Allegro-IT
diff --git a/doc/cla/corporate/biktrix.md b/doc/cla/corporate/biktrix.md
new file mode 100644
index 0000000000..2a7edefdf8
--- /dev/null
+++ b/doc/cla/corporate/biktrix.md
@@ -0,0 +1,15 @@
+Canada, 2021-09-03
+
+Biktrix Electric Bikes agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Andrew Tremblay 69811674+atremblay-biktrix@users.noreply.github.com https://github.com/atremblay-biktrix
+
+List of contributors:
+
+Andrew Tremblay 69811674+atremblay-biktrix@users.noreply.github.com https://github.com/atremblay-biktrix
diff --git a/doc/cla/corporate/bizi-software-srl.md b/doc/cla/corporate/bizi-software-srl.md
new file mode 100644
index 0000000000..cfcecad1d7
--- /dev/null
+++ b/doc/cla/corporate/bizi-software-srl.md
@@ -0,0 +1,13 @@
+Romania, 2021-01-11
+
+Bizi Software SRL agrees to the terms of the Flectra Corporate Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Erik Ludescher erik@bizicloud.ro https://github.com/bizicloud-ro
+
+List of contributors:
+
+Erik Ludescher erik@bizicloud.ro https://github.com/bizicloud-ro
diff --git a/doc/cla/corporate/bluemark.md b/doc/cla/corporate/bluemark.md
new file mode 100644
index 0000000000..85a66a0070
--- /dev/null
+++ b/doc/cla/corporate/bluemark.md
@@ -0,0 +1,16 @@
+United States, 2021-08-11
+
+Bluemark agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Joseph Shusterman joseph@bluemark.com https://github.com/shusty
+
+List of contributors:
+
+John Wilson johnw@bluemark.com https://github.com/johnw-bluemark
+Veli Kocak velik@bluemark.com https://github.com/velibm
diff --git a/doc/cla/corporate/cloudition.md b/doc/cla/corporate/cloudition.md
new file mode 100644
index 0000000000..61d98b95f2
--- /dev/null
+++ b/doc/cla/corporate/cloudition.md
@@ -0,0 +1,15 @@
+Germany, 2022-07-11
+
+Cloudition GmbH agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Stefan Reisich stefan.reisich@cloudition.de https://github.com/sreisich
+
+List of contributors:
+
+Stefan Reisich stefan.reisich@cloudition.de https://github.com/sreisich
diff --git a/doc/cla/corporate/comunitea.md b/doc/cla/corporate/comunitea.md
new file mode 100644
index 0000000000..e94970505c
--- /dev/null
+++ b/doc/cla/corporate/comunitea.md
@@ -0,0 +1,19 @@
+Spain, 2022-08-12
+
+Comunitea Servicios Tecnológicos S.L.
+agrees to the terms of the Flectra Corporate Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Omar Castiñeira Saavedra omar@comunitea.com https://github.com/omar7r
+
+List of contributors:
+
+Omar Castiñeira Saavedra omar@comunitea.com https://github.com/omar7r
+Javier Colmenero Fernández javier@comunitea.com https://github.com/javierjcf
+Francisco José Sánchez Álvarez kiko@comunitea.com https://github.com/kikosanchez
+Santiago Argüeso Armesto santi@comunitea.com https://github.com/Roodin
+Vicente Gutiérrez Fernández vicente@comunitea.com https://github.com/vicentecom
diff --git a/doc/cla/corporate/coopiteasy.md b/doc/cla/corporate/coopiteasy.md
new file mode 100644
index 0000000000..c36255d903
--- /dev/null
+++ b/doc/cla/corporate/coopiteasy.md
@@ -0,0 +1,30 @@
+Belgium, 2022-10-26
+
+Coop IT Easy SC agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Carmen Bianca Bakker https://github.com/carmenbianca
+
+List of contributors:
+
+Carmen Bianca Bakker https://github.com/carmenbianca
+
+Catherine Lembrée https://github.com/cathLemb
+
+Hugues De Keyzer https://github.com/huguesdk
+
+Pol Champion https://github.com/polchampion
+
+Rémy Taymans https://github.com/remytms
+
+Robin Keunen https://github.com/robinkeunen
+
+Victor Champonnois https://github.com/victor-champonnois
+
+Virginie Dewulf https://github.com/vdewulf
+
diff --git a/doc/cla/corporate/demolium.md b/doc/cla/corporate/demolium.md
new file mode 100644
index 0000000000..a2d3f3b104
--- /dev/null
+++ b/doc/cla/corporate/demolium.md
@@ -0,0 +1,15 @@
+The Netherlands, 2021-04-14
+
+Demolium BV agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+rconjour robin@conjour.nl https://github.com/rconjour
+
+List of contributors:
+
+rconjour robin@conjour.nl https://github.com/rconjour
\ No newline at end of file
diff --git a/doc/cla/corporate/digitaldomus.md b/doc/cla/corporate/digitaldomus.md
new file mode 100644
index 0000000000..b2ca5ecb13
--- /dev/null
+++ b/doc/cla/corporate/digitaldomus.md
@@ -0,0 +1,15 @@
+Italy, 22-04-2021
+
+Digital Domus s.n.c. agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Alessandro Fiorino alessandro.fiorino@digitaldomus.it https://github.com/alessandro-fiorino
+
+List of contributors:
+
+Alessandro Fiorino alessandro.fiorino@digitaldomus.it https://github.com/alessandro-fiorino
diff --git a/doc/cla/corporate/entrivistech.md b/doc/cla/corporate/entrivistech.md
new file mode 100644
index 0000000000..368f9204f0
--- /dev/null
+++ b/doc/cla/corporate/entrivistech.md
@@ -0,0 +1,16 @@
+India, 2021-04-21
+
+Entrivis Tech Private Limited agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Entrivis Tech Pvt. Ltd. hello@entrivistech.com https://github.com/Entrivis-Tech
+
+List of contributors:
+
+Krutarth Buch krutarth@entrivistech.com https://github.com/krutarthbuch
+Meet Dholakia meet@entrivistech.com https://github.com/MeetKD
diff --git a/doc/cla/corporate/flectratech.md b/doc/cla/corporate/flectratech.md
new file mode 100644
index 0000000000..acab360cbf
--- /dev/null
+++ b/doc/cla/corporate/flectratech.md
@@ -0,0 +1,14 @@
+Hungary, 2023-05-24
+
+FlectraTech Zrt. agrees to the terms of the Flectra Corporate Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Csaba Tóth csaba.toth@flectratech.hu https://github.com/tsabi
+
+List of contributors:
+
+Csaba Tóth csaba.toth@flectratech.hu https://github.com/tsabi
+Krisztián Juhász juhasz.krisztian@flectratech.hu https://github.com/flectratechnology
diff --git a/doc/cla/corporate/itpp-labs.md b/doc/cla/corporate/itpp-labs.md
new file mode 100644
index 0000000000..0fb320386a
--- /dev/null
+++ b/doc/cla/corporate/itpp-labs.md
@@ -0,0 +1,15 @@
+Russia, 2021-03-20
+
+IT Projects Labs agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Denis Mudarisov denis.mudarisov@gmail.com https://github.com/trojikman
+
+List of contributors:
+
+Denis Mudarisov denis.mudarisov@gmail.com https://github.com/trojikman
diff --git a/doc/cla/corporate/layline-tech.md b/doc/cla/corporate/layline-tech.md
new file mode 100644
index 0000000000..56651080da
--- /dev/null
+++ b/doc/cla/corporate/layline-tech.md
@@ -0,0 +1,13 @@
+Israel, 2021-09-20
+
+Layline Tech agrees to the terms of the Flectra Corporate Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Hed Shefer hed@laylinetech.com https://github.com/hedshefer
+
+List of contributors:
+
+Uriel Ehrman uriel@laylinetech.com https://github.com/UrielLaylineTech
\ No newline at end of file
diff --git a/doc/cla/corporate/le-filament.md b/doc/cla/corporate/le-filament.md
new file mode 100644
index 0000000000..4fa0c9691c
--- /dev/null
+++ b/doc/cla/corporate/le-filament.md
@@ -0,0 +1,19 @@
+France, 2023-04-27
+
+Le Filament agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Rémi Cazenave 30716308+remi-filament@users.noreply.github.com https://github.com/remi-filament
+
+List of contributors:
+
+Benjamin Rivier 35699580+benj-filament@users.noreply.github.com https://github.com/benj-filament
+Juliana Poudou 35699320+JulianaPoudou@users.noreply.github.com https://github.com/JulianaPoudou
+Mathieu Hazard 61692077+MathieuFilament@users.noreply.github.com https://github.com/MathieuFilament
+Rémi Cazenave 30716308+remi-filament@users.noreply.github.com https://github.com/remi-filament
+Théo Chapy 97020404+theo-le-filament@users.noreply.github.com https://github.com/theo-le-filament
diff --git a/doc/cla/corporate/mainframemonkey.md b/doc/cla/corporate/mainframemonkey.md
new file mode 100644
index 0000000000..70102ada5d
--- /dev/null
+++ b/doc/cla/corporate/mainframemonkey.md
@@ -0,0 +1,18 @@
+Belgium, 07.04.2021
+
+Mainframe Monkey agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Yenthe Van Ginneken yenthevg@gmail.com https://github.com/Yenthe666
+
+List of contributors:
+
+Yenthe Van Ginneken yenthe@mainframemonkey.com https://github.com/Yenthe666
+Ward Marissen ward@mainframemonkey.com https://github.com/wardm95
+Swapnesh Shah swapnesh@mainframemonkey.com https://github.com/sswapnesh
+Vincent Adriaensen vincent@mainframemonkey.com https://github.com/vincentadriaensen
diff --git a/doc/cla/corporate/manatec.md b/doc/cla/corporate/manatec.md
new file mode 100644
index 0000000000..fda89dd776
--- /dev/null
+++ b/doc/cla/corporate/manatec.md
@@ -0,0 +1,23 @@
+Germany, 2022-09-28
+
+manaTec GmbH agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Robert Duckstein robert.duckstein@manatec.de https://github.com/rd-manatec
+
+List of contributors:
+
+Tobias Reinwarth mailtobyte@googlemail.com https://github.com/tobytes
+
+Tom Tietze tietze.development@web.de https://github.com/TomTietze
+
+Philipp Köhler bandsache@gmx.net https://github.com/fploetzlich
+
+Alexander Heyber alexander.heyber@manatec.de https://github.com/alexander-heyber-manatec
+
+Walter Salzmann walter.salzmann@manatec.de https://github.com/ws-manatec
diff --git a/doc/cla/corporate/moduon.md b/doc/cla/corporate/moduon.md
new file mode 100644
index 0000000000..04b84501a4
--- /dev/null
+++ b/doc/cla/corporate/moduon.md
@@ -0,0 +1,16 @@
+Spain, 2021-01-04
+
+Moduon Team S.L. agrees to the terms of the Flectra Corporate Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Rafael Blasco rblasco@moduon.team https://github.com/rafaelbn
+
+List of contributors:
+
+Jairo Llopis jairo@moduon.team https://github.com/Yajo
+Eduardo De Miguel edu@moduon.team https://github.com/Shide
+moduonbot moduonbot@moduon.team https://github.com/moduonbot
+Rafael Blasco rblasco@moduon.team https://github.com/rafaelbn
diff --git a/doc/cla/corporate/online-erp-hungary-kft.md b/doc/cla/corporate/online-erp-hungary-kft.md
new file mode 100644
index 0000000000..1971f23c1d
--- /dev/null
+++ b/doc/cla/corporate/online-erp-hungary-kft.md
@@ -0,0 +1,22 @@
+Hungary, 2021-02-24
+
+Online ERP Hungary Kft. agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Csaba Tóth csaba.toth@online-erp.hu https://github.com/tsabi
+
+List of contributors:
+
+Csaba Tóth csaba.toth@online-erp.hu https://github.com/tsabi
+Attila Eiler eiler.attila@online-erp.hu https://github.com/Eilerant
+András Horváth horvath.andras@online-erp.hu https://github.com/siriusandris
+Miklós Zsitva zsitva.miklos@online-erp.hu https://github.com/nurefexc
+László Balassa balassa.laszlo@online-erp.hu https://github.com/BLacika
+Zsolt Godó godo.zsolt@online-erp.hu https://github.com/sakaitsu
+Ákos Lőrincz lorincz.akos@online-erp.hu https://github.com/LorinczAks
+Balázs Regényi regenyi.balazs@online-erp.hu https://github.com/regisz
diff --git a/doc/cla/corporate/rapsflectra.md b/doc/cla/corporate/rapsflectra.md
new file mode 100644
index 0000000000..5b7dc3fc18
--- /dev/null
+++ b/doc/cla/corporate/rapsflectra.md
@@ -0,0 +1,25 @@
+Rome, 2021-01-13
+
+Rapsflectra agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Filippo Iovine filippo.iovine@rapsflectrahq.com https://github.com/ioFilippo
+
+List of contributors:
+
+Filippo Iovine filippo.iovine@rapsflectrahq.com https://github.com/ioFilippo
+Lucio Valente lucio.valente@rapsflectrahq.com https://github.com/luciovalente
+Mario Pitingolo mario.pitingolo@rapsflectrahq.com https://github.com/Pits79
+Simone Papandrea simone.papandrea@rapsflectrahq.com https://github.com/SI3P
+Davide Fella davide.fella@rapsflectrahq.com https://github.com/davidefella
+Angel Corpuz angel.corpuz@rapsflectrahq.com https://github.com/acorpuz
+Tony Masci tony.masci@rapsflectrahq.com https://github.com/TonyMasciI
+Andrea Patusso andrea.patusso@rapsflectrahq.com https://github.com/AndreaPatusso
+Valentina Maltese valentina.maltese@rapsflectrahq.com https://github.com/ValentinaMal
+Tommaso Bellelli tommaso.bellelli@rapsflectrahq.com https://github.com/tommasobellelli
+Saydigital info@rapsflectrahq.com https://github.com/saydigital
diff --git a/doc/cla/corporate/simpit.md b/doc/cla/corporate/simpit.md
new file mode 100644
index 0000000000..8ef7631c01
--- /dev/null
+++ b/doc/cla/corporate/simpit.md
@@ -0,0 +1,17 @@
+Switzerland, 2021-01-20
+
+simpit GmbH agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Dario Bösch boesch@simpit.ch https://github.com/simpit-boesch
+
+List of contributors:
+
+Dario Bösch boesch@simpit.ch https://github.com/simpit-boesch
+Lukas Eisner eisner@simpit.ch https://github.com/simpit-eisner
+Mario Burger burger@simpit.ch https://github.com/marioburger
\ No newline at end of file
diff --git a/doc/cla/corporate/stesiconsultingsrl.md b/doc/cla/corporate/stesiconsultingsrl.md
new file mode 100644
index 0000000000..7f65e12b90
--- /dev/null
+++ b/doc/cla/corporate/stesiconsultingsrl.md
@@ -0,0 +1,17 @@
+Italy, 07/03/2023
+
+STeSI Consulting srl agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Francesco Moccia moccia.f@stesi.eu https://github.com/stesifrancesco
+
+List of contributors:
+
+Michele Di Croce dicroce.m@stesi.eu https://github.com/micheledic
+Francesco Moccia moccia.f@stesi.eu https://github.com/stesifrancesco
+Arcadio Pinto pinto.a@stesi.eu https://github.com/ArcadioPinto
diff --git a/doc/cla/corporate/studio73.md b/doc/cla/corporate/studio73.md
new file mode 100644
index 0000000000..c25aab3841
--- /dev/null
+++ b/doc/cla/corporate/studio73.md
@@ -0,0 +1,23 @@
+Spain, 2021-03-23
+
+Consultoria Informatica Studio73 S.L. agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Pablo Fuentes pablo@studio73.es https://github.com/fuentes73
+
+List of contributors:
+
+Pablo Fuentes pablo@studio73.es https://github.com/fuentes73
+Jordi Tolsa jordi@studio73.es https://github.com/jortolsa-s73
+Ioan Galan ioan@studio73.es https://github.com/ioans73
+Ethan Hildick ethan@studio73.es https://github.com/hildickethan-s73
+Ferran Mora ferran@studio73.es https://github.com/ferran-s73
+Carlos Reyes carlos@studio73.es https://github.com/reyes4711-s73
+Miguel Gandia miguel@studio73.es https://github.com/miguel-s73
+Roger Amorós roger@studio73.es https://github.com/rabbitjon-s73
+Guillermo Llinares guillermo@studio73.es https://github.com/willerr-mo-s73
diff --git a/doc/cla/corporate/systemworks.md b/doc/cla/corporate/systemworks.md
new file mode 100644
index 0000000000..512cd3b35c
--- /dev/null
+++ b/doc/cla/corporate/systemworks.md
@@ -0,0 +1,18 @@
+South Africa, 2022-01-10
+
+SystemWorks agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Michael de Villiers michael@systemworks.co.za https://github.com/COUR4G3
+
+List of contributors:
+
+Michael de Villiers michael@systemworks.co.za https://github.com/COUR4G3
+Mziwakhe Ndinga mzi@systemworks.co.za https://github.com/mndinga
+Alex Zimmerman alexz@systemworks.co.za https://github.com/AFZimmers
+
diff --git a/doc/cla/corporate/trescloud.md b/doc/cla/corporate/trescloud.md
new file mode 100644
index 0000000000..a5fcb2feda
--- /dev/null
+++ b/doc/cla/corporate/trescloud.md
@@ -0,0 +1,18 @@
+Ecuador, 15/03/2021
+
+TRESCLOUD CÍA LTDA agrees to the terms of the Flectra Corporate Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Andrés Calle andres.calle@trescloud.com https://github.com/pepetreshere
+
+List of contributors:
+
+Andrés Calle andres.calle@trescloud.com https://github.com/pepetreshere
+Juan Álvarez juan.alvarez@trescloud.com https://github.com/JuanDanielAlvarez
+Steven Luna steven.luna@trescloud.com https://github.com/stevTresCloud
+José Rivero jose.rivero@trescloud.com https://github.com/JoseMiguelRivero
diff --git a/doc/cla/individual/0xsaltyhash.md b/doc/cla/individual/0xsaltyhash.md
new file mode 100644
index 0000000000..b4845fab92
--- /dev/null
+++ b/doc/cla/individual/0xsaltyhash.md
@@ -0,0 +1,11 @@
+Egypt, 30/07/2023
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Ahmed Saeed. mohameda7med64@gmail.com https://github.com/0xSaltyHash
diff --git a/doc/cla/individual/Ajroo.md b/doc/cla/individual/Ajroo.md
new file mode 100644
index 0000000000..226f92a3da
--- /dev/null
+++ b/doc/cla/individual/Ajroo.md
@@ -0,0 +1,11 @@
+Belgium, 2021-07-09
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Kasper Declercq declercq.kasper@gmail.com https://github.com/Ajroo
diff --git a/doc/cla/individual/AlfaFza.md b/doc/cla/individual/AlfaFza.md
new file mode 100644
index 0000000000..df1f1257d8
--- /dev/null
+++ b/doc/cla/individual/AlfaFza.md
@@ -0,0 +1,12 @@
+India, 2021-09-13
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+AlfaFza sssalfi07@gmail.com
+https://github.com/AlfaFza
diff --git a/doc/cla/individual/AndrewChau.md b/doc/cla/individual/AndrewChau.md
new file mode 100644
index 0000000000..7282db8174
--- /dev/null
+++ b/doc/cla/individual/AndrewChau.md
@@ -0,0 +1,11 @@
+Australia, 2022-01-15
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Andrew Chau ky@andrewchau.com https://github.com/AndrewChau
diff --git a/doc/cla/individual/BayarkhuuBataa.md b/doc/cla/individual/BayarkhuuBataa.md
new file mode 100644
index 0000000000..32cf86b0ce
--- /dev/null
+++ b/doc/cla/individual/BayarkhuuBataa.md
@@ -0,0 +1,11 @@
+Mongolia, 2021-12-08
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Bayarkhuu Bataa bbayarkhuu@gmail.com https://github.com/BayarkhuuBataa
\ No newline at end of file
diff --git a/doc/cla/individual/EsamHussein.md b/doc/cla/individual/EsamHussein.md
new file mode 100644
index 0000000000..0e92bdea67
--- /dev/null
+++ b/doc/cla/individual/EsamHussein.md
@@ -0,0 +1,9 @@
+Egypt, 2021-06-14
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Esam Hussein esam.n.hussein@gmail.com https://github.com/esamhussein
\ No newline at end of file
diff --git a/doc/cla/individual/KareemAbuzaid.md b/doc/cla/individual/KareemAbuzaid.md
new file mode 100644
index 0000000000..e5590363f1
--- /dev/null
+++ b/doc/cla/individual/KareemAbuzaid.md
@@ -0,0 +1,11 @@
+Egypt, 2020-03-12
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Kareem Abuzaid 36644028+KareemAbuzaid@users.noreply.github.com https://github.com/KareemAbuzaid
\ No newline at end of file
diff --git a/doc/cla/individual/SlaveWilson.md b/doc/cla/individual/SlaveWilson.md
new file mode 100644
index 0000000000..a48bf2224d
--- /dev/null
+++ b/doc/cla/individual/SlaveWilson.md
@@ -0,0 +1,11 @@
+Hong Kong, 2023-05-14
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Tommy Ng tommynhm@gmail.com https://github.com/SlaveWilson
\ No newline at end of file
diff --git a/doc/cla/individual/SplashS.md b/doc/cla/individual/SplashS.md
new file mode 100644
index 0000000000..42d479e226
--- /dev/null
+++ b/doc/cla/individual/SplashS.md
@@ -0,0 +1,11 @@
+Russian Federation, 2021-06-22
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Sergey Shebanin sergey@shebanin.ru https://github.com/SplashS
diff --git a/doc/cla/individual/TeoGoddet.md b/doc/cla/individual/TeoGoddet.md
new file mode 100644
index 0000000000..9c53ab6749
--- /dev/null
+++ b/doc/cla/individual/TeoGoddet.md
@@ -0,0 +1,9 @@
+Switzerland, 2021-12-11
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Téo Goddet teo.goddet@gmail.com https://github.com/TeoGoddet
diff --git a/doc/cla/individual/abdurrahmansaber.md b/doc/cla/individual/abdurrahmansaber.md
new file mode 100644
index 0000000000..ba599e1851
--- /dev/null
+++ b/doc/cla/individual/abdurrahmansaber.md
@@ -0,0 +1,11 @@
+Egypt, 2023-07-19
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Abdurrahman Saber abdelrahmansaber85@gmail.com https://github.com/abdurrahmansaber
\ No newline at end of file
diff --git a/doc/cla/individual/abharos.md b/doc/cla/individual/abharos.md
new file mode 100644
index 0000000000..cf2ab76e09
--- /dev/null
+++ b/doc/cla/individual/abharos.md
@@ -0,0 +1,10 @@
+The Netherlands, 2021-03-15
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+Abri Bharos 33723400+abharos@users.noreply.github.com https://github.com/abharos
diff --git a/doc/cla/individual/aims-khan.md b/doc/cla/individual/aims-khan.md
new file mode 100644
index 0000000000..cd22709f71
--- /dev/null
+++ b/doc/cla/individual/aims-khan.md
@@ -0,0 +1,11 @@
+Afghanistan, 2021-07-29
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Ahmad Khan zuhal.nader@gmail.com https://github.com/aims-khan
diff --git a/doc/cla/individual/amincheloh.md b/doc/cla/individual/amincheloh.md
new file mode 100644
index 0000000000..a512201020
--- /dev/null
+++ b/doc/cla/individual/amincheloh.md
@@ -0,0 +1,11 @@
+Thailand, 2021-06-04
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Amin Cheloh amincheloh@gmail.com https://github.com/amincheloh
diff --git a/doc/cla/individual/angelmoya.md b/doc/cla/individual/angelmoya.md
new file mode 100644
index 0000000000..6457df5056
--- /dev/null
+++ b/doc/cla/individual/angelmoya.md
@@ -0,0 +1,11 @@
+Spain, 2022-07-12
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Angel Moya amoyapardo@gmail.com https://github.com/angelmoya
\ No newline at end of file
diff --git a/doc/cla/individual/beshoynabeih.md b/doc/cla/individual/beshoynabeih.md
new file mode 100644
index 0000000000..c00e879041
--- /dev/null
+++ b/doc/cla/individual/beshoynabeih.md
@@ -0,0 +1,11 @@
+Egypt, 2023-02-25
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Beshoy Nabeih beshoynabeih@gmail.com https://github.com/beshoynabeih
diff --git a/doc/cla/individual/bhtabor.md b/doc/cla/individual/bhtabor.md
new file mode 100644
index 0000000000..39d7edac1d
--- /dev/null
+++ b/doc/cla/individual/bhtabor.md
@@ -0,0 +1,11 @@
+Ethiopia, 2021-08-12
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Biruk Haileye Tabor biruk.haileye@gmail.com https://github.com/bhtabor
diff --git a/doc/cla/individual/bilalattar.md b/doc/cla/individual/bilalattar.md
new file mode 100644
index 0000000000..99ee0d3428
--- /dev/null
+++ b/doc/cla/individual/bilalattar.md
@@ -0,0 +1,11 @@
+The Netherlands, 2021-03-10
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Bilal El Attar B.ElAttar@student.tudelft.nl https://github.com/bilalattar
\ No newline at end of file
diff --git a/doc/cla/individual/brawn1.md b/doc/cla/individual/brawn1.md
new file mode 100644
index 0000000000..871892767e
--- /dev/null
+++ b/doc/cla/individual/brawn1.md
@@ -0,0 +1,11 @@
+Austria, 2023-06-22
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Guenter Bailey brawn1@gmx.at https://github.com/Brawn1
diff --git a/doc/cla/individual/budisentosa.md b/doc/cla/individual/budisentosa.md
new file mode 100644
index 0000000000..9eae7f67d3
--- /dev/null
+++ b/doc/cla/individual/budisentosa.md
@@ -0,0 +1,11 @@
+Indonesia, 2022-04-28
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Budi Sentosa budi@avasoft.co https://github.com/budisentosa
\ No newline at end of file
diff --git a/doc/cla/individual/cybernexus.md b/doc/cla/individual/cybernexus.md
new file mode 100644
index 0000000000..e248ce674c
--- /dev/null
+++ b/doc/cla/individual/cybernexus.md
@@ -0,0 +1,11 @@
+United States, 2021-04-08
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Pete Snyder cybernexus00@yahoo.com https://github.com/cybernexus
\ No newline at end of file
diff --git a/doc/cla/individual/davejames.md b/doc/cla/individual/davejames.md
new file mode 100644
index 0000000000..72b47a7ff0
--- /dev/null
+++ b/doc/cla/individual/davejames.md
@@ -0,0 +1,11 @@
+Australia, 2020-12-01
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+David James david@djdc.net.au https://github.com/davejames
diff --git a/doc/cla/individual/derfl0.md b/doc/cla/individual/derfl0.md
new file mode 100644
index 0000000000..0f5fbefe1c
--- /dev/null
+++ b/doc/cla/individual/derfl0.md
@@ -0,0 +1,11 @@
+Germany, 2023-05-03
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Florian Bieringer github@fl0.eu https://github.com/derfl0
\ No newline at end of file
diff --git a/doc/cla/individual/dishon.md b/doc/cla/individual/dishon.md
new file mode 100644
index 0000000000..799df20b31
--- /dev/null
+++ b/doc/cla/individual/dishon.md
@@ -0,0 +1,11 @@
+Kenya, 2021-07-29
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Dishon Kadoh dishon.kadoh@gmail.com https://github.com/realestdon
diff --git a/doc/cla/individual/dnplkndll.md b/doc/cla/individual/dnplkndll.md
new file mode 100644
index 0000000000..0bef2c5711
--- /dev/null
+++ b/doc/cla/individual/dnplkndll.md
@@ -0,0 +1,11 @@
+United States, 2022-01-15
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Don Kendall kendall@donkendall.com https://github.com/dnplkndll
diff --git a/doc/cla/individual/dosipchuk.md b/doc/cla/individual/dosipchuk.md
new file mode 100644
index 0000000000..d438f307d5
--- /dev/null
+++ b/doc/cla/individual/dosipchuk.md
@@ -0,0 +1,11 @@
+Ukraine, 2021-05-24
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Dmytro Osipchuk d.e.osipchuk@gmail.com https://github.com/dosipchuk
diff --git a/doc/cla/individual/dupski.md b/doc/cla/individual/dupski.md
new file mode 100644
index 0000000000..f6ab07e419
--- /dev/null
+++ b/doc/cla/individual/dupski.md
@@ -0,0 +1,11 @@
+United Kingdom, 2021-07-04
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Russell Briggs russ@paraflyer.net https://github.com/dupski
\ No newline at end of file
diff --git a/doc/cla/individual/duybq86.md b/doc/cla/individual/duybq86.md
new file mode 100644
index 0000000000..92c30fb092
--- /dev/null
+++ b/doc/cla/individual/duybq86.md
@@ -0,0 +1,11 @@
+Vietnam, 2023-07-16
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+DuyBQ duybq86@gmail.com https://github.com/duybq86
diff --git a/doc/cla/individual/emilkholod.md b/doc/cla/individual/emilkholod.md
new file mode 100644
index 0000000000..1720ad67df
--- /dev/null
+++ b/doc/cla/individual/emilkholod.md
@@ -0,0 +1,11 @@
+Russia, 2021-03-01
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Emil emil.kholod@gmail.com https://github.com/emilkholod
diff --git a/doc/cla/individual/ene0815.md b/doc/cla/individual/ene0815.md
new file mode 100644
index 0000000000..afa97fe4f1
--- /dev/null
+++ b/doc/cla/individual/ene0815.md
@@ -0,0 +1,9 @@
+Germany, 2021-10-27
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Christoph Adolphs 65236372+ene0815@users.noreply.github.com https://github.com/ene0815
diff --git a/doc/cla/individual/ettoreleandrotognoli.md b/doc/cla/individual/ettoreleandrotognoli.md
new file mode 100644
index 0000000000..4ee0f3ecb7
--- /dev/null
+++ b/doc/cla/individual/ettoreleandrotognoli.md
@@ -0,0 +1,11 @@
+Brazil, 2021-08-20
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Ettore Leandro Tognoli ettoreleandrotognoli@gmail.com https://github.com/ettoreleandrotognoli
\ No newline at end of file
diff --git a/doc/cla/individual/fedegobea.md b/doc/cla/individual/fedegobea.md
new file mode 100644
index 0000000000..2479e9f8ab
--- /dev/null
+++ b/doc/cla/individual/fedegobea.md
@@ -0,0 +1,11 @@
+Argentina, 12/12/2020
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Federico Gobea 65693362+fedegobea@users.noreply.github.com https://github.com/fedegobea
diff --git a/doc/cla/individual/flectramates.md b/doc/cla/individual/flectramates.md
new file mode 100644
index 0000000000..982dce0642
--- /dev/null
+++ b/doc/cla/individual/flectramates.md
@@ -0,0 +1,11 @@
+India, 2021-07-22
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Flectra Mates flectramates@gmail.com https://github.com/flectramates
diff --git a/doc/cla/individual/francescoballerini.md b/doc/cla/individual/francescoballerini.md
new file mode 100644
index 0000000000..8db91c2da5
--- /dev/null
+++ b/doc/cla/individual/francescoballerini.md
@@ -0,0 +1,9 @@
+Italy, 2023-04-02
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Francesco Ballerini francescobl.lavoro@gmail.com https://github.com/FrancescoBallerini
diff --git a/doc/cla/individual/fredzamoabg.md b/doc/cla/individual/fredzamoabg.md
new file mode 100644
index 0000000000..fa6cec05a9
--- /dev/null
+++ b/doc/cla/individual/fredzamoabg.md
@@ -0,0 +1,11 @@
+Italy, 2021-11-25
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Alfredo Zamora alfredo.zamora@agilebg.com https://github.com/fredzamoabg
diff --git a/doc/cla/individual/geraldaistleitner.md b/doc/cla/individual/geraldaistleitner.md
new file mode 100644
index 0000000000..cc1652811d
--- /dev/null
+++ b/doc/cla/individual/geraldaistleitner.md
@@ -0,0 +1,11 @@
+Austria, 2021-03-28
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Gerald Aistleitner https://github.com/geraldaistleitner
diff --git a/doc/cla/individual/gordon.md b/doc/cla/individual/gordon.md
new file mode 100644
index 0000000000..67975b53d8
--- /dev/null
+++ b/doc/cla/individual/gordon.md
@@ -0,0 +1,13 @@
+
+
+gordon, 2022-7-14
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+gordon 54697960+filwu8@users.noreply.github.com https://github.com/filwu8
diff --git a/doc/cla/individual/goz4el.md b/doc/cla/individual/goz4el.md
new file mode 100644
index 0000000000..86814cbc03
--- /dev/null
+++ b/doc/cla/individual/goz4el.md
@@ -0,0 +1,11 @@
+Venezuela, 2023-08-09
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Miguel Gozaine hordemzerado@gmail.com https://github.com/GOZ4EL
diff --git a/doc/cla/individual/grzana12.md b/doc/cla/individual/grzana12.md
new file mode 100644
index 0000000000..31add7ee16
--- /dev/null
+++ b/doc/cla/individual/grzana12.md
@@ -0,0 +1,11 @@
+Poland, 2022-05-04
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Łukasz Grzenkowicz lukasz@grzana.pl https://github.com/grzana12
diff --git a/doc/cla/individual/guimarc.md b/doc/cla/individual/guimarc.md
new file mode 100644
index 0000000000..425d8a781c
--- /dev/null
+++ b/doc/cla/individual/guimarc.md
@@ -0,0 +1,10 @@
+Brazil, 2021-03-03
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+Guilherme Marcondes guimarc@br.ibm.com https://github.com/guimarc-br/
\ No newline at end of file
diff --git a/doc/cla/individual/haumenphai.md b/doc/cla/individual/haumenphai.md
new file mode 100644
index 0000000000..109217002a
--- /dev/null
+++ b/doc/cla/individual/haumenphai.md
@@ -0,0 +1,9 @@
+Vietnam, 2022-05-28
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Trinh Duc Do codegunpow@gmail.com https://github.com/haumenphai
diff --git a/doc/cla/individual/hoangtiendung070797.md b/doc/cla/individual/hoangtiendung070797.md
new file mode 100644
index 0000000000..0da4f56d7f
--- /dev/null
+++ b/doc/cla/individual/hoangtiendung070797.md
@@ -0,0 +1,9 @@
+Vietnam, 2023-05-24
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Hoang Tien Dung hoangtiendung070797@gmail.com https://github.com/hoangtiendung070797
diff --git a/doc/cla/individual/holoborodkobohdan.md b/doc/cla/individual/holoborodkobohdan.md
new file mode 100644
index 0000000000..128d84e20d
--- /dev/null
+++ b/doc/cla/individual/holoborodkobohdan.md
@@ -0,0 +1,11 @@
+Ukraine, 2021-08-03
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Holoborodko Bohdan holoborodko.bohdan@gmail.com https://github.com/HoloborodkoBohdan
diff --git a/doc/cla/individual/huakkai.md b/doc/cla/individual/huakkai.md
new file mode 100644
index 0000000000..8926b37d1b
--- /dev/null
+++ b/doc/cla/individual/huakkai.md
@@ -0,0 +1,11 @@
+China, 2021-02-15
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Kai huaqiangyan@163.com https://github.com/huakkai
diff --git a/doc/cla/individual/imbarbudiman.md b/doc/cla/individual/imbarbudiman.md
new file mode 100644
index 0000000000..8e708a4887
--- /dev/null
+++ b/doc/cla/individual/imbarbudiman.md
@@ -0,0 +1,11 @@
+Indonesia, 2021-08-25
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Imbar Budiman imbarbudiman@yahoo.com https://github.com/imbarbudiman
\ No newline at end of file
diff --git a/doc/cla/individual/innovara.md b/doc/cla/individual/innovara.md
new file mode 100644
index 0000000000..ca62c85ff4
--- /dev/null
+++ b/doc/cla/individual/innovara.md
@@ -0,0 +1,11 @@
+United Kingdom, 2021-09-14
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Manuel Fombuena mfombuena@innovara.co.uk https://github.com/innovara
\ No newline at end of file
diff --git a/doc/cla/individual/insiyashakir02.md b/doc/cla/individual/insiyashakir02.md
new file mode 100644
index 0000000000..1da2d6ff86
--- /dev/null
+++ b/doc/cla/individual/insiyashakir02.md
@@ -0,0 +1,11 @@
+India, 2022-01-31
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Insiya insiyashakir215@gmail.com https://github.com/InsiyaShakir02
diff --git a/doc/cla/individual/jadir-bs.md b/doc/cla/individual/jadir-bs.md
new file mode 100644
index 0000000000..a4eb1ba2a7
--- /dev/null
+++ b/doc/cla/individual/jadir-bs.md
@@ -0,0 +1,11 @@
+Bangladesh, 2023-05-24
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Jadir Ibna Hasan jadir@brainstation-23.com https://github.com/jadir-bs
\ No newline at end of file
diff --git a/doc/cla/individual/janikvonrotz.md b/doc/cla/individual/janikvonrotz.md
new file mode 100644
index 0000000000..a99ea48621
--- /dev/null
+++ b/doc/cla/individual/janikvonrotz.md
@@ -0,0 +1,11 @@
+Switzerland, 2021-05-25
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Janik von Rotz login@janikvonrotz.ch https://github.com/janikvonrotz
diff --git a/doc/cla/individual/jannikbecher.md b/doc/cla/individual/jannikbecher.md
new file mode 100644
index 0000000000..be1bb0a763
--- /dev/null
+++ b/doc/cla/individual/jannikbecher.md
@@ -0,0 +1,11 @@
+Germany, 2021-01-12
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Jannik Becher becher.jannik@gmail.com https://github.com/jannikbecher
diff --git a/doc/cla/individual/jeelkhanpara.md b/doc/cla/individual/jeelkhanpara.md
new file mode 100644
index 0000000000..7e0a2d99b9
--- /dev/null
+++ b/doc/cla/individual/jeelkhanpara.md
@@ -0,0 +1,9 @@
+India, July 29th, 2021
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Jeel Khanpara khanpara.jeel@gmail.com https://github.com/JeelBKhanpara
diff --git a/doc/cla/individual/joanna350.md b/doc/cla/individual/joanna350.md
new file mode 100644
index 0000000000..b35f8d3fa5
--- /dev/null
+++ b/doc/cla/individual/joanna350.md
@@ -0,0 +1,9 @@
+South Korea, 2022-10-03
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Joanna joanna@kaist.ac.kr https://github.com/joanna350
diff --git a/doc/cla/individual/joseramongarcia.md b/doc/cla/individual/joseramongarcia.md
new file mode 100644
index 0000000000..7cd4886427
--- /dev/null
+++ b/doc/cla/individual/joseramongarcia.md
@@ -0,0 +1,11 @@
+Spain, 2021/08/24
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Jose Ramon Garcia jrgarcia.cosin@gmail.com https://github.com/JoseRamonGarcia
diff --git a/doc/cla/individual/kerteszgergo.md b/doc/cla/individual/kerteszgergo.md
new file mode 100644
index 0000000000..1927d998f1
--- /dev/null
+++ b/doc/cla/individual/kerteszgergo.md
@@ -0,0 +1,11 @@
+Hungary, 2021-07-06
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Kertész Gergő 87029616+kerteszgergo@users.noreply.github.com https://github.com/kerteszgergo
diff --git a/doc/cla/individual/khalidelhaji.md b/doc/cla/individual/khalidelhaji.md
new file mode 100644
index 0000000000..db7534e7e1
--- /dev/null
+++ b/doc/cla/individual/khalidelhaji.md
@@ -0,0 +1,11 @@
+The Netherlands, 2021-03-14
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Khalid El Haji k.elhaji@student.tudelft.nl https://github.com/khalidelhaji
\ No newline at end of file
diff --git a/doc/cla/individual/kmagusiak.md b/doc/cla/individual/kmagusiak.md
new file mode 100644
index 0000000000..d10b295647
--- /dev/null
+++ b/doc/cla/individual/kmagusiak.md
@@ -0,0 +1,11 @@
+Belgium, 2021-03-03
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Krzysztof Magusiak chris.magusiak@gmail.com https://github.com/kmagusiak
diff --git a/doc/cla/individual/kwfx.md b/doc/cla/individual/kwfx.md
new file mode 100644
index 0000000000..787b643822
--- /dev/null
+++ b/doc/cla/individual/kwfx.md
@@ -0,0 +1,9 @@
+Tunisia, 2022-01-16
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Kahlaoui Fahmi kwfahmi@gmail.com https://github.com/kwfx
diff --git a/doc/cla/individual/leogavidia.md b/doc/cla/individual/leogavidia.md
new file mode 100644
index 0000000000..c0d8fd8a1a
--- /dev/null
+++ b/doc/cla/individual/leogavidia.md
@@ -0,0 +1,9 @@
+Ecuador, 2021-04-06
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Leonardo Gavidia lgavidia@gaheos.com https://github.com/leogavidia/
diff --git a/doc/cla/individual/malaycmkhamar.md b/doc/cla/individual/malaycmkhamar.md
new file mode 100644
index 0000000000..ce01beb399
--- /dev/null
+++ b/doc/cla/individual/malaycmkhamar.md
@@ -0,0 +1,12 @@
+India, 2022-11-17
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Malay Khamar cmk.malay.khamar@gmail.com https://github.com/malaycmkhamar
+
diff --git a/doc/cla/individual/manalimalpani.md b/doc/cla/individual/manalimalpani.md
new file mode 100644
index 0000000000..0dd9e6c66d
--- /dev/null
+++ b/doc/cla/individual/manalimalpani.md
@@ -0,0 +1,10 @@
+Ireland, 2021-06-18
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+Manali Malpani manali.malpani@ibm.com https://github.com/manali-malpani
\ No newline at end of file
diff --git a/doc/cla/individual/manishkumarbohra.md b/doc/cla/individual/manishkumarbohra.md
new file mode 100755
index 0000000000..566a322fdb
--- /dev/null
+++ b/doc/cla/individual/manishkumarbohra.md
@@ -0,0 +1,11 @@
+India, 2021-08-16
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Manish Bohra manishkumarbohra@outlook.com https://github.com/manishkumarbohra
diff --git a/doc/cla/individual/mashanz.md b/doc/cla/individual/mashanz.md
new file mode 100644
index 0000000000..0f2f247d0d
--- /dev/null
+++ b/doc/cla/individual/mashanz.md
@@ -0,0 +1,11 @@
+Indonesia, 2021-06-24
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Hanjara CA mangatkk@gmail.com https://github.com/mashanz
\ No newline at end of file
diff --git a/doc/cla/individual/mehjabin.md b/doc/cla/individual/mehjabin.md
new file mode 100644
index 0000000000..b74567f02c
--- /dev/null
+++ b/doc/cla/individual/mehjabin.md
@@ -0,0 +1,12 @@
+India, 2023-01-23
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Mehjabin Farsana mehjabinfarsanapc@gmail.com https://github.com/mehjabinfarsana
+
diff --git a/doc/cla/individual/mhabboush.md b/doc/cla/individual/mhabboush.md
new file mode 100644
index 0000000000..acb2b580f8
--- /dev/null
+++ b/doc/cla/individual/mhabboush.md
@@ -0,0 +1,11 @@
+Saudi Arabia, 2021-06-18
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Mahmoud Habboush iii.ma7mod.iii@gmail.com https://github.com/mhabboush
diff --git a/doc/cla/individual/miikanissi.md b/doc/cla/individual/miikanissi.md
new file mode 100644
index 0000000000..7f1e6be4e8
--- /dev/null
+++ b/doc/cla/individual/miikanissi.md
@@ -0,0 +1,11 @@
+United States, 2022-09-26
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Miika Nissi miika@miikanissi.com https://github.com/miikanissi
diff --git a/doc/cla/individual/milwell.md b/doc/cla/individual/milwell.md
new file mode 100644
index 0000000000..8e8af5cb31
--- /dev/null
+++ b/doc/cla/individual/milwell.md
@@ -0,0 +1,11 @@
+Philippines, 2023-07-27
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Milwell Sia milwell@milwell.com https://github.com/milwell
diff --git a/doc/cla/individual/mshahbazi.md b/doc/cla/individual/mshahbazi.md
new file mode 100644
index 0000000000..9e99b9e95a
--- /dev/null
+++ b/doc/cla/individual/mshahbazi.md
@@ -0,0 +1,9 @@
+Iran, 2021-03-19
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Mohammad M. Shahbazi https://github.com/mshahbazi
diff --git a/doc/cla/individual/msteinfeld.md b/doc/cla/individual/msteinfeld.md
new file mode 100644
index 0000000000..2f5c156d3b
--- /dev/null
+++ b/doc/cla/individual/msteinfeld.md
@@ -0,0 +1,11 @@
+Germany, 2020-01-24
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Maik Steinfeld entwicklung@steinfeld.one https://github.com/msteinfeld
diff --git a/doc/cla/individual/mt-software-de.md b/doc/cla/individual/mt-software-de.md
new file mode 100644
index 0000000000..868885012f
--- /dev/null
+++ b/doc/cla/individual/mt-software-de.md
@@ -0,0 +1,11 @@
+Germany, 2021-10-19
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Michael Tietz mtietz@mt-software.de https://github.com/mt-software-de
diff --git a/doc/cla/individual/newtratip.md b/doc/cla/individual/newtratip.md
new file mode 100644
index 0000000000..decfdb7907
--- /dev/null
+++ b/doc/cla/individual/newtratip.md
@@ -0,0 +1,11 @@
+Thailand, 2021-05-23
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Tharathip Chaweewongphan tharathip.chaweewongphan@gmail.com https://github.com/newtratip
diff --git a/doc/cla/individual/nikohoseki.md b/doc/cla/individual/nikohoseki.md
new file mode 100644
index 0000000000..63d03cb45e
--- /dev/null
+++ b/doc/cla/individual/nikohoseki.md
@@ -0,0 +1,11 @@
+Indonesia, 2021-02-25
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Niko Jenius 77722602+nikohoseki@users.noreply.github.com https://github.com/nikohoseki
diff --git a/doc/cla/individual/oerp-flectra.md b/doc/cla/individual/oerp-flectra.md
new file mode 100644
index 0000000000..0b7f61d3ea
--- /dev/null
+++ b/doc/cla/individual/oerp-flectra.md
@@ -0,0 +1,9 @@
+Lithuania, 2023-03-15
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Andrius Laukavičius anlaukavic@gmail.com https://github.com/oerp-flectra
diff --git a/doc/cla/individual/os-ia.md b/doc/cla/individual/os-ia.md
new file mode 100644
index 0000000000..70491038c7
--- /dev/null
+++ b/doc/cla/individual/os-ia.md
@@ -0,0 +1,11 @@
+Spain, 2021-02-05
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Iago Alonso iago.alonso@opensolutions.net https://github.com/os-ia
diff --git a/doc/cla/individual/ossimantylahti.md b/doc/cla/individual/ossimantylahti.md
new file mode 100644
index 0000000000..1f4deb839e
--- /dev/null
+++ b/doc/cla/individual/ossimantylahti.md
@@ -0,0 +1,11 @@
+Finland, 2021-03-07
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Ossi Mäntylahti 37711285+ossimantylahti@users.noreply.github.com https://github.com/ossimantylahti
diff --git a/doc/cla/individual/paimonchan.md b/doc/cla/individual/paimonchan.md
new file mode 100644
index 0000000000..720a0c8746
--- /dev/null
+++ b/doc/cla/individual/paimonchan.md
@@ -0,0 +1,11 @@
+Indonesia, 2023-01-28
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Nazzun Hanif Ahsani nazzunhanif@gmail.com https://github.com/paimonchan
diff --git a/doc/cla/individual/partho222.md b/doc/cla/individual/partho222.md
new file mode 100644
index 0000000000..a8dd325c88
--- /dev/null
+++ b/doc/cla/individual/partho222.md
@@ -0,0 +1,11 @@
+Bangladesh, 2021-11-18
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Tariq Ahmed Khan partho222@gmail.com https://github.com/partho222
diff --git a/doc/cla/individual/petrus-v.md b/doc/cla/individual/petrus-v.md
new file mode 100644
index 0000000000..8c41234f0c
--- /dev/null
+++ b/doc/cla/individual/petrus-v.md
@@ -0,0 +1,11 @@
+France, 2021-03-22
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Pierre Verkest pierreverkest84@gmail.com https://github.com/petrus-v
diff --git a/doc/cla/individual/ppreeper.md b/doc/cla/individual/ppreeper.md
new file mode 100644
index 0000000000..9d02b6bf0f
--- /dev/null
+++ b/doc/cla/individual/ppreeper.md
@@ -0,0 +1,11 @@
+Canada, 2022-02-03
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Peter Preeper ppreeper@gmail.com https://github.com/ppreeper
diff --git a/doc/cla/individual/qaidjoharbarbhaya.md b/doc/cla/individual/qaidjoharbarbhaya.md
new file mode 100644
index 0000000000..6524c1fd00
--- /dev/null
+++ b/doc/cla/individual/qaidjoharbarbhaya.md
@@ -0,0 +1,11 @@
+India, 2021-03-16
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Qaidjohar qaidjoharbarbhaya@gmail.com https://github.com/QaidjoharBarbhaya
diff --git a/doc/cla/individual/ramiadavid.md b/doc/cla/individual/ramiadavid.md
new file mode 100644
index 0000000000..bac91610f8
--- /dev/null
+++ b/doc/cla/individual/ramiadavid.md
@@ -0,0 +1,11 @@
+spain, 2022/1/12
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+david ramia david.ramia@processcontrol.es https://github.com/ramiadavid
diff --git a/doc/cla/individual/saran440.md b/doc/cla/individual/saran440.md
new file mode 100644
index 0000000000..e975c5bf75
--- /dev/null
+++ b/doc/cla/individual/saran440.md
@@ -0,0 +1,11 @@
+Thailand, 2021-08-20
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Saran saranl@ecosoft.co.th https://github.com/Saran440
diff --git a/doc/cla/individual/shide.md b/doc/cla/individual/shide.md
new file mode 100644
index 0000000000..64a2ba2988
--- /dev/null
+++ b/doc/cla/individual/shide.md
@@ -0,0 +1,11 @@
+Spain, 2021-03-16
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Eduardo de Miguel shide.shugo@gmail.com https://github.com/Shide
diff --git a/doc/cla/individual/shurshilov.md b/doc/cla/individual/shurshilov.md
new file mode 100644
index 0000000000..9123f40c13
--- /dev/null
+++ b/doc/cla/individual/shurshilov.md
@@ -0,0 +1,11 @@
+Russia, 2022-03-11
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Artem Shurshilov shurshilov.a@yandex.ru https://github.com/shurshilov
diff --git a/doc/cla/individual/simonevagile.md b/doc/cla/individual/simonevagile.md
new file mode 100644
index 0000000000..035b35dc08
--- /dev/null
+++ b/doc/cla/individual/simonevagile.md
@@ -0,0 +1,11 @@
+
+
+Italy, 2021-11-11
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Simone Vanin simone.vanin@agilebg.com https://github.com/SimoneVagile
diff --git a/doc/cla/individual/sirtakobi.md b/doc/cla/individual/sirtakobi.md
new file mode 100644
index 0000000000..fea6c4cdd5
--- /dev/null
+++ b/doc/cla/individual/sirtakobi.md
@@ -0,0 +1,11 @@
+Italy, 2022-04-07
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Simone Rubino https://github.com/SirTakobi
\ No newline at end of file
diff --git a/doc/cla/individual/sushiwushi.md b/doc/cla/individual/sushiwushi.md
new file mode 100644
index 0000000000..c7e18b65f0
--- /dev/null
+++ b/doc/cla/individual/sushiwushi.md
@@ -0,0 +1,11 @@
+Malaysia, 2021-06-01
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+iamsushi 45194995+sushiwushi@users.noreply.github.com https://github.com/sushiwushi
diff --git a/doc/cla/individual/thicham43.md b/doc/cla/individual/thicham43.md
new file mode 100644
index 0000000000..6cc3d47014
--- /dev/null
+++ b/doc/cla/individual/thicham43.md
@@ -0,0 +1,11 @@
+Morocco, 2021-08-09
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Hicham TAROQ taroqhicham@gmail.com https://github.com/thicham43
diff --git a/doc/cla/individual/tranngocson1996.md b/doc/cla/individual/tranngocson1996.md
new file mode 100644
index 0000000000..8f2bbc77ff
--- /dev/null
+++ b/doc/cla/individual/tranngocson1996.md
@@ -0,0 +1,9 @@
+Vietnam, 2023-03-31
+
+I hereby agree to the terms of the Flectra Individual Contributor License Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this declaration.
+
+Signed,
+
+Tran Ngoc Son tranngocson8296@gmail.com https://github.com/tranngocson1996
diff --git a/doc/cla/individual/tvibliani.md b/doc/cla/individual/tvibliani.md
new file mode 100644
index 0000000000..a7a0155cfa
--- /dev/null
+++ b/doc/cla/individual/tvibliani.md
@@ -0,0 +1,11 @@
+Georgia, 2021-01-02
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Temur Vibliani tvibliani@users.noreply.github.com https://github.com/tvibliani
diff --git a/doc/cla/individual/veryberry.md b/doc/cla/individual/veryberry.md
new file mode 100644
index 0000000000..2ae0c6ac71
--- /dev/null
+++ b/doc/cla/individual/veryberry.md
@@ -0,0 +1,11 @@
+Belarus, 2021-03-16
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Veronika Kotovich veronika.kotovich@gmail.com https://github.com/veryberry
diff --git a/doc/cla/individual/zwgshr.md b/doc/cla/individual/zwgshr.md
new file mode 100644
index 0000000000..f5ecb12801
--- /dev/null
+++ b/doc/cla/individual/zwgshr.md
@@ -0,0 +1,11 @@
+china, 2020-11-26
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Zhang WenGuang zwgmlr3@outlook.com https://github.com/zwgshr
diff --git a/doc/cla/individual/zyzcss.md b/doc/cla/individual/zyzcss.md
new file mode 100644
index 0000000000..c790126920
--- /dev/null
+++ b/doc/cla/individual/zyzcss.md
@@ -0,0 +1,11 @@
+China, 2023-01-05
+
+I hereby agree to the terms of the Flectra Individual Contributor License
+Agreement v1.0.
+
+I declare that I am authorized and able to make this agreement and sign this
+declaration.
+
+Signed,
+
+Zhou Yingze yzdslloli@163.com https://github.com/zyzcss
diff --git a/doc/setup/install.rst b/doc/setup/install.rst
index 78db80a40e..5265e3b2d3 100644
--- a/doc/setup/install.rst
+++ b/doc/setup/install.rst
@@ -49,7 +49,7 @@ Demo_ instances require no local installation, just a web browser.
SaaS
----
-Trivial to start with, fully managed and migrated by Flectra S.A., Flectra's SaaS_
+Trivial to start with, fully managed and migrated by FlectraHQ, Inc., Flectra's SaaS_
provides private instances and starts out free. It can be used to discover and
test Flectra and do non-code customizations (i.e. incompatible with custom modules
or the Flectra Apps Store) without having to install it locally.
@@ -119,7 +119,7 @@ Flectra instance. Execute the following command in order to install the PostgreS
Repository
^^^^^^^^^^
-Flectra S.A. provides a repository that can be used with Debian and Ubuntu distributions. It can be
+FlectraHQ, Inc. provides a repository that can be used with Debian and Ubuntu distributions. It can be
used to install *Flectra Community Edition* by executing the following commands **as root**:
.. code-block:: console
@@ -194,7 +194,7 @@ server:
Repository
^^^^^^^^^^
-Flectra S.A. provides a repository that can be used with the Fedora distributions.
+FlectraHQ, Inc. provides a repository that can be used with the Fedora distributions.
It can be used to install *Flectra Community Edition* by executing the following
commands:
diff --git a/flectra/__init__.py b/flectra/__init__.py
index 819c72f0fb..8f6decb850 100644
--- a/flectra/__init__.py
+++ b/flectra/__init__.py
@@ -16,7 +16,7 @@ __path__ = [
]
import sys
-assert sys.version_info > (3, 6), "Outdated python version detected, Odoo requires Python >= 3.6 to run."
+assert sys.version_info > (3, 6), "Outdated python version detected, Flectra requires Python >= 3.6 to run."
#----------------------------------------------------------
# Running mode flags (gevent, prefork)
diff --git a/flectra/addons/__init__.py b/flectra/addons/__init__.py
index fdea2b9900..bd4727c63a 100644
--- a/flectra/addons/__init__.py
+++ b/flectra/addons/__init__.py
@@ -3,7 +3,7 @@
""" Addons module.
-This module serves to contain all Odoo addons, across all configured addons
+This module serves to contain all Flectra addons, across all configured addons
paths. For the code to manage those addons, see flectra.modules.
Addons are made available under `flectra.addons` after
diff --git a/flectra/addons/base/__manifest__.py b/flectra/addons/base/__manifest__.py
index eccc702a21..6d7ddd7766 100644
--- a/flectra/addons/base/__manifest__.py
+++ b/flectra/addons/base/__manifest__.py
@@ -7,7 +7,7 @@
'version': '1.3',
'category': 'Hidden',
'description': """
-The kernel of Odoo, needed for all installation.
+The kernel of Flectra, needed for all installation.
===================================================
""",
'depends': [],
diff --git a/flectra/addons/base/data/ir_module_module.xml b/flectra/addons/base/data/ir_module_module.xml
index 00cd462bcc..37d0d17163 100644
--- a/flectra/addons/base/data/ir_module_module.xml
+++ b/flectra/addons/base/data/ir_module_module.xml
@@ -10,10 +10,10 @@
Create and Customize ApplicationsOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/web_studio.png
- https://flectra.com/page/studio?utm_source=db&utm_medium=module
+ https://flectrahq.com/page/studio?utm_source=db&utm_medium=module
@@ -24,10 +24,10 @@
Track time & costsOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/timesheet_grid.png
- https://www.flectra.com/page/timesheet-mobile-app?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/timesheet-mobile-app?utm_source=db&utm_medium=module
@@ -38,10 +38,10 @@
Accounting, Taxes, Budgets, Assets...OEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/account_accountant.png
- https://www.flectra.com/page/accounting?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/accounting?utm_source=db&utm_medium=module
@@ -52,10 +52,10 @@
Track support ticketsOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/helpdesk.png
- https://www.flectra.com/page/helpdesk?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/helpdesk?utm_source=db&utm_medium=module
@@ -66,10 +66,10 @@
Assess your employeesOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/hr_appraisal.png
- https://www.flectra.com/page/appraisal?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/appraisal?utm_source=db&utm_medium=module
@@ -80,10 +80,10 @@
Build automated mailing campaignsOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/marketing_automation.png
- https://www.flectra.com/page/marketing-automation?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/marketing-automation?utm_source=db&utm_medium=module
@@ -94,10 +94,10 @@
PLM, ECOs, VersionsOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/mrp_plm.png
- https://www.flectra.com/page/mrp-plm?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/mrp-plm?utm_source=db&utm_medium=module
@@ -108,10 +108,10 @@
Quality Alerts, Control PointsOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/quality_control.png
- https://www.flectra.com/page/quality-management-software?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/quality-management-software?utm_source=db&utm_medium=module
@@ -122,10 +122,10 @@
Sell on eBay easilyOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/sale_ebay.png
- https://www.flectra.com/page/sales?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/sales?utm_source=db&utm_medium=module
@@ -136,10 +136,10 @@
Manage your employees' scheduleOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/planning.png
- https://www.flectra.com/page/planning?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/planning?utm_source=db&utm_medium=module
@@ -150,10 +150,10 @@
MRR, Churn, Recurring paymentsOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/sale_subscription.png
- https://www.flectra.com/page/subscriptions?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/subscriptions?utm_source=db&utm_medium=module
@@ -164,10 +164,10 @@
Send documents to sign onlineOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/sign.png
- https://www.flectra.com/page/sign?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/sign?utm_source=db&utm_medium=module
@@ -178,10 +178,10 @@
Barcode scanner for warehousesOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/stock_barcode.png
- https://www.flectra.com/page/warehouse?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/warehouse?utm_source=db&utm_medium=module
@@ -192,10 +192,10 @@
Call using VoIPOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/voip.png
- https://www.flectra.com/page/crm?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/crm?utm_source=db&utm_medium=module
@@ -206,10 +206,10 @@
Online appointments schedulerOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/website_calendar.png
- https://www.flectra.com/page/appointments?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/appointments?utm_source=db&utm_medium=module
@@ -220,10 +220,10 @@
Work Orders, Planning, RoutingOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/mrp_workorder.png
- https://www.flectra.com/page/mrp-cloud-software?utm_source=db&utm_medium=module
+ https://www.flectrahq.com/page/mrp-cloud-software?utm_source=db&utm_medium=module
@@ -234,7 +234,7 @@
Support for Android & iOS AppsOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/web_mobile.pnghttps://play.google.com/store/apps/details?id=com.flectra.mobile
@@ -246,7 +246,7 @@
Interactive twitter wall for eventsOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/website_twitter_wall.png
@@ -257,7 +257,7 @@
Checkout with SEPA Direct DebitOEEL-1
- Odoo S.A.
+ FlectraHQ, Inc./base/static/img/icons/payment_sepa_direct_debit.png
diff --git a/flectra/addons/base/models/assetsbundle.py b/flectra/addons/base/models/assetsbundle.py
index 62aa27e243..fb449a0871 100644
--- a/flectra/addons/base/models/assetsbundle.py
+++ b/flectra/addons/base/models/assetsbundle.py
@@ -539,7 +539,7 @@ class AssetsBundle(object):
if '.' not in ref and line not in imports and not ref.startswith(('.', '/', '~')):
imports.append(line)
return line
- msg = "Local import '%s' is forbidden for security reasons. Please remove all @import {your_file} imports in your custom files. In Odoo you have to import all files in the assets, and not through the @import statement." % ref
+ msg = "Local import '%s' is forbidden for security reasons. Please remove all @import {your_file} imports in your custom files. In Flectra you have to import all files in the assets, and not through the @import statement." % ref
_logger.warning(msg)
self.css_errors.append(msg)
return ''
diff --git a/flectra/addons/base/models/ir_actions.py b/flectra/addons/base/models/ir_actions.py
index d2dddbd955..4c86209aa0 100644
--- a/flectra/addons/base/models/ir_actions.py
+++ b/flectra/addons/base/models/ir_actions.py
@@ -357,7 +357,7 @@ class IrActionsServer(models.Model):
action rules, of manually, by adding the action in the 'More' contextual
menu.
- Since Odoo 8.0 a button 'Create Menu Action' button is available on the
+ Since Flectra 8.0 a button 'Create Menu Action' button is available on the
action form view. It creates an entry in the More menu of the base model.
This allows to create server actions and run them in mass mode easily through
the interface.
@@ -378,12 +378,12 @@ class IrActionsServer(models.Model):
_order = 'sequence,name'
DEFAULT_PYTHON_CODE = """# Available variables:
-# - env: Odoo Environment on which the action is triggered
-# - model: Odoo Model of the record on which the action is triggered; is a void recordset
+# - env: Flectra Environment on which the action is triggered
+# - model: Flectra Model of the record on which the action is triggered; is a void recordset
# - record: record on which the action is triggered; may be void
# - records: recordset of all records on which the action is triggered in multi-mode; may be void
# - time, datetime, dateutil, timezone: useful Python libraries
-# - float_compare: Odoo function to compare floats based on specific precisions
+# - float_compare: Flectra function to compare floats based on specific precisions
# - log: log(message, level='info'): logging function to record debug information in ir.logging table
# - UserError: Warning Exception to use with raise
# To return an action, assign: action = {...}\n\n\n\n"""
diff --git a/flectra/addons/base/models/ir_actions_report.py b/flectra/addons/base/models/ir_actions_report.py
index 3f2cca8945..369d0039d3 100644
--- a/flectra/addons/base/models/ir_actions_report.py
+++ b/flectra/addons/base/models/ir_actions_report.py
@@ -43,7 +43,7 @@ _logger = logging.getLogger(__name__)
# A lock occurs when the user wants to print a report having multiple barcode while the server is
# started in threaded-mode. The reason is that reportlab has to build a cache of the T1 fonts
# before rendering a barcode (done in a C extension) and this part is not thread safe. We attempt
-# here to init the T1 fonts cache at the start-up of Odoo so that rendering of barcode in multiple
+# here to init the T1 fonts cache at the start-up of Flectra so that rendering of barcode in multiple
# thread does not lock the server.
try:
createBarcodeDrawing('Code128', value='foo', format='png', width=100, height=100, humanReadable=1).asString('png')
@@ -55,7 +55,7 @@ def _get_wkhtmltopdf_bin():
return find_in_path('wkhtmltopdf')
-# Check the presence of Wkhtmltopdf and return its version at Odoo start-up
+# Check the presence of Wkhtmltopdf and return its version at Flectra start-up
wkhtmltopdf_state = 'install'
wkhtmltopdf_dpi_zoom_ratio = False
try:
@@ -79,7 +79,7 @@ else:
wkhtmltopdf_dpi_zoom_ratio = True
if config['workers'] == 1:
- _logger.info('You need to start Odoo with at least two workers to print a pdf version of the reports.')
+ _logger.info('You need to start Flectra with at least two workers to print a pdf version of the reports.')
wkhtmltopdf_state = 'workers'
else:
_logger.info('Wkhtmltopdf seems to be broken.')
@@ -798,7 +798,7 @@ class IrActionsReport(models.Model):
if unreadable_pdfs:
records = [stream_record[s].name for s in unreadable_pdfs if s in stream_record]
raise UserError(_(
- "Odoo is unable to merge the PDFs attached to the following records:\n"
+ "Flectra is unable to merge the PDFs attached to the following records:\n"
"%s\n\n"
"Please exclude them from the selection to continue. It's possible to "
"still retrieve those PDFs by selecting each of the affected records "
diff --git a/flectra/addons/base/models/ir_mail_server.py b/flectra/addons/base/models/ir_mail_server.py
index 78cc7450fc..efcafe60ce 100644
--- a/flectra/addons/base/models/ir_mail_server.py
+++ b/flectra/addons/base/models/ir_mail_server.py
@@ -108,7 +108,7 @@ class IrMailServer(models.Model):
if not email_from:
raise UserError(_('Please configure an email on the current user to simulate '
'sending an email message via this outgoing server'))
- return email_from, 'noreply@flectra.com'
+ return email_from, 'noreply@flectrahq.com'
def test_smtp_connection(self):
for server in self:
@@ -224,7 +224,7 @@ class IrMailServer(models.Model):
if smtp_encryption == 'ssl':
if 'SMTP_SSL' not in smtplib.__all__:
raise UserError(
- _("Your Odoo Server does not support SMTP-over-SSL. "
+ _("Your Flectra Server does not support SMTP-over-SSL. "
"You could use STARTTLS instead. "
"If SSL is needed, an upgrade to Python 2.6 on the server-side "
"should do the trick."))
diff --git a/flectra/addons/base/models/ir_model.py b/flectra/addons/base/models/ir_model.py
index a91e0ef002..210eb887c5 100644
--- a/flectra/addons/base/models/ir_model.py
+++ b/flectra/addons/base/models/ir_model.py
@@ -1468,7 +1468,7 @@ class IrModelSelection(models.Model):
class IrModelConstraint(models.Model):
"""
- This model tracks PostgreSQL foreign keys and constraints used by Odoo
+ This model tracks PostgreSQL foreign keys and constraints used by Flectra
models.
"""
_name = 'ir.model.constraint'
@@ -1621,7 +1621,7 @@ class IrModelConstraint(models.Model):
class IrModelRelation(models.Model):
"""
- This model tracks PostgreSQL tables used to implement Odoo many2many
+ This model tracks PostgreSQL tables used to implement Flectra many2many
relations.
"""
_name = 'ir.model.relation'
@@ -1869,7 +1869,7 @@ class IrModelData(models.Model):
* allows easy data integration with third-party systems,
making import/export/sync of data possible, as records
can be uniquely identified across multiple systems
- * allows tracking the origin of data installed by Odoo
+ * allows tracking the origin of data installed by Flectra
modules themselves, thus making it possible to later
update them seamlessly.
"""
diff --git a/flectra/addons/base/models/ir_module.py b/flectra/addons/base/models/ir_module.py
index 40efce4ae5..f1ee80733f 100644
--- a/flectra/addons/base/models/ir_module.py
+++ b/flectra/addons/base/models/ir_module.py
@@ -288,8 +288,8 @@ class Module(models.Model):
('AGPL-3', 'Affero GPL-3'),
('LGPL-3', 'LGPL Version 3'),
('Other OSI approved licence', 'Other OSI Approved License'),
- ('OEEL-1', 'Odoo Enterprise Edition License v1.0'),
- ('OPL-1', 'Odoo Proprietary License v1.0'),
+ ('OEEL-1', 'Flectra Professional Edition License v1.0'),
+ ('OPL-1', 'Flectra Proprietary License v1.0'),
('Other proprietary', 'Other Proprietary')
], string='License', default='LGPL-3', readonly=True)
menus_by_module = fields.Text(string='Menus', compute='_get_views', store=True)
@@ -298,7 +298,7 @@ class Module(models.Model):
application = fields.Boolean('Application', readonly=True)
icon = fields.Char('Icon URL')
icon_image = fields.Binary(string='Icon', compute='_get_icon_image')
- to_buy = fields.Boolean('Odoo Enterprise Module', default=False)
+ to_buy = fields.Boolean('Flectra Professional Module', default=False)
has_iap = fields.Boolean(compute='_compute_has_iap')
_sql_constraints = [
@@ -551,7 +551,7 @@ class Module(models.Model):
# during execution, the lock won't be released until timeout.
self._cr.execute("SELECT * FROM ir_cron FOR UPDATE NOWAIT")
except psycopg2.OperationalError:
- raise UserError(_("Odoo is currently processing a scheduled action.\n"
+ raise UserError(_("Flectra is currently processing a scheduled action.\n"
"Module operations are not possible at this time, "
"please try again later or contact your system administrator."))
function(self)
@@ -852,7 +852,7 @@ class Module(models.Model):
@api.model
def get_apps_server(self):
- return tools.config.get('apps_server', 'https://apps.flectra.com/apps')
+ return tools.config.get('apps_server', 'https://apps.flectrahq.com/apps')
def _update_dependencies(self, depends=None, auto_install_requirements=()):
existing = set(dep.name for dep in self.dependencies_id)
diff --git a/flectra/addons/base/models/ir_sequence.py b/flectra/addons/base/models/ir_sequence.py
index b40ba474a5..a496bc0379 100644
--- a/flectra/addons/base/models/ir_sequence.py
+++ b/flectra/addons/base/models/ir_sequence.py
@@ -143,7 +143,7 @@ class IrSequence(models.Model):
number_increment = fields.Integer(string='Step', required=True, default=1,
help="The next number of the sequence will be incremented by this number")
padding = fields.Integer(string='Sequence Size', required=True, default=0,
- help="Odoo will automatically adds some '0' on the left of the "
+ help="Flectra will automatically adds some '0' on the left of the "
"'Next Number' to get the required padding size.")
company_id = fields.Many2one('res.company', string='Company',
default=lambda s: s.env.company)
diff --git a/flectra/addons/base/models/ir_ui_menu.py b/flectra/addons/base/models/ir_ui_menu.py
index 0f68c0e986..7be1b8a922 100644
--- a/flectra/addons/base/models/ir_ui_menu.py
+++ b/flectra/addons/base/models/ir_ui_menu.py
@@ -33,7 +33,7 @@ class IrUiMenu(models.Model):
groups_id = fields.Many2many('res.groups', 'ir_ui_menu_group_rel',
'menu_id', 'gid', string='Groups',
help="If you have groups, the visibility of this menu will be based on these groups. "\
- "If this field is empty, Odoo will compute visibility based on the related object's read access.")
+ "If this field is empty, Flectra will compute visibility based on the related object's read access.")
complete_name = fields.Char(compute='_compute_complete_name', string='Full Path')
web_icon = fields.Char(string='Web Icon File')
action = fields.Reference(selection=[('ir.actions.report', 'ir.actions.report'),
diff --git a/flectra/addons/base/models/qweb.py b/flectra/addons/base/models/qweb.py
index 4e0dbf5053..78d21e2b3d 100644
--- a/flectra/addons/base/models/qweb.py
+++ b/flectra/addons/base/models/qweb.py
@@ -1276,7 +1276,7 @@ class QWeb(object):
return ast_options if ast_options and ast_options.keys else None
def _compile_directive_field(self, el, options):
- """ Compile something like ``+1 555 555 8069`` """
+ """ Compile something like ``+1 555 555 7073`` """
node_name = el.tag
assert node_name not in ("table", "tbody", "thead", "tfoot", "tr", "td",
"li", "ul", "ol", "dl", "dt", "dd"),\
diff --git a/flectra/addons/base/models/res_users.py b/flectra/addons/base/models/res_users.py
index 25dad6dd5a..7ab209d5e1 100644
--- a/flectra/addons/base/models/res_users.py
+++ b/flectra/addons/base/models/res_users.py
@@ -607,7 +607,7 @@ class Users(models.Model):
def unlink(self):
if SUPERUSER_ID in self.ids:
- raise UserError(_('You can not remove the admin user as it is used internally for resources created by Odoo (updates, module installation, ...)'))
+ raise UserError(_('You can not remove the admin user as it is used internally for resources created by Flectra (updates, module installation, ...)'))
self.clear_caches()
return super(Users, self).unlink()
@@ -946,10 +946,10 @@ class Users(models.Model):
if ipaddress.ip_address(source).is_private:
_logger.warning(
"The rate-limited IP address %s is classified as private "
- "and *might* be a proxy. If your Odoo is behind a proxy, "
+ "and *might* be a proxy. If your Flectra is behind a proxy, "
"it may be mis-configured. Check that you are running "
- "Odoo in Proxy Mode and that the proxy is properly configured, see "
- "https://www.flectra.com/documentation/14.0/administration/deployment/deploy.html#https for details.",
+ "Flectra in Proxy Mode and that the proxy is properly configured, see "
+ "https://www.flectrahq.com/documentation/14.0/administration/deployment/deploy.html#https for details.",
source
)
raise AccessDenied(_("Too many login failures, please wait a bit before trying again."))
diff --git a/flectra/addons/base/report/corporate_defaults.xsl b/flectra/addons/base/report/corporate_defaults.xsl
index 7f7a1e8182..168b6684db 100644
--- a/flectra/addons/base/report/corporate_defaults.xsl
+++ b/flectra/addons/base/report/corporate_defaults.xsl
@@ -2,7 +2,7 @@
- Odoo Report
+ Flectra Report1cm1cm1cm
diff --git a/flectra/addons/base/report/custom_rml_printscreen.xsl b/flectra/addons/base/report/custom_rml_printscreen.xsl
index 52cba543d8..42571987bb 100644
--- a/flectra/addons/base/report/custom_rml_printscreen.xsl
+++ b/flectra/addons/base/report/custom_rml_printscreen.xsl
@@ -6,7 +6,7 @@
-
+
diff --git a/flectra/addons/base/security/base_groups.xml b/flectra/addons/base/security/base_groups.xml
index bc82e5525d..a6e0a5909e 100644
--- a/flectra/addons/base/security/base_groups.xml
+++ b/flectra/addons/base/security/base_groups.xml
@@ -62,7 +62,7 @@
PortalPortal members have specific access rights (such as record rules and restricted menus).
- They usually do not belong to the usual Odoo groups.
+ They usually do not belong to the usual Flectra groups.
Third-Party Apps
- https://apps.flectra.com/apps/modules
+ https://apps.flectrahq.com/apps/modulesTheme Store
- https://apps.flectra.com/apps/themes
+ https://apps.flectrahq.com/apps/themes
diff --git a/flectra/addons/base/views/ir_ui_menu_views.xml b/flectra/addons/base/views/ir_ui_menu_views.xml
index 1336909ff6..2d417887b9 100644
--- a/flectra/addons/base/views/ir_ui_menu_views.xml
+++ b/flectra/addons/base/views/ir_ui_menu_views.xml
@@ -69,7 +69,7 @@
{'ir.ui.menu.full_list':True}
- Manage and customize the items available and displayed in your Odoo system menu. You can delete an item by clicking on the box at the beginning of each line and then delete it through the button that appeared. Items can be assigned to specific groups in order to make them accessible to some users within the system.
+ Manage and customize the items available and displayed in your Flectra system menu. You can delete an item by clicking on the box at the beginning of each line and then delete it through the button that appeared. Items can be assigned to specific groups in order to make them accessible to some users within the system.
diff --git a/flectra/addons/base/views/ir_ui_view_views.xml b/flectra/addons/base/views/ir_ui_view_views.xml
index df669ce0c3..9659dffa95 100644
--- a/flectra/addons/base/views/ir_ui_view_views.xml
+++ b/flectra/addons/base/views/ir_ui_view_views.xml
@@ -24,7 +24,7 @@
Be aware that editing the architecture of a standard view is not advised, since the changes will be overwritten during future module updates.
- We recommend applying modifications to standard views through inherited views or customization with Odoo Studio.
+ We recommend applying modifications to standard views through inherited views or customization with Flectra Studio.
@@ -98,7 +98,7 @@
ir.ui.view{'search_default_active': 1}
- Views allows you to personalize each view of Odoo. You can add new fields, move fields, rename them or delete the ones that you do not need.
+ Views allows you to personalize each view of Flectra. You can add new fields, move fields, rename them or delete the ones that you do not need.
diff --git a/flectra/addons/base/views/res_company_views.xml b/flectra/addons/base/views/res_company_views.xml
index c7c598f6d1..757dee21f9 100644
--- a/flectra/addons/base/views/res_company_views.xml
+++ b/flectra/addons/base/views/res_company_views.xml
@@ -30,7 +30,7 @@
-
+
@@ -113,7 +113,7 @@
Create a new company
- Create and manage the companies that will be managed by Odoo from here. Shops or subsidiaries can be created and maintained from here.
+ Create and manage the companies that will be managed by Flectra from here. Shops or subsidiaries can be created and maintained from here.