From f30e7c9b9899ed60a6ad0fa49e126e016bcaec24 Mon Sep 17 00:00:00 2001
From: Simone Rubino
Date: Mon, 20 Jan 2025 18:57:58 +0100
Subject: [PATCH] [IMP] account_reconcile_oca: Reconcile multiple lines
---
account_reconcile_oca/README.rst | 11 ++-
account_reconcile_oca/__init__.py | 1 +
account_reconcile_oca/__manifest__.py | 1 +
account_reconcile_oca/readme/CONTRIBUTORS.md | 1 +
account_reconcile_oca/readme/USAGE.md | 7 ++
.../security/ir.model.access.csv | 1 +
.../static/description/index.html | 37 +++++---
account_reconcile_oca/tests/__init__.py | 1 +
.../tests/test_reconcile_multiple_lines.py | 88 +++++++++++++++++++
account_reconcile_oca/wizards/__init__.py | 3 +
.../reconcile_multiple_lines views.xml | 38 ++++++++
.../wizards/reconcile_multiple_lines.py | 46 ++++++++++
12 files changed, 221 insertions(+), 14 deletions(-)
create mode 100644 account_reconcile_oca/tests/test_reconcile_multiple_lines.py
create mode 100644 account_reconcile_oca/wizards/__init__.py
create mode 100644 account_reconcile_oca/wizards/reconcile_multiple_lines views.xml
create mode 100644 account_reconcile_oca/wizards/reconcile_multiple_lines.py
diff --git a/account_reconcile_oca/README.rst b/account_reconcile_oca/README.rst
index ceaf846b75..a3739ff3e9 100644
--- a/account_reconcile_oca/README.rst
+++ b/account_reconcile_oca/README.rst
@@ -7,7 +7,7 @@ Account Reconcile Oca
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- !! source digest: sha256:fa8f7f5af2e7a631cb39b699ebbc41f1bc6cca067be28665f5d4590c752f3054
+ !! source digest: sha256:b15b5402e37deee0e1b65e9884ddead837cf2813d7b85799d6f14994d06c00df
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
@@ -52,6 +52,14 @@ Access Invoicing / Accounting / Actions / Reconcile All the possible
reconcile options will show and you will be able to reconcile properly.
You can access the same widget from accounts and Partners.
+Applying a reconcilation model to multiple lines
+------------------------------------------------
+
+1. Select multiple transactions (account.bank.statement.line)
+2. Actions -> Reconcile with model
+3. In the wizard, select the model
+4. Run
+
Known issues / Roadmap
======================
@@ -82,6 +90,7 @@ Contributors
------------
- Enric Tobella
+- Simone Rubino
Maintainers
-----------
diff --git a/account_reconcile_oca/__init__.py b/account_reconcile_oca/__init__.py
index cc6b6354ad..a0f653930e 100644
--- a/account_reconcile_oca/__init__.py
+++ b/account_reconcile_oca/__init__.py
@@ -1,2 +1,3 @@
from . import models
+from . import wizards
from .hooks import post_init_hook
diff --git a/account_reconcile_oca/__manifest__.py b/account_reconcile_oca/__manifest__.py
index b34888a213..360aedea2f 100644
--- a/account_reconcile_oca/__manifest__.py
+++ b/account_reconcile_oca/__manifest__.py
@@ -25,6 +25,7 @@
"views/account_move.xml",
"views/account_account.xml",
"views/account_bank_statement.xml",
+ "wizards/reconcile_multiple_lines views.xml",
],
"demo": ["demo/demo.xml"],
"post_init_hook": "post_init_hook",
diff --git a/account_reconcile_oca/readme/CONTRIBUTORS.md b/account_reconcile_oca/readme/CONTRIBUTORS.md
index c84bf49d7c..2a3cbdd789 100644
--- a/account_reconcile_oca/readme/CONTRIBUTORS.md
+++ b/account_reconcile_oca/readme/CONTRIBUTORS.md
@@ -1 +1,2 @@
- Enric Tobella
+- Simone Rubino
diff --git a/account_reconcile_oca/readme/USAGE.md b/account_reconcile_oca/readme/USAGE.md
index 2a053a39f6..6c9ae7c496 100644
--- a/account_reconcile_oca/readme/USAGE.md
+++ b/account_reconcile_oca/readme/USAGE.md
@@ -8,3 +8,10 @@ capabilities. Select reconcile on the journal of your choice.
Access Invoicing / Accounting / Actions / Reconcile All the possible
reconcile options will show and you will be able to reconcile properly.
You can access the same widget from accounts and Partners.
+
+## Applying a reconcilation model to multiple lines
+
+1. Select multiple transactions (account.bank.statement.line)
+2. Actions -> Reconcile with model
+3. In the wizard, select the model
+4. Run
diff --git a/account_reconcile_oca/security/ir.model.access.csv b/account_reconcile_oca/security/ir.model.access.csv
index d73fa145dd..66529426c4 100644
--- a/account_reconcile_oca/security/ir.model.access.csv
+++ b/account_reconcile_oca/security/ir.model.access.csv
@@ -1,3 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_account_reconcile,account.account.reconcile,model_account_account_reconcile,account.group_account_user,1,1,0,0
access_account_account_reconcile_data,account.account.reconcile,model_account_account_reconcile_data,account.group_account_user,1,1,1,1
+account_reconcile_oca.access_account_reconcile_oca_reconcile_multiple_lines,Allow account user to reconcile multiple lines with a reconciliation model,account_reconcile_oca.model_account_reconcile_oca_reconcile_multiple_lines,account.group_account_user,1,1,1,1
diff --git a/account_reconcile_oca/static/description/index.html b/account_reconcile_oca/static/description/index.html
index 280f37dba3..56c1ff31ba 100644
--- a/account_reconcile_oca/static/description/index.html
+++ b/account_reconcile_oca/static/description/index.html
@@ -367,7 +367,7 @@ Account Reconcile Oca
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!! source digest: sha256:fa8f7f5af2e7a631cb39b699ebbc41f1bc6cca067be28665f5d4590c752f3054
+!! source digest: sha256:b15b5402e37deee0e1b65e9884ddead837cf2813d7b85799d6f14994d06c00df
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

