[ADD] pms: wizard massive changes on availability plans and pricelists (#28)

* [IMP] pms: wizard massive changes on availability plans

* [TEST] add creation rule based on weeek days

* [REF] pms: model av. plan, rule_ids & inv. name

* [IMP] pms: wizard called from pricelist & availability plans consistently

* [IMP] pms: wizard massive changes on pricelists

* [FIX] pms: fix creation pricelist items

* [FIX] pms: fix timezone on create pricelist items

* [TEST] pms: fix time zone issues in testing
This commit is contained in:
Miguel Padin
2020-12-22 10:53:13 +01:00
committed by GitHub
parent 977feac1e6
commit 5f7bd6b540
24 changed files with 1218 additions and 79 deletions

View File

@@ -52,7 +52,7 @@
"views/account_move_views.xml",
"views/res_users_views.xml",
"views/pms_room_type_class_views.xml",
"views/pms_room_type_availability_views.xml",
"views/pms_room_type_availability_plan_views.xml",
"views/pms_room_type_availability_rule_views.xml",
"views/pms_service_views.xml",
"views/pms_service_line_views.xml",
@@ -65,6 +65,7 @@
"views/webclient_templates.xml",
"views/ir_sequence_views.xml",
"wizards/wizard_reservation.xml",
"wizards/wizard_massive_changes.xml",
],
"demo": [
"demo/pms_master_data.xml",

View File

@@ -2,7 +2,10 @@
<odoo>
<data noupdate="1">
<!-- Basic pms -->
<record id="main_pms_room_type_availability" model="pms.room.type.availability">
<record
id="main_pms_room_type_availability_plan"
model="pms.room.type.availability.plan"
>
<field name="name">Availability Plan</field>
</record>
<record id="main_pms_property" model="pms.property">
@@ -10,8 +13,8 @@
<field name="company_id" ref="base.main_company" />
<field name="default_pricelist_id" ref="product.list0" />
<field
name="default_availability_id"
ref="main_pms_room_type_availability"
name="default_availability_plan_id"
ref="main_pms_room_type_availability_plan"
/>
<field name="street">Rua Street Demo, s/n</field>
<field name="city">Commitsun city</field>

View File

@@ -298,7 +298,10 @@
</field>
</record>
<!-- Multi pms Demo -->
<record id="demo_pms_room_type_availability" model="pms.room.type.availability">
<record
id="demo_pms_room_type_availability_plan"
model="pms.room.type.availability.plan"
>
<field name="name">Availability Plan Demo</field>
</record>
<record id="demo_pms_property" model="pms.property">
@@ -306,8 +309,8 @@
<field name="company_id" ref="base.main_company" />
<field name="default_pricelist_id" ref="product.list0" />
<field
name="default_availability_id"
ref="demo_pms_room_type_availability"
name="default_availability_plan_id"
ref="demo_pms_room_type_availability_plan"
/>
</record>
<!-- pms.room.type -->

View File

@@ -23,7 +23,7 @@ from . import account_move
from . import product_template
from . import res_company
from . import account_payment
from . import pms_room_type_availability
from . import pms_room_type_availability_plan
from . import pms_room_type_availability_rule
from . import pms_reservation_line
from . import pms_checkin_partner

View File

@@ -41,8 +41,8 @@ class PmsProperty(models.Model):
required=True,
help="The default pricelist used in this property.",
)
default_availability_id = fields.Many2one(
"pms.room.type.availability",
default_availability_plan_id = fields.Many2one(
"pms.room.type.availability.plan",
"Availability Plan",
required=True,
help="The default availability plan used in this property.",

View File

@@ -522,7 +522,7 @@ class PmsReservation(models.Model):
)
return
rooms_available = self.env[
"pms.room.type.availability"
"pms.room.type.availability.plan"
].rooms_available(
checkin=reservation.checkin,
checkout=reservation.checkout,
@@ -1103,7 +1103,7 @@ class PmsReservation(models.Model):
}
def open_reservation_wizard(self):
rooms_available = self.env["pms.room.type.availability"].rooms_available(
rooms_available = self.env["pms.room.type.availability.plan"].rooms_available(
checkin=self.checkin,
checkout=self.checkout,
current_lines=self.reservation_line_ids.ids,
@@ -1186,7 +1186,7 @@ class PmsReservation(models.Model):
def _autoassign(self):
self.ensure_one()
room_chosen = False
rooms_available = self.env["pms.room.type.availability"].rooms_available(
rooms_available = self.env["pms.room.type.availability.plan"].rooms_available(
checkin=self.checkin,
checkout=self.checkout,
room_type_id=self.room_type_id.id or False,

View File

@@ -109,7 +109,7 @@ class PmsReservationLine(models.Model):
free_room_select = True if reservation.preferred_room_id else False
# we get the rooms available for the entire stay
rooms_available = self.env[
"pms.room.type.availability"
"pms.room.type.availability.plan"
].rooms_available(
checkin=line.reservation_id.checkin,
checkout=line.reservation_id.checkout,
@@ -141,7 +141,9 @@ class PmsReservationLine(models.Model):
else:
line.room_id = rooms_available[0]
# check that the reservation cannot be allocated even by dividing it
elif not self.env["pms.room.type.availability"].splitted_availability(
elif not self.env[
"pms.room.type.availability.plan"
].splitted_availability(
checkin=line.reservation_id.checkin,
checkout=line.reservation_id.checkout,
room_type_id=line.reservation_id.room_type_id.id,
@@ -235,7 +237,9 @@ class PmsReservationLine(models.Model):
def _compute_impact_quota(self):
for line in self:
reservation = line.reservation_id
line.impacts_quota = self.env["pms.room.type.availability"].update_quota(
line.impacts_quota = self.env[
"pms.room.type.availability.plan"
].update_quota(
pricelist_id=reservation.pricelist_id,
room_type_id=reservation.room_type_id,
date=line.date,

View File

@@ -9,7 +9,7 @@ class PmsRoomTypeAvailability(models.Model):
"""The room type availability is used as a daily availability plan for room types
and therefore is related only with one property."""
_name = "pms.room.type.availability"
_name = "pms.room.type.availability.plan"
_description = "Reservation availability plan"
# Default methods
@@ -27,17 +27,15 @@ class PmsRoomTypeAvailability(models.Model):
pms_pricelist_ids = fields.One2many(
comodel_name="product.pricelist",
inverse_name="availability_id",
inverse_name="availability_plan_id",
string="Pricelists",
required=False,
ondelete="restrict",
)
item_ids = fields.One2many(
rule_ids = fields.One2many(
comodel_name="pms.room.type.availability.rule",
inverse_name="availability_id",
string="Rule Items",
copy=True,
inverse_name="availability_plan_id",
string="Availability Rules",
)
active = fields.Boolean(
@@ -104,7 +102,9 @@ class PmsRoomTypeAvailability(models.Model):
free_rooms = self.env["pms.room"].search(domain_rooms)
if pricelist:
domain_rules.append(("availability_id.pms_pricelist_ids", "=", pricelist))
domain_rules.append(
("availability_plan_id.pms_pricelist_ids", "=", pricelist)
)
rule_items = self.env["pms.room.type.availability.rule"].search(
domain_rules
)
@@ -149,7 +149,7 @@ class PmsRoomTypeAvailability(models.Model):
if pricelist_id and room_type_id and date:
rule = self.env["pms.room.type.availability.rule"].search(
[
("availability_id.pms_pricelist_ids", "=", pricelist_id.id),
("availability_plan_id.pms_pricelist_ids", "=", pricelist_id.id),
("room_type_id", "=", room_type_id.id),
("date", "=", date),
]
@@ -191,3 +191,19 @@ class PmsRoomTypeAvailability(models.Model):
old_rule.quota += 1
return False
# Action methods
def open_massive_changes_wizard(self):
if self.ensure_one():
return {
"view_type": "form",
"view_mode": "form",
"name": "Massive changes on Availability Plan: " + self.name,
"res_model": "pms.massive.changes.wizard",
"target": "new",
"type": "ir.actions.act_window",
"context": {
"availability_plan_id": self.id,
},
}

View File

@@ -10,8 +10,8 @@ class PmsRoomTypeAvailabilityRule(models.Model):
# Field Declarations
availability_id = fields.Many2one(
comodel_name="pms.room.type.availability",
availability_plan_id = fields.Many2one(
comodel_name="pms.room.type.availability.plan",
string="Availability Plan",
ondelete="cascade",
index=True,
@@ -71,7 +71,7 @@ class PmsRoomTypeAvailabilityRule(models.Model):
_sql_constraints = [
(
"room_type_registry_unique",
"unique(availability_id, room_type_id, date)",
"unique(availability_plan_id, room_type_id, date)",
"Only can exists one availability rule in the same \
day for the same room type!",
)

View File

@@ -22,8 +22,8 @@ class ProductPricelist(models.Model):
[("daily", "Daily Plan")], string="Pricelist Type", default="daily"
)
availability_id = fields.Many2one(
comodel_name="pms.room.type.availability",
availability_plan_id = fields.Many2one(
comodel_name="pms.room.type.availability.plan",
string="Availability Plan",
ondelete="restrict",
)
@@ -79,3 +79,19 @@ class ProductPricelist(models.Model):
)
)
return items
# Action methods
def open_massive_changes_wizard(self):
if self.ensure_one():
return {
"view_type": "form",
"view_mode": "form",
"name": "Massive changes on Pricelist: " + self.name,
"res_model": "pms.massive.changes.wizard",
"target": "new",
"type": "ir.actions.act_window",
"context": {
"pricelist_id": self.id,
},
}

View File

@@ -22,7 +22,7 @@ user_access_account_partial_reconcile,user_access_account_partial_reconcile,acco
user_access_pms_cancelation_rule,user_access_pms_cancelation_rule,model_pms_cancelation_rule,pms.group_pms_user,1,0,0,0
user_access_account_full_reconcile,user_access_account_full_reconcile,account.model_account_full_reconcile,pms.group_pms_user,1,1,1,1
user_access_property,user_access_property,model_pms_property,pms.group_pms_user,1,0,0,0
user_access_availability,user_access_availability,model_pms_room_type_availability,pms.group_pms_user,1,0,0,0
user_access_availability,user_access_availability,model_pms_room_type_availability_plan,pms.group_pms_user,1,0,0,0
user_access_pms_sale_channel,user_access_pms_sale_channel,model_pms_sale_channel,pms.group_pms_user,1,0,0,0
manager_access_pms_floor,manager_access_pms_floor,model_pms_floor,pms.group_pms_manager,1,1,1,1
manager_access_pms_amenity,manager_access_pms_amenity,model_pms_amenity,pms.group_pms_manager,1,1,1,1
@@ -45,6 +45,7 @@ manager_access_pms_board_service_room_type_line,manager_access_pms_board_service
manager_access_pms_board_service_line,manager_access_pms_board_service_line,model_pms_board_service_line,pms.group_pms_manager,1,1,1,1
manager_access_property,manager_access_property,model_pms_property,pms.group_pms_manager,1,1,1,1
manager_access_pms_cancelation_rule,manager_access_pms_cancelation_rule,model_pms_cancelation_rule,pms.group_pms_manager,1,1,1,1
manager_access_availability,manager_access_availability,model_pms_room_type_availability,pms.group_pms_manager,1,1,1,1
manager_access_availability,manager_access_availability,model_pms_room_type_availability_plan,pms.group_pms_manager,1,1,1,1
manager_access_pms_sale_channel,manager_access_pms_sale_channel,model_pms_sale_channel,pms.group_pms_manager,1,1,1,1
user_access_pms_reservation_wizard,user_access_pms_reservation_wizard,model_pms_reservation_wizard,pms.group_pms_user,1,1,1,1
user_access_pms_massive_changes_wizard,user_access_pms_massive_changes_wizard,model_pms_massive_changes_wizard,pms.group_pms_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
22 user_access_pms_cancelation_rule user_access_pms_cancelation_rule model_pms_cancelation_rule pms.group_pms_user 1 0 0 0
23 user_access_account_full_reconcile user_access_account_full_reconcile account.model_account_full_reconcile pms.group_pms_user 1 1 1 1
24 user_access_property user_access_property model_pms_property pms.group_pms_user 1 0 0 0
25 user_access_availability user_access_availability model_pms_room_type_availability model_pms_room_type_availability_plan pms.group_pms_user 1 0 0 0
26 user_access_pms_sale_channel user_access_pms_sale_channel model_pms_sale_channel pms.group_pms_user 1 0 0 0
27 manager_access_pms_floor manager_access_pms_floor model_pms_floor pms.group_pms_manager 1 1 1 1
28 manager_access_pms_amenity manager_access_pms_amenity model_pms_amenity pms.group_pms_manager 1 1 1 1
45 manager_access_pms_board_service_line manager_access_pms_board_service_line model_pms_board_service_line pms.group_pms_manager 1 1 1 1
46 manager_access_property manager_access_property model_pms_property pms.group_pms_manager 1 1 1 1
47 manager_access_pms_cancelation_rule manager_access_pms_cancelation_rule model_pms_cancelation_rule pms.group_pms_manager 1 1 1 1
48 manager_access_availability manager_access_availability model_pms_room_type_availability model_pms_room_type_availability_plan pms.group_pms_manager 1 1 1 1
49 manager_access_pms_sale_channel manager_access_pms_sale_channel model_pms_sale_channel pms.group_pms_manager 1 1 1 1
50 user_access_pms_reservation_wizard user_access_pms_reservation_wizard model_pms_reservation_wizard pms.group_pms_user 1 1 1 1
51 user_access_pms_massive_changes_wizard user_access_pms_massive_changes_wizard model_pms_massive_changes_wizard pms.group_pms_user 1 1 1 1

View File

@@ -26,4 +26,5 @@ from . import test_pms_checkin_partner
from . import test_pms_sale_channel
from . import test_pms_folio
from . import test_pms_room_type_availability_rules
from . import test_pms_room_type
from . import test_pms_room_type
from . import test_pms_wizard_massive_changes

View File

@@ -15,11 +15,11 @@ class TestPmsPricelistRules(common.TransactionCase):
{"name": "Category1"}
)
self.availability = self.env["pms.room.type.availability"].create(
self.availability_plan1 = self.env["pms.room.type.availability.plan"].create(
{"name": "Availability 1"}
)
self.availability2 = self.env["pms.room.type.availability"].create(
self.availability_plan2 = self.env["pms.room.type.availability.plan"].create(
{"name": "Availability"}
)
self.property1 = self.env["pms.property"].create(
@@ -27,7 +27,7 @@ class TestPmsPricelistRules(common.TransactionCase):
"name": "Property_1",
"company_id": self.env.ref("base.main_company").id,
"default_pricelist_id": self.env.ref("product.list0").id,
"default_availability_id": self.availability.id,
"default_availability_plan_id": self.availability_plan1.id,
}
)
@@ -36,7 +36,7 @@ class TestPmsPricelistRules(common.TransactionCase):
"name": "Property_2",
"company_id": self.env.ref("base.main_company").id,
"default_pricelist_id": self.env.ref("product.list0").id,
"default_availability_id": self.availability2.id,
"default_availability_plan_id": self.availability_plan2.id,
}
)

View File

@@ -12,9 +12,9 @@ from .common import TestHotel
class TestPmsReservations(TestHotel):
def create_common_scenario(self):
# create a room type availability
self.room_type_availability = self.env["pms.room.type.availability"].create(
{"name": "Availability plan for TEST"}
)
self.room_type_availability = self.env[
"pms.room.type.availability.plan"
].create({"name": "Availability plan for TEST"})
# create a property
self.property = self.env["pms.property"].create(
@@ -22,7 +22,7 @@ class TestPmsReservations(TestHotel):
"name": "MY PMS TEST",
"company_id": self.env.ref("base.main_company").id,
"default_pricelist_id": self.env.ref("product.list0").id,
"default_availability_id": self.room_type_availability.id,
"default_availability_plan_id": self.room_type_availability.id,
}
)

View File

@@ -15,8 +15,8 @@ class TestRoomType(SavepointCase):
"name": "p2",
"company_id": self.m1.id,
"default_pricelist_id": self.ref("product.list0"),
"default_availability_id": self.ref(
"pms.main_pms_room_type_availability"
"default_availability_plan_id": self.ref(
"pms.main_pms_room_type_availability_plan"
),
}
)
@@ -30,8 +30,8 @@ class TestRoomType(SavepointCase):
"name": "p3",
"company_id": self.m2.id,
"default_pricelist_id": self.ref("product.list0"),
"default_availability_id": self.ref(
"pms.main_pms_room_type_availability"
"default_availability_plan_id": self.ref(
"pms.main_pms_room_type_availability_plan"
),
}
)

View File

@@ -17,9 +17,9 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
"name": "test pricelist 1",
}
)
# pms.room.type.availability
# pms.room.type.availability.plan
self.test_room_type_availability1 = self.env[
"pms.room.type.availability"
"pms.room.type.availability.plan"
].create(
{
"name": "Availability plan for TEST",
@@ -32,7 +32,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
"name": "MY PMS TEST",
"company_id": self.env.ref("base.main_company").id,
"default_pricelist_id": self.test_pricelist1.id,
"default_availability_id": self.test_room_type_availability1.id,
"default_availability_plan_id": self.test_room_type_availability1.id,
}
)
# pms.room.type.class
@@ -127,7 +127,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
)
# ACT
result = self.env["pms.room.type.availability"].rooms_available(
result = self.env["pms.room.type.availability.plan"].rooms_available(
checkin=checkin,
checkout=checkout,
)
@@ -160,7 +160,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
)
# ACT
result = self.env["pms.room.type.availability"].rooms_available(
result = self.env["pms.room.type.availability.plan"].rooms_available(
checkin=checkin,
checkout=checkout,
current_lines=test_reservation.reservation_line_ids.ids,
@@ -188,7 +188,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
)
# ACT
result = self.env["pms.room.type.availability"].rooms_available(
result = self.env["pms.room.type.availability.plan"].rooms_available(
checkin=fields.date.today(),
checkout=(fields.datetime.today() + datetime.timedelta(days=4)).date(),
room_type_id=self.test_room_type_double.id,
@@ -215,14 +215,14 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
"pms.room.type.availability.rule"
].create(
{
"availability_id": self.test_room_type_availability1.id,
"availability_plan_id": self.test_room_type_availability1.id,
"room_type_id": self.test_room_type_double.id,
"date": (fields.datetime.today() + datetime.timedelta(days=2)).date(),
"closed": True, # <- (1/2)
}
)
# ACT
result = self.env["pms.room.type.availability"].rooms_available(
result = self.env["pms.room.type.availability.plan"].rooms_available(
checkin=fields.date.today(),
checkout=(fields.datetime.today() + datetime.timedelta(days=4)).date(),
# room_type_id=False, # <- (2/2)
@@ -249,7 +249,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
"pms.room.type.availability.rule"
].create(
{
"availability_id": self.test_room_type_availability1.id,
"availability_plan_id": self.test_room_type_availability1.id,
"room_type_id": self.test_room_type_double.id,
"date": (fields.datetime.today() + datetime.timedelta(days=0)).date(),
}
@@ -363,7 +363,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
# ACT
self.test_room_type_availability1_item1.write(test_case)
result = self.env["pms.room.type.availability"].rooms_available(
result = self.env["pms.room.type.availability.plan"].rooms_available(
checkin=checkin,
checkout=checkout,
room_type_id=self.test_room_type_double.id,
@@ -390,7 +390,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
"pms.room.type.availability.rule"
].create(
{
"availability_id": self.test_room_type_availability1.id,
"availability_plan_id": self.test_room_type_availability1.id,
"room_type_id": self.test_room_type_double.id,
"date": (fields.datetime.today() + datetime.timedelta(days=2)).date(),
"closed": True,
@@ -429,7 +429,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
"pms.room.type.availability.rule"
].create(
{
"availability_id": self.test_room_type_availability1.id,
"availability_plan_id": self.test_room_type_availability1.id,
"room_type_id": self.test_room_type_double.id,
"date": (fields.datetime.today() + datetime.timedelta(days=2)).date(),
"closed": True,
@@ -491,7 +491,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
"pms.room.type.availability.rule"
].create(
{
"availability_id": self.test_room_type_availability1.id,
"availability_plan_id": self.test_room_type_availability1.id,
"room_type_id": self.test_room_type_double.id,
"date": datetime.date.today(),
"quota": 1,
@@ -541,7 +541,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
)
rule = self.env["pms.room.type.availability.rule"].create(
{
"availability_id": self.test_room_type_availability1.id,
"availability_plan_id": self.test_room_type_availability1.id,
"room_type_id": self.test_room_type_double.id,
"date": datetime.date.today(),
"quota": test_quota,

View File

@@ -0,0 +1,414 @@
import datetime
import pytz
from freezegun import freeze_time
from odoo import fields
from .common import TestHotel
class TestPmsWizardMassiveChanges(TestHotel):
def create_common_scenario(self):
# product.pricelist
self.test_pricelist = self.env["product.pricelist"].create(
{
"name": "test pricelist 1",
}
)
# pms.room.type.availability.plan
self.test_availability_plan = self.env[
"pms.room.type.availability.plan"
].create(
{
"name": "Availability plan for TEST",
"pms_pricelist_ids": [(6, 0, [self.test_pricelist.id])],
}
)
# pms.property
self.test_property = self.env["pms.property"].create(
{
"name": "MY PMS TEST",
"company_id": self.env.ref("base.main_company").id,
"default_pricelist_id": self.test_pricelist.id,
"default_availability_plan_id": self.test_availability_plan.id,
}
)
# pms.room.type.class
self.test_room_type_class = self.env["pms.room.type.class"].create(
{"name": "Room"}
)
# pms.room.type
self.test_room_type_single = self.env["pms.room.type"].create(
{
"pms_property_ids": [self.test_property.id],
"name": "Single Test",
"code_type": "SNG_Test",
"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],
"name": "Double Test",
"code_type": "DBL_Test",
"class_id": self.test_room_type_class.id,
}
)
# MASSIVE CHANGE WIZARD TESTS ON AVAILABILITY RULES
@freeze_time("1980-12-01")
def test_num_availability_rules_create(self):
# TEST CASE
# rules should be created consistently for 1,2,3,4 days
# ARRANGE
self.create_common_scenario()
for days in [0, 1, 2, 3]:
with self.subTest(k=days):
num_exp_rules_to_create = days + 1
self.env["pms.massive.changes.wizard"].create(
{
"massive_changes_on": "availability_plan",
"availability_plan_id": 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,
}
).apply_massive_changes()
self.assertEqual(
len(self.test_availability_plan.rule_ids),
num_exp_rules_to_create,
"the number of rules created by should contains all the "
"days between start and finish (both included)",
)
@freeze_time("1980-12-01")
def test_num_availability_rules_create_no_room_type(self):
# TEST CASE
# (days x room_types) rules should be created
# ARRANGE
self.create_common_scenario()
date_from = fields.date.today()
date_to = fields.date.today() + datetime.timedelta(days=3)
num_room_types = self.env["pms.room.type"].search_count([])
num_exp_rules_to_create = ((date_to - date_from).days + 1) * num_room_types
# ACT
self.env["pms.massive.changes.wizard"].create(
{
"massive_changes_on": "availability_plan",
"availability_plan_id": self.test_availability_plan.id,
"start_date": date_from,
"end_date": date_to,
}
).apply_massive_changes()
# ASSERT
self.assertEqual(
len(self.test_availability_plan.rule_ids),
num_exp_rules_to_create,
"the number of rules created by the wizard should consider all "
"room types",
)
@freeze_time("1980-12-01")
def test_value_availability_rules_create(self):
# TEST CASE
# Rule values should be set correctly
# ARRANGE
self.create_common_scenario()
date_from = fields.date.today()
date_to = fields.date.today()
vals = {
"massive_changes_on": "availability_plan",
"availability_plan_id": self.test_availability_plan.id,
"start_date": date_from,
"end_date": date_to,
"room_type_id": self.test_room_type_double.id,
"quota": 50,
"max_avail": 5,
"min_stay": 10,
"min_stay_arrival": 10,
"max_stay": 10,
"max_stay_arrival": 10,
"closed": True,
"closed_arrival": True,
"closed_departure": True,
}
# ACT
self.env["pms.massive.changes.wizard"].create(vals).apply_massive_changes()
# ASSERT
del vals["massive_changes_on"]
del vals["availability_plan_id"]
del vals["start_date"]
del vals["end_date"]
del vals["room_type_id"]
for key in vals:
with self.subTest(k=key):
self.assertEqual(
self.test_availability_plan.rule_ids[0][key],
vals[key],
"The value of " + key + " is not correctly established",
)
@freeze_time("1980-12-01")
def test_day_of_week_availability_rules_create(self):
# TEST CASE
# rules for each day of week should be created
# ARRANGE
self.create_common_scenario()
test_case_week_days = [
[1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1],
]
date_from = fields.date.today()
date_to = fields.date.today() + datetime.timedelta(days=6)
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,
"start_date": date_from,
"end_date": date_to,
}
)
for index, test_case in enumerate(test_case_week_days):
with self.subTest(k=test_case):
# ARRANGE
wizard.write(
{
"apply_on_monday": test_case[0],
"apply_on_tuesday": test_case[1],
"apply_on_wednesday": test_case[2],
"apply_on_thursday": test_case[3],
"apply_on_friday": test_case[4],
"apply_on_saturday": test_case[5],
"apply_on_sunday": test_case[6],
}
)
# ACT
wizard.apply_massive_changes()
availability_rules = self.test_availability_plan.rule_ids.sorted(
key=lambda s: s.date
)
# ASSERT
self.assertTrue(
availability_rules[index].date.timetuple()[6] == index
and test_case[index],
"Rule not created on correct day of week",
)
# MASSIVE CHANGE WIZARD TESTS ON PRICELIST ITEMS
@freeze_time("1980-12-01")
def test_pricelist_items_create(self):
# TEST CASE
# items should be created consistently for 1,2,3,4 days
# ARRANGE
self.create_common_scenario()
for days in [0, 1, 2, 3]:
with self.subTest(k=days):
# ARRANGE
num_exp_items_to_create = days + 1
self.test_pricelist.item_ids = False
# ACT
self.env["pms.massive.changes.wizard"].create(
{
"massive_changes_on": "pricelist",
"pricelist_id": 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,
}
).apply_massive_changes()
# ASSERT
self.assertEqual(
len(
self.test_pricelist.item_ids
if self.test_pricelist.item_ids
else []
),
num_exp_items_to_create,
"the number of rules created by the wizard should include all the "
"days between start and finish (both included)",
)
@freeze_time("1980-12-01")
def test_num_pricelist_items_create_no_room_type(self):
# TEST CASE
# (days x room_types) items should be created
# ARRANGE
self.create_common_scenario()
date_from = fields.date.today()
date_to = fields.date.today() + datetime.timedelta(days=3)
num_room_types = self.env["pms.room.type"].search_count([])
num_exp_items_to_create = ((date_to - date_from).days + 1) * num_room_types
# ACT
self.env["pms.massive.changes.wizard"].create(
{
"massive_changes_on": "pricelist",
"pricelist_id": self.test_pricelist.id,
"start_date": date_from,
"end_date": date_to,
}
).apply_massive_changes()
# ASSERT
self.assertEqual(
len(self.test_pricelist.item_ids),
num_exp_items_to_create,
"the number of rules created by the wizard should consider all "
"room types when one is not applied",
)
@freeze_time("1980-12-01")
def test_value_pricelist_items_create(self):
# TEST CASE
# Item values should be set correctly
# ARRANGE
self.create_common_scenario()
date_from = fields.date.today()
date_to = fields.date.today()
price = 20
min_quantity = 3
vals = {
"pricelist_id": self.test_pricelist,
"date_start": datetime.datetime.combine(
date_from,
datetime.time.min,
),
"date_end": datetime.datetime.combine(
date_to,
datetime.time.max,
),
"compute_price": "fixed",
"applied_on": "1_product",
"product_tmpl_id": self.test_room_type_double.product_id.product_tmpl_id,
"fixed_price": price,
"min_quantity": min_quantity,
}
# ACT
self.env["pms.massive.changes.wizard"].create(
{
"massive_changes_on": "pricelist",
"pricelist_id": self.test_pricelist.id,
"start_date": date_from,
"end_date": date_to,
"room_type_id": self.test_room_type_double.id,
"price": price,
"min_quantity": min_quantity,
}
).apply_massive_changes()
vals["date_start"] = pytz.timezone("Europe/Madrid").localize(vals["date_start"])
vals["date_end"] = pytz.timezone("Europe/Madrid").localize(vals["date_end"])
# ASSERT
for key in vals:
with self.subTest(k=key):
if key == "date_start" or key == "date_end":
self.assertEqual(
fields.Datetime.context_timestamp(
self.test_pricelist.item_ids[0],
self.test_pricelist.item_ids[0][key],
),
vals[key],
"The value of " + key + " is not correctly established",
)
else:
self.assertEqual(
self.test_pricelist.item_ids[0][key],
vals[key],
"The value of " + key + " is not correctly established",
)
@freeze_time("1980-12-01")
def test_day_of_week_pricelist_items_create(self):
# TEST CASE
# items for each day of week should be created
# ARRANGE
self.create_common_scenario()
test_case_week_days = [
[1, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 1],
]
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_id": self.test_pricelist.id,
"room_type_id": self.test_room_type_double.id,
"start_date": date_from,
"end_date": date_to,
}
)
for index, test_case in enumerate(test_case_week_days):
with self.subTest(k=test_case):
# ARRANGE
wizard.write(
{
"apply_on_monday": test_case[0],
"apply_on_tuesday": test_case[1],
"apply_on_wednesday": test_case[2],
"apply_on_thursday": test_case[3],
"apply_on_friday": test_case[4],
"apply_on_saturday": test_case[5],
"apply_on_sunday": test_case[6],
}
)
self.test_pricelist.item_ids = False
# ACT
wizard.apply_massive_changes()
# ASSERT
pricelist_items = self.test_pricelist.item_ids.sorted(
key=lambda s: s.date_start
)
# ASSERT
self.assertTrue(
(
fields.Datetime.context_timestamp(
pricelist_items[index], pricelist_items[index].date_start
)
).timetuple()[6]
== index
and test_case[index],
"Rule not created on correct day of week",
)

View File

@@ -24,7 +24,10 @@
string="Price and Availability Plans"
>
<field name="default_pricelist_id" required="True" />
<field name="default_availability_id" required="True" />
<field
name="default_availability_plan_id"
required="True"
/>
</group>
<group string="Timezone">
<field name="tz" widget="timezone_mismatch" />

View File

@@ -1,12 +1,24 @@
<?xml version="1.0" ?>
<odoo>
<record id="room_type_availability_view_form" model="ir.ui.view">
<field name="name">pms.room.type.availability.form</field>
<field name="model">pms.room.type.availability</field>
<field name="name">pms.room.type.availability.plan.form</field>
<field name="model">pms.room.type.availability.plan</field>
<field name="arch" type="xml">
<form string="Rules">
<sheet>
<div class="oe_button_box" name="button_box">
<div class="oe_button_box " name="button_box">
<button
name="open_massive_changes_wizard"
type="object"
class="oe_stat_button mr-5"
icon="fa-magic"
>
<label
for="open_massive_changes_wizard"
string="Massive changes"
/>
</button>
<button
name="toggle_active"
type="object"
@@ -21,10 +33,12 @@
</button>
</div>
<div class="oe_title">
<label for="name" string="Name" />
<h1>
<field name="name" />
</h1>
<group>
<label for="name" string="Name" />
<h1>
<field name="name" />
</h1>
</group>
</div>
<group>
<field
@@ -38,19 +52,15 @@
/>
</group>
<separator string="Availability Rules" />
<field name="item_ids" nolabel="1">
<tree string="Availability Rules">
<field name="room_type_id" />
<field name="date" />
</tree>
</field>
<field name="rule_ids" nolabel="1" />
</sheet>
</form>
</field>
</record>
<record id="room_type_availability_view_tree" model="ir.ui.view">
<field name="name">pms.room.type.availability.tree</field>
<field name="model">pms.room.type.availability</field>
<field name="name">pms.room.type.availability.plan.tree</field>
<field name="model">pms.room.type.availability.plan</field>
<field name="arch" type="xml">
<tree string="Availability Plans">
<field name="name" />
@@ -67,7 +77,7 @@
<!-- Action of reservation availability plan-->
<record model="ir.actions.act_window" id="room_type_availability_action">
<field name="name">Reservation Availability Plans</field>
<field name="res_model">pms.room.type.availability</field>
<field name="res_model">pms.room.type.availability.plan</field>
<field name="view_mode">tree,form</field>
</record>
<!-- MENUS -->

View File

@@ -36,10 +36,17 @@
<field name="model">pms.room.type.availability.rule</field>
<field name="arch" type="xml">
<tree string="Availability rules">
<field name="room_type_id" />
<field name="date" />
<field name="room_type_id" />
<field name="quota" />
<field name="max_avail" />
<field name="min_stay" />
<field name="max_stay" />
<field name="min_stay_arrival" />
<field name="max_stay_arrival" />
<field name="closed" />
<field name="closed_arrival" />
<field name="closed_departure" />
</tree>
</field>
</record>

View File

@@ -12,8 +12,7 @@
/>
<field name="pricelist_type" />
<field name="cancelation_rule_id" />
<field name="availability_id" />
<field name="availability_plan_id" />
</xpath>
<xpath
expr="//field[@name='item_ids']/tree/field[@name='base']"
@@ -24,8 +23,27 @@
widget="many2many_tags"
options="{'no_create': True,'no_open': True}"
/>
</xpath>
<xpath expr="//widget[@name='web_ribbon']" position="after">
<div class="oe_button_box " name="button_box">
<button
name="open_massive_changes_wizard"
type="object"
class="oe_stat_button mr-5"
icon="fa-magic"
>
<label
for="open_massive_changes_wizard"
string="Massive changes"
/>
</button>
</div>
</xpath>
</field>
</record>
<menuitem
name="Pricelist"

View File

@@ -1 +1,2 @@
from . import wizard_reservation
from . import wizard_massive_changes

View File

@@ -0,0 +1,392 @@
import datetime
import pytz
from odoo import api, fields, models
class AvailabilityWizard(models.TransientModel):
_name = "pms.massive.changes.wizard"
_description = "Wizard for massive changes on Availability Plans & Pricelists."
# Fields declaration
massive_changes_on = fields.Selection(
[("pricelist", "Pricelist"), ("availability_plan", "Availability Plan")],
string="Massive changes on",
default="availability_plan",
required=True,
)
availability_plan_id = fields.Many2one(
comodel_name="pms.room.type.availability.plan",
string="Availability Plan to apply massive changes",
# can be setted by context from availability plan detail
)
pricelist_id = fields.Many2one(
comodel_name="product.pricelist",
string="Pricelist to apply massive changes",
)
allowed_pricelist_ids = fields.One2many(
comodel_name="product.pricelist", compute="_compute_allowed_pricelist_ids"
)
start_date = fields.Date(
string="From:",
required=True,
)
end_date = fields.Date(
string="To:",
required=True,
)
room_type_id = fields.Many2one(comodel_name="pms.room.type", string="Room Type")
price = fields.Float(string="Price")
min_quantity = fields.Float(string="Min. Quantity")
min_stay = fields.Integer(
string="Min. Stay",
default=0,
)
min_stay_arrival = fields.Integer(
string="Min. Stay Arrival",
default=0,
)
max_stay = fields.Integer(
string="Max. Stay",
default=0,
)
max_stay_arrival = fields.Integer(
string="Max. Stay Arrival",
default=0,
)
closed = fields.Boolean(
string="Closed",
default=False,
)
closed_departure = fields.Boolean(
string="Closed Departure",
default=False,
)
closed_arrival = fields.Boolean(
string="Closed Arrival",
default=False,
)
quota = fields.Integer(
string="Quota",
help="Generic Quota assigned.",
default=-1,
)
max_avail = fields.Integer(
string="Max. Availability",
help="Maximum simultaneous availability on own Booking Engine.",
default=-1,
)
apply_on_monday = fields.Boolean(
string="Apply Availability Rule on mondays",
default=False,
)
apply_on_tuesday = fields.Boolean(
string="Apply Availability Rule on tuesdays",
default=False,
)
apply_on_wednesday = fields.Boolean(
string="Apply Availability Rule on wednesdays",
default=False,
)
apply_on_thursday = fields.Boolean(
string="Apply Availability Rule on thursdays",
default=False,
)
apply_on_friday = fields.Boolean(
string="Apply Availability Rule on fridays",
default=False,
)
apply_on_saturday = fields.Boolean(
string="Apply Availability Rule on saturdays",
default=False,
)
apply_on_sunday = fields.Boolean(
string="Apply Availability Rule on sundays",
default=False,
)
apply_on_all_week = fields.Boolean(
string="Apply Availability Rule for the whole week",
default=True,
)
rules_to_overwrite = fields.One2many(
comodel_name="pms.room.type.availability.rule",
compute="_compute_rules_to_overwrite",
store=False,
readonly=True,
)
pricelist_items_to_overwrite = fields.One2many(
comodel_name="product.pricelist.item",
compute="_compute_pricelist_items_to_overwrite",
store=False,
readonly=True,
)
num_rules_to_overwrite = fields.Integer(
string="Rules to overwrite on massive changes",
compute="_compute_num_rules_to_overwrite",
store=False,
readonly=True,
)
num_pricelist_items_to_overwrite = fields.Integer(
string="Pricelist items to overwrite on massive changes",
compute="_compute_num_pricelist_items_to_overwrite",
store=False,
readonly=True,
)
avail_readonly = fields.Boolean(compute="_compute_avail_readonly")
pricelist_readonly = fields.Boolean(compute="_compute_pricelist_readonly")
def _compute_allowed_pricelist_ids(self):
for record in self:
record.allowed_pricelist_ids = self.env["product.pricelist"].search(
[
("pricelist_type", "=", "daily"),
]
)
@api.depends(
"start_date",
"end_date",
"room_type_id",
"apply_on_monday",
"apply_on_tuesday",
"apply_on_wednesday",
"apply_on_thursday",
"apply_on_friday",
"apply_on_saturday",
"apply_on_sunday",
"apply_on_all_week",
"availability_plan_id",
)
def _compute_rules_to_overwrite(self):
for record in self:
if not record.availability_plan_id and self._context.get(
"availability_plan_id"
):
record.availability_plan_id = self._context.get("availability_plan_id")
record.massive_changes_on = "availability_plan"
if record.availability_plan_id:
domain = [
("availability_plan_id", "=", record.availability_plan_id.id),
]
if record.room_type_id:
domain.append(("room_type_id", "=", record.room_type_id.id))
if record.start_date:
domain.append(("date", ">=", record.start_date))
if record.end_date:
domain.append(("date", "<=", record.end_date))
week_days_to_apply = (
record.apply_on_monday,
record.apply_on_tuesday,
record.apply_on_wednesday,
record.apply_on_thursday,
record.apply_on_friday,
record.apply_on_saturday,
record.apply_on_sunday,
)
if record.start_date and record.end_date:
rules = self.env["pms.room.type.availability.rule"].search(domain)
if (
not record.apply_on_all_week
and record.start_date
and record.end_date
):
record.rules_to_overwrite = rules.filtered(
lambda x: week_days_to_apply[x.date.timetuple()[6]]
)
else:
record.rules_to_overwrite = rules
else:
record.rules_to_overwrite = False
else:
record.rules_to_overwrite = False
@api.depends(
"start_date",
"end_date",
"room_type_id",
"apply_on_monday",
"apply_on_tuesday",
"apply_on_wednesday",
"apply_on_thursday",
"apply_on_friday",
"apply_on_saturday",
"apply_on_sunday",
"apply_on_all_week",
"pricelist_id",
)
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")
record.massive_changes_on = "pricelist"
if record.pricelist_id:
domain = [
("pricelist_id", "=", record.pricelist_id.id),
]
if record.start_date:
domain.append(("date_start", ">=", record.start_date))
if record.end_date:
domain.append(("date_end", "<=", record.end_date))
if record.room_type_id:
domain.append(
(
"product_tmpl_id",
"=",
record.room_type_id.product_id.product_tmpl_id.id,
)
)
week_days_to_apply = (
record.apply_on_monday,
record.apply_on_tuesday,
record.apply_on_wednesday,
record.apply_on_thursday,
record.apply_on_friday,
record.apply_on_saturday,
record.apply_on_sunday,
)
if record.start_date and record.end_date:
items = self.env["product.pricelist.item"].search(domain)
if (
not record.apply_on_all_week
and record.start_date
and record.end_date
):
record.pricelist_items_to_overwrite = items.filtered(
lambda x: week_days_to_apply[x.date_start.timetuple()[6]]
)
else:
record.pricelist_items_to_overwrite = items
else:
record.pricelist_items_to_overwrite = False
else:
record.pricelist_items_to_overwrite = False
@api.depends(
"rules_to_overwrite",
)
def _compute_num_rules_to_overwrite(self):
for record in self:
self.num_rules_to_overwrite = len(record.rules_to_overwrite)
@api.depends(
"pricelist_items_to_overwrite",
)
def _compute_num_pricelist_items_to_overwrite(self):
for record in self:
self.num_pricelist_items_to_overwrite = len(
record.pricelist_items_to_overwrite
)
def _compute_avail_readonly(self):
for record in self:
record.avail_readonly = (
True if self._context.get("availability_plan_id") else False
)
def _compute_pricelist_readonly(self):
for record in self:
record.pricelist_readonly = (
True if self._context.get("pricelist_id") else False
)
# actions
def apply_massive_changes(self):
tz = "Europe/Madrid"
for record in self:
# remove old rules
record.rules_to_overwrite.unlink()
record.pricelist_items_to_overwrite.unlink()
week_days_to_apply = (
record.apply_on_monday,
record.apply_on_tuesday,
record.apply_on_wednesday,
record.apply_on_thursday,
record.apply_on_friday,
record.apply_on_saturday,
record.apply_on_sunday,
)
# dates between start and end (both included)
for date in [
record.start_date + datetime.timedelta(days=x)
for x in range(0, (record.end_date - record.start_date).days + 1)
]:
if (
not record.apply_on_all_week
and not week_days_to_apply[date.timetuple()[6]]
):
continue
if not record.room_type_id:
rooms = self.env["pms.room.type"].search([])
else:
rooms = [record.room_type_id]
for room in rooms:
# REVIEW -> maybe would be more efficient creating a list
# and write all data in 1 operation
if record.massive_changes_on == "pricelist":
dt_from = datetime.datetime.combine(
date,
datetime.time.min,
)
dt_to = datetime.datetime.combine(
date,
datetime.time.max,
)
dt_from = pytz.timezone(tz).localize(dt_from)
dt_to = pytz.timezone(tz).localize(dt_to)
dt_from = dt_from.astimezone(pytz.utc)
dt_to = dt_to.astimezone(pytz.utc)
dt_from = dt_from.replace(tzinfo=None)
dt_to = dt_to.replace(tzinfo=None)
self.env["product.pricelist.item"].create(
{
"pricelist_id": record.pricelist_id.id,
"date_start": dt_from,
"date_end": dt_to,
"compute_price": "fixed",
"applied_on": "1_product",
"product_tmpl_id": room.product_id.product_tmpl_id.id,
"fixed_price": record.price,
"min_quantity": record.min_quantity,
}
)
else:
self.env["pms.room.type.availability.rule"].create(
{
"availability_plan_id": record.availability_plan_id.id,
"date": date,
"room_type_id": room.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,
}
)
# return {}

View File

@@ -0,0 +1,249 @@
<?xml version="1.0" ?>
<odoo>
<record id="massive_changes_wizard" model="ir.ui.view">
<field name="name">Availability Wizard</field>
<field name="model">pms.massive.changes.wizard</field>
<field name="arch" type="xml">
<form class="pt-1">
<group>
<field name="avail_readonly" invisible="1" />
<field name="pricelist_readonly" invisible="1" />
</group>
<div class="row">
<div class="col-5 ">
<group>
<field
name="start_date"
widget="daterange"
options="{'related_end_date': 'end_date'}"
/>
<field
name="end_date"
widget="daterange"
options="{'related_start_date': 'start_date'}"
/>
</group>
</div>
<div class="col-5">
<group class="">
<field
name="massive_changes_on"
attrs="{'invisible':['|', ('avail_readonly','=',True), ('pricelist_readonly', '=', True)]}"
/>
<field
name="availability_plan_id"
class="mr-5"
string="Availability Plan"
attrs="{'invisible':['|','|',('massive_changes_on','=','pricelist'), ('avail_readonly','=',True),
('pricelist_readonly', '=', True)],
'required': [('massive_changes_on','=','availability_plan')]}"
/>
<field
name="pricelist_id"
string="Pricelist"
attrs="{'invisible':['|','|',('massive_changes_on','=','availability_plan'),
('pricelist_readonly','=',True), ('pricelist_readonly', '=', True)],
'required': [('massive_changes_on','=','pricelist')]}"
domain="[('id', 'in', allowed_pricelist_ids)]"
/>
<field name="room_type_id" default_focus="1" />
</group>
</div>
</div>
<field name="allowed_pricelist_ids" invisible="1" />
<div class="row">
<div class="col-12">
<group>
<table class="table table-bordered text-center">
<thead>
<tr>
<th>All days</th>
<th>Sunday</th>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<field
name="apply_on_all_week"
widget="boolean_toggle"
/>
</td>
<td>
<field
name="apply_on_sunday"
widget="boolean_toggle"
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
/>
</td>
<td>
<field
name="apply_on_monday"
widget="boolean_toggle"
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
/>
</td>
<td>
<field
name="apply_on_tuesday"
widget="boolean_toggle"
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
/>
</td>
<td>
<field
name="apply_on_wednesday"
widget="boolean_toggle"
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
/>
</td>
<td>
<field
name="apply_on_thursday"
widget="boolean_toggle"
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
/>
</td>
<td>
<field
name="apply_on_friday"
widget="boolean_toggle"
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
/>
</td>
<td>
<field
name="apply_on_saturday"
widget="boolean_toggle"
attrs="{'invisible':[('apply_on_all_week','=',True)]}"
/>
</td>
</tr>
</tbody>
</table>
</group>
</div>
</div>
<b
attrs="{'invisible':['|','|', ('massive_changes_on','=','pricelist'), ('avail_readonly','=',True), ('pricelist_readonly', '=', True)]}"
>
Rules to apply:
</b>
<div
class="row"
attrs="{'invisible':[('massive_changes_on','=','pricelist')]}"
>
<div class="col-4">
<group>
<field string="Min. Stay" name="min_stay" />
<field string="Max. Stay" name="max_stay" />
</group>
</div>
<div class="col-4">
<group>
<field string="Min. Stay Arrival" name="min_stay_arrival" />
<field string="Max. Stay Arrival" name="max_stay_arrival" />
</group>
</div>
<div class="col-4">
<group>
<field string="Closed" name="closed" />
<field string="Closed Arrival" name="closed_arrival" />
<field string="Closed departure" name="closed_departure" />
</group>
</div>
<div class="col-4">
<group>
<field string="Quota" name="quota" />
</group>
</div>
<div class="col-4">
<group>
<field string="Max. Avail." name="max_avail" />
</group>
</div>
</div>
<div
class="row"
attrs="{'invisible':[('massive_changes_on','=','availability_plan')]}"
>
<div class="col-4">
<group>
<field name="price" />
<field name="min_quantity" />
</group>
</div>
</div>
<b attrs="{'invisible':[('massive_changes_on','=','pricelist')]}">
<span style="text-decoration:underline;">
<field name="num_rules_to_overwrite" />
</span>
availability rules
<u>will be overwritten:</u>
</b>
<b
attrs="{'invisible':[('massive_changes_on','=','availability_plan')]}"
>
<span style="text-decoration:underline;">
<field name="num_pricelist_items_to_overwrite" />
</span>
pricelist items
<u>will be overwritten:</u>
</b>
<!-- REVIEW: a calendar view could be more understandable -->
<field
name="rules_to_overwrite"
attrs="{'invisible':[('massive_changes_on','=','pricelist')]}"
/>
<field
name="pricelist_items_to_overwrite"
attrs="{'invisible':[('massive_changes_on','=','availability_plan')]}"
/>
<footer>
<button
name="apply_massive_changes"
string="Apply changes"
type="object"
class="btn-primary"
/>
or
<button
string="Cancel"
class="btn-default border"
special="cancel"
/>
</footer>
</form>
</field>
</record>
<record id="action_wizard_massive_changes" model="ir.actions.act_window">
<field name="name">Massive changes on Pricelist &amp; Availability Plans</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pms.massive.changes.wizard</field>
<field name="view_id" ref="massive_changes_wizard" />
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem
name="Massive Changes"
id="menu_pms_room_massive_changes_wizard"
action="action_wizard_massive_changes"
sequence="25"
parent="pms.configuration_others"
/>
</odoo>