From e3d9930b04495257adfa26a29f5ef04dc47be470 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sun, 6 Nov 2022 09:11:45 +0100 Subject: [PATCH 1/7] [REF+IMP] account_payment_order: Use native payments The previous approach creates manually the journal entries and does all the hard work, plus not being 100% compatible with the bank statement reconciliation widget (requiring a patch on OCB to see blue lines). That decision made sense on the moment it was done (v9), where the native payment model (account.payment) was very limited, and wasn't able to store all the needed information for the bank transaction. Now that the limitations are gone, we can get rid off this extra model, and generate instead `account.payment` records, using both the native model + methods to perform the same operations. This serves also to workaround the problem found in #966. All the code, views and tests of main module have been adapted to this new approach in this commit. Later commits will adapt the rest of the modules of the suite, and add migration scripts to transit from the previous approach to this new one. TT39832 --- account_payment_order/__manifest__.py | 3 +- account_payment_order/data/payment_seq.xml | 12 +- account_payment_order/models/__init__.py | 1 - .../models/account_move_line.py | 6 - .../models/account_payment.py | 6 +- .../models/account_payment_line.py | 69 ++++- .../models/account_payment_mode.py | 34 +-- .../models/account_payment_order.py | 242 +++--------------- .../models/bank_payment_line.py | 204 --------------- .../security/ir.model.access.csv | 2 +- .../security/payment_security.xml | 7 - .../tests/test_payment_mode.py | 8 - .../tests/test_payment_order_inbound.py | 10 +- .../tests/test_payment_order_outbound.py | 26 +- .../views/account_move_line.xml | 1 - .../views/account_payment_line.xml | 2 +- .../views/account_payment_mode.xml | 15 -- .../views/account_payment_order.xml | 12 +- .../views/bank_payment_line.xml | 106 -------- 19 files changed, 127 insertions(+), 639 deletions(-) delete mode 100644 account_payment_order/models/bank_payment_line.py delete mode 100644 account_payment_order/views/bank_payment_line.xml diff --git a/account_payment_order/__manifest__.py b/account_payment_order/__manifest__.py index b8d4b83c8..55ad33d95 100644 --- a/account_payment_order/__manifest__.py +++ b/account_payment_order/__manifest__.py @@ -1,9 +1,9 @@ # © 2009 EduSense BV () # © 2011-2013 Therp BV () # © 2013-2014 ACSONE SA (). -# © 2014-2016 Tecnativa - Pedro M. Baeza # © 2016 Akretion (). # © 2016 Aselcis (). +# © 2014-2023 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). @@ -30,7 +30,6 @@ "views/account_payment_mode.xml", "views/account_payment_order.xml", "views/account_payment_line.xml", - "views/bank_payment_line.xml", "views/account_move_line.xml", "views/ir_attachment.xml", "views/account_invoice_view.xml", diff --git a/account_payment_order/data/payment_seq.xml b/account_payment_order/data/payment_seq.xml index 0d80d10ff..7b288105d 100644 --- a/account_payment_order/data/payment_seq.xml +++ b/account_payment_order/data/payment_seq.xml @@ -1,18 +1,10 @@ - - Bank Payment Line - bank.payment.line - L - 5 - - Payment Line account.payment.line diff --git a/account_payment_order/models/__init__.py b/account_payment_order/models/__init__.py index e5537935e..e686e3db3 100644 --- a/account_payment_order/models/__init__.py +++ b/account_payment_order/models/__init__.py @@ -1,7 +1,6 @@ from . import account_payment_mode from . import account_payment_order from . import account_payment_line -from . import bank_payment_line from . import account_move from . import account_move_line from . import res_bank diff --git a/account_payment_order/models/account_move_line.py b/account_payment_order/models/account_move_line.py index 0e2a6ff6f..ec0759fdf 100644 --- a/account_payment_order/models/account_move_line.py +++ b/account_payment_order/models/account_move_line.py @@ -18,12 +18,6 @@ class AccountMoveLine(models.Model): help="Bank account on which we should pay the supplier", check_company=True, ) - bank_payment_line_id = fields.Many2one( - comodel_name="bank.payment.line", - readonly=True, - index=True, - check_company=True, - ) payment_line_ids = fields.One2many( comodel_name="account.payment.line", inverse_name="move_line_id", diff --git a/account_payment_order/models/account_payment.py b/account_payment_order/models/account_payment.py index e01f83da8..b10bfda63 100644 --- a/account_payment_order/models/account_payment.py +++ b/account_payment_order/models/account_payment.py @@ -1,12 +1,16 @@ # Copyright 2019 ACSONE SA/NV +# Copyright 2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, models +from odoo import api, fields, models class AccountPayment(models.Model): _inherit = "account.payment" + payment_order_id = fields.Many2one(comodel_name="account.payment.order") + payment_line_ids = fields.Many2many(comodel_name="account.payment.line") + def _get_default_journal(self): res = super()._get_default_journal() return res.filtered(lambda journal: not journal.inbound_payment_order_only) diff --git a/account_payment_order/models/account_payment_line.py b/account_payment_order/models/account_payment_line.py index 4eddb58de..44c61ea03 100644 --- a/account_payment_order/models/account_payment_line.py +++ b/account_payment_order/models/account_payment_line.py @@ -77,19 +77,17 @@ class AccountPaymentLine(models.Model): communication_type = fields.Selection( selection=[("normal", "Free")], required=True, default="normal" ) - bank_line_id = fields.Many2one( - comodel_name="bank.payment.line", - string="Bank Payment Line", + payment_ids = fields.Many2many( + comodel_name="account.payment", + string="Payment transaction", readonly=True, - index=True, - check_company=True, ) _sql_constraints = [ ( "name_company_unique", "unique(name, company_id)", - "A payment line already exists with this reference " "in the same company!", + "A payment line already exists with this reference in the same company!", ) ] @@ -114,11 +112,21 @@ class AccountPaymentLine(models.Model): else: line.amount_company_currency = 0 + @api.model + def _get_payment_line_grouping_fields(self): + """This list of fields is used o compute the grouping hashcode.""" + return [ + "currency_id", + "partner_id", + "partner_bank_id", + "date", + "communication_type", + ] + def payment_line_hashcode(self): self.ensure_one() - bplo = self.env["bank.payment.line"] values = [] - for field in bplo.same_fields_payment_line_and_bank_payment_line(): + for field in self._get_payment_line_grouping_fields(): values.append(str(self[field])) # Don't group the payment lines that are attached to the same supplier # but to move lines with different accounts (very unlikely), @@ -128,8 +136,7 @@ class AccountPaymentLine(models.Model): # otherwise it would break the structured communication system ! if self.communication_type != "normal": values.append(str(self.id)) - hashcode = "-".join(values) - return hashcode + return "-".join(values) @api.onchange("partner_id") def partner_id_change(self): @@ -168,3 +175,45 @@ class AccountPaymentLine(models.Model): ) if not self.communication: raise UserError(_("Communication is empty on payment line %s.") % self.name) + + def _prepare_account_payment_vals(self): + """Prepare the dictionary to create an account payment record from a set of + payment lines. + """ + journal = self.order_id.journal_id + vals = { + "payment_type": self.order_id.payment_type, + "partner_id": self.partner_id.id, + "destination_account_id": self.move_line_id.account_id.id, + "company_id": self.order_id.company_id.id, + "amount": sum(self.mapped("amount_currency")), + "date": self[:1].date, + "currency_id": self.currency_id.id, + "ref": self.order_id.name, + "payment_reference": "-".join([line.communication for line in self]), + "journal_id": journal.id, + "partner_bank_id": self.partner_bank_id.id, + "payment_order_id": self.order_id.id, + "payment_method_id": self.order_id.payment_mode_id.payment_method_id.id, + "payment_line_ids": [(6, 0, self.ids)], + } + # Determine partner_type + move_type = self[:1].move_line_id.move_id.move_type + if move_type in {"out_invoice", "out_refund"}: + vals["partner_type"] = "customer" + elif move_type in {"in_invoice", "in_refund"}: + vals["partner_type"] = "supplier" + else: + p_type = "customer" if vals["payment_type"] == "inbound" else "supplier" + vals["partner_type"] = p_type + # Fill destination account if manual payment line with no linked journal item + if not vals["destination_account_id"]: + if vals["partner_type"] == "customer": + vals[ + "destination_account_id" + ] = self.partner_id.property_account_receivable_id.id + else: + vals[ + "destination_account_id" + ] = self.partner_id.property_account_payable_id.id + return vals diff --git a/account_payment_order/models/account_payment_mode.py b/account_payment_order/models/account_payment_mode.py index cc134930e..d1685e45e 100644 --- a/account_payment_order/models/account_payment_mode.py +++ b/account_payment_order/models/account_payment_mode.py @@ -4,8 +4,7 @@ # © 2016 Akretion (Alexis de Lattre ) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import _, api, fields, models -from odoo.exceptions import ValidationError +from odoo import api, fields, models class AccountPaymentMode(models.Model): @@ -72,29 +71,6 @@ class AccountPaymentMode(models.Model): "(other modules can set additional fields to restrict the " "grouping.)", ) - generate_move = fields.Boolean( - string="Generate Accounting Entries On File Upload", default=True - ) - move_option = fields.Selection( - selection=[ - ("date", "One move per payment date"), - ("line", "One move per payment line"), - ], - default="date", - ) - post_move = fields.Boolean(default=True) - - @api.constrains("generate_move", "move_option") - def transfer_move_constrains(self): - for mode in self: - 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): @@ -116,11 +92,3 @@ class AccountPaymentMode(models.Model): ] ).ids self.default_journal_ids = [(6, 0, aj_ids)] - - @api.onchange("generate_move") - def generate_move_change(self): - if self.generate_move: - # default values - self.move_option = "date" - else: - self.move_option = False diff --git a/account_payment_order/models/account_payment_order.py b/account_payment_order/models/account_payment_order.py index 33e3dad01..7bd0fe4f8 100644 --- a/account_payment_order/models/account_payment_order.py +++ b/account_payment_order/models/account_payment_order.py @@ -1,7 +1,7 @@ # © 2009 EduSense BV () # © 2011-2013 Therp BV () -# © 2016 Serv. Tecnol. Avanzados - Pedro M. Baeza # © 2016 Akretion (Alexis de Lattre - alexis.delattre@akretion.com) +# Copyright 2016-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). import base64 @@ -120,24 +120,19 @@ class AccountPaymentOrder(models.Model): readonly=True, states={"draft": [("readonly", False)]}, ) - bank_line_ids = fields.One2many( - comodel_name="bank.payment.line", - inverse_name="order_id", - string="Bank Transactions", + payment_ids = fields.One2many( + comodel_name="account.payment", + inverse_name="payment_order_id", + string="Payment Transactions", readonly=True, - help="The bank payment lines are used to generate the payment file. " - "They are automatically created from transaction lines upon " - "confirmation of the payment order: one bank payment line can " - "group several transaction lines if the option " - "'Group Transactions in Payment Orders' is active on the payment " - "mode.", + ) + payment_count = fields.Integer( + compute="_compute_payment_count", + string="Number of Payment Transactions", ) total_company_currency = fields.Monetary( compute="_compute_total", store=True, currency_field="company_currency_id" ) - bank_line_count = fields.Integer( - compute="_compute_bank_line_count", string="Number of Bank Transactions" - ) move_ids = fields.One2many( comodel_name="account.move", inverse_name="payment_order_id", @@ -208,10 +203,10 @@ class AccountPaymentOrder(models.Model): rec.mapped("payment_line_ids.amount_company_currency") or [0.0] ) - @api.depends("bank_line_ids") - def _compute_bank_line_count(self): + @api.depends("payment_ids") + def _compute_payment_count(self): for order in self: - order.bank_line_count = len(order.bank_line_ids) + order.payment_count = len(order.payment_ids) @api.depends("move_ids") def _compute_move_count(self): @@ -251,11 +246,6 @@ class AccountPaymentOrder(models.Model): self.date_prefered = self.payment_mode_id.default_date_prefered def action_uploaded_cancel(self): - for move in self.move_ids: - move.button_cancel() - for move_line in move.line_ids: - move_line.remove_move_reconcile() - move.with_context(force_delete=True).unlink() self.action_cancel() return True @@ -264,27 +254,19 @@ class AccountPaymentOrder(models.Model): return True def action_cancel(self): - for order in self: - order.write({"state": "cancel"}) - order.bank_line_ids.unlink() + # Unreconcile and cancel payments + self.payment_ids.action_draft() + self.payment_ids.action_cancel() + self.write({"state": "cancel"}) return True - @api.model - def _prepare_bank_payment_line(self, paylines): - return { - "order_id": paylines[0].order_id.id, - "payment_line_ids": [(6, 0, paylines.ids)], - "communication": "-".join([line.communication for line in paylines]), - } - def draft2open(self): """ Called when you click on the 'Confirm' button Set the 'date' on payment line depending on the 'date_prefered' setting of the payment.order - Re-generate the bank payment lines + Re-generate the account payments. """ - bplo = self.env["bank.payment.line"] today = fields.Date.context_today(self) for order in self: if not order.journal_id: @@ -303,9 +285,11 @@ class AccountPaymentOrder(models.Model): raise UserError( _("There are no transactions on payment order %s.") % order.name ) - # Delete existing bank payment lines - order.bank_line_ids.unlink() - # Create the bank payment lines from the payment lines + # Unreconcile, cancel and delete existing account payments + order.payment_ids.action_draft() + order.payment_ids.action_cancel() + order.payment_ids.unlink() + # Prepare account payments from the payment lines group_paylines = {} # key = hashcode for payline in order.payment_line_ids: payline.draft2open_payment_line_check() @@ -360,7 +344,8 @@ class AccountPaymentOrder(models.Model): "total": payline.amount_currency, } order.recompute() - # Create bank payment lines + # Create account payments + payment_vals = [] for paydict in list(group_paylines.values()): # Block if a bank payment line is <= 0 if paydict["total"] <= 0: @@ -372,8 +357,8 @@ class AccountPaymentOrder(models.Model): amount=paydict["total"], ) ) - vals = self._prepare_bank_payment_line(paydict["paylines"]) - bplo.create(vals) + payment_vals.append(paydict["paylines"]._prepare_account_payment_vals()) + self.env["account.payment"].create(payment_vals) self.write({"state": "open"}) return True @@ -425,177 +410,20 @@ class AccountPaymentOrder(models.Model): return action def generated2uploaded(self): - for order in self: - if order.payment_mode_id.generate_move: - order.generate_move() + self.payment_ids.action_post() + # Perform the reconciliation of payments and source journal items + for payment in self.payment_ids: + ( + payment.payment_line_ids.move_line_id + + payment.move_id.line_ids.filtered( + lambda x: x.account_id == payment.destination_account_id + ) + ).reconcile() self.write( {"state": "uploaded", "date_uploaded": fields.Date.context_today(self)} ) return True - def _prepare_move(self, bank_lines=None): - 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 - vals = { - "date": bank_lines[0].date, - "journal_id": self.journal_id.id, - "ref": ref, - "payment_order_id": self.id, - "line_ids": [], - } - total_company_currency = total_payment_currency = 0 - for bline in bank_lines: - total_company_currency += bline.amount_company_currency - total_payment_currency += bline.amount_currency - partner_ml_vals = self._prepare_move_line_partner_account(bline) - vals["line_ids"].append((0, 0, partner_ml_vals)) - trf_ml_vals = self._prepare_move_line_offsetting_account( - total_company_currency, total_payment_currency, bank_lines - ) - vals["line_ids"].append((0, 0, trf_ml_vals)) - return vals - - def _prepare_move_line_offsetting_account( - self, amount_company_currency, amount_payment_currency, bank_lines - ): - vals = {} - payment_method = self.payment_mode_id.payment_method_id - account_id = False - if self.payment_type == "inbound": - name = _("Debit order %s") % self.name - account_id = ( - self.journal_id.inbound_payment_method_line_ids.filtered( - lambda x: x.payment_method_id == payment_method - ).payment_account_id.id - or self.journal_id.company_id.account_journal_payment_debit_account_id.id - ) - elif self.payment_type == "outbound": - name = _("Payment order %s") % self.name - account_id = ( - self.journal_id.outbound_payment_method_line_ids.filtered( - lambda x: x.payment_method_id == payment_method - ).payment_account_id.id - or self.journal_id.company_id.account_journal_payment_credit_account_id.id - ) - - partner_id = False - for index, bank_line in enumerate(bank_lines): - if index == 0: - partner_id = bank_line.payment_line_ids[0].partner_id.id - elif bank_line.payment_line_ids[0].partner_id.id != partner_id: - # we have different partners in the grouped move - partner_id = False - break - vals.update( - { - "name": name, - "partner_id": partner_id, - "account_id": account_id, - "credit": ( - self.payment_type == "outbound" and amount_company_currency or 0.0 - ), - "debit": ( - self.payment_type == "inbound" and amount_company_currency or 0.0 - ), - } - ) - if bank_lines[0].currency_id != bank_lines[0].company_currency_id: - sign = self.payment_type == "outbound" and -1 or 1 - vals.update( - { - "currency_id": bank_lines[0].currency_id.id, - "amount_currency": amount_payment_currency * sign, - } - ) - return vals - - def _prepare_move_line_partner_account(self, bank_line): - if bank_line.payment_line_ids[0].move_line_id: - account_id = bank_line.payment_line_ids[0].move_line_id.account_id.id - else: - if self.payment_type == "inbound": - account_id = bank_line.partner_id.property_account_receivable_id.id - else: - account_id = bank_line.partner_id.property_account_payable_id.id - if self.payment_type == "outbound": - name = _("Payment bank line %s") % bank_line.name - else: - name = _("Debit bank line %s") % bank_line.name - vals = { - "name": name, - "bank_payment_line_id": bank_line.id, - "partner_id": bank_line.partner_id.id, - "account_id": account_id, - "credit": ( - self.payment_type == "inbound" - and bank_line.amount_company_currency - or 0.0 - ), - "debit": ( - self.payment_type == "outbound" - and bank_line.amount_company_currency - or 0.0 - ), - } - - if bank_line.currency_id != bank_line.company_currency_id: - sign = self.payment_type == "inbound" and -1 or 1 - vals.update( - { - "currency_id": bank_line.currency_id.id, - "amount_currency": bank_line.amount_currency * sign, - } - ) - return vals - - def _create_reconcile_move(self, hashcode, blines): - self.ensure_one() - post_move = self.payment_mode_id.post_move - am_obj = self.env["account.move"] - mvals = self._prepare_move(blines) - move = am_obj.create(mvals) - if post_move: - move.action_post() - blines.reconcile_payment_lines() - - def _prepare_trf_moves(self): - """ - prepare a dict "trfmoves" that can be used when - self.payment_mode_id.move_option = date or line - key = unique identifier (date or True or line.id) - value = bank_pay_lines (recordset that can have several entries) - """ - self.ensure_one() - trfmoves = {} - for bline in self.bank_line_ids: - hashcode = bline.move_line_offsetting_account_hashcode() - if hashcode in trfmoves: - trfmoves[hashcode] += bline - else: - trfmoves[hashcode] = bline - return trfmoves - - def generate_move(self): - """ - Create the moves that pay off the move lines from - the payment/debit order. - """ - self.ensure_one() - trfmoves = self._prepare_trf_moves() - for hashcode, blines in trfmoves.items(): - self._create_reconcile_move(hashcode, blines) - - def action_bank_payment_line(self): - self.ensure_one() - action = self.env.ref("account_payment_order.bank_payment_line_action") - action_dict = action.read()[0] - action_dict["domain"] = [("id", "in", self.bank_line_ids.ids)] - return action_dict - def action_move_journal_line(self): self.ensure_one() action = self.env.ref("account.action_move_journal_line").sudo().read()[0] diff --git a/account_payment_order/models/bank_payment_line.py b/account_payment_order/models/bank_payment_line.py deleted file mode 100644 index ed7e04622..000000000 --- a/account_payment_order/models/bank_payment_line.py +++ /dev/null @@ -1,204 +0,0 @@ -# Copyright 2015-2016 Akretion - Alexis de Lattre -# Copyright 2018 Tecnativa - Pedro M. Baeza -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). - -from odoo import _, api, fields, models -from odoo.exceptions import UserError - - -class BankPaymentLine(models.Model): - _name = "bank.payment.line" - _description = "Bank Payment Lines" - _check_company_auto = True - - name = fields.Char(string="Bank Payment Line Ref", required=True, readonly=True) - order_id = fields.Many2one( - comodel_name="account.payment.order", - ondelete="cascade", - index=True, - readonly=True, - check_company=True, - ) - payment_type = fields.Selection( - related="order_id.payment_type", readonly=True, store=True - ) - state = fields.Selection(related="order_id.state", readonly=True, store=True) - payment_line_ids = fields.One2many( - comodel_name="account.payment.line", - inverse_name="bank_line_id", - string="Payment Lines", - readonly=True, - ) - partner_id = fields.Many2one( - comodel_name="res.partner", - related="payment_line_ids.partner_id", - readonly=True, - store=True, - check_company=True, - ) # store=True for groupby - # Function Float fields are sometimes badly displayed in tree view, - # see bug report https://github.com/odoo/odoo/issues/8632 - # But is it still true in v9 ? - amount_currency = fields.Monetary( - string="Amount", - currency_field="currency_id", - compute="_compute_amount", - store=True, - readonly=True, - ) - amount_company_currency = fields.Monetary( - string="Amount in Company Currency", - currency_field="company_currency_id", - compute="_compute_amount", - store=True, - readonly=True, - ) - currency_id = fields.Many2one( - comodel_name="res.currency", - required=True, - readonly=True, - related="payment_line_ids.currency_id", - ) - partner_bank_id = fields.Many2one( - comodel_name="res.partner.bank", - string="Bank Account", - readonly=True, - related="payment_line_ids.partner_bank_id", - check_company=True, - ) - date = fields.Date(related="payment_line_ids.date", readonly=True) - communication_type = fields.Selection( - related="payment_line_ids.communication_type", readonly=True - ) - communication = fields.Char(required=True, readonly=True) - company_id = fields.Many2one( - comodel_name="res.company", - related="order_id.payment_mode_id.company_id", - store=True, - readonly=True, - ) - company_currency_id = fields.Many2one( - comodel_name="res.currency", - related="order_id.payment_mode_id.company_id.currency_id", - readonly=True, - store=True, - ) - - @api.model - def same_fields_payment_line_and_bank_payment_line(self): - """ - This list of fields is used both to compute the grouping - hashcode and to copy the values from payment line - to bank payment line - The fields must have the same name on the 2 objects - """ - same_fields = [ - "currency_id", - "partner_id", - "partner_bank_id", - "date", - "communication_type", - ] - return same_fields - - @api.depends("payment_line_ids", "payment_line_ids.amount_currency") - def _compute_amount(self): - for bline in self: - amount_currency = sum(bline.mapped("payment_line_ids.amount_currency")) - amount_company_currency = bline.currency_id._convert( - amount_currency, - bline.company_currency_id, - bline.company_id, - bline.date or fields.Date.today(), - ) - bline.amount_currency = amount_currency - bline.amount_company_currency = amount_company_currency - - @api.model - @api.returns("self") - def create(self, vals): - if vals.get("name", "New") == "New": - vals["name"] = ( - self.env["ir.sequence"].next_by_code("bank.payment.line") or "New" - ) - return super(BankPaymentLine, self).create(vals) - - def move_line_offsetting_account_hashcode(self): - """ - This method is inherited in the module - account_banking_sepa_direct_debit - """ - self.ensure_one() - if self.order_id.payment_mode_id.move_option == "date": - hashcode = fields.Date.to_string(self.date) - else: - hashcode = str(self.id) - return hashcode - - def reconcile_payment_lines(self): - for bline in self: - if all([pline.move_line_id for pline in bline.payment_line_ids]): - bline.reconcile() - else: - bline.no_reconcile_hook() - - def no_reconcile_hook(self): - """This method is designed to be inherited if needed""" - return - - def reconcile(self): - self.ensure_one() - amlo = self.env["account.move.line"] - transit_mlines = amlo.search([("bank_payment_line_id", "=", self.id)]) - assert len(transit_mlines) == 1, "We should have only 1 move" - transit_mline = transit_mlines[0] - assert not transit_mline.reconciled, "Transit move should not be reconciled" - lines_to_rec = transit_mline - for payment_line in self.payment_line_ids: - - if not payment_line.move_line_id: - raise UserError( - _( - "Can not reconcile: no move line for " - "payment line %(line)s of partner '%(partner)s'.", - line=payment_line.name, - partner=payment_line.partner_id.name, - ) - ) - if payment_line.move_line_id.reconciled: - raise UserError( - _( - "Move line '%(line)s' of partner '%(partner)s' has already " - "been reconciled", - line=payment_line.move_line_id.name, - partner=payment_line.partner_id.name, - ) - ) - if payment_line.move_line_id.account_id != transit_mline.account_id: - raise UserError( - _( - "For partner '%(partner)s', the account of the account " - "move line to pay (%(line1)s) is different from the " - "account of of the transit move line (%(line2)s).", - partner=payment_line.move_line_id.partner_id.name, - line1=payment_line.move_line_id.account_id.code, - line2=transit_mline.account_id.code, - ) - ) - - lines_to_rec += payment_line.move_line_id - - lines_to_rec.reconcile() - - def unlink(self): - for line in self: - order_state = line.order_id.state - if order_state == "uploaded": - raise UserError( - _( - "Cannot delete a payment order line whose payment order is" - " in state '%(state)s'. You need to cancel it first.", - state=order_state, - ) - ) - return super(BankPaymentLine, self).unlink() diff --git a/account_payment_order/security/ir.model.access.csv b/account_payment_order/security/ir.model.access.csv index 11512c93f..d23d69ab9 100644 --- a/account_payment_order/security/ir.model.access.csv +++ b/account_payment_order/security/ir.model.access.csv @@ -1,7 +1,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_account_payment_order,Full access on account.payment.order to Payment Manager,model_account_payment_order,group_account_payment,1,1,1,1 access_account_payment_line,Full access on account.payment.line to Payment Manager,model_account_payment_line,group_account_payment,1,1,1,1 -access_bank_payment_line,Full access on bank.payment.line to Payment Manager,model_bank_payment_line,group_account_payment,1,1,1,1 +access_bank_payment_line,Full access on account.payment to Payment Manager,account.model_account_payment,group_account_payment,1,1,1,1 base.access_res_partner_bank_group_partner_manager,Full access on res.partner.bank to Account Payment group,base.model_res_partner_bank,group_account_payment,1,1,1,1 base.access_res_bank_group_partner_manager,Full access on res.bank to Account Payment group,base.model_res_bank,group_account_payment,1,1,1,1 access_account_payment_line_create,access_account_payment_line_create,model_account_payment_line_create,group_account_payment,1,1,1,1 diff --git a/account_payment_order/security/payment_security.xml b/account_payment_order/security/payment_security.xml index 38a7336eb..a3f0a2050 100644 --- a/account_payment_order/security/payment_security.xml +++ b/account_payment_order/security/payment_security.xml @@ -25,12 +25,5 @@ name="domain_force" >['|', ('company_id', '=', False), ('company_id', 'in', company_ids)] - - Bank payment line multi-company rule - - ['|', ('company_id', '=', False), ('company_id', 'in', company_ids)] - diff --git a/account_payment_order/tests/test_payment_mode.py b/account_payment_order/tests/test_payment_mode.py index 5a101b044..a8d13c371 100644 --- a/account_payment_order/tests/test_payment_mode.py +++ b/account_payment_order/tests/test_payment_mode.py @@ -68,14 +68,6 @@ class TestPaymentMode(TransactionCase): } ) - def test_onchange_generate_move(self): - self.payment_mode_c1.generate_move = True - self.payment_mode_c1.generate_move_change() - self.assertEqual(self.payment_mode_c1.move_option, "date") - self.payment_mode_c1.generate_move = False - self.payment_mode_c1.generate_move_change() - self.assertFalse(self.payment_mode_c1.move_option) - def test_onchange_payment_type(self): self.payment_mode_c1.payment_method_id = self.manual_in self.payment_mode_c1.payment_method_id_change() diff --git a/account_payment_order/tests/test_payment_order_inbound.py b/account_payment_order/tests/test_payment_order_inbound.py index 1e663f129..c7c2b0314 100644 --- a/account_payment_order/tests/test_payment_order_inbound.py +++ b/account_payment_order/tests/test_payment_order_inbound.py @@ -1,6 +1,6 @@ # Copyright 2017 Camptocamp SA # Copyright 2017 Creu Blanca -# Copyright 2019 Tecnativa - Pedro M. Baeza +# Copyright 2019-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from datetime import date, timedelta @@ -99,12 +99,12 @@ class TestPaymentOrderInbound(TestPaymentOrderInboundBase): payment_order.write({"journal_id": self.journal.id}) self.assertEqual(len(payment_order.payment_line_ids), 1) - self.assertEqual(len(payment_order.bank_line_ids), 0) + self.assertFalse(payment_order.payment_ids) # Open payment order payment_order.draft2open() - self.assertEqual(payment_order.bank_line_count, 1) + self.assertEqual(payment_order.payment_count, 1) # Generate and upload payment_order.open2generated() @@ -114,10 +114,6 @@ class TestPaymentOrderInbound(TestPaymentOrderInboundBase): with self.assertRaises(UserError): payment_order.unlink() - bank_line = payment_order.bank_line_ids - - with self.assertRaises(UserError): - bank_line.unlink() payment_order.action_uploaded_cancel() self.assertEqual(payment_order.state, "cancel") payment_order.cancel2draft() diff --git a/account_payment_order/tests/test_payment_order_outbound.py b/account_payment_order/tests/test_payment_order_outbound.py index 1bae28cb8..833490739 100644 --- a/account_payment_order/tests/test_payment_order_outbound.py +++ b/account_payment_order/tests/test_payment_order_outbound.py @@ -1,5 +1,6 @@ # © 2017 Camptocamp SA # © 2017 Creu Blanca +# Copyright 2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from datetime import date, datetime, timedelta @@ -205,7 +206,7 @@ class TestPaymentOrderOutbound(TestPaymentOrderOutboundBase): order.draft2open() order.open2generated() order.generated2uploaded() - self.assertEqual(order.move_ids[0].date, order.bank_line_ids[0].date) + self.assertEqual(order.move_ids[0].date, order.payment_ids[0].date) self.assertEqual(order.state, "uploaded") def test_cancel_payment_order(self): @@ -222,13 +223,11 @@ class TestPaymentOrderOutbound(TestPaymentOrderOutboundBase): payment_order.write({"journal_id": self.bank_journal.id}) self.assertEqual(len(payment_order.payment_line_ids), 1) - self.assertEqual(len(payment_order.bank_line_ids), 0) + self.assertFalse(payment_order.payment_ids) # Open payment order payment_order.draft2open() - - self.assertEqual(payment_order.bank_line_count, 1) - + self.assertEqual(payment_order.payment_count, 1) # Generate and upload payment_order.open2generated() payment_order.generated2uploaded() @@ -237,10 +236,6 @@ class TestPaymentOrderOutbound(TestPaymentOrderOutboundBase): with self.assertRaises(UserError): payment_order.unlink() - bank_line = payment_order.bank_line_ids - - with self.assertRaises(UserError): - bank_line.unlink() payment_order.action_uploaded_cancel() self.assertEqual(payment_order.state, "cancel") payment_order.cancel2draft() @@ -296,16 +291,21 @@ class TestPaymentOrderOutbound(TestPaymentOrderOutboundBase): self.assertEqual(len(outbound_order.payment_line_ids), 2) self.assertEqual(outbound_order.payment_line_ids[1].date, False) # Open payment order - self.assertEqual(len(outbound_order.bank_line_ids), 0) + self.assertFalse(outbound_order.payment_ids) outbound_order.draft2open() - self.assertEqual(outbound_order.bank_line_count, 2) + self.assertEqual(outbound_order.payment_count, 2) self.assertEqual( outbound_order.payment_line_ids[0].date, - outbound_order.payment_line_ids[0].bank_line_id.date, + outbound_order.payment_line_ids[0].payment_ids.date, ) self.assertEqual(outbound_order.payment_line_ids[1].date, date.today()) self.assertEqual( - outbound_order.payment_line_ids[1].bank_line_id.date, date.today() + outbound_order.payment_line_ids[1].date, + fields.Date.context_today(outbound_order), + ) + self.assertEqual( + outbound_order.payment_line_ids[1].payment_ids.date, + fields.Date.context_today(outbound_order), ) def test_supplier_refund(self): diff --git a/account_payment_order/views/account_move_line.xml b/account_payment_order/views/account_move_line.xml index b6d9cd1f2..52a7ebf7a 100644 --- a/account_payment_order/views/account_move_line.xml +++ b/account_payment_order/views/account_move_line.xml @@ -15,7 +15,6 @@ name="partner_bank_id" domain="[('partner_id', '=', partner_id), '|', ('company_id', '=', company_id), ('company_id', '=', False)]" /> - diff --git a/account_payment_order/views/account_payment_line.xml b/account_payment_order/views/account_payment_line.xml index b0040a484..1c2c72a06 100644 --- a/account_payment_order/views/account_payment_line.xml +++ b/account_payment_order/views/account_payment_line.xml @@ -40,7 +40,7 @@ /> - + diff --git a/account_payment_order/views/account_payment_mode.xml b/account_payment_order/views/account_payment_mode.xml index 303d96704..1b7bdb01b 100644 --- a/account_payment_order/views/account_payment_mode.xml +++ b/account_payment_order/views/account_payment_mode.xml @@ -32,21 +32,6 @@ - - - - - diff --git a/account_payment_order/views/account_payment_order.xml b/account_payment_order/views/account_payment_order.xml index 7c21a4b2b..39b783038 100644 --- a/account_payment_order/views/account_payment_order.xml +++ b/account_payment_order/views/account_payment_order.xml @@ -98,7 +98,7 @@ /> @@ -122,11 +122,11 @@ /> - + @@ -150,9 +150,9 @@ diff --git a/account_payment_order/views/bank_payment_line.xml b/account_payment_order/views/bank_payment_line.xml deleted file mode 100644 index 624742fc9..000000000 --- a/account_payment_order/views/bank_payment_line.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - bank.payment.line.form - bank.payment.line - -
- - - - - - - - - - - - - - - -
-
-
- - bank.payment.line.tree - bank.payment.line - - - - - - - - - - - - - - - - bank.payment.line.search - bank.payment.line - - - - - - - - - - - - - - Bank Payment Lines - bank.payment.line - tree,form - {'bank_payment_line_main_view': True} - - -
From 5b299ca94f6bdf3e1c886a5c34a04304f781fb53 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sun, 6 Nov 2022 13:16:17 +0100 Subject: [PATCH 2/7] [REF] account_banking_pain_base: Adapt module to native payment refactoring --- account_banking_pain_base/__manifest__.py | 3 +- account_banking_pain_base/models/__init__.py | 1 - .../models/account_payment_line.py | 11 +++++-- .../models/account_payment_order.py | 13 ++++---- .../models/bank_payment_line.py | 24 -------------- .../views/bank_payment_line_view.xml | 31 ------------------- 6 files changed, 17 insertions(+), 66 deletions(-) delete mode 100644 account_banking_pain_base/models/bank_payment_line.py delete mode 100644 account_banking_pain_base/views/bank_payment_line_view.xml diff --git a/account_banking_pain_base/__manifest__.py b/account_banking_pain_base/__manifest__.py index 00b65e0dd..8b92ad440 100644 --- a/account_banking_pain_base/__manifest__.py +++ b/account_banking_pain_base/__manifest__.py @@ -1,7 +1,7 @@ # Copyright 2013-2016 Akretion - Alexis de Lattre -# Copyright 2014-2017 Tecnativa - Pedro M. Baeza # Copyright 2016 Tecnativa - Antonio Espinosa # Copyright 2021 Tecnativa - Carlos Roca +# Copyright 2014-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { @@ -18,7 +18,6 @@ "security/security.xml", "views/account_payment_line.xml", "views/account_payment_order.xml", - "views/bank_payment_line_view.xml", "views/account_payment_mode.xml", "views/res_config_settings.xml", "views/account_payment_method.xml", diff --git a/account_banking_pain_base/models/__init__.py b/account_banking_pain_base/models/__init__.py index af5bbf1f2..4f1503393 100644 --- a/account_banking_pain_base/models/__init__.py +++ b/account_banking_pain_base/models/__init__.py @@ -1,6 +1,5 @@ from . import account_payment_line from . import account_payment_order -from . import bank_payment_line from . import account_payment_mode from . import res_company from . import res_config_settings diff --git a/account_banking_pain_base/models/account_payment_line.py b/account_banking_pain_base/models/account_payment_line.py index 8753b263d..2e3d03147 100644 --- a/account_banking_pain_base/models/account_payment_line.py +++ b/account_banking_pain_base/models/account_payment_line.py @@ -1,9 +1,9 @@ # Copyright 2013-2016 Akretion - Alexis de Lattre -# Copyright 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza # Copyright 2021 Tecnativa - Carlos Roca +# Copyright 2014-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import fields, models +from odoo import api, fields, models class AccountPaymentLine(models.Model): @@ -171,3 +171,10 @@ class AccountPaymentLine(models.Model): 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"] + return res diff --git a/account_banking_pain_base/models/account_payment_order.py b/account_banking_pain_base/models/account_payment_order.py index 4380e291c..753db771d 100644 --- a/account_banking_pain_base/models/account_payment_order.py +++ b/account_banking_pain_base/models/account_payment_order.py @@ -1,7 +1,7 @@ # Copyright 2013-2016 Akretion - Alexis de Lattre -# Copyright 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza # Copyright 2016 Antiun Ingenieria S.L. - Antonio Espinosa # Copyright 2021 Tecnativa - Carlos Roca +# Copyright 2014-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). import logging @@ -606,11 +606,12 @@ class AccountPaymentOrder(models.Model): @api.model def generate_remittance_info_block(self, parent_node, line, gen_args): remittance_info = etree.SubElement(parent_node, "RmtInf") - if line.communication_type == "normal": + communication_type = line.payment_line_ids[:1].communication_type + if communication_type == "normal": remittance_info_unstructured = etree.SubElement(remittance_info, "Ustrd") remittance_info_unstructured.text = self._prepare_field( "Remittance Unstructured Information", - "line.communication", + "line.payment_reference", {"line": line}, 140, gen_args=gen_args, @@ -632,7 +633,7 @@ class AccountPaymentOrder(models.Model): creditor_ref_info_type_issuer = etree.SubElement( creditor_ref_info_type, "Issr" ) - creditor_ref_info_type_issuer.text = line.communication_type + creditor_ref_info_type_issuer.text = communication_type creditor_reference = etree.SubElement( creditor_ref_information, "CdtrRef" ) @@ -651,13 +652,13 @@ class AccountPaymentOrder(models.Model): creditor_ref_info_type_issuer = etree.SubElement( creditor_ref_info_type, "Issr" ) - creditor_ref_info_type_issuer.text = line.communication_type + creditor_ref_info_type_issuer.text = communication_type creditor_reference = etree.SubElement(creditor_ref_information, "Ref") creditor_reference.text = self._prepare_field( "Creditor Structured Reference", - "line.communication", + "line.payment_reference", {"line": line}, 35, gen_args=gen_args, diff --git a/account_banking_pain_base/models/bank_payment_line.py b/account_banking_pain_base/models/bank_payment_line.py deleted file mode 100644 index 0079b5fda..000000000 --- a/account_banking_pain_base/models/bank_payment_line.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2013-2016 Akretion - Alexis de Lattre -# Copyright 2021 Tecnativa - Carlos Roca -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). - -from odoo import api, fields, models - - -class BankPaymentLine(models.Model): - _inherit = "bank.payment.line" - - priority = fields.Selection(related="payment_line_ids.priority", string="Priority") - local_instrument = fields.Selection( - related="payment_line_ids.local_instrument", string="Local Instrument" - ) - category_purpose = fields.Selection( - related="payment_line_ids.category_purpose", string="Category Purpose" - ) - purpose = fields.Selection(related="payment_line_ids.purpose") - - @api.model - def same_fields_payment_line_and_bank_payment_line(self): - res = super().same_fields_payment_line_and_bank_payment_line() - res += ["priority", "local_instrument", "category_purpose", "purpose"] - return res diff --git a/account_banking_pain_base/views/bank_payment_line_view.xml b/account_banking_pain_base/views/bank_payment_line_view.xml deleted file mode 100644 index 247de1783..000000000 --- a/account_banking_pain_base/views/bank_payment_line_view.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - pain.base.bank.payment.line.form - bank.payment.line - - - - - - - - - - - - pain.base.bank.payment.line.tree - bank.payment.line - - - - - - - - - From 96c7a8aa94745eec7afeb7b33e76281ebfcacd6a Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sun, 6 Nov 2022 13:35:56 +0100 Subject: [PATCH 3/7] [REF] account_banking_sepa_credit_transfer: Adapt module to native payment refactoring Notables changes: - InstrId and EndToEndId tags are now filled with the journal entry ID, as there's no bank payment line identifier. --- .../__manifest__.py | 5 +-- .../models/account_payment_order.py | 26 +++++++++------- .../tests/test_sct.py | 31 ++++++------------- 3 files changed, 27 insertions(+), 35 deletions(-) diff --git a/account_banking_sepa_credit_transfer/__manifest__.py b/account_banking_sepa_credit_transfer/__manifest__.py index 5cf3c27cb..4dd212ac8 100644 --- a/account_banking_sepa_credit_transfer/__manifest__.py +++ b/account_banking_sepa_credit_transfer/__manifest__.py @@ -1,5 +1,6 @@ # Copyright 2010-2020 Akretion (www.akretion.com) -# Copyright 2016-2020 Tecnativa - Antonio Espinosa and Pedro M. Baeza +# Copyright 2016 Tecnativa - Antonio Espinosa +# Copyright 2016-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) { @@ -7,7 +8,7 @@ "summary": "Create SEPA XML files for Credit Transfers", "version": "15.0.1.0.3", "license": "AGPL-3", - "author": "Akretion, " "Tecnativa, " "Odoo Community Association (OCA)", + "author": "Akretion, Tecnativa, Odoo Community Association (OCA)", "website": "https://github.com/OCA/bank-payment", "category": "Banking addons", "conflicts": ["account_sepa"], diff --git a/account_banking_sepa_credit_transfer/models/account_payment_order.py b/account_banking_sepa_credit_transfer/models/account_payment_order.py index f2f92d38a..ebd404740 100644 --- a/account_banking_sepa_credit_transfer/models/account_payment_order.py +++ b/account_banking_sepa_credit_transfer/models/account_payment_order.py @@ -1,5 +1,5 @@ # Copyright 2010-2020 Akretion (www.akretion.com) -# Copyright 2014-2020 Tecnativa - Pedro M. Baeza +# Copyright 2014-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from lxml import etree @@ -78,10 +78,11 @@ class AccountPaymentOrder(models.Model): lines_per_group = {} # key = (requested_date, priority, local_instrument, categ_purpose) # values = list of lines as object - for line in self.bank_line_ids: - priority = line.priority - local_instrument = line.local_instrument - categ_purpose = line.category_purpose + for line in self.payment_ids: + payment_line = line.payment_line_ids[:1] + priority = payment_line.priority + local_instrument = payment_line.local_instrument + categ_purpose = payment_line.category_purpose # The field line.date is the requested payment date # taking into account the 'date_prefered' setting # cf account_banking_payment_export/models/account_payment.py @@ -145,7 +146,7 @@ class AccountPaymentOrder(models.Model): ) instruction_identification.text = self._prepare_field( "Instruction Identification", - "line.name", + "str(line.move_id.id)", {"line": line}, 35, gen_args=gen_args, @@ -155,7 +156,7 @@ class AccountPaymentOrder(models.Model): ) end2end_identification.text = self._prepare_field( "End to End Identification", - "line.name", + "str(line.move_id.id)", {"line": line}, 35, gen_args=gen_args, @@ -171,9 +172,9 @@ class AccountPaymentOrder(models.Model): instructed_amount = etree.SubElement( amount, "InstdAmt", Ccy=currency_name ) - instructed_amount.text = "%.2f" % line.amount_currency - amount_control_sum_a += line.amount_currency - amount_control_sum_b += line.amount_currency + instructed_amount.text = "%.2f" % line.amount + amount_control_sum_a += line.amount + amount_control_sum_b += line.amount if not line.partner_bank_id: raise UserError( _( @@ -190,9 +191,10 @@ class AccountPaymentOrder(models.Model): gen_args, line, ) - if line.purpose: + 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 + etree.SubElement(purpose, "Cd").text = line_purpose self.generate_remittance_info_block( credit_transfer_transaction_info, line, gen_args ) diff --git a/account_banking_sepa_credit_transfer/tests/test_sct.py b/account_banking_sepa_credit_transfer/tests/test_sct.py index 933323e61..c354821bc 100644 --- a/account_banking_sepa_credit_transfer/tests/test_sct.py +++ b/account_banking_sepa_credit_transfer/tests/test_sct.py @@ -1,6 +1,6 @@ # Copyright 2016 Akretion (Alexis de Lattre ) -# Copyright 2018 Tecnativa - Pedro M. Baeza # Copyright 2020 Sygel Technology - Valentin Vinagre +# Copyright 2018-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import base64 @@ -21,7 +21,6 @@ class TestSCT(TransactionCase): cls.journal_model = cls.env["account.journal"] cls.payment_order_model = cls.env["account.payment.order"] cls.payment_line_model = cls.env["account.payment.line"] - cls.bank_line_model = cls.env["bank.payment.line"] cls.partner_bank_model = cls.env["res.partner.bank"] cls.attachment_model = cls.env["ir.attachment"] cls.invoice_model = cls.env["account.move"] @@ -104,7 +103,7 @@ class TestSCT(TransactionCase): "payment_method_id": cls.env.ref( "account_banking_sepa_credit_transfer.sepa_credit_transfer" ).id, - "payment_account_id": cls.account_payable.id, + "payment_account_id": cls.account_expense.id, }, ) ], @@ -207,20 +206,16 @@ class TestSCT(TransactionCase): self.payment_order.draft2open() self.assertEqual(self.payment_order.state, "open") self.assertEqual(self.payment_order.sepa, True) - bank_lines = self.bank_line_model.search( - [("partner_id", "=", self.partner_agrolait.id)] - ) - self.assertEqual(len(bank_lines), 1) - agrolait_bank_line = bank_lines[0] + self.assertTrue(self.payment_order.payment_ids) + agrolait_bank_line = self.payment_order.payment_ids[0] self.assertEqual(agrolait_bank_line.currency_id, self.eur_currency) self.assertEqual( agrolait_bank_line.currency_id.compare_amounts( - agrolait_bank_line.amount_currency, 49.0 + agrolait_bank_line.amount, 49.0 ), 0, ) - self.assertEqual(agrolait_bank_line.communication_type, "normal") - self.assertEqual(agrolait_bank_line.communication, "F1341-F1342-A1301") + self.assertEqual(agrolait_bank_line.payment_reference, "F1341-F1342-A1301") self.assertEqual(agrolait_bank_line.partner_bank_id, invoice1.partner_bank_id) action = self.payment_order.open2generated() @@ -299,20 +294,14 @@ class TestSCT(TransactionCase): self.payment_order.draft2open() self.assertEqual(self.payment_order.state, "open") self.assertEqual(self.payment_order.sepa, False) - bank_lines = self.bank_line_model.search( - [("partner_id", "=", self.partner_asus.id)] - ) - self.assertEqual(len(bank_lines), 1) - asus_bank_line = bank_lines[0] + self.assertEqual(self.payment_order.payment_count, 1) + asus_bank_line = self.payment_order.payment_ids[0] self.assertEqual(asus_bank_line.currency_id, self.usd_currency) self.assertEqual( - asus_bank_line.currency_id.compare_amounts( - asus_bank_line.amount_currency, 3054.0 - ), + asus_bank_line.currency_id.compare_amounts(asus_bank_line.amount, 3054.0), 0, ) - self.assertEqual(asus_bank_line.communication_type, "normal") - self.assertEqual(asus_bank_line.communication, "Inv9032-Inv9033") + self.assertEqual(asus_bank_line.payment_reference, "Inv9032-Inv9033") self.assertEqual(asus_bank_line.partner_bank_id, invoice1.partner_bank_id) action = self.payment_order.open2generated() From 8aff0fdaf3a8b164ffa1c9c964459ee0f3b29a22 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sun, 6 Nov 2022 14:00:59 +0100 Subject: [PATCH 4/7] [REF] account_banking_mandate: Adapt module to native payment refactoring --- account_banking_mandate/__manifest__.py | 5 ++- account_banking_mandate/models/__init__.py | 1 - .../models/bank_payment_line.py | 23 ------------- .../tests/test_invoice_mandate.py | 16 ++------- .../views/bank_payment_line_view.xml | 34 ------------------- 5 files changed, 5 insertions(+), 74 deletions(-) delete mode 100644 account_banking_mandate/models/bank_payment_line.py delete mode 100644 account_banking_mandate/views/bank_payment_line_view.xml diff --git a/account_banking_mandate/__manifest__.py b/account_banking_mandate/__manifest__.py index bd4302b5c..3b226d0a4 100644 --- a/account_banking_mandate/__manifest__.py +++ b/account_banking_mandate/__manifest__.py @@ -1,7 +1,7 @@ # Copyright 2014 Compassion CH - Cyril Sester -# Copyright 2014 Tecnativa - Pedro M. Baeza # Copyright 2015-2020 Akretion - Alexis de Lattre -# Copyright 2017 Tecnativa - Carlos Dauden +# Copyright 2017 Tecnativa - Carlos Dauden +# Copyright 2014-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { @@ -24,7 +24,6 @@ "views/account_payment_line.xml", "views/res_partner_bank_view.xml", "views/res_partner.xml", - "views/bank_payment_line_view.xml", "data/mandate_reference_sequence.xml", "security/mandate_security.xml", "security/ir.model.access.csv", diff --git a/account_banking_mandate/models/__init__.py b/account_banking_mandate/models/__init__.py index 096b524b8..0de456248 100644 --- a/account_banking_mandate/models/__init__.py +++ b/account_banking_mandate/models/__init__.py @@ -4,5 +4,4 @@ from . import account_move from . import res_partner_bank from . import res_partner from . import account_payment_line -from . import bank_payment_line from . import account_move_line diff --git a/account_banking_mandate/models/bank_payment_line.py b/account_banking_mandate/models/bank_payment_line.py deleted file mode 100644 index 5eb6c80ba..000000000 --- a/account_banking_mandate/models/bank_payment_line.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2014 Compassion CH - Cyril Sester -# Copyright 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza -# Copyright 2015-16 Akretion - Alexis de Lattre -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). - -from odoo import api, fields, models - - -class BankPaymentLine(models.Model): - _inherit = "bank.payment.line" - - mandate_id = fields.Many2one( - comodel_name="account.banking.mandate", - string="Direct Debit Mandate", - related="payment_line_ids.mandate_id", - check_company=True, - ) - - @api.model - def same_fields_payment_line_and_bank_payment_line(self): - res = super().same_fields_payment_line_and_bank_payment_line() - res.append("mandate_id") - return res diff --git a/account_banking_mandate/tests/test_invoice_mandate.py b/account_banking_mandate/tests/test_invoice_mandate.py index aec660c85..3b9ad47a0 100644 --- a/account_banking_mandate/tests/test_invoice_mandate.py +++ b/account_banking_mandate/tests/test_invoice_mandate.py @@ -1,4 +1,5 @@ # Copyright 2017 Creu Blanca +# Copyright 2017-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from unittest.mock import patch @@ -13,27 +14,16 @@ from odoo.addons.account.models.account_payment_method import AccountPaymentMeth class TestInvoiceMandate(TransactionCase): def test_post_invoice_01(self): self.invoice._onchange_partner_id() - + prev_orders = self.env["account.payment.order"].search([]) self.assertEqual(self.invoice.mandate_id, self.mandate) - self.invoice.action_post() - - payable_move_lines = self.invoice.line_ids.filtered( - lambda s: s.account_id == self.invoice_account - ) - if payable_move_lines: - self.assertEqual(payable_move_lines[0].move_id.mandate_id, self.mandate) - self.env["account.invoice.payment.line.multi"].with_context( active_model="account.move", active_ids=self.invoice.ids ).create({}).run() - - payment_order = self.env["account.payment.order"].search([]) + payment_order = self.env["account.payment.order"].search([]) - prev_orders self.assertEqual(len(payment_order.ids), 1) payment_order.payment_mode_id_change() payment_order.draft2open() - payment_order.open2generated() - payment_order.generated2uploaded() self.assertEqual(self.mandate.payment_line_ids_count, 1) def test_post_invoice_02(self): diff --git a/account_banking_mandate/views/bank_payment_line_view.xml b/account_banking_mandate/views/bank_payment_line_view.xml deleted file mode 100644 index d4f19a113..000000000 --- a/account_banking_mandate/views/bank_payment_line_view.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - banking.mandate.bank.payment.line.form - bank.payment.line - - - - - - - - - banking.mandate.bank.payment.line.tree - bank.payment.line - - - - - - - - From ee6b97b66529a44d9aa452c50b88f322ae041073 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sun, 6 Nov 2022 16:08:09 +0100 Subject: [PATCH 5/7] [REF] account_banking_sepa_direct_debit: Adapt module to native payment refactoring Notable changes: - InstrId and EndToEndId tags are now filled with the journal entry ID, as there's no bank payment line identifier. --- .../__manifest__.py | 5 +- .../models/__init__.py | 1 - .../models/account_payment_order.py | 68 +++++++++---------- .../models/bank_payment_line.py | 20 ------ .../tests/test_sdd.py | 19 ++---- 5 files changed, 41 insertions(+), 72 deletions(-) delete mode 100644 account_banking_sepa_direct_debit/models/bank_payment_line.py diff --git a/account_banking_sepa_direct_debit/__manifest__.py b/account_banking_sepa_direct_debit/__manifest__.py index 3d4cf4176..b3f1ed088 100644 --- a/account_banking_sepa_direct_debit/__manifest__.py +++ b/account_banking_sepa_direct_debit/__manifest__.py @@ -1,5 +1,6 @@ # Copyright 2013-2020 Akretion (www.akretion.com) -# Copyright 2014-2020 Tecnativa - Pedro M. Baeza & Antonio Espinosa +# Copyright 2016 Tecnativa - Antonio Espinosa +# Copyright 2014-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { @@ -7,7 +8,7 @@ "summary": "Create SEPA files for Direct Debit", "version": "15.0.1.0.2", "license": "AGPL-3", - "author": "Akretion, " "Tecnativa, " "Odoo Community Association (OCA)", + "author": "Akretion, Tecnativa, Odoo Community Association (OCA)", "website": "https://github.com/OCA/bank-payment", "category": "Banking addons", "depends": ["account_banking_pain_base", "account_banking_mandate"], diff --git a/account_banking_sepa_direct_debit/models/__init__.py b/account_banking_sepa_direct_debit/models/__init__.py index 3a13c7d5b..6902b752e 100644 --- a/account_banking_sepa_direct_debit/models/__init__.py +++ b/account_banking_sepa_direct_debit/models/__init__.py @@ -1,6 +1,5 @@ from . import res_company from . import account_banking_mandate -from . import bank_payment_line from . import account_payment_mode from . import account_payment_method from . import account_payment_order diff --git a/account_banking_sepa_direct_debit/models/account_payment_order.py b/account_banking_sepa_direct_debit/models/account_payment_order.py index f5a041c49..3fc5537ce 100644 --- a/account_banking_sepa_direct_debit/models/account_payment_order.py +++ b/account_banking_sepa_direct_debit/models/account_payment_order.py @@ -1,5 +1,5 @@ # Copyright 2020 Akretion (Alexis de Lattre ) -# Copyright 2018 Tecnativa - Pedro M. Baeza +# Copyright 2018-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from lxml import etree @@ -72,16 +72,17 @@ class AccountPaymentOrder(models.Model): lines_per_group = {} # key = (requested_date, priority, sequence type) # value = list of lines as objects - for line in self.bank_line_ids: + for line in self.payment_ids: transactions_count_a += 1 - priority = line.priority - categ_purpose = line.category_purpose - scheme = line.mandate_id.scheme - if line.mandate_id.type == "oneoff": + 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 line.mandate_id.type == "recurrent": + elif payment_line.mandate_id.type == "recurrent": seq_type_map = {"recurring": "RCUR", "first": "FRST", "final": "FNAL"} - seq_type_label = line.mandate_id.recurrent_sequence_type + 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: @@ -90,7 +91,7 @@ class AccountPaymentOrder(models.Model): "Invalid mandate type in '%s'. Valid ones are 'Recurrent' " "or 'One-Off'" ) - % line.mandate_id.unique_mandate_reference + % payment_line.mandate_id.unique_mandate_reference ) # The field line.date is the requested payment date # taking into account the 'date_preferred' setting @@ -165,7 +166,7 @@ class AccountPaymentOrder(models.Model): ) instruction_identification.text = self._prepare_field( "Instruction Identification", - "line.name", + "str(line.move_id.id)", {"line": line}, 35, gen_args=gen_args, @@ -175,7 +176,7 @@ class AccountPaymentOrder(models.Model): ) end2end_identification.text = self._prepare_field( "End to End Identification", - "line.name", + "str(line.move_id.id)", {"line": line}, 35, gen_args=gen_args, @@ -190,18 +191,19 @@ class AccountPaymentOrder(models.Model): instructed_amount = etree.SubElement( dd_transaction_info, "InstdAmt", Ccy=currency_name ) - instructed_amount.text = "%.2f" % line.amount_currency - amount_control_sum_a += line.amount_currency - amount_control_sum_b += line.amount_currency + 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", - "line.mandate_id.unique_mandate_reference", - {"line": line}, + "mandate.unique_mandate_reference", + {"mandate": mandate}, 35, gen_args=gen_args, ) @@ -211,16 +213,11 @@ class AccountPaymentOrder(models.Model): mandate_signature_date.text = self._prepare_field( "Mandate Signature Date", "signature_date", - { - "line": line, - "signature_date": fields.Date.to_string( - line.mandate_id.signature_date - ), - }, + {"signature_date": fields.Date.to_string(mandate.signature_date)}, 10, gen_args=gen_args, ) - if sequence_type == "FRST" and line.mandate_id.last_debit_date: + if sequence_type == "FRST" and mandate.last_debit_date: amendment_indicator = etree.SubElement( mandate_related_info, "AmdmntInd" ) @@ -252,10 +249,10 @@ class AccountPaymentOrder(models.Model): gen_args, line, ) - - if line.purpose: + 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 + etree.SubElement(purpose, "Cd").text = line_purpose self.generate_remittance_info_block(dd_transaction_info, line, gen_args) @@ -281,18 +278,19 @@ class AccountPaymentOrder(models.Model): to_expire_mandates = abmo.browse([]) first_mandates = abmo.browse([]) all_mandates = abmo.browse([]) - for bline in order.bank_line_ids: - if bline.mandate_id in all_mandates: + for payment in order.payment_ids: + mandate = payment.payment_line_ids.mandate_id + if mandate in all_mandates: continue - all_mandates += bline.mandate_id - if bline.mandate_id.type == "oneoff": - to_expire_mandates += bline.mandate_id - elif bline.mandate_id.type == "recurrent": - seq_type = bline.mandate_id.recurrent_sequence_type + all_mandates += mandate + if mandate.type == "oneoff": + to_expire_mandates += mandate + elif mandate.type == "recurrent": + seq_type = mandate.recurrent_sequence_type if seq_type == "final": - to_expire_mandates += bline.mandate_id + to_expire_mandates += mandate elif seq_type == "first": - first_mandates += bline.mandate_id + first_mandates += mandate all_mandates.write({"last_debit_date": order.date_generated}) to_expire_mandates.write({"state": "expired"}) first_mandates.write({"recurrent_sequence_type": "recurring"}) diff --git a/account_banking_sepa_direct_debit/models/bank_payment_line.py b/account_banking_sepa_direct_debit/models/bank_payment_line.py deleted file mode 100644 index 5c4e69073..000000000 --- a/account_banking_sepa_direct_debit/models/bank_payment_line.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2020 Akretion - Alexis de Lattre -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). - -from odoo import models - - -class BankPaymentLine(models.Model): - _inherit = "bank.payment.line" - - def move_line_offsetting_account_hashcode(self): - """ - From my experience, even when you ask several direct debits - at the same date with enough delay, you will have several credits - on your bank statement: one for each mandate types. - So we split the transfer move lines by mandate type, so easier - reconciliation of the bank statement. - """ - hashcode = super().move_line_offsetting_account_hashcode() - hashcode += "-" + str(self.mandate_id.recurrent_sequence_type) - return hashcode diff --git a/account_banking_sepa_direct_debit/tests/test_sdd.py b/account_banking_sepa_direct_debit/tests/test_sdd.py index dc9d8575c..f05ffa554 100644 --- a/account_banking_sepa_direct_debit/tests/test_sdd.py +++ b/account_banking_sepa_direct_debit/tests/test_sdd.py @@ -1,5 +1,5 @@ # Copyright 2016 Akretion (Alexis de Lattre ) -# Copyright 2018-2020 Tecnativa - Pedro M. Baeza +# Copyright 2018-2022 Tecnativa - Pedro M. Baeza # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). import base64 @@ -42,7 +42,6 @@ class TestSDDBase(TransactionCase): cls.payment_order_model = cls.env["account.payment.order"] cls.payment_line_model = cls.env["account.payment.line"] cls.mandate_model = cls.env["account.banking.mandate"] - cls.bank_line_model = cls.env["bank.payment.line"] cls.partner_bank_model = cls.env["res.partner.bank"] cls.attachment_model = cls.env["ir.attachment"] cls.invoice_model = cls.env["account.move"] @@ -265,22 +264,14 @@ class TestSDDBase(TransactionCase): payment_order.draft2open() self.assertEqual(payment_order.state, "open") self.assertEqual(payment_order.sepa, True) - # Check bank payment line - bank_lines = self.bank_line_model.search( - [("partner_id", "=", self.partner_agrolait.id)] - ) - self.assertEqual(len(bank_lines), 1) - agrolait_bank_line = bank_lines[0] + # Check account payment + agrolait_bank_line = payment_order.payment_ids[0] self.assertEqual(agrolait_bank_line.currency_id, self.eur_currency) self.assertEqual( - float_compare( - agrolait_bank_line.amount_currency, 42.0, precision_digits=accpre - ), + float_compare(agrolait_bank_line.amount, 42.0, precision_digits=accpre), 0, ) - self.assertEqual(agrolait_bank_line.communication_type, "normal") - self.assertEqual(agrolait_bank_line.communication, invoice1.name) - self.assertEqual(agrolait_bank_line.mandate_id, invoice1.mandate_id) + self.assertEqual(agrolait_bank_line.payment_reference, invoice1.name) self.assertEqual( agrolait_bank_line.partner_bank_id, invoice1.mandate_id.partner_bank_id ) From 25533267f41fe00a9cb7c8f08cb2b3ffce888a7f Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Mon, 7 Nov 2022 13:29:45 +0100 Subject: [PATCH 6/7] [OU-ADD] account_payment_order: Migration scripts to native payment ref This adapts the old bank.payment.line records to account.payment records according the new approach, taking into account if you come from v14 with the refactoring applied. --- .../migrations/14.0.1.3.0/pre-migration.py | 10 - .../migrations/15.0.2.0.0/post-migration.py | 179 ++++++++++++++++++ .../models/account_payment.py | 2 + 3 files changed, 181 insertions(+), 10 deletions(-) delete mode 100644 account_payment_order/migrations/14.0.1.3.0/pre-migration.py create mode 100644 account_payment_order/migrations/15.0.2.0.0/post-migration.py diff --git a/account_payment_order/migrations/14.0.1.3.0/pre-migration.py b/account_payment_order/migrations/14.0.1.3.0/pre-migration.py deleted file mode 100644 index f5f7ace2c..000000000 --- a/account_payment_order/migrations/14.0.1.3.0/pre-migration.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2021 Akretion France (http://www.akretion.com/) -# @author: Alexis de Lattre -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - - -def migrate(cr, version): - if not version: - return - - cr.execute("UPDATE account_payment_order SET state='uploaded' WHERE state='done'") diff --git a/account_payment_order/migrations/15.0.2.0.0/post-migration.py b/account_payment_order/migrations/15.0.2.0.0/post-migration.py new file mode 100644 index 000000000..be62ed2ab --- /dev/null +++ b/account_payment_order/migrations/15.0.2.0.0/post-migration.py @@ -0,0 +1,179 @@ +# Copyright 2022 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + +from openupgradelib import openupgrade + +_logger = logging.getLogger(__name__) + + +def _insert_account_payments(env): + openupgrade.logged_query( + env.cr, "ALTER TABLE account_payment ADD old_bank_payment_line_id INT4" + ) + # Create an account.payment record for each bank.payment.line + openupgrade.logged_query( + env.cr, + """ + INSERT INTO account_payment ( + create_date, create_uid, write_date, write_uid, old_bank_payment_line_name, + payment_order_id, partner_id, amount, currency_id, + payment_method_id, old_bank_payment_line_id, payment_type, + partner_type, + destination_account_id, payment_reference, move_id + ) + SELECT + bpl.create_date, bpl.create_uid, bpl.write_date, bpl.write_uid, bpl.name, + bpl.order_id, bpl.partner_id, bpl.amount_currency, 1, + apm.payment_method_id, bpl.id, apo.payment_type, + CASE WHEN apo.payment_type = 'inbound' THEN 'customer' ELSE 'supplier' END, + aml.account_id, bpl.communication, aml.move_id + FROM bank_payment_line bpl + JOIN account_payment_order apo ON apo.id = bpl.order_id + JOIN account_payment_mode apm ON apm.id = apo.payment_mode_id + LEFT JOIN account_move_line aml ON aml.bank_payment_line_id = bpl.id + WHERE apo.state not in ('uploaded', 'done') or aml.move_id is not null + """, + ) + # As the information is asymmetric: N payment lines > 1 bank payment line, but there + # are some related non-stored fields to payment lines, we need a second query to + # update some of the fields + openupgrade.logged_query( + env.cr, + """ + UPDATE account_payment ap + SET currency_id = apl.currency_id, + partner_bank_id = apl.partner_bank_id + FROM account_payment_line apl + WHERE apl.bank_line_id = ap.old_bank_payment_line_id + """, + ) + + +def _create_hooks(env): + """Avoid errors due to locked dates, overriding involved methods.""" + + def _check_fiscalyear_lock_date(self): + return True + + def _check_tax_lock_date(self): + return True + + def _check_reconciliation(self): + return True + + # create hooks + _check_fiscalyear_lock_date._original_method = type( + env["account.move"] + )._check_fiscalyear_lock_date + type(env["account.move"])._check_fiscalyear_lock_date = _check_fiscalyear_lock_date + _check_tax_lock_date._original_method = type( + env["account.move.line"] + )._check_tax_lock_date + type(env["account.move.line"])._check_tax_lock_date = _check_tax_lock_date + _check_reconciliation._original_method = type( + env["account.move.line"] + )._check_reconciliation + type(env["account.move.line"])._check_reconciliation = _check_reconciliation + + +def create_moves_from_orphan_account_payments(env): + """Recreate missing journal entries on the newly created account payments.""" + env.cr.execute( + """ + SELECT ap.id, MIN(apl.date), MIN(bpl.company_id), MIN(apo.name), + MIN(apo.journal_id), MIN(apl.currency_id), MIN(apo.state), MIN(apo.id) + FROM bank_payment_line bpl + JOIN account_payment ap ON ap.old_bank_payment_line_id = bpl.id + JOIN account_payment_order apo ON apo.id = bpl.order_id + JOIN account_payment_line apl ON apl.bank_line_id = bpl.id + LEFT JOIN account_move_line aml ON aml.bank_payment_line_id = bpl.id + WHERE aml.move_id IS NULL + GROUP BY ap.id + """ + ) + deprecated_acc_by_company = {} + for row in env.cr.fetchall(): + payment = ( + env["account.payment"] + .with_context( + check_move_validity=False, + tracking_disable=True, + ) + .browse(row[0]) + ) + move = env["account.move"].create( + { + "name": "/", + "date": row[1], + "payment_id": payment.id, + "move_type": "entry", + "company_id": row[2], + "ref": row[3], + "journal_id": row[4], + "currency_id": row[5], + "state": "draft" if row[6] in {"open", "generated"} else "cancel", + "payment_order_id": row[7], + } + ) + payment.move_id = move + # Avoid deprecated account warning + if payment.company_id not in deprecated_acc_by_company: + deprecated_accounts = env["account.account"].search( + [("deprecated", "=", True), ("company_id", "=", payment.company_id.id)] + ) + deprecated_acc_by_company[payment.company_id] = deprecated_accounts + deprecated_accounts.deprecated = False + try: + payment._synchronize_to_moves(["date"]) # no more changed fields needed + except Exception as e: + _logger.error("Failed for payment with id %s: %s", payment.id, e) + raise + # Restore deprecated accounts + for deprecated_accounts in deprecated_acc_by_company.values(): + deprecated_accounts.deprecated = True + + +def _delete_hooks(env): + """Restore the locking dates original methods.""" + type(env["account.move"])._check_fiscalyear_lock_date = type( + env["account.move"] + )._check_fiscalyear_lock_date._original_method + type(env["account.move.line"])._check_tax_lock_date = type( + env["account.move.line"] + )._check_tax_lock_date._original_method + type(env["account.move.line"])._check_reconciliation = type( + env["account.move.line"] + )._check_reconciliation._original_method + + +def _insert_payment_line_payment_link(env): + openupgrade.logged_query( + env.cr, + """ + INSERT INTO account_payment_account_payment_line_rel + (account_payment_id, account_payment_line_id) + SELECT ap.id, apl.id + FROM account_payment_line apl + JOIN account_payment ap ON ap.old_bank_payment_line_id = apl.bank_line_id + """, + ) + + +@openupgrade.migrate() +def migrate(env, version): + if openupgrade.column_exists(env.cr, "account_payment", "old_bank_payment_line_id"): + # No execution if the column exists, as that means that this DB comes from v14 + # with the refactoring already applied + return + openupgrade.logged_query( + env.cr, "ALTER TABLE account_payment ALTER move_id DROP NOT NULL" + ) + _insert_account_payments(env) + _create_hooks(env) + create_moves_from_orphan_account_payments(env) + openupgrade.logged_query( + env.cr, "ALTER TABLE account_payment ALTER move_id SET NOT NULL" + ) + _delete_hooks(env) + _insert_payment_line_payment_link(env) diff --git a/account_payment_order/models/account_payment.py b/account_payment_order/models/account_payment.py index b10bfda63..ed155aa3f 100644 --- a/account_payment_order/models/account_payment.py +++ b/account_payment_order/models/account_payment.py @@ -10,6 +10,8 @@ class AccountPayment(models.Model): payment_order_id = fields.Many2one(comodel_name="account.payment.order") payment_line_ids = fields.Many2many(comodel_name="account.payment.line") + # Compatibility with previous approach for returns - To be removed on v16 + old_bank_payment_line_name = fields.Char() def _get_default_journal(self): res = super()._get_default_journal() From ccad6d34a84976f4d288c4b38ad615b58e476c79 Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Sat, 4 Mar 2023 13:29:32 +0100 Subject: [PATCH 7/7] [FIX] account_payment_order: Do correctly the fix on tests Previous patch by Alexis created a co-dependency between account_payment_order and account_banking_sepa_direct_debit, which is not correct. This patch avoids such problem and fix properly the test, although the utility of some of them is debatible. --- .../tests/test_account_payment.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/account_payment_order/tests/test_account_payment.py b/account_payment_order/tests/test_account_payment.py index edd838472..feee07439 100644 --- a/account_payment_order/tests/test_account_payment.py +++ b/account_payment_order/tests/test_account_payment.py @@ -65,9 +65,7 @@ class TestAccountPayment(AccountTestInvoicingCommon): ) # Journals cls.manual_in = cls.env.ref("account.account_payment_method_manual_in") - cls.sepa_in = cls.env.ref("account_banking_sepa_direct_debit.sepa_direct_debit") cls.manual_out = cls.env.ref("account.account_payment_method_manual_out") - cls.bank_journal = cls.company_data["default_journal_bank"] def test_account_payment_01(self): @@ -78,11 +76,8 @@ class TestAccountPayment(AccountTestInvoicingCommon): self.assertTrue(self.inbound_payment_method_01.payment_order_only) self.assertFalse(self.inbound_payment_method_02.payment_order_only) self.assertFalse(self.bank_journal.inbound_payment_order_only) - self.inbound_payment_method_02.payment_order_only = True - self.assertTrue(self.inbound_payment_method_01.payment_order_only) - self.assertTrue(self.inbound_payment_method_02.payment_order_only) - self.manual_in.payment_order_only = True - self.sepa_in.payment_order_only = True + for p in self.bank_journal.inbound_payment_method_line_ids.payment_method_id: + p.payment_order_only = True self.assertTrue(self.bank_journal.inbound_payment_order_only) def test_account_payment_02(self): @@ -90,7 +85,6 @@ class TestAccountPayment(AccountTestInvoicingCommon): self.assertFalse(self.bank_journal.outbound_payment_order_only) self.outbound_payment_method_01.payment_order_only = True self.assertTrue(self.outbound_payment_method_01.payment_order_only) - payment_method_id = ( self.bank_journal.outbound_payment_method_line_ids.payment_method_id ) @@ -146,11 +140,8 @@ class TestAccountPayment(AccountTestInvoicingCommon): self.assertNotIn(self.inbound_payment_method_01.id, payment_methods) self.assertIn(self.inbound_payment_method_02.id, payment_methods) # Set all payment methods of the bank journal 'payment order only' - self.inbound_payment_method_02.payment_order_only = True - self.assertTrue(self.inbound_payment_method_01.payment_order_only) - self.assertTrue(self.inbound_payment_method_02.payment_order_only) - self.manual_in.payment_order_only = True - self.sepa_in.payment_order_only = True + for p in self.bank_journal.inbound_payment_method_line_ids.payment_method_id: + p.payment_order_only = True self.assertTrue(self.bank_journal.inbound_payment_order_only) # check journals journals = new_account_payment._get_default_journal()