diff --git a/pms/i18n/es.po b/pms/i18n/es.po index dd2d2e980..c1564f752 100644 --- a/pms/i18n/es.po +++ b/pms/i18n/es.po @@ -2681,8 +2681,8 @@ msgid "Employee" msgstr "Empleado/a" #. module: pms -#: model:ir.model.fields,field_description:pms.field_product_pricelist_item__date_end_overnight -msgid "End Date Overnight" +#: model:ir.model.fields,field_description:pms.field_product_pricelist_item__date_end_consumption +msgid "End Date Consumption" msgstr "Fin Noche Pernocta" #. module: pms @@ -2691,7 +2691,7 @@ msgid "End date for creation of reservations and folios" msgstr "" #. module: pms -#: model:ir.model.fields,help:pms.field_product_pricelist_item__date_end_overnight +#: model:ir.model.fields,help:pms.field_product_pricelist_item__date_end_consumption msgid "End date to apply daily pricelist items" msgstr "Fecha límite para aplicar los ítems de la tarifa diaria" @@ -7370,8 +7370,8 @@ msgid "Stage" msgstr "" #. module: pms -#: model:ir.model.fields,field_description:pms.field_product_pricelist_item__date_start_overnight -msgid "Start Date Overnight" +#: model:ir.model.fields,field_description:pms.field_product_pricelist_item__date_start_consumption +msgid "Start Date Consumption" msgstr "Fecha de Inicio Durante la Noche" #. module: pms @@ -7380,7 +7380,7 @@ msgid "Start date for creation of reservations and folios" msgstr "" #. module: pms -#: model:ir.model.fields,help:pms.field_product_pricelist_item__date_start_overnight +#: model:ir.model.fields,help:pms.field_product_pricelist_item__date_start_consumption msgid "Start date to apply daily pricelist items" msgstr "Fecha de inicio para aplicar los items de tarifa diarios" diff --git a/pms/i18n/pms.pot b/pms/i18n/pms.pot index c207dc904..0903f72d1 100644 --- a/pms/i18n/pms.pot +++ b/pms/i18n/pms.pot @@ -2532,8 +2532,8 @@ msgid "Employee" msgstr "" #. module: pms -#: model:ir.model.fields,field_description:pms.field_product_pricelist_item__date_end_overnight -msgid "End Date Overnight" +#: model:ir.model.fields,field_description:pms.field_product_pricelist_item__date_end_consumption +msgid "End Date Consumption" msgstr "" #. module: pms @@ -2542,7 +2542,7 @@ msgid "End date for creation of reservations and folios" msgstr "" #. module: pms -#: model:ir.model.fields,help:pms.field_product_pricelist_item__date_end_overnight +#: model:ir.model.fields,help:pms.field_product_pricelist_item__date_end_consumption msgid "End date to apply daily pricelist items" msgstr "" @@ -7015,8 +7015,8 @@ msgid "Stage" msgstr "" #. module: pms -#: model:ir.model.fields,field_description:pms.field_product_pricelist_item__date_start_overnight -msgid "Start Date Overnight" +#: model:ir.model.fields,field_description:pms.field_product_pricelist_item__date_start_consumption +msgid "Start Date Consumption" msgstr "" #. module: pms @@ -7025,7 +7025,7 @@ msgid "Start date for creation of reservations and folios" msgstr "" #. module: pms -#: model:ir.model.fields,help:pms.field_product_pricelist_item__date_start_overnight +#: model:ir.model.fields,help:pms.field_product_pricelist_item__date_start_consumption msgid "Start date to apply daily pricelist items" msgstr "" 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..db3811c9b 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 @@ -95,15 +94,15 @@ class ProductPricelist(models.Model): AND (item.pricelist_id = %s) AND (item.date_start IS NULL OR item.date_start <=%s) AND (item.date_end IS NULL OR item.date_end >=%s) - AND (item.date_start_overnight IS NULL - OR item.date_start_overnight <=%s) - AND (item.date_end_overnight IS NULL - OR item.date_end_overnight >=%s) + AND (item.date_start_consumption IS NULL + OR item.date_start_consumption <=%s) + AND (item.date_end_consumption IS NULL + OR item.date_end_consumption >=%s) GROUP BY item.id ORDER BY item.applied_on, - /* REVIEW: priotrity date sale / date overnight */ + /* REVIEW: priotrity date sale / date consumption */ item.date_end - item.date_start ASC, - item.date_end_overnight - item.date_start_overnight ASC, + item.date_end_consumption - item.date_start_consumption ASC, NULLIF((SELECT COUNT(1) FROM product_pricelist_item_pms_property_rel l WHERE item.id = l.product_pricelist_item_id) @@ -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 @@ -142,13 +146,10 @@ class ProductPricelist(models.Model): for record in self: if record.item_ids: for item in record.item_ids: - days_diff = ( - item.date_end_overnight - item.date_start_overnight - ).days if record.pricelist_type == "daily" and ( item.compute_price != "fixed" or len(record.pms_property_ids) != 1 - or days_diff > 1 + or item.date_end_consumption != item.date_start_consumption ): raise ValidationError( _( diff --git a/pms/models/product_pricelist_item.py b/pms/models/product_pricelist_item.py index 267f145a1..d6507ae46 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): @@ -18,26 +18,18 @@ class ProductPricelistItem(models.Model): ondelete="restrict", check_pms_properties=True, ) - date_start_overnight = fields.Date( - string="Start Date Overnight", + date_start_consumption = fields.Date( + string="Start Date Consumption", help="Start date to apply daily pricelist items", ) - date_end_overnight = fields.Date( - string="End Date Overnight", + date_end_consumption = fields.Date( + string="End Date Consumption", 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..7e04d8386 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_consumption_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_consumption": date_from, + "date_end_consumption": 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_consumption_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_consumption_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_consumption": date_from, + "date_end_consumption": 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_consumption_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_consumption_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_consumption": date_from, + "date_end_consumption": 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_consumption_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() @@ -207,43 +796,43 @@ class TestPmsPricelist(common.SavepointCase): { "compute_price": "fixed", "pms_property_ids": [self.property1.id, self.property2.id], - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.today() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.today() + datetime.timedelta(days=1), }, { "compute_price": "fixed", "pms_property_ids": False, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.today() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.today() + datetime.timedelta(days=1), }, { "compute_price": "percentage", "pms_property_ids": [self.property1.id], - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.today() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.today() + datetime.timedelta(days=1), }, { "compute_price": "percentage", "pms_property_ids": [self.property1.id, self.property2.id], - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.today() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.today() + datetime.timedelta(days=1), }, { "compute_price": "percentage", "pms_property_ids": False, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.today() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.today() + datetime.timedelta(days=1), }, { "compute_price": "fixed", "pms_property_ids": [self.property1.id], - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.today() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.today() + datetime.timedelta(days=3), }, ] @@ -258,8 +847,8 @@ class TestPmsPricelist(common.SavepointCase): "compute_price": tc["compute_price"], "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": tc["date_start_overnight"], - "date_end_overnight": tc["date_end_overnight"], + "date_start_consumption": tc["date_start_consumption"], + "date_end_consumption": tc["date_end_consumption"], } ) self.pricelist_test = self.env["product.pricelist"].create( @@ -281,9 +870,8 @@ class TestPmsPricelist(common.SavepointCase): "compute_price": "fixed", "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.today() - + datetime.timedelta(days=1), + "date_start_consumption": datetime.date.today(), + "date_end_consumption": datetime.date.today(), } ) self.pricelist_test = self.env["product.pricelist"].create( diff --git a/pms/tests/test_pms_pricelist_priority.py b/pms/tests/test_pms_pricelist_priority.py index 544ba1289..94011c18b 100644 --- a/pms/tests/test_pms_pricelist_priority.py +++ b/pms/tests/test_pms_pricelist_priority.py @@ -141,11 +141,11 @@ class TestPmsPricelistRules(common.SavepointCase): # - test cases to prioritize fields over other fields: # 1. applied_on # 2. date - # 3. date overnight + # 3. date consumption # 4. num. properties # 5. id # - tie - # - no [date_start|date_end|date_start_overnight|date_end_overnight] + # - no [date_start|date_end|date_start_consumption|date_end_consumption] properties = self.room_type.product_id.pms_property_ids.ids test_cases = [ { @@ -212,15 +212,15 @@ class TestPmsPricelistRules(common.SavepointCase): ], }, { - "name": "sorting OVERNIGHT date min range", + "name": "sorting CONSUMPTION date min range", "expected_price": 40.0 * 3, "items": [ { "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=6), "fixed_price": 60.0, "pms_property_ids": properties, @@ -229,8 +229,8 @@ class TestPmsPricelistRules(common.SavepointCase): "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=10), "fixed_price": 50.0, "pms_property_ids": properties, @@ -239,8 +239,8 @@ class TestPmsPricelistRules(common.SavepointCase): "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=3), "fixed_price": 40.0, "pms_property_ids": properties, @@ -329,7 +329,7 @@ class TestPmsPricelistRules(common.SavepointCase): ], }, { - "name": "prioritize SALE date over OVERNIGHT date", + "name": "prioritize SALE date over CONSUMPTION date", "expected_price": 120.0 * 3, "items": [ { @@ -346,8 +346,8 @@ class TestPmsPricelistRules(common.SavepointCase): "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=3), "fixed_price": 50.0, "pms_property_ids": properties, @@ -355,15 +355,15 @@ class TestPmsPricelistRules(common.SavepointCase): ], }, { - "name": "prioritize OVERNIGHT date over min. num. properties", + "name": "prioritize CONSUMPTION date over min. num. properties", "expected_price": 50.0 * 3, "items": [ { "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=3), "fixed_price": 120.0, "pms_property_ids": properties, @@ -372,8 +372,8 @@ class TestPmsPricelistRules(common.SavepointCase): "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=3), "pms_property_ids": [self.property1.id, self.property2.id], "fixed_price": 50.0, @@ -388,8 +388,8 @@ class TestPmsPricelistRules(common.SavepointCase): "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=3), "fixed_price": 120.0, "pms_property_ids": properties, @@ -398,8 +398,8 @@ class TestPmsPricelistRules(common.SavepointCase): "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=3), "pms_property_ids": [self.property1.id, self.property2.id], "fixed_price": 50.0, @@ -414,8 +414,8 @@ class TestPmsPricelistRules(common.SavepointCase): "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=3), "date_start": datetime.datetime.now(), "date_end": datetime.datetime.now() @@ -427,8 +427,8 @@ class TestPmsPricelistRules(common.SavepointCase): "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now() + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now() + datetime.timedelta(days=3), "date_start": datetime.datetime.now(), "date_end": datetime.datetime.now() @@ -468,43 +468,43 @@ class TestPmsPricelistRules(common.SavepointCase): ], }, { - "name": "no overnight DATE START", + "name": "no consumption DATE START", "expected_price": 40.0 + self.room_type.list_price * 2, "items": [ { "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_end_overnight": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now(), "fixed_price": 40.0, "pms_property_ids": properties, }, ], }, { - "name": "no overnight DATE END", + "name": "no consumption DATE END", "expected_price": 40.0 * 3, "items": [ { "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), + "date_start_consumption": datetime.datetime.now(), "fixed_price": 40.0, "pms_property_ids": properties, }, ], }, { - "name": "only applied overnight in one night", + "name": "only applied consumption in one night", "expected_price": 40.0 + self.room_type.list_price * 2, "items": [ { "pricelist_id": self.pricelist.id, "applied_on": "0_product_variant", "product_id": self.room_type.product_id.id, - "date_start_overnight": datetime.datetime.now(), - "date_end_overnight": datetime.datetime.now(), + "date_start_consumption": datetime.datetime.now(), + "date_end_consumption": datetime.datetime.now(), "fixed_price": 40.0, "pms_property_ids": properties, }, diff --git a/pms/tests/test_pms_wizard_folio.py b/pms/tests/test_pms_wizard_folio.py index 51751fcf3..a0ed6bd0c 100644 --- a/pms/tests/test_pms_wizard_folio.py +++ b/pms/tests/test_pms_wizard_folio.py @@ -271,8 +271,8 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): pricelist_item = self.env["product.pricelist.item"].create( { "pricelist_id": self.test_pricelist.id, - "date_start_overnight": checkin, - "date_end_overnight": checkin, + "date_start_consumption": checkin, + "date_end_consumption": checkin, "compute_price": "fixed", "applied_on": "1_product", "product_tmpl_id": product_tmpl.id, @@ -343,8 +343,8 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): # pricelist_item = self.env["product.pricelist.item"].create( # { # "pricelist_id": self.test_pricelist.id, - # "date_start_overnight": checkin, - # "date_end_overnight": checkin, + # "date_start_consumption": checkin, + # "date_end_consumption": checkin, # "compute_price": "fixed", # "applied_on": "1_product", # "product_tmpl_id": product_tmpl_id, diff --git a/pms/tests/test_pms_wizard_massive_changes.py b/pms/tests/test_pms_wizard_massive_changes.py index dc81206df..96aeb6302 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") @@ -99,10 +153,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 +193,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 +220,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 +241,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 +277,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 +332,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], @@ -298,6 +354,158 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): "another rules for the same day and room type", ) + @freeze_time("2025-12-01") + def test_several_availability_plan(self): + # TEST CASE + # If several availability plans are set, the wizard should create as + # many rules as availability plans. + + # ARRANGE + self.create_common_scenario() + self.test_availability_plan_2 = self.env["pms.availability.plan"].create( + { + "name": "Second availability plan for TEST", + "pms_pricelist_ids": [self.test_pricelist.id], + } + ) + expected_av_plans = [ + self.test_availability_plan.id, + self.test_availability_plan_2.id, + ] + date_from = fields.date.today() + date_to = fields.date.today() + vals_wizard = { + "massive_changes_on": "availability_plan", + "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, + } + # ACT + self.env["pms.massive.changes.wizard"].create( + vals_wizard + ).apply_massive_changes() + # ASSERT + self.assertEqual( + set(expected_av_plans), + set( + self.env["pms.availability.plan.rule"] + .search([("room_type_id", "=", self.test_room_type_double.id)]) + .mapped("availability_plan_id") + .ids + ), + "The wizard should create as many rules as availability plans given.", + ) + + @freeze_time("2025-02-01") + def test_several_room_types_availability_plan(self): + # TEST CASE + # If several room types are set, the wizard should create as + # many rules as room types. + + # ARRANGE + self.create_common_scenario() + self.test_availability_plan_2 = self.env["pms.availability.plan"].create( + { + "name": "Second availability plan for TEST", + "pms_pricelist_ids": [self.test_pricelist.id], + } + ) + expected_room_types = [ + self.test_room_type_double.id, + self.test_room_type_single.id, + ] + date_from = fields.date.today() + date_to = fields.date.today() + vals_wizard = { + "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_single.id], + ) + ], + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + } + # ACT + self.env["pms.massive.changes.wizard"].create( + vals_wizard + ).apply_massive_changes() + # ASSERT + self.assertEqual( + set(expected_room_types), + set( + self.env["pms.availability.plan.rule"] + .search([("availability_plan_id", "=", self.test_availability_plan.id)]) + .mapped("room_type_id") + .ids + ), + "The wizard should create as many rules as room types given.", + ) + + @freeze_time("1980-12-01") + def test_several_properties_availability_plan(self): + # TEST CASE + # If several properties are set, the wizard should create as + # many rules as properties. + + # ARRANGE + self.create_common_scenario() + self.test_property2 = self.env["pms.property"].create( + { + "name": "MY 2nd PMS TEST", + "company_id": self.env.ref("base.main_company").id, + } + ) + self.test_room_type_double.pms_property_ids = [ + (6, 0, [self.test_property.id, self.test_property2.id]) + ] + expected_properties = [ + self.test_property.id, + self.test_property2.id, + ] + date_from = fields.date.today() + date_to = fields.date.today() + vals_wizard = { + "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])], + "pms_property_ids": [ + (6, 0, [self.test_property.id, self.test_property2.id]) + ], + "start_date": date_from, + "end_date": date_to, + } + # ACT + self.env["pms.massive.changes.wizard"].create( + vals_wizard + ).apply_massive_changes() + # ASSERT + self.assertEqual( + set(expected_properties), + set( + self.env["pms.availability.plan.rule"] + .search([("availability_plan_id", "=", self.test_availability_plan.id)]) + .mapped("pms_property_id") + .ids + ), + "The wizard should create as many rules as properties given.", + ) + # MASSIVE CHANGE WIZARD TESTS ON PRICELIST ITEMS @freeze_time("1980-12-01") @@ -318,10 +526,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 +567,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,17 +610,17 @@ 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], } ).apply_massive_changes() - vals["date_start_overnight"] = date_from - vals["date_end_overnight"] = date_to + vals["date_start_consumption"] = date_from + vals["date_end_consumption"] = date_to del vals["date_start"] del vals["date_end"] @@ -446,8 +654,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], @@ -474,12 +682,451 @@ class TestPmsWizardMassiveChanges(common.SavepointCase): # ASSERT pricelist_items = self.test_pricelist.item_ids.sorted( - key=lambda s: s.date_start_overnight + key=lambda s: s.date_start_consumption ) # ASSERT self.assertTrue( - pricelist_items[index].date_start_overnight.timetuple()[6] == index + pricelist_items[index].date_start_consumption.timetuple()[6] + == index and test_case[index], "Rule not created on correct day of week", ) + + @freeze_time("2025-01-01") + def test_several_pricelists(self): + # TEST CASE + # If several pricelist are set, the wizard should create as + # many items as pricelists. + + # ARRANGE + self.create_common_scenario() + self.test_pricelist_2 = self.env["product.pricelist"].create( + { + "name": "test pricelist 2", + } + ) + expected_pricelists = [self.test_pricelist.id, self.test_pricelist_2.id] + + date_from = fields.date.today() + date_to = fields.date.today() + vals_wizard = { + "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, + } + # ACT + self.env["pms.massive.changes.wizard"].create( + vals_wizard + ).apply_massive_changes() + # ASSERT + self.assertEqual( + set(expected_pricelists), + set( + self.env["product.pricelist.item"] + .search([("product_id", "=", self.test_room_type_double.product_id.id)]) + .mapped("pricelist_id") + .ids + ), + "The wizard should create as many items as pricelists given.", + ) + + @freeze_time("2025-02-01") + def test_several_room_types_pricelist(self): + # TEST CASE + # If several room types are set, the wizard should create as + # many items as room types. + + # ARRANGE + self.create_common_scenario() + date_from = fields.date.today() + date_to = fields.date.today() + expected_product_ids = [ + self.test_room_type_double.product_id.id, + self.test_room_type_single.product_id.id, + ] + vals_wizard = { + "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_single.id], + ) + ], + "pms_property_ids": [self.test_property.id], + "start_date": date_from, + "end_date": date_to, + } + # ACT + self.env["pms.massive.changes.wizard"].create( + vals_wizard + ).apply_massive_changes() + # ASSERT + self.assertEqual( + set(expected_product_ids), + set( + self.env["product.pricelist.item"] + .search([("pricelist_id", "=", self.test_pricelist.id)]) + .mapped("product_id") + .ids + ), + "The wizard should create as many items as room types given.", + ) + + @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.", + ) + + def test_several_properties_pricelist(self): + # TEST CASE + # If several properties are set, the wizard should create as + # many items as properties. + + # ARRANGE + self.create_common_scenario() + self.test_property2 = self.env["pms.property"].create( + { + "name": "MY 2nd PMS TEST", + "company_id": self.env.ref("base.main_company").id, + } + ) + date_from = fields.date.today() + date_to = fields.date.today() + expected_properties = [ + self.test_property.id, + self.test_property2.id, + ] + vals_wizard = { + "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": [ + (6, 0, [self.test_property.id, self.test_property2.id]) + ], + "start_date": date_from, + "end_date": date_to, + "date_types": "sale_dates", + } + # ACT + self.env["pms.massive.changes.wizard"].create( + vals_wizard + ).apply_massive_changes() + # ASSERT + self.assertEqual( + set(expected_properties), + set( + self.env["product.pricelist.item"] + .search([("pricelist_id", "=", self.test_pricelist.id)]) + .mapped("pms_property_ids") + .ids + ), + "The wizard should create as many items as properties given.", + ) 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..41e7ebc22 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 + + + + + + + + + + + + + + + + + Pricelists Items + ir.actions.act_window + product.pricelist.item + {'group_by':'pricelist_id'} + + tree + diff --git a/pms/views/product_pricelist_views.xml b/pms/views/product_pricelist_views.xml index 3883064bd..ff7870024 100644 --- a/pms/views/product_pricelist_views.xml +++ b/pms/views/product_pricelist_views.xml @@ -19,8 +19,8 @@ expr="//field[@name='item_ids']/tree/field[@name='base']" position="after" > - - + + + + + + + + =", record.start_date)) if record.end_date: @@ -284,7 +439,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 +468,12 @@ class AvailabilityWizard(models.TransientModel): @api.depends( "start_date", "end_date", - "room_type_id", + "room_type_ids", + "board_service_room_type_ids", + "board_service", + "service", + "apply_pricelists_on", + "date_types", "apply_on_monday", "apply_on_tuesday", "apply_on_wednesday", @@ -323,37 +482,74 @@ class AvailabilityWizard(models.TransientModel): "apply_on_saturday", "apply_on_sunday", "apply_on_all_week", - "pricelist_id", + "pricelist_ids", + "pms_property_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_id"): + record.pricelist_ids = [(4, self._context.get("pricelist_id"))] record.massive_changes_on = "pricelist" - if record.pricelist_id: + if ( + record.pricelist_ids + and record.start_date + and record.end_date + and record.pms_property_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), ] - if record.start_date: - 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.date_types == "sale_dates": domain.append( ( - "product_tmpl_id", - "=", - record.room_type_id.product_id.product_tmpl_id.id, + "date_start", + ">=", + datetime.datetime.combine( + record.start_date, datetime.datetime.min.time() + ), ) ) + domain.append( + ( + "date_start", + "<=", + datetime.datetime.combine( + record.end_date, datetime.datetime.max.time() + ), + ) + ) + elif record.date_types == "consumption_dates": + domain.append(("date_start_consumption", ">=", record.start_date)) + domain.append(("date_end_consumption", "<=", record.end_date)) + product_ids = self.generate_product_ids_to_filter( + record.apply_pricelists_on, + record.room_type_ids, + record.board_service_room_type_ids, + record.board_service, + record.service, + ) + if product_ids: + domain.append( + ( + "product_id", + "in", + product_ids, + ) + ) + if record.board_service_room_type_ids: + domain.append( + ( + "board_service_room_type_id", + "in", + record.board_service_room_type_ids.ids, + ) + ) week_days_to_apply = ( record.apply_on_monday, record.apply_on_tuesday, @@ -371,11 +567,20 @@ class AvailabilityWizard(models.TransientModel): and record.start_date and record.end_date ): - record.pricelist_items_to_overwrite = items.filtered( - lambda x: week_days_to_apply[ - x.date_end_overnight.timetuple()[6] - ] - ) + items_filtered = False + if record.date_types == "consumption_dates": + items_filtered = items.filtered( + lambda x: x.date_end_consumption + and week_days_to_apply[ + x.date_end_consumption.timetuple()[6] + ] + ) + elif record.date_types == "sale_dates": + items_filtered = items.filtered( + lambda x: x.date_end + and week_days_to_apply[x.date_end.date().timetuple()[6]] + ) + record.pricelist_items_to_overwrite = items_filtered else: record.pricelist_items_to_overwrite = items else: @@ -430,6 +635,247 @@ class AvailabilityWizard(models.TransientModel): ) return domain_overwrite + @api.model + def generate_product_ids_to_filter( + self, + apply_pricelists_on, + room_type_ids, + board_service_room_type_ids, + board_service, + service, + ): + product_ids = False + all_room_type_ids = self.env["pms.room.type"].search([]).ids + + if apply_pricelists_on == "room_types": + room_type_ids = room_type_ids.ids + if not room_type_ids: + room_type_ids = all_room_type_ids + product_ids = ( + self.env["pms.room.type"] + .search([("id", "in", room_type_ids)]) + .mapped("product_id") + .ids + ) + elif apply_pricelists_on == "board_services": + if board_service: + product_ids = [board_service.id] + elif not board_service_room_type_ids and not board_service: + product_ids = ( + self.env["pms.board.service.room.type"] + .search([]) + .board_service_line_ids.mapped("product_id") + .ids + ) + else: + bsrti = board_service_room_type_ids + product_ids = bsrti.board_service_line_ids.mapped("product_id").ids + + elif apply_pricelists_on == "service": + domain = [] + product_ids_board_services = ( + self.env["pms.board.service.room.type"] + .search([]) + .board_service_line_ids.mapped("product_id") + .ids + ) + if product_ids_board_services: + domain.append(("id", "not in", product_ids_board_services)) + if service: + domain.append(("id", "=", service.id)) + product_ids = self.env["product.product"].search(domain).ids + + return product_ids + + @api.model + def generate_dates_vals( + self, + date_types, + vals, + date, + ): + if date_types == "sale_dates": + vals["date_start"] = datetime.datetime.combine( + date, datetime.datetime.min.time() + ) + vals["date_end"] = datetime.datetime.combine( + date, datetime.datetime.max.time() + ) + else: + vals["date_start_consumption"] = date + vals["date_end_consumption"] = date + return vals + + @api.model + def create_pricelists_items_room_types( + self, + room_types, + pricelist_ids, + price, + min_quantity, + pms_property, + date, + date_types, + ): + new_items = [] + for room_type in room_types: + for pricelist in pricelist_ids: + vals = { + "pricelist_id": pricelist.id, + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": room_type.product_id.id, + "fixed_price": price, + "min_quantity": min_quantity, + "pms_property_ids": [pms_property.id], + } + vals = self.generate_dates_vals(date_types, vals, date) + + pricelist_item = self.env["product.pricelist.item"].create(vals) + new_items.append(pricelist_item.id) + return new_items + + @api.model + def create_pricelists_items_board_services( + self, + board_service_room_type_ids, + pricelist_ids, + board_service, + price, + min_quantity, + pms_property, + date_types, + date, + ): + new_items = [] + for bs_room_type in board_service_room_type_ids: + for pricelist in pricelist_ids: + if board_service: + vals = { + "pricelist_id": pricelist.id, + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": board_service.id, + "board_service_room_type_id": bs_room_type.id, + "fixed_price": price, + "min_quantity": min_quantity, + "pms_property_ids": [pms_property.id], + } + vals = self.generate_dates_vals(date_types, vals, date) + + pricelist_item = self.env["product.pricelist.item"].create(vals) + new_items.append(pricelist_item.id) + + else: + for ( + board_service_line + ) in bs_room_type.pms_board_service_id.board_service_line_ids: + vals = { + "pricelist_id": pricelist.id, + "compute_price": "fixed", + "applied_on": "0_product_variant", + "product_id": board_service_line.product_id.id, + "board_service_room_type_id": bs_room_type.id, + "fixed_price": price, + "min_quantity": min_quantity, + "pms_property_ids": [pms_property.id], + } + vals = self.generate_dates_vals(date_types, vals, date) + + pricelist_item = self.env["product.pricelist.item"].create(vals) + new_items.append(pricelist_item.id) + return new_items + + @api.model + def create_availability_plans_rules( + self, + room_types, + availability_plan_ids, + min_stay, + apply_min_stay, + min_stay_arrival, + apply_min_stay_arrival, + max_stay, + apply_max_stay, + max_stay_arrival, + apply_max_stay_arrival, + quota, + apply_quota, + max_avail, + apply_max_avail, + closed, + apply_closed, + closed_arrival, + apply_closed_arrival, + closed_departure, + apply_closed_departure, + date, + rules_to_overwrite, + pms_property, + ): + new_items = [] + for room_type in room_types: + for avail_plan_id in availability_plan_ids: + vals = {} + vals.update({"min_stay": min_stay} if apply_min_stay else {}) + vals.update( + {"min_stay_arrival": min_stay_arrival} + if apply_min_stay_arrival + else {} + ) + vals.update({"max_stay": max_stay} if apply_max_stay else {}) + + vals.update( + {"max_stay_arrival": max_stay_arrival} + if apply_max_stay_arrival + else {} + ) + vals.update({"quota": quota} if apply_quota else {}) + vals.update({"max_avail": max_avail} if apply_max_avail else {}) + + vals.update({"closed": closed} if apply_closed else {}) + vals.update( + {"closed_arrival": closed_arrival} if apply_closed_arrival else {} + ) + vals.update( + {"closed_departure": closed_departure} + if apply_closed_departure + else {} + ) + + if date in rules_to_overwrite.mapped( + "date" + ) and room_type in rules_to_overwrite.mapped("room_type_id"): + overwrite = rules_to_overwrite.search( + [ + ("room_type_id", "=", room_type.id), + ("date", "=", date), + ] + ) + overwrite.write(vals) + new_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": quota, + "max_avail": max_avail, + "min_stay": min_stay, + "min_stay_arrival": min_stay_arrival, + "max_stay": max_stay, + "max_stay_arrival": max_stay_arrival, + "closed": closed, + "closed_arrival": closed_arrival, + "closed_departure": closed_departure, + "pms_property_id": pms_property.id, + } + ) + new_items.append(plan_rule.id) + + return new_items + def apply_massive_changes(self): for record in self: @@ -445,6 +891,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 +903,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 +912,109 @@ 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: - if record.massive_changes_on == "pricelist": + room_types = record.room_type_ids - self.env["product.pricelist.item"].create( - { - "pricelist_id": record.pricelist_id.id, - "date_start_overnight": date, - "date_end_overnight": date, + for pms_property in record.pms_property_ids: + if ( + record.massive_changes_on == "pricelist" + and record.apply_pricelists_on == "room_types" + ): + new_items = self.create_pricelists_items_room_types( + room_types, + record.pricelist_ids, + record.price, + record.min_quantity, + pms_property, + date, + record.date_types, + ) + items = items + new_items if new_items else items + + elif ( + record.massive_changes_on == "pricelist" + and record.apply_pricelists_on == "board_services" + ): + new_items = self.create_pricelists_items_board_services( + record.board_service_room_type_ids, + record.pricelist_ids, + record.board_service, + record.price, + record.min_quantity, + pms_property, + record.date_types, + date, + ) + items = items + new_items if new_items else items + + elif ( + record.massive_changes_on == "pricelist" + and record.apply_pricelists_on == "service" + ): + for pricelist in record.pricelist_ids: + if record.service: + vals = { + "pricelist_id": pricelist.id, "compute_price": "fixed", "applied_on": "0_product_variant", - "product_id": room_type.product_id.id, + "product_id": record.service.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( - { - "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, - } + vals = self.generate_dates_vals( + record.date_types, vals, date ) + + pricelist_item = self.env[ + "product.pricelist.item" + ].create(vals) + items.append(pricelist_item.id) + elif record.massive_changes_on == "availability_plan": + + new_items = self.create_availability_plans_rules( + room_types, + record.availability_plan_ids, + record.min_stay, + record.apply_min_stay, + record.min_stay_arrival, + record.apply_min_stay_arrival, + record.max_stay, + record.apply_max_stay, + record.max_stay_arrival, + record.apply_max_stay_arrival, + record.quota, + record.apply_quota, + record.max_avail, + record.apply_max_avail, + record.closed, + record.apply_closed, + record.closed_arrival, + record.apply_closed_arrival, + record.closed_departure, + record.apply_closed_departure, + date, + record.rules_to_overwrite, + pms_property, + ) + items = items + new_items if new_items else items 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] + } + action["view"]["domain"] = [("id", "in", items)] + return action["view"] + 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..dc87d505a 100644 --- a/pms/wizards/wizard_massive_changes.xml +++ b/pms/wizards/wizard_massive_changes.xml @@ -9,9 +9,10 @@ + - + + - + - + + + + + @@ -412,6 +452,7 @@ name="closed_departure" attrs="{'column_invisible':[('parent.apply_closed_departure', '==', False)]}" /> + - - + + + + + +