From 9da52f06ca9024cc7ad64e2802cab90442252f07 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Mon, 20 Jan 2025 16:50:10 +0100 Subject: [PATCH 1/4] [ADD] account_payment_base_oca: New base module for OCA/bank-payment --- account_payment_base_oca/README.rst | 105 ++++ account_payment_base_oca/__init__.py | 2 + account_payment_base_oca/__manifest__.py | 26 + account_payment_base_oca/demo/demo.xml | 53 +++ account_payment_base_oca/models/__init__.py | 5 + .../models/account_move.py | 16 + .../models/account_payment_method.py | 34 ++ .../models/account_payment_method_line.py | 195 ++++++++ account_payment_base_oca/models/res_bank.py | 37 ++ .../models/res_partner_bank.py | 64 +++ account_payment_base_oca/pyproject.toml | 3 + .../readme/CONTRIBUTORS.md | 17 + .../readme/DESCRIPTION.md | 1 + account_payment_base_oca/reports/__init__.py | 1 + .../reports/account_invoice_report.py | 22 + .../reports/account_invoice_report_view.xml | 35 ++ .../security/ir.model.access.csv | 2 + account_payment_base_oca/security/ir_rule.xml | 13 + .../static/description/index.html | 447 ++++++++++++++++++ .../views/account_move.xml | 38 ++ .../views/account_payment_method.xml | 92 ++++ .../views/account_payment_method_line.xml | 159 +++++++ 22 files changed, 1367 insertions(+) create mode 100644 account_payment_base_oca/README.rst create mode 100644 account_payment_base_oca/__init__.py create mode 100644 account_payment_base_oca/__manifest__.py create mode 100644 account_payment_base_oca/demo/demo.xml create mode 100644 account_payment_base_oca/models/__init__.py create mode 100644 account_payment_base_oca/models/account_move.py create mode 100644 account_payment_base_oca/models/account_payment_method.py create mode 100644 account_payment_base_oca/models/account_payment_method_line.py create mode 100644 account_payment_base_oca/models/res_bank.py create mode 100644 account_payment_base_oca/models/res_partner_bank.py create mode 100644 account_payment_base_oca/pyproject.toml create mode 100644 account_payment_base_oca/readme/CONTRIBUTORS.md create mode 100644 account_payment_base_oca/readme/DESCRIPTION.md create mode 100644 account_payment_base_oca/reports/__init__.py create mode 100644 account_payment_base_oca/reports/account_invoice_report.py create mode 100644 account_payment_base_oca/reports/account_invoice_report_view.xml create mode 100644 account_payment_base_oca/security/ir.model.access.csv create mode 100644 account_payment_base_oca/security/ir_rule.xml create mode 100644 account_payment_base_oca/static/description/index.html create mode 100644 account_payment_base_oca/views/account_move.xml create mode 100644 account_payment_base_oca/views/account_payment_method.xml create mode 100644 account_payment_base_oca/views/account_payment_method_line.xml diff --git a/account_payment_base_oca/README.rst b/account_payment_base_oca/README.rst new file mode 100644 index 00000000000..0ba5406b152 --- /dev/null +++ b/account_payment_base_oca/README.rst @@ -0,0 +1,105 @@ +======================== +Account Payment Base OCA +======================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:398fe25e1ed0988a7a0504f68878755aa77b7b87532718ca8dfaa344c31b88e1 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fbank--payment-lightgray.png?logo=github + :target: https://github.com/OCA/bank-payment/tree/18.0/account_payment_base_oca + :alt: OCA/bank-payment +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/bank-payment-18-0/bank-payment-18-0-account_payment_base_oca + :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/bank-payment&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This is the new base module for the OCA **bank-payment** project. This +module has been developped for Odoo 18 to adapt the OCA bank-payment +stack to the new native payment mode object of Odoo. + +**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 +------- + +* Akretion + +Contributors +------------ + +- Alexis de Lattre +- Eric Lembregts +- Andrea Stirpe +- Marçal Isern +- Miquel Alzanillas +- Raphaël Valyi +- Stefan Rijnhart (Therp) +- Alexandre Fayolle +- Stéphane Bidoul +- Danimar Ribeiro +- Angel Moya +- `Tecnativa `__: + + - Pedro M. Baeza + - Carlos Dauden + - Víctor Martínez + +- `DynApps `__: + + - Raf Ven + +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-alexis-via| image:: https://github.com/alexis-via.png?size=40px + :target: https://github.com/alexis-via + :alt: alexis-via + +Current `maintainer `__: + +|maintainer-alexis-via| + +This module is part of the `OCA/bank-payment `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_payment_base_oca/__init__.py b/account_payment_base_oca/__init__.py new file mode 100644 index 00000000000..55ec7fc9ac7 --- /dev/null +++ b/account_payment_base_oca/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import reports diff --git a/account_payment_base_oca/__manifest__.py b/account_payment_base_oca/__manifest__.py new file mode 100644 index 00000000000..7c2b3cc8ff7 --- /dev/null +++ b/account_payment_base_oca/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright 2024-2025 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Account Payment Base OCA", + "version": "18.0.1.0.0", + "category": "Accounting", + "license": "AGPL-3", + "summary": "OCA extensions to native payment objects of Odoo", + "author": "Akretion,Odoo Community Association (OCA)", + "maintainers": ["alexis-via"], + "development_status": "Beta", + "website": "https://github.com/OCA/bank-payment", + "depends": ["account"], + "data": [ + "security/ir.model.access.csv", + "views/account_payment_method.xml", + "views/account_payment_method_line.xml", + "views/account_move.xml", + "reports/account_invoice_report_view.xml", + "security/ir_rule.xml", + ], + "demo": ["demo/demo.xml"], + "installable": True, +} diff --git a/account_payment_base_oca/demo/demo.xml b/account_payment_base_oca/demo/demo.xml new file mode 100644 index 00000000000..928fbade92f --- /dev/null +++ b/account_payment_base_oca/demo/demo.xml @@ -0,0 +1,53 @@ + + + + Qonto + QNTOFRP1XXX + 20 bis rue La Fayette + 75009 + Paris + + + + La Banque Postale + PSSTFRPPXXX + 115 rue de Sèvres + 75007 + Paris + + + + Société Générale + SOGEFRPPXXX + 1 avenue du Roi Fabien 1er + 75008 + Paris + + + + BNP Paribas Fortis Charleroi + GEBABEBB03A + Charleroi + + + + FR76 4242 4242 4242 4242 4242 424 + + + + + FR20 1242 1242 1242 1242 1242 124 + + + + + FR66 1212 1212 1212 1212 1212 121 + + + + + BE96 9988 7766 5544 + + + + diff --git a/account_payment_base_oca/models/__init__.py b/account_payment_base_oca/models/__init__.py new file mode 100644 index 00000000000..cbe36cdb3be --- /dev/null +++ b/account_payment_base_oca/models/__init__.py @@ -0,0 +1,5 @@ +from . import account_payment_method +from . import account_payment_method_line +from . import account_move +from . import res_partner_bank +from . import res_bank diff --git a/account_payment_base_oca/models/account_move.py b/account_payment_base_oca/models/account_move.py new file mode 100644 index 00000000000..67fefc846b6 --- /dev/null +++ b/account_payment_base_oca/models/account_move.py @@ -0,0 +1,16 @@ +# Copyright 2024-2025 Akretion France (https://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountMove(models.Model): + _inherit = "account.move" + + bank_account_required = fields.Boolean( + related="preferred_payment_method_line_id.payment_method_id.bank_account_required", + ) + payment_method_code = fields.Char( + related="preferred_payment_method_line_id.payment_method_id.code", store=True + ) diff --git a/account_payment_base_oca/models/account_payment_method.py b/account_payment_base_oca/models/account_payment_method.py new file mode 100644 index 00000000000..6424e82406c --- /dev/null +++ b/account_payment_base_oca/models/account_payment_method.py @@ -0,0 +1,34 @@ +# Copyright 2016-2025 Akretion France (https://www.akretion.com/) +# @author: Alexis de Lattre +# 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" + + # native field, we just inherit string and help + code = fields.Char( + string="Code (do not modify)", + help="This code is used in the source code of the Odoo module that handles " + "this payment method. Therefore, if you change it, " + "the generation of the payment file may fail.", + ) + active = fields.Boolean(default=True) + bank_account_required = fields.Boolean( + help="Activate this option if this payment method requires you to " + "know the bank account number of your customer or supplier." + ) + # add the one2many field which is not native + line_ids = fields.One2many( + comodel_name="account.payment.method.line", + inverse_name="payment_method_id", + string="Payment Methods", + ) + + @api.depends("code", "name", "payment_type") + def _compute_display_name(self): + for method in self: + name = f"[{method.code}] {method.name} ({method.payment_type})" + method.display_name = name diff --git a/account_payment_base_oca/models/account_payment_method_line.py b/account_payment_base_oca/models/account_payment_method_line.py new file mode 100644 index 00000000000..78631ea31b3 --- /dev/null +++ b/account_payment_base_oca/models/account_payment_method_line.py @@ -0,0 +1,195 @@ +# Copyright 2024-2025 Akretion France (http://www.akretion.com/) +# @author: Alexis de Lattre +# Copyright 2017 ForgeFlow S.L. +# Copyright 2018 Tecnativa - Carlos Dauden, Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import Command, _, api, fields, models +from odoo.exceptions import ValidationError + + +class AccountPaymentMethodLine(models.Model): + _inherit = "account.payment.method.line" + # native order: sequence, id + _order = "active desc, sequence, id" + _check_company_auto = True + + # START inherit of native fields + name = fields.Char(translate=True) + journal_id = fields.Many2one( + domain="[('id', 'in', filter_journal_ids)]", + ) + company_id = fields.Many2one( + "res.company", + related=False, # native: related='journal_id.company_id' + required=True, + compute="_compute_company_id", # for smooth post-install + store=True, + precompute=True, + readonly=False, + ) + # END inherit of native fields + # Here is the strategy to support bank_account_link = variable + # without breaking the native behavior + # company_id is a related of journal_id.company_id + # When bank_account_link = 'fixed' => we use journal_id + # When bank_account_link = 'variable': + # - journal_id is considered as the default journal + # - alternative_journal_ids are additional journals that can be used + filter_journal_ids = fields.Many2many( + "account.journal", compute="_compute_filter_journal_ids" + ) + bank_account_link = fields.Selection( + [("fixed", "Fixed"), ("variable", "Variable")], + string="Link to Bank Account", + required=True, + default="fixed", + help="For payment modes that are always attached to the same bank " + "account of your company (such as wire transfer from customers or " + "SEPA direct debit from suppliers), select " + "'Fixed'. For payment modes that are not always attached to the same " + "bank account (such as SEPA Direct debit for customers, wire transfer " + "to suppliers), you should select 'Variable', which means that you " + "will select the bank account on the payment order. If your company " + "only has one bank account, you should always select 'Fixed'.", + ) + # I need to explicitly define the table name + # because I have 2 M2M fields pointing to account.journal + alternative_journal_ids = fields.Many2many( + comodel_name="account.journal", + relation="account_payment_method_line_alternative_journal_rel", + column1="method_line_id", + column2="journal_id", + string="Alternative Bank Journals", + domain="[('id', '!=', journal_id), ('id', 'in', filter_journal_ids)]", + check_company=True, + compute="_compute_alternative_journal_ids", + store=True, + readonly=False, + precompute=True, + ) + # active is default=False on purpose ! + # When an account.payment.method with mode='multi' is created, Odoo + # generates an account.payment.method.line for each bank journal and there is no + # prepare method to inherit the values of the generated method lines. + # With default=False, Odoo will auto-generate inactive account.payment.method.line + # and we will only enable the one we want to use. If a payment order has a method + # line with bank_account_link='variable' and an alternative journal is selected, + # Odoo will not use the method line of the payment order to generate + # the account.payment but it will select the (inactive) method line + # linked to the chosen journal + # TODO default=False causes problems in tests of the account module + active = fields.Boolean(default=False) + report_description = fields.Html(translate=True) + show_bank_account = fields.Selection( + selection=[ + ("full", "Full"), + ("first", "First n chars"), + ("last", "Last n chars"), + ("first_last", "First n chars and Last n chars"), + ("no", "No"), + ], + default="full", + string="Show Customer Bank Account", + help="On invoice report, show partial or full bank account number.", + ) + show_bank_account_chars = fields.Integer( + string="# of Digits to Show for Customer Bank Account", + default=4, + ) + refund_payment_method_line_id = fields.Many2one( + comodel_name="account.payment.method.line", + domain="[('payment_type', '!=', payment_type)]", + string="Payment Mode for Refunds", + help="This payment mode will be used when doing " + "refunds coming from the current payment mode.", + check_company=True, + ) + + _sql_constraints = [ + ( + "show_bank_account_chars_positive", + "CHECK(show_bank_account_chars >= 0)", + "The number of digits to show for customer bank account " + "must be positive or null.", + ) + ] + + @api.constrains( + "bank_account_link", + "journal_id", + "alternative_journal_ids", + "payment_method_id", + ) + def _check_payment_method_line(self): + for line in self: + if not line.journal_id: + raise ValidationError( + _( + "On %(name)s, the bank journal is not set.", + name=line.display_name, + ) + ) + if line.payment_method_id.bank_account_required: + # if line.journal_id and not line.journal_id.bank_account_id: + # raise ValidationError( + # _( + # "On %(name)s, the Payment Method %(method)s is " + # "configured with Bank Account Required but journal " + # "%(journal)s is not linked to a bank account.", + # name=line.display_name, + # method=line.payment_method_id.display_name, + # journal=line.journal_id.display_name, + # ) + # ) + if line.bank_account_link == "variable": + for journal in line.alternative_journal_ids: + if not journal.bank_account_id: + raise ValidationError( + _( + "On %(name)s, the Payment Method %(method)s is " + "configured with Bank Account Required but journal " + "%(journal)s is not linked to a bank account.", + name=line.display_name, + method=line.payment_method_id.display_name, + journal=journal.display_name, + ) + ) + + @api.depends("journal_id", "bank_account_link") + def _compute_alternative_journal_ids(self): + for line in self: + if line.bank_account_link == "fixed": + line.alternative_journal_ids = [Command.clear()] + elif ( + line.bank_account_link == "variable" + and line.journal_id + and line.journal_id.id in line.alternative_journal_ids.ids + ): + line.alternative_journal_ids = [Command.unlink(line.journal_id.id)] + + @api.depends("journal_id") + def _compute_company_id(self): + for line in self: + if line.journal_id: + line.company_id = line.journal_id.company_id.id + else: + line.company_id = self.env.company.id + + @api.depends("payment_method_id", "company_id") + def _compute_filter_journal_ids(self): + infos = self.env["account.payment.method"]._get_payment_method_information() + for line in self: + domain = [] + if line.company_id: + domain.append(("company_id", "=", line.company_id.id)) + if line.payment_method_id: + journal_types = infos.get(line.payment_method_id.code, {}).get("type") + if journal_types: + domain.append(("type", "in", journal_types)) + else: + domain.append(("type", "in", ("bank", "cash", "credit"))) + else: + domain.append(("type", "in", ("bank", "cash", "credit"))) + line.filter_journal_ids = self.env["account.journal"].search(domain).ids diff --git a/account_payment_base_oca/models/res_bank.py b/account_payment_base_oca/models/res_bank.py new file mode 100644 index 00000000000..7874b65a67d --- /dev/null +++ b/account_payment_base_oca/models/res_bank.py @@ -0,0 +1,37 @@ +# Copyright 2015-2025 Akretion France (https://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +import re + +from odoo import _, api, models +from odoo.exceptions import ValidationError + +BIC_REGEX = re.compile(r"[A-Z]{6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3})?$") + + +class ResBank(models.Model): + _inherit = "res.bank" + + @api.constrains("bic") + def _check_bic_length(self): + for bank in self: + if bank.bic: + if len(bank.bic) not in (8, 11): + raise ValidationError( + _( + "A valid BIC contains 8 or 11 characters. BIC '%(bic)s' " + "contains %(num)d characters, so it is not valid.", + bic=bank.bic, + num=len(bank.bic), + ) + ) + if not BIC_REGEX.match(bank.bic): + raise ValidationError( + _( + "BIC '%(bic)s' doesn't respect the standard " + "pattern '{pattern}'.", + bic=bank.bic, + pattern=BIC_REGEX.pattern, + ) + ) diff --git a/account_payment_base_oca/models/res_partner_bank.py b/account_payment_base_oca/models/res_partner_bank.py new file mode 100644 index 00000000000..b918859c1f0 --- /dev/null +++ b/account_payment_base_oca/models/res_partner_bank.py @@ -0,0 +1,64 @@ +# Copyright 2023-2025 Akretion France (https://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + +SCRAMBLE_CHAR = "*" + + +class ResPartnerBank(models.Model): + _inherit = "res.partner.bank" + + acc_number_scrambled = fields.Char(compute="_compute_acc_number_scrambled") + + def _do_scramble( + self, letter, position_from_start, position_from_end, first_n, last_n + ): + if first_n and position_from_start <= first_n: + return False + elif last_n and position_from_end <= last_n: + return False + return True + + def _scramble_acc_number(self, acc_number, first_n, last_n): + # scramble account number and while keeping spaces + scrambled_number_list = list(acc_number) + position_from_start = 1 + position_from_end = len(acc_number.replace(" ", "")) + position = 0 + for letter in acc_number: + if letter != " ": + do_scramble = self._do_scramble( + letter, position_from_start, position_from_end, first_n, last_n + ) + if do_scramble: + scrambled_number_list[position] = SCRAMBLE_CHAR + position_from_start += 1 + position_from_end -= 1 + position += 1 + scrambled_acc_number = "".join(scrambled_number_list) + return scrambled_acc_number + + def get_acc_number(self, show_policy, show_chars=4): + self.ensure_one() + assert show_policy in ("full", "first", "last", "first_last", "no") + if not self.acc_number or show_policy == "no": + return "" + if show_policy == "full": + res = self.acc_number + elif show_policy == "first": + res = self._scramble_acc_number(self.acc_number, show_chars, 0) + elif show_policy == "last": + res = self._scramble_acc_number(self.acc_number, 0, show_chars) + elif show_policy == "first_last": + res = self._scramble_acc_number(self.acc_number, show_chars, show_chars) + return res + + @api.depends("acc_number") + @api.depends_context("show_bank_account", "show_bank_account_chars") + def _compute_acc_number_scrambled(self): + policy = self.env.context.get("show_bank_account", "first_last") + show_chars = self.env.context.get("show_bank_account_chars", 4) + for rec in self: + rec.acc_number_scrambled = rec.get_acc_number(policy, show_chars=show_chars) diff --git a/account_payment_base_oca/pyproject.toml b/account_payment_base_oca/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/account_payment_base_oca/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/account_payment_base_oca/readme/CONTRIBUTORS.md b/account_payment_base_oca/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..545b23428be --- /dev/null +++ b/account_payment_base_oca/readme/CONTRIBUTORS.md @@ -0,0 +1,17 @@ +- Alexis de Lattre \<\> +- Eric Lembregts \<\> +- Andrea Stirpe \<\> +- Marçal Isern \<\> +- Miquel Alzanillas \<\> +- Raphaël Valyi +- Stefan Rijnhart (Therp) +- Alexandre Fayolle +- Stéphane Bidoul \<\> +- Danimar Ribeiro +- Angel Moya \<\> +- [Tecnativa](https://www.tecnativa.com): + - Pedro M. Baeza + - Carlos Dauden + - Víctor Martínez +- [DynApps](https://www.dynapps.be): + - Raf Ven \<\> diff --git a/account_payment_base_oca/readme/DESCRIPTION.md b/account_payment_base_oca/readme/DESCRIPTION.md new file mode 100644 index 00000000000..e796678e547 --- /dev/null +++ b/account_payment_base_oca/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This is the new base module for the OCA **bank-payment** project. This module has been developped for Odoo 18 to adapt the OCA bank-payment stack to the new native payment mode object of Odoo. diff --git a/account_payment_base_oca/reports/__init__.py b/account_payment_base_oca/reports/__init__.py new file mode 100644 index 00000000000..52e62702b3c --- /dev/null +++ b/account_payment_base_oca/reports/__init__.py @@ -0,0 +1 @@ +from . import account_invoice_report diff --git a/account_payment_base_oca/reports/account_invoice_report.py b/account_payment_base_oca/reports/account_invoice_report.py new file mode 100644 index 00000000000..b53cfb2bdc4 --- /dev/null +++ b/account_payment_base_oca/reports/account_invoice_report.py @@ -0,0 +1,22 @@ +# Copyright 2024-2025 Akretion France (https://www.akretion.com/) +# @author: Alexis de Lattre +# Copyright 2021 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models +from odoo.tools import SQL + + +class AccountInvoiceReport(models.Model): + _inherit = "account.invoice.report" + + payment_method_line_id = fields.Many2one( + "account.payment.method.line", readonly=True, string="Payment Mode" + ) + + @api.model + def _select(self) -> SQL: + return SQL( + "%s, move.preferred_payment_method_line_id AS " "payment_method_line_id", + super()._select(), + ) diff --git a/account_payment_base_oca/reports/account_invoice_report_view.xml b/account_payment_base_oca/reports/account_invoice_report_view.xml new file mode 100644 index 00000000000..b574f83bae8 --- /dev/null +++ b/account_payment_base_oca/reports/account_invoice_report_view.xml @@ -0,0 +1,35 @@ + + + + + account.invoice.report + + + + + + + + + + account.invoice.report + + + + + + + + + + + diff --git a/account_payment_base_oca/security/ir.model.access.csv b/account_payment_base_oca/security/ir.model.access.csv new file mode 100644 index 00000000000..53aacac9d19 --- /dev/null +++ b/account_payment_base_oca/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +account.access_account_payment_method,Full access on account.payment.method to Financial Manager,account.model_account_payment_method,account.group_account_manager,1,1,1,1 diff --git a/account_payment_base_oca/security/ir_rule.xml b/account_payment_base_oca/security/ir_rule.xml new file mode 100644 index 00000000000..e17454f8213 --- /dev/null +++ b/account_payment_base_oca/security/ir_rule.xml @@ -0,0 +1,13 @@ + + + + + Payment mode multi-company + + [('company_id', 'in', company_ids)] + + diff --git a/account_payment_base_oca/static/description/index.html b/account_payment_base_oca/static/description/index.html new file mode 100644 index 00000000000..7371def2f2a --- /dev/null +++ b/account_payment_base_oca/static/description/index.html @@ -0,0 +1,447 @@ + + + + + +Account Payment Base OCA + + + +
+

