Skip to content

Commit ff4e9d5

Browse files
[IMP] account_invoice_overdue_reminder: add tests
1 parent 01a0171 commit ff4e9d5

File tree

7 files changed

+739
-0
lines changed

7 files changed

+739
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Copyright 2026 NICO SOLUTIONS - ENGINEERING & IT, Nils Coenen
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from . import test_account_invoice_overdue_reminder
4+
from . import test_account_move
5+
from . import test_overdue_reminder_action
6+
from . import test_overdue_reminder_start
7+
from . import test_overdue_reminder_step
8+
from . import test_overdue_reminder_mass_update
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Copyright 2026 NICO SOLUTIONS - ENGINEERING & IT, Nils Coenen
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from odoo.exceptions import ValidationError
4+
from odoo.tests.common import TransactionCase
5+
6+
7+
class TestAccountInvoiceOverdueReminder(TransactionCase):
8+
@classmethod
9+
def setUpClass(cls):
10+
super().setUpClass()
11+
cls.partner = cls.env["res.partner"].create({"name": "Test Customer"})
12+
cls.invoice = cls.env["account.move"].create(
13+
{
14+
"move_type": "out_invoice",
15+
"partner_id": cls.partner.id,
16+
"invoice_line_ids": [
17+
(
18+
0,
19+
0,
20+
{
21+
"name": "Test line",
22+
"quantity": 1,
23+
"price_unit": 100,
24+
},
25+
)
26+
],
27+
}
28+
)
29+
cls.invalid_invoice = cls.env["account.move"].create(
30+
{
31+
"move_type": "in_invoice",
32+
"partner_id": cls.partner.id,
33+
"invoice_line_ids": [
34+
(
35+
0,
36+
0,
37+
{
38+
"name": "Vendor line",
39+
"quantity": 1,
40+
"price_unit": 100,
41+
},
42+
)
43+
],
44+
}
45+
)
46+
cls.reminder_action = cls.env["overdue.reminder.action"].create(
47+
{
48+
"commercial_partner_id": cls.partner.id,
49+
"partner_id": cls.partner.id,
50+
"date": "2024-01-01",
51+
"user_id": cls.env.ref("base.user_admin").id,
52+
"reminder_type": "mail",
53+
}
54+
)
55+
56+
def test_accept_out_invoice(self):
57+
rec = self.env["account.invoice.overdue.reminder"].create(
58+
{
59+
"invoice_id": self.invoice.id,
60+
"action_id": self.reminder_action.id,
61+
"counter": 1,
62+
}
63+
)
64+
self.assertTrue(rec.exists())
65+
self.assertEqual(rec.counter, 1)
66+
67+
def test_display_name_compute(self):
68+
rec = self.env["account.invoice.overdue.reminder"].create(
69+
{
70+
"invoice_id": self.invoice.id,
71+
"action_id": self.reminder_action.id,
72+
"counter": 3,
73+
}
74+
)
75+
rec._compute_display_name()
76+
expected = f"{self.invoice.name} Reminder n°3"
77+
self.assertEqual(rec.display_name, expected)
78+
79+
def test_reject_in_invoice(self):
80+
with self.assertRaises(ValidationError):
81+
self.env["account.invoice.overdue.reminder"].create(
82+
{
83+
"invoice_id": self.invalid_invoice.id,
84+
"action_id": self.reminder_action.id,
85+
"counter": 1,
86+
}
87+
)
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# Copyright 2026 NICO SOLUTIONS - ENGINEERING & IT, Nils Coenen
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from dateutil.relativedelta import relativedelta
4+
5+
from odoo import fields
6+
from odoo.tests.common import TransactionCase
7+
8+
9+
class TestAccountMove(TransactionCase):
10+
@classmethod
11+
def setUpClass(cls):
12+
super().setUpClass()
13+
cls.partner = cls.env["res.partner"].create({"name": "Test Customer"})
14+
cls.company = cls.env.company
15+
cls.overdue_invoice = cls.env["account.move"].create(
16+
{
17+
"move_type": "out_invoice",
18+
"partner_id": cls.partner.id,
19+
"invoice_date_due": fields.Date.today() - relativedelta(days=5),
20+
"invoice_line_ids": [
21+
(
22+
0,
23+
0,
24+
{
25+
"name": "Test line overdue",
26+
"quantity": 1,
27+
"price_unit": 100,
28+
},
29+
)
30+
],
31+
"company_id": cls.company.id,
32+
}
33+
)
34+
cls.overdue_invoice.action_post()
35+
cls.overdue_invoice.payment_state = "not_paid"
36+
37+
cls.not_due_invoice = cls.env["account.move"].create(
38+
{
39+
"move_type": "out_invoice",
40+
"partner_id": cls.partner.id,
41+
"invoice_date_due": fields.Date.today() + relativedelta(days=5),
42+
"invoice_line_ids": [
43+
(
44+
0,
45+
0,
46+
{
47+
"name": "Test line not due",
48+
"quantity": 1,
49+
"price_unit": 100,
50+
},
51+
)
52+
],
53+
"company_id": cls.company.id,
54+
}
55+
)
56+
cls.not_due_invoice.action_post()
57+
cls.not_due_invoice.payment_state = "not_paid"
58+
59+
cls.reminder_action = cls.env["overdue.reminder.action"].create(
60+
{
61+
"commercial_partner_id": cls.partner.id,
62+
"partner_id": cls.partner.id,
63+
"date": fields.Date.today(),
64+
"user_id": cls.env.ref("base.user_admin").id,
65+
"reminder_type": "mail",
66+
}
67+
)
68+
69+
def test_overdue_computation(self):
70+
self.assertTrue(self.overdue_invoice.overdue, "Invoice should be overdue")
71+
self.assertFalse(self.not_due_invoice.overdue, "Invoice should not be overdue")
72+
73+
def test_overdue_reminder_counter_initial(self):
74+
self.assertEqual(self.overdue_invoice.overdue_reminder_counter, 0)
75+
self.assertFalse(self.overdue_invoice.overdue_reminder_last_date)
76+
77+
def test_overdue_remind_sent_logic(self):
78+
company = self.env.company
79+
company.overdue_reminder_min_interval_days = 3
80+
self.assertFalse(self.overdue_invoice.overdue_remind_sent)
81+
self.env["account.invoice.overdue.reminder"].create(
82+
{
83+
"invoice_id": self.overdue_invoice.id,
84+
"action_id": self.reminder_action.id,
85+
"counter": 1,
86+
"action_date": fields.Date.today() - relativedelta(days=1),
87+
}
88+
)
89+
self.overdue_invoice._compute_overdue_reminder_sent()
90+
self.assertTrue(self.overdue_invoice.overdue_remind_sent)
91+
92+
def test_compute_overdue_reminder_multiple(self):
93+
self.env["account.invoice.overdue.reminder"].create(
94+
{
95+
"invoice_id": self.overdue_invoice.id,
96+
"action_id": self.reminder_action.id,
97+
"counter": 1,
98+
"action_date": fields.Date.today() - relativedelta(days=5),
99+
}
100+
)
101+
self.env["account.invoice.overdue.reminder"].create(
102+
{
103+
"invoice_id": self.overdue_invoice.id,
104+
"action_id": self.reminder_action.id,
105+
"counter": 3,
106+
"action_date": fields.Date.today() - relativedelta(days=1),
107+
}
108+
)
109+
self.overdue_invoice._compute_overdue_reminder()
110+
reminder = self.env["account.invoice.overdue.reminder"].search(
111+
[("invoice_id", "=", self.overdue_invoice.id)],
112+
order="action_date desc, id desc",
113+
limit=1,
114+
)
115+
self.assertEqual(
116+
self.overdue_invoice.overdue_reminder_last_date, reminder.action_date
117+
)
118+
self.assertEqual(
119+
self.overdue_invoice.overdue_reminder_counter, reminder.counter
120+
)
121+
122+
def test_no_overdue_reminder_flag(self):
123+
self.overdue_invoice.no_overdue_reminder = True
124+
self.assertTrue(
125+
self.overdue_invoice.no_overdue_reminder,
126+
"Invoice should have no_overdue_reminder=True",
127+
)
128+
self.overdue_invoice._compute_overdue()
129+
self.assertTrue(
130+
self.overdue_invoice.overdue,
131+
"Overdue may still be True, we are only testing the flag here",
132+
)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copyright 2026 NICO SOLUTIONS - ENGINEERING & IT, Nils Coenen
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from odoo import fields
4+
from odoo.tests.common import TransactionCase
5+
from odoo.tools.misc import format_date
6+
7+
8+
class TestOverdueReminderAction(TransactionCase):
9+
@classmethod
10+
def setUpClass(cls):
11+
super().setUpClass()
12+
cls.partner = cls.env["res.partner"].create({"name": "Test Partner"})
13+
cls.product = cls.env["product.product"].create({"name": "Test Product"})
14+
uom_unit = cls.env.ref("uom.product_uom_unit")
15+
cls.invoice_model = cls.env["account.move"].create(
16+
{
17+
"move_type": "out_invoice",
18+
"partner_id": cls.partner.id,
19+
"invoice_date": "2025-12-31",
20+
"line_ids": [
21+
(
22+
0,
23+
0,
24+
{
25+
"name": "Test line",
26+
"partner_id": cls.partner.id,
27+
"quantity": 1.0,
28+
"price_unit": 100.0,
29+
"product_id": cls.product.id,
30+
"product_uom_id": uom_unit.id,
31+
},
32+
)
33+
],
34+
}
35+
)
36+
cls.reminder_action = cls.env["overdue.reminder.action"].create(
37+
{
38+
"reminder_type": "mail",
39+
"partner_id": cls.partner.id,
40+
"commercial_partner_id": cls.partner.id,
41+
}
42+
)
43+
cls.reminder_model = cls.env["account.invoice.overdue.reminder"].create(
44+
{
45+
"invoice_id": cls.invoice_model.id,
46+
"action_id": cls.reminder_action.id,
47+
"counter": 0,
48+
}
49+
)
50+
51+
def test_default_values(self):
52+
self.assertEqual(self.reminder_action.user_id, self.env.user)
53+
self.assertEqual(self.reminder_action.reminder_type, "mail")
54+
self.assertEqual(
55+
self.reminder_action.date, fields.Date.context_today(self.reminder_action)
56+
)
57+
58+
def test_compute_invoice_count(self):
59+
self.reminder_action._compute_invoice_count()
60+
self.assertEqual(self.reminder_action.reminder_count, 1)
61+
62+
def test_compute_display_name(self):
63+
self.reminder_action._compute_display_name()
64+
self.assertIn("Test Partner", self.reminder_action.display_name)
65+
expected_date = format_date(self.env, self.reminder_action.date)
66+
self.assertIn(expected_date, self.reminder_action.display_name)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Copyright 2026 NICO SOLUTIONS - ENGINEERING & IT, Nils Coenen
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from unittest.mock import patch
4+
5+
from odoo import fields
6+
from odoo.exceptions import UserError
7+
from odoo.tests.common import TransactionCase
8+
9+
from odoo.addons.account_invoice_overdue_reminder.wizard import (
10+
overdue_reminder_wizard as wizard,
11+
)
12+
13+
14+
class TestOverdueRemindMassUpdate(TransactionCase):
15+
@classmethod
16+
def setUpClass(cls):
17+
super().setUpClass()
18+
cls.partner = cls.env["res.partner"].create({"name": "Test Partner"})
19+
cls.user = cls.env.user
20+
cls.invoice = cls.env["account.move"].create(
21+
{
22+
"move_type": "out_invoice",
23+
"partner_id": cls.partner.id,
24+
"invoice_date": fields.Date.today(),
25+
"invoice_date_due": fields.Date.today(),
26+
}
27+
)
28+
cls.step = cls.env["overdue.reminder.step"].create(
29+
{
30+
"partner_id": cls.partner.id,
31+
"commercial_partner_id": cls.partner.id,
32+
"user_id": cls.user.id,
33+
"invoice_ids": [(6, 0, [cls.invoice.id])],
34+
"reminder_type": "mail",
35+
}
36+
)
37+
38+
def _create_wizard(self, update_action, reminder_type=None):
39+
return self.env["overdue.reminder.mass.update"].create(
40+
{
41+
"update_action": update_action,
42+
"reminder_type": reminder_type,
43+
}
44+
)
45+
46+
def test_run_validate(self):
47+
wizard_rec = self._create_wizard("validate")
48+
with patch.object(wizard.OverdueReminderStep, "validate") as mock_validate:
49+
wizard_rec.with_context(
50+
active_model="overdue.reminder.step", active_ids=[self.step.id]
51+
).run()
52+
mock_validate.assert_called_once()
53+
54+
def test_run_skip(self):
55+
wizard_rec = self._create_wizard("skip")
56+
with patch.object(wizard.OverdueReminderStep, "skip") as mock_skip:
57+
wizard_rec.with_context(
58+
active_model="overdue.reminder.step", active_ids=[self.step.id]
59+
).run()
60+
mock_skip.assert_called_once()
61+
62+
def test_run_reminder_type_change(self):
63+
wizard = self._create_wizard("reminder_type", reminder_type="phone")
64+
wizard.with_context(
65+
active_model="overdue.reminder.step", active_ids=[self.step.id]
66+
).run()
67+
self.assertEqual(self.step.reminder_type, "phone")
68+
69+
def test_run_reminder_type_missing(self):
70+
wizard = self._create_wizard("reminder_type")
71+
with self.assertRaises(UserError):
72+
wizard.with_context(
73+
active_model="overdue.reminder.step", active_ids=[self.step.id]
74+
).run()

0 commit comments

Comments
 (0)