diff --git a/l10n_it_sdd_cbi/README.rst b/l10n_it_sdd_cbi/README.rst new file mode 100644 index 000000000000..852e1f3a6340 --- /dev/null +++ b/l10n_it_sdd_cbi/README.rst @@ -0,0 +1,82 @@ +======================= +ITA - SEPA Direct Debit +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:6bc737911a767ce7d4e92809a11ef7de5acedfd8abc2b2cc9a7c36f5e4523546 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/14.0/l10n_it_sdd_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-14-0/l10n-italy-14-0-l10n_it_sdd_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=14.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +**Italiano** + +Questo modulo consente di generare correttamente file CBI SDD Italy. + +**English** + +The module allows to use correctly generate the file CBI SDD Italy. + +**Table of contents** + +.. contents:: + :local: + +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 +~~~~~~~ + +* Dinamiche Aziendali srl + +Contributors +~~~~~~~~~~~~ + +* Giuseppe Borruso + +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. + +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_sdd_cbi/__init__.py b/l10n_it_sdd_cbi/__init__.py new file mode 100644 index 000000000000..e2b93a535668 --- /dev/null +++ b/l10n_it_sdd_cbi/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .post_install import update_bank_journals diff --git a/l10n_it_sdd_cbi/__manifest__.py b/l10n_it_sdd_cbi/__manifest__.py new file mode 100644 index 000000000000..2c4e2198505a --- /dev/null +++ b/l10n_it_sdd_cbi/__manifest__.py @@ -0,0 +1,27 @@ +# Copyright 2024 Giuseppe Borruso - Dinamiche Aziendali srl +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "ITA - SEPA Direct Debit", + "version": "14.0.1.0.0", + "development_status": "Beta", + "category": "Localization/Italy", + "summary": "Create SEPA files for CBI SDD Italy", + "author": "Dinamiche Aziendali srl, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/l10n-italy", + "license": "AGPL-3", + "depends": [ + "account_payment_order", + "account_banking_pain_base", + "account_banking_mandate", + "account_banking_sepa_direct_debit", + "l10n_it_abicab", + ], + "data": [ + "data/account_payment_method.xml", + "views/account_payment_order_view.xml", + "views/res_config_settings_view.xml", + ], + "post_init_hook": "update_bank_journals", + "installable": True, +} diff --git a/l10n_it_sdd_cbi/data/CBIBdySDDReq.00.01.00.xsd b/l10n_it_sdd_cbi/data/CBIBdySDDReq.00.01.00.xsd new file mode 100644 index 000000000000..d3ad8d448f43 --- /dev/null +++ b/l10n_it_sdd_cbi/data/CBIBdySDDReq.00.01.00.xsd @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + 1.3.1. - Informazioni generali sul messaggio fisico + + + + + 1.3.2. - Blocco contenente il messaggio logico CBI. E' strutturato per poter contenere anche la firma digitale secondo le regole riportate nel documento FIRMA-MO-001. + + + + + + + + + 1.3.2.1. - Messaggio logico CBI di richiesta incasso SDD + + + + + + + + + + 1.3.1.1 - Tipologia di messaggio fisico, espressa in forma codificata + + + + + + + + + + + 1.3.1.2 - Indica il numero di messaggi logici contenuti nel messaggio fisico. Deve coincidere con il numero dei blocchi 1.3.2. + + + + + + + + + IdE2E presente nell'header di servizio del messaggio fisico referenziato + + + + + XMLCreDt presente nell'header di servizio del messaggio fisico referenziato + + + + + Riporta informazioni circa lo stato del messaggio fisico referenziato + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sdd_cbi/data/CBIBdySDDReq.00.01.01.xsd b/l10n_it_sdd_cbi/data/CBIBdySDDReq.00.01.01.xsd new file mode 100644 index 000000000000..79927ce41af1 --- /dev/null +++ b/l10n_it_sdd_cbi/data/CBIBdySDDReq.00.01.01.xsd @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + 1.3.1. - Informazioni generali sul messaggio fisico + + + + + 1.3.2. - Blocco contenente il messaggio logico CBI. E' strutturato per poter contenere anche la firma digitale secondo le regole riportate nel documento FIRMA-MO-001. + + + + + + + + + 1.3.2.1. - Messaggio logico CBI di richiesta incasso SDD + + + + + + + + + + 1.3.1.1 - Tipologia di messaggio fisico, espressa in forma codificata + + + + + + + + + + + 1.3.1.2 - Indica il numero di messaggi logici contenuti nel messaggio fisico. Deve coincidere con il numero dei blocchi 1.3.2. + + + + + + + + + IdE2E presente nell'header di servizio del messaggio fisico referenziato + + + + + XMLCreDt presente nell'header di servizio del messaggio fisico referenziato + + + + + Riporta informazioni circa lo stato del messaggio fisico referenziato + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sdd_cbi/data/CBISDDReqLogMsg.00.01.00.xsd b/l10n_it_sdd_cbi/data/CBISDDReqLogMsg.00.01.00.xsd new file mode 100644 index 000000000000..d9c536fad461 --- /dev/null +++ b/l10n_it_sdd_cbi/data/CBISDDReqLogMsg.00.01.00.xsd @@ -0,0 +1,983 @@ + + + + + + + + + + 1.3.2.1.1. - Blocco contenente le informazioni generali sul messaggio logico di richiesta incasso + + + + + 1.3.2.1.2. - Blocco contenente le informazioni di accredito + + + + + + + + + 1.3.2.1.1.1 +Identificativo del messaggio logico. Deve essere univoco a parità di azienda mittente e data di creazione + + + + + 1.3.2.1.1.2 +Data e ora di creazione del messaggio logico + + + + + 1.3.2.1.1.3 +Numero di transazioni DD incluse nel messaggio logico + + + + + 1.3.2.1.1.4 +Somma di controllo. Deve coincidere con la somma degli importi delle disposizioni di incasso contenute nella richiesta + + + + + 1.3.2.1.1.5. +Mittente della richiesta di incasso + + + + + + + + + Identificativo informazioni di accredito + + + + + Metodo di pagamento + + + + + Accredito cumulativo + + + + + Informazioni tipo di pagamento + + + + + Data scadenza richiesta dal mittente + + + + + Titolare c/c di accredito / beneficiario + + + + + Conto del creditore + + + + + Banca Passiva sulla quale risiede il c/c di accredito + + + + + Creditore effettivo. Se presente deve essere diverso dal creditore; il controllo viene effettuato sul campo Nm + + + + + Tipologia Commissioni + + + + + Conto su cui sono addebitate le spese associate alle transazioni richieste + + + + + Identificativo schema creditore + + + + + Informazioni relative alle singole transazioni (disposizioni) + + + + + + + + + Identificativi transazione + + + + + Informazioni sul tipo di transazione + + + + + Importo della singola transazione + + + + + Tipologia commissioni, specifica quale parte sosterrà le commissioni associate alla transazione + + + + + Informazioni sul mandato + + + + + Creditore effettivo + + + + + Banca del Debitore + + + + + Titolare c/c addebito + + + + + Coordinate bancarie di addebito + + + + + Debitore effettivo + + + + + Istruzioni per Banca titolare del c/c di accredito bilateralmente concordate tra banca e cliente e rese in testo libero (max 140 caratteri) + + + + + Causale della transazione + + + + + Comunicazioni valutarie + + + + + Informazioni di riconciliazione + + + + + + + + + + + + + + + + + IBAN + + + + + + + + + Identificativo mandato originario + + + + + Identificativo schema creditore originario + + + + + Banca di accredito originaria + + + + + Debitore originario + + + + + Coordinate bancarie di addebito originarie + + + + + Banca originaria del Debitore + + + + + Data originaria della richiesta di incasso + + + + + Frequenza originaria + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Identificativo conto + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Identificativo univoco assegnato all'istruzione dal Mittente nei confronti della sua Banca + + + + + Identificativo URI assegnato dal Mittente e che identifica la singola disposizione di incasso per tutta la catena fino al Debitore. + + + + + + + + + Finalità dell'incasso. +Identifica le causali di alto livello dell'instruzione, basate su un set predefinito di categorie + + + + + + + + + Livelli di servizio specifici + + + + + Strumento specifico di comunità + + + + + Tipo sequenza di incasso + + + + + Strumento specifico di comunità + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Causale in forma codificata. Gli unici valori ammessi sono quelli riportati nella tabella ISO ExternalPurposeCode pubblicata sul sito ISO20022 all'indirizzo http://www.iso20022.org/Payments_External_Code_Lists.page + + + + + + + + + + + + + + + Codifica di servizio + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Informazioni specifiche relative al mandato + + + + + Identificativo pre-notifica + + + + + Data pre-notifica + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Codice strumento + + + + + + + + + Identificativo mandato + + + + + Data di sottoscrizione + + + + + Indicatore di rettifica/variazione mandato + + + + + Dettagli relativi alle modifiche + + + + + Firma digitale/Riferimento al mandato + + + + + Data della prima richiesta di incasso + + + + + Data della ultima richiesta di incasso + + + + + Frequenza incassi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/l10n_it_sdd_cbi/data/CBISDDReqLogMsg.00.01.01.xsd b/l10n_it_sdd_cbi/data/CBISDDReqLogMsg.00.01.01.xsd new file mode 100644 index 000000000000..e6b664924780 --- /dev/null +++ b/l10n_it_sdd_cbi/data/CBISDDReqLogMsg.00.01.01.xsd @@ -0,0 +1,1159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Type Changed into Frequency36Choice for migration to ISO20022 v2019 message + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Name Changed into BICFI and Type Changed into BICFIDec2014Identifier for v2019 ISO message migration + + + + + + CHAN: Field included 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: 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: Type Changed into CBIPostalAddress24 for v2019 ISO message migration + + + + + + + + + + + + + CHAN: Field included for v2019 ISO message migration + + + + + + + + + Finalità dell'incasso. +Identifica le causali di alto livello dell'instruzione, basate su un set predefinito di categorie + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CHAN: Type Changed into Frequency36Choice for migration to ISO20022 v2019 message + + + + + CHAN: Field included for v2019 ISO message migration + + + + + CHAN: Field included for v2019 ISO message migration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/l10n_it_sdd_cbi/data/account_payment_method.xml b/l10n_it_sdd_cbi/data/account_payment_method.xml new file mode 100644 index 000000000000..4f42e4b90c71 --- /dev/null +++ b/l10n_it_sdd_cbi/data/account_payment_method.xml @@ -0,0 +1,22 @@ + + + + + CBI SDD Italy for customers (00.01.00) + cbi_sdd_italy_00_01_00 + inbound + + + CBIBdySDDReq.00.01.00 + + + + CBI SDD Italy for customers (00.01.01) + cbi_sdd_italy_00_01_01 + inbound + + + CBIBdySDDReq.00.01.01 + + + diff --git a/l10n_it_sdd_cbi/models/__init__.py b/l10n_it_sdd_cbi/models/__init__.py new file mode 100644 index 000000000000..039e57f2aae7 --- /dev/null +++ b/l10n_it_sdd_cbi/models/__init__.py @@ -0,0 +1,4 @@ +from . import res_company +from . import res_config_settings +from . import account_payment_method +from . import account_payment_order diff --git a/l10n_it_sdd_cbi/models/account_payment_method.py b/l10n_it_sdd_cbi/models/account_payment_method.py new file mode 100644 index 000000000000..66d839887314 --- /dev/null +++ b/l10n_it_sdd_cbi/models/account_payment_method.py @@ -0,0 +1,26 @@ +# Copyright 2024 Giuseppe Borruso - Dinamiche Aziendali srl +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class AccountPaymentMethodInherit(models.Model): + _inherit = "account.payment.method" + + pain_version = fields.Selection( + selection_add=[ + ("CBIBdySDDReq.00.01.00", "CBIBdySDDReq.00.01.00 (CBI SDD Italy)"), + ("CBIBdySDDReq.00.01.01", "CBIBdySDDReq.00.01.01 (CBI SDD Italy)"), + ], + ondelete={ + "CBIBdySDDReq.00.01.00": "set null", + "CBIBdySDDReq.00.01.01": "set null", + }, + ) + + def get_xsd_file_path(self): + self.ensure_one() + if self.pain_version in ["CBIBdySDDReq.00.01.00", "CBIBdySDDReq.00.01.01"]: + path = f"l10n_it_sdd_cbi/data/{self.pain_version}.xsd" + return path + return super().get_xsd_file_path() diff --git a/l10n_it_sdd_cbi/models/account_payment_order.py b/l10n_it_sdd_cbi/models/account_payment_order.py new file mode 100644 index 000000000000..ed8aaf752b8b --- /dev/null +++ b/l10n_it_sdd_cbi/models/account_payment_order.py @@ -0,0 +1,352 @@ +# Copyright 2024 Giuseppe Borruso - Dinamiche Aziendali srl +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from lxml import etree + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class AccountPaymentOrderInherit(models.Model): + _inherit = "account.payment.order" + + scheme = fields.Selection( + [ + ("CORE", "Basic (CORE)"), + ("B2B", "Enterprise (B2B)"), + ], + default=lambda self: self.env.user.company_id.sepa_payment_order_schema, + track_visibility="onchange", + ) + + @api.model + def _create_creditor_agent_node(self, parent_node, partner_bank): + party_agent = etree.SubElement(parent_node, "CdtrAgt") + institution_node = etree.SubElement(party_agent, "FinInstnId") + member_id_node = etree.SubElement(institution_node, "ClrSysMmbId") + member_id_text = etree.SubElement(member_id_node, "MmbId") + + member_id_text.text = partner_bank.bank_abi or "NOTPROVIDED" + + @api.model + def _is_italian_bank(self, partner_bank): + return ( + partner_bank.acc_type == "iban" + and partner_bank.sanitized_acc_number.upper().startswith("IT") + ) + + @api.model + def generate_party_agent( + self, parent_node, party_type, order, partner_bank, gen_args, bank_line=None + ): + if gen_args.get("pain_flavor").startswith("CBIBdySDDReq"): + if party_type == "Cdtr": + self._create_creditor_agent_node(parent_node, partner_bank) + return True + + if self._is_italian_bank(partner_bank): + return True + + return super().generate_party_agent( + parent_node=parent_node, + party_type=party_type, + order=order, + partner_bank=partner_bank, + gen_args=gen_args, + bank_line=bank_line, + ) + + def generate_pain_nsmap(self): + self.ensure_one() + pain_flavor = self.payment_mode_id.payment_method_id.pain_version + if pain_flavor.startswith("CBIBdySDDReq"): + nsmap = { + "xsi": "http://www.w3.org/2001/XMLSchema-instance", + None: "urn:CBI:xsd:%s" % pain_flavor, + } + return nsmap + + return super().generate_pain_nsmap() + + def _prepare_generation_args(self): + pain_flavor = self.payment_method_id.pain_version + + if not pain_flavor.startswith("CBIBdySDDReq"): + raise UserError( + _( + f"Payment Type Code '{pain_flavor}' is not supported. " + "Only 'CBIBdySDDReq' is allowed for CBI SDD Italy." + ) + ) + + pay_method = self.payment_mode_id.payment_method_id + version = pain_flavor.replace("CBIBdySDDReq", "") + if version.endswith(".00"): + bic_xml_tag = "BIC" + else: + bic_xml_tag = "BICFI" + return { + "bic_xml_tag": bic_xml_tag, + "name_maxsize": 70, + "convert_to_ascii": pay_method.convert_to_ascii, + "payment_method": "DD", + "file_prefix": "sdd_", + "pain_flavor": pain_flavor, + "version": version, + "pain_xsd_file": pay_method.get_xsd_file_path(), + } + + def generate_payment_file(self): + """ + Creates the CBI SDD Italy. + That's the important code! + """ + self.ensure_one() + if not self.payment_method_id.code.startswith("cbi_sdd_italy"): + return super().generate_payment_file() + + initiating_party_issuer = ( + self.payment_mode_id.initiating_party_issuer + or self.payment_mode_id.company_id.initiating_party_issuer + ) + if not initiating_party_issuer or initiating_party_issuer != "CBI": + raise UserError( + _( + "Missing 'Initiating Party Issuer' must be set to 'CBI' " + f"for the company '{self.company_id.name}'." + ) + ) + + gen_args = self._prepare_generation_args() + nsmap = self.generate_pain_nsmap() + attrib = self.generate_pain_attrib() + xml_root = etree.Element("CBIBdySDDReq", nsmap=nsmap, attrib=attrib) + + phyMsgInf = etree.SubElement(xml_root, "PhyMsgInf") + phyMsgTpCd = etree.SubElement(phyMsgInf, "PhyMsgTpCd") + if self.scheme == "CORE": + phyMsgTpCd.text = "INC-SDDC-01" + elif self.scheme == "B2B": + phyMsgTpCd.text = "INC-SDDB-01" + else: + raise UserError(_(f"Invalid CBI SDD Italy Order Scheme {self.scheme}")) + numLogMsg = etree.SubElement(phyMsgInf, "NbOfLogMsg") + numLogMsg.text = "1" + + envel_pay_req = etree.SubElement(xml_root, "CBIEnvelSDDReqLogMsg") + pain_root = etree.SubElement(envel_pay_req, "CBISDDReqLogMsg") + + # A. Group header + (__, nb_of_transactions_a, control_sum_a) = self.generate_group_header_block( + pain_root, gen_args + ) + grp_hdr_node = pain_root.xpath("//GrpHdr")[0] + grp_hdr_node.attrib["xmlns"] = f"urn:CBI:xsd:CBISDDReqLogMsg{gen_args['version']}" + + amount_control_sum_a = 0.0 + lines_per_group, transactions_count_a = self._grouping_payments() + + for ( + (requested_date, priority, categ_purpose, sequence_type, scheme), + lines, + ) in list(lines_per_group.items()): + requested_date = fields.Date.to_string(requested_date) + # B. Payment info + ( + payment_info, + nb_of_transactions_b, + control_sum_b, + ) = self.generate_start_payment_info_block( + pain_root, + "self.name + '-' + " + "sequence_type + '-' + requested_date.replace('-', '') " + "+ '-' + priority + '-' + category_purpose", + priority, + scheme, + categ_purpose, + sequence_type, + requested_date, + { + "self": self, + "sequence_type": sequence_type, + "priority": priority, + "category_purpose": categ_purpose or "NOcateg", + "requested_date": requested_date, + }, + gen_args, + ) + # Add pain to payment info tag (CBI required) + pmt_inf_node = pain_root.xpath("//PmtInf")[0] + pmt_inf_node.attrib["xmlns"] = f"urn:CBI:xsd:CBISDDReqLogMsg{gen_args['version']}" + tags_to_remove = ["//PmtInf//NbOfTxs", "//PmtInf//CtrlSum"] + for tag in tags_to_remove: + elements_to_remove = pain_root.xpath(tag) + for element in elements_to_remove: + parent = element.getparent() + if parent is not None: + parent.remove(element) + + self.generate_party_block( + payment_info, "Cdtr", "B", self.company_partner_bank_id, gen_args + ) + charge_bearer = etree.SubElement(payment_info, "ChrgBr") + if self.sepa: + charge_bearer_text = "SLEV" + else: + charge_bearer_text = self.charge_bearer + charge_bearer.text = charge_bearer_text + creditor_scheme_identification = etree.SubElement( + payment_info, "CdtrSchmeId" + ) + self.generate_creditor_scheme_identification( + creditor_scheme_identification, + "self.payment_mode_id.sepa_creditor_identifier or " + "self.company_id.sepa_creditor_identifier", + "SEPA Creditor Identifier", + {"self": self}, + "SEPA", + gen_args, + ) + transactions_count_b = 0 + amount_control_sum_b = 0.0 + for line in lines: + transactions_count_b += 1 + # C. Direct Debit Transaction Info + dd_transaction_info = etree.SubElement(payment_info, "DrctDbtTxInf") + payment_identification = etree.SubElement(dd_transaction_info, "PmtId") + instruction_identification = etree.SubElement( + payment_identification, "InstrId" + ) + instruction_identification.text = self._prepare_field( + "Instruction Identification", + "str(line.move_id.id)", + {"line": line}, + 6, + 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, + ) + instructed_amount = etree.SubElement( + dd_transaction_info, "InstdAmt", Ccy=currency_name + ) + instructed_amount.text = "%.2f" % line.amount + amount_control_sum_a += line.amount + amount_control_sum_b += line.amount + dd_transaction = etree.SubElement(dd_transaction_info, "DrctDbtTx") + mandate_related_info = etree.SubElement(dd_transaction, "MndtRltdInf") + mandate_identification = etree.SubElement( + mandate_related_info, "MndtId" + ) + mandate = line.payment_line_ids[:1].mandate_id + mandate_identification.text = self._prepare_field( + "Unique Mandate Reference", + "mandate.unique_mandate_reference", + {"mandate": mandate}, + 35, + gen_args=gen_args, + ) + mandate_signature_date = etree.SubElement( + mandate_related_info, "DtOfSgntr" + ) + mandate_signature_date.text = self._prepare_field( + "Mandate Signature Date", + "signature_date", + {"signature_date": fields.Date.to_string(mandate.signature_date)}, + 10, + gen_args=gen_args, + ) + if sequence_type == "FRST" and mandate.last_debit_date: + amendment_indicator = etree.SubElement( + mandate_related_info, "AmdmntInd" + ) + amendment_indicator.text = "true" + amendment_info_details = etree.SubElement( + mandate_related_info, "AmdmntInfDtls" + ) + ori_debtor_account = etree.SubElement( + amendment_info_details, "OrgnlDbtrAcct" + ) + ori_debtor_account_id = etree.SubElement(ori_debtor_account, "Id") + ori_debtor_agent_other = etree.SubElement( + ori_debtor_account_id, "Othr" + ) + ori_debtor_agent_other_id = etree.SubElement( + ori_debtor_agent_other, "Id" + ) + ori_debtor_agent_other_id.text = "SMNDA" + # Until 20/11/2016, SMNDA meant + # "Same Mandate New Debtor Agent" + # After 20/11/2016, SMNDA means + # "Same Mandate New Debtor Account" + + self.generate_party_block( + dd_transaction_info, + "Dbtr", + "C", + line.partner_bank_id, + gen_args, + line, + ) + line_purpose = line.payment_line_ids[:1].purpose + if line_purpose: + purpose = etree.SubElement(dd_transaction_info, "Purp") + etree.SubElement(purpose, "Cd").text = line_purpose + + self.generate_remittance_info_block(dd_transaction_info, line, gen_args) + + nb_of_transactions_a.text = str(transactions_count_a) + control_sum_a.text = "%.2f" % amount_control_sum_a + + return self.finalize_sepa_file_creation(xml_root, gen_args) + + def _grouping_payments(self): + lines_per_group = {} + transactions_count_a = 0 + # key = (requested_date, priority, sequence type) + # value = list of lines as objects + for line in self.payment_ids: + transactions_count_a += 1 + payment_line = line.payment_line_ids[:1] + priority = payment_line.priority + categ_purpose = payment_line.category_purpose + scheme = payment_line.mandate_id.scheme + if payment_line.mandate_id.type == "oneoff": + seq_type = "OOFF" + elif payment_line.mandate_id.type == "recurrent": + seq_type_map = {"recurring": "RCUR", "first": "FRST", "final": "FNAL"} + seq_type_label = payment_line.mandate_id.recurrent_sequence_type + assert seq_type_label is not False + seq_type = seq_type_map[seq_type_label] + else: + raise UserError( + _( + "Invalid mandate type in '%s'. Valid ones are 'Recurrent' " + "or 'One-Off'" + ) + % payment_line.mandate_id.unique_mandate_reference + ) + # The field line.date is the requested payment date + # taking into account the 'date_preferred' setting + # cf account_banking_payment_export/models/account_payment.py + # in the inherit of action_open() + key = (line.date, priority, categ_purpose, seq_type, scheme) + if key in lines_per_group: + lines_per_group[key].append(line) + else: + lines_per_group[key] = [line] + return lines_per_group, transactions_count_a diff --git a/l10n_it_sdd_cbi/models/res_company.py b/l10n_it_sdd_cbi/models/res_company.py new file mode 100644 index 000000000000..c90e53956eb8 --- /dev/null +++ b/l10n_it_sdd_cbi/models/res_company.py @@ -0,0 +1,17 @@ +# Copyright 2024 Giuseppe Borruso - Dinamiche Aziendali srl +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ResCompanyInherit(models.Model): + _inherit = "res.company" + + sepa_payment_order_schema = fields.Selection( + [ + ("CORE", "Basic (CORE)"), + ("B2B", "Enterprise (B2B)"), + ], + string="Payment Order Scheme", + default="CORE", + ) diff --git a/l10n_it_sdd_cbi/models/res_config_settings.py b/l10n_it_sdd_cbi/models/res_config_settings.py new file mode 100644 index 000000000000..c882fc6dbb6e --- /dev/null +++ b/l10n_it_sdd_cbi/models/res_config_settings.py @@ -0,0 +1,13 @@ +# Copyright 2024 Giuseppe Borruso - Dinamiche Aziendali srl +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ResConfigSettingsInherit(models.TransientModel): + _inherit = "res.config.settings" + + sepa_payment_order_schema = fields.Selection( + related="company_id.sepa_payment_order_schema", + readonly=False, + ) diff --git a/l10n_it_sdd_cbi/post_install.py b/l10n_it_sdd_cbi/post_install.py new file mode 100644 index 000000000000..ce17cd4960cc --- /dev/null +++ b/l10n_it_sdd_cbi/post_install.py @@ -0,0 +1,18 @@ +# Copyright 2016 Akretion (Alexis de Lattre ) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import SUPERUSER_ID, api + + +def update_bank_journals(cr, registry): + with api.Environment.manage(): + env = api.Environment(cr, SUPERUSER_ID, {}) + ajo = env["account.journal"] + journals = ajo.search([("type", "=", "bank")]) + sdd_00 = env.ref("l10n_it_sepa_direct_debit.cbi_sdd_italy_00_01_00") + if sdd_00: + journals.write({"inbound_payment_method_ids": [(4, sdd_00.id)]}) + sdd_01 = env.ref("l10n_it_sepa_direct_debit.cbi_sdd_italy_00_01_01") + if sdd_01: + journals.write({"inbound_payment_method_ids": [(4, sdd_01.id)]}) + return diff --git a/l10n_it_sdd_cbi/readme/CONTRIBUTORS.rst b/l10n_it_sdd_cbi/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..9c778da36d4a --- /dev/null +++ b/l10n_it_sdd_cbi/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Giuseppe Borruso diff --git a/l10n_it_sdd_cbi/readme/DESCRIPTION.rst b/l10n_it_sdd_cbi/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..ace5bccd33d9 --- /dev/null +++ b/l10n_it_sdd_cbi/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +**Italiano** + +Questo modulo consente di generare correttamente file CBI SDD Italy. + +**English** + +The module allows to use correctly generate the file CBI SDD Italy. diff --git a/l10n_it_sdd_cbi/static/description/icon.png b/l10n_it_sdd_cbi/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/l10n_it_sdd_cbi/static/description/icon.png differ diff --git a/l10n_it_sdd_cbi/static/description/index.html b/l10n_it_sdd_cbi/static/description/index.html new file mode 100644 index 000000000000..26c0fd7ac943 --- /dev/null +++ b/l10n_it_sdd_cbi/static/description/index.html @@ -0,0 +1,426 @@ + + + + + +ITA - SEPA Direct Debit + + + +
+

