mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[ADD] 14.0 pms real avail compute (#60)
* [ADD]pms: avail real * [ADD] Wizards adaptation multiproperty & new real avail model * [ADD] Tests Wizard avail
This commit is contained in:
@@ -201,7 +201,7 @@
|
||||
<field name="name">Open Talk Away Room</field>
|
||||
<field name="room_type_id" ref="pms_room_type_4" />
|
||||
<field name="floor_id" ref="pms_floor_0" />
|
||||
<field name="capacity">1</field>
|
||||
<field name="capacity">10</field>
|
||||
<field name="pms_property_id" ref="pms.main_pms_property" />
|
||||
</record>
|
||||
<!-- product.product for pms services -->
|
||||
|
||||
@@ -46,3 +46,4 @@ from . import folio_sale_line
|
||||
from . import account_bank_statement_line
|
||||
from . import account_bank_statement
|
||||
from . import account_journal
|
||||
from . import pms_room_type_availability
|
||||
|
||||
@@ -598,6 +598,8 @@ class PmsReservation(models.Model):
|
||||
|
||||
@api.depends(
|
||||
"reservation_line_ids.date",
|
||||
"reservation_line_ids.room_id",
|
||||
"reservation_line_ids.occupies_availability",
|
||||
"overbooking",
|
||||
"state",
|
||||
"preferred_room_id",
|
||||
@@ -618,7 +620,8 @@ class PmsReservation(models.Model):
|
||||
checkout=reservation.checkout,
|
||||
room_type_id=False, # Allow chosen any available room
|
||||
current_lines=reservation.reservation_line_ids.ids,
|
||||
pricelist=reservation.pricelist_id.id,
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
pms_property_id=reservation.pms_property_id.id,
|
||||
)
|
||||
reservation.allowed_room_ids = rooms_available
|
||||
|
||||
@@ -1314,7 +1317,8 @@ class PmsReservation(models.Model):
|
||||
checkin=self.checkin,
|
||||
checkout=self.checkout,
|
||||
current_lines=self.reservation_line_ids.ids,
|
||||
pricelist=self.pricelist_id.id,
|
||||
pricelist_id=self.pricelist_id.id,
|
||||
pms_property_id=self.pms_property_id.id,
|
||||
)
|
||||
# REVIEW: check capacity room
|
||||
return {
|
||||
@@ -1358,7 +1362,8 @@ class PmsReservation(models.Model):
|
||||
self.checkin,
|
||||
self.checkout,
|
||||
room_type_id=self.room_type_id.id,
|
||||
pricelist=self.pricelist_id.id,
|
||||
pricelist_id=self.pricelist_id.id,
|
||||
pms_property_id=self.pms_property_id.id,
|
||||
)
|
||||
if self.preferred_room_id.id in rooms_available.ids:
|
||||
default["preferred_room_id"] = self.preferred_room_id.id
|
||||
@@ -1410,7 +1415,8 @@ class PmsReservation(models.Model):
|
||||
checkin=self.checkin,
|
||||
checkout=self.checkout,
|
||||
room_type_id=self.room_type_id.id or False,
|
||||
pricelist=self.pricelist_id.id,
|
||||
pricelist_id=self.pricelist_id.id,
|
||||
pms_property_id=self.pms_property_id.id,
|
||||
)
|
||||
if rooms_available:
|
||||
room_chosen = rooms_available[0]
|
||||
|
||||
@@ -78,6 +78,14 @@ class PmsReservationLine(models.Model):
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
avail_id = fields.Many2one(
|
||||
string="Availability Day",
|
||||
comodel_name="pms.room.type.availability",
|
||||
ondelete="restrict",
|
||||
compute="_compute_avail_id",
|
||||
store=True,
|
||||
)
|
||||
|
||||
discount = fields.Float(string="Discount (%)", digits=("Discount"), default=0.0)
|
||||
occupies_availability = fields.Boolean(
|
||||
string="Occupies",
|
||||
@@ -108,7 +116,7 @@ class PmsReservationLine(models.Model):
|
||||
key=lambda r: (r.reservation_id, r.date)
|
||||
):
|
||||
reservation = line.reservation_id
|
||||
if reservation.preferred_room_id or not line.room_id:
|
||||
if reservation.preferred_room_id != line.room_id or not line.room_id:
|
||||
# If reservation has a preferred_room_id We can allow
|
||||
# select room_id regardless room_type_id selected on reservation
|
||||
free_room_select = True if reservation.preferred_room_id else False
|
||||
@@ -122,7 +130,8 @@ class PmsReservationLine(models.Model):
|
||||
if not free_room_select
|
||||
else False,
|
||||
current_lines=line.reservation_id.reservation_line_ids.ids,
|
||||
pricelist=line.reservation_id.pricelist_id.id,
|
||||
pricelist_id=line.reservation_id.pricelist_id.id,
|
||||
pms_property_id=line.pms_property_id.id,
|
||||
)
|
||||
# if there is availability for the entire stay
|
||||
if rooms_available:
|
||||
@@ -154,6 +163,7 @@ class PmsReservationLine(models.Model):
|
||||
room_type_id=line.reservation_id.room_type_id.id,
|
||||
current_lines=line._origin.reservation_id.reservation_line_ids.ids,
|
||||
pricelist=line.reservation_id.pricelist_id,
|
||||
pms_property_id=line.pms_property_id.id,
|
||||
):
|
||||
raise ValidationError(
|
||||
_("%s: No room type available")
|
||||
@@ -166,9 +176,11 @@ class PmsReservationLine(models.Model):
|
||||
|
||||
# we go through the rooms of the type
|
||||
for room in self.env["pms.room"].search(
|
||||
[("room_type_id", "=", reservation.room_type_id.id)]
|
||||
[
|
||||
("room_type_id", "=", reservation.room_type_id.id),
|
||||
("pms_property_id", "=", reservation.pms_property_id.id),
|
||||
]
|
||||
):
|
||||
|
||||
# we iterate the dates from the date of the line to the checkout
|
||||
for date_iterator in [
|
||||
line.date + datetime.timedelta(days=x)
|
||||
@@ -391,6 +403,35 @@ class PmsReservationLine(models.Model):
|
||||
# else:
|
||||
# reservation.reservation_line_ids.update({"cancel_discount": 0})
|
||||
|
||||
@api.depends("room_id", "pms_property_id", "date", "occupies_availability")
|
||||
def _compute_avail_id(self):
|
||||
for record in self:
|
||||
if (
|
||||
record.room_id.room_type_id
|
||||
and record.date
|
||||
and record.pms_property_id
|
||||
and record.occupies_availability
|
||||
):
|
||||
avail = self.env["pms.room.type.availability"].search(
|
||||
[
|
||||
("date", "=", record.date),
|
||||
("room_type_id", "=", record.room_id.room_type_id.id),
|
||||
("pms_property_id", "=", record.pms_property_id.id),
|
||||
]
|
||||
)
|
||||
if avail:
|
||||
record.avail_id = avail.id
|
||||
else:
|
||||
record.avail_id = self.env["pms.room.type.availability"].create(
|
||||
{
|
||||
"date": record.date,
|
||||
"room_type_id": record.room_id.room_type_id.id,
|
||||
"pms_property_id": record.pms_property_id.id,
|
||||
}
|
||||
)
|
||||
else:
|
||||
record.avail_id = False
|
||||
|
||||
# Constraints and onchanges
|
||||
@api.constrains("date")
|
||||
def constrains_duplicated_date(self):
|
||||
|
||||
@@ -18,6 +18,25 @@ class PmsRoomType(models.Model):
|
||||
_inherits = {"product.product": "product_id"}
|
||||
_order = "sequence, code_type, name"
|
||||
|
||||
# Defaults and Gets
|
||||
def name_get(self):
|
||||
result = []
|
||||
for room_type in self:
|
||||
name = room_type.name
|
||||
if self._context.get("checkin") and self._context.get("checkin"):
|
||||
avail = self.env[
|
||||
"pms.room.type.availability.plan"
|
||||
].get_count_rooms_available(
|
||||
checkin=self._context.get("checkin"),
|
||||
checkout=self._context.get("checkout"),
|
||||
room_type_id=room_type.id,
|
||||
pms_property_id=self._context.get("pms_property_id") or False,
|
||||
pricelist_id=self._context.get("pricelist_id") or False,
|
||||
)
|
||||
name += " (%s)" % avail
|
||||
result.append((room_type.id, name))
|
||||
return result
|
||||
|
||||
# Fields declaration
|
||||
product_id = fields.Many2one(
|
||||
"product.product",
|
||||
|
||||
88
pms/models/pms_room_type_availability.py
Normal file
88
pms/models/pms_room_type_availability.py
Normal file
@@ -0,0 +1,88 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class PmsRoomTypeAvailability(models.Model):
|
||||
_name = "pms.room.type.availability"
|
||||
_description = "Room type availability per day"
|
||||
|
||||
room_type_id = fields.Many2one(
|
||||
comodel_name="pms.room.type",
|
||||
string="Room Type",
|
||||
required=True,
|
||||
ondelete="cascade",
|
||||
readonly=True,
|
||||
)
|
||||
date = fields.Date(
|
||||
string="Date",
|
||||
required=True,
|
||||
readonly=True,
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
comodel_name="pms.property",
|
||||
string="Property",
|
||||
ondelete="restrict",
|
||||
required=True,
|
||||
readonly=True,
|
||||
)
|
||||
reservation_line_ids = fields.One2many(
|
||||
string="Reservation Lines",
|
||||
comodel_name="pms.reservation.line",
|
||||
inverse_name="avail_id",
|
||||
readonly=True,
|
||||
)
|
||||
real_avail = fields.Integer(
|
||||
compute="_compute_real_avail",
|
||||
store=True,
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
"room_type_registry_unique",
|
||||
"unique(room_type_id, date, pms_property_id)",
|
||||
"Only can exists one availability in the same \
|
||||
day for the same room type!",
|
||||
)
|
||||
]
|
||||
|
||||
@api.depends("reservation_line_ids.occupies_availability")
|
||||
def _compute_real_avail(self):
|
||||
for record in self:
|
||||
Rooms = self.env["pms.room"]
|
||||
RoomLines = self.env["pms.reservation.line"]
|
||||
total_rooms = Rooms.search_count(
|
||||
[
|
||||
("room_type_id", "=", record.room_type_id.id),
|
||||
("pms_property_id", "=", record.pms_property_id.id),
|
||||
]
|
||||
)
|
||||
room_ids = record.room_type_id.mapped("room_ids.id")
|
||||
rooms_not_avail = RoomLines.search_count(
|
||||
[
|
||||
("date", "=", record.date),
|
||||
("room_id", "in", room_ids),
|
||||
("pms_property_id", "=", record.pms_property_id.id),
|
||||
("occupies_availability", "=", True),
|
||||
# ("id", "not in", current_lines if current_lines else []),
|
||||
]
|
||||
)
|
||||
record.real_avail = total_rooms - rooms_not_avail
|
||||
|
||||
@api.constrains(
|
||||
"room_type_id",
|
||||
"pms_property_id",
|
||||
)
|
||||
def _check_property_integrity(self):
|
||||
for rec in self:
|
||||
if rec.pms_property_id and rec.room_type_id:
|
||||
if (
|
||||
rec.room_type_id.pms_property_ids.ids
|
||||
and rec.pms_property_id.id
|
||||
not in rec.room_type_id.pms_property_ids.ids
|
||||
):
|
||||
raise ValidationError(
|
||||
_("Property not allowed on availability day compute")
|
||||
)
|
||||
@@ -2,7 +2,9 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import datetime
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
|
||||
|
||||
class PmsRoomTypeAvailability(models.Model):
|
||||
@@ -69,66 +71,157 @@ class PmsRoomTypeAvailability(models.Model):
|
||||
checkout,
|
||||
room_type_id=False,
|
||||
current_lines=False,
|
||||
pricelist=False,
|
||||
pricelist_id=False,
|
||||
pms_property_id=False,
|
||||
):
|
||||
if current_lines and not isinstance(current_lines, list):
|
||||
current_lines = [current_lines]
|
||||
|
||||
rooms_not_avail = (
|
||||
self.env["pms.reservation.line"]
|
||||
.search(
|
||||
[
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout - datetime.timedelta(1)),
|
||||
("occupies_availability", "=", True),
|
||||
("id", "not in", current_lines if current_lines else []),
|
||||
]
|
||||
)
|
||||
.mapped("room_id.id")
|
||||
free_rooms = self.get_real_free_rooms(
|
||||
checkin, checkout, room_type_id, current_lines, pms_property_id
|
||||
)
|
||||
|
||||
domain_rooms = [
|
||||
("id", "not in", rooms_not_avail if len(rooms_not_avail) > 0 else []),
|
||||
]
|
||||
domain_rules = [
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout),
|
||||
(
|
||||
"date",
|
||||
"<=",
|
||||
checkout,
|
||||
), # TODO: only closed_departure take account checkout date!
|
||||
]
|
||||
|
||||
if pms_property_id:
|
||||
domain_rooms.append(("pms_property_id", "=", pms_property_id))
|
||||
domain_rules.append(("pms_property_id", "=", pms_property_id))
|
||||
|
||||
if room_type_id:
|
||||
domain_rooms.append(("room_type_id", "=", room_type_id))
|
||||
domain_rules.append(("room_type_id", "=", room_type_id))
|
||||
if pricelist_id:
|
||||
pricelist = self.env["product.pricelist"].browse(pricelist_id)
|
||||
if pricelist and pricelist.availability_plan_id:
|
||||
domain_rules.append(
|
||||
("availability_plan_id", "=", pricelist.availability_plan_id.id)
|
||||
)
|
||||
rule_items = self.env["pms.room.type.availability.rule"].search(
|
||||
domain_rules
|
||||
)
|
||||
|
||||
free_rooms = self.env["pms.room"].search(domain_rooms)
|
||||
if len(rule_items) > 0:
|
||||
room_types_to_remove = []
|
||||
for item in rule_items:
|
||||
if self.any_rule_applies(checkin, checkout, item):
|
||||
room_types_to_remove.append(item.room_type_id.id)
|
||||
free_rooms = free_rooms.filtered(
|
||||
lambda x: x.room_type_id.id not in room_types_to_remove
|
||||
)
|
||||
elif not pricelist:
|
||||
raise ValidationError(_("Pricelist not found"))
|
||||
return free_rooms.sorted(key=lambda r: r.sequence)
|
||||
|
||||
if pricelist:
|
||||
def get_real_free_rooms(
|
||||
self,
|
||||
checkin,
|
||||
checkout,
|
||||
room_type_id=False,
|
||||
current_lines=False,
|
||||
pms_property_id=False,
|
||||
):
|
||||
Avail = self.env["pms.room.type.availability"]
|
||||
if isinstance(checkin, str):
|
||||
checkin = datetime.datetime.strptime(
|
||||
checkin, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
if isinstance(checkout, str):
|
||||
checkout = datetime.datetime.strptime(
|
||||
checkout, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
domain = [
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout - datetime.timedelta(1)),
|
||||
]
|
||||
rooms_not_avail = (
|
||||
Avail.search(domain)
|
||||
.reservation_line_ids.filtered(
|
||||
lambda l: l.id not in current_lines if current_lines else []
|
||||
)
|
||||
.room_id.ids
|
||||
)
|
||||
domain_rooms = [
|
||||
("id", "not in", rooms_not_avail if rooms_not_avail else []),
|
||||
]
|
||||
if pms_property_id:
|
||||
domain_rooms.append(("pms_property_id", "=", pms_property_id))
|
||||
if room_type_id:
|
||||
domain_rooms.append(("room_type_id", "=", room_type_id))
|
||||
return self.env["pms.room"].search(domain_rooms)
|
||||
|
||||
@api.model
|
||||
def get_count_rooms_available(
|
||||
self,
|
||||
checkin,
|
||||
checkout,
|
||||
room_type_id,
|
||||
pms_property_id,
|
||||
current_lines=False,
|
||||
pricelist_id=False,
|
||||
):
|
||||
if current_lines and not isinstance(current_lines, list):
|
||||
current_lines = [current_lines]
|
||||
|
||||
avail = self.get_count_real_free_rooms(
|
||||
checkin, checkout, room_type_id, pms_property_id, current_lines
|
||||
)
|
||||
domain_rules = [
|
||||
("date", ">=", checkin),
|
||||
(
|
||||
"date",
|
||||
"<=",
|
||||
checkout,
|
||||
), # TODO: only closed_departure take account checkout date!
|
||||
("room_type_id", "=", room_type_id),
|
||||
("pms_property_id", "=", pms_property_id),
|
||||
]
|
||||
if pricelist_id:
|
||||
pricelist = self.env["product.pricelist"].browse(pricelist_id)
|
||||
if pricelist and pricelist.availability_plan_id:
|
||||
domain_rules.append(
|
||||
("availability_plan_id.pms_pricelist_ids", "=", pricelist)
|
||||
("availability_plan_id", "=", pricelist.availability_plan_id.id)
|
||||
)
|
||||
rule_items = self.env["pms.room.type.availability.rule"].search(
|
||||
domain_rules
|
||||
)
|
||||
|
||||
if len(rule_items) > 0:
|
||||
room_types_to_remove = []
|
||||
for item in rule_items:
|
||||
if self.any_rule_applies(checkin, checkout, item):
|
||||
room_types_to_remove.append(item.room_type_id.id)
|
||||
free_rooms = free_rooms.filtered(
|
||||
lambda x: x.room_type_id.id not in room_types_to_remove
|
||||
)
|
||||
return 0
|
||||
avail = min(rule_items.mapped("plan_avail"))
|
||||
return avail
|
||||
|
||||
# if pms_property_id:
|
||||
# free_rooms = free_rooms.filtered(
|
||||
# lambda x: x.pms_property_id = pms_property_id
|
||||
# )
|
||||
|
||||
return free_rooms.sorted(key=lambda r: r.sequence)
|
||||
def get_count_real_free_rooms(
|
||||
self,
|
||||
checkin,
|
||||
checkout,
|
||||
room_type_id,
|
||||
pms_property_id,
|
||||
current_lines=False,
|
||||
):
|
||||
Avail = self.env["pms.room.type.availability"]
|
||||
count_free_rooms = len(self.env["pms.room.type"].browse(room_type_id).room_ids)
|
||||
if isinstance(checkin, str):
|
||||
checkin = datetime.datetime.strptime(
|
||||
checkin, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
if isinstance(checkout, str):
|
||||
checkout = datetime.datetime.strptime(
|
||||
checkout, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
for avail in Avail.search(
|
||||
[
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout - datetime.timedelta(1)),
|
||||
("room_type_id", "=", room_type_id),
|
||||
("pms_property_id", "=", pms_property_id),
|
||||
]
|
||||
):
|
||||
if avail.real_avail < count_free_rooms:
|
||||
count_free_rooms = avail.real_avail
|
||||
return count_free_rooms
|
||||
|
||||
@api.model
|
||||
def splitted_availability(
|
||||
@@ -138,7 +231,16 @@ class PmsRoomTypeAvailability(models.Model):
|
||||
room_type_id=False,
|
||||
current_lines=False,
|
||||
pricelist=False,
|
||||
pms_property_id=False,
|
||||
):
|
||||
if isinstance(checkin, str):
|
||||
checkin = datetime.datetime.strptime(
|
||||
checkin, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
if isinstance(checkout, str):
|
||||
checkout = datetime.datetime.strptime(
|
||||
checkout, DEFAULT_SERVER_DATE_FORMAT
|
||||
).date()
|
||||
for date_iterator in [
|
||||
checkin + datetime.timedelta(days=x)
|
||||
for x in range(0, (checkout - checkin).days)
|
||||
@@ -148,7 +250,8 @@ class PmsRoomTypeAvailability(models.Model):
|
||||
checkout=date_iterator + datetime.timedelta(1),
|
||||
room_type_id=room_type_id,
|
||||
current_lines=current_lines,
|
||||
pricelist=pricelist.id,
|
||||
pricelist_id=pricelist.id,
|
||||
pms_property_id=pms_property_id,
|
||||
)
|
||||
if len(rooms_avail) < 1:
|
||||
return False
|
||||
|
||||
@@ -59,7 +59,6 @@ class PmsRoomTypeAvailabilityRule(models.Model):
|
||||
compute="_compute_quota",
|
||||
help="Generic Quota assigned.",
|
||||
)
|
||||
|
||||
max_avail = fields.Integer(
|
||||
string="Max. Availability",
|
||||
store=True,
|
||||
@@ -67,13 +66,12 @@ class PmsRoomTypeAvailabilityRule(models.Model):
|
||||
compute="_compute_max_avail",
|
||||
help="Maximum simultaneous availability on own Booking Engine.",
|
||||
)
|
||||
|
||||
pms_property_id = fields.Many2one(
|
||||
comodel_name="pms.property",
|
||||
string="Property",
|
||||
ondelete="restrict",
|
||||
required=True,
|
||||
)
|
||||
|
||||
allowed_property_ids = fields.Many2many(
|
||||
"pms.property",
|
||||
"allowed_availability_move_rel",
|
||||
@@ -84,6 +82,22 @@ class PmsRoomTypeAvailabilityRule(models.Model):
|
||||
readonly=True,
|
||||
compute="_compute_allowed_property_ids",
|
||||
)
|
||||
avail_id = fields.Many2one(
|
||||
string="Avail record",
|
||||
comodel_name="pms.room.type.availability",
|
||||
compute="_compute_avail_id",
|
||||
store=True,
|
||||
readonly=False,
|
||||
ondelete="restrict",
|
||||
)
|
||||
real_avail = fields.Integer(
|
||||
related="avail_id.real_avail",
|
||||
store="True",
|
||||
)
|
||||
plan_avail = fields.Integer(
|
||||
compute="_compute_plan_avail",
|
||||
store="True",
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
@@ -94,6 +108,44 @@ class PmsRoomTypeAvailabilityRule(models.Model):
|
||||
)
|
||||
]
|
||||
|
||||
@api.depends("room_type_id", "date", "pms_property_id")
|
||||
def _compute_avail_id(self):
|
||||
for record in self:
|
||||
if record.room_type_id and record.pms_property_id and record.date:
|
||||
avail = self.env["pms.room.type.availability"].search(
|
||||
[
|
||||
("date", "=", record.date),
|
||||
("room_type_id", "=", record.room_type_id.id),
|
||||
("pms_property_id", "=", record.pms_property_id.id),
|
||||
]
|
||||
)
|
||||
if avail:
|
||||
record.avail_id = avail.id
|
||||
else:
|
||||
record.avail_id = self.env["pms.room.type.availability"].create(
|
||||
{
|
||||
"date": record.date,
|
||||
"room_type_id": record.room_type_id.id,
|
||||
"pms_property_id": record.pms_property_id.id,
|
||||
}
|
||||
)
|
||||
else:
|
||||
record.avail_id = False
|
||||
|
||||
@api.depends("quota", "max_avail", "real_avail")
|
||||
def _compute_plan_avail(self):
|
||||
for record in self.filtered("real_avail"):
|
||||
real_avail = record.real_avail
|
||||
plan_avail = min(
|
||||
[
|
||||
record.max_avail if record.max_avail >= 0 else real_avail,
|
||||
record.quota if record.quota >= 0 else real_avail,
|
||||
real_avail,
|
||||
]
|
||||
)
|
||||
if not record.plan_avail or record.plan_avail != plan_avail:
|
||||
record.plan_avail = plan_avail
|
||||
|
||||
@api.depends("room_type_id")
|
||||
def _compute_quota(self):
|
||||
for record in self:
|
||||
|
||||
@@ -12,6 +12,7 @@ user_access_pms_room_type_class,user_access_pms_room_type_class,model_pms_room_t
|
||||
user_access_pms_room,user_access_pms_room,model_pms_room,pms.group_pms_user,1,0,0,0
|
||||
user_access_shared_pms_room,user_access_pms_shared_room,model_pms_shared_room,pms.group_pms_user,1,0,0,0
|
||||
user_access_pms_room_type_availability_rule,user_access_pms_room_type_availability_rule,model_pms_room_type_availability_rule,pms.group_pms_user,1,0,0,0
|
||||
user_access_pms_room_type_availability,user_access_pms_room_type_availability,model_pms_room_type_availability,pms.group_pms_user,1,1,1,0
|
||||
user_access_pms_reservation,user_access_pms_reservation,model_pms_reservation,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_folio,user_access_pms_folio,model_pms_folio,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_room_type,user_access_pms_room_type,model_pms_room_type,pms.group_pms_user,1,0,0,0
|
||||
@@ -38,6 +39,7 @@ manager_access_pms_room,manager_access_pms_room,model_pms_room,pms.group_pms_man
|
||||
manager_access_pms_shared_room,manager_access_pms_shared_room,model_pms_shared_room,pms.group_pms_manager,1,1,1,1
|
||||
manager_access_pms_room_type_availability_rule,manager_access_pms_room_type_availability_rule,model_pms_room_type_availability_rule,pms.group_pms_manager,1,1,1,1
|
||||
manager_access_pms_reservation,manager_access_pms_reservation,model_pms_reservation,pms.group_pms_manager,1,1,1,1
|
||||
manager_access_pms_room_type_availability,manager_access_pms_room_type_availability,model_pms_room_type_availability,pms.group_pms_manager,1,1,1,0
|
||||
manager_access_pms_folio,manager_access_pms_folio,model_pms_folio,pms.group_pms_manager,1,1,1,1
|
||||
manager_access_pms_room_type,manager_access_pms_room_type,model_pms_room_type,pms.group_pms_manager,1,1,1,1
|
||||
manager_access_pms_board_service_room_type,manager_access_pms_board_service_room_type,model_pms_board_service_room_type,pms.group_pms_manager,1,1,1,1
|
||||
|
||||
|
@@ -271,7 +271,6 @@ class TestPmsReservations(TestHotel):
|
||||
}
|
||||
)
|
||||
r_test.flush()
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
expected_num_changes,
|
||||
|
||||
@@ -262,6 +262,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"date": (fields.datetime.today() + datetime.timedelta(days=2)).date(),
|
||||
"closed": True, # <- (1/2)
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
# ACT
|
||||
@@ -269,7 +270,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
checkin=fields.date.today(),
|
||||
checkout=(fields.datetime.today() + datetime.timedelta(days=4)).date(),
|
||||
# room_type_id=False, # <- (2/2)
|
||||
pricelist=self.test_pricelist1.id,
|
||||
pricelist_id=self.test_pricelist1.id,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertNotIn(
|
||||
@@ -295,6 +296,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
"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(),
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -410,7 +412,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
room_type_id=self.test_room_type_double.id,
|
||||
pricelist=self.test_pricelist1.id,
|
||||
pricelist_id=self.test_pricelist1.id,
|
||||
)
|
||||
|
||||
# ASSERT
|
||||
@@ -437,6 +439,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"date": (fields.datetime.today() + datetime.timedelta(days=2)).date(),
|
||||
"closed": True,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
checkin = datetime.datetime.now()
|
||||
@@ -475,6 +478,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"date": (fields.datetime.today() + datetime.timedelta(days=2)).date(),
|
||||
"closed": True,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -537,6 +541,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"date": datetime.date.today(),
|
||||
"quota": 1,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
@@ -587,6 +592,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"date": datetime.date.today(),
|
||||
"quota": test_quota,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
reservation = self.env["pms.reservation"].create(
|
||||
@@ -687,7 +693,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
fields.datetime.today() + datetime.timedelta(days=2)
|
||||
).date(),
|
||||
room_type_id=self.test_room_type_special.id,
|
||||
pricelist=self.test_pricelist1.id,
|
||||
pricelist_id=self.test_pricelist1.id,
|
||||
pms_property_id=p["property"],
|
||||
)
|
||||
# ASSERT
|
||||
@@ -730,6 +736,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
"room_type_id": self.test_room_type_special.id,
|
||||
"date": (fields.datetime.today() + datetime.timedelta(days=2)).date(),
|
||||
"closed": True,
|
||||
"pms_property_id": self.test_property1.id,
|
||||
}
|
||||
)
|
||||
# Test cases when creating a availability_rule
|
||||
@@ -794,6 +801,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
"room_type_id": self.test_room_type_special.id,
|
||||
"date": (fields.datetime.today() + datetime.timedelta(days=2)).date(),
|
||||
"closed": True,
|
||||
"pms_property_id": self.test_property1.id,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -802,6 +810,3 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
|
||||
self.availability_rule1.allowed_property_ids.mapped("id"),
|
||||
"error",
|
||||
)
|
||||
|
||||
# plan 1 property 01 | rule property: False
|
||||
# plan 1 property 02 | rule property: False
|
||||
|
||||
@@ -150,7 +150,6 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
# Set values for the wizard and the total price is correct
|
||||
# Also check the discount is correctly applied to get
|
||||
# the total folio price
|
||||
# (no pricelist applied)
|
||||
|
||||
# ARRANGE
|
||||
# common scenario
|
||||
@@ -183,6 +182,8 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"start_date": checkin,
|
||||
"end_date": checkout,
|
||||
"partner_id": self.partner_id.id,
|
||||
"pms_property_id": self.test_property.id,
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -206,7 +207,6 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
)
|
||||
|
||||
lines_availability_test[0].num_rooms_selected = value
|
||||
|
||||
for discount in discounts:
|
||||
with self.subTest(k=discount):
|
||||
# ACT
|
||||
@@ -265,6 +265,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"end_date": checkout,
|
||||
"partner_id": self.partner_id.id,
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
wizard_folio.flush()
|
||||
@@ -395,6 +396,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"end_date": checkout,
|
||||
"partner_id": self.partner_id.id,
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
wizard_folio.flush()
|
||||
@@ -444,6 +446,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"end_date": checkout,
|
||||
"partner_id": self.partner_id.id,
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
wizard_folio.flush()
|
||||
@@ -495,6 +498,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"end_date": checkout,
|
||||
"partner_id": self.partner_id.id,
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
wizard_folio.flush()
|
||||
@@ -552,6 +556,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"end_date": checkout,
|
||||
"partner_id": self.partner_id.id,
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
wizard_folio.flush()
|
||||
@@ -585,6 +590,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"room_type_id": self.test_room_type_double,
|
||||
"partner_id": self.partner_id.id,
|
||||
"pricelist_id": folio.pricelist_id.id,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
|
||||
# ASSERT
|
||||
@@ -593,7 +599,8 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
with self.subTest(k=key):
|
||||
self.assertEqual(
|
||||
reservation[key].id
|
||||
if key in ["folio_id", "partner_id", "pricelist_id"]
|
||||
if key
|
||||
in ["folio_id", "partner_id", "pricelist_id", "pms_property_id"]
|
||||
else reservation[key],
|
||||
vals[key],
|
||||
"The value of " + key + " is not correctly established",
|
||||
@@ -620,6 +627,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"partner_id": self.partner_id.id,
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"discount": discount,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
wizard_folio.flush()
|
||||
@@ -655,3 +663,87 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
discount * 100,
|
||||
"The discount is not correctly established",
|
||||
)
|
||||
|
||||
def test_check_quota_avail(self):
|
||||
# TEST CASE
|
||||
# Check avail on room type with quota
|
||||
|
||||
# ARRANGE
|
||||
# common scenario
|
||||
self.create_common_scenario()
|
||||
|
||||
# checkin & checkout
|
||||
checkin = fields.date.today()
|
||||
checkout = fields.date.today() + datetime.timedelta(days=1)
|
||||
|
||||
self.env["pms.room.type.availability.rule"].create(
|
||||
{
|
||||
"quota": 1,
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"availability_plan_id": self.test_availability_plan.id,
|
||||
"date": fields.date.today(),
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
|
||||
# create folio wizard with partner id => pricelist & start-end dates
|
||||
wizard_folio = self.env["pms.folio.wizard"].create(
|
||||
{
|
||||
"start_date": checkin,
|
||||
"end_date": checkout,
|
||||
"partner_id": self.partner_id.id,
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
wizard_folio.flush()
|
||||
|
||||
room_type_plan_avail = wizard_folio.availability_results.filtered(
|
||||
lambda r: r.room_type_id.id == self.test_room_type_double.id
|
||||
).num_rooms_available
|
||||
|
||||
# ASSERT
|
||||
|
||||
self.assertEqual(room_type_plan_avail, 1, "Quota not applied in Wizard Folio")
|
||||
|
||||
def test_check_min_stay_avail(self):
|
||||
# TEST CASE
|
||||
# Check avail on room type with quota
|
||||
|
||||
# ARRANGE
|
||||
# common scenario
|
||||
self.create_common_scenario()
|
||||
|
||||
# checkin & checkout
|
||||
checkin = fields.date.today()
|
||||
checkout = fields.date.today() + datetime.timedelta(days=1)
|
||||
|
||||
self.env["pms.room.type.availability.rule"].create(
|
||||
{
|
||||
"min_stay": 3,
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"availability_plan_id": self.test_availability_plan.id,
|
||||
"date": fields.date.today(),
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
|
||||
# create folio wizard with partner id => pricelist & start-end dates
|
||||
wizard_folio = self.env["pms.folio.wizard"].create(
|
||||
{
|
||||
"start_date": checkin,
|
||||
"end_date": checkout,
|
||||
"partner_id": self.partner_id.id,
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
wizard_folio.flush()
|
||||
|
||||
room_type_plan_avail = wizard_folio.availability_results.filtered(
|
||||
lambda r: r.room_type_id.id == self.test_room_type_double.id
|
||||
).num_rooms_available
|
||||
|
||||
# ASSERT
|
||||
|
||||
self.assertEqual(room_type_plan_avail, 0, "Quota not applied in Wizard Folio")
|
||||
|
||||
@@ -78,6 +78,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"start_date": fields.date.today(),
|
||||
"end_date": fields.date.today() + datetime.timedelta(days=days),
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"pms_property_ids": [self.test_property.id],
|
||||
}
|
||||
).apply_massive_changes()
|
||||
|
||||
@@ -98,7 +99,13 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
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_room_types = self.env["pms.room.type"].search_count(
|
||||
[
|
||||
"|",
|
||||
("pms_property_ids", "=", False),
|
||||
("pms_property_ids", "in", self.test_property.id),
|
||||
]
|
||||
)
|
||||
num_exp_rules_to_create = ((date_to - date_from).days + 1) * num_room_types
|
||||
|
||||
# ACT
|
||||
@@ -108,6 +115,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"availability_plan_id": self.test_availability_plan.id,
|
||||
"start_date": date_from,
|
||||
"end_date": date_to,
|
||||
"pms_property_ids": [self.test_property.id],
|
||||
}
|
||||
).apply_massive_changes()
|
||||
|
||||
@@ -144,6 +152,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"closed": True,
|
||||
"closed_arrival": True,
|
||||
"closed_departure": True,
|
||||
"pms_property_ids": [self.test_property.id],
|
||||
}
|
||||
|
||||
# ACT
|
||||
@@ -155,6 +164,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
del vals["start_date"]
|
||||
del vals["end_date"]
|
||||
del vals["room_type_id"]
|
||||
del vals["pms_property_ids"]
|
||||
for key in vals:
|
||||
with self.subTest(k=key):
|
||||
self.assertEqual(
|
||||
@@ -190,6 +200,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"start_date": date_from,
|
||||
"end_date": date_to,
|
||||
"pms_property_ids": [self.test_property.id],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -243,6 +254,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"start_date": fields.date.today(),
|
||||
"end_date": fields.date.today() + datetime.timedelta(days=days),
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"pms_property_ids": [self.test_property.id],
|
||||
}
|
||||
).apply_massive_changes()
|
||||
# ASSERT
|
||||
@@ -266,7 +278,13 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
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_room_types = self.env["pms.room.type"].search_count(
|
||||
[
|
||||
"|",
|
||||
("pms_property_ids", "=", False),
|
||||
("pms_property_ids", "in", self.test_property.id),
|
||||
]
|
||||
)
|
||||
num_exp_items_to_create = ((date_to - date_from).days + 1) * num_room_types
|
||||
|
||||
# ACT
|
||||
@@ -276,6 +294,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"pricelist_id": self.test_pricelist.id,
|
||||
"start_date": date_from,
|
||||
"end_date": date_to,
|
||||
"pms_property_ids": [self.test_property.id],
|
||||
}
|
||||
).apply_massive_changes()
|
||||
|
||||
@@ -305,8 +324,8 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"date_start": date_from,
|
||||
"date_end": date_to,
|
||||
"compute_price": "fixed",
|
||||
"applied_on": "1_product",
|
||||
"product_tmpl_id": self.test_room_type_double.product_id.product_tmpl_id,
|
||||
"applied_on": "0_product_variant",
|
||||
"product_id": self.test_room_type_double.product_id,
|
||||
"fixed_price": price,
|
||||
"min_quantity": min_quantity,
|
||||
}
|
||||
@@ -321,6 +340,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"room_type_id": 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
|
||||
@@ -362,6 +382,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"start_date": date_from,
|
||||
"end_date": date_to,
|
||||
"pms_property_ids": [self.test_property.id],
|
||||
}
|
||||
)
|
||||
for index, test_case in enumerate(test_case_week_days):
|
||||
|
||||
@@ -178,6 +178,7 @@
|
||||
placeholder="Room Type"
|
||||
on_change="1"
|
||||
nolabel="1"
|
||||
context="{'checkin': checkin, 'checkout': checkout, 'pms_property_id':pms_property_id, 'pricelist_id':pricelist_id}"
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
attrs="{'readonly':[('state','not in',('draft'))]}"
|
||||
style="margin-right: 30px;"
|
||||
|
||||
@@ -85,61 +85,35 @@ class FolioWizard(models.TransientModel):
|
||||
|
||||
cmds = [(5, 0, 0)]
|
||||
|
||||
for room_type_iterator in self.env["pms.room.type"].search([]):
|
||||
|
||||
num_rooms_available_by_date = []
|
||||
room_type_total_price_per_room = 0
|
||||
|
||||
for date_iterator in [
|
||||
record.start_date + datetime.timedelta(days=x)
|
||||
for x in range(0, (record.end_date - record.start_date).days)
|
||||
]:
|
||||
rooms_available = self.env[
|
||||
"pms.room.type.availability.plan"
|
||||
].rooms_available(
|
||||
date_iterator,
|
||||
date_iterator + datetime.timedelta(days=1),
|
||||
room_type_id=room_type_iterator.id,
|
||||
pricelist=record.pricelist_id.id,
|
||||
)
|
||||
|
||||
num_rooms_available_by_date.append(len(rooms_available))
|
||||
product = room_type_iterator
|
||||
product = product.with_context(
|
||||
lang=record.partner_id.lang,
|
||||
partner=record.partner_id.id,
|
||||
quantity=1,
|
||||
date=fields.Date.today(),
|
||||
date_overnight=date_iterator,
|
||||
pricelist=record.pricelist_id.id,
|
||||
uom=product.uom_id.id,
|
||||
property=record.pms_property_id.id,
|
||||
)
|
||||
room_type_total_price_per_room += product.price
|
||||
|
||||
# check there are rooms of the type
|
||||
if room_type_iterator.total_rooms_count > 0:
|
||||
|
||||
# get min availability between start date & end date
|
||||
num_rooms_available = min(num_rooms_available_by_date)
|
||||
|
||||
cmds.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"folio_wizard_id": record.id,
|
||||
"checkin": record.start_date,
|
||||
"checkout": record.end_date,
|
||||
"room_type_id": room_type_iterator.id,
|
||||
"num_rooms_available": num_rooms_available,
|
||||
"price_per_room": room_type_total_price_per_room
|
||||
if num_rooms_available
|
||||
> 0 # not showing price if there's no availability
|
||||
else 0,
|
||||
},
|
||||
)
|
||||
for room_type_iterator in self.env["pms.room.type"].search(
|
||||
[
|
||||
"|",
|
||||
("pms_property_ids", "=", False),
|
||||
("pms_property_ids", "in", record.pms_property_id.id),
|
||||
]
|
||||
):
|
||||
num_rooms_available = self.env[
|
||||
"pms.room.type.availability.plan"
|
||||
].get_count_rooms_available(
|
||||
checkin=record.start_date,
|
||||
checkout=record.end_date,
|
||||
room_type_id=room_type_iterator.id,
|
||||
pricelist_id=record.pricelist_id.id,
|
||||
pms_property_id=record.pms_property_id.id,
|
||||
)
|
||||
cmds.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"folio_wizard_id": record.id,
|
||||
"checkin": record.start_date,
|
||||
"checkout": record.end_date,
|
||||
"room_type_id": room_type_iterator.id,
|
||||
"num_rooms_available": num_rooms_available,
|
||||
},
|
||||
)
|
||||
)
|
||||
# remove old items
|
||||
old_lines = record.availability_results.mapped("id")
|
||||
for old_line in old_lines:
|
||||
@@ -158,6 +132,7 @@ class FolioWizard(models.TransientModel):
|
||||
{
|
||||
"pricelist_id": record.pricelist_id.id,
|
||||
"partner_id": record.partner_id.id,
|
||||
"pms_property_id": record.pms_property_id.id,
|
||||
}
|
||||
)
|
||||
for line in record.availability_results:
|
||||
@@ -170,6 +145,7 @@ class FolioWizard(models.TransientModel):
|
||||
"room_type_id": line.room_type_id.id,
|
||||
"partner_id": folio.partner_id.id,
|
||||
"pricelist_id": folio.pricelist_id.id,
|
||||
"pms_property_id": record.pms_property_id.id,
|
||||
}
|
||||
)
|
||||
res.reservation_line_ids.discount = record.discount * 100
|
||||
|
||||
@@ -23,11 +23,13 @@
|
||||
<div class="col-5">
|
||||
<group>
|
||||
<field name="partner_id" string="Partner" required="1" />
|
||||
<field
|
||||
<field name="pms_property_id" required="1" />
|
||||
<field
|
||||
default_focus="1"
|
||||
name="pricelist_id"
|
||||
string="Pricelist"
|
||||
required="1"
|
||||
domain="['|', ('pms_property_ids', '=', False), ('pms_property_ids', 'in', pms_property_id)]"
|
||||
/>
|
||||
</group>
|
||||
</div>
|
||||
|
||||
@@ -33,7 +33,8 @@ class AvailabilityWizard(models.TransientModel):
|
||||
|
||||
num_rooms_available = fields.Integer(
|
||||
string="Available rooms",
|
||||
default=0,
|
||||
compute="_compute_num_rooms_available",
|
||||
store="true",
|
||||
)
|
||||
price_per_room = fields.Float(
|
||||
string="Price per room",
|
||||
@@ -53,6 +54,10 @@ class AvailabilityWizard(models.TransientModel):
|
||||
price_total = fields.Float(
|
||||
string="Total price", default=0, compute="_compute_price_total"
|
||||
)
|
||||
pms_property_id = fields.Many2one(
|
||||
related="folio_wizard_id.pms_property_id",
|
||||
string="Property",
|
||||
)
|
||||
|
||||
@api.depends("num_rooms_selected", "checkin", "checkout")
|
||||
def _compute_price_total(self):
|
||||
@@ -62,22 +67,13 @@ class AvailabilityWizard(models.TransientModel):
|
||||
# this field refresh is just to update it and take into account @ xml
|
||||
record.value_num_rooms_selected = record.num_rooms_selected.value
|
||||
|
||||
num_rooms_available_by_date = []
|
||||
room_type_total_price_per_room = 0
|
||||
|
||||
for date_iterator in [
|
||||
record.checkin + datetime.timedelta(days=x)
|
||||
for x in range(0, (record.checkout - record.checkin).days)
|
||||
]:
|
||||
rooms_available = self.env[
|
||||
"pms.room.type.availability.plan"
|
||||
].rooms_available(
|
||||
date_iterator,
|
||||
date_iterator + datetime.timedelta(days=1),
|
||||
room_type_id=record.room_type_id.id,
|
||||
pricelist=record.folio_wizard_id.pricelist_id.id,
|
||||
)
|
||||
num_rooms_available_by_date.append(len(rooms_available))
|
||||
|
||||
partner = record.folio_wizard_id.partner_id
|
||||
product = record.room_type_id.product_id
|
||||
product = product.with_context(
|
||||
@@ -92,10 +88,6 @@ class AvailabilityWizard(models.TransientModel):
|
||||
)
|
||||
room_type_total_price_per_room += product.price
|
||||
|
||||
# get the availability for the entire stay (min of all dates)
|
||||
if num_rooms_available_by_date:
|
||||
record.num_rooms_available = min(num_rooms_available_by_date)
|
||||
|
||||
# udpate the price per room
|
||||
record.price_per_room = room_type_total_price_per_room
|
||||
|
||||
@@ -117,6 +109,19 @@ class AvailabilityWizard(models.TransientModel):
|
||||
|
||||
record.price_total = record.price_per_room * record.num_rooms_selected.value
|
||||
|
||||
@api.depends("room_type_id", "checkin", "checkout")
|
||||
def _compute_num_rooms_available(self):
|
||||
for record in self:
|
||||
record.num_rooms_available = self.env[
|
||||
"pms.room.type.availability.plan"
|
||||
].get_count_rooms_available(
|
||||
record.checkin,
|
||||
record.checkout,
|
||||
room_type_id=record.room_type_id.id,
|
||||
pricelist_id=record.folio_wizard_id.pricelist_id.id,
|
||||
pms_property_id=record.folio_wizard_id.pms_property_id.id,
|
||||
)
|
||||
|
||||
def _compute_dynamic_selection(self):
|
||||
for record in self:
|
||||
for elem_to_insert in range(0, record.num_rooms_available + 1):
|
||||
|
||||
@@ -15,6 +15,13 @@ class AvailabilityWizard(models.TransientModel):
|
||||
return True if self._context.get("pricelist_id") else False
|
||||
|
||||
# Fields declaration
|
||||
pms_property_ids = fields.Many2many(
|
||||
comodel_name="pms.property",
|
||||
string="Property",
|
||||
default=lambda self: self.env["pms.property"].browse(
|
||||
self.env.user.get_active_property_ids()[0]
|
||||
),
|
||||
)
|
||||
massive_changes_on = fields.Selection(
|
||||
[("pricelist", "Pricelist"), ("availability_plan", "Availability Plan")],
|
||||
string="Massive changes on",
|
||||
@@ -236,6 +243,9 @@ class AvailabilityWizard(models.TransientModel):
|
||||
if record.pricelist_id:
|
||||
domain = [
|
||||
("pricelist_id", "=", record.pricelist_id.id),
|
||||
"|",
|
||||
("pms_property_ids", "=", False),
|
||||
("pms_property_ids", "in", record.pms_property_ids.ids),
|
||||
]
|
||||
|
||||
if record.start_date:
|
||||
@@ -327,41 +337,50 @@ class AvailabilityWizard(models.TransientModel):
|
||||
continue
|
||||
|
||||
if not record.room_type_id:
|
||||
rooms = self.env["pms.room.type"].search([])
|
||||
room_types = self.env["pms.room.type"].search(
|
||||
[
|
||||
"|",
|
||||
("pms_property_ids", "=", False),
|
||||
("pms_property_ids", "in", record.pms_property_ids.ids),
|
||||
]
|
||||
)
|
||||
else:
|
||||
rooms = [record.room_type_id]
|
||||
for room in rooms:
|
||||
if record.massive_changes_on == "pricelist":
|
||||
|
||||
self.env["product.pricelist.item"].create(
|
||||
{
|
||||
"pricelist_id": record.pricelist_id.id,
|
||||
"date_start_overnight": date,
|
||||
"date_end_overnight": date,
|
||||
"compute_price": "fixed",
|
||||
"applied_on": "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,
|
||||
}
|
||||
)
|
||||
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":
|
||||
self.env["product.pricelist.item"].create(
|
||||
{
|
||||
"pricelist_id": record.pricelist_id.id,
|
||||
"date_start_overnight": date,
|
||||
"date_end_overnight": date,
|
||||
"compute_price": "fixed",
|
||||
"applied_on": "0_product_variant",
|
||||
"product_id": room_type.product_id.id,
|
||||
"fixed_price": record.price,
|
||||
"min_quantity": record.min_quantity,
|
||||
"pms_property_ids": [pms_property.id],
|
||||
}
|
||||
)
|
||||
else:
|
||||
avail_plan_id = record.availability_plan_id.id
|
||||
self.env["pms.room.type.availability.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,
|
||||
}
|
||||
)
|
||||
if (
|
||||
record.massive_changes_on == "pricelist"
|
||||
and not record.pricelist_readonly
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<group class="">
|
||||
<field name="pms_property_ids" widget="many2many_tags" />
|
||||
<field
|
||||
name="massive_changes_on"
|
||||
attrs="{'invisible':['|', ('avail_readonly','=',True), ('pricelist_readonly', '=', True)]}"
|
||||
@@ -37,6 +38,7 @@
|
||||
attrs="{'invisible':['|','|',('massive_changes_on','=','pricelist'), ('avail_readonly','=',True),
|
||||
('pricelist_readonly', '=', True)],
|
||||
'required': [('massive_changes_on','=','availability_plan')]}"
|
||||
domain="['|', ('pms_property_ids', '=', False), ('pms_property_ids', 'in', pms_property_ids)]"
|
||||
/>
|
||||
|
||||
<field
|
||||
@@ -45,9 +47,13 @@
|
||||
attrs="{'invisible':['|','|',('massive_changes_on','=','availability_plan'),
|
||||
('pricelist_readonly','=',True), ('pricelist_readonly', '=', True)],
|
||||
'required': [('massive_changes_on','=','pricelist')]}"
|
||||
domain="[('id', 'in', allowed_pricelist_ids)]"
|
||||
domain="[('id', 'in', allowed_pricelist_ids), '|', ('pms_property_ids', '=', False), ('pms_property_ids', 'in', pms_property_ids)]"
|
||||
/>
|
||||
<field
|
||||
name="room_type_id"
|
||||
default_focus="1"
|
||||
domain="['|', ('pms_property_ids', '=', False), ('pms_property_ids', 'in', pms_property_ids)]"
|
||||
/>
|
||||
<field name="room_type_id" default_focus="1" />
|
||||
</group>
|
||||
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user