From 344153b7e8cc08e4318bb693f03f5677b27549da Mon Sep 17 00:00:00 2001 From: "Pedro M. Baeza" Date: Fri, 6 Jan 2023 13:04:57 +0100 Subject: [PATCH] [ADD] account_payment_order_grouped_output: Generate grouped entries from payment orders This module adds an option to generate extra grouped moves for the payment orders since the refactoring done to use native Odoo payments. This serves for easing the reconciliation on bank statements of large payment orders, handling them as one or several journal entries according payment date. --- .../README.rst | 75 ++++ .../__init__.py | 1 + .../__manifest__.py | 18 + .../models/__init__.py | 3 + .../models/account_move.py | 16 + .../models/account_payment_mode.py | 12 + .../models/account_payment_order.py | 194 ++++++++ .../readme/DESCRIPTION.rst | 5 + .../static/description/index.html | 418 ++++++++++++++++++ .../tests/__init__.py | 1 + .../test_payment_order_inbound_grouped.py | 21 + .../views/account_payment_mode_views.xml | 25 ++ .../views/account_payment_order_views.xml | 26 ++ 13 files changed, 815 insertions(+) create mode 100644 account_payment_order_grouped_output/README.rst create mode 100644 account_payment_order_grouped_output/__init__.py create mode 100644 account_payment_order_grouped_output/__manifest__.py create mode 100644 account_payment_order_grouped_output/models/__init__.py create mode 100644 account_payment_order_grouped_output/models/account_move.py create mode 100644 account_payment_order_grouped_output/models/account_payment_mode.py create mode 100644 account_payment_order_grouped_output/models/account_payment_order.py create mode 100644 account_payment_order_grouped_output/readme/DESCRIPTION.rst create mode 100644 account_payment_order_grouped_output/static/description/index.html create mode 100644 account_payment_order_grouped_output/tests/__init__.py create mode 100644 account_payment_order_grouped_output/tests/test_payment_order_inbound_grouped.py create mode 100644 account_payment_order_grouped_output/views/account_payment_mode_views.xml create mode 100644 account_payment_order_grouped_output/views/account_payment_order_views.xml diff --git a/account_payment_order_grouped_output/README.rst b/account_payment_order_grouped_output/README.rst new file mode 100644 index 000000000..157587efd --- /dev/null +++ b/account_payment_order_grouped_output/README.rst @@ -0,0 +1,75 @@ +============================================== +Account Payment Order - Generate grouped moves +============================================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/14.0/account_payment_order_grouped_output + :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-14-0/bank-payment-14-0-account_payment_order_grouped_output + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/bank-payment&target_branch=14.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds an option to generate extra grouped moves for the payment +orders since the refactoring done to use native Odoo payments. + +This serves for easing the reconciliation on bank statements of large payment +orders, handling them as one or several journal entries according payment date. + +**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 smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ACSONE SA/NV +* Therp BV +* Tecnativa +* Akretion + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/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_order_grouped_output/__init__.py b/account_payment_order_grouped_output/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/account_payment_order_grouped_output/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_payment_order_grouped_output/__manifest__.py b/account_payment_order_grouped_output/__manifest__.py new file mode 100644 index 000000000..233548200 --- /dev/null +++ b/account_payment_order_grouped_output/__manifest__.py @@ -0,0 +1,18 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +{ + "name": "Account Payment Order - Generate grouped moves", + "version": "14.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV, Therp BV, Tecnativa, Akretion, " + "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/bank-payment", + "category": "Banking addons", + "depends": ["account_payment_order"], + "data": [ + "views/account_payment_mode_views.xml", + "views/account_payment_order_views.xml", + ], + "demo": [], + "installable": True, +} diff --git a/account_payment_order_grouped_output/models/__init__.py b/account_payment_order_grouped_output/models/__init__.py new file mode 100644 index 000000000..b17a1af2e --- /dev/null +++ b/account_payment_order_grouped_output/models/__init__.py @@ -0,0 +1,3 @@ +from . import account_move +from . import account_payment_mode +from . import account_payment_order diff --git a/account_payment_order_grouped_output/models/account_move.py b/account_payment_order_grouped_output/models/account_move.py new file mode 100644 index 000000000..4dee19d00 --- /dev/null +++ b/account_payment_order_grouped_output/models/account_move.py @@ -0,0 +1,16 @@ +# Copyright 2022 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class AccountMove(models.Model): + _inherit = "account.move" + + grouped_payment_order_id = fields.Many2one( + comodel_name="account.payment.order", + string="Payment Order (Grouped)", + copy=False, + readonly=True, + check_company=True, + ) diff --git a/account_payment_order_grouped_output/models/account_payment_mode.py b/account_payment_order_grouped_output/models/account_payment_mode.py new file mode 100644 index 000000000..e0344efe4 --- /dev/null +++ b/account_payment_order_grouped_output/models/account_payment_mode.py @@ -0,0 +1,12 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class AccountPaymentMode(models.Model): + _inherit = "account.payment.mode" + + generate_move = fields.Boolean( + string="Generate Grouped Accounting Entries On File Upload", default=True + ) + post_move = fields.Boolean(default=True) diff --git a/account_payment_order_grouped_output/models/account_payment_order.py b/account_payment_order_grouped_output/models/account_payment_order.py new file mode 100644 index 000000000..d72835d29 --- /dev/null +++ b/account_payment_order_grouped_output/models/account_payment_order.py @@ -0,0 +1,194 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import _, api, fields, models + + +class AccountPaymentOrder(models.Model): + _inherit = "account.payment.order" + + grouped_move_ids = fields.One2many( + comodel_name="account.move", + inverse_name="grouped_payment_order_id", + string="Journal Entries (Grouped)", + readonly=True, + ) + grouped_move_count = fields.Integer( + compute="_compute_grouped_move_count", + string="Number of Grouped Journal Entries", + ) + + @api.depends("grouped_move_ids") + def _compute_grouped_move_count(self): + rg_res = self.env["account.move"].read_group( + [("grouped_payment_order_id", "in", self.ids)], + ["grouped_payment_order_id"], + ["grouped_payment_order_id"], + ) + mapped_data = { + x["grouped_payment_order_id"][0]: x["grouped_payment_order_id_count"] + for x in rg_res + } + for order in self: + order.grouped_move_count = mapped_data.get(order.id, 0) + + def action_uploaded_cancel(self): + """Unreconcile and remove grouped moves.""" + for move in self.grouped_move_ids: + move.button_cancel() + for move_line in move.line_ids: + move_line.remove_move_reconcile() + move.with_context(force_delete=True).unlink() + return super().action_uploaded_cancel() + + def generated2uploaded(self): + """Generate grouped moves if configured that way.""" + super().generated2uploaded() + for order in self: + if order.payment_mode_id.generate_move: + order.generate_move() + + 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, plines in trfmoves.items(): + self._create_reconcile_move(hashcode, plines) + + def _prepare_trf_moves(self): + """Prepare a dict "trfmoves" grouped by date.""" + self.ensure_one() + trfmoves = {} + for pline in self.payment_ids: + hashcode = fields.Date.to_string(pline.date) + trfmoves.setdefault(hashcode, self.env["account.payment"]) + trfmoves[hashcode] += pline + return trfmoves + + def _create_reconcile_move(self, hashcode, payments): + self.ensure_one() + post_move = self.payment_mode_id.post_move + am_obj = self.env["account.move"] + mvals = self._prepare_move(payments) + move = am_obj.create(mvals) + if post_move: + move.action_post() + self.reconcile_grouped_payments(move, payments) + + def reconcile_grouped_payments(self, move, payments): + lines_to_rec = move.line_ids[:-1] + for payment in payments: + lines_to_rec += payment.move_id.line_ids.filtered( + lambda x: x.account_id + in ( + payment.journal_id.payment_debit_account_id, + payment.journal_id.payment_credit_account_id, + ) + ) + lines_to_rec.reconcile() + + def _prepare_move(self, payments=None): + if self.payment_type == "outbound": + ref = _("Payment order %s") % self.name + else: + ref = _("Debit order %s") % self.name + if payments and len(payments) == 1: + ref += " - " + payments.name + vals = { + "date": payments[0].date, + "journal_id": self.journal_id.id, + "ref": ref, + "grouped_payment_order_id": self.id, + "line_ids": [], + } + total_company_currency = total_payment_currency = 0 + for pline in payments: + amount_company_currency = abs(pline.move_id.line_ids[0].balance) + total_company_currency += amount_company_currency + total_payment_currency += pline.amount + partner_ml_vals = self._prepare_move_line_partner_account(pline) + vals["line_ids"].append((0, 0, partner_ml_vals)) + trf_ml_vals = self._prepare_move_line_offsetting_account( + total_company_currency, total_payment_currency, payments + ) + vals["line_ids"].append((0, 0, trf_ml_vals)) + return vals + + def _prepare_move_line_partner_account(self, payment): + if self.payment_type == "inbound": + account = payment.journal_id.payment_debit_account_id + else: + account = payment.journal_id.payment_credit_account_id + if self.payment_type == "outbound": + name = _("Payment bank line %s") % payment.name + else: + name = _("Debit bank line %s") % payment.name + sign = self.payment_type == "inbound" and -1 or 1 + amount_company_currency = abs(payment.move_id.line_ids[0].balance) + vals = { + "name": name, + "partner_id": payment.partner_id.id, + "account_id": account.id, + "credit": ( + self.payment_type == "inbound" and amount_company_currency or 0.0 + ), + "debit": ( + self.payment_type == "outbound" and amount_company_currency or 0.0 + ), + "currency_id": payment.currency_id.id, + "amount_currency": payment.amount * sign, + } + return vals + + def _prepare_move_line_offsetting_account( + self, amount_company_currency, amount_payment_currency, payments + ): + if self.payment_type == "outbound": + name = _("Payment order %s") % self.name + account = self.journal_id.payment_credit_account_id + else: + name = _("Debit order %s") % self.name + account = self.journal_id.payment_debit_account_id + partner = self.env["res.partner"] + for index, payment in enumerate(payments): + if index == 0: + partner = payment.payment_line_ids[0].partner_id + elif payment.payment_line_ids[0].partner_id != partner: + # we have different partners in the grouped move + partner = self.env["res.partner"] + break + sign = self.payment_type == "outbound" and -1 or 1 + vals = { + "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 + ), + "currency_id": payments[0].currency_id.id, + "amount_currency": amount_payment_currency * sign, + } + return vals + + def action_grouped_moves(self): + self.ensure_one() + action = self.env["ir.actions.act_window"]._for_xml_id( + "account.action_move_journal_line" + ) + if self.grouped_move_count == 1: + action.update( + { + "view_mode": "form,tree,kanban", + "views": False, + "view_id": False, + "res_id": self.grouped_move_ids.id, + } + ) + else: + action["domain"] = [("id", "in", self.grouped_move_ids.ids)] + ctx = self.env.context.copy() + ctx.update({"search_default_misc_filter": 0}) + action["context"] = ctx + return action diff --git a/account_payment_order_grouped_output/readme/DESCRIPTION.rst b/account_payment_order_grouped_output/readme/DESCRIPTION.rst new file mode 100644 index 000000000..5558dd233 --- /dev/null +++ b/account_payment_order_grouped_output/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +This module adds an option to generate extra grouped moves for the payment +orders since the refactoring done to use native Odoo payments. + +This serves for easing the reconciliation on bank statements of large payment +orders, handling them as one or several journal entries according payment date. diff --git a/account_payment_order_grouped_output/static/description/index.html b/account_payment_order_grouped_output/static/description/index.html new file mode 100644 index 000000000..0ff14a5c9 --- /dev/null +++ b/account_payment_order_grouped_output/static/description/index.html @@ -0,0 +1,418 @@ + + + + + + +Account Payment Order - Generate grouped moves + + + +
+

