From 18318dd86b2f8c9ffa572db247bc9fd1cbba5a52 Mon Sep 17 00:00:00 2001 From: braisab Date: Wed, 19 May 2021 19:56:16 +0200 Subject: [PATCH 1/6] [IMP]pms: change many2one fields to many2many --- pms/tests/test_pms_wizard_massive_changes.py | 142 +++++++-- .../pms_availability_plan_rule_views.xml | 9 + pms/views/product_pricelist_item_views.xml | 21 ++ pms/wizards/wizard_massive_changes.py | 299 ++++++++++-------- pms/wizards/wizard_massive_changes.xml | 15 +- 5 files changed, 326 insertions(+), 160 deletions(-) diff --git a/pms/tests/test_pms_wizard_massive_changes.py b/pms/tests/test_pms_wizard_massive_changes.py index dc81206df..6cab0afca 100644 --- a/pms/tests/test_pms_wizard_massive_changes.py +++ b/pms/tests/test_pms_wizard_massive_changes.py @@ -99,10 +99,12 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "availability_plan", - "availability_plan_id": self.test_availability_plan.id, + "availability_plan_ids": [ + (6, 0, [self.test_availability_plan.id]) + ], "start_date": fields.date.today(), "end_date": fields.date.today() + datetime.timedelta(days=days), - "room_type_id": self.test_room_type_double.id, + "room_type_ids": [(6, 0, [self.test_room_type_double.id])], "pms_property_ids": [self.test_property.id], } ).apply_massive_changes() @@ -137,7 +139,7 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "availability_plan", - "availability_plan_id": self.test_availability_plan.id, + "availability_plan_ids": [(6, 0, [self.test_availability_plan.id])], "start_date": date_from, "end_date": date_to, "pms_property_ids": [self.test_property.id], @@ -164,10 +166,10 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): vals = { "massive_changes_on": "availability_plan", - "availability_plan_id": self.test_availability_plan.id, + "availability_plan_ids": [(6, 0, [self.test_availability_plan.id])], "start_date": date_from, "end_date": date_to, - "room_type_id": self.test_room_type_double.id, + "room_type_ids": [(6, 0, [self.test_room_type_double.id])], "quota": 50, "max_avail": 5, "min_stay": 10, @@ -185,10 +187,10 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): # ASSERT del vals["massive_changes_on"] - del vals["availability_plan_id"] + del vals["availability_plan_ids"] del vals["start_date"] del vals["end_date"] - del vals["room_type_id"] + del vals["room_type_ids"] del vals["pms_property_ids"] for key in vals: with self.subTest(k=key): @@ -221,8 +223,8 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): wizard = self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "availability_plan", - "availability_plan_id": self.test_availability_plan.id, - "room_type_id": self.test_room_type_double.id, + "availability_plan_ids": [(6, 0, [self.test_availability_plan.id])], + "room_type_ids": [(6, 0, [self.test_room_type_double.id])], "start_date": date_from, "end_date": date_to, "pms_property_ids": [self.test_property.id], @@ -276,10 +278,10 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): ) vals_wizard = { "massive_changes_on": "availability_plan", - "availability_plan_id": self.test_availability_plan.id, + "availability_plan_ids": [(6, 0, [self.test_availability_plan.id])], "start_date": date, "end_date": date, - "room_type_id": self.test_room_type_double.id, + "room_type_ids": [(6, 0, [self.test_room_type_double.id])], "apply_max_avail": True, "max_avail": 2, "pms_property_ids": [self.test_property.id], @@ -318,10 +320,10 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "pricelist", - "pricelist_id": self.test_pricelist.id, + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], "start_date": fields.date.today(), "end_date": fields.date.today() + datetime.timedelta(days=days), - "room_type_id": self.test_room_type_double.id, + "room_type_ids": [(6, 0, [self.test_room_type_double.id])], "pms_property_ids": [self.test_property.id], } ).apply_massive_changes() @@ -359,7 +361,7 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "pricelist", - "pricelist_id": self.test_pricelist.id, + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], "start_date": date_from, "end_date": date_to, "pms_property_ids": [self.test_property.id], @@ -402,10 +404,10 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "pricelist", - "pricelist_id": self.test_pricelist.id, + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], "start_date": date_from, "end_date": date_to, - "room_type_id": self.test_room_type_double.id, + "room_type_ids": [(6, 0, [self.test_room_type_double.id])], "price": price, "min_quantity": min_quantity, "pms_property_ids": [self.test_property.id], @@ -446,8 +448,8 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): wizard = self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "pricelist", - "pricelist_id": self.test_pricelist.id, - "room_type_id": self.test_room_type_double.id, + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], + "room_type_ids": [(6, 0, [self.test_room_type_double.id])], "start_date": date_from, "end_date": date_to, "pms_property_ids": [self.test_property.id], @@ -483,3 +485,107 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): and test_case[index], "Rule not created on correct day of week", ) + + @freeze_time("2025-12-01") + def test_several_availability_plan(self): + self.create_common_scenario() + date_from = fields.date.today() + date_to = date_from + datetime.timedelta(days=6) + self.test_availability_plan_2 = self.env["pms.availability.plan"].create( + { + "name": "Second availability plan for TEST", + "pms_pricelist_ids": [(6, 0, [self.test_pricelist.id])], + } + ) + + wizard = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "pricelist", + "availability_plan_ids": [ + ( + 6, + 0, + [ + self.test_availability_plan.id, + self.test_availability_plan_2.id, + ], + ) + ], + "room_type_ids": [(6, 0, [self.test_room_type_double.id])], + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + } + ) + + availability_plan_ids = [ + self.test_availability_plan.id, + self.test_availability_plan_2.id, + ] + for avail_plan_id in wizard["availability_plan_ids"].ids: + with self.subTest(k=avail_plan_id): + self.assertIn( + avail_plan_id, + availability_plan_ids, + "Availability plan has not been write ", + ) + + @freeze_time("2025-01-01") + def test_several_pricelists(self): + self.create_common_scenario() + date_from = fields.date.today() + date_to = date_from + datetime.timedelta(days=6) + self.test_pricelist_2 = self.env["product.pricelist"].create( + { + "name": "test pricelist 2", + } + ) + + wizard = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "pricelist", + "pricelist_ids": [ + (6, 0, [self.test_pricelist.id, self.test_pricelist_2.id]) + ], + "room_type_ids": [(6, 0, [self.test_room_type_double.id])], + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + } + ) + + pricelist_ids = [self.test_pricelist.id, self.test_pricelist_2.id] + for pricelist_id in wizard["pricelist_ids"].ids: + with self.subTest(k=pricelist_id): + self.assertIn( + pricelist_id, pricelist_ids, "Pricelist has not been write " + ) + + @freeze_time("2025-02-01") + def test_several_room_types(self): + self.create_common_scenario() + date_from = fields.date.today() + date_to = date_from + datetime.timedelta(days=6) + wizard = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "pricelist", + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], + "room_type_ids": [ + ( + 6, + 0, + [self.test_room_type_double.id, self.test_room_type_double.id], + ) + ], + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + } + ) + + room_type_ids = [self.test_room_type_double.id, self.test_room_type_double.id] + for room_type_id in wizard["room_type_ids"].ids: + with self.subTest(k=room_type_id): + self.assertIn( + room_type_id, room_type_ids, "Room type has not been write " + ) diff --git a/pms/views/pms_availability_plan_rule_views.xml b/pms/views/pms_availability_plan_rule_views.xml index c0e4fa2ec..3b133bb7f 100644 --- a/pms/views/pms_availability_plan_rule_views.xml +++ b/pms/views/pms_availability_plan_rule_views.xml @@ -42,6 +42,7 @@ pms.availability.plan.rule + @@ -57,4 +58,12 @@ + + Availability Plan Rules + ir.actions.act_window + pms.availability.plan.rule + {'group_by':'availability_plan_id'} + + tree + diff --git a/pms/views/product_pricelist_item_views.xml b/pms/views/product_pricelist_item_views.xml index c2a231799..0226574f2 100644 --- a/pms/views/product_pricelist_item_views.xml +++ b/pms/views/product_pricelist_item_views.xml @@ -26,4 +26,25 @@ + + product.pricelist.item + + + + + + + + + + + + + Pricelists Items + ir.actions.act_window + product.pricelist.item + {'group_by':'pricelist_id'} + + tree + diff --git a/pms/wizards/wizard_massive_changes.py b/pms/wizards/wizard_massive_changes.py index 3750fd328..5c1453070 100644 --- a/pms/wizards/wizard_massive_changes.py +++ b/pms/wizards/wizard_massive_changes.py @@ -24,18 +24,23 @@ class AvailabilityWizard(models.TransientModel): ("pricelist", "Pricelist"), ("availability_plan", "Availability Plan"), ], - required=True, - default="availability_plan", + default=lambda self: "availability_plan" + if self._context.get("availability_plan_ids") + else "pricelist" + if self._context.get("pricelist_ids") + else "availability_plan", ) - availability_plan_id = fields.Many2one( - string="Availability Plan to apply massive changes", + + availability_plan_ids = fields.Many2many( comodel_name="pms.availability.plan", + string="Availability Plan to apply massive changes", check_pms_properties=True, # can be setted by context from availability plan detail ) - pricelist_id = fields.Many2one( - string="Pricelist to apply massive changes", + + pricelist_ids = fields.Many2many( comodel_name="product.pricelist", + string="Pricelist to apply massive changes", check_pms_properties=True, ) allowed_pricelist_ids = fields.One2many( @@ -51,9 +56,10 @@ class AvailabilityWizard(models.TransientModel): string="To", required=True, ) - room_type_id = fields.Many2one( - string="Room Type", + + room_type_ids = fields.Many2many( comodel_name="pms.room.type", + string="Room Type", check_pms_properties=True, ) price = fields.Float(string="Price") @@ -210,10 +216,10 @@ class AvailabilityWizard(models.TransientModel): ) def _default_avail_readonly(self): - return True if self._context.get("availability_plan_id") else False + return True if self._context.get("availability_plan_ids") else False def _default_pricelist_readonly(self): - return True if self._context.get("pricelist_id") else False + return True if self._context.get("pricelist_ids") else False @api.depends("massive_changes_on") def _compute_allowed_pricelist_ids(self): @@ -227,7 +233,7 @@ class AvailabilityWizard(models.TransientModel): @api.depends( "start_date", "end_date", - "room_type_id", + "room_type_ids", "apply_on_monday", "apply_on_tuesday", "apply_on_wednesday", @@ -236,7 +242,7 @@ class AvailabilityWizard(models.TransientModel): "apply_on_saturday", "apply_on_sunday", "apply_on_all_week", - "availability_plan_id", + "availability_plan_ids", "apply_quota", "apply_max_avail", "apply_min_stay", @@ -258,20 +264,21 @@ class AvailabilityWizard(models.TransientModel): ) def _compute_rules_to_overwrite(self): for record in self: - - if not record.availability_plan_id and self._context.get( - "availability_plan_id" + if not record.availability_plan_ids and self._context.get( + "availability_plan_ids" ): - record.availability_plan_id = self._context.get("availability_plan_id") + record.availability_plan_ids = [ + (4, self._context.get("availability_plan_ids")) + ] record.massive_changes_on = "availability_plan" - if record.availability_plan_id: + if record.availability_plan_ids: domain = [ - ("availability_plan_id", "=", record.availability_plan_id.id), + ("availability_plan_id", "in", record.availability_plan_ids.ids), ] - if record.room_type_id: - domain.append(("room_type_id", "=", record.room_type_id.id)) + if record.room_type_ids: + domain.append(("room_type_id", "in", record.room_type_ids.ids)) if record.start_date: domain.append(("date", ">=", record.start_date)) if record.end_date: @@ -284,7 +291,6 @@ class AvailabilityWizard(models.TransientModel): else: domain_overwrite = expression.OR(domain_overwrite) domain.extend(domain_overwrite) - week_days_to_apply = ( record.apply_on_monday, record.apply_on_tuesday, @@ -314,7 +320,7 @@ class AvailabilityWizard(models.TransientModel): @api.depends( "start_date", "end_date", - "room_type_id", + "room_type_ids", "apply_on_monday", "apply_on_tuesday", "apply_on_wednesday", @@ -323,18 +329,17 @@ class AvailabilityWizard(models.TransientModel): "apply_on_saturday", "apply_on_sunday", "apply_on_all_week", - "pricelist_id", + "pricelist_ids", ) def _compute_pricelist_items_to_overwrite(self): for record in self: - - if not record.pricelist_id and self._context.get("pricelist_id"): - record.pricelist_id = self._context.get("pricelist_id") + if not record.pricelist_ids and self._context.get("pricelist_ids"): + record.pricelist_ids = [(4, self._context.get("pricelist_ids"))] record.massive_changes_on = "pricelist" - if record.pricelist_id: + if record.pricelist_ids: domain = [ - ("pricelist_id", "=", record.pricelist_id.id), + ("pricelist_id", "in", record.pricelist_ids.ids), "|", ("pms_property_ids", "=", False), ("pms_property_ids", "in", record.pms_property_ids.ids), @@ -344,16 +349,21 @@ class AvailabilityWizard(models.TransientModel): domain.append(("date_start_overnight", ">=", record.start_date)) if record.end_date: domain.append(("date_end_overnight", "<=", record.end_date)) - - if record.room_type_id: + if record.room_type_ids: + room_type_ids = record.room_type_ids.ids + product_ids = ( + self.env["pms.room.type"] + .search([("id", "in", room_type_ids)]) + .mapped("product_id") + .ids + ) domain.append( ( - "product_tmpl_id", - "=", - record.room_type_id.product_id.product_tmpl_id.id, + "product_id", + "in", + product_ids, ) ) - week_days_to_apply = ( record.apply_on_monday, record.apply_on_tuesday, @@ -445,6 +455,7 @@ class AvailabilityWizard(models.TransientModel): ) # dates between start and end (both included) + items = [] for date in [ record.start_date + datetime.timedelta(days=x) for x in range(0, (record.end_date - record.start_date).days + 1) @@ -456,7 +467,7 @@ class AvailabilityWizard(models.TransientModel): ): continue - if not record.room_type_id: + if not record.room_type_ids: room_types = self.env["pms.room.type"].search( [ "|", @@ -465,119 +476,129 @@ class AvailabilityWizard(models.TransientModel): ] ) else: - room_types = [record.room_type_id] - for room_type in room_types: - for pms_property in record.pms_property_ids: + room_types = record.room_type_ids + for pms_property in record.pms_property_ids: + for room_type in room_types: if record.massive_changes_on == "pricelist": - - self.env["product.pricelist.item"].create( - { - "pricelist_id": record.pricelist_id.id, - "date_start_overnight": date, - "date_end_overnight": date, - "compute_price": "fixed", - "applied_on": "0_product_variant", - "product_id": room_type.product_id.id, - "fixed_price": record.price, - "min_quantity": record.min_quantity, - "pms_property_ids": [pms_property.id], - } - ) - else: - avail_plan_id = record.availability_plan_id.id - vals = {} - vals.update( - {"min_stay": record.min_stay} - if record.apply_min_stay - else {} - ) - vals.update( - {"min_stay_arrival": record.min_stay_arrival} - if record.apply_min_stay_arrival - else {} - ) - vals.update( - {"max_stay": record.max_stay} - if record.apply_max_stay - else {} - ) - - vals.update( - {"max_stay_arrival": record.max_stay_arrival} - if record.apply_max_stay_arrival - else {} - ) - vals.update( - {"quota": record.quota} if record.apply_quota else {} - ) - vals.update( - {"max_avail": record.max_avail} - if record.apply_max_avail - else {} - ) - - vals.update( - {"closed": record.closed} if record.apply_closed else {} - ) - vals.update( - {"closed_arrival": record.closed_arrival} - if record.apply_closed_arrival - else {} - ) - vals.update( - {"closed_departure": record.closed_departure} - if record.apply_closed_departure - else {} - ) - - if date in record.rules_to_overwrite.mapped( - "date" - ) and room_type in record.rules_to_overwrite.mapped( - "room_type_id" - ): - - overwrite = record.rules_to_overwrite.search( - [ - ("room_type_id", "=", room_type.id), - ("date", "=", date), - ] - ) - overwrite.write(vals) - else: - self.env["pms.availability.plan.rule"].create( + for pricelist in record.pricelist_ids: + pricelist_item = self.env[ + "product.pricelist.item" + ].create( { - "availability_plan_id": avail_plan_id, - "date": date, - "room_type_id": room_type.id, - "quota": record.quota, - "max_avail": record.max_avail, - "min_stay": record.min_stay, - "min_stay_arrival": record.min_stay_arrival, - "max_stay": record.max_stay, - "max_stay_arrival": record.max_stay_arrival, - "closed": record.closed, - "closed_arrival": record.closed_arrival, - "closed_departure": record.closed_departure, - "pms_property_id": pms_property.id, + "pricelist_id": pricelist.id, + "date_start_overnight": date, + "date_end_overnight": date, + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": room_type.product_id.id, + "fixed_price": record.price, + "min_quantity": record.min_quantity, + "pms_property_ids": [pms_property.id], } ) + items.append(pricelist_item.id) + else: + for avail_plan_id in record.availability_plan_ids: + vals = {} + vals.update( + {"min_stay": record.min_stay} + if record.apply_min_stay + else {} + ) + vals.update( + {"min_stay_arrival": record.min_stay_arrival} + if record.apply_min_stay_arrival + else {} + ) + vals.update( + {"max_stay": record.max_stay} + if record.apply_max_stay + else {} + ) + + vals.update( + {"max_stay_arrival": record.max_stay_arrival} + if record.apply_max_stay_arrival + else {} + ) + vals.update( + {"quota": record.quota} + if record.apply_quota + else {} + ) + vals.update( + {"max_avail": record.max_avail} + if record.apply_max_avail + else {} + ) + + vals.update( + {"closed": record.closed} + if record.apply_closed + else {} + ) + vals.update( + {"closed_arrival": record.closed_arrival} + if record.apply_closed_arrival + else {} + ) + vals.update( + {"closed_departure": record.closed_departure} + if record.apply_closed_departure + else {} + ) + + if date in record.rules_to_overwrite.mapped( + "date" + ) and room_type in record.rules_to_overwrite.mapped( + "room_type_id" + ): + overwrite = record.rules_to_overwrite.search( + [ + ("room_type_id", "=", room_type.id), + ("date", "=", date), + ] + ) + overwrite.write(vals) + items.append(overwrite.id) + else: + plan_rule = self.env[ + "pms.availability.plan.rule" + ].create( + { + "availability_plan_id": avail_plan_id.id, + "date": date, + "room_type_id": room_type.id, + "quota": record.quota, + "max_avail": record.max_avail, + "min_stay": record.min_stay, + "min_stay_arrival": record.min_stay_arrival, + "max_stay": record.max_stay, + "max_stay_arrival": record.max_stay_arrival, + "closed": record.closed, + "closed_arrival": record.closed_arrival, + "closed_departure": record.closed_departure, + "pms_property_id": pms_property.id, + } + ) + items.append(plan_rule.id) + action = {} if ( record.massive_changes_on == "pricelist" and not record.pricelist_readonly ): - action = self.env.ref("product.product_pricelist_action2").read()[0] - action["views"] = [ - (self.env.ref("pms.product_pricelist_view_form").id, "form") - ] - action["res_id"] = record.pricelist_id.id - return action + action = { + "view": self.env.ref("pms.product_pricelist_item_action2").read()[0] + } + if ( record.massive_changes_on == "availability_plan" and not record.avail_readonly ): - action = self.env.ref("pms.availability_action").read()[0] - action["views"] = [ - (self.env.ref("pms.availability_view_form").id, "form") - ] - action["res_id"] = record.availability_plan_id.id - return action + action = { + "view": self.env.ref( + "pms.availability_plan_rule_view_tree_action" + ).read()[0] + } + action["view"]["domain"] = [("id", "in", items)] + return action["view"] diff --git a/pms/wizards/wizard_massive_changes.xml b/pms/wizards/wizard_massive_changes.xml index 420c9434e..e0652d335 100644 --- a/pms/wizards/wizard_massive_changes.xml +++ b/pms/wizards/wizard_massive_changes.xml @@ -33,9 +33,11 @@ - + From e8bb9fd0d058ae5d9ea1193e9cb7077ddc90bf2d Mon Sep 17 00:00:00 2001 From: miguelpadin Date: Thu, 3 Jun 2021 00:21:27 +0200 Subject: [PATCH 2/6] [IMP] pms: manage pricelist of board services --- pms/models/pms_board_service_room_type.py | 9 + pms/models/pms_service.py | 4 +- pms/models/product_pricelist.py | 12 +- pms/models/product_pricelist_item.py | 81 ++- pms/tests/test_pms_pricelist.py | 589 ++++++++++++++++ pms/tests/test_pms_wizard_massive_changes.py | 405 ++++++++++- pms/views/product_pricelist_item_views.xml | 29 +- pms/views/product_pricelist_views.xml | 12 + pms/wizards/wizard_massive_changes.py | 674 +++++++++++++++---- pms/wizards/wizard_massive_changes.xml | 40 +- 10 files changed, 1688 insertions(+), 167 deletions(-) diff --git a/pms/models/pms_board_service_room_type.py b/pms/models/pms_board_service_room_type.py index 881042cb5..8beefc95e 100644 --- a/pms/models/pms_board_service_room_type.py +++ b/pms/models/pms_board_service_room_type.py @@ -109,6 +109,15 @@ class PmsBoardServiceRoomType(models.Model): total += service.amount record.update({"amount": total}) + def name_get(self): + res = [] + for record in self: + name = "{} - {}".format( + record.pms_board_service_id.name, record.pms_room_type_id.name + ) + res.append((record.id, name)) + return res + @api.constrains("by_default") def constrains_duplicated_board_defaul(self): for record in self: diff --git a/pms/models/pms_service.py b/pms/models/pms_service.py index 61b6835e7..6fbd0c2de 100644 --- a/pms/models/pms_service.py +++ b/pms/models/pms_service.py @@ -544,10 +544,10 @@ class PmsService(models.Model): board_service=board_room_type.id if board_room_type else False, uom=self.product_id.uom_id.id, fiscal_position=False, - property=self.pms_property_id.id, + property=self.reservation_id.pms_property_id.id, ) if date: - product_context["date_overnight"] = date + product_context["consumption_date"] = date if reservation and self.is_board_service: product_context["board_service"] = reservation.board_service_room_id.id product = self.product_id.with_context(product_context) diff --git a/pms/models/product_pricelist.py b/pms/models/product_pricelist.py index b76571c4c..cff0c5a07 100644 --- a/pms/models/product_pricelist.py +++ b/pms/models/product_pricelist.py @@ -69,6 +69,7 @@ class ProductPricelist(models.Model): def _compute_price_rule_get_items( self, products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids ): + board_service = True if self._context.get("board_service") else False if ( "property" in self._context and self._context["property"] @@ -84,8 +85,6 @@ class ProductPricelist(models.Model): ON item.pricelist_id = cab.product_pricelist_id LEFT JOIN product_pricelist_item_pms_property_rel lin ON item.id = lin.product_pricelist_item_id - LEFT JOIN board_service_pricelist_item_rel board - ON item.id = board.pricelist_item_id WHERE (lin.pms_property_id = %s OR lin.pms_property_id IS NULL) AND (cab.pms_property_id = %s OR cab.pms_property_id IS NULL) AND (item.product_tmpl_id IS NULL @@ -119,8 +118,6 @@ class ProductPricelist(models.Model): prod_tmpl_ids, prod_ids, categ_ids, - # on_board_service_bool, - # board_service_id, self.id, date, date, @@ -131,6 +128,13 @@ class ProductPricelist(models.Model): item_ids = [x[0] for x in self.env.cr.fetchall()] items = self.env["product.pricelist.item"].browse(item_ids) + if board_service: + items = items.filtered( + lambda x: x.board_service_room_type_id.id + == self._context.get("board_service") + ) + else: + items = items.filtered(lambda x: not x.board_service_room_type_id.id) else: items = super(ProductPricelist, self)._compute_price_rule_get_items( products_qty_partner, date, uom_id, prod_tmpl_ids, prod_ids, categ_ids diff --git a/pms/models/product_pricelist_item.py b/pms/models/product_pricelist_item.py index 267f145a1..454e14d28 100644 --- a/pms/models/product_pricelist_item.py +++ b/pms/models/product_pricelist_item.py @@ -1,6 +1,6 @@ # Copyright 2017 Alexandre Díaz, Pablo Quesada, Darío Lodeiros # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models +from odoo import api, fields, models class ProductPricelistItem(models.Model): @@ -26,18 +26,10 @@ class ProductPricelistItem(models.Model): string="End Date Overnight", help="End date to apply daily pricelist items", ) - on_board_service = fields.Boolean( - string="On Board Service", - help="Those included in Board Services", - ) - board_service_room_type_ids = fields.Many2many( - string="Board Services", - help="""Specify a Board services on Room Types.""", + board_service_room_type_id = fields.Many2one( + string="Board Service", + help="Specify a Board services on Room Types.", comodel_name="pms.board.service.room.type", - relation="board_service_pricelist_item_rel", - column1="pricelist_item_id", - column2="board_service_id", - ondelete="cascade", check_pms_properties=True, ) pricelist_id = fields.Many2one( @@ -55,3 +47,68 @@ class ProductPricelistItem(models.Model): help="Product template associated with the item", check_pms_properties=True, ) + allowed_board_service_product_ids = fields.Many2many( + string="Allowed board service products", + comodel_name="product.product", + store=True, + readonly=False, + compute="_compute_allowed_board_service_product_ids", + ) + + allowed_board_service_room_type_ids = fields.Many2many( + string="Allowed board service room types", + comodel_name="pms.board.service.room.type", + store=True, + readonly=False, + compute="_compute_allowed_board_service_room_type_ids", + ) + + @api.depends("board_service_room_type_id") + def _compute_allowed_board_service_product_ids(self): + for record in self: + domain = [] + if record.board_service_room_type_id: + domain.append( + ( + "id", + "in", + record.board_service_room_type_id.board_service_line_ids.mapped( + "product_id" + ).ids, + ) + ) + allowed_board_service_product_ids = self.env["product.product"].search( + domain + ) + record.allowed_board_service_product_ids = allowed_board_service_product_ids + + @api.depends("product_id") + def _compute_allowed_board_service_room_type_ids(self): + for record in self: + allowed_board_service_room_type_ids = [] + all_board_service_room_type_ids = self.env[ + "pms.board.service.room.type" + ].search([]) + if record.product_id: + for board_service_room_type_id in all_board_service_room_type_ids: + if ( + record.product_id + in board_service_room_type_id.board_service_line_ids.mapped( + "product_id" + ) + ): + allowed_board_service_room_type_ids.append( + board_service_room_type_id.id + ) + else: + allowed_board_service_room_type_ids = ( + all_board_service_room_type_ids.ids + ) + domain = [] + if allowed_board_service_room_type_ids: + domain.append(("id", "in", allowed_board_service_room_type_ids)) + record.allowed_board_service_room_type_ids = ( + self.env["pms.board.service.room.type"].search(domain) + if domain + else False + ) diff --git a/pms/tests/test_pms_pricelist.py b/pms/tests/test_pms_pricelist.py index 23fcd0218..853733852 100644 --- a/pms/tests/test_pms_pricelist.py +++ b/pms/tests/test_pms_pricelist.py @@ -2,6 +2,7 @@ import datetime from freezegun import freeze_time +from odoo import fields from odoo.exceptions import UserError, ValidationError from odoo.tests import common, tagged @@ -81,12 +82,51 @@ class TestPmsPricelist(common.SavepointCase): } ) + # pms.room + self.room1 = self.env["pms.room"].create( + { + "pms_property_id": self.property1.id, + "name": "Single 101", + "room_type_id": self.room_type.id, + "capacity": 2, + } + ) + self.pricelist = self.env["product.pricelist"].create( { "name": "pricelist_1", "pms_property_ids": [self.property1.id, self.property2.id], } ) + # product.product 1 + self.test_service_breakfast = self.env["product.product"].create( + {"name": "Test Breakfast"} + ) + + # pms.board.service + self.test_board_service_only_breakfast = self.env["pms.board.service"].create( + { + "name": "Test Only Breakfast", + "default_code": "CB1", + } + ) + # pms.board.service.line + self.board_service_line_single_1 = self.env["pms.board.service.line"].create( + { + "product_id": self.test_service_breakfast.id, + "pms_board_service_id": self.test_board_service_only_breakfast.id, + } + ) + + # pms.board.service.room.type + self.test_board_service_single = self.env["pms.board.service.room.type"].create( + { + "pms_room_type_id": self.room_type.id, + "pms_board_service_id": self.test_board_service_only_breakfast.id, + } + ) + + self.partner1 = self.env["res.partner"].create({"name": "Carles"}) def test_advanced_pricelist_exists(self): @@ -200,6 +240,555 @@ class TestPmsPricelist(common.SavepointCase): } ) + # board services pricelist items + def test_board_service_pricelist_item_apply_sale_dates(self): + # TEST CASE + # Pricelist item is created to apply on board services at SALE date. + # The reservation created take into account the board service + # pricelist item created previously according to the SALE date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start": datetime.datetime.combine( + date_from, datetime.datetime.min.time() + ), + "date_end": datetime.datetime.combine( + date_to, datetime.datetime.max.time() + ), + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.test_service_breakfast.id, + "board_service_room_type_id": self.test_board_service_single.id, + "fixed_price": expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now(), + "checkout": datetime.datetime.now() + datetime.timedelta(days=1), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + "board_service_room_id": self.test_board_service_single.id, + } + ) + # ASSERT + self.assertEqual( + reservation_created.service_ids.price_subtotal, + expected_price, + "The reservation created should take into account the board service" + " pricelist item created previously according to the SALE date.", + ) + + def test_board_service_pricelist_item_not_apply_sale_dates(self): + # TEST CASE + # Pricelist item is created to apply on board services at SALE date. + # The reservation created DONT take into account the board service pricelist + # item created previously according to the SALE date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + datetime.timedelta(days=1) + date_to = fields.date.today() + datetime.timedelta(days=1) + not_expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start": datetime.datetime.combine( + date_from, datetime.datetime.min.time() + ), + "date_end": datetime.datetime.combine( + date_to, datetime.datetime.max.time() + ), + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.test_service_breakfast.id, + "board_service_room_type_id": self.test_board_service_single.id, + "fixed_price": not_expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now(), + "checkout": datetime.datetime.now() + datetime.timedelta(days=1), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + "board_service_room_id": self.test_board_service_single.id, + } + ) + # ASSERT + self.assertNotEqual( + reservation_created.service_ids.price_subtotal, + not_expected_price, + "The reservation created shouldnt take into account the board service pricelist" + " item created previously according to the SALE date.", + ) + + def test_board_service_pricelist_item_apply_overnight_dates(self): + # TEST CASE + # Pricelist item is created to apply on board services + # at CONSUMPTION date. + # The reservation created take into account the board service + # pricelist item created previously according to the CONSUMPTION date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + datetime.timedelta(days=1) + date_to = fields.date.today() + datetime.timedelta(days=1) + expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start_overnight": date_from, + "date_end_overnight": date_to, + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.test_service_breakfast.id, + "board_service_room_type_id": self.test_board_service_single.id, + "fixed_price": expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now() + datetime.timedelta(days=1), + "checkout": datetime.datetime.now() + datetime.timedelta(days=2), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + "board_service_room_id": self.test_board_service_single.id, + } + ) + # ASSERT + self.assertEqual( + reservation_created.service_ids.price_subtotal, + expected_price, + "The reservation created should take into account the board service" + " pricelist item created previously according to the CONSUMPTION date.", + ) + + def test_board_service_pricelist_item_not_apply_overnight_dates(self): + # TEST CASE + # Pricelist item is created to apply on board services + # at CONSUMPTION date. + # The reservation created DONT take into account the board service + # pricelist item created previously according to the CONSUMPTION date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + datetime.timedelta(days=2) + date_to = fields.date.today() + datetime.timedelta(days=2) + not_expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start": datetime.datetime.combine( + date_from, datetime.datetime.min.time() + ), + "date_end": datetime.datetime.combine( + date_to, datetime.datetime.max.time() + ), + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.test_service_breakfast.id, + "board_service_room_type_id": self.test_board_service_single.id, + "fixed_price": not_expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now(), + "checkout": datetime.datetime.now() + datetime.timedelta(days=1), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + "board_service_room_id": self.test_board_service_single.id, + } + ) + # ASSERT + self.assertNotEqual( + reservation_created.service_ids.price_subtotal, + not_expected_price, + "The reservation created shouldnt take into account the board service" + " pricelist item created previously according to the CONSUMPTION date.", + ) + + # room types pricelist items + def test_room_type_pricelist_item_apply_sale_dates(self): + # TEST CASE + # Pricelist item is created to apply on room types + # at SALE date. + # The reservation created take into account the room type + # pricelist item created previously according to the SALE date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start": datetime.datetime.combine( + date_from, datetime.datetime.min.time() + ), + "date_end": datetime.datetime.combine( + date_to, datetime.datetime.max.time() + ), + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "fixed_price": expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now(), + "checkout": datetime.datetime.now() + datetime.timedelta(days=1), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ASSERT + self.assertEqual( + reservation_created.price_subtotal, + expected_price, + "The reservation created should take into account the room type" + " pricelist item created previously according to the SALE date.", + ) + + def test_room_type_pricelist_item_not_apply_sale_dates(self): + # TEST CASE + # Pricelist item is created to apply on room types + # at SALE date. + # The reservation created DONT take into account the room type + # pricelist item created previously according to the SALE date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + datetime.timedelta(days=1) + date_to = fields.date.today() + datetime.timedelta(days=1) + not_expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start": datetime.datetime.combine( + date_from, datetime.datetime.min.time() + ), + "date_end": datetime.datetime.combine( + date_to, datetime.datetime.max.time() + ), + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "fixed_price": not_expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now(), + "checkout": datetime.datetime.now() + datetime.timedelta(days=1), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ASSERT + self.assertNotEqual( + reservation_created.price_subtotal, + not_expected_price, + "The reservation created shouldnt take into account the room type" + " pricelist item created previously according to the SALE date.", + ) + + def test_room_type_pricelist_item_apply_overnight_dates(self): + # TEST CASE + # Pricelist item is created to apply on room types + # at CONSUMPTION date. + # The reservation created take into account the room type + # pricelist item created previously according to the CONSUMPTION date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + datetime.timedelta(days=1) + date_to = fields.date.today() + datetime.timedelta(days=1) + expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start_overnight": date_from, + "date_end_overnight": date_to, + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "fixed_price": expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now() + datetime.timedelta(days=1), + "checkout": datetime.datetime.now() + datetime.timedelta(days=2), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ASSERT + self.assertEqual( + reservation_created.price_subtotal, + expected_price, + "The reservation created should take into account the room type" + " pricelist item created previously according to the CONSUMPTION date.", + ) + + def test_room_type_pricelist_item_not_apply_overnight_dates(self): + # TEST CASE + # Pricelist item is created to apply on room types + # at CONSUMPTION date. + # The reservation created DONT take into account the room type + # pricelist item created previously according to the CONSUMPTION date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + datetime.timedelta(days=2) + date_to = fields.date.today() + datetime.timedelta(days=2) + not_expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start": datetime.datetime.combine( + date_from, datetime.datetime.min.time() + ), + "date_end": datetime.datetime.combine( + date_to, datetime.datetime.max.time() + ), + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.room_type.product_id.id, + "fixed_price": not_expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now(), + "checkout": datetime.datetime.now() + datetime.timedelta(days=1), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + } + ) + # ASSERT + self.assertNotEqual( + reservation_created.price_subtotal, + not_expected_price, + "The reservation created shouldnt take into account the room type" + " pricelist item created previously according to the CONSUMPTION date.", + ) + + # services pricelist items + def test_service_pricelist_item_apply_sale_dates(self): + # TEST CASE + # Pricelist item is created to apply on services at SALE date. + # The reservation created take into account the service + # pricelist item created previously according to the SALE date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start": datetime.datetime.combine( + date_from, datetime.datetime.min.time() + ), + "date_end": datetime.datetime.combine( + date_to, datetime.datetime.max.time() + ), + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.test_service_breakfast.id, + "fixed_price": expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now(), + "checkout": datetime.datetime.now() + datetime.timedelta(days=1), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + "service_ids": [(0, 0, {"product_id": self.test_service_breakfast.id})], + } + ) + # ASSERT + self.assertEqual( + reservation_created.service_ids.price_subtotal, + expected_price, + "The reservation created should take into account the service" + " pricelist item created previously according to the SALE date.", + ) + + def test_service_pricelist_item_not_apply_sale_dates(self): + # TEST CASE + # Pricelist item is created to apply on services at SALE date. + # The reservation created DONT take into account the service pricelist + # item created previously according to the SALE date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + datetime.timedelta(days=1) + date_to = fields.date.today() + datetime.timedelta(days=1) + not_expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start": datetime.datetime.combine( + date_from, datetime.datetime.min.time() + ), + "date_end": datetime.datetime.combine( + date_to, datetime.datetime.max.time() + ), + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.test_service_breakfast.id, + "fixed_price": not_expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now(), + "checkout": datetime.datetime.now() + datetime.timedelta(days=1), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + "service_ids": [(0, 0, {"product_id": self.test_service_breakfast.id})], + } + ) + # ASSERT + self.assertNotEqual( + reservation_created.service_ids.price_subtotal, + not_expected_price, + "The reservation created shouldnt take into account the service pricelist" + " item created previously according to the SALE date.", + ) + + def test_service_pricelist_item_apply_overnight_dates(self): + # TEST CASE + # Pricelist item is created to apply on services at CONSUMPTION date. + # The reservation created take into account the service + # pricelist item created previously according to the CONSUMPTION date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + datetime.timedelta(days=1) + date_to = fields.date.today() + datetime.timedelta(days=1) + expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start_overnight": date_from, + "date_end_overnight": date_to, + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.test_service_breakfast.id, + "fixed_price": expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now() + datetime.timedelta(days=1), + "checkout": datetime.datetime.now() + datetime.timedelta(days=2), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + "service_ids": [(0, 0, {"product_id": self.test_service_breakfast.id})], + } + ) + # ASSERT + self.assertEqual( + reservation_created.service_ids.price_subtotal, + expected_price, + "The reservation created should take into account the service" + " pricelist item created previously according to the CONSUMPTION date.", + ) + + def test_service_pricelist_item_not_apply_overnight_dates(self): + # TEST CASE + # Pricelist item is created to apply on services at CONSUMPTION date. + # The reservation created DONT take into account the service pricelist + # item created previously according to the CONSUMPTION date. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + datetime.timedelta(days=2) + date_to = fields.date.today() + datetime.timedelta(days=2) + not_expected_price = 1000.0 + vals = { + "pricelist_id": self.pricelist.id, + "date_start": datetime.datetime.combine( + date_from, datetime.datetime.min.time() + ), + "date_end": datetime.datetime.combine( + date_to, datetime.datetime.max.time() + ), + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": self.test_service_breakfast.id, + "fixed_price": not_expected_price, + "pms_property_ids": [self.property1.id], + } + self.env["product.pricelist.item"].create(vals) + # ACT + reservation_created = self.env["pms.reservation"].create( + { + "partner_id": self.partner1.id, + "checkin": datetime.datetime.now(), + "checkout": datetime.datetime.now() + datetime.timedelta(days=1), + "preferred_room_id": self.room1.id, + "pms_property_id": self.property1.id, + "pricelist_id": self.pricelist.id, + "service_ids": [(0, 0, {"product_id": self.test_service_breakfast.id})], + } + ) + # ASSERT + self.assertNotEqual( + reservation_created.service_ids.price_subtotal, + not_expected_price, + "The reservation created shouldnt take into account the service pricelist " + "item created previously according to the CONSUMPTION date.", + ) + @freeze_time("2000-01-01") def test_pricelist_daily_failed(self): self.create_common_scenario() diff --git a/pms/tests/test_pms_wizard_massive_changes.py b/pms/tests/test_pms_wizard_massive_changes.py index 6cab0afca..c07afacb5 100644 --- a/pms/tests/test_pms_wizard_massive_changes.py +++ b/pms/tests/test_pms_wizard_massive_changes.py @@ -61,7 +61,6 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): self.test_room_type_class = self.env["pms.room.type.class"].create( {"name": "Room", "default_code": "ROOM"} ) - # pms.room.type self.test_room_type_single = self.env["pms.room.type"].create( { @@ -71,7 +70,6 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): "class_id": self.test_room_type_class.id, } ) - # pms.room.type self.test_room_type_double = self.env["pms.room.type"].create( { "pms_property_ids": [self.test_property.id], @@ -81,6 +79,62 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): } ) + # pms.board.service + self.test_board_service_only_breakfast = self.env["pms.board.service"].create( + { + "name": "Test Only Breakfast", + "default_code": "CB1", + } + ) + self.test_board_service_half_board = self.env["pms.board.service"].create( + { + "name": "Test Half Board", + "default_code": "CB2", + } + ) + # product.product 1 + self.test_service_breakfast = self.env["product.product"].create( + {"name": "Test Breakfast"} + ) + self.test_service_dinner = self.env["product.product"].create( + {"name": "Test Dinner"} + ) + self.test_service_spa = self.env["product.product"].create({"name": "Test Spa"}) + # pms.board.service.room.type + self.test_board_service_single = self.env["pms.board.service.room.type"].create( + { + "pms_room_type_id": self.test_room_type_single.id, + "pms_board_service_id": self.test_board_service_only_breakfast.id, + } + ) + self.test_board_service_double = self.env["pms.board.service.room.type"].create( + { + "pms_room_type_id": self.test_room_type_double.id, + "pms_board_service_id": self.test_board_service_half_board.id, + } + ) + # pms.board.service.line + self.board_service_line_single_1 = self.env["pms.board.service.line"].create( + { + "product_id": self.test_service_breakfast.id, + "pms_board_service_id": self.test_board_service_only_breakfast.id, + } + ) + self.board_service_line_double_1 = self.env["pms.board.service.line"].create( + { + "product_id": self.test_service_breakfast.id, + "pms_board_service_id": self.test_board_service_half_board.id, + } + ) + self.board_service_line_double_2 = self.board_service_line = self.env[ + "pms.board.service.line" + ].create( + { + "product_id": self.test_service_dinner.id, + "pms_board_service_id": self.test_board_service_half_board.id, + } + ) + # MASSIVE CHANGE WIZARD TESTS ON AVAILABILITY RULES @freeze_time("1980-12-01") @@ -498,7 +552,7 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): } ) - wizard = self.env["pms.massive.changes.wizard"].create( + wizard_result = self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "pricelist", "availability_plan_ids": [ @@ -522,7 +576,7 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): self.test_availability_plan.id, self.test_availability_plan_2.id, ] - for avail_plan_id in wizard["availability_plan_ids"].ids: + for avail_plan_id in wizard_result["availability_plan_ids"].ids: with self.subTest(k=avail_plan_id): self.assertIn( avail_plan_id, @@ -541,7 +595,7 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): } ) - wizard = self.env["pms.massive.changes.wizard"].create( + wizard_result = self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "pricelist", "pricelist_ids": [ @@ -555,18 +609,18 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): ) pricelist_ids = [self.test_pricelist.id, self.test_pricelist_2.id] - for pricelist_id in wizard["pricelist_ids"].ids: + for pricelist_id in wizard_result["pricelist_ids"].ids: with self.subTest(k=pricelist_id): self.assertIn( pricelist_id, pricelist_ids, "Pricelist has not been write " ) @freeze_time("2025-02-01") - def test_several_room_types(self): + def test_several_room_types_pricelist(self): self.create_common_scenario() date_from = fields.date.today() date_to = date_from + datetime.timedelta(days=6) - wizard = self.env["pms.massive.changes.wizard"].create( + wizard_result = self.env["pms.massive.changes.wizard"].create( { "massive_changes_on": "pricelist", "pricelist_ids": [(6, 0, [self.test_pricelist.id])], @@ -584,8 +638,341 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): ) room_type_ids = [self.test_room_type_double.id, self.test_room_type_double.id] - for room_type_id in wizard["room_type_ids"].ids: + for room_type_id in wizard_result["room_type_ids"].ids: with self.subTest(k=room_type_id): self.assertIn( room_type_id, room_type_ids, "Room type has not been write " ) + + @freeze_time("2025-02-01") + def test_several_room_types_availability_plan(self): + self.create_common_scenario() + date_from = fields.date.today() + date_to = date_from + datetime.timedelta(days=6) + wizard_result = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "availability_plan", + "availability_plan_ids": [(6, 0, [self.test_availability_plan.id])], + "room_type_ids": [ + ( + 6, + 0, + [self.test_room_type_double.id, self.test_room_type_double.id], + ) + ], + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + } + ) + + room_type_ids = [self.test_room_type_double.id, self.test_room_type_double.id] + for room_type_id in wizard_result["room_type_ids"].ids: + with self.subTest(k=room_type_id): + self.assertIn( + room_type_id, room_type_ids, "Room type has not been write " + ) + + @freeze_time("2025-02-01") + def test_one_board_service_room_type_no_board_service(self): + # TEST CASE + # Call to wizard with one board service room type and no + # board service. + # The wizard must create as many pricelist items as there + # are services on the given board service. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + wizard_result = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "pricelist", + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], + "apply_pricelists_on": "board_services", + "board_service_room_type_ids": [ + ( + 6, + 0, + [self.test_board_service_single.id], + ) + ], + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + "date_types": "consumption_dates", + } + ) + # ACT + wizard_result.apply_massive_changes() + + items_created = self.env["product.pricelist.item"].search( + [ + ("pricelist_id", "=", self.test_pricelist.id), + ("pms_property_ids", "=", self.test_property.id), + ("product_id", "=", self.board_service_line_single_1.product_id.id), + ] + ) + # ASSERT + self.assertIn( + self.test_service_breakfast, + items_created.mapped("product_id"), + "The wizard must create as many pricelist items as there " + "are services on the given board service.", + ) + + @freeze_time("2025-02-01") + def test_one_board_service_room_type_with_board_service(self): + # TEST CASE + # Call to wizard with one board service room type and + # board service. + # The wizard must create one pricelist items with + # the board service given. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + wizard_result = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "pricelist", + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], + "apply_pricelists_on": "board_services", + "board_service_room_type_ids": [ + ( + 6, + 0, + [self.test_board_service_single.id], + ) + ], + "board_service": self.board_service_line_single_1.product_id.id, + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + "date_types": "consumption_dates", + } + ) + # ACT + wizard_result.apply_massive_changes() + + items_created = self.env["product.pricelist.item"].search( + [ + ("pricelist_id", "=", self.test_pricelist.id), + ("pms_property_ids", "=", self.test_property.id), + ("product_id", "=", self.board_service_line_single_1.product_id.id), + ] + ) + # ASSERT + self.assertIn( + self.test_service_breakfast, + items_created.mapped("product_id"), + "The wizard must create one pricelist items with " + " the board service given.", + ) + + @freeze_time("2025-02-01") + def test_several_board_service_room_type_no_board_service(self): + # TEST CASE + # Call to wizard with several board service room type and no + # board service. + # The wizard must create as many pricelist items as there + # are services on the given board services. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + product_ids_expected = ( + self.test_board_service_double.pms_board_service_id.board_service_line_ids.mapped( + "product_id" + ).ids + + self.test_board_service_single.pms_board_service_id.board_service_line_ids.mapped( + "product_id" + ).ids + ) + wizard_result = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "pricelist", + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], + "apply_pricelists_on": "board_services", + "board_service_room_type_ids": [ + ( + 6, + 0, + [ + self.test_board_service_single.id, + self.test_board_service_double.id, + ], + ) + ], + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + "date_types": "consumption_dates", + } + ) + # ACT + wizard_result.apply_massive_changes() + + items_created = self.env["product.pricelist.item"].search( + [ + ("pricelist_id", "=", self.test_pricelist.id), + ("pms_property_ids", "=", self.test_property.id), + ("product_id", "in", product_ids_expected), + ] + ) + # ASSERT + self.assertEqual( + set(product_ids_expected), + set(items_created.mapped("product_id").ids), + "The wizard should create as many pricelist items as there" + " are services on the given board services.", + ) + + @freeze_time("2025-02-01") + def test_several_board_service_room_type_with_board_service(self): + # TEST CASE + # Call to wizard with several board service room types and + # board service. + # The wizard must create as many pricelist items as there + # are services on the given board services. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + board_service_id_double = self.test_board_service_double.pms_board_service_id + board_service_id_single = self.test_board_service_single.pms_board_service_id + product_ids_expected = list( + set(board_service_id_double.board_service_line_ids.mapped("product_id").ids) + & set( + board_service_id_single.board_service_line_ids.mapped("product_id").ids + ) + ) + wizard_result = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "pricelist", + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], + "apply_pricelists_on": "board_services", + "board_service_room_type_ids": [ + ( + 6, + 0, + [ + self.test_board_service_single.id, + self.test_board_service_double.id, + ], + ) + ], + "board_service": self.test_service_breakfast.id, + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + "date_types": "consumption_dates", + } + ) + # ACT + wizard_result.apply_massive_changes() + + items_created = self.env["product.pricelist.item"].search( + [ + ("pricelist_id", "=", self.test_pricelist.id), + ("pms_property_ids", "=", self.test_property.id), + ("product_id", "in", product_ids_expected), + ] + ) + # ASSERT + self.assertEqual( + set(product_ids_expected), + set(items_created.mapped("product_id").ids), + "The wizard should create as many pricelist items as there" + " are services on the given board services.", + ) + + @freeze_time("2025-02-01") + def test_service(self): + # TEST CASE + # Call to wizard with one service (product_id) + # The wizard must create one pricelist items with + # the given service (product_id). + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + wizard_result = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "pricelist", + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], + "apply_pricelists_on": "service", + "service": self.test_service_spa.id, + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + "date_types": "consumption_dates", + } + ) + # ACT + wizard_result.apply_massive_changes() + + items_created = self.env["product.pricelist.item"].search( + [ + ("pricelist_id", "=", self.test_pricelist.id), + ("pms_property_ids", "=", self.test_property.id), + ("product_id", "=", self.test_service_spa.id), + ] + ) + # ASSERT + self.assertIn( + self.test_service_spa.id, + items_created.mapped("product_id").ids, + "The wizard should create one pricelist items with" + " the given service (product_id).", + ) + + @freeze_time("2025-02-01") + def test_sale_dates(self): + # TEST CASE + # Call to wizard with one service (product_id) + # and dates of SALE + # The wizard must create one pricelist items with + # the given service (product_id) and dates of SALE. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + wizard_result = self.env["pms.massive.changes.wizard"].create( + { + "massive_changes_on": "pricelist", + "pricelist_ids": [(6, 0, [self.test_pricelist.id])], + "apply_pricelists_on": "service", + "service": self.test_service_spa.id, + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + "date_types": "sale_dates", + } + ) + # ACT + wizard_result.apply_massive_changes() + + items_created = self.env["product.pricelist.item"].search( + [ + ("pricelist_id", "=", self.test_pricelist.id), + ("pms_property_ids", "=", self.test_property.id), + ("product_id", "=", self.test_service_spa.id), + ] + ) + + expected_dates = [ + datetime.datetime.combine(date_from, datetime.datetime.min.time()), + datetime.datetime.combine(date_to, datetime.datetime.max.time()), + ] + # ASSERT + self.assertEqual( + expected_dates, + items_created.mapped("date_start") + items_created.mapped("date_end"), + "The wizard should create one pricelist items with" + " the given service (product_id) and dates of sale.", + ) diff --git a/pms/views/product_pricelist_item_views.xml b/pms/views/product_pricelist_item_views.xml index 0226574f2..6f65b1e20 100644 --- a/pms/views/product_pricelist_item_views.xml +++ b/pms/views/product_pricelist_item_views.xml @@ -5,13 +5,15 @@ - + + + + + + [('id', 'in',allowed_board_service_product_ids)] + product.pricelist.item - - - - - + + + + + + + + + diff --git a/pms/views/product_pricelist_views.xml b/pms/views/product_pricelist_views.xml index 3883064bd..3d3f19aa2 100644 --- a/pms/views/product_pricelist_views.xml +++ b/pms/views/product_pricelist_views.xml @@ -29,6 +29,18 @@ + + + + + +