diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0ce6eb6d9960..c4b6f633223e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,6 +22,7 @@ exclude: | (LICENSE.*|COPYING.*)| # official goverment specs (l10n_it_account/tools/xsd)| + (l10n_it_sct_cbi/data/standards)| # external stylesheets (l10n_it_fatturapa/data/Foglio_di_stile_fatturaordinaria_v1.2.2.xsl)| (l10n_it_fatturapa/data/fatturasemplificata_v1.0.xsl)| diff --git a/l10n_it_sct_cbi/README.rst b/l10n_it_sct_cbi/README.rst new file mode 100644 index 000000000000..7442ee26cb88 --- /dev/null +++ b/l10n_it_sct_cbi/README.rst @@ -0,0 +1,160 @@ +====================================== +ITA - Banking SEPA Credit Transfer CBI +====================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:02902c5254c68bfbf56f4d27f656976d29ad127c532e85dbf1d965b337bb505f + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--italy-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-italy/tree/16.0/l10n_it_sct_cbi + :alt: OCA/l10n-italy +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-italy-16-0/l10n-italy-16-0-l10n_it_sct_cbi + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/l10n-italy&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds new payment export types to use in the payment order. +For italian credit transfer, the format codes are + +- CBIBdyPaymentRequest.00.04.01 +- CBIBdyCrossBorderPaymentRequest.00.01.01 + +The created XML follows the CBI standards in +https://www.cbi-org.eu/My-Menu/Servizio-CBI-Documentazione/Servizio-CBI-Documentazione-Standard. + +Note (ITA): + +Le specifiche CBI del bonifico XML SEPA (versione 00.04.01) si basano +sul messaggio ISO20022 pain.001.001.09 e sono compliant al Rulebook +SEPA. + +Ad esempio la presenza obbligatoria dell’ABI della banca di addebito +contenuto nel campo “MmbId” che è invece facoltativo nel tracciato ISO. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +In Invoicing / Configuration / Settings / SEPA/PAIN, set: + +- the CUC code in field ``Initiating Party Identifier`` +- the ``Initiating Party Identifier`` (must be "CBI"). + +|company_setting| + +-------------- + +In Invoicing / Configuration / Management / Payment Modes, create a new +payment mode. + +|payment_mode1| + +-------------- + +In the new payment mode is important to set the Italian format SEPA CBI + +|payment_mode2| + +.. |company_setting| image:: https://raw.githubusercontent.com/OCA/l10n-italy/16.0/l10n_it_sct_cbi/static/company_setting.png +.. |payment_mode1| image:: https://raw.githubusercontent.com/OCA/l10n-italy/16.0/l10n_it_sct_cbi/static/payment_mode1.png +.. |payment_mode2| image:: https://raw.githubusercontent.com/OCA/l10n-italy/16.0/l10n_it_sct_cbi/static/payment_mode2.png + +Usage +===== + +This module uses the grouped payments implemented by the OCA in +``account_payment_order``, grouped payments are also implemented in Odoo +EE. + +When you create a new payment order, you must select the payment mode +created during configuration + +|order_payment| + +In order to get the xml file: + +1. click on "Confirm payments" +2. click on "Generate payment file" |generate_payment| + +-------------- + +Then you can download the generated file + +|make_payment_download| + +.. |order_payment| image:: https://raw.githubusercontent.com/OCA/l10n-italy/16.0/l10n_it_sct_cbi/static/order_payment.png +.. |generate_payment| image:: https://raw.githubusercontent.com/OCA/l10n-italy/16.0/l10n_it_sct_cbi/static/generate_payment.png +.. |make_payment_download| image:: https://raw.githubusercontent.com/OCA/l10n-italy/16.0/l10n_it_sct_cbi/static/make_payment_download.png + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Openforce di Alessandro Camilli + +Contributors +------------ + +- Alessandro Camilli +- Andrea Colangelo +- Lorenzo Battistini +- Alex Comba +- `Aion Tech `__: + + - Simone Rubino + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-SirAionTech| image:: https://github.com/SirAionTech.png?size=40px + :target: https://github.com/SirAionTech + :alt: SirAionTech + +Current `maintainer `__: + +|maintainer-SirAionTech| + +This module is part of the `OCA/l10n-italy `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/l10n_it_sct_cbi/__init__.py b/l10n_it_sct_cbi/__init__.py new file mode 100644 index 000000000000..69f7babdfb1a --- /dev/null +++ b/l10n_it_sct_cbi/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/l10n_it_sct_cbi/__manifest__.py b/l10n_it_sct_cbi/__manifest__.py new file mode 100644 index 000000000000..e8c681cd3279 --- /dev/null +++ b/l10n_it_sct_cbi/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2016 Alessandro Camilli +# Copyright 2024 Simone Rubino - Aion Tech +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "ITA - Banking SEPA Credit Transfer CBI", + "summary": "Usare gli standard CBI per SEPA Credit Transfer", + "version": "16.0.1.0.0", + "category": "Banking", + "author": "Openforce di Alessandro Camilli, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/l10n-italy" "/tree/16.0/l10n_it_sct_cbi", + "license": "AGPL-3", + "maintainers": [ + "SirAionTech", + ], + "depends": [ + "account_banking_pain_base", + ], + "data": [ + "data/account_payment_method.xml", + ], +} diff --git a/l10n_it_sct_cbi/data/account_payment_method.xml b/l10n_it_sct_cbi/data/account_payment_method.xml new file mode 100644 index 000000000000..9e09d063ab4b --- /dev/null +++ b/l10n_it_sct_cbi/data/account_payment_method.xml @@ -0,0 +1,15 @@ + + + + + SEPA Credit Transfer Payment Request CBI + sepa_cbi_credit_transfer + outbound + + CBIBdyPaymentRequest.00.04.01 + + + diff --git a/l10n_it_sct_cbi/data/standards/CBIBdyCrossBorderPaymentRequest.00.01.01.xsd b/l10n_it_sct_cbi/data/standards/CBIBdyCrossBorderPaymentRequest.00.01.01.xsd new file mode 100644 index 000000000000..e524287ef209 --- /dev/null +++ b/l10n_it_sct_cbi/data/standards/CBIBdyCrossBorderPaymentRequest.00.01.01.xsd @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sct_cbi/data/standards/CBIBdyPaymentRequest.00.04.01.xsd b/l10n_it_sct_cbi/data/standards/CBIBdyPaymentRequest.00.04.01.xsd new file mode 100644 index 000000000000..9fc44580b71a --- /dev/null +++ b/l10n_it_sct_cbi/data/standards/CBIBdyPaymentRequest.00.04.01.xsd @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sct_cbi/data/standards/CBICrossBorderPaymentRequestLogMsg.00.01.01.xsd b/l10n_it_sct_cbi/data/standards/CBICrossBorderPaymentRequestLogMsg.00.01.01.xsd new file mode 100644 index 000000000000..edc2b2a8fb53 --- /dev/null +++ b/l10n_it_sct_cbi/data/standards/CBICrossBorderPaymentRequestLogMsg.00.01.01.xsd @@ -0,0 +1,826 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: removed "OR" construction for ISO 20022 compliance + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sct_cbi/data/standards/CBICrossBorderPaymentRequestPhyMsg.00.01.01.xsd b/l10n_it_sct_cbi/data/standards/CBICrossBorderPaymentRequestPhyMsg.00.01.01.xsd new file mode 100644 index 000000000000..cd49ead19fa3 --- /dev/null +++ b/l10n_it_sct_cbi/data/standards/CBICrossBorderPaymentRequestPhyMsg.00.01.01.xsd @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/l10n_it_sct_cbi/data/standards/CBIHdrSrv.001.07.xsd b/l10n_it_sct_cbi/data/standards/CBIHdrSrv.001.07.xsd new file mode 100644 index 000000000000..d39cc9cc9cd1 --- /dev/null +++ b/l10n_it_sct_cbi/data/standards/CBIHdrSrv.001.07.xsd @@ -0,0 +1,174 @@ + + + + + + Header di Servizio incluso nella release 6.15 della documentazione Parte Generale. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sct_cbi/data/standards/CBIHdrTrt.001.07.xsd b/l10n_it_sct_cbi/data/standards/CBIHdrTrt.001.07.xsd new file mode 100644 index 000000000000..cd44ff205260 --- /dev/null +++ b/l10n_it_sct_cbi/data/standards/CBIHdrTrt.001.07.xsd @@ -0,0 +1,129 @@ + + + + + + Header di Tratta incluso nella release 6.15 della documentazione Parte Generale + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sct_cbi/data/standards/CBIPaymentRequest.00.04.01.xsd b/l10n_it_sct_cbi/data/standards/CBIPaymentRequest.00.04.01.xsd new file mode 100644 index 000000000000..d180699f6f91 --- /dev/null +++ b/l10n_it_sct_cbi/data/standards/CBIPaymentRequest.00.04.01.xsd @@ -0,0 +1,1231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Type Changed into DateAndDateTime2Choice for v2019 ISO message migration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN - Type Changed in order to add the optional Proxy Field under Creditor Account + + + + + + + + + + CHAN - Complex structure included for the migration to v2019 ISO message + + + + + CHAN - Modified structure to adopt v2019 ISO message + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Name Changed into BICFI and Type Changed into BICFIDec2014Identifier for v2019 ISO message migration + + + + + + + + + CHAN: Name Changed into BICFI and Type Changed into BICFIDec2014Identifier for v2019 ISO message migration + + + + + + CHAN: Field included for v2019 ISO message migration + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Removed "OR" XSD check and restored "sequence" for ISO 20022 compliance + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Name Changed into AnyBIC and Type Changed into AnyBICDec2014Identifier for v2019 ISO message migration + + + + + CHAN: Field included for v2019 ISO message migration + + + + + + + + + + CHAN: Name Changed into AnyBIC and Type Changed into AnyBICDec2014Identifier for v2019 ISO message migration + + + + + CHAN: Field included for v2019 ISO message migration + + + + + + + + + + + + + + + CHAN: Removed "OR" XSD check and restored "sequence" for ISO 20022 compliance + + + + + + + + + + + + + + + + + CHAN: Type Changed into CBIPostalAddress24 for v2019 ISO message migration + + + + + + + + + + + + CHAN: Type Changed into CBIPostalAddress24 for v2019 ISO message migration + + + + + + + + + + + + CHAN: Type Changed into CBIPostalAddress24 for v2019 ISO message migration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Element included for v2019 ISO message migration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Name Changed into AnyBIC and Type Changed into AnyBICDec2014Identifier for v2019 ISO message migration + + + + + CHAN: Field included for v2019 ISO message migration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Field included for v2019 ISO message migration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Changed data type for migration to v2019 ISO Message + + + + + CHAN: Changed data type for migration to v2019 ISO Message + + + + + CHAN - Complex structure included for the migration to v2019 ISO message + + + + + CHAN - Complex structure included for the migration to v2019 ISO message + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sct_cbi/data/standards/CBIPaymentRequestMsg.00.04.01.xsd b/l10n_it_sct_cbi/data/standards/CBIPaymentRequestMsg.00.04.01.xsd new file mode 100644 index 000000000000..d68393d7ca5e --- /dev/null +++ b/l10n_it_sct_cbi/data/standards/CBIPaymentRequestMsg.00.04.01.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/l10n_it_sct_cbi/data/standards/CBISgnInf.001.04.xsd b/l10n_it_sct_cbi/data/standards/CBISgnInf.001.04.xsd new file mode 100644 index 000000000000..ca058a5c4508 --- /dev/null +++ b/l10n_it_sct_cbi/data/standards/CBISgnInf.001.04.xsd @@ -0,0 +1,61 @@ + + + + + + + Definizione del blocco di informazioni per la gestione della firma digitale incluso nella release 6.12 della documentazione Parte Generale. +Presenta variazioni in seguito alla deliberazione CNIPA/DigitPA n.45 del 21 maggio 2009 + + + + + + + Tipologia di firma digitale utilizzata. +Può assumere i seguenti valori: +1 = PKCS#7 detached +2 = PKCS#7 attached +3 = CAdES-BES detached +4 = CAdES-BES attached + + + + + Codifica di riferimento: + A = UTF-8 + + + + + Data e ora di apposizione della firma + + + + + Busta di firma codificata in base64 +Il formato della busta deve essere coerente con la tipologia di firma indicata nel tag SgnTyp + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sct_cbi/i18n/it.po b/l10n_it_sct_cbi/i18n/it.po new file mode 100644 index 000000000000..1d5c4995e1b9 --- /dev/null +++ b/l10n_it_sct_cbi/i18n/it.po @@ -0,0 +1,114 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_it_sct_cbi +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-02 08:46+0000\n" +"PO-Revision-Date: 2024-07-02 08: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: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"ABI is mandatory for Payment Type Code '%(pain_flavor)s', but the bank " +"%(bank)s of %(partner_bank)s has no ABI.\n" +msgstr "" +"ABI è obbligatorio per il tipo di pagamento '%(pain_flavor)s', ma la banca " +"%(bank)s di %(partner_bank)s non ha alcun ABI.\n" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"BIC is mandatory for Payment Type Code '%(pain_flavor)s', but the bank " +"%(bank)s of %(partner_bank)s has no BIC.\n" +msgstr "" +"BIC è obbligatorio per il tipo di pagamento '%(pain_flavor)s', ma la banca " +"%(bank)s di %(partner_bank)s non ha alcun BIC.\n" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "Bank account '%(partner_bank)s' must have a valid IBAN" +msgstr "Il conto bancario '%(partner_bank)s' deve avere un IBAN valido" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"Bank account is missing on the bank payment line of partner '%(partner)s' " +"(reference '%(reference)s')." +msgstr "" +"Il conto bancario non è presente sulla riga di pagamento bancario del partner '%(partner)s' " +"(riferimento '%(reference)s')." + +#. module: l10n_it_sct_cbi +#: model:ir.model.fields.selection,name:l10n_it_sct_cbi.selection__account_payment_method__pain_version__cbibdycrossborderpaymentrequest_00_01_01 +msgid "CBIBdyCrossBorderPaymentRequest.00.01.01" +msgstr "" + +#. module: l10n_it_sct_cbi +#: model:ir.model.fields.selection,name:l10n_it_sct_cbi.selection__account_payment_method__pain_version__cbibdypaymentrequest_00_04_01 +msgid "CBIBdyPaymentRequest.00.04.01" +msgstr "" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"Missing Country for Partner '%(partner)s' (payment order line reference " +"'%(reference)s')" +msgstr "" +"Nazione mancante per il partner '%(partner)s' (riferimento riga ordine di pagamento " +"'%(reference)s')" + +#. module: l10n_it_sct_cbi +#: model:ir.model.fields,field_description:l10n_it_sct_cbi.field_account_payment_method__pain_version +msgid "PAIN Version" +msgstr "Versione PAIN" + +#. module: l10n_it_sct_cbi +#: model:ir.model,name:l10n_it_sct_cbi.model_account_payment_method +msgid "Payment Methods" +msgstr "Metodi di pagamento" + +#. module: l10n_it_sct_cbi +#: model:ir.model,name:l10n_it_sct_cbi.model_account_payment_order +msgid "Payment Order" +msgstr "Ordine di pagamento" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"Payment Type Code '%(pain_flavor)s' is not supported.\n" +"The only Payment Type Codes supported for SEPA Credit Transfers 'CBIBdyPaymentRequest.00.04.01' and 'CBIBdyCrossBorderPaymentRequest.00.01.01'." +msgstr "" +"Il tipo di pagamento '%(pain_flavor)s' non è supportato.\n" +"Gli unici tipi di pagamento supportati per SEPA Credit Transfer sono 'CBIBdyPaymentRequest.00.04.01' e 'CBIBdyCrossBorderPaymentRequest.00.01.01'." + +#. module: l10n_it_sct_cbi +#: model:account.payment.method,name:l10n_it_sct_cbi.sepa_cbi_credit_transfer +msgid "SEPA Credit Transfer Payment Request CBI" +msgstr "Richiesta di pagamento SEPA Credit Transfer con CBI" diff --git a/l10n_it_sct_cbi/i18n/l10n_it_sct_cbi.pot b/l10n_it_sct_cbi/i18n/l10n_it_sct_cbi.pot new file mode 100644 index 000000000000..da9ac3d87280 --- /dev/null +++ b/l10n_it_sct_cbi/i18n/l10n_it_sct_cbi.pot @@ -0,0 +1,104 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_it_sct_cbi +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-07-02 08:45+0000\n" +"PO-Revision-Date: 2024-07-02 08:45+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_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"ABI is mandatory for Payment Type Code '%(pain_flavor)s', but the bank " +"%(bank)s of %(partner_bank)s has no ABI.\n" +msgstr "" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"BIC is mandatory for Payment Type Code '%(pain_flavor)s', but the bank " +"%(bank)s of %(partner_bank)s has no BIC.\n" +msgstr "" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "Bank account '%(partner_bank)s' must have a valid IBAN" +msgstr "" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"Bank account is missing on the bank payment line of partner '%(partner)s' " +"(reference '%(reference)s')." +msgstr "" + +#. module: l10n_it_sct_cbi +#: model:ir.model.fields.selection,name:l10n_it_sct_cbi.selection__account_payment_method__pain_version__cbibdycrossborderpaymentrequest_00_01_01 +msgid "CBIBdyCrossBorderPaymentRequest.00.01.01" +msgstr "" + +#. module: l10n_it_sct_cbi +#: model:ir.model.fields.selection,name:l10n_it_sct_cbi.selection__account_payment_method__pain_version__cbibdypaymentrequest_00_04_01 +msgid "CBIBdyPaymentRequest.00.04.01" +msgstr "" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"Missing Country for Partner '%(partner)s' (payment order line reference " +"'%(reference)s')" +msgstr "" + +#. module: l10n_it_sct_cbi +#: model:ir.model.fields,field_description:l10n_it_sct_cbi.field_account_payment_method__pain_version +msgid "PAIN Version" +msgstr "" + +#. module: l10n_it_sct_cbi +#: model:ir.model,name:l10n_it_sct_cbi.model_account_payment_method +msgid "Payment Methods" +msgstr "" + +#. module: l10n_it_sct_cbi +#: model:ir.model,name:l10n_it_sct_cbi.model_account_payment_order +msgid "Payment Order" +msgstr "" + +#. module: l10n_it_sct_cbi +#. odoo-python +#: code:addons/l10n-italy/l10n_it_sct_cbi/models/account_payment_order.py:0 +#: code:addons/l10n_it_sct_cbi/models/account_payment_order.py:0 +#, python-format +msgid "" +"Payment Type Code '%(pain_flavor)s' is not supported.\n" +"The only Payment Type Codes supported for SEPA Credit Transfers 'CBIBdyPaymentRequest.00.04.01' and 'CBIBdyCrossBorderPaymentRequest.00.01.01'." +msgstr "" + +#. module: l10n_it_sct_cbi +#: model:account.payment.method,name:l10n_it_sct_cbi.sepa_cbi_credit_transfer +msgid "SEPA Credit Transfer Payment Request CBI" +msgstr "" \ No newline at end of file diff --git a/l10n_it_sct_cbi/i18n/sl.po b/l10n_it_sct_cbi/i18n/sl.po new file mode 100644 index 000000000000..f2ffc27bbe52 --- /dev/null +++ b/l10n_it_sct_cbi/i18n/sl.po @@ -0,0 +1,260 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * l10n_it_sct_cbi +# +# Translators: +# Matjaž Mozetič , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-10-20 06:13+0000\n" +"PO-Revision-Date: 2017-10-20 06:13+0000\n" +"Last-Translator: Matjaž Mozetič , 2017\n" +"Language-Team: Slovenian (https://www.transifex.com/oca/teams/23907/sl/)\n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" +"%100==4 ? 2 : 3);\n" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,batch_booking:0 +#: field:banking.export.sepa.cbi.wizard,batch_booking:0 +msgid "Batch Booking" +msgstr "Skupinska rezervacija" + +#. module: l10n_it_sct_cbi +#: selection:banking.export.sepa.cbi.estero.wizard,charge_bearer:0 +#: selection:banking.export.sepa.cbi.wizard,charge_bearer:0 +msgid "Borne by Creditor" +msgstr "Nosi upnik" + +#. module: l10n_it_sct_cbi +#: selection:banking.export.sepa.cbi.estero.wizard,charge_bearer:0 +#: selection:banking.export.sepa.cbi.wizard,charge_bearer:0 +msgid "Borne by Debtor" +msgstr "Nosi dolžnik" + +#. module: l10n_it_sct_cbi +#: view:banking.export.sepa.cbi.estero.wizard:l10n_it_sct_cbi.banking_export_sepa_cbi_estero_wizard_view +#: view:banking.export.sepa.cbi.wizard:l10n_it_sct_cbi.banking_export_sepa_cbi_wizard_view +msgid "Cancel" +msgstr "Preklic" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,charge_bearer:0 +#: field:banking.export.sepa.cbi.wizard,charge_bearer:0 +msgid "Charge Bearer" +msgstr "Nosilec stroškov" + +#. module: l10n_it_sct_cbi +#: selection:banking.export.sepa.cbi.estero.wizard,state:0 +#: selection:banking.export.sepa.cbi.wizard,state:0 +msgid "Create" +msgstr "Ustvari" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,create_uid:0 +#: field:banking.export.sepa.cbi.wizard,create_uid:0 +msgid "Created by" +msgstr "Ustvaril" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,create_date:0 +#: field:banking.export.sepa.cbi.wizard,create_date:0 +msgid "Created on" +msgstr "Ustvarjeno" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,display_name:0 +#: field:banking.export.sepa.cbi.wizard,display_name:0 +msgid "Display Name" +msgstr "Prikazni naziv" + +#. module: l10n_it_sct_cbi +#: code:addons/l10n_it_sct_cbi/wizard/export_sepa_cbi.py:79 +#: code:addons/l10n_it_sct_cbi/wizard/export_sepa_cbi_estero.py:100 +#, python-format +msgid "Error Bank Code ABI" +msgstr "Napačna bančna koda ABI" + +#. module: l10n_it_sct_cbi +#: code:addons/l10n_it_sct_cbi/wizard/export_sepa_cbi_estero.py:105 +#, python-format +msgid "Error Bank Code BIC" +msgstr "Napačna bančna koda BIC" + +#. module: l10n_it_sct_cbi +#: model:ir.model,name:l10n_it_sct_cbi.model_banking_export_sepa_cbi_estero_wizard +msgid "Export SEPA CBI Estero File" +msgstr "Izvoz SEPA CPI datoteke za tujino" + +#. module: l10n_it_sct_cbi +#: model:ir.model,name:l10n_it_sct_cbi.model_banking_export_sepa_cbi_wizard +msgid "Export SEPA CBI File" +msgstr "Izvoz SEPA CBI datoteke" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,file:0 +#: field:banking.export.sepa.cbi.wizard,file:0 +msgid "File" +msgstr "Datoteka" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,filename:0 +#: field:banking.export.sepa.cbi.wizard,filename:0 +msgid "Filename" +msgstr "Naziv datoteke" + +#. module: l10n_it_sct_cbi +#: selection:banking.export.sepa.cbi.estero.wizard,state:0 +#: selection:banking.export.sepa.cbi.wizard,state:0 +msgid "Finish" +msgstr "Dokončaj" + +#. module: l10n_it_sct_cbi +#: selection:banking.export.sepa.cbi.wizard,charge_bearer:0 +msgid "Following Service Level" +msgstr "Raven storitev" + +#. module: l10n_it_sct_cbi +#: help:banking.export.sepa.cbi.estero.wizard,charge_bearer:0 +#: help:banking.export.sepa.cbi.wizard,charge_bearer:0 +msgid "" +"Following service level : transaction charges are to be applied following " +"the rules agreed in the service level and/or scheme (SEPA Core messages must " +"use this). Shared : transaction charges on the creditor side are to be borne " +"by the creditor, transaction charges on the debtor side are to be borne by " +"the debtor. Borne by creditor : all transaction charges are to be borne by " +"the creditor. Borne by debtor : all transaction charges are to be borne by " +"the debtor." +msgstr "" +"Nivo sledenja: stroške transakcije se dodeli glede na naslednja pravila v " +"sporazumu o ravni storitev in/ali shemi (SEPA temeljna sporočila morajo to " +"uporabljati). Deljeno: stroške transakcije na strani upnika nosi upnik sam, " +"stroške na strani dolžnika pa dolžnik. Nosi upnik: vse stroške transakcije " +"nosi upnik. Nosi dolžnik: vse stroške transakcije nosi dolžnik." + +#. module: l10n_it_sct_cbi +#: view:banking.export.sepa.cbi.estero.wizard:l10n_it_sct_cbi.banking_export_sepa_cbi_estero_wizard_view +#: view:banking.export.sepa.cbi.wizard:l10n_it_sct_cbi.banking_export_sepa_cbi_wizard_view +msgid "Generate" +msgstr "Ustvari" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,id:0 +#: field:banking.export.sepa.cbi.wizard,id:0 +msgid "ID" +msgstr "ID" + +#. module: l10n_it_sct_cbi +#: help:banking.export.sepa.cbi.estero.wizard,batch_booking:0 +#: help:banking.export.sepa.cbi.wizard,batch_booking:0 +msgid "" +"If true, the bank statement will display only one credit line for all the " +"direct debits of the SEPA file ; if false, the bank statement will display " +"one credit line per direct debit of the SEPA file." +msgstr "" +"Če pravilno, bančni izpisek prikaže le eno postavko v dobro za vse direktne " +"obremenitve v SEPA XML datoteki ; če napačno, bančni izpisek prikaže le eno " +"postavko v dobro za vsako direktno obremenitev v SEPA datoteki." + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,__last_update:0 +#: field:banking.export.sepa.cbi.wizard,__last_update:0 +msgid "Last Modified on" +msgstr "Zadnjič spremenjeno" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,write_uid:0 +#: field:banking.export.sepa.cbi.wizard,write_uid:0 +msgid "Last Updated by" +msgstr "Zadnji posodobil" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,write_date:0 +#: field:banking.export.sepa.cbi.wizard,write_date:0 +msgid "Last Updated on" +msgstr "Zadnjič posodobljeno" + +#. module: l10n_it_sct_cbi +#: code:addons/l10n_it_sct_cbi/wizard/export_sepa_cbi.py:234 +#: code:addons/l10n_it_sct_cbi/wizard/export_sepa_cbi_estero.py:301 +#, python-format +msgid "" +"Missing Bank Account on invoice '%s' (payment order line reference '%s')" +msgstr "" +"Manjkajoča številka bančnega računa pri računu '%s' (sklic na postavko " +"plačilnega naloga '%s')" + +#. module: l10n_it_sct_cbi +#: code:addons/l10n_it_sct_cbi/wizard/export_sepa_cbi_estero.py:323 +#, python-format +msgid "Missing Country for Partner '%s' (payment order line reference '%s')" +msgstr "" +"Manjkajoča država pri partnerju '%s' (sklic postavke plačilnega naloga '%s')" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,nb_transactions:0 +#: field:banking.export.sepa.cbi.wizard,nb_transactions:0 +msgid "Number of Transactions" +msgstr "Število transakcij" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,payment_order_ids:0 +#: field:banking.export.sepa.cbi.wizard,payment_order_ids:0 +msgid "Payment Orders" +msgstr "Plačilni nalogi" + +#. module: l10n_it_sct_cbi +#: code:addons/l10n_it_sct_cbi/wizard/export_sepa_cbi_estero.py:172 +#, python-format +msgid "" +"Payment Type Code '%s' is not supported. The only Payment Type Code " +"supported for SEPA Credit Transfers " +"'CBIBdyCrossBorderPaymentRequest.00.01.01'. " +msgstr "" +"Koda tipa plačila '%s' ni podprta. Edina koda tipov plačil, ki je podprta za " +"SEPA bremenilne transakcije, je 'CBIBdyCrossBorderPaymentRequest.00.01.01'." + +#. module: l10n_it_sct_cbi +#: code:addons/l10n_it_sct_cbi/wizard/export_sepa_cbi.py:111 +#, python-format +msgid "" +"Payment Type Code '%s' is not supported. The only Payment Type Code " +"supported for SEPA Credit Transfers 'CBIBdyPaymentRequest.00.04.00'. " +msgstr "" +"Koda tipa plačila '%s' ni podprta. Edina koda tipov plačil, ki je podprta za " +"SEPA bremenilne transakcije, je 'CBIBdyPaymentRequest.00.04.00'." + +#. module: l10n_it_sct_cbi +#: view:banking.export.sepa.cbi.estero.wizard:l10n_it_sct_cbi.banking_export_sepa_cbi_estero_wizard_view +#: view:banking.export.sepa.cbi.wizard:l10n_it_sct_cbi.banking_export_sepa_cbi_wizard_view +msgid "SEPA File Generation" +msgstr "Generiranje SEPA datoteke" + +#. module: l10n_it_sct_cbi +#: selection:banking.export.sepa.cbi.estero.wizard,charge_bearer:0 +#: selection:banking.export.sepa.cbi.wizard,charge_bearer:0 +msgid "Shared" +msgstr "V souporabi" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,state:0 +#: field:banking.export.sepa.cbi.wizard,state:0 +msgid "State" +msgstr "Stanje" + +#. module: l10n_it_sct_cbi +#: field:banking.export.sepa.cbi.estero.wizard,total_amount:0 +#: field:banking.export.sepa.cbi.wizard,total_amount:0 +msgid "Total Amount" +msgstr "Skupni znesek" + +#. module: l10n_it_sct_cbi +#: view:banking.export.sepa.cbi.estero.wizard:l10n_it_sct_cbi.banking_export_sepa_cbi_estero_wizard_view +#: view:banking.export.sepa.cbi.wizard:l10n_it_sct_cbi.banking_export_sepa_cbi_wizard_view +msgid "Validate" +msgstr "Overi" diff --git a/l10n_it_sct_cbi/models/__init__.py b/l10n_it_sct_cbi/models/__init__.py new file mode 100644 index 000000000000..bce35619b7c8 --- /dev/null +++ b/l10n_it_sct_cbi/models/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import account_payment_method +from . import account_payment_order diff --git a/l10n_it_sct_cbi/models/account_payment_method.py b/l10n_it_sct_cbi/models/account_payment_method.py new file mode 100644 index 000000000000..bc955ddffec9 --- /dev/null +++ b/l10n_it_sct_cbi/models/account_payment_method.py @@ -0,0 +1,44 @@ +# Copyright 2013-2015 Alexis de Lattre +# Copyright 2016 Alessandro Camilli +# Copyright 2024 Simone Rubino - Aion Tech +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + + +class AccountPaymentMethod(models.Model): + _inherit = "account.payment.method" + + pain_version = fields.Selection( + selection_add=[ + ("CBIBdyPaymentRequest.00.04.01", "CBIBdyPaymentRequest.00.04.01"), + ( + "CBIBdyCrossBorderPaymentRequest.00.01.01", + "CBIBdyCrossBorderPaymentRequest.00.01.01", + ), + ], + ondelete={ + "CBIBdyPaymentRequest.00.04.01": "set null", + "CBIBdyCrossBorderPaymentRequest.00.01.01": "set null", + }, + ) + + def get_xsd_file_path(self): + self.ensure_one() + if self.pain_version in [ + "CBIBdyPaymentRequest.00.04.01", + "CBIBdyCrossBorderPaymentRequest.00.01.01", + ]: + path = f"l10n_it_sct_cbi/data/standards/{self.pain_version}.xsd" + else: + path = super().get_xsd_file_path() + return path + + @api.model + def _get_payment_method_information(self): + res = super()._get_payment_method_information() + res["sepa_cbi_credit_transfer"] = { + "mode": "multi", + "domain": [("type", "=", "bank")], + } + return res diff --git a/l10n_it_sct_cbi/models/account_payment_order.py b/l10n_it_sct_cbi/models/account_payment_order.py new file mode 100644 index 000000000000..70321b527662 --- /dev/null +++ b/l10n_it_sct_cbi/models/account_payment_order.py @@ -0,0 +1,544 @@ +# Copyright 2013-2015 Alexis de Lattre +# Copyright 2016 Alessandro Camilli +# Copyright 2024 Simone Rubino - Aion Tech +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from collections import defaultdict + +from lxml import etree + +from odoo import _, api, fields, models +from odoo.exceptions import UserError +from odoo.fields import first + + +class AccountPaymentOrder(models.Model): + _inherit = "account.payment.order" + + @api.model + def generate_party_acc_number( + self, + parent_node, + party_type, + order, + partner_bank, + gen_args, + bank_line=None, + ): + res = super().generate_party_acc_number( + parent_node, + party_type, + order, + partner_bank, + gen_args, + bank_line=bank_line, + ) + pain_flavor = gen_args.get("pain_flavor") + if pain_flavor == "CBIBdyPaymentRequest.00.04.01": + iban_node = parent_node.find(f".//{'%sAcct' % party_type}/Id/IBAN") + if iban_node is None: + raise UserError( + _( + "Bank account '%(partner_bank)s' must have a valid IBAN", + partner_bank=partner_bank.display_name, + ) + ) + return res + + @api.model + def generate_party_agent( + self, + parent_node, + party_type, + order, + partner_bank, + gen_args, + bank_line=None, + ): + res = super().generate_party_agent( + parent_node, + party_type, + order, + partner_bank, + gen_args, + bank_line=bank_line, + ) + pain_flavor = gen_args.get("pain_flavor") + if pain_flavor == "CBIBdyPaymentRequest.00.04.01": + full_debtor_data = False + elif pain_flavor == "CBIBdyCrossBorderPaymentRequest.00.01.01": + full_debtor_data = True + if not partner_bank.bank_bic: + raise UserError( + _( + "BIC is mandatory for Payment Type Code '%(pain_flavor)s', " + "but the bank %(bank)s of %(partner_bank)s has no BIC.\n", + bank=partner_bank.bank_id.display_name, + partner_bank=partner_bank.display_name, + pain_flavor=pain_flavor, + ) + ) + else: + return res + + if party_type == "Dbtr": + party_agent_tag = "%sAgt" % party_type + party_agent_node = parent_node.xpath(f"//{party_agent_tag}")[-1] + + party_agent_institution_tag = "FinInstnId" + party_agent_institution_node = party_agent_node.xpath( + f"{party_agent_institution_tag}" + )[-1] + + othr = party_agent_institution_node.find(".//Othr") + if othr is not None: + party_agent_institution_node.remove(othr) + + iban = ( + partner_bank.sanitized_acc_number + if partner_bank.acc_type == "iban" + else "" + ) + + # ABI + abi_code = False + if "bank_abi" in partner_bank._fields: + abi_code = partner_bank.bank_abi + # ... try from iban + if not abi_code and iban: + abi_code = iban[5:10] + if not abi_code: + raise UserError( + _( + "ABI is mandatory for Payment Type Code '%(pain_flavor)s', " + "but the bank %(bank)s of %(partner_bank)s has no ABI.\n", + bank=partner_bank.bank_id.display_name, + partner_bank=partner_bank.display_name, + pain_flavor=pain_flavor, + ) + ) + party_agent_institution_sys = etree.SubElement( + party_agent_institution_node, "ClrSysMmbId" + ) + party_agent_institution_sys_abi = etree.SubElement( + party_agent_institution_sys, "MmbId" + ) + party_agent_institution_sys_abi.text = abi_code + + if full_debtor_data: + # Complete Debtor data + debtor_node = parent_node.xpath("//Dbtr")[0] + debtor_address_node = etree.SubElement(debtor_node, "PstlAdr") + debtor_country_node = etree.SubElement(debtor_address_node, "Ctry") + debtor_country_node.text = iban[:2] + + debtor_partner = partner_bank.partner_id + if debtor_partner: + debtor_address_line_node = etree.SubElement( + debtor_address_node, "AdrLine" + ) + debtor_address_line_node.text = "{} {} {}".format( + debtor_partner.street or "", + debtor_partner.city or "", + debtor_partner.country_id + and debtor_partner.country_id.name + or "", + ) + + return res + + @api.model + def _must_have_initiating_party(self, gen_args): + pain_flavor = gen_args.get("pain_flavor") + is_sct_cbi_flavor = pain_flavor in [ + "CBIBdyPaymentRequest.00.04.01", + "CBIBdyCrossBorderPaymentRequest.00.01.01", + ] + return is_sct_cbi_flavor or super()._must_have_initiating_party(gen_args) + + def generate_pain_nsmap(self): + self.ensure_one() + payment_method = self.payment_method_id + if payment_method.code != "sepa_cbi_credit_transfer": + nsmap = super().generate_pain_nsmap() + else: + pain_flavor = self.payment_method_id.pain_version + if pain_flavor == "CBIBdyPaymentRequest.00.04.01": + pain_xml_xsd = "CBIPaymentRequest.00.04.01" + elif pain_flavor == "CBIBdyCrossBorderPaymentRequest.00.01.01": + pain_xml_xsd = "CBICrossBorderPaymentRequestLogMsg" + else: + raise self._l10n_it_sct_cbi_unsupported_pain_exception(pain_flavor) + nsmap = { + None: f"urn:CBI:xsd:{payment_method.pain_version}", + "PMRQ": f"urn:CBI:xsd:{pain_xml_xsd}", + } + return nsmap + + @api.model + def generate_start_payment_info_block( + self, + parent_node, + payment_info_ident, + priority, + local_instrument, + category_purpose, + sequence_type, + requested_date, + eval_ctx, + gen_args, + ): + pain_flavor = gen_args.get("pain_flavor") + if pain_flavor == "CBIBdyCrossBorderPaymentRequest.00.01.01": + priority = local_instrument = False + + ( + payment_info_node, + nb_of_payment_transactions_node, + control_payment_sum_node, + ) = super().generate_start_payment_info_block( + parent_node, + payment_info_ident, + priority, + local_instrument, + category_purpose, + sequence_type, + requested_date, + eval_ctx, + gen_args, + ) + + if pain_flavor in [ + "CBIBdyPaymentRequest.00.04.01", + "CBIBdyCrossBorderPaymentRequest.00.01.01", + ]: + # Remove duplicate nodes + duplicate_node_xpath_list = [ + "//PmtInf//NbOfTxs", + "//PmtInf//CtrlSum", + ] + for duplicate_node_xpath in duplicate_node_xpath_list: + duplicate_node = payment_info_node.xpath(duplicate_node_xpath)[0] + if duplicate_node is not None: + duplicate_node.getparent().remove(duplicate_node) + + # Refactor ReqdExctnDt to ReqdExctnDt/Dt and move its text + requested_execution_date_node = payment_info_node.find(".//ReqdExctnDt") + requested_execution_date_child_node = etree.SubElement( + requested_execution_date_node, "Dt" + ) + requested_execution_date_child_node.text = ( + requested_execution_date_node.text + ) + requested_execution_date_node.text = None + + return ( + payment_info_node, + nb_of_payment_transactions_node, + control_payment_sum_node, + ) + + def _l10n_it_sct_cbi_group_transactions_key(self, line): + """Key for grouping transactions + + key = (requested_date, priority) + """ + payment_line = first(line.payment_line_ids) + + requested_date = fields.Date.to_string(line.date) + priority = payment_line.priority + return ( + requested_date, + priority, + ) + + def _l10n_it_sct_cbi_group_transactions(self): + """Group transactions by key. + + Key is defined by `_l10n_it_sct_cbi_group_transactions_key`. + """ + lines_per_group = defaultdict(list) + for line in self.payment_ids: + key = self._l10n_it_sct_cbi_group_transactions_key(line) + lines_per_group[key].append(line) + return lines_per_group + + def _l10n_it_sct_cbi_unsupported_pain_exception(self, pain_flavor): + return UserError( + _( + "Payment Type Code '%(pain_flavor)s' is not supported.\n" + "The only Payment Type Codes supported for SEPA Credit Transfers " + "'CBIBdyPaymentRequest.00.04.01' and " + "'CBIBdyCrossBorderPaymentRequest.00.01.01'.", + pain_flavor=pain_flavor, + ) + ) + + def _l10n_it_sct_cbi_gen_args(self): + payment_method = self.payment_method_id + pain_flavor = payment_method.pain_version + if pain_flavor == "CBIBdyCrossBorderPaymentRequest.00.01.01": + bic_xml_tag = "BIC" + elif pain_flavor == "CBIBdyPaymentRequest.00.04.01": + bic_xml_tag = "BICFI" + else: + raise self._l10n_it_sct_cbi_unsupported_pain_exception(pain_flavor) + return { + "bic_xml_tag": bic_xml_tag, + "name_maxsize": 70, + "convert_to_ascii": payment_method.convert_to_ascii, + "payment_method": "TRF", + "file_prefix": "sct_bci_", + "pain_flavor": pain_flavor, + "pain_xsd_file": payment_method.get_xsd_file_path(), + } + + def _l10n_it_sct_cbi_root_tag(self): + pain_flavor = self.payment_method_id.pain_version + if pain_flavor == "CBIBdyPaymentRequest.00.04.01": + root_xml_tag = "CBIBdyPaymentRequest" + elif pain_flavor == "CBIBdyCrossBorderPaymentRequest.00.01.01": + root_xml_tag = "CBIBdyCrossBorderPaymentRequest" + else: + raise self._l10n_it_sct_cbi_unsupported_pain_exception(pain_flavor) + return root_xml_tag + + def _l10n_it_sct_cbi_generate_xml_root(self): + root_xml_tag = self._l10n_it_sct_cbi_root_tag() + + nsmap = self.generate_pain_nsmap() + xml_root = etree.Element(root_xml_tag, nsmap=nsmap) + return xml_root + + def _l10n_it_sct_cbi_payment_tags(self): + pain_flavor = self.payment_method_id.pain_version + if pain_flavor == "CBIBdyPaymentRequest.00.04.01": + envel_xml_tag = "CBIEnvelPaymentRequest" + pain_xml_tag = "CBIPaymentRequest" + elif pain_flavor == "CBIBdyCrossBorderPaymentRequest.00.01.01": + envel_xml_tag = "CBIEnvelCBICrossBorderPaymentRequest" + pain_xml_tag = "CBICrossBorderPaymentRequestLogMsg" + else: + raise self._l10n_it_sct_cbi_unsupported_pain_exception(pain_flavor) + return envel_xml_tag, pain_xml_tag + + def _l10n_it_sct_cbi_generate_payment_root(self, parent_node): + envel_xml_tag, pain_xml_tag = self._l10n_it_sct_cbi_payment_tags() + + envel_root = etree.SubElement(parent_node, envel_xml_tag) + pain_root = etree.SubElement(envel_root, pain_xml_tag) + return pain_root + + def _l10n_it_sct_cbi_generate_transaction_block( + self, payment_info_node, line, gen_args + ): + # C. Credit Transfer Transaction Info + credit_transfer_transaction_info_node = etree.SubElement( + payment_info_node, "CdtTrfTxInf" + ) + payment_identification = etree.SubElement( + credit_transfer_transaction_info_node, "PmtId" + ) + # CBI PmtTpInf (Causale bonifici) + payment_identification_PmtTpInf = etree.SubElement( + credit_transfer_transaction_info_node, "PmtTpInf" + ) + payment_identification_CtgyPurp = etree.SubElement( + payment_identification_PmtTpInf, "CtgyPurp" + ) + payment_identification_CtgyPurp_Cd = etree.SubElement( + payment_identification_CtgyPurp, "Cd" + ) + payment_identification_CtgyPurp_Cd.text = "SEPA" + instruction_identification = etree.SubElement(payment_identification, "InstrId") + instruction_identification.text = self._prepare_field( + "Instruction Identification", + "str(line.move_id.id)", + {"line": line}, + 35, + gen_args=gen_args, + ) + end2end_identification = etree.SubElement(payment_identification, "EndToEndId") + end2end_identification.text = self._prepare_field( + "End to End Identification", + "str(line.move_id.id)", + { + "line": line, + }, + 35, + gen_args=gen_args, + ) + currency_name = self._prepare_field( + "Currency Code", + "line.currency_id.name", + { + "line": line, + }, + 3, + gen_args=gen_args, + ) + amount_node = etree.SubElement(credit_transfer_transaction_info_node, "Amt") + instructed_amount = etree.SubElement(amount_node, "InstdAmt", Ccy=currency_name) + instructed_amount.text = "%.2f" % line.amount + if not line.partner_bank_id: + raise UserError( + _( + "Bank account is missing on the bank payment line " + "of partner '%(partner)s' (reference '%(reference)s').", + partner=line.partner_id.name, + reference=line.name, + ) + ) + self.generate_party_block( + credit_transfer_transaction_info_node, + "Cdtr", + "C", + line.partner_bank_id, + gen_args, + line, + ) + + pain_flavor = self.payment_method_id.pain_version + if pain_flavor == "CBIBdyCrossBorderPaymentRequest.00.01.01": + # Add info for Cross Border payment + creditor_partner = line.partner_id + creditor_node = credit_transfer_transaction_info_node.xpath("//Cdtr[-1]") + creditor_address_node = etree.SubElement(creditor_node, "PstlAdr") + + creditor_address_country_node = etree.SubElement( + creditor_address_node, "Ctry" + ) + iso_country = False + iban = ( + line.bank_id.sanitized_acc_number + if line.bank_id.acc_type == "iban" + else "" + ) + if iban: + iso_country = iban[:2] + elif creditor_partner.country_id: + iso_country = creditor_partner.country_id.code + if not iso_country: + raise UserError( + _( + "Missing Country for Partner '%(partner)s' (payment " + "order line reference '%(reference)s')", + partner=line.partner_id.name, + reference=line.name, + ) + ) + creditor_address_country_node.text = iso_country + + creditor_address_line_node = etree.SubElement( + creditor_address_node, "AdrLine" + ) + if creditor_partner: + address = ( + f"{creditor_partner.street or ''} " + f"{creditor_partner.city or ''} " + f"{creditor_partner.country_id.name or ''}" + ) + creditor_address_line_node.text = address[:70] + + self.generate_remittance_info_block( + credit_transfer_transaction_info_node, line, gen_args + ) + return credit_transfer_transaction_info_node, line.amount + + def _l10n_it_sct_cbi_generate_payment_block( + self, pain_root, transactions_key, transactions, gen_args + ): + # Payment + # Unpack key as defined in _l10n_it_sct_cbi_group_transactions_key + requested_date, priority = transactions_key + ( + payment_node, + transactions_number_node, + transactions_amount_node, + ) = self.generate_start_payment_info_block( + pain_root, + "self.name + '-' " "+ requested_date.replace('-', '') + '-' + priority", + priority, + False, + False, + False, + requested_date, + { + "self": self, + "priority": priority, + "requested_date": requested_date, + }, + gen_args, + ) + + self.generate_party_block( + payment_node, "Dbtr", "B", self.company_partner_bank_id, gen_args + ) + + charge_bearer = etree.SubElement(payment_node, "ChrgBr") + charge_bearer.text = self.charge_bearer + + transactions_amount = 0.0 + for transaction in transactions: + ( + transaction_node, + transaction_amount, + ) = self._l10n_it_sct_cbi_generate_transaction_block( + payment_node, transaction, gen_args + ) + transactions_amount += transaction_amount + + transactions_number = len(transactions) + transactions_number_node.text = str(transactions_number) + transactions_amount_node.text = "%.2f" % transactions_amount + return payment_node, transactions_number, transactions_amount + + def finalize_sepa_file_creation(self, xml_root, gen_args): + if self.payment_method_id.code == "sepa_cbi_credit_transfer": + # Children of pain node must be in PMRQ namespace + pain_namespace = xml_root.nsmap["PMRQ"] + _envel_xml_tag, pain_xml_tag = self._l10n_it_sct_cbi_payment_tags() + pain_roots = xml_root.findall(f".//{pain_xml_tag}") + for pain_root in pain_roots: + for pain_child in pain_root.iterdescendants(): + pain_child.tag = etree.QName(pain_namespace, tag=pain_child.tag) + return super().finalize_sepa_file_creation(xml_root, gen_args) + + def generate_payment_file(self): + """Creates the SEPA Credit Transfer file. That's the important code!""" + self.ensure_one() + if self.payment_method_id.code != "sepa_cbi_credit_transfer": + return super().generate_payment_file() + + gen_args = self._l10n_it_sct_cbi_gen_args() + + xml_root = self._l10n_it_sct_cbi_generate_xml_root() + + transactions_number = 0 + transactions_amount = 0.0 + grouped_transactions = self._l10n_it_sct_cbi_group_transactions() + for transactions_key, transactions in grouped_transactions.items(): + pain_root = self._l10n_it_sct_cbi_generate_payment_root(xml_root) + + # Header + ( + group_header_node, + transactions_number_node, + transactions_amount_node, + ) = self.generate_group_header_block(pain_root, gen_args) + + ( + payment_node, + payment_transactions_number, + payment_transactions_amount, + ) = self._l10n_it_sct_cbi_generate_payment_block( + pain_root, transactions_key, transactions, gen_args + ) + + transactions_number += payment_transactions_number + transactions_amount += payment_transactions_amount + + transactions_number_node.text = str(transactions_number) + transactions_amount_node.text = "%.2f" % transactions_amount + + return self.finalize_sepa_file_creation(xml_root, gen_args) diff --git a/l10n_it_sct_cbi/pyproject.toml b/l10n_it_sct_cbi/pyproject.toml new file mode 100644 index 000000000000..4231d0cccb3d --- /dev/null +++ b/l10n_it_sct_cbi/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/l10n_it_sct_cbi/readme/CONFIGURE.md b/l10n_it_sct_cbi/readme/CONFIGURE.md new file mode 100644 index 000000000000..60061eab1bb2 --- /dev/null +++ b/l10n_it_sct_cbi/readme/CONFIGURE.md @@ -0,0 +1,17 @@ +In Invoicing / Configuration / Settings / SEPA/PAIN, set: +- the CUC code in field `Initiating Party Identifier` +- the `Initiating Party Identifier` (must be "CBI"). + +![company_setting](../static/company_setting.png) + +------------------------------------------------------------------------ + +In Invoicing / Configuration / Management / Payment Modes, create a new payment mode. + +![payment_mode1](../static/payment_mode1.png) + +------------------------------------------------------------------------ + +In the new payment mode is important to set the Italian format SEPA CBI + +![payment_mode2](../static/payment_mode2.png) diff --git a/l10n_it_sct_cbi/readme/CONTRIBUTORS.md b/l10n_it_sct_cbi/readme/CONTRIBUTORS.md new file mode 100644 index 000000000000..70a9c6894382 --- /dev/null +++ b/l10n_it_sct_cbi/readme/CONTRIBUTORS.md @@ -0,0 +1,6 @@ +- Alessandro Camilli \<\> +- Andrea Colangelo \<\> +- Lorenzo Battistini \<\> +- Alex Comba \<\> +- [Aion Tech](https://aiontech.company/): + - Simone Rubino \<\> diff --git a/l10n_it_sct_cbi/readme/DESCRIPTION.md b/l10n_it_sct_cbi/readme/DESCRIPTION.md new file mode 100644 index 000000000000..d4edf33f7fe2 --- /dev/null +++ b/l10n_it_sct_cbi/readme/DESCRIPTION.md @@ -0,0 +1,12 @@ +This module adds new payment export types to use in the payment order. +For italian credit transfer, the format codes are +- CBIBdyPaymentRequest.00.04.01 +- CBIBdyCrossBorderPaymentRequest.00.01.01 + +The created XML follows the CBI standards in https://www.cbi-org.eu/My-Menu/Servizio-CBI-Documentazione/Servizio-CBI-Documentazione-Standard. + +Note (ITA): + +Le specifiche CBI del bonifico XML SEPA (versione 00.04.01) si basano sul messaggio ISO20022 pain.001.001.09 e sono compliant al Rulebook SEPA. + +Ad esempio la presenza obbligatoria dell’ABI della banca di addebito contenuto nel campo “MmbId” che è invece facoltativo nel tracciato ISO. diff --git a/l10n_it_sct_cbi/readme/USAGE.md b/l10n_it_sct_cbi/readme/USAGE.md new file mode 100644 index 000000000000..671274d304c4 --- /dev/null +++ b/l10n_it_sct_cbi/readme/USAGE.md @@ -0,0 +1,18 @@ +This module uses the grouped payments implemented by the OCA in +`account_payment_order`, grouped payments are also implemented in Odoo EE. + +When you create a new payment order, you must select the payment mode +created during configuration + +![order_payment](../static/order_payment.png) + +In order to get the xml file: +1. click on "Confirm payments" +2. click on "Generate payment file" +![generate_payment](../static/generate_payment.png) + +------------------------------------------------------------------------ + +Then you can download the generated file + +![make_payment_download](../static/make_payment_download.png) diff --git a/l10n_it_sct_cbi/static/company_setting.png b/l10n_it_sct_cbi/static/company_setting.png new file mode 100644 index 000000000000..8d52fce9892e Binary files /dev/null and b/l10n_it_sct_cbi/static/company_setting.png differ diff --git a/l10n_it_sct_cbi/static/description/icon.png b/l10n_it_sct_cbi/static/description/icon.png new file mode 100644 index 000000000000..c139c9463c8e Binary files /dev/null and b/l10n_it_sct_cbi/static/description/icon.png differ diff --git a/l10n_it_sct_cbi/static/description/index.html b/l10n_it_sct_cbi/static/description/index.html new file mode 100644 index 000000000000..7e33949262aa --- /dev/null +++ b/l10n_it_sct_cbi/static/description/index.html @@ -0,0 +1,477 @@ + + + + + +ITA - Banking SEPA Credit Transfer CBI + + + +
+

