Skip to content

Commit

Permalink
Add support for regulatory reporting in PAIN files
Browse files Browse the repository at this point in the history
Harmonize values for reference_type on account.move and communication_type on account.payment.line:
2 possible values : free and structured (migration script provided)
Simplify code for reference.
  • Loading branch information
alexis-via committed Nov 15, 2023
1 parent caad76b commit 4584b38
Show file tree
Hide file tree
Showing 26 changed files with 247 additions and 93 deletions.
2 changes: 1 addition & 1 deletion account_banking_pain_base/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Account Banking PAIN Base Module
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:cb0a3e1e489965d9fd1e4540fb54b404f630887d8a913484c222034edbe91786
!! source digest: sha256:b830f262c5a7db70d35218b9b420e0d1614bbb20c17e2a3cb4197609a514d2da
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
Expand Down
2 changes: 2 additions & 0 deletions account_banking_pain_base/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
"external_dependencies": {"python": ["unidecode", "lxml"]},
"data": [
"security/security.xml",
"security/ir.model.access.csv",
"views/account_payment_line.xml",
"views/account_payment_order.xml",
"views/account_payment_mode.xml",
"views/res_config_settings.xml",
"views/account_payment_method.xml",
"views/account_pain_regulatory_reporting.xml",
],
"post_init_hook": "set_default_initiating_party",
"installable": True,
Expand Down
1 change: 1 addition & 0 deletions account_banking_pain_base/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from . import account_payment_line
from . import account_payment_order
from . import account_payment_mode
from . import account_pain_regulatory_reporting
from . import res_company
from . import res_config_settings
from . import account_payment_method
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright 2023 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class AccountPainRegulatoryReporting(models.Model):
_name = "account.pain.regulatory.reporting"
_description = "Regulatory Reporting Codes for ISO 20022/PAIN banking standard"
_order = "code, country_id"

code = fields.Char(required=True, copy=False, size=10)
name = fields.Char(required=True, translate=True, copy=False)
country_id = fields.Many2one("res.country", ondelete="restrict", required=False)
active = fields.Boolean(default=True)

_sql_constraints = [
(
"code_country_unique",
"unique(code, country_id)",
"This code already exists for that country.",
)
]

@api.depends("code", "name")
def name_get(self):
res = []
for rec in self:
res.append((rec.id, "[%s] %s" % (rec.code, rec.name)))
return res

def _name_search(
self, name="", args=None, operator="ilike", limit=100, name_get_uid=None
):
if args is None:
args = []
ids = []
if name and operator == "ilike":
ids = list(self._search([("code", "=", name)] + args, limit=limit))
if ids:
return ids
return super()._name_search(
name=name,
args=args,
operator=operator,
limit=limit,
name_get_uid=name_get_uid,
)
48 changes: 41 additions & 7 deletions account_banking_pain_base/models/account_payment_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
# Copyright 2014-2022 Tecnativa - Pedro M. Baeza
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from lxml import etree

from odoo import api, fields, models


Expand Down Expand Up @@ -163,18 +165,50 @@ class AccountPaymentLine(models.Model):
help="If neither your bank nor your local regulations oblige you to "
"set the category purpose, leave the field empty.",
)
# Regulatory Reporting codes are provided by national central banks for the countries
# where this data is required in specific circumstances
regulatory_reporting_id = fields.Many2one(
"account.pain.regulatory.reporting",
ondelete="restrict",
domain="[('country_id', 'in', (False, company_country_id))]",
)
company_country_id = fields.Many2one(related="company_id.country_id")
# PAIN allows 140 characters
communication = fields.Char(size=140)
# The field struct_communication_type has been dropped in v9
# We now use communication_type ; you should add an option
# in communication_type with selection_add=[]
communication_type = fields.Selection(
selection_add=[("ISO", "ISO")], ondelete={"ISO": "cascade"}
)

@api.model
def _get_payment_line_grouping_fields(self):
"""Add specific PAIN fields to the grouping criteria."""
res = super()._get_payment_line_grouping_fields()
res += ["priority", "local_instrument", "category_purpose", "purpose"]
res += [
"priority",
"local_instrument",
"category_purpose",
"purpose",
"regulatory_reporting_id",
]
return res

