diff --git a/account_reconcile_payment_order/README.rst b/account_reconcile_payment_order/README.rst new file mode 100644 index 0000000000..1afe2670fc --- /dev/null +++ b/account_reconcile_payment_order/README.rst @@ -0,0 +1,78 @@ +=============================== +Account Reconcile Payment Order +=============================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:62593d3c4026a4022d861045e7c9cd3fa56484718450a6e7d52325acb833b6e4 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Faccount--reconcile-lightgray.png?logo=github + :target: https://github.com/OCA/account-reconcile/tree/16.0/account_reconcile_payment_order + :alt: OCA/account-reconcile +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/account-reconcile-16-0/account-reconcile-16-0-account_reconcile_payment_order + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/account-reconcile&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to show the payment orders directly on the recocncile +widget. This way, we can select or unselect automatically all the lines +of the payment order. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Dixmit + +Contributors +------------ + +- Enric Tobella (`www.dixmit.com `__) + +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/account-reconcile `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/account_reconcile_payment_order/__init__.py b/account_reconcile_payment_order/__init__.py new file mode 100644 index 0000000000..cc6b6354ad --- /dev/null +++ b/account_reconcile_payment_order/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import post_init_hook diff --git a/account_reconcile_payment_order/__manifest__.py b/account_reconcile_payment_order/__manifest__.py new file mode 100644 index 0000000000..9ecfa61356 --- /dev/null +++ b/account_reconcile_payment_order/__manifest__.py @@ -0,0 +1,27 @@ +# Copyright 2024 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Account Reconcile Payment Order", + "summary": """ + Allow to reconcile payment order on reconcile widget""", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "Dixmit,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/account-reconcile", + "depends": ["account_reconcile_oca", "account_payment_order"], + "data": [ + "security/security.xml", + "security/ir.model.access.csv", + "views/account_payment_order_maturity.xml", + "views/account_bank_statement_line.xml", + ], + "assets": { + "web.assets_backend": [ + "account_reconcile_payment_order/static/src/**/*.esm.js", + "account_reconcile_payment_order/static/src/**/*.xml", + ] + }, + "post_init_hook": "post_init_hook", + "demo": [], +} diff --git a/account_reconcile_payment_order/hooks.py b/account_reconcile_payment_order/hooks.py new file mode 100644 index 0000000000..a718465e32 --- /dev/null +++ b/account_reconcile_payment_order/hooks.py @@ -0,0 +1,61 @@ +# Copyright 2023 ForgeFlow S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import SUPERUSER_ID, api + + +def post_init_hook(cr, registry): + cr.execute( + """ + INSERT INTO account_payment_order_maturity ( + payment_order_id, + date, + currency_id, + company_id, + payment_type, + is_matched + ) + SELECT + apo.id, + apl.date, + ap.currency_id, + apo.company_id, + apo.payment_type, + bool_and(ap.is_matched) + FROM + account_payment_order apo + INNER JOIN account_payment ap + ON ap.payment_order_id = apo.id + INNER JOIN account_payment_account_payment_line_rel apaplr + ON apaplr.account_payment_id = ap.id + INNER JOIN account_payment_line apl + ON apl.id = apaplr.account_payment_line_id + INNER JOIN account_move_line aml + ON aml.move_id = ap.move_id + INNER JOIN account_account aa + ON aa.id = aml.account_id + WHERE apo.state = 'uploaded' + GROUP BY apo.id, apl.date, ap.currency_id + """ + ) + cr.execute( + """ + UPDATE account_payment ap + SET maturity_order_id = apom.id + FROM account_payment_order_maturity apom + INNER JOIN account_payment_line apl + ON apl.order_id = apom.payment_order_id + INNER JOIN account_payment_account_payment_line_rel apaplr + ON apl.id = apaplr.account_payment_line_id + WHERE + apaplr.account_payment_id = ap.id + AND apom.date = apl.date + AND apom.currency_id = ap.currency_id + """ + ) + env = api.Environment(cr, SUPERUSER_ID, {}) + + # We assume that there will not be too many records to process + env["account.payment.order.maturity"].search( + [("is_matched", "=", False)] + )._compute_matched_info() diff --git a/account_reconcile_payment_order/models/__init__.py b/account_reconcile_payment_order/models/__init__.py new file mode 100644 index 0000000000..a591b8eea1 --- /dev/null +++ b/account_reconcile_payment_order/models/__init__.py @@ -0,0 +1,4 @@ +from . import account_bank_statement_line +from . import account_payment_order +from . import account_payment_order_maturity +from . import account_payment diff --git a/account_reconcile_payment_order/models/account_bank_statement_line.py b/account_reconcile_payment_order/models/account_bank_statement_line.py new file mode 100644 index 0000000000..6c4eb6ad57 --- /dev/null +++ b/account_reconcile_payment_order/models/account_bank_statement_line.py @@ -0,0 +1,121 @@ +# Copyright 2024 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class AccountBankStatementLine(models.Model): + + _inherit = "account.bank.statement.line" + + payment_type_filter = fields.Selection( + selection=lambda r: r.env["account.payment.order"] + ._fields["payment_type"] + .selection, + compute="_compute_payment_type_filter", + ) + add_payment_order_id = fields.Many2one( + "account.payment.order.maturity", + check_company=True, + store=False, + default=False, + prefetch=False, + ) + + @api.depends() + def _compute_payment_type_filter(self): + for record in self: + record.payment_type_filter = "inbound" if record.amount > 0 else "outbound" + + def clean_reconcile(self): + """ + Remove the counterparts when cleaning + """ + res = super().clean_reconcile() + data = self.reconcile_data_info + data["order_counterparts"] = [] + self.reconcile_data_info = data + return res + + @api.onchange("add_payment_order_id") + def _onchange_add_payment_order_id(self): + """ + We need to check if the payment order is in already on the counterpart. + In this case we need to add all the liquidity lines. Otherwise, we remove them + """ + if self.add_payment_order_id: + data = self.reconcile_data_info["data"] + if self.add_payment_order_id.id not in self.reconcile_data_info.get( + "order_counterparts", [] + ): + new_data = [] + counterparts = [] + for line in data: + counterparts += line.get("counterpart_line_ids", []) + new_data.append(line) + for payment in self.add_payment_order_id.payment_ids.filtered( + lambda r: not r.is_matched + ): + ( + liquidity_lines, + counterpart_lines, + writeoff_lines, + ) = payment._seek_for_lines() + for line in liquidity_lines.filtered( + lambda r: r.id not in counterparts + ): + reconcile_auxiliary_id, lines = self._get_reconcile_line( + line, "other", True, 0.0 + ) + new_data += lines + data_info = self._recompute_suspense_line( + new_data, + self.reconcile_data_info["reconcile_auxiliary_id"], + self.manual_reference, + ) + data_info["order_counterparts"].append(self.add_payment_order_id.id) + self.reconcile_data_info = data_info + elif self.add_payment_order_id: + data = self.reconcile_data_info["data"] + lines = [] + for payment in self.add_payment_order_id.payment_ids.filtered( + lambda r: not r.is_matched + ): + ( + liquidity_lines, + counterpart_lines, + writeoff_lines, + ) = payment._seek_for_lines() + lines += liquidity_lines.ids + new_data = [] + for line in data: + if set(line.get("counterpart_line_ids", [])).intersection( + set(lines) + ): + continue + new_data.append(line) + data_info = self._recompute_suspense_line( + new_data, + self.reconcile_data_info["reconcile_auxiliary_id"], + self.manual_reference, + ) + ["order_counterparts"].append(self.add_payment_order_id.id) + counterparts = set(data_info["order_counterparts"]) + counterparts.remove(self.add_payment_order_id.id) + data_info["order_counterparts"] = list(counterparts) + self.reconcile_data_info = data_info + self.add_payment_order_id = False + + def _recompute_suspense_line(self, data, reconcile_auxiliary_id, manual_reference): + """ + We want to keep the counterpart when we recompute + """ + order_counterparts = ( + self.reconcile_data_info + and self.reconcile_data_info.get("order_counterparts", []) + ) or [] + result = super()._recompute_suspense_line( + data, reconcile_auxiliary_id, manual_reference + ) + result["order_counterparts"] = order_counterparts + return result diff --git a/account_reconcile_payment_order/models/account_payment.py b/account_reconcile_payment_order/models/account_payment.py new file mode 100644 index 0000000000..d9e620f38c --- /dev/null +++ b/account_reconcile_payment_order/models/account_payment.py @@ -0,0 +1,11 @@ +# Copyright 2024 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountPayment(models.Model): + + _inherit = "account.payment" + + maturity_order_id = fields.Many2one(comodel_name="account.payment.order.maturity") diff --git a/account_reconcile_payment_order/models/account_payment_order.py b/account_reconcile_payment_order/models/account_payment_order.py new file mode 100644 index 0000000000..cdc33b1cb6 --- /dev/null +++ b/account_reconcile_payment_order/models/account_payment_order.py @@ -0,0 +1,48 @@ +# Copyright 2024 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from itertools import groupby + +from odoo import fields, models + + +class AccountPaymentOrder(models.Model): + + _inherit = "account.payment.order" + + maturity_order_ids = fields.One2many( + comodel_name="account.payment.order.maturity", inverse_name="payment_order_id" + ) + + def generated2uploaded(self): + result = super().generated2uploaded() + for record in self: + vals = sorted( + self.payment_ids.read(["id", "payment_line_date", "currency_id"]), + key=lambda r: (r["payment_line_date"], r["currency_id"][0]), + ) + for key, _group in groupby( + vals, lambda x: (x["payment_line_date"], x["currency_id"][0]) + ): + self.env["account.payment.order.maturity"].create( + { + "payment_order_id": record.id, + "currency_id": key[1], + "date": key[0], + "payment_ids": [ + ( + 6, + 0, + record.payment_ids.filtered( + lambda r: r.payment_line_date == key[0] + and r.currency_id.id == key[1] + ).ids, + ) + ], + } + ) + return result + + def action_uploaded_cancel(self): + self.maturity_order_ids.unlink() + return super().action_cancel() diff --git a/account_reconcile_payment_order/models/account_payment_order_maturity.py b/account_reconcile_payment_order/models/account_payment_order_maturity.py new file mode 100644 index 0000000000..d1b244d47f --- /dev/null +++ b/account_reconcile_payment_order/models/account_payment_order_maturity.py @@ -0,0 +1,52 @@ +# Copyright 2024 Dixmit +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class AccountPaymentOrderMaturity(models.Model): + + _name = "account.payment.order.maturity" + _description = "Account Payment Order Maturity" # TODO + + payment_order_id = fields.Many2one( + "account.payment.order", required=True, ondelete="cascade" + ) + currency_id = fields.Many2one("res.currency", required=True) + date = fields.Date(required=True) + company_id = fields.Many2one( + "res.company", related="payment_order_id.company_id", store=True + ) + payment_ids = fields.One2many("account.payment", inverse_name="maturity_order_id") + payment_type = fields.Selection(related="payment_order_id.payment_type", store=True) + is_matched = fields.Boolean(compute="_compute_matched_info", store=True) + amount_residual = fields.Monetary( + compute="_compute_matched_info", store=True, currency_field="currency_id" + ) + + @api.depends( + "payment_ids", + "payment_ids.is_matched", + "payment_ids.move_id.line_ids.amount_residual", + ) + def _compute_matched_info(self): + for record in self: + record.is_matched = all(record.mapped("payment_ids.is_matched")) + residual_field = ( + "amount_residual" + if record.currency_id == record.company_id.currency_id + else "amount_residual_currency" + ) + amount_residual = 0.0 + for pay in record.mapped("payment_ids"): + ( + liquidity_lines, + counterpart_lines, + writeoff_lines, + ) = pay._seek_for_lines() + amount_residual += sum(liquidity_lines.mapped(residual_field)) + record.amount_residual = amount_residual + + def action_view_order(self): + self.ensure_one() + return self.payment_order_id.get_formview_action() diff --git a/account_reconcile_payment_order/readme/CONTRIBUTORS.md b/account_reconcile_payment_order/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..53bc70c0c5 --- /dev/null +++ b/account_reconcile_payment_order/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Enric Tobella (www.dixmit.com) diff --git a/account_reconcile_payment_order/readme/DESCRIPTION.md b/account_reconcile_payment_order/readme/DESCRIPTION.md new file mode 100644 index 0000000000..6291ce8615 --- /dev/null +++ b/account_reconcile_payment_order/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This module allows to show the payment orders directly on the recocncile widget. +This way, we can select or unselect automatically all the lines of the payment order. diff --git a/account_reconcile_payment_order/security/ir.model.access.csv b/account_reconcile_payment_order/security/ir.model.access.csv new file mode 100644 index 0000000000..5b710f1042 --- /dev/null +++ b/account_reconcile_payment_order/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_account_payment_order_maturity,account.account_paymenbt_order_maturity,model_account_payment_order_maturity,account.group_account_user,1,1,1,1 diff --git a/account_reconcile_payment_order/security/security.xml b/account_reconcile_payment_order/security/security.xml new file mode 100644 index 0000000000..6496f8ce53 --- /dev/null +++ b/account_reconcile_payment_order/security/security.xml @@ -0,0 +1,12 @@ + + + + payment_order_maturity_company_rule + + [('company_id', 'in', company_ids)] + + + + + + diff --git a/account_reconcile_payment_order/static/description/icon.png b/account_reconcile_payment_order/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/account_reconcile_payment_order/static/description/icon.png differ diff --git a/account_reconcile_payment_order/static/description/index.html b/account_reconcile_payment_order/static/description/index.html new file mode 100644 index 0000000000..69dbed6f99 --- /dev/null +++ b/account_reconcile_payment_order/static/description/index.html @@ -0,0 +1,425 @@ + + + + + +Account Reconcile Payment Order + + + +
+