ITA - Banking SEPA Credit Transfer CBI

+ + +

Beta License: AGPL-3 OCA/l10n-italy Translate me on Weblate Try me on Runboat

+

This module adds new payment export types to use in the payment order. +For italian credit transfer, the format codes are

+
    +
  • CBIBdyPaymentRequest.00.04.01
  • +
  • CBIBdyCrossBorderPaymentRequest.00.01.01
  • +
+

The created XML follows the CBI standards in +https://www.cbi-org.eu/My-Menu/Servizio-CBI-Documentazione/Servizio-CBI-Documentazione-Standard.

+

Note (ITA):

+

Le specifiche CBI del bonifico XML SEPA (versione 00.04.01) si basano +sul messaggio ISO20022 pain.001.001.09 e sono compliant al Rulebook +SEPA.

+

Ad esempio la presenza obbligatoria dell’ABI della banca di addebito +contenuto nel campo “MmbId” che è invece facoltativo nel tracciato ISO.

+

Table of contents

+ +
+

Configuration

+

In Invoicing / Configuration / Settings / SEPA/PAIN, set:

+
    +
  • the CUC code in field Initiating Party Identifier
  • +
  • the Initiating Party Identifier (must be “CBI”).
  • +
+

company_setting

+
+

In Invoicing / Configuration / Management / Payment Modes, create a new +payment mode.

