From 09206fb73e118ffe4ec16f539550cd9aabc72cad Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 1 Apr 2020 11:16:57 +0200 Subject: [PATCH] Adapt test module --- base_time_window/models/__init__.py | 4 +- base_time_window/readme/DESCRIPTION.rst | 3 +- base_time_window/readme/USAGE.rst | 30 ++++ test_base_time_window/__init__.py | 3 +- test_base_time_window/__manifest__.py | 4 +- test_base_time_window/models/__init__.py | 4 +- .../models/partner_time_window.py | 76 ++------ test_base_time_window/models/res_partner.py | 8 +- test_base_time_window/readme/CONTRIBUTORS.rst | 2 + test_base_time_window/readme/DESCRIPTION.rst | 1 + .../security/ir.model.access.xml | 14 +- test_base_time_window/tests/__init__.py | 3 +- .../tests/test_base_time_window.py | 166 +++++++++++------- 13 files changed, 165 insertions(+), 153 deletions(-) create mode 100644 base_time_window/readme/USAGE.rst create mode 100644 test_base_time_window/readme/CONTRIBUTORS.rst create mode 100644 test_base_time_window/readme/DESCRIPTION.rst diff --git a/base_time_window/models/__init__.py b/base_time_window/models/__init__.py index b878f0eaf..122ebbf3e 100644 --- a/base_time_window/models/__init__.py +++ b/base_time_window/models/__init__.py @@ -1,2 +1,2 @@ -from . import base_time_weekday -from . import base_time_window +from . import time_weekday +from . import time_window_mixin diff --git a/base_time_window/readme/DESCRIPTION.rst b/base_time_window/readme/DESCRIPTION.rst index f8c3d63ba..ad077245b 100644 --- a/base_time_window/readme/DESCRIPTION.rst +++ b/base_time_window/readme/DESCRIPTION.rst @@ -1 +1,2 @@ -This module provides base classes to manage time windows. +This module provides base classes and models to manage time windows through +`time.window.mixin`. diff --git a/base_time_window/readme/USAGE.rst b/base_time_window/readme/USAGE.rst new file mode 100644 index 000000000..f27eb7352 --- /dev/null +++ b/base_time_window/readme/USAGE.rst @@ -0,0 +1,30 @@ +Example implementation for the mixin can be found in module `test_base_time_window`. + +As a time window will always be linked to a related model thourgh a M2o relation, +when defining the new model inheriting the mixin, one should pay attention to the +following points in order to have the overlapping check work properly: + +- Define class property `_overlap_check_field`: This must state the M2o field to + use for the to check of overlapping time window records linked to a specific + record of the related model. + +- Add the M2o field to the related model in the `api.constrains`: + + +For example: + +.. code-block:: python + + class PartnerTimeWindow(models.Model): + _name = 'partner.time.window' + _inherit = 'time.window.mixin' + + partner_id = fields.Many2one( + res.partner', required=True, index=True, ondelete='cascade' + ) + + _overlap_check_field = 'partner_id' + + @api.constrains('partner_id') + def check_window_no_overlaps(self): + return super().check_window_no_overlaps() diff --git a/test_base_time_window/__init__.py b/test_base_time_window/__init__.py index 5437c31a2..0650744f6 100644 --- a/test_base_time_window/__init__.py +++ b/test_base_time_window/__init__.py @@ -1,2 +1 @@ -# Copyright 2020 Camptocamp SA -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from . import models diff --git a/test_base_time_window/__manifest__.py b/test_base_time_window/__manifest__.py index fe22565db..28a6e3d55 100644 --- a/test_base_time_window/__manifest__.py +++ b/test_base_time_window/__manifest__.py @@ -8,7 +8,7 @@ "author": "ACSONE SA/NV, Camptocamp, Odoo Community Association (OCA)", "license": "AGPL-3", "website": "https://github.com/OCA/server-tools", - "depends": ["base"], - "data": [], + "depends": ["base_time_window"], + "data": ["security/ir.model.access.xml"], "installable": True, } diff --git a/test_base_time_window/models/__init__.py b/test_base_time_window/models/__init__.py index 5437c31a2..76868ae2d 100644 --- a/test_base_time_window/models/__init__.py +++ b/test_base_time_window/models/__init__.py @@ -1,2 +1,2 @@ -# Copyright 2020 Camptocamp SA -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from . import partner_time_window +from . import res_partner diff --git a/test_base_time_window/models/partner_time_window.py b/test_base_time_window/models/partner_time_window.py index 4786cfcd0..15ef8691c 100644 --- a/test_base_time_window/models/partner_time_window.py +++ b/test_base_time_window/models/partner_time_window.py @@ -4,82 +4,30 @@ import math -from psycopg2.extensions import AsIs - from odoo import _, api, fields, models -from odoo.exceptions import ValidationError -class DeliveryWindow(models.Model): +class TestPartnerTimeWindow(models.Model): - _name = "delivery.window" - _description = "Delivery Window" - _order = "partner_id, start" + _name = "test.partner.time.window" + _inherit = "time.window.mixin" + _description = "Test partner time Window" + + _overlap_check_field = 'partner_id' - start = fields.Float("From", required=True) - end = fields.Float("To", required=True) - week_day_ids = fields.Many2many( - comodel_name="alc.delivery.week.day", required=True - ) partner_id = fields.Many2one( "res.partner", required=True, index=True, ondelete='cascade' ) - @api.constrains("start", "end", "week_day_ids") - def check_window_no_onverlaps(self): - week_days_field = self._fields["week_day_ids"] - for record in self: - if record.start > record.end: - raise ValidationError( - _("%s must be > %s") - % ( - self.float_to_time_repr(record.end), - self.float_to_time_repr(record.start), - ) - ) - # here we use a plain SQL query to benefit of the numrange - # function available in PostgresSQL - # (http://www.postgresql.org/docs/current/static/rangetypes.html) - SQL = """ - SELECT - id - FROM - %(table)s w - join %(relation)s as d - on d.%(relation_window_fkey)s = w.id - WHERE - NUMRANGE(w.start::numeric, w.end::numeric) && - NUMRANGE(%(start)s::numeric, %(end)s::numeric) - AND w.id != %(window_id)s - AND d.%(relation_week_day_fkey)s in %(week_day_ids)s - AND w.partner_id = %(partner_id)s""" - self.env.cr.execute( - SQL, - dict( - table=AsIs(self._table), - relation=AsIs(week_days_field.relation), - relation_window_fkey=AsIs(week_days_field.column1), - relation_week_day_fkey=AsIs(week_days_field.column2), - start=record.start, - end=record.end, - window_id=record.id, - week_day_ids=tuple(record.week_day_ids.ids), - partner_id=record.partner_id.id, - ), - ) - res = self.env.cr.fetchall() - if res: - other = self.browse(res[0][0]) - raise ValidationError( - _("%s overlaps %s") - % (record.display_name, other.display_name) - ) + @api.constrains("partner_id") + def check_window_no_overlaps(self): + return super().check_window_no_overlaps() - @api.depends("start", "end", "week_day_ids") + @api.depends("start", "end", "weekday_ids") def _compute_display_name(self): for record in self: - "{days}: From {start} to {end}".format( - days=", ".join(record.week_day_ids.mapped("display_name")), + record.display_name = _("{days}: From {start} to {end}").format( + days=", ".join(record.weekday_ids.mapped("display_name")), start=self.float_to_time_repr(record.start), end=self.float_to_time_repr(record.end), ) diff --git a/test_base_time_window/models/res_partner.py b/test_base_time_window/models/res_partner.py index 697056f3f..f9aa4c53c 100644 --- a/test_base_time_window/models/res_partner.py +++ b/test_base_time_window/models/res_partner.py @@ -11,12 +11,10 @@ class ResPartner(models.Model): _inherit = "res.partner" - delivery_window_ids = fields.One2many( - comodel_name="delivery.window", + time_window_ids = fields.One2many( + comodel_name="test.partner.time.window", inverse_name="partner_id", - string="Delivery windows", - help="If specified, delivery is only possible into the specified " - "time windows. (Leaves empty if no restriction)", + string="Time windows", ) def get_delivery_windows(self, day_name): diff --git a/test_base_time_window/readme/CONTRIBUTORS.rst b/test_base_time_window/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..d7222fd22 --- /dev/null +++ b/test_base_time_window/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Laurent Mignon +* Akim Juillerat diff --git a/test_base_time_window/readme/DESCRIPTION.rst b/test_base_time_window/readme/DESCRIPTION.rst new file mode 100644 index 000000000..3a0a4d558 --- /dev/null +++ b/test_base_time_window/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module provides unittests for module `base_time_window`. diff --git a/test_base_time_window/security/ir.model.access.xml b/test_base_time_window/security/ir.model.access.xml index 4af476408..998c1de58 100644 --- a/test_base_time_window/security/ir.model.access.xml +++ b/test_base_time_window/security/ir.model.access.xml @@ -3,9 +3,9 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> - - delivery.window access read - + + test.partner.time.window access read + @@ -13,10 +13,10 @@ - - delivery.window access read - - + + test.partner.time.window access read + + diff --git a/test_base_time_window/tests/__init__.py b/test_base_time_window/tests/__init__.py index 5437c31a2..20e2afe6b 100644 --- a/test_base_time_window/tests/__init__.py +++ b/test_base_time_window/tests/__init__.py @@ -1,2 +1 @@ -# Copyright 2020 Camptocamp SA -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from . import test_base_time_window diff --git a/test_base_time_window/tests/test_base_time_window.py b/test_base_time_window/tests/test_base_time_window.py index 0462f131e..01b3905a2 100644 --- a/test_base_time_window/tests/test_base_time_window.py +++ b/test_base_time_window/tests/test_base_time_window.py @@ -6,182 +6,216 @@ from odoo.exceptions import ValidationError from odoo.tests import SavepointCase -class TestDeliveryWindow(SavepointCase): +class TestTimeWindow(SavepointCase): @classmethod def setUpClass(cls): - super(TestDeliveryWindow, cls).setUpClass() + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) cls.partner_1 = cls.env['res.partner'].create({'name': 'partner 1'}) - cls.partner_2 = cls.env['res.partner'].create({'name': 'patner 2'}) - cls.DeliveryWindow = cls.env["delivery.window"] + cls.partner_2 = cls.env['res.partner'].create({'name': 'partner 2'}) + cls.TimeWindow = cls.env["test.partner.time.window"] cls.monday = cls.env.ref( - "partner_delivery_window.delivery_weed_day_monday" + "base_time_window.time_weekday_monday" ) cls.sunday = cls.env.ref( - "partner_delivery_window.delivery_weed_day_sunday" + "base_time_window.time_weekday_sunday" ) def test_00(self): """ Data: - A partner without delivery window + A partner without time window Test Case: - Add a delivery window + Add a time window Expected result: - A delivery window is created for the partner + A time window is created for the partner """ - self.assertFalse(self.partner_1.delivery_window_ids) - self.DeliveryWindow.create( + self.assertFalse(self.partner_1.time_window_ids) + self.TimeWindow.create( { "partner_id": self.partner_1.id, "start": 10.0, "end": 12.0, - "week_day_ids": [(4, self.monday.id)], + "weekday_ids": [(4, self.monday.id)], } ) - self.assertTrue(self.partner_1.delivery_window_ids) - delivery_window = self.partner_1.delivery_window_ids - self.assertEqual(delivery_window.start, 10.0) - self.assertEqual(delivery_window.end, 12.0) - self.assertEqual(delivery_window.week_day_ids, self.monday) + self.assertTrue(self.partner_1.time_window_ids) + time_window = self.partner_1.time_window_ids + self.assertEqual(time_window.start, 10.0) + self.assertEqual(time_window.end, 12.0) + self.assertEqual(time_window.weekday_ids, self.monday) def test_01(self): """ Data: - A partner without delivery window + A partner without time window Test Case: - 1 Add a delivery window + 1 Add a time window 2 unlink the partner Expected result: - 1 A delivery window is created for the partner - 2 The delivery window is removed + 1 A time window is created for the partner + 2 The time window is removed """ partner_id = self.partner_1.id - self.assertFalse(self.partner_1.delivery_window_ids) - self.DeliveryWindow.create( + self.assertFalse(self.partner_1.time_window_ids) + self.TimeWindow.create( { "partner_id": self.partner_1.id, "start": 10.0, "end": 12.0, - "week_day_ids": [(4, self.monday.id)], + "weekday_ids": [(4, self.monday.id)], } ) - self.assertTrue(self.partner_1.delivery_window_ids) - delivery_window = self.DeliveryWindow.search( + self.assertTrue(self.partner_1.time_window_ids) + time_window = self.TimeWindow.search( [("partner_id", "=", partner_id)] ) - self.assertTrue(delivery_window) + self.assertTrue(time_window) self.partner_1.unlink() - self.assertFalse(delivery_window.exists()) + self.assertFalse(time_window.exists()) def test_02(self): """ Data: - A partner without delivery window + A partner without time window Test Case: - 1 Add a delivery window - 2 Add a second delivery window that overlaps the first one (same day) + 1 Add a time window + 2 Add a second time window that overlaps the first one (same day) Expected result: - 1 A delivery window is created for the partner + 1 A time window is created for the partner 2 ValidationError is raised """ - self.DeliveryWindow.create( + self.TimeWindow.create( { "partner_id": self.partner_1.id, "start": 10.0, "end": 12.0, - "week_day_ids": [(4, self.monday.id)], + "weekday_ids": [(4, self.monday.id)], } ) with self.assertRaises(ValidationError): - self.DeliveryWindow.create( + self.TimeWindow.create( { "partner_id": self.partner_1.id, "start": 11.0, "end": 13.0, - "week_day_ids": [(4, self.monday.id), (4, self.sunday.id)], + "weekday_ids": [(4, self.monday.id), (4, self.sunday.id)], } ) def test_03(self): """ Data: - A partner without delivery window + A partner without time window Test Case: - 1 Add a delivery window - 2 Add a second delivery window that overlaps the first one (another day) + 1 Add a time window + 2 Add a second time window that overlaps the first one (another day) Expected result: - 1 A delivery window is created for the partner - 2 A second delivery window is created for the partner + 1 A time window is created for the partner + 2 A second time window is created for the partner """ - self.assertFalse(self.partner_1.delivery_window_ids) - self.DeliveryWindow.create( + self.assertFalse(self.partner_1.time_window_ids) + self.TimeWindow.create( { "partner_id": self.partner_1.id, "start": 10.0, "end": 12.0, - "week_day_ids": [(4, self.monday.id)], + "weekday_ids": [(4, self.monday.id)], } ) - self.assertTrue(self.partner_1.delivery_window_ids) - self.DeliveryWindow.create( + self.assertTrue(self.partner_1.time_window_ids) + self.TimeWindow.create( { "partner_id": self.partner_1.id, "start": 11.0, "end": 13.0, - "week_day_ids": [(4, self.sunday.id)], + "weekday_ids": [(4, self.sunday.id)], } ) - self.assertEquals(len(self.partner_1.delivery_window_ids), 2) + self.assertEquals(len(self.partner_1.time_window_ids), 2) def test_04(self): """ Data: - Partner 1 without delivery window - Partner 2 without delivery window + Partner 1 without time window + Partner 2 without time window Test Case: - 1 Add a delivery window to partner 1 - 2 Add the same delivery window to partner 2 + 1 Add a time window to partner 1 + 2 Add the same time window to partner 2 Expected result: - 1 A delivery window is created for the partner 1 - 1 A delivery window is created for the partner 2 + 1 A time window is created for the partner 1 + 1 A time window is created for the partner 2 """ - self.assertFalse(self.partner_1.delivery_window_ids) - self.DeliveryWindow.create( + self.assertFalse(self.partner_1.time_window_ids) + self.TimeWindow.create( { "partner_id": self.partner_1.id, "start": 10.0, "end": 12.0, - "week_day_ids": [(4, self.monday.id)], + "weekday_ids": [(4, self.monday.id)], } ) - self.assertTrue(self.partner_1.delivery_window_ids) - self.assertFalse(self.partner_2.delivery_window_ids) - self.DeliveryWindow.create( + self.assertTrue(self.partner_1.time_window_ids) + self.assertFalse(self.partner_2.time_window_ids) + self.TimeWindow.create( { "partner_id": self.partner_2.id, "start": 10.0, "end": 12.0, - "week_day_ids": [(4, self.monday.id)], + "weekday_ids": [(4, self.monday.id)], } ) - self.assertTrue(self.partner_2.delivery_window_ids) + self.assertTrue(self.partner_2.time_window_ids) def test_05(self): """"" Data: - Partner 1 without delivery window + Partner 1 without time window Test Case: - Add a delivery window to partner 1 with end > start + Add a time window to partner 1 with end > start Expected result: ValidationError is raised """ with self.assertRaises(ValidationError): - self.DeliveryWindow.create( + self.TimeWindow.create( { "partner_id": self.partner_1.id, "start": 14.0, "end": 12.0, - "week_day_ids": [(4, self.monday.id)], + "weekday_ids": [(4, self.monday.id)], } ) + + def test_06(self): + """"" + Data: + Partner 1 with time window on monday + Partner 2 with time window on monday + Test Case: + Change time window from Partner 1 to Partner 2 + Expected result: + ValidationError is raised + """ + self.assertFalse(self.partner_1.time_window_ids) + p1_timewindow = self.TimeWindow.create( + { + "partner_id": self.partner_1.id, + "start": 10.0, + "end": 12.0, + "weekday_ids": [(4, self.monday.id)], + } + ) + self.assertTrue(self.partner_1.time_window_ids) + self.assertFalse(self.partner_2.time_window_ids) + self.TimeWindow.create( + { + "partner_id": self.partner_2.id, + "start": 10.0, + "end": 12.0, + "weekday_ids": [(4, self.monday.id)], + } + ) + self.assertTrue(self.partner_2.time_window_ids) + with self.assertRaises(ValidationError): + p1_timewindow.partner_id = self.partner_2