This addon allows to reconcile bank statements and account marked as
@@ -378,14 +378,15 @@
Account Reconcile Oca
Usage
-Known issues / Roadmap
-Bug Tracker
-Credits
@@ -403,16 +404,25 @@
reconcile options will show and you will be able to reconcile properly.
You can access the same widget from accounts and Partners.
+
+
+
+- Select multiple transactions (account.bank.statement.line)
+- Actions -> Reconcile with model
+- In the wizard, select the model
+- Run
+
+
-
+
The following bugs are already detected:
- Creation of activities on the chatter do show automatically
-
+
Bugs are tracked on GitHub Issues.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
@@ -420,22 +430,23 @@
Do not contact contributors directly about support or help with technical issues.
-
+
-
+
- Enric Tobella
+- Simone Rubino
-
+
This module is maintained by the OCA.
diff --git a/account_reconcile_oca/tests/__init__.py b/account_reconcile_oca/tests/__init__.py
index 17f193edb5..d3a4dc27ac 100644
--- a/account_reconcile_oca/tests/__init__.py
+++ b/account_reconcile_oca/tests/__init__.py
@@ -1,2 +1,3 @@
from . import test_bank_account_reconcile
from . import test_account_reconcile
+from . import test_reconcile_multiple_lines
diff --git a/account_reconcile_oca/tests/test_reconcile_multiple_lines.py b/account_reconcile_oca/tests/test_reconcile_multiple_lines.py
new file mode 100644
index 0000000000..5b2aced62e
--- /dev/null
+++ b/account_reconcile_oca/tests/test_reconcile_multiple_lines.py
@@ -0,0 +1,88 @@
+# Copyright 2025 Simone Rubino
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import Command
+from odoo.tests import Form, tagged
+
+from odoo.addons.account_reconcile_model_oca.tests.common import (
+ TestAccountReconciliationCommon,
+)
+
+
+@tagged("post_install", "-at_install")
+class TestReconcileMultipleLines(TestAccountReconciliationCommon):
+ @classmethod
+ def setUpClass(cls, chart_template_ref=None):
+ super().setUpClass(chart_template_ref=chart_template_ref)
+ (cls.reconcile_account,) = cls.env["account.account"].create(
+ [
+ {
+ "name": "Test account for reconciliation",
+ "code": "TSTREC",
+ "account_type": "liability_payable",
+ }
+ ]
+ )
+
+ cls.bank_journal = cls.company_data["default_journal_bank"]
+ (
+ cls.bank_line_1,
+ cls.bank_line_2,
+ ) = cls.env["account.bank.statement.line"].create(
+ [
+ {
+ "journal_id": cls.bank_journal.id,
+ "date": "2020-01-01",
+ "amount": 100,
+ },
+ {
+ "journal_id": cls.bank_journal.id,
+ "date": "2020-01-01",
+ "amount": 600,
+ },
+ ],
+ )
+ (cls.reconcile_model,) = cls.env["account.reconcile.model"].create(
+ [
+ {
+ "name": "Test Writeoff",
+ "rule_type": "writeoff_button",
+ "line_ids": [
+ Command.create(
+ {
+ "account_id": cls.reconcile_account.id,
+ }
+ ),
+ ],
+ },
+ ]
+ )
+
+ def _get_wizard(self, statement_lines, reconcile_model):
+ selection_context = {
+ "active_model": statement_lines._name,
+ "active_ids": statement_lines.ids,
+ }
+ wizard_model = self.env[
+ "account_reconcile_oca.reconcile_multiple_lines"
+ ].with_context(**selection_context)
+ wizard_form = Form(wizard_model)
+ wizard_form.manual_model_id = reconcile_model
+ return wizard_form.save()
+
+ def test_writeoff_2_lines(self):
+ """The wizard can writeoff 2 statement lines."""
+ # Arrange
+ reconcile_account = self.reconcile_account
+ statement_lines = self.bank_line_1 | self.bank_line_2
+ writeoff_reconcile_model = self.reconcile_model
+ wizard = self._get_wizard(statement_lines, writeoff_reconcile_model)
+ # pre-condition
+ self.assertEqual(writeoff_reconcile_model.rule_type, "writeoff_button")
+ self.assertNotIn(reconcile_account, statement_lines.line_ids.account_id)
+
+ # Act
+ wizard.run()
+
+ # Assert
+ self.assertIn(reconcile_account, statement_lines.line_ids.account_id)
diff --git a/account_reconcile_oca/wizards/__init__.py b/account_reconcile_oca/wizards/__init__.py
new file mode 100644
index 0000000000..bc02c4a825
--- /dev/null
+++ b/account_reconcile_oca/wizards/__init__.py
@@ -0,0 +1,3 @@
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from . import reconcile_multiple_lines
diff --git a/account_reconcile_oca/wizards/reconcile_multiple_lines views.xml b/account_reconcile_oca/wizards/reconcile_multiple_lines views.xml
new file mode 100644
index 0000000000..edaefe50f6
--- /dev/null
+++ b/account_reconcile_oca/wizards/reconcile_multiple_lines views.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+ Form view to reconcile multiple lines with a reconciliation model
+ account_reconcile_oca.reconcile_multiple_lines
+
+
+
+
+
+
+ Reconcile with model
+ account_reconcile_oca.reconcile_multiple_lines
+ form
+ new
+
+
+
diff --git a/account_reconcile_oca/wizards/reconcile_multiple_lines.py b/account_reconcile_oca/wizards/reconcile_multiple_lines.py
new file mode 100644
index 0000000000..a37b6fc364
--- /dev/null
+++ b/account_reconcile_oca/wizards/reconcile_multiple_lines.py
@@ -0,0 +1,46 @@
+# Copyright 2025 Simone Rubino
+# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
+
+from odoo import _, fields, models
+from odoo.exceptions import UserError
+
+
+class ReconcileMultipleLines(models.TransientModel):
+ _name = "account_reconcile_oca.reconcile_multiple_lines"
+ _description = "Reconcile multiple lines with a reconciliation model"
+
+ manual_model_id = fields.Many2one(
+ comodel_name="account.reconcile.model",
+ required=True,
+ )
+
+ def _get_statement_lines(self):
+ model = self.env.context.get("active_model")
+ ids = self.env.context.get("active_ids")
+ statement_lines = self.env[model].browse(ids)
+ return statement_lines
+
+ def _apply_model_to_line(self, reconciliation_model, statement_line):
+ reconciliation_model.ensure_one()
+ statement_line.ensure_one()
+ partner = reconciliation_model._get_partner_from_mapping(statement_line)
+ if not reconciliation_model._is_applicable_for(statement_line, partner):
+ raise UserError(
+ _(
+ "Reconcilation model %(model)s "
+ "cannot be applied to line %(line)s.\n"
+ "Please select a compatible reconciliation model "
+ "or deselect the line.",
+ model=reconciliation_model.display_name,
+ line=statement_line.display_name,
+ )
+ )
+ statement_line.manual_model_id = reconciliation_model
+ statement_line._onchange_manual_model_id()
+ statement_line.reconcile_bank_line()
+
+ def run(self):
+ statement_lines = self._get_statement_lines()
+ reconciliation_model = self.manual_model_id
+ for line in statement_lines:
+ self._apply_model_to_line(reconciliation_model, line)