mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[RFC] Availability and free rooms
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import datetime
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class PmsAvailabilityPlan(models.Model):
|
||||
@@ -72,204 +69,6 @@ class PmsAvailabilityPlan(models.Model):
|
||||
]
|
||||
)
|
||||
|
||||
@api.model
|
||||
def rooms_available(
|
||||
self,
|
||||
checkin,
|
||||
checkout,
|
||||
room_type_id=False,
|
||||
current_lines=False,
|
||||
pricelist_id=False,
|
||||
pms_property_id=False,
|
||||
):
|
||||
if current_lines and not isinstance(current_lines, list):
|
||||
current_lines = [current_lines]
|
||||
free_rooms = self.get_real_free_rooms(
|
||||
checkin, checkout, room_type_id, current_lines, pms_property_id
|
||||
)
|
||||
domain_rules = [
|
||||
("date", ">=", checkin),
|
||||
(
|
||||
"date",
|
||||
"<=",
|
||||
checkout,
|
||||
), # TODO: only closed_departure take account checkout date!
|
||||
]
|
||||
if pms_property_id:
|
||||
domain_rules.append(("pms_property_id", "=", pms_property_id))
|
||||
|
||||
if 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.availability.plan.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
|
||||
)
|
||||
elif not pricelist:
|
||||
raise ValidationError(_("Pricelist not found"))
|
||||
return free_rooms.sorted(key=lambda r: r.sequence)
|
||||
|
||||
def get_real_free_rooms(
|
||||
self,
|
||||
checkin,
|
||||
checkout,
|
||||
room_type_id=False,
|
||||
current_lines=False,
|
||||
pms_property_id=False,
|
||||
):
|
||||
Avail = self.env["pms.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)),
|
||||
]
|
||||
if not current_lines:
|
||||
current_lines = []
|
||||
rooms_not_avail = (
|
||||
Avail.search(domain)
|
||||
.reservation_line_ids.filtered(
|
||||
lambda l: l.occupies_availability and l.id and l.id not in current_lines
|
||||
)
|
||||
.room_id.ids
|
||||
)
|
||||
domain_rooms = []
|
||||
if rooms_not_avail:
|
||||
domain_rooms = [
|
||||
("id", "not in", rooms_not_avail),
|
||||
]
|
||||
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),
|
||||
]
|
||||
pricelist = False
|
||||
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.availability.plan.rule"].search(domain_rules)
|
||||
if len(rule_items) > 0:
|
||||
for item in rule_items:
|
||||
if self.any_rule_applies(checkin, checkout, item):
|
||||
return 0
|
||||
avail = min(rule_items.mapped("plan_avail"))
|
||||
return avail
|
||||
|
||||
def get_count_real_free_rooms(
|
||||
self,
|
||||
checkin,
|
||||
checkout,
|
||||
room_type_id,
|
||||
pms_property_id,
|
||||
current_lines=False,
|
||||
):
|
||||
Avail = self.env["pms.availability"]
|
||||
count_free_rooms = len(
|
||||
self.env["pms.room.type"]
|
||||
.browse(room_type_id)
|
||||
.room_ids.filtered(lambda r: r.pms_property_id.id == pms_property_id)
|
||||
)
|
||||
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(
|
||||
self,
|
||||
checkin,
|
||||
checkout,
|
||||
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)
|
||||
]:
|
||||
rooms_avail = self.rooms_available(
|
||||
checkin=date_iterator,
|
||||
checkout=date_iterator + datetime.timedelta(1),
|
||||
room_type_id=room_type_id,
|
||||
current_lines=current_lines,
|
||||
pricelist_id=pricelist.id,
|
||||
pms_property_id=pms_property_id,
|
||||
)
|
||||
if len(rooms_avail) < 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def update_quota(self, pricelist_id, room_type_id, date, line):
|
||||
if pricelist_id and room_type_id and date:
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
# Copyright 2019 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import datetime
|
||||
import time
|
||||
|
||||
import pytz
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
|
||||
from odoo.addons.base.models.res_partner import _tz_get
|
||||
|
||||
@@ -97,6 +99,243 @@ class PmsProperty(models.Model):
|
||||
"charge a day's stay according to current rate that day",
|
||||
help="Notice under the signature on the traveler's ticket.",
|
||||
)
|
||||
free_room_ids = fields.One2many(
|
||||
string="Rooms available",
|
||||
help="allows you to send different parameters in the context "
|
||||
"(checkin(required), checkout(required), room_type_id, location_id, capacity, "
|
||||
"amenity_ids and / or pricelist_id) and return rooms available",
|
||||
comodel_name="pms.room",
|
||||
compute="_compute_free_room_ids",
|
||||
)
|
||||
availability = fields.Integer(
|
||||
string="Number of rooms available",
|
||||
help="allows you to send different parameters in the context "
|
||||
"(checkin(required), checkout(required), room_type_id, location_id, capacity,"
|
||||
"amenity_ids and / or pricelist_id) check the availability for the hotel",
|
||||
compute="_compute_availability",
|
||||
)
|
||||
|
||||
@api.depends_context(
|
||||
"checkin",
|
||||
"checkout",
|
||||
"room_type_id",
|
||||
"location_id",
|
||||
"capacity",
|
||||
"amenity_ids",
|
||||
"pricelist_id",
|
||||
"current_lines",
|
||||
)
|
||||
def _compute_free_room_ids(self):
|
||||
self.free_room_ids = False
|
||||
checkin = self._context["checkin"]
|
||||
checkout = self._context["checkout"]
|
||||
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()
|
||||
current_lines = self.env.context.get("current_lines", False)
|
||||
if current_lines and not isinstance(current_lines, list):
|
||||
current_lines = [current_lines]
|
||||
|
||||
pricelist_id = self.env.context.get("pricelist_id", False)
|
||||
room_type_id = self.env.context.get("room_type_id", False)
|
||||
|
||||
for pms_property in self:
|
||||
free_rooms = pms_property.get_real_free_rooms(
|
||||
checkin, checkout, current_lines
|
||||
)
|
||||
if pricelist_id:
|
||||
# TODO: only closed_departure take account checkout date!
|
||||
domain_rules = [
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout),
|
||||
("pms_property_id", "=", pms_property.id),
|
||||
]
|
||||
if room_type_id:
|
||||
domain_rules.append(("room_type_id", "=", room_type_id))
|
||||
|
||||
pricelist = self.env["product.pricelist"].browse(pricelist_id)
|
||||
if pricelist.availability_plan_id:
|
||||
domain_rules.append(
|
||||
("availability_plan_id", "=", pricelist.availability_plan_id.id)
|
||||
)
|
||||
rule_items = self.env["pms.availability.plan.rule"].search(
|
||||
domain_rules
|
||||
)
|
||||
|
||||
if len(rule_items) > 0:
|
||||
room_types_to_remove = []
|
||||
for item in rule_items:
|
||||
if pricelist.availability_plan_id.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
|
||||
)
|
||||
if len(free_rooms) > 0:
|
||||
pms_property.free_room_ids = free_rooms.ids
|
||||
else:
|
||||
pms_property.free_room_ids = False
|
||||
|
||||
def get_real_free_rooms(self, checkin, checkout, current_lines=False):
|
||||
self.ensure_one()
|
||||
Avail = self.env["pms.availability"]
|
||||
tarjet_rooms = self.env["pms.room"].search([("pms_property_id", "=", self.id)])
|
||||
|
||||
room_type_id = self.env.context.get("room_type_id", False)
|
||||
if room_type_id:
|
||||
tarjet_rooms = tarjet_rooms.filtered(
|
||||
lambda r: r.room_type_id.id == room_type_id
|
||||
)
|
||||
|
||||
capacity = self.env.context.get("capacity", False)
|
||||
if capacity:
|
||||
tarjet_rooms = tarjet_rooms.filtered(lambda r: r.capacity >= capacity)
|
||||
|
||||
location_id = self.env.context.get("location_id", False)
|
||||
if location_id:
|
||||
tarjet_rooms = tarjet_rooms.filtered(
|
||||
lambda r: r.location_id.id == location_id
|
||||
)
|
||||
|
||||
amenity_ids = self.env.context.get("amenity_ids", False)
|
||||
if amenity_ids:
|
||||
if amenity_ids and not isinstance(amenity_ids, list):
|
||||
amenity_ids = [amenity_ids]
|
||||
tarjet_rooms = tarjet_rooms.filtered(
|
||||
lambda r: len(set(amenity_ids) - set(r.room_amenity_ids.ids)) == 0
|
||||
)
|
||||
|
||||
domain_avail = [
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout - datetime.timedelta(1)),
|
||||
("pms_property_id", "=", self.id),
|
||||
]
|
||||
|
||||
if not current_lines:
|
||||
current_lines = []
|
||||
|
||||
rooms_not_avail = (
|
||||
Avail.search(domain_avail)
|
||||
.reservation_line_ids.filtered(
|
||||
lambda l: l.occupies_availability and l.id and l.id not in current_lines
|
||||
)
|
||||
.room_id.ids
|
||||
)
|
||||
|
||||
domain_rooms = [("id", "in", tarjet_rooms.ids)]
|
||||
if rooms_not_avail:
|
||||
domain_rooms.append(
|
||||
("id", "not in", rooms_not_avail),
|
||||
)
|
||||
return self.env["pms.room"].search(domain_rooms)
|
||||
|
||||
@api.depends_context(
|
||||
"checkin",
|
||||
"checkout",
|
||||
"room_type_id",
|
||||
"location_id",
|
||||
"capacity",
|
||||
"amenity_ids",
|
||||
"pricelist_id",
|
||||
"current_lines",
|
||||
)
|
||||
def _compute_availability(self):
|
||||
self.availability = 0
|
||||
for pms_property in self:
|
||||
checkin = self._context["checkin"]
|
||||
checkout = self._context["checkout"]
|
||||
room_type_id = self.env.context.get("room_type_id", False)
|
||||
pricelist_id = self.env.context.get("pricelist_id", False)
|
||||
current_lines = self.env.context.get("current_lines", False)
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
room_type_id=room_type_id,
|
||||
current_lines=current_lines,
|
||||
pricelist_id=pricelist_id,
|
||||
)
|
||||
count_free_rooms = len(pms_property.free_room_ids)
|
||||
|
||||
if current_lines and not isinstance(current_lines, list):
|
||||
current_lines = [current_lines]
|
||||
|
||||
domain_rules = [
|
||||
("date", ">=", checkin),
|
||||
("date", "<=", checkout),
|
||||
("pms_property_id", "=", pms_property.id),
|
||||
]
|
||||
|
||||
if room_type_id:
|
||||
domain_rules.append(("room_type_id", "=", room_type_id))
|
||||
|
||||
pricelist = False
|
||||
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_groups = self.env["pms.availability.plan.rule"].read_group(
|
||||
domain_rules,
|
||||
["plan_avail:sum"],
|
||||
["date:day"],
|
||||
lazy=False,
|
||||
)
|
||||
if len(rule_groups) > 0:
|
||||
# If in the group per day, some room type has the sale blocked,
|
||||
# we must subtract from that day the availability of that room type
|
||||
for group in rule_groups:
|
||||
items = self.env["pms.availability.plan.rule"].search(
|
||||
group["__domain"]
|
||||
)
|
||||
for item in items:
|
||||
if pricelist.availability_plan_id.any_rule_applies(
|
||||
checkin, checkout, item
|
||||
):
|
||||
group["plan_avail"] -= item.plan_avail
|
||||
count_free_rooms = min(i["plan_avail"] for i in rule_groups)
|
||||
pms_property.availability = count_free_rooms
|
||||
|
||||
@api.model
|
||||
def splitted_availability(
|
||||
self,
|
||||
checkin,
|
||||
checkout,
|
||||
pms_property_id,
|
||||
room_type_id=False,
|
||||
current_lines=False,
|
||||
pricelist=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)
|
||||
]:
|
||||
pms_property = self.env["pms.property"].browse(pms_property_id)
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=date_iterator,
|
||||
checkout=date_iterator + datetime.timedelta(1),
|
||||
room_type_id=room_type_id,
|
||||
current_lines=current_lines,
|
||||
pricelist_id=pricelist.id,
|
||||
)
|
||||
|
||||
if len(pms_property.free_room_ids) < 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
@api.constrains("default_arrival_hour")
|
||||
def _check_arrival_hour(self):
|
||||
|
||||
@@ -736,15 +736,16 @@ class PmsReservation(models.Model):
|
||||
[("active", "=", True)]
|
||||
)
|
||||
return
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = reservation.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=reservation.checkin,
|
||||
checkout=reservation.checkout,
|
||||
room_type_id=False, # Allows to choose any available room
|
||||
current_lines=reservation.reservation_line_ids.ids,
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
pms_property_id=reservation.pms_property_id.id,
|
||||
)
|
||||
reservation.allowed_room_ids = rooms_available
|
||||
reservation.allowed_room_ids = pms_property.free_room_ids
|
||||
|
||||
else:
|
||||
reservation.allowed_room_ids = False
|
||||
|
||||
@@ -1502,13 +1503,15 @@ class PmsReservation(models.Model):
|
||||
return self.folio_id.action_pay()
|
||||
|
||||
def open_reservation_wizard(self):
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = self.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=self.checkin,
|
||||
checkout=self.checkout,
|
||||
current_lines=self.reservation_line_ids.ids,
|
||||
pricelist_id=self.pricelist_id.id,
|
||||
pms_property_id=self.pms_property_id.id,
|
||||
)
|
||||
rooms_available = pms_property.free_room_ids
|
||||
|
||||
# REVIEW: check capacity room
|
||||
return {
|
||||
"view_type": "form",
|
||||
@@ -1544,21 +1547,6 @@ class PmsReservation(models.Model):
|
||||
result.append((res.id, name))
|
||||
return result
|
||||
|
||||
# REVIEW: Is it necessary?
|
||||
def copy_data(self, default=None):
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
self.checkin,
|
||||
self.checkout,
|
||||
room_type_id=self.room_type_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
|
||||
if self.room_type_id.id in rooms_available.mapped("room_type_id.id"):
|
||||
default["room_type_id"] = self.room_type_id.id
|
||||
return super(PmsReservation, self).copy_data(default)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get("folio_id"):
|
||||
|
||||
@@ -175,7 +175,8 @@ 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.availability.plan"].rooms_available(
|
||||
pms_property = line.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=reservation.checkin,
|
||||
checkout=reservation.checkout,
|
||||
room_type_id=reservation.room_type_id.id
|
||||
@@ -183,8 +184,9 @@ class PmsReservationLine(models.Model):
|
||||
else False,
|
||||
current_lines=reservation.reservation_line_ids.ids,
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
pms_property_id=line.pms_property_id.id,
|
||||
)
|
||||
rooms_available = pms_property.free_room_ids
|
||||
|
||||
# Check if the room assigment is manual or automatic to set the
|
||||
# to_assign value on reservation
|
||||
manual_assigned = False
|
||||
@@ -228,7 +230,7 @@ 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.availability.plan"].splitted_availability(
|
||||
elif not self.env["pms.property"].splitted_availability(
|
||||
checkin=reservation.checkin,
|
||||
checkout=reservation.checkout,
|
||||
room_type_id=reservation.room_type_id.id,
|
||||
|
||||
@@ -70,6 +70,16 @@ class PmsRoom(models.Model):
|
||||
required=True,
|
||||
default="0",
|
||||
)
|
||||
room_amenity_ids = fields.Many2many(
|
||||
string="Room Amenities",
|
||||
help="List of amenities included in room",
|
||||
comodel_name="pms.amenity",
|
||||
relation="pms_room_amenity_rel",
|
||||
column1="room_id",
|
||||
column2="amenity_id",
|
||||
check_pms_properties=True,
|
||||
)
|
||||
|
||||
description_sale = fields.Text(
|
||||
string="Sale Description",
|
||||
help="A description of the Product that you want to communicate to "
|
||||
|
||||
@@ -98,13 +98,16 @@ class PmsRoomType(models.Model):
|
||||
for room_type in self:
|
||||
name = room_type.name
|
||||
if self._context.get("checkin") and self._context.get("checkout"):
|
||||
avail = self.env["pms.availability.plan"].get_count_rooms_available(
|
||||
pms_property = self.env["pms.property"].browse(
|
||||
self._context.get("pms_property_id")
|
||||
)
|
||||
pms_property = pms_property.with_context(
|
||||
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,
|
||||
)
|
||||
avail = pms_property.availability
|
||||
name += " (%s)" % avail
|
||||
result.append((room_type.id, name))
|
||||
return result
|
||||
|
||||
@@ -130,7 +130,7 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
---------------------
|
||||
The checkin and checkout dates on which the availability will be checked are saved
|
||||
in a variable and in another all the rooms of the property are also saved. Then the
|
||||
rooms_available() method is launched which should return the number of available rooms
|
||||
free_room_ids compute field is called which should return the number of available rooms
|
||||
of the property and they are saved in another variable with which it is verified that
|
||||
all the rooms have been returned because there are no availability rules for that plan.
|
||||
"""
|
||||
@@ -142,10 +142,12 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
[("pms_property_id", "=", self.pms_property3.id)]
|
||||
)
|
||||
# ACT
|
||||
result = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = self.pms_property3.with_context(
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
)
|
||||
result = pms_property.free_room_ids
|
||||
|
||||
# ASSERT
|
||||
obtained = all(elem.id in result.ids for elem in test_rooms_double_rooms)
|
||||
self.assertTrue(
|
||||
@@ -162,7 +164,7 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
-----------------
|
||||
The checkin and checkout dates on which the availability will be checked are saved
|
||||
in a variable and in another all the rooms of the property are also saved. Then create
|
||||
a reservation for this property and the rooms_available() method is launched with the
|
||||
a reservation for this property and the free_room_ids compute field is called with the
|
||||
parameters checkin, checkout and the reservation lines of the reservation as a curent
|
||||
lines, this method should return the number of available rooms of the property. Then the
|
||||
result is saved in another variable with which it is verified that all the rooms have
|
||||
@@ -185,11 +187,13 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
)
|
||||
|
||||
# ACT
|
||||
result = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = self.pms_property3.with_context(
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
current_lines=test_reservation.reservation_line_ids.ids,
|
||||
)
|
||||
result = pms_property.free_room_ids
|
||||
|
||||
# ASSERT
|
||||
obtained = all(elem.id in result.ids for elem in test_rooms_double_rooms)
|
||||
self.assertTrue(
|
||||
@@ -202,8 +206,8 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
"""
|
||||
Check the availability of a room type for a property.
|
||||
----------------
|
||||
Double rooms of a property are saved in a variable. The rooms_available() method
|
||||
is launched giving as parameters checkin, checkout and the type of room (in this
|
||||
Double rooms of a property are saved in a variable. The free_room_ids compute field
|
||||
is called giving as parameters checkin, checkout and the type of room (in this
|
||||
case double). Then with the all () function we check that all rooms of this type
|
||||
were returned.
|
||||
"""
|
||||
@@ -216,11 +220,12 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
]
|
||||
)
|
||||
# ACT
|
||||
result = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = self.pms_property3.with_context(
|
||||
checkin=fields.date.today(),
|
||||
checkout=(fields.datetime.today() + datetime.timedelta(days=4)).date(),
|
||||
room_type_id=self.test_room_type_double.id,
|
||||
)
|
||||
result = pms_property.free_room_ids
|
||||
|
||||
# ASSERT
|
||||
obtained = all(elem.id in result.ids for elem in test_rooms_double_rooms)
|
||||
@@ -237,7 +242,7 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
--------------------
|
||||
Create an availability rule for double rooms with the field closed = true
|
||||
and the date from today until tomorrow. Then the availability is saved in a
|
||||
variable through the rooms_available() method, passing it the pricelist that
|
||||
variable through the free_room_ids computed field, passing it the pricelist that
|
||||
it contains the availability plan where the rule is included, and the checkin
|
||||
and checkout dates are between the date of the rule. Then it is verified that
|
||||
the double rooms are not available.
|
||||
@@ -255,12 +260,14 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
}
|
||||
)
|
||||
# ACT
|
||||
result = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = self.pms_property3.with_context(
|
||||
checkin=fields.date.today(),
|
||||
checkout=(fields.datetime.today() + datetime.timedelta(days=4)).date(),
|
||||
# room_type_id=False, # <- (2/2)
|
||||
pricelist_id=self.pricelist2.id,
|
||||
)
|
||||
result = pms_property.free_room_ids
|
||||
|
||||
# ASSERT
|
||||
self.assertNotIn(
|
||||
self.test_room_type_double,
|
||||
@@ -283,7 +290,7 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
6. max_stay_arrival = 3
|
||||
7. quota = 0
|
||||
8. max_avail = 0
|
||||
For each test case, it is verified through the rooms_available() method,
|
||||
For each test case, it is verified through the free_room_ids compute field,
|
||||
that double rooms are not available since the rules are applied to this
|
||||
room type.
|
||||
"""
|
||||
@@ -409,12 +416,13 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
# ACT
|
||||
self.test_room_type_availability_rule1.write(test_case)
|
||||
|
||||
result = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = self.pms_property3.with_context(
|
||||
checkin=checkin,
|
||||
checkout=checkout,
|
||||
room_type_id=self.test_room_type_double.id,
|
||||
pricelist_id=self.pricelist2.id,
|
||||
)
|
||||
result = pms_property.free_room_ids
|
||||
|
||||
# ASSERT
|
||||
self.assertNotIn(
|
||||
@@ -639,15 +647,17 @@ class TestPmsRoomTypeAvailabilityRules(TestPms):
|
||||
for p in properties:
|
||||
with self.subTest(k=p):
|
||||
# ACT
|
||||
rooms_avail = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = self.env["pms.property"].browse(p["property"])
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=fields.date.today(),
|
||||
checkout=(
|
||||
fields.datetime.today() + datetime.timedelta(days=2)
|
||||
).date(),
|
||||
room_type_id=self.test_room_type_special.id,
|
||||
pricelist_id=self.pricelist2.id,
|
||||
pms_property_id=p["property"],
|
||||
)
|
||||
rooms_avail = pms_property.free_room_ids
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
len(rooms_avail) > 0, p["value"], "Availability is not correct"
|
||||
|
||||
@@ -703,7 +703,6 @@ class TestPmsWizardMassiveChanges(common.SavepointCase):
|
||||
"pms_property_id": self.test_property.id,
|
||||
}
|
||||
)
|
||||
|
||||
# create folio wizard with partner id => pricelist & start-end dates
|
||||
booking_engine = self.env["pms.booking.engine"].create(
|
||||
{
|
||||
@@ -715,7 +714,6 @@ class TestPmsWizardMassiveChanges(common.SavepointCase):
|
||||
}
|
||||
)
|
||||
booking_engine.flush()
|
||||
|
||||
room_type_plan_avail = booking_engine.availability_results.filtered(
|
||||
lambda r: r.room_type_id.id == self.test_room_type_double.id
|
||||
).num_rooms_available
|
||||
|
||||
@@ -177,15 +177,15 @@ class BookingEngine(models.TransientModel):
|
||||
("pms_property_ids", "in", record.pms_property_id.id),
|
||||
]
|
||||
):
|
||||
num_rooms_available = self.env[
|
||||
"pms.availability.plan"
|
||||
].get_count_rooms_available(
|
||||
pms_property = record.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
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,
|
||||
)
|
||||
num_rooms_available = pms_property.availability
|
||||
|
||||
cmds.append(
|
||||
(
|
||||
0,
|
||||
@@ -338,15 +338,14 @@ class AvailabilityWizard(models.TransientModel):
|
||||
@api.depends("room_type_id", "checkin", "checkout")
|
||||
def _compute_num_rooms_available(self):
|
||||
for record in self:
|
||||
record.num_rooms_available = self.env[
|
||||
"pms.availability.plan"
|
||||
].get_count_rooms_available(
|
||||
record.checkin,
|
||||
record.checkout,
|
||||
pms_property = record.booking_engine_id.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=record.checkin,
|
||||
checkout=record.checkout,
|
||||
room_type_id=record.room_type_id.id,
|
||||
pricelist_id=record.booking_engine_id.pricelist_id.id,
|
||||
pms_property_id=record.booking_engine_id.pms_property_id.id,
|
||||
)
|
||||
record.num_rooms_available = pms_property.availability
|
||||
|
||||
@api.depends("num_rooms_available")
|
||||
def _compute_num_rooms_selected(self):
|
||||
|
||||
@@ -172,14 +172,16 @@ class ReservationSplitJoinSwapWizard(models.TransientModel):
|
||||
record.allowed_rooms_target = False
|
||||
record.room_target = False
|
||||
if record.checkin and record.checkout:
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = record.reservation_id.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=record.checkin,
|
||||
checkout=record.checkout,
|
||||
room_type_id=False, # Allows to choose any available room
|
||||
current_lines=record.reservation_id.reservation_line_ids.ids,
|
||||
pricelist_id=record.reservation_id.pricelist_id.id,
|
||||
pms_property_id=record.reservation_id.pms_property_id.id,
|
||||
)
|
||||
rooms_available = pms_property.free_room_ids
|
||||
|
||||
domain = [("capacity", ">=", record.reservation_id.adults)]
|
||||
if record.room_source:
|
||||
domain.append(("id", "!=", record.room_source.id))
|
||||
@@ -214,7 +216,7 @@ class ReservationSplitJoinSwapWizard(models.TransientModel):
|
||||
|
||||
if not self.browse(room.id):
|
||||
raise UserError(_("The room does not exist"))
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = reservation.pms_property_id.with_context(
|
||||
checkin=date,
|
||||
checkout=(
|
||||
datetime.datetime(year=date.year, month=date.month, day=date.day)
|
||||
@@ -222,8 +224,9 @@ class ReservationSplitJoinSwapWizard(models.TransientModel):
|
||||
).date(),
|
||||
current_lines=reservation.reservation_line_ids.ids,
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
pms_property_id=reservation.pms_property_id.id,
|
||||
)
|
||||
rooms_available = pms_property.free_room_ids
|
||||
|
||||
if room not in rooms_available:
|
||||
raise UserError(_("The room is not available"))
|
||||
|
||||
@@ -233,13 +236,15 @@ class ReservationSplitJoinSwapWizard(models.TransientModel):
|
||||
|
||||
@api.model
|
||||
def reservation_join(self, reservation, room):
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = reservation.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=reservation.checkin,
|
||||
checkout=reservation.checkout,
|
||||
current_lines=reservation.reservation_line_ids.ids,
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
pms_property_id=reservation.pms_property_id.id,
|
||||
)
|
||||
rooms_available = pms_property.free_room_ids
|
||||
|
||||
if room in rooms_available:
|
||||
for line in (
|
||||
self.env["pms.reservation"]
|
||||
@@ -347,13 +352,14 @@ class ReservationLinesToSplit(models.TransientModel):
|
||||
[("active", "=", True)]
|
||||
)
|
||||
return
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
pms_property = reservation.pms_property_id
|
||||
pms_property = pms_property.with_context(
|
||||
checkin=line.date,
|
||||
checkout=line.date + datetime.timedelta(days=1),
|
||||
room_type_id=False, # Allows to choose any available room
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
pms_property_id=reservation.pms_property_id.id,
|
||||
)
|
||||
rooms_available = pms_property.free_room_ids
|
||||
rooms_available += line.room_id
|
||||
line.allowed_room_ids = rooms_available
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user