From ab50455ad3d11d91a3b393d8c9ed99a0e8641b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phan=20Sainl=C3=A9ger?= Date: Tue, 4 Aug 2026 12:02:47 +0200 Subject: [PATCH] [MIG] account_chorus_notify: migrate to 18.0 --- account_chorus_notify/README.md | 32 ++++++ account_chorus_notify/__init__.py | 2 + account_chorus_notify/__manifest__.py | 75 +++++++++++++ account_chorus_notify/models/__init__.py | 2 + account_chorus_notify/models/chorus_flow.py | 14 +++ account_chorus_notify/tests/__init__.py | 1 + .../tests/test_chorus_notify.py | 100 ++++++++++++++++++ 7 files changed, 226 insertions(+) create mode 100644 account_chorus_notify/README.md create mode 100644 account_chorus_notify/__init__.py create mode 100644 account_chorus_notify/__manifest__.py create mode 100644 account_chorus_notify/models/__init__.py create mode 100644 account_chorus_notify/models/chorus_flow.py create mode 100644 account_chorus_notify/tests/__init__.py create mode 100644 account_chorus_notify/tests/test_chorus_notify.py diff --git a/account_chorus_notify/README.md b/account_chorus_notify/README.md new file mode 100644 index 0000000..5620fe0 --- /dev/null +++ b/account_chorus_notify/README.md @@ -0,0 +1,32 @@ +# account_chorus_notify + +Posts a notification on supplier invoices when their Chorus flow is rejected. + +Override of `chorus.flow.update_flow_status()`: when a flow status becomes `IN_REJETE`, a message is posted on each related invoice (`invoice_ids`) with the flow reference. + +## Installation + +Make sure `l10n_fr_chorus_account` is available, then use the standard Odoo module installation procedure to install `account_chorus_notify`. + +## Known issues / Roadmap + +None yet. + +## Bug Tracker + +Bugs are tracked on [our issues website](https://github.com/elabore-coop/account-tools/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. + +## Credits + +### Contributors + +* Stéphan Sainléger - [Github](https://github.com/stephansainleger) + +### Funders + +The development of this module has been financially supported by: +* [Elabore](https://elabore.coop) + +### Maintainer + +This module is maintained by Elabore. \ No newline at end of file diff --git a/account_chorus_notify/__init__.py b/account_chorus_notify/__init__.py new file mode 100644 index 0000000..a9e3372 --- /dev/null +++ b/account_chorus_notify/__init__.py @@ -0,0 +1,2 @@ + +from . import models diff --git a/account_chorus_notify/__manifest__.py b/account_chorus_notify/__manifest__.py new file mode 100644 index 0000000..c062a39 --- /dev/null +++ b/account_chorus_notify/__manifest__.py @@ -0,0 +1,75 @@ +# Copyright 2021 Elabore () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "account_chorus_notify", + "version": "18.0.1.0.0", + "author": "Elabore", + "maintainer": "False", + "website": "False", + "license": "AGPL-3", + "category": "False", + "summary": "Send notification when chorus invoice failed", + "description": """ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +======================= +Account Chorus Notify +======================= +Send notification when chorus invoice failed + +Installation +============ +Just install account_chorus_notify, all dependencies will be installed by default. + +Known issues / Roadmap +====================== + +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. + +Credits +======= + +Images +------ +* Elabore: `Icon `_. + + +Funders +------- +The development of this module has been financially supported by: +* Elabore (https://elabore.coop) + +Maintainer +---------- +This module is maintained by ELABORE. + +""", + # any module necessary for this one to work correctly + "depends": [ + "l10n_fr_chorus_account", + ], + "external_dependencies": { + "python": [], + }, + # always loaded + "data": [ + + ], + # only loaded in demonstration mode + "demo": [], + "js": [], + "css": [], + "qweb": [], + "installable": True, + # Install this module automatically if all dependency have been previously + # and independently installed. Used for synergetic or glue modules. + "auto_install": False, + "application": False, +} diff --git a/account_chorus_notify/models/__init__.py b/account_chorus_notify/models/__init__.py new file mode 100644 index 0000000..5861b1f --- /dev/null +++ b/account_chorus_notify/models/__init__.py @@ -0,0 +1,2 @@ + +from . import chorus_flow \ No newline at end of file diff --git a/account_chorus_notify/models/chorus_flow.py b/account_chorus_notify/models/chorus_flow.py new file mode 100644 index 0000000..351abcb --- /dev/null +++ b/account_chorus_notify/models/chorus_flow.py @@ -0,0 +1,14 @@ + +from odoo import models, fields, api, _ + + +class ChorusFlow(models.Model): + _inherit = "chorus.flow" + + def update_flow_status(self): + res = super(ChorusFlow, self).update_flow_status() + for flow in self: + if flow.status == 'IN_REJETE': + for invoice in flow.invoice_ids: + invoice.message_post(body=_("Chorus flow n°%s rejected.")%(flow.name,)) + return res \ No newline at end of file diff --git a/account_chorus_notify/tests/__init__.py b/account_chorus_notify/tests/__init__.py new file mode 100644 index 0000000..54e6d4b --- /dev/null +++ b/account_chorus_notify/tests/__init__.py @@ -0,0 +1 @@ +from . import test_chorus_notify \ No newline at end of file diff --git a/account_chorus_notify/tests/test_chorus_notify.py b/account_chorus_notify/tests/test_chorus_notify.py new file mode 100644 index 0000000..4ddb050 --- /dev/null +++ b/account_chorus_notify/tests/test_chorus_notify.py @@ -0,0 +1,100 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import Command, fields +from odoo.tests.common import TransactionCase + + +class TestChorusNotify(TransactionCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.company = cls.env.ref('base.main_company') + cls.partner = cls.env['res.partner'].create({ + 'name': 'Test Vendor', + 'company_id': cls.company.id, + }) + + cls.expense_account = cls.env['account.account'].create({ + 'code': '6TEST001', + 'name': 'Test Expense', + 'account_type': 'expense', + }) + + cls.journal = cls.env['account.journal'].create({ + 'name': 'Test Purchase', + 'type': 'purchase', + 'code': 'PURCH', + }) + + cls.flow = cls.env['chorus.flow'].create({ + 'name': 'TEST-FLOW-001', + 'date': fields.Date.today(), + 'company_id': cls.company.id, + }) + + cls.invoice = cls.env['account.move'].create({ + 'move_type': 'in_invoice', + 'journal_id': cls.journal.id, + 'partner_id': cls.partner.id, + 'invoice_date': fields.Date.today(), + 'chorus_flow_id': cls.flow.id, + 'invoice_line_ids': [Command.create({ + 'name': 'Test line', + 'price_unit': 100, + 'quantity': 1, + 'account_id': cls.expense_account.id, + })], + }) + + def _patch_chorus_api(self, status): + self.patch( + type(self.env['res.company']), + '_chorus_get_api_params', + lambda self, raise_if_ko=True: {'dummy': True}, + ) + self.patch( + type(self.env['chorus.flow']), + '_chorus_api_consulter_cr', + lambda self, api_params, session=None: ( + {'status': status, 'notes': ''}, session, + ), + ) + + def _assert_rejection_message(self, invoice, flow_name, expected=True): + messages = invoice.message_ids.filtered( + lambda m: 'Chorus flow n°%s rejected.' % flow_name in (m.body or '') + ) + if expected: + self.assertTrue( + messages, + "A rejection message should be posted on invoice %s" % invoice.name, + ) + else: + self.assertFalse( + messages, + "No rejection message expected on invoice %s" % invoice.name, + ) + + def test_flow_rejected_notifies_invoice(self): + self._patch_chorus_api('IN_REJETE') + self.flow.update_flow_status() + self.assertEqual(self.flow.status, 'IN_REJETE') + self._assert_rejection_message(self.invoice, 'TEST-FLOW-001') + + def test_flow_accepted_does_not_notify(self): + self._patch_chorus_api('IN_INTEGRE') + self.flow.update_flow_status() + self.assertEqual(self.flow.status, 'IN_INTEGRE') + self._assert_rejection_message(self.invoice, 'TEST-FLOW-001', expected=False) + + def test_flow_rejected_no_invoices(self): + flow2 = self.env['chorus.flow'].create({ + 'name': 'TEST-FLOW-002', + 'date': fields.Date.today(), + 'company_id': self.company.id, + }) + self._patch_chorus_api('IN_REJETE') + flow2.update_flow_status() + self.assertEqual(flow2.status, 'IN_REJETE')