ITA - SEPA Direct Debit

+ + +

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

+

Italiano

+

Questo modulo consente di generare correttamente file CBI SDD Italy.

+

English

+

The module allows to use correctly generate the file CBI SDD Italy.

+

Table of contents

+ +
+

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

+
    +
  • Dinamiche Aziendali srl
  • +
+
+
+

Contributors

+
    +
  • Giuseppe Borruso
  • +
+
+
+

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.

+

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_sdd_cbi/views/account_payment_order_view.xml b/l10n_it_sdd_cbi/views/account_payment_order_view.xml new file mode 100644 index 000000000000..89693ed65c11 --- /dev/null +++ b/l10n_it_sdd_cbi/views/account_payment_order_view.xml @@ -0,0 +1,32 @@ + + + + + account.payment.order.form.inherit.view + account.payment.order + + + + + + + + + + account.payment.order.tree.inherit.view + account.payment.order + + + + + + + + + diff --git a/l10n_it_sdd_cbi/views/res_config_settings_view.xml b/l10n_it_sdd_cbi/views/res_config_settings_view.xml new file mode 100644 index 000000000000..456b4261669f --- /dev/null +++ b/l10n_it_sdd_cbi/views/res_config_settings_view.xml @@ -0,0 +1,27 @@ + + + + + res.config.settings.form.inherit.view + res.config.settings + + + +
+
+
+
+
+ +
diff --git a/setup/l10n_it_sdd_cbi/odoo/addons/l10n_it_sdd_cbi b/setup/l10n_it_sdd_cbi/odoo/addons/l10n_it_sdd_cbi new file mode 120000 index 000000000000..b0696f004469 --- /dev/null +++ b/setup/l10n_it_sdd_cbi/odoo/addons/l10n_it_sdd_cbi @@ -0,0 +1 @@ +../../../../l10n_it_sdd_cbi \ No newline at end of file diff --git a/setup/l10n_it_sdd_cbi/setup.py b/setup/l10n_it_sdd_cbi/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/l10n_it_sdd_cbi/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)