From 5af27ea4acfca2f4262721202f9a3e20ab9e9200 Mon Sep 17 00:00:00 2001 From: Julien Van Roy Date: Mon, 20 Nov 2023 10:11:50 +0100 Subject: [PATCH] [ADD] l10n_jp_ubl_pint: Add PINT e-invoicing for Japan OpenPeppol released a new extension of its BIS 3 format for international use: PINT BIS Billing. It serves as a base for per-country specialization, while keeping a standard core for data being used across countries. This is not meant to be used directly, but rather to be extended by country-specific modules. Japan has implementated PINT and published its specific rules: https://docs.peppol.eu/poac/jp/pint-jp. A new module is created to add this format. task-3469718 closes odoo/odoo#136025 Signed-off-by: Laurent Smet (las) --- .../models/account_edi_common.py | 1 + addons/l10n_jp_ubl_pint/__init__.py | 1 + addons/l10n_jp_ubl_pint/__manifest__.py | 12 +++ addons/l10n_jp_ubl_pint/models/__init__.py | 2 + .../models/account_edi_xml_pint_jp.py | 89 +++++++++++++++++++ addons/l10n_jp_ubl_pint/models/res_partner.py | 20 +++++ 6 files changed, 125 insertions(+) create mode 100644 addons/l10n_jp_ubl_pint/__init__.py create mode 100644 addons/l10n_jp_ubl_pint/__manifest__.py create mode 100644 addons/l10n_jp_ubl_pint/models/__init__.py create mode 100644 addons/l10n_jp_ubl_pint/models/account_edi_xml_pint_jp.py create mode 100644 addons/l10n_jp_ubl_pint/models/res_partner.py diff --git a/addons/account_edi_ubl_cii/models/account_edi_common.py b/addons/account_edi_ubl_cii/models/account_edi_common.py index edab3ac1d10..9ac6c6bf5bd 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_common.py +++ b/addons/account_edi_ubl_cii/models/account_edi_common.py @@ -63,6 +63,7 @@ EAS_MAPPING = { 'IE': {'9935': 'vat'}, 'IS': {'0196': 'vat'}, 'IT': {'0211': 'vat', '0210': 'l10n_it_codice_fiscale'}, + 'JP': {'0221': 'vat'}, 'LI': {'9936': 'vat'}, 'LT': {'9937': 'vat'}, 'LU': {'9938': 'vat'}, diff --git a/addons/l10n_jp_ubl_pint/__init__.py b/addons/l10n_jp_ubl_pint/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/addons/l10n_jp_ubl_pint/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/addons/l10n_jp_ubl_pint/__manifest__.py b/addons/l10n_jp_ubl_pint/__manifest__.py new file mode 100644 index 00000000000..66fe46f3761 --- /dev/null +++ b/addons/l10n_jp_ubl_pint/__manifest__.py @@ -0,0 +1,12 @@ +{ + 'name': 'Japan - UBL PINT', + 'countries': ['jp'], + 'version': '1.0', + 'category': 'Accounting/Localizations/EDI', + 'description': """ + The UBL PINT e-invoicing format for Japan is based on the Peppol International (PINT) model for Billing. + """, + 'depends': ['account_edi_ubl_cii'], + 'installable': True, + 'license': 'LGPL-3' +} diff --git a/addons/l10n_jp_ubl_pint/models/__init__.py b/addons/l10n_jp_ubl_pint/models/__init__.py new file mode 100644 index 00000000000..32f0d90164f --- /dev/null +++ b/addons/l10n_jp_ubl_pint/models/__init__.py @@ -0,0 +1,2 @@ +from . import account_edi_xml_pint_jp +from . import res_partner diff --git a/addons/l10n_jp_ubl_pint/models/account_edi_xml_pint_jp.py b/addons/l10n_jp_ubl_pint/models/account_edi_xml_pint_jp.py new file mode 100644 index 00000000000..02ce0e6a98d --- /dev/null +++ b/addons/l10n_jp_ubl_pint/models/account_edi_xml_pint_jp.py @@ -0,0 +1,89 @@ +from odoo import models + + +class AccountEdiXmlUBLPINTJP(models.AbstractModel): + _inherit = "account.edi.xml.ubl_bis3" + _name = 'account.edi.xml.pint_jp' + _description = "Japanese implementation of Peppol International (PINT) model for Billing" + """ + Pint is a standard for International Billing from Peppol. It is based on Peppol BIS Billing 3. + It serves as a base for per-country specialization, while keeping a standard core for data being used + across countries. This is not meant to be used directly, but rather to be extended by country-specific modules. + + The JP PINT format is the Japanese implementation of PINT. + + * PINT Official documentation: https://docs.peppol.eu/poac/pint/pint/ + * PINT JP Official documentation: https://docs.peppol.eu/poac/jp/pint-jp + """ + + def _export_invoice_filename(self, invoice): + # EXTENDS account_edi_ubl_cii + return f"{invoice.name.replace('/', '_')}_pint_jp.xml" + + def _get_partner_address_vals(self, partner): + # EXTENDS account_edi_ubl_cii + vals = super()._get_partner_address_vals(partner) + vals.pop('country_subentity_code', None) + return vals + + def _get_partner_party_legal_entity_vals_list(self, partner): + # EXTENDS account_edi_ubl_cii + vals_list = super()._get_partner_party_legal_entity_vals_list(partner) + for vals in vals_list: + vals.pop('company_id') # optional, if set: scheme_id should be taken from ISO/IEC 6523 list + return vals_list + + def _get_invoice_period_vals_list(self, invoice): + # EXTENDS + vals_list = super()._get_invoice_period_vals_list(invoice) + # [aligned-ibrp-052] An Invoice MUST have an invoice period (ibg-14) or an Invoice line period (ibg-26). + vals_list.append({ + 'start_date': invoice.invoice_date, + 'end_date': invoice.invoice_date, + }) + return vals_list + + def _get_invoice_tax_totals_vals_list(self, invoice, taxes_vals): + # [aligned-ibr-jp-06]-Tax category tax amount (ibt-117) with currency code JPY and tax category tax amount + # in accounting currency (ibt-190) shall not have decimal. + # see also: https://docs.peppol.eu/poac/jp/pint-jp/bis/#_rounding + vals_list = super()._get_invoice_tax_totals_vals_list(invoice, taxes_vals) + for vals in vals_list: + vals['currency_dp'] = invoice.currency_id.decimal_places + for subtotal_vals in vals.get('tax_subtotal_vals', []): + subtotal_vals['currency_dp'] = invoice.currency_id.decimal_places + + company_currency = invoice.company_id.currency_id + if invoice.currency_id != company_currency: + # if company currency != invoice currency, need to add a TaxTotal section + # see https://docs.peppol.eu/poac/jp/pint-jp/bis/#_tax_in_accounting_currency + tax_totals_vals = { + 'currency': company_currency, + 'currency_dp': company_currency.decimal_places, + 'tax_amount': taxes_vals['tax_amount'], + 'tax_subtotal_vals': [], + } + for _grouping_key, vals in taxes_vals['tax_details'].items(): + tax_totals_vals['tax_subtotal_vals'].append({ + 'currency': company_currency, + 'currency_dp': company_currency.decimal_places, + 'taxable_amount': vals['base_amount'], + 'tax_amount': vals['tax_amount'], + 'percent': vals['_tax_category_vals_']['percent'], + 'tax_category_vals': vals['_tax_category_vals_'], + }) + vals_list.append(tax_totals_vals) + return vals_list + + def _export_invoice_vals(self, invoice): + # EXTENDS account_edi_ubl_cii + vals = super()._export_invoice_vals(invoice) + vals['vals'].update({ + # see https://docs.peppol.eu/poac/jp/pint-jp/bis/#profiles + 'customization_id': 'urn:peppol:pint:billing-1@jp-1', + 'profile_id': 'urn:peppol:bis:billing', + }) + if invoice.currency_id != invoice.company_id.currency_id: + # see https://docs.peppol.eu/poac/jp/pint-jp/bis/#_tax_in_accounting_currency + vals['vals']['tax_currency_code'] = invoice.company_id.currency_id.name # accounting currency + return vals diff --git a/addons/l10n_jp_ubl_pint/models/res_partner.py b/addons/l10n_jp_ubl_pint/models/res_partner.py new file mode 100644 index 00000000000..6e58de7985e --- /dev/null +++ b/addons/l10n_jp_ubl_pint/models/res_partner.py @@ -0,0 +1,20 @@ +from odoo import models, fields + + +class ResPartner(models.Model): + _inherit = 'res.partner' + + ubl_cii_format = fields.Selection(selection_add=[('pint_jp', "PINT Japan")]) + + def _get_edi_builder(self): + # EXTENDS 'account_edi_ubl_cii' + if self.ubl_cii_format == 'pint_jp': + return self.env['account.edi.xml.pint_jp'] + return super()._get_edi_builder() + + def _compute_ubl_cii_format(self): + # EXTENDS 'account_edi_ubl_cii' + super()._compute_ubl_cii_format() + for partner in self: + if partner.country_code == 'JP': + partner.ubl_cii_format = 'pint_jp'