From 17ec22059a77442f1b4582f5f3a37b744c4a082c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brais=20Abeij=C3=B3n?= <> Date: Fri, 27 Nov 2020 15:36:21 +0100 Subject: [PATCH 1/2] [ADD] pms: Test case for product.pricelist rule priority --- pms/tests/__init__.py | 1 + pms/tests/test_pms_pricelist_priority.py | 550 +++++++++++++++++++++++ 2 files changed, 551 insertions(+) create mode 100644 pms/tests/test_pms_pricelist_priority.py diff --git a/pms/tests/__init__.py b/pms/tests/__init__.py index cfbd2f1f4..32033ab63 100644 --- a/pms/tests/__init__.py +++ b/pms/tests/__init__.py @@ -21,3 +21,4 @@ ############################################################################## from . import test_pms_reservation from . import test_pms_pricelist +from . import test_pms_pricelist_priority diff --git a/pms/tests/test_pms_pricelist_priority.py b/pms/tests/test_pms_pricelist_priority.py new file mode 100644 index 000000000..1b9442354 --- /dev/null +++ b/pms/tests/test_pms_pricelist_priority.py @@ -0,0 +1,550 @@ +import datetime + +from freezegun import freeze_time + +from odoo.tests import common, tagged + + +@tagged("standard", "nice") +class TestPmsPricelistRules(common.TransactionCase): + def create_common_scenario(self): + self.product_template = self.env["product.template"].create( + {"name": "Template1"} + ) + self.product_category = self.env["product.category"].create( + {"name": "Category1"} + ) + + self.restriction = self.env["pms.room.type.restriction"].create( + {"name": "Restriction1"} + ) + + self.restriction2 = self.env["pms.room.type.restriction"].create( + {"name": "Restriction2"} + ) + self.property1 = self.env["pms.property"].create( + { + "name": "Property_1", + "company_id": self.env.ref("base.main_company").id, + "default_pricelist_id": self.env.ref("product.list0").id, + "default_restriction_id": self.restriction.id, + } + ) + + self.property2 = self.env["pms.property"].create( + { + "name": "Property_2", + "company_id": self.env.ref("base.main_company").id, + "default_pricelist_id": self.env.ref("product.list0").id, + "default_restriction_id": self.restriction2.id, + } + ) + + self.room_type_class = self.env["pms.room.type.class"].create( + {"name": "Room Class"} + ) + + self.room_type = self.env["pms.room.type"].create( + { + "pms_property_ids": [self.property1.id, self.property2.id], + "name": "Single", + "code_type": "SIN", + "class_id": self.room_type_class.id, + "list_price": 30, + } + ) + + self.room = self.env["pms.room"].create( + { + "pms_property_id": self.property1.id, + "name": "Single 101", + "room_type_id": self.room_type.id, + } + ) + + self.room2 = self.env["pms.room"].create( + { + "pms_property_id": self.property2.id, + "name": "Single 102", + "room_type_id": self.room_type.id, + } + ) + + self.pricelist = self.env["product.pricelist"].create( + { + "name": "pricelist_1", + } + ) + + @freeze_time("2000-01-01 00:00:00") + def test_items_sort_applied_on(self): + + # ARRANGE + self.create_common_scenario() + + self.item1 = self.env["product.pricelist.item"].create( + { + "name": "item_1", + "categ_id": self.product_category.id, + "applied_on": "2_product_category", + "date_start": datetime.datetime.now(), + "date_end": datetime.datetime.now() + datetime.timedelta(days=3), + "pms_property_ids": [self.property1.id], + "fixed_price": 40.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item2 = self.env["product.pricelist.item"].create( + { + "name": "item_2", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.now(), + "date_end": datetime.datetime.now() + datetime.timedelta(days=3), + "pms_property_ids": [self.property1.id], + "fixed_price": 50.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + reservation = self.env["pms.reservation"].create( + { + "checkin": datetime.datetime.today(), + "checkout": datetime.datetime.today() + datetime.timedelta(days=3), + "preferred_room_id": self.room.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + + # ACT + n_days = (reservation.checkout - reservation.checkin).days + expected_price = self.item2.fixed_price * n_days + + # ASSERT + self.assertEqual( + expected_price, reservation.price_total, "The price is not as expected" + ) + + @freeze_time("2000-01-16 00:00:00") + def test_items_sort_date(self): + + # ARRANGE + self.create_common_scenario() + + self.item1 = self.env["product.pricelist.item"].create( + { + "name": "item_1", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today() + datetime.timedelta(days=3), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=5, hours=23, minutes=59), + "fixed_price": 40.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item2 = self.env["product.pricelist.item"].create( + { + "name": "item_2", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=10, hours=23, minutes=59), + "fixed_price": 50.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + reservation = self.env["pms.reservation"].create( + { + "checkin": datetime.datetime.today() + + datetime.timedelta(days=3, hours=12, minutes=00), + "checkout": datetime.datetime.today() + + datetime.timedelta(days=5, hours=12, minutes=00), + "preferred_room_id": self.room.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ACT + n_days = (reservation.checkout - reservation.checkin).days + expected_price = self.item1.fixed_price * n_days + # ASSERT + self.assertEqual( + expected_price, reservation.price_total, "The price is not as expected" + ) + + @freeze_time("2000-01-05 00:00:00") + def test_items_sort_property(self): + + # ARRANGE + self.create_common_scenario() + + self.item1 = self.env["product.pricelist.item"].create( + { + "name": "item_1", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=5, hours=23, minutes=59), + "fixed_price": 40.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item2 = self.env["product.pricelist.item"].create( + { + "name": "item_2", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=5, hours=23, minutes=59), + "fixed_price": 50.0, + "pms_property_ids": [self.property1.id], + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + reservation = self.env["pms.reservation"].create( + { + "checkin": datetime.datetime.today() + + datetime.timedelta(days=2, hours=12, minutes=00), + "checkout": datetime.datetime.today() + + datetime.timedelta(days=5, hours=12, minutes=00), + "preferred_room_id": self.room.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ACT + n_days = (reservation.checkout - reservation.checkin).days + expected_price = self.item2.fixed_price * n_days + # ASSERT + self.assertEqual( + expected_price, reservation.price_total, "The price is not as expected" + ) + + @freeze_time("2000-01-20 00:00:00") + def test_three_items_sort_applied_on(self): + + # ARRANGE + self.create_common_scenario() + + self.item1 = self.env["product.pricelist.item"].create( + { + "name": "item_1", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=1, hours=23, minutes=59), + "fixed_price": 40.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item2 = self.env["product.pricelist.item"].create( + { + "name": "item_2", + "product_id": self.room_type.product_id.id, + "product_tmpl_id": self.product_template.id, + "applied_on": "1_product", + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=1, hours=23, minutes=59), + "fixed_price": 50.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item3 = self.env["product.pricelist.item"].create( + { + "name": "item_3", + "categ_id": self.product_category.id, + "applied_on": "2_product_category", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=1, hours=23, minutes=59), + "fixed_price": 60.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + reservation = self.env["pms.reservation"].create( + { + "checkin": datetime.datetime.today() + + datetime.timedelta(hours=12, minutes=00), + "checkout": datetime.datetime.today() + + datetime.timedelta(days=1, hours=12, minutes=00), + "preferred_room_id": self.room.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ACT + expected_price = self.item1.fixed_price + # ASSERT + self.assertEqual( + expected_price, reservation.price_total, "The price is not as expected" + ) + + @freeze_time("2000-01-25 00:00:00") + def test_three_items_sort_date(self): + + # ARRANGE + self.create_common_scenario() + + self.item1 = self.env["product.pricelist.item"].create( + { + "name": "item_1", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=6, hours=23, minutes=59), + "fixed_price": 40.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item2 = self.env["product.pricelist.item"].create( + { + "name": "item_2", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today() + + datetime.timedelta(days=1, hours=00, minutes=00), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=5, hours=23, minutes=59), + "fixed_price": 50.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item3 = self.env["product.pricelist.item"].create( + { + "name": "item_3", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today() + + datetime.timedelta(days=2, hours=00, minutes=00), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=4, hours=23, minutes=59), + "fixed_price": 60.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + reservation = self.env["pms.reservation"].create( + { + "checkin": datetime.datetime.today() + + datetime.timedelta(days=3, hours=10, minutes=00), + "checkout": datetime.datetime.today() + + datetime.timedelta(days=4, hours=12, minutes=00), + "preferred_room_id": self.room.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ACT + expected_price = self.item3.fixed_price + # ASSERT + self.assertEqual( + expected_price, reservation.price_total, "The price is not as expected" + ) + + @freeze_time("2000-02-01 00:00:00") + def test_three_items_sort_property(self): + + # ARRANGE + self.create_common_scenario() + + self.item1 = self.env["product.pricelist.item"].create( + { + "name": "item_1", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=3, hours=23, minutes=59), + "fixed_price": 40.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item2 = self.env["product.pricelist.item"].create( + { + "name": "item_2", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=3, hours=23, minutes=59), + "fixed_price": 50.0, + "pms_property_ids": [self.property1.id], + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item3 = self.env["product.pricelist.item"].create( + { + "name": "item_3", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=3, hours=23, minutes=59), + "fixed_price": 60.0, + "pms_property_ids": [self.property1.id, self.property2.id], + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + reservation = self.env["pms.reservation"].create( + { + "checkin": datetime.datetime.today(), + "checkout": datetime.datetime.today() + + datetime.timedelta(days=2, hours=12, minutes=00), + "preferred_room_id": self.room.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ACT + n_days = (reservation.checkout - reservation.checkin).days + expected_price = self.item3.fixed_price * n_days + # ASSERT + self.assertEqual( + expected_price, reservation.price_total, "The price is not as expected" + ) + + @freeze_time("2000-02-01 00:00:00") + def test_sort_applied_on_before_date(self): + # ARRANGE + self.create_common_scenario() + + self.item1 = self.env["product.pricelist.item"].create( + { + "name": "item_1", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=8, hours=23, minutes=59), + "fixed_price": 40.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item2 = self.env["product.pricelist.item"].create( + { + "name": "item_2", + "product_id": self.room_type.product_id.id, + "product_tmpl_id": self.product_template.id, + "applied_on": "1_product", + "date_start": datetime.datetime.today() + + datetime.timedelta(days=2, hours=00, minutes=00), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=5, hours=23, minutes=59), + "fixed_price": 50.0, + "pms_property_ids": [self.property1.id], + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + reservation = self.env["pms.reservation"].create( + { + "checkin": datetime.datetime.today() + + datetime.timedelta(days=2, hours=12, minutes=00), + "checkout": datetime.datetime.today() + + datetime.timedelta(days=4, hours=12, minutes=00), + "preferred_room_id": self.room.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ACT + n_days = (reservation.checkout - reservation.checkin).days + expected_price = self.item1.fixed_price * n_days + # ASSERT + self.assertEqual( + expected_price, reservation.price_total, "The price is not as expected" + ) + + @freeze_time("2000-02-10 00:00:00") + def test_sort_date_before_property(self): + # ARRANGE + self.create_common_scenario() + + self.item1 = self.env["product.pricelist.item"].create( + { + "name": "item_1", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today(), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=10, hours=23, minutes=59), + "fixed_price": 40.0, + "pms_property_ids": [self.property1.id], + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + self.item2 = self.env["product.pricelist.item"].create( + { + "name": "item_2", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "date_start": datetime.datetime.today() + + datetime.timedelta(days=2, hours=00, minutes=00), + "date_end": datetime.datetime.today() + + datetime.timedelta(days=5, hours=23, minutes=59), + "fixed_price": 50.0, + "pricelist_id": self.pricelist.id, + "compute_price": "fixed", + } + ) + + reservation = self.env["pms.reservation"].create( + { + "checkin": datetime.datetime.today() + + datetime.timedelta(days=2, hours=12, minutes=00), + "checkout": datetime.datetime.today() + + datetime.timedelta(days=4, hours=12, minutes=00), + "preferred_room_id": self.room.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ACT + n_days = (reservation.checkout - reservation.checkin).days + expected_price = self.item2.fixed_price * n_days + # ASSERT + self.assertEqual( + expected_price, reservation.price_total, "The price is not as expected" + ) From 26625774927cdb9f9ed02191e136d174ba9358c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brais=20Abeij=C3=B3n?= <> Date: Fri, 27 Nov 2020 15:41:03 +0100 Subject: [PATCH 2/2] [IMP] pms: pricelist rule priority --- pms/models/product_pricelist.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pms/models/product_pricelist.py b/pms/models/product_pricelist.py index 20c7fe4db..eb6ad46ba 100644 --- a/pms/models/product_pricelist.py +++ b/pms/models/product_pricelist.py @@ -61,11 +61,14 @@ class ProductPricelist(models.Model): # Discard the rules with defined properties other than the context, # and we reorder the rules to return the most concrete property rule first if "property" in self._context: - return items.filtered( + items_filtered = items.filtered( lambda i: not i.pms_property_ids or self._context["property"] in i.pms_property_ids.ids - ).sorted( - key=lambda s: ((not s.pms_property_ids, s), len(s.pms_property_ids)) ) - else: - return items + return items_filtered.sorted( + key=lambda s: ( + (s.applied_on), + ((s.date_end - s.date_start).days), + ((not s.pms_property_ids, s), len(s.pms_property_ids)), + ) + )