def generate_regulatory_reporting(self, parent_node, gen_args):
if self.regulatory_reporting_id:
regulatory_reporting = etree.SubElement(parent_node, "RgltryRptg")
regulatory_reporting_details = etree.SubElement(
regulatory_reporting, "Dtls"
)
regulatory_reporting_details_code = etree.SubElement(
regulatory_reporting_details, "Cd"
)
regulatory_reporting_details_code.text = self.env[
"account.payment.order"
]._prepare_field(
"Regulatory Details Code",
"line.regulatory_reporting_id.code",
{"line": self},
10,
gen_args=gen_args,
)

def generate_purpose(self, parent_node):
if self.purpose:
purpose = etree.SubElement(parent_node, "Purp")
etree.SubElement(purpose, "Cd").text = self.purpose
19 changes: 7 additions & 12 deletions account_banking_pain_base/models/account_payment_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,6 @@ def _validate_xml(self, xml_string, gen_args):
)
% str(e)
) from None
return True

def finalize_sepa_file_creation(self, xml_root, gen_args):
xml_string = etree.tostring(
Expand Down Expand Up @@ -461,7 +460,6 @@ def generate_initiating_party_block(self, parent_node, gen_args):
)
% self.company_id.name
)
return True

@api.model
def generate_party_agent(
Expand Down Expand Up @@ -495,7 +493,6 @@ def generate_party_agent(
# for Credit Transfers, in the 'C' block, if BIC is not provided,
# we should not put the 'Creditor Agent' block at all,
# as per the guidelines of the EPC
return True

@api.model
def generate_party_id(self, parent_node, party_type, partner):
Expand All @@ -519,7 +516,9 @@ def generate_party_acc_number(
party_account_other = etree.SubElement(party_account_id, "Othr")
party_account_other_id = etree.SubElement(party_account_other, "Id")
party_account_other_id.text = partner_bank.sanitized_acc_number
return True
if party_type == "Dbtr" and partner_bank.currency_id:
party_account_current = etree.SubElement(party_account, "Ccy")
party_account_current.text = partner_bank.currency_id.name

@api.model
def generate_address_block(self, parent_node, partner, gen_args):
Expand Down Expand Up @@ -567,7 +566,6 @@ def generate_address_block(self, parent_node, partner, gen_args):
gen_args=gen_args,
)
adrline2.text = val
return True

@api.model
def generate_party_block(
Expand Down Expand Up @@ -625,13 +623,12 @@ def generate_party_block(
gen_args,
bank_line=bank_line,
)
return True

@api.model
def generate_remittance_info_block(self, parent_node, line, gen_args):
remittance_info = etree.SubElement(parent_node, "RmtInf")
communication_type = line.payment_line_ids[:1].communication_type
if communication_type == "normal":
if communication_type == "free":
remittance_info_unstructured = etree.SubElement(remittance_info, "Ustrd")
remittance_info_unstructured.text = self._prepare_field(
"Remittance Unstructured Information",
Expand All @@ -640,7 +637,7 @@ def generate_remittance_info_block(self, parent_node, line, gen_args):
140,
gen_args=gen_args,
)
else:
elif communication_type == "structured":
remittance_info_structured = etree.SubElement(remittance_info, "Strd")
creditor_ref_information = etree.SubElement(
remittance_info_structured, "CdtrRefInf"
Expand All @@ -657,7 +654,7 @@ def generate_remittance_info_block(self, parent_node, line, gen_args):
creditor_ref_info_type_issuer = etree.SubElement(
creditor_ref_info_type, "Issr"
)
creditor_ref_info_type_issuer.text = communication_type
creditor_ref_info_type_issuer.text = "ISO"
creditor_reference = etree.SubElement(
creditor_ref_information, "CdtrRef"
)
Expand All @@ -676,7 +673,7 @@ def generate_remittance_info_block(self, parent_node, line, gen_args):
creditor_ref_info_type_issuer = etree.SubElement(
creditor_ref_info_type, "Issr"
)
creditor_ref_info_type_issuer.text = communication_type
creditor_ref_info_type_issuer.text = "ISO"

creditor_reference = etree.SubElement(creditor_ref_information, "Ref")

Expand All @@ -687,7 +684,6 @@ def generate_remittance_info_block(self, parent_node, line, gen_args):
35,
gen_args=gen_args,
)
return True

@api.model
def generate_creditor_scheme_identification(
Expand All @@ -709,4 +705,3 @@ def generate_creditor_scheme_identification(
csi_scheme_name = etree.SubElement(csi_other, "SchmeNm")
csi_scheme_name_proprietary = etree.SubElement(csi_scheme_name, "Prtry")
csi_scheme_name_proprietary.text = scheme_name_proprietary
return True
3 changes: 3 additions & 0 deletions account_banking_pain_base/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_pain_regulatory_reporting_read,Read access on account.pain.regulatory.reporting,model_account_pain_regulatory_reporting,base.group_user,1,0,0,0
access_account_pain_regulatory_reporting_full,Full access on account.pain.regulatory.reporting,model_account_pain_regulatory_reporting,account.group_account_manager,1,1,1,1
2 changes: 1 addition & 1 deletion account_banking_pain_base/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ <h1 class="title">Account Banking PAIN Base Module</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:cb0a3e1e489965d9fd1e4540fb54b404f630887d8a913484c222034edbe91786
!! source digest: sha256:b830f262c5a7db70d35218b9b420e0d1614bbb20c17e2a3cb4197609a514d2da
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/bank-payment/tree/16.0/account_banking_pain_base"><img alt="OCA/bank-payment" src="https://img.shields.io/badge/github-OCA%2Fbank--payment-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/bank-payment-16-0/bank-payment-16-0-account_banking_pain_base"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/bank-payment&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module contains fields and functions that are used by the module for SEPA
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2023 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <[email protected]>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>

<record id="account_pain_regulatory_reporting_form" model="ir.ui.view">
<field name="model">account.pain.regulatory.reporting</field>
<field name="arch" type="xml">
<form>
<widget
name="web_ribbon"
title="Archived"
bg_color="bg-danger"
attrs="{'invisible': [('active', '=', True)]}"
/>
<group name="main">
<field name="code" />
<field name="name" />
<field name="country_id" />
<field name="active" invisible="1" />
</group>
</form>
</field>
</record>

<record id="account_pain_regulatory_reporting_tree" model="ir.ui.view">
<field name="model">account.pain.regulatory.reporting</field>
<field name="arch" type="xml">
<tree>
<field name="code" decoration-bf="1" />
<field name="name" />
<field name="country_id" />
</tree>
</field>
</record>

<record id="account_pain_regulatory_reporting_search" model="ir.ui.view">
<field name="model">account.pain.regulatory.reporting</field>
<field name="arch" type="xml">
<search>
<field
name="name"
filter_domain="['|', ('name', 'ilike', self), ('code', 'ilike', self)]"
string="Code or Name"
/>
<field name="country_id" />
<separator />
<filter
string="Archived"
name="inactive"
domain="[('active', '=', False)]"
/>
<group name="groupby">
<filter
name="country_groupby"
string="Country"
context="{'group_by': 'country_id'}"
/>
</group>
</search>
</field>
</record>

<record id="account_pain_regulatory_reporting_action" model="ir.actions.act_window">
<field name="name">PAIN Regulatory Reporting</field>
<field name="res_model">account.pain.regulatory.reporting</field>
<field name="view_mode">tree,form</field>
</record>

<menuitem
id="account_pain_regulatory_reporting_menu"
action="account_pain_regulatory_reporting_action"
parent="account.account_management_menu"
sequence="200"
/>

</odoo>
10 changes: 10 additions & 0 deletions account_banking_pain_base/views/account_payment_line.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<field name="local_instrument" />
<field name="category_purpose" />
<field name="purpose" />
<field
name="regulatory_reporting_id"
options="{'no_create': True, 'no_create_edit': True}"
/>
<field name="company_country_id" invisible="1" />
</group>
</field>
</record>
Expand All @@ -30,6 +35,11 @@
<field name="arch" type="xml">
<field name="communication" position="after">
<field name="priority" optional="hide" />
<field name="local_instrument" optional="hide" />
<field name="category_purpose" optional="hide" />
<field name="purpose" optional="hide" />
<field name="regulatory_reporting_id" optional="hide" />
<field name="company_country_id" invisible="1" />
</field>
</field>
</record>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,11 @@ def generate_payment_file(self): # noqa: C901
gen_args,
line,
)
line_purpose = line.payment_line_ids[:1].purpose
if line_purpose:
purpose = etree.SubElement(credit_transfer_transaction_info, "Purp")
etree.SubElement(purpose, "Cd").text = line_purpose
payment_line = line.payment_line_ids[0]
payment_line.generate_purpose(credit_transfer_transaction_info)
payment_line.generate_regulatory_reporting(
credit_transfer_transaction_info, gen_args
)
self.generate_remittance_info_block(
credit_transfer_transaction_info, line, gen_args
)
Expand Down
Loading

0 comments on commit 4584b38

Please sign in to comment.