Account Payment Base OCA

+ + +

Beta License: AGPL-3 OCA/bank-payment Translate me on Weblate Try me on Runboat

+

This is the new base module for the OCA bank-payment project. This +module has been developped for Odoo 18 to adapt the OCA bank-payment +stack to the new native payment mode object of Odoo.

+

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

+
    +
  • Akretion
  • +
+
+
+

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:

+

alexis-via

+

This module is part of the OCA/bank-payment project on GitHub.

+

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

+
+
+
+ + diff --git a/account_payment_base_oca/views/account_move.xml b/account_payment_base_oca/views/account_move.xml new file mode 100644 index 00000000000..afeb9b4dcac --- /dev/null +++ b/account_payment_base_oca/views/account_move.xml @@ -0,0 +1,38 @@ + + + + + account.move + + + + + + + + bank_account_required and move_type in ('in_invoice', 'in_refund') + + + + + + account_payment_partner.view_invoice_tree + account.move + + + + + + + + + diff --git a/account_payment_base_oca/views/account_payment_method.xml b/account_payment_base_oca/views/account_payment_method.xml new file mode 100644 index 00000000000..61b1d520c55 --- /dev/null +++ b/account_payment_base_oca/views/account_payment_method.xml @@ -0,0 +1,92 @@ + + + + + + account_payment_method.form + account.payment.method + +
+ + + + + + + + + + +
+
+
+ + account_payment_method.list + account.payment.method + + + + + + + + + + account_payment_method.search + account.payment.method + + + + + + + + + + + + + + + Payment Methods + account.payment.method + list,form + + +
diff --git a/account_payment_base_oca/views/account_payment_method_line.xml b/account_payment_base_oca/views/account_payment_method_line.xml new file mode 100644 index 00000000000..a54ad3b23d0 --- /dev/null +++ b/account_payment_base_oca/views/account_payment_method_line.xml @@ -0,0 +1,159 @@ + + + + + + account.payment.method.line.form + account.payment.method.line + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + account.payment.method.line + + + + not active + 1 + + + + + + + + + + + 1 + + + + + + + + + + account.payment.method.line.search + account.payment.method.line + + + + + + + + + + + + + + + + + Payment Modes + account.payment.method.line + list,form + {'default_active': True, 'active_test': False} + + + +
From fd0aa9fa8fe3faebde5fbc4d0681ed8e12cc51a2 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Thu, 30 Jan 2025 13:18:18 +0100 Subject: [PATCH 2/4] [IMP] account_payment_base_oca: add selectable boolean field Switch back to active True by default --- account_payment_base_oca/models/__init__.py | 1 + .../models/account_payment_method_line.py | 14 ++--------- .../models/res_partner.py | 25 +++++++++++++++++++ .../views/account_move.xml | 16 ++++++++++++ .../views/account_payment_method_line.xml | 19 ++++++++------ 5 files changed, 56 insertions(+), 19 deletions(-) create mode 100644 account_payment_base_oca/models/res_partner.py diff --git a/account_payment_base_oca/models/__init__.py b/account_payment_base_oca/models/__init__.py index cbe36cdb3be..9a49b7e6cbc 100644 --- a/account_payment_base_oca/models/__init__.py +++ b/account_payment_base_oca/models/__init__.py @@ -1,5 +1,6 @@ from . import account_payment_method from . import account_payment_method_line from . import account_move +from . import res_partner from . import res_partner_bank from . import res_bank diff --git a/account_payment_base_oca/models/account_payment_method_line.py b/account_payment_base_oca/models/account_payment_method_line.py index 78631ea31b3..2e2be590ae6 100644 --- a/account_payment_base_oca/models/account_payment_method_line.py +++ b/account_payment_base_oca/models/account_payment_method_line.py @@ -69,18 +69,8 @@ class AccountPaymentMethodLine(models.Model): readonly=False, precompute=True, ) - # active is default=False on purpose ! - # When an account.payment.method with mode='multi' is created, Odoo - # generates an account.payment.method.line for each bank journal and there is no - # prepare method to inherit the values of the generated method lines. - # With default=False, Odoo will auto-generate inactive account.payment.method.line - # and we will only enable the one we want to use. If a payment order has a method - # line with bank_account_link='variable' and an alternative journal is selected, - # Odoo will not use the method line of the payment order to generate - # the account.payment but it will select the (inactive) method line - # linked to the chosen journal - # TODO default=False causes problems in tests of the account module - active = fields.Boolean(default=False) + active = fields.Boolean(default=True) + selectable = fields.Boolean(string="Selectable on Partners/Invoices") report_description = fields.Html(translate=True) show_bank_account = fields.Selection( selection=[ diff --git a/account_payment_base_oca/models/res_partner.py b/account_payment_base_oca/models/res_partner.py new file mode 100644 index 00000000000..ce764e24874 --- /dev/null +++ b/account_payment_base_oca/models/res_partner.py @@ -0,0 +1,25 @@ +# Copyright 2025 Akretion France (https://www.akretion.com/) +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + # add selectable=True in domain + property_outbound_payment_method_line_id = fields.Many2one( + domain=lambda self: [ + ("payment_type", "=", "outbound"), + ("company_id", "=", self.env.company.id), + ("selectable", "=", True), + ] + ) + property_inbound_payment_method_line_id = fields.Many2one( + domain=lambda self: [ + ("payment_type", "=", "inbound"), + ("company_id", "=", self.env.company.id), + ("selectable", "=", True), + ] + ) diff --git a/account_payment_base_oca/views/account_move.xml b/account_payment_base_oca/views/account_move.xml index afeb9b4dcac..930e9b3f4a6 100644 --- a/account_payment_base_oca/views/account_move.xml +++ b/account_payment_base_oca/views/account_move.xml @@ -21,6 +21,22 @@ name="required" >bank_account_required and move_type in ('in_invoice', 'in_refund') + + + [('payment_type', '=', 'inbound'), ('company_id', '=', company_id), ('selectable', '=', True)] + + + + [('payment_type', '=', 'outbound'), ('company_id', '=', company_id), ('selectable', '=', True)] + diff --git a/account_payment_base_oca/views/account_payment_method_line.xml b/account_payment_base_oca/views/account_payment_method_line.xml index a54ad3b23d0..017a0953f6e 100644 --- a/account_payment_base_oca/views/account_payment_method_line.xml +++ b/account_payment_base_oca/views/account_payment_method_line.xml @@ -25,8 +25,7 @@ - - + @@ -47,6 +46,7 @@ /> + @@ -99,8 +99,8 @@ 1 + - @@ -123,10 +123,16 @@ /> + + Payment Modes account.payment.method.line list,form - {'default_active': True, 'active_test': False} Date: Thu, 30 Jan 2025 17:40:23 +0100 Subject: [PATCH 3/4] [UDP] account_payment_base_oca: Replace alternative_journal_ids by variable_journal_ids --- .../models/account_payment_method_line.py | 51 ++++++++----------- .../views/account_payment_method_line.xml | 7 ++- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/account_payment_base_oca/models/account_payment_method_line.py b/account_payment_base_oca/models/account_payment_method_line.py index 2e2be590ae6..7266d74d32a 100644 --- a/account_payment_base_oca/models/account_payment_method_line.py +++ b/account_payment_base_oca/models/account_payment_method_line.py @@ -35,8 +35,8 @@ class AccountPaymentMethodLine(models.Model): # company_id is a related of journal_id.company_id # When bank_account_link = 'fixed' => we use journal_id # When bank_account_link = 'variable': - # - journal_id is considered as the default journal - # - alternative_journal_ids are additional journals that can be used + # - journal_id is empty + # - variable_journal_ids hsa the list of allowed journals on payment order filter_journal_ids = fields.Many2many( "account.journal", compute="_compute_filter_journal_ids" ) @@ -56,15 +56,15 @@ class AccountPaymentMethodLine(models.Model): ) # I need to explicitly define the table name # because I have 2 M2M fields pointing to account.journal - alternative_journal_ids = fields.Many2many( + variable_journal_ids = fields.Many2many( comodel_name="account.journal", - relation="account_payment_method_line_alternative_journal_rel", + relation="account_payment_method_line_variable_journal_rel", column1="method_line_id", column2="journal_id", - string="Alternative Bank Journals", - domain="[('id', '!=', journal_id), ('id', 'in', filter_journal_ids)]", + string="Allowed Bank Journals", + domain="[('id', 'in', filter_journal_ids)]", check_company=True, - compute="_compute_alternative_journal_ids", + compute="_compute_variable_journal_ids", store=True, readonly=False, precompute=True, @@ -109,32 +109,25 @@ class AccountPaymentMethodLine(models.Model): @api.constrains( "bank_account_link", "journal_id", - "alternative_journal_ids", + "variable_journal_ids", "payment_method_id", ) def _check_payment_method_line(self): for line in self: - if not line.journal_id: + # I cannot check line.journal_id.bank_account_id when + # line.bank_account_link == "fixed" because method lines are + # auto-created on bank journal creation and the bank account + # but not be configured yet. + if line.bank_account_link == "fixed" and not line.journal_id: raise ValidationError( _( - "On %(name)s, the bank journal is not set.", + "On %(name)s, the journal is not set.", name=line.display_name, ) ) if line.payment_method_id.bank_account_required: - # if line.journal_id and not line.journal_id.bank_account_id: - # raise ValidationError( - # _( - # "On %(name)s, the Payment Method %(method)s is " - # "configured with Bank Account Required but journal " - # "%(journal)s is not linked to a bank account.", - # name=line.display_name, - # method=line.payment_method_id.display_name, - # journal=line.journal_id.display_name, - # ) - # ) if line.bank_account_link == "variable": - for journal in line.alternative_journal_ids: + for journal in line.variable_journal_ids: if not journal.bank_account_id: raise ValidationError( _( @@ -147,17 +140,11 @@ def _check_payment_method_line(self): ) ) - @api.depends("journal_id", "bank_account_link") - def _compute_alternative_journal_ids(self): + @api.depends("bank_account_link") + def _compute_variable_journal_ids(self): for line in self: if line.bank_account_link == "fixed": - line.alternative_journal_ids = [Command.clear()] - elif ( - line.bank_account_link == "variable" - and line.journal_id - and line.journal_id.id in line.alternative_journal_ids.ids - ): - line.alternative_journal_ids = [Command.unlink(line.journal_id.id)] + line.variable_journal_ids = [Command.clear()] @api.depends("journal_id") def _compute_company_id(self): @@ -180,6 +167,8 @@ def _compute_filter_journal_ids(self): domain.append(("type", "in", journal_types)) else: domain.append(("type", "in", ("bank", "cash", "credit"))) + if line.payment_method_id.bank_account_required: + domain.append(("bank_account_id", "!=", False)) else: domain.append(("type", "in", ("bank", "cash", "credit"))) line.filter_journal_ids = self.env["account.journal"].search(domain).ids diff --git a/account_payment_base_oca/views/account_payment_method_line.xml b/account_payment_base_oca/views/account_payment_method_line.xml index 017a0953f6e..09faff239a6 100644 --- a/account_payment_base_oca/views/account_payment_method_line.xml +++ b/account_payment_base_oca/views/account_payment_method_line.xml @@ -37,9 +37,12 @@ - + Date: Thu, 30 Jan 2025 18:41:55 +0100 Subject: [PATCH 4/4] [DON'T MERGE] add test-requirements.txt --- account_payment_base_oca/test-requirements.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 account_payment_base_oca/test-requirements.txt diff --git a/account_payment_base_oca/test-requirements.txt b/account_payment_base_oca/test-requirements.txt new file mode 100644 index 00000000000..203d6d9e829 --- /dev/null +++ b/account_payment_base_oca/test-requirements.txt @@ -0,0 +1,5 @@ +odoo-addon-account_payment_order @ git+https://github.com/OCA/bank-payment.git@refs/pull/1403/head#subdirectory=account_payment_order +odoo-addon-account_banking_pain_base @ git+https://github.com/OCA/bank-payment.git@refs/pull/1404/head#subdirectory=account_banking_pain_base +odoo-addon-account_banking_sepa_credit_transfer @ git+https://github.com/OCA/bank-payment.git@refs/pull/1405/head#subdirectory=account_banking_sepa_credit_transfer +odoo-addon-account_banking_sepa_direct_debit @ git+https://github.com/OCA/bank-payment.git@refs/pull/1406/head#subdirectory=account_banking_sepa_direct_debit +odoo-addon-account_banking_mandate @ git+https://github.com/OCA/bank-payment.git@refs/pull/1407/head#subdirectory=account_banking_mandate