From cbe1eed5ac2a7987a3f23db1d975b6e13abab32c Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 9 Jun 2021 00:39:32 +0200 Subject: [PATCH] Improve computation of sepa on account.payment.order: check IBAN is in SEPA zone Update move line generation to get transfer account from bank journal Update payment mode configuration accordingly (3 fields removed) Several improvements in payment order tree and form view --- .../models/account_payment_order.py | 52 ++++++++++++ .../views/account_payment_line.xml | 14 ++++ .../views/account_payment_order.xml | 16 +++- .../views/bank_payment_line_view.xml | 11 +++ .../models/account_payment_line.py | 2 +- .../models/account_payment_mode.py | 80 ++----------------- .../models/account_payment_order.py | 66 ++++++++------- .../views/account_invoice_view.xml | 21 ++++- .../views/account_payment_line.xml | 8 +- .../views/account_payment_mode.xml | 15 ---- .../views/account_payment_order.xml | 63 +++++++++------ .../views/bank_payment_line.xml | 4 +- 12 files changed, 203 insertions(+), 149 deletions(-) diff --git a/account_banking_pain_base/models/account_payment_order.py b/account_banking_pain_base/models/account_payment_order.py index 9e35926e6..4d5da9800 100644 --- a/account_banking_pain_base/models/account_payment_order.py +++ b/account_banking_pain_base/models/account_payment_order.py @@ -58,17 +58,66 @@ class AccountPaymentOrder(models.Model): "transfer of the SEPA XML file.", ) + @api.model + def _sepa_iban_prefix_list(self): + # List of IBAN prefixes (not country codes !) + # Source: https://www.europeanpaymentscouncil.eu/sites/default/files/kb/file/2020-10/EPC409-09%20EPC%20List%20of%20SEPA%20Scheme%20Countries%20v3.0_1.pdf # noqa: B950 + # Some countries use IBAN but are not part of the SEPA zone + # example: Turkey, Madagascar, Tunisia, etc. + return [ + "BE", + "BG", + "ES", + "HR", + "CY", + "CZ", + "DK", + "EE", + "FI", + "FR", + "DE", + "GI", + "GR", + "GB", + "HU", + "IS", + "IE", + "IT", + "LV", + "LI", + "LT", + "LU", + "PT", + "MT", + "MC", + "NL", + "NO", + "PL", + "RO", + "SM", + "SK", + "SI", + "SE", + "CH", + "VA", + ] + @api.depends( "company_partner_bank_id.acc_type", + "company_partner_bank_id.sanitized_acc_number", "payment_line_ids.currency_id", "payment_line_ids.partner_bank_id.acc_type", + "payment_line_ids.partner_bank_id.sanitized_acc_number", ) def _compute_sepa(self): eur = self.env.ref("base.EUR") + sepa_list = self._sepa_iban_prefix_list() for order in self: sepa = True if order.company_partner_bank_id.acc_type != "iban": sepa = False + if order.company_partner_bank_id and order.company_partner_bank_id.sanitized_acc_number[:2] not in sepa_list: + sepa = False for pline in order.payment_line_ids: if pline.currency_id != eur: sepa = False @@ -76,6 +125,9 @@ class AccountPaymentOrder(models.Model): if pline.partner_bank_id.acc_type != "iban": sepa = False break + if pline.partner_bank_id and pline.partner_bank_id.sanitized_acc_number[:2] not in sepa_list: + sepa = False + break sepa = order.compute_sepa_final_hook(sepa) self.sepa = sepa diff --git a/account_banking_pain_base/views/account_payment_line.xml b/account_banking_pain_base/views/account_payment_line.xml index e71be074a..4e3eecce7 100644 --- a/account_banking_pain_base/views/account_payment_line.xml +++ b/account_banking_pain_base/views/account_payment_line.xml @@ -20,4 +20,18 @@ + + pain.base.account.payment.tree + account.payment.line + + + + + + + + diff --git a/account_banking_pain_base/views/account_payment_order.xml b/account_banking_pain_base/views/account_payment_order.xml index 8188bf27d..b06fdcacb 100644 --- a/account_banking_pain_base/views/account_payment_order.xml +++ b/account_banking_pain_base/views/account_payment_order.xml @@ -21,5 +21,19 @@ /> - + + + pain.base.account.payment.order.tree + account.payment.order + + + + + + + + diff --git a/account_banking_pain_base/views/bank_payment_line_view.xml b/account_banking_pain_base/views/bank_payment_line_view.xml index 1eb1e72d5..247de1783 100644 --- a/account_banking_pain_base/views/bank_payment_line_view.xml +++ b/account_banking_pain_base/views/bank_payment_line_view.xml @@ -17,4 +17,15 @@ + + pain.base.bank.payment.line.tree + bank.payment.line + + + + + + + + diff --git a/account_payment_order/models/account_payment_line.py b/account_payment_order/models/account_payment_line.py index 4b54700a5..ede7c7679 100644 --- a/account_payment_order/models/account_payment_line.py +++ b/account_payment_order/models/account_payment_line.py @@ -68,7 +68,7 @@ class AccountPaymentLine(models.Model): ) date = fields.Date(string="Payment Date") communication = fields.Char( - required=True, help="Label of the payment that will be seen by the destinee" + required=False, help="Label of the payment that will be seen by the destinee" ) communication_type = fields.Selection( selection=[("normal", "Free")], required=True, default="normal" diff --git a/account_payment_order/models/account_payment_mode.py b/account_payment_order/models/account_payment_mode.py index e99c062df..cc134930e 100644 --- a/account_payment_order/models/account_payment_mode.py +++ b/account_payment_order/models/account_payment_mode.py @@ -75,27 +75,6 @@ class AccountPaymentMode(models.Model): generate_move = fields.Boolean( string="Generate Accounting Entries On File Upload", default=True ) - offsetting_account = fields.Selection( - selection=[ - ("bank_account", "Bank Account"), - ("transfer_account", "Transfer Account"), - ], - default="bank_account", - ) - transfer_account_id = fields.Many2one( - comodel_name="account.account", - domain=[("reconcile", "=", True)], - help="Pay off lines in 'file uploaded' payment orders with a move on " - "this account. You can only select accounts " - "that are marked for reconciliation", - check_company=True, - ) - transfer_journal_id = fields.Many2one( - comodel_name="account.journal", - help="Journal to write payment entries when confirming " - "payment/debit orders of this mode", - check_company=True, - ) move_option = fields.Selection( selection=[ ("date", "One move per payment date"), @@ -105,50 +84,17 @@ class AccountPaymentMode(models.Model): ) post_move = fields.Boolean(default=True) - @api.constrains( - "generate_move", - "offsetting_account", - "transfer_account_id", - "transfer_journal_id", - "move_option", - ) + @api.constrains("generate_move", "move_option") def transfer_move_constrains(self): for mode in self: - if mode.generate_move: - if not mode.offsetting_account: - raise ValidationError( - _( - "On the payment mode '%s', you must select an " - "option for the 'Offsetting Account' parameter" - ) - % mode.name - ) - elif mode.offsetting_account == "transfer_account": - if not mode.transfer_account_id: - raise ValidationError( - _( - "On the payment mode '%s', you must " - "select a value for the 'Transfer Account'." - ) - % mode.name - ) - if not mode.transfer_journal_id: - raise ValidationError( - _( - "On the payment mode '%s', you must " - "select a value for the 'Transfer Journal'." - ) - % mode.name - ) - if not mode.move_option: - raise ValidationError( - _( - "On the payment mode '%s', you must " - "choose an option for the 'Move Option' " - "parameter." - ) - % mode.name + if mode.generate_move and not mode.move_option: + raise ValidationError( + _( + "On the payment mode '%s', you must " + "choose an option for the 'Move Option' parameter." ) + % mode.name + ) @api.onchange("payment_method_id") def payment_method_id_change(self): @@ -175,16 +121,6 @@ class AccountPaymentMode(models.Model): def generate_move_change(self): if self.generate_move: # default values - self.offsetting_account = "bank_account" self.move_option = "date" else: - self.offsetting_account = False - self.transfer_account_id = False - self.transfer_journal_id = False self.move_option = False - - @api.onchange("offsetting_account") - def offsetting_account_change(self): - if self.offsetting_account == "bank_account": - self.transfer_account_id = False - self.transfer_journal_id = False diff --git a/account_payment_order/models/account_payment_order.py b/account_payment_order/models/account_payment_order.py index a9a54d368..e9a400f7e 100644 --- a/account_payment_order/models/account_payment_order.py +++ b/account_payment_order/models/account_payment_order.py @@ -118,14 +118,14 @@ class AccountPaymentOrder(models.Model): payment_line_ids = fields.One2many( comodel_name="account.payment.line", inverse_name="order_id", - string="Transaction Lines", + string="Transactions", readonly=True, states={"draft": [("readonly", False)]}, ) bank_line_ids = fields.One2many( comodel_name="bank.payment.line", inverse_name="order_id", - string="Bank Payment Lines", + string="Bank Transactions", readonly=True, help="The bank payment lines are used to generate the payment file. " "They are automatically created from transaction lines upon " @@ -138,7 +138,7 @@ class AccountPaymentOrder(models.Model): compute="_compute_total", store=True, currency_field="company_currency_id" ) bank_line_count = fields.Integer( - compute="_compute_bank_line_count", string="Number of Bank Lines" + compute="_compute_bank_line_count", string="Number of Bank Transactions" ) move_ids = fields.One2many( comodel_name="account.move", @@ -146,6 +146,9 @@ class AccountPaymentOrder(models.Model): string="Journal Entries", readonly=True, ) + move_count = fields.Integer( + compute="_compute_move_count", string="Number of Journal Entries" + ) description = fields.Char() @api.depends("payment_mode_id") @@ -210,6 +213,19 @@ class AccountPaymentOrder(models.Model): for order in self: order.bank_line_count = len(order.bank_line_ids) + @api.depends("move_ids") + def _compute_move_count(self): + rg_res = self.env["account.move"].read_group( + [("payment_order_id", "in", self.ids)], + ["payment_order_id"], + ["payment_order_id"], + ) + mapped_data = { + x["payment_order_id"][0]: x["payment_order_id_count"] for x in rg_res + } + for order in self: + order.move_count = mapped_data.get(order.id, 0) + @api.model def create(self, vals): if vals.get("name", "New") == "New": @@ -420,27 +436,19 @@ class AccountPaymentOrder(models.Model): return True def _prepare_move(self, bank_lines=None): - move_date = False if self.payment_type == "outbound": ref = _("Payment order %s") % self.name else: ref = _("Debit order %s") % self.name if bank_lines and len(bank_lines) == 1: ref += " - " + bank_lines.name - if self.payment_mode_id.offsetting_account == "bank_account": - journal_id = self.journal_id.id - if bank_lines: - move_date = bank_lines[0].date - elif self.payment_mode_id.offsetting_account == "transfer_account": - journal_id = self.payment_mode_id.transfer_journal_id.id vals = { - "journal_id": journal_id, + "date": bank_lines[0].date, + "journal_id": self.journal_id.id, "ref": ref, "payment_order_id": self.id, "line_ids": [], } - if move_date: - vals.update({"date": move_date}) total_company_currency = total_payment_currency = 0 for bline in bank_lines: total_company_currency += bline.amount_company_currency @@ -458,18 +466,10 @@ class AccountPaymentOrder(models.Model): ): vals = {} if self.payment_type == "outbound": - name = _("Payment order %s") % self.name + account_id = self.journal_id.payment_credit_account_id.id else: - name = _("Debit order %s") % self.name - if self.payment_mode_id.offsetting_account == "bank_account": - vals.update({"date": bank_lines[0].date}) - else: - vals.update({"date_maturity": bank_lines[0].date}) + account_id = self.journal_id.payment_debit_account_id.id - if self.payment_mode_id.offsetting_account == "bank_account": - account_id = self.journal_id.default_account_id.id - elif self.payment_mode_id.offsetting_account == "transfer_account": - account_id = self.payment_mode_id.transfer_account_id.id partner_id = False for index, bank_line in enumerate(bank_lines): if index == 0: @@ -480,7 +480,6 @@ class AccountPaymentOrder(models.Model): break vals.update( { - "name": name, "partner_id": partner_id, "account_id": account_id, "credit": ( @@ -586,10 +585,19 @@ class AccountPaymentOrder(models.Model): def action_move_journal_line(self): self.ensure_one() - action = self.env.ref("account.action_move_journal_line") - action_dict = action.read()[0] - action_dict["domain"] = [("id", "in", self.move_ids.ids)] + action = self.env.ref("account.action_move_journal_line").sudo().read()[0] + if self.move_count == 1: + action.update( + { + "view_mode": "form,tree,kanban", + "views": False, + "view_id": False, + "res_id": self.move_ids[0].id, + } + ) + else: + action["domain"] = [("id", "in", self.move_ids.ids)] ctx = self.env.context.copy() ctx.update({"search_default_misc_filter": 0}) - action_dict["context"] = ctx - return action_dict + action["context"] = ctx + return action diff --git a/account_payment_order/views/account_invoice_view.xml b/account_payment_order/views/account_invoice_view.xml index 62d7331e5..843663693 100644 --- a/account_payment_order/views/account_invoice_view.xml +++ b/account_payment_order/views/account_invoice_view.xml @@ -42,7 +42,7 @@ - + - + new + + + account_payment_order.view_invoice_tree + account.move + + + + + diff --git a/account_payment_order/views/account_payment_line.xml b/account_payment_order/views/account_payment_line.xml index c486859c0..6f774cd38 100644 --- a/account_payment_order/views/account_payment_line.xml +++ b/account_payment_order/views/account_payment_line.xml @@ -59,12 +59,12 @@ - - + + - - + + - - - - - +
-