Account Reconcile Payment Order

+ + +

Beta License: AGPL-3 OCA/account-reconcile Translate me on Weblate Try me on Runboat

+

This module allows to show the payment orders directly on the recocncile +widget. This way, we can select or unselect automatically all the lines +of the payment order.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Dixmit
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

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

+

This module is part of the OCA/account-reconcile project on GitHub.

+

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

+
+
+
+ + diff --git a/account_reconcile_payment_order/tests/__init__.py b/account_reconcile_payment_order/tests/__init__.py new file mode 100644 index 0000000000..78da099c10 --- /dev/null +++ b/account_reconcile_payment_order/tests/__init__.py @@ -0,0 +1 @@ +from . import test_bank_account_reconcile diff --git a/account_reconcile_payment_order/tests/test_bank_account_reconcile.py b/account_reconcile_payment_order/tests/test_bank_account_reconcile.py new file mode 100644 index 0000000000..6562b890bc --- /dev/null +++ b/account_reconcile_payment_order/tests/test_bank_account_reconcile.py @@ -0,0 +1,247 @@ +import time + +from odoo.tests import Form, tagged + +from odoo.addons.account.tests.common import TestAccountReconciliationCommon + + +@tagged("post_install", "-at_install") +class TestReconciliationWidget(TestAccountReconciliationCommon): + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + + cls.acc_bank_stmt_model = cls.env["account.bank.statement"] + cls.acc_bank_stmt_line_model = cls.env["account.bank.statement.line"] + cls.bank_journal_usd.suspense_account_id = ( + cls.company.account_journal_suspense_account_id + ) + cls.bank_journal_euro.suspense_account_id = ( + cls.company.account_journal_suspense_account_id + ) + cls.current_assets_account = cls.env["account.account"].search( + [ + ("account_type", "=", "asset_current"), + ("company_id", "=", cls.company.id), + ], + limit=1, + ) + cls.current_assets_account.reconcile = True + + cls.rule = cls.env["account.reconcile.model"].create( + { + "name": "write-off model", + "rule_type": "writeoff_button", + "match_partner": True, + "match_partner_ids": [], + "line_ids": [(0, 0, {"account_id": cls.current_assets_account.id})], + } + ) + cls.tax_10 = cls.env["account.tax"].create( + { + "name": "tax_10", + "amount_type": "percent", + "amount": 10.0, + } + ) + # We need to make some fields visible in order to make the tests work + cls.env["ir.ui.view"].create( + { + "name": "DEMO Account bank statement", + "model": "account.bank.statement.line", + "inherit_id": cls.env.ref( + "account_reconcile_oca.bank_statement_line_form_reconcile_view" + ).id, + "arch": """ + + + 0 + + + 0 + + + 0 + + + """, + } + ) + cls.inbound_mode = cls.env["account.payment.mode"].create( + { + "name": "Test Direct Debit of customers", + "bank_account_link": "variable", + "payment_method_id": cls.env.ref( + "account.account_payment_method_manual_in" + ).id, + "company_id": cls.company.id, + } + ) + cls.inbound_order = cls.env["account.payment.order"].create( + { + "payment_type": "inbound", + "payment_mode_id": cls.inbound_mode.id, + "journal_id": cls.bank_journal_usd.id, + } + ) + cls.outbound_mode = cls.env["account.payment.mode"].create( + { + "name": "Test Direct Debit of customers", + "bank_account_link": "variable", + "payment_method_id": cls.env.ref( + "account.account_payment_method_manual_out" + ).id, + "company_id": cls.company.id, + } + ) + cls.outbound_order = cls.env["account.payment.order"].create( + { + "payment_type": "outbound", + "payment_mode_id": cls.outbound_mode.id, + "journal_id": cls.bank_journal_usd.id, + } + ) + cls.partner = cls.env["res.partner"].create({"name": "other partner"}) + + def create_invoice_order(self, order, partner_id=False): + # Create invoice + move_type = "in_invoice" + if order.payment_type == "inbound": + move_type = "out_invoice" + invoice = self._create_invoice( + move_type=move_type, + partner_id=partner_id, + invoice_amount=100, + auto_validate=True, + ) + # Add to payment order using the + invoice.payment_mode_id = order.payment_mode_id + invoice.ref = "My Reference" + self.env["account.invoice.payment.line.multi"].with_context( + active_model="account.move", active_ids=invoice.ids + ).create({}).run() + return invoice + + def test_inbound(self): + invoice = self.create_invoice_order(self.inbound_order) + invoice2 = self.create_invoice_order( + self.inbound_order, partner_id=self.partner.id + ) + self.inbound_order.draft2open() + self.inbound_order.open2generated() + self.inbound_order.generated2uploaded() + self.assertEqual(invoice.payment_state, "in_payment") + self.assertEqual(invoice2.payment_state, "in_payment") + self.assertEqual(2, len(self.inbound_order.payment_ids)) + self.assertEqual(1, len(self.inbound_order.maturity_order_ids)) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 200, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_payment_order_id = self.inbound_order.maturity_order_ids + self.assertTrue(bank_stmt_line.can_reconcile) + self.assertTrue(bank_stmt_line.can_reconcile) + bank_stmt_line.reconcile_bank_line() + self.assertEqual(invoice.payment_state, "paid") + self.assertEqual(invoice2.payment_state, "paid") + + def test_inbound_unselect(self): + invoice = self.create_invoice_order(self.inbound_order) + invoice2 = self.create_invoice_order( + self.inbound_order, partner_id=self.partner.id + ) + self.inbound_order.draft2open() + self.inbound_order.open2generated() + self.inbound_order.generated2uploaded() + self.assertEqual(invoice.payment_state, "in_payment") + self.assertEqual(invoice2.payment_state, "in_payment") + self.assertEqual(2, len(self.inbound_order.payment_ids)) + self.assertEqual(1, len(self.inbound_order.maturity_order_ids)) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": 200, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_payment_order_id = self.inbound_order.maturity_order_ids + self.assertTrue(bank_stmt_line.can_reconcile) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + f.add_payment_order_id = self.inbound_order.maturity_order_ids + self.assertFalse(bank_stmt_line.can_reconcile) + + def test_outbound(self): + invoice = self.create_invoice_order(self.outbound_order) + invoice2 = self.create_invoice_order( + self.outbound_order, partner_id=self.partner.id + ) + self.outbound_order.draft2open() + self.outbound_order.open2generated() + self.outbound_order.generated2uploaded() + self.assertEqual(invoice.payment_state, "in_payment") + self.assertEqual(invoice2.payment_state, "in_payment") + self.assertEqual(2, len(self.outbound_order.payment_ids)) + self.assertEqual(1, len(self.outbound_order.maturity_order_ids)) + bank_stmt = self.acc_bank_stmt_model.create( + { + "company_id": self.env.ref("base.main_company").id, + "journal_id": self.bank_journal_euro.id, + "date": time.strftime("%Y-07-15"), + "name": "test", + } + ) + bank_stmt_line = self.acc_bank_stmt_line_model.create( + { + "name": "testLine", + "journal_id": self.bank_journal_euro.id, + "statement_id": bank_stmt.id, + "amount": -200, + "date": time.strftime("%Y-07-15"), + } + ) + with Form( + bank_stmt_line, + view="account_reconcile_oca.bank_statement_line_form_reconcile_view", + ) as f: + self.assertFalse(f.can_reconcile) + f.add_payment_order_id = self.outbound_order.maturity_order_ids + self.assertTrue(bank_stmt_line.can_reconcile) + bank_stmt_line.reconcile_bank_line() + self.assertEqual(invoice.payment_state, "paid") + self.assertEqual(invoice2.payment_state, "paid") diff --git a/account_reconcile_payment_order/views/account_bank_statement_line.xml b/account_reconcile_payment_order/views/account_bank_statement_line.xml new file mode 100644 index 0000000000..7b2a792fc3 --- /dev/null +++ b/account_reconcile_payment_order/views/account_bank_statement_line.xml @@ -0,0 +1,34 @@ + + + + + + account.bank.statement.line + + + + + + + + + + + + + + diff --git a/account_reconcile_payment_order/views/account_payment_order.xml b/account_reconcile_payment_order/views/account_payment_order.xml new file mode 100644 index 0000000000..6bc61134c9 --- /dev/null +++ b/account_reconcile_payment_order/views/account_payment_order.xml @@ -0,0 +1,16 @@ + + + + + + account.payment.order + + + + + + + + + diff --git a/account_reconcile_payment_order/views/account_payment_order_maturity.xml b/account_reconcile_payment_order/views/account_payment_order_maturity.xml new file mode 100644 index 0000000000..97ea2ec091 --- /dev/null +++ b/account_reconcile_payment_order/views/account_payment_order_maturity.xml @@ -0,0 +1,60 @@ + + + + + + account.payment.order.maturity + +
+
+ + + + + + + + + + + + account.payment.order.maturity + + + + + + + + + + + + + account.payment.order.maturity + + + + + + +