Account Payment Order - Generate grouped moves

+ + +

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

+

This module adds an option to generate extra grouped moves for the payment +orders since the refactoring done to use native Odoo payments.

+

This serves for easing the reconciliation on bank statements of large payment +orders, handling them as one or several journal entries according payment date.

+

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 smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • ACSONE SA/NV
  • +
  • Therp BV
  • +
  • Tecnativa
  • +
  • Akretion
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/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_order_grouped_output/tests/__init__.py b/account_payment_order_grouped_output/tests/__init__.py new file mode 100644 index 000000000..31846c7eb --- /dev/null +++ b/account_payment_order_grouped_output/tests/__init__.py @@ -0,0 +1 @@ +from . import test_payment_order_inbound_grouped diff --git a/account_payment_order_grouped_output/tests/test_payment_order_inbound_grouped.py b/account_payment_order_grouped_output/tests/test_payment_order_inbound_grouped.py new file mode 100644 index 000000000..385ac39b7 --- /dev/null +++ b/account_payment_order_grouped_output/tests/test_payment_order_inbound_grouped.py @@ -0,0 +1,21 @@ +# Copyright 2022 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests.common import tagged + +from odoo.addons.account_payment_order.tests.test_payment_order_inbound import ( + TestPaymentOrderInboundBase, +) + + +@tagged("post_install", "-at_install") +class TestPaymentOrderInbound(TestPaymentOrderInboundBase): + def test_grouped_output(self): + self.inbound_mode.generate_move = True + self.inbound_mode.post_move = True + self.inbound_order.draft2open() + self.inbound_order.open2generated() + self.inbound_order.generated2uploaded() + grouped_moves = self.inbound_order.grouped_move_ids + self.assertTrue(grouped_moves) + self.assertTrue(grouped_moves.line_ids[0].reconciled) diff --git a/account_payment_order_grouped_output/views/account_payment_mode_views.xml b/account_payment_order_grouped_output/views/account_payment_mode_views.xml new file mode 100644 index 000000000..3c555885d --- /dev/null +++ b/account_payment_order_grouped_output/views/account_payment_mode_views.xml @@ -0,0 +1,25 @@ + + + + account.payment.mode + + + + + + + + + + + diff --git a/account_payment_order_grouped_output/views/account_payment_order_views.xml b/account_payment_order_grouped_output/views/account_payment_order_views.xml new file mode 100644 index 000000000..a326fc1ed --- /dev/null +++ b/account_payment_order_grouped_output/views/account_payment_order_views.xml @@ -0,0 +1,26 @@ + + + + account.payment.order + + +
+ +
+
+
+