+

payment_mode1

+
+

In the new payment mode is important to set the Italian format SEPA CBI

+

payment_mode2

+
+
+

Usage

+

This module uses the grouped payments implemented by the OCA in +account_payment_order, grouped payments are also implemented in Odoo +EE.

+

When you create a new payment order, you must select the payment mode +created during configuration

+

order_payment

+

In order to get the xml file:

+
    +
  1. click on “Confirm payments”
  2. +
  3. click on “Generate payment file” generate_payment
  4. +
+
+

Then you can download the generated file

+

make_payment_download

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Openforce di Alessandro Camilli
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

SirAionTech

+

This module is part of the OCA/l10n-italy project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/l10n_it_sct_cbi/static/generate_payment.png b/l10n_it_sct_cbi/static/generate_payment.png new file mode 100644 index 000000000000..8f79dde7aa4b Binary files /dev/null and b/l10n_it_sct_cbi/static/generate_payment.png differ diff --git a/l10n_it_sct_cbi/static/make_payment_download.png b/l10n_it_sct_cbi/static/make_payment_download.png new file mode 100644 index 000000000000..d25780319d3a Binary files /dev/null and b/l10n_it_sct_cbi/static/make_payment_download.png differ diff --git a/l10n_it_sct_cbi/static/order_payment.png b/l10n_it_sct_cbi/static/order_payment.png new file mode 100644 index 000000000000..38792d921d33 Binary files /dev/null and b/l10n_it_sct_cbi/static/order_payment.png differ diff --git a/l10n_it_sct_cbi/static/payment_mode1.png b/l10n_it_sct_cbi/static/payment_mode1.png new file mode 100644 index 000000000000..65f093160599 Binary files /dev/null and b/l10n_it_sct_cbi/static/payment_mode1.png differ diff --git a/l10n_it_sct_cbi/static/payment_mode2.png b/l10n_it_sct_cbi/static/payment_mode2.png new file mode 100644 index 000000000000..18099e6a04af Binary files /dev/null and b/l10n_it_sct_cbi/static/payment_mode2.png differ diff --git a/l10n_it_sct_cbi/tests/__init__.py b/l10n_it_sct_cbi/tests/__init__.py new file mode 100644 index 000000000000..b5747bff6ff9 --- /dev/null +++ b/l10n_it_sct_cbi/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import test_generate_file diff --git a/l10n_it_sct_cbi/tests/test_generate_file.py b/l10n_it_sct_cbi/tests/test_generate_file.py new file mode 100644 index 000000000000..cc350a31f4c4 --- /dev/null +++ b/l10n_it_sct_cbi/tests/test_generate_file.py @@ -0,0 +1,147 @@ +# Copyright 2024 Simone Rubino - Aion Tech +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import base64 + +from odoo import Command +from odoo.tests import Form, tagged + +from odoo.addons.account.tests.common import AccountTestInvoicingCommon + + +@tagged("post_install", "-at_install") +class TestGenerateFile(AccountTestInvoicingCommon): + """Test payment file generation.""" + + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + + company = cls.env.company + company.initiating_party_identifier = "CUC Code" + company.initiating_party_issuer = "CBI" + + company_bank_account_form = Form(cls.env["res.partner.bank"]) + company_bank_account_form.acc_number = "IT89O0300203280429513916296" + company_bank_account_form.partner_id = company.partner_id + cls.company_bank_account = company_bank_account_form.save() + + cls.bank_journal = cls.company_data["default_journal_bank"] + cls.bank_journal.bank_account_id = cls.company_bank_account + + cls.supplier_bank = cls.env["res.bank"].create( + { + "name": "Test supplier bank", + "bic": "TESTBICA", + } + ) + + cls.supplier = cls.env["res.partner"].create( + { + "name": "Test supplier", + "bank_ids": [ + Command.create( + { + "acc_number": "IT48N0300203280543765183341", + "bank_id": cls.supplier_bank.id, + } + ), + ], + } + ) + + cls.payment_method = cls.env.ref("l10n_it_sct_cbi.sepa_cbi_credit_transfer") + + payment_mode_form = Form(cls.env["account.payment.mode"]) + payment_mode_form.name = "Test SEPA CBI payment mode" + payment_mode_form.bank_account_link = "fixed" + payment_mode_form.fixed_journal_id = cls.bank_journal + payment_mode_form.payment_method_id = cls.payment_method + cls.payment_mode = payment_mode_form.save() + + def _get_record_from_action(self, action): + record_id = action["res_id"] + record_model = action["res_model"] + return self.env[record_model].browse(record_id) + + def _get_payment_order(self, invoices): + payment_order_action = invoices.create_account_payment_line() + return self._get_record_from_action(payment_order_action) + + def _get_payment_attachment(self, invoices): + payment_order = self._get_payment_order(invoices) + payment_order.draft2open() + payment_file_action = payment_order.open2generated() + return self._get_record_from_action(payment_file_action) + + def test_2_bills(self): + """Generate a payment file for 2 vendor bills.""" + # Arrange + payment_mode = self.payment_mode + supplier = self.supplier + + bill_1 = self.init_invoice( + "in_invoice", + partner=supplier, + amounts=[ + 100, + ], + post=True, + ) + bill_1.ref = "Test invoice 1" + bill_2 = self.init_invoice( + "in_invoice", + partner=supplier, + amounts=[ + 200, + ], + post=True, + ) + bill_2.ref = "Test invoice 2" + bills = bill_1 | bill_2 + bills.payment_mode_id = payment_mode + + # Act + payment_att = self._get_payment_attachment(bills) + + # Assert + payment_att_content = base64.b64decode(payment_att.datas).decode() + self.assertIn(bill_1.ref, payment_att_content) + self.assertIn(bill_2.ref, payment_att_content) + + def test_multiple_payment_priority(self): + """Generate a payment file for a vendor bill + and use different priority in payments.""" + # Arrange + payment_term = self.env.ref("account.account_payment_term_advance_60days") + payment_mode = self.payment_mode + supplier = self.supplier + bill = self.init_invoice( + "in_invoice", + partner=supplier, + amounts=[ + 100, + ], + post=False, + ) + with Form(bill) as bill_form: + bill_form.ref = "Test multiple payment term" + bill_form.invoice_payment_term_id = payment_term + bill_form.payment_mode_id = payment_mode + bill.action_post() + + payment_order = self._get_payment_order(bill) + payment_lines = payment_order.payment_line_ids + # pre-condition + self.assertEqual(len(payment_lines), 2) + payment_lines[0].priority = "HIGH" + payment_lines[1].priority = "NORM" + + # Act + payment_order.draft2open() + payment_file_action = payment_order.open2generated() + payment_att = self._get_record_from_action(payment_file_action) + + # Assert + payment_att_content = base64.b64decode(payment_att.datas).decode() + self.assertIn(bill.ref, payment_att_content)