Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions pms/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ You will find the hotel settings in PMS Management > Configuration > Properties

This module required additional configuration for company, accounting, invoicing and user privileges.

Children and room capacity
~~~~~~~~~~~~~~~~~~~~~~~~~~

By default children take no place in the room, so only the adults are checked
against its capacity. Properties that want to count them can set the system
parameter ``pms.children_occupy_capacity`` to ``True``, in Settings > Technical
> System Parameters.

Once it is on, children take the regular places of the room first and only
overflow into its children places, the ones where only a child can sleep, such
as child bunk beds. Adults never occupy those, so a room with free children
places can still be full.

Mind that turning it on refuses reservations that the property may have been
taking until then.

Usage
=====

Expand Down
2 changes: 1 addition & 1 deletion pms/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{
"name": "PMS (Property Management System)",
"summary": "A property management system",
"version": "16.0.4.24.0",
"version": "16.0.4.25.0",
"development_status": "Beta",
"category": "Generic Modules/Property Management System",
"website": "https://github.com/OCA/pms",
Expand Down
5 changes: 5 additions & 0 deletions pms/demo/pms_master_data_no_update.xml
Original file line number Diff line number Diff line change
Expand Up @@ -326,34 +326,39 @@
<field name="room_type_id" ref="pms_room_type_single" />
<field name="ubication_id" ref="pms_ubication_1st_floor" />
<field name="capacity">1</field>
<field name="children_capacity">1</field>
<field name="pms_property_id" ref="pms.main_pms_property" />
</record>
<record id="pms_room_single_02" model="pms.room">
<field name="name">Single-107</field>
<field name="room_type_id" ref="pms_room_type_single" />
<field name="ubication_id" ref="pms_ubication_1st_floor" />
<field name="capacity">1</field>
<field name="children_capacity">1</field>
<field name="pms_property_id" ref="pms.main_pms_property" />
</record>
<record id="pms_room_single_03" model="pms.room">
<field name="name">Single-108</field>
<field name="room_type_id" ref="pms_room_type_single" />
<field name="ubication_id" ref="pms_ubication_1st_floor" />
<field name="capacity">1</field>
<field name="children_capacity">1</field>
<field name="pms_property_id" ref="pms.main_pms_property" />
</record>
<record id="pms_room_single_04" model="pms.room">
<field name="name">Single-109</field>
<field name="room_type_id" ref="pms_room_type_single" />
<field name="ubication_id" ref="pms_ubication_1st_floor" />
<field name="capacity">1</field>
<field name="children_capacity">1</field>
<field name="pms_property_id" ref="pms.main_pms_property" />
</record>
<record id="pms_room_single_05" model="pms.room">
<field name="name">Single-110</field>
<field name="room_type_id" ref="pms_room_type_single" />
<field name="ubication_id" ref="pms_ubication_1st_floor" />
<field name="capacity">1</field>
<field name="children_capacity">1</field>
<field name="pms_property_id" ref="pms.main_pms_property" />
</record>
<!-- double rooms (My Property) -->
Expand Down
21 changes: 21 additions & 0 deletions pms/migrations/16.0.4.25.0/pre-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2026 Commit [Sun]
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openupgradelib import openupgrade

# children_occupying held the children taking a place in the room, apart from
# children, which held them all. Nothing kept both in sync, so a reservation
# could declare an occupying child without counting it in children. Those
# children are folded into children before the column goes away, or they would
# be lost.
_FOLD_CHILDREN_OCCUPYING = """
UPDATE pms_reservation
SET children = children_occupying
WHERE children_occupying > COALESCE(children, 0)
"""


@openupgrade.migrate()
def migrate(env, version):
if openupgrade.column_exists(env.cr, "pms_reservation", "children_occupying"):
openupgrade.logged_query(env.cr, _FOLD_CHILDREN_OCCUPYING)
openupgrade.drop_columns(env.cr, [("pms_reservation", "children_occupying")])
14 changes: 6 additions & 8 deletions pms/models/pms_reservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,12 +356,9 @@ class PmsReservation(models.Model):
compute="_compute_adults",
tracking=True,
)
children_occupying = fields.Integer(
help="Number of children there in guest list whose presence counts",
)
children = fields.Integer(
help="Number total of children there in guest list,"
"whose presence counts or not",
help="Number of children there in guest list. They take the regular "
"places of the room first, and only overflow into its children places",
readonly=False,
tracking=True,
)
Expand Down Expand Up @@ -2215,9 +2212,10 @@ def write(self, vals):

for record in self:
record._check_services(vals)
# Only check if adult to avoid to check capacity in intermediate states
# (p.e. flush) that not take access to possible extra beds service in vals
if "adults" in vals:
# Only check on occupancy changes to avoid checking capacity in
# intermediate states (p.e. flush) that not take access to possible
# extra beds service in vals
if "adults" in vals or "children" in vals:
record._check_capacity()
# The room of the lines is recomputed from the preferred room, so
# that write does not go through pms.reservation.line.write and the
Expand Down
26 changes: 17 additions & 9 deletions pms/models/pms_reservation_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,23 +685,31 @@ def _check_room_capacity(self):
of the room (capacity + allowed extra beds) instead of the extra beds
actually sold, to avoid false positives in intermediate states where
the extra bed service is not created yet.

Children count too: they take regular places first and only overflow
into the children places of the room.
"""
if self.env.context.get("avoid_capacity_check"):
return
for record in self:
reservation = record.reservation_id
if not record.room_id or reservation.reservation_type == "out":
room = record.room_id
if not room or reservation.reservation_type == "out":
continue
occupancy = reservation.adults + reservation.children_occupying
max_capacity = record.room_id.capacity + record.room_id.extra_beds_allowed
if occupancy > max_capacity:
if not room.fits_occupancy(
reservation.adults, reservation.children, room.extra_beds_allowed
):
raise ValidationError(
_(
"The room %(room)s can't hold %(occupancy)s guests "
"(maximum capacity: %(capacity)s) (%(reservation)s)",
room=record.room_id.display_name,
occupancy=occupancy,
capacity=max_capacity,
"The room %(room)s can't hold %(adults)s adults and "
"%(children)s children (capacity: %(capacity)s, "
"children places: %(children_capacity)s) "
"(%(reservation)s)",
room=room.display_name,
adults=reservation.adults,
children=reservation.children,
capacity=room.capacity + room.extra_beds_allowed,
children_capacity=room.children_capacity,
reservation=reservation.name,
)
)
Expand Down
60 changes: 50 additions & 10 deletions pms/models/pms_room.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools import str2bool


class PmsRoom(models.Model):
Expand Down Expand Up @@ -77,7 +78,14 @@ class PmsRoom(models.Model):
check_pms_properties=True,
)
capacity = fields.Integer(
help="The maximum number of people that can occupy a room"
help="Number of places where anyone can sleep, adults or children"
)
children_capacity = fields.Integer(
help="Number of places where only children can sleep, such as child "
"bunk beds. Adults never occupy them, children occupy them only once "
"the regular capacity is full",
required=True,
default=0,
)
extra_beds_allowed = fields.Integer(
help="Number of extra beds allowed in room",
Expand Down Expand Up @@ -314,16 +322,15 @@ def _check_adults(self, reservation, service_line_ids=False):
and x.product_id.is_extra_bed is True
)
num_extra_beds = sum(extra_beds.mapped("day_qty")) if extra_beds else 0
if line.room_id:
if (
reservation.adults + reservation.children_occupying
) > line.room_id.get_capacity(num_extra_beds):
raise ValidationError(
_(
"Persons can't be higher than room capacity (%s)",
reservation.name,
)
if line.room_id and not line.room_id.fits_occupancy(
reservation.adults, reservation.children, num_extra_beds
):
raise ValidationError(
_(
"Persons can't be higher than room capacity (%s)",
reservation.name,
)
)

@api.constrains("short_name")
def _check_short_name(self):
Expand Down Expand Up @@ -430,3 +437,36 @@ def get_capacity(self, extra_bed=0):
_("Extra beds can't be greater than allowed beds for this room")
)
return record.capacity + extra_bed

@api.model
def _children_occupy_capacity(self):
"""Whether children take a place in the room.

Off unless the property turns it on, which is how it worked until
now: counting them refuses reservations that properties have been
taking, so it is theirs to decide and not something an upgrade does.
"""
return str2bool(
self.env["ir.config_parameter"]
.sudo()
.get_param("pms.children_occupy_capacity"),
default=False,
)

def fits_occupancy(self, adults, children=0, extra_bed=0):
"""Whether the room can hold the given guests.

Children sleep in the regular capacity as well, and only overflow
into 'children_capacity' once it is full. Adults never occupy those
places, so a room with free children places can still be full.

Whether children take a place at all is up to the property, see
_children_occupy_capacity.
"""
self.ensure_one()
capacity = self.get_capacity(extra_bed)
if adults > capacity:
return False
if not self._children_occupy_capacity():
return True
return adults + children <= capacity + self.children_capacity
16 changes: 16 additions & 0 deletions pms/readme/CONFIGURE.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
You will find the hotel settings in PMS Management > Configuration > Properties > Your Property.

This module required additional configuration for company, accounting, invoicing and user privileges.

Children and room capacity
~~~~~~~~~~~~~~~~~~~~~~~~~~

By default children take no place in the room, so only the adults are checked
against its capacity. Properties that want to count them can set the system
parameter ``pms.children_occupy_capacity`` to ``True``, in Settings > Technical
> System Parameters.

Once it is on, children take the regular places of the room first and only
overflow into its children places, the ones where only a child can sleep, such
as child bunk beds. Adults never occupy those, so a room with free children
places can still be full.

Mind that turning it on refuses reservations that the property may have been
taking until then.
42 changes: 29 additions & 13 deletions pms/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -383,13 +383,16 @@ <h1>PMS (Property Management System)</h1>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#installation" id="toc-entry-1">Installation</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-2">Configuration</a></li>
<li><a class="reference internal" href="#usage" id="toc-entry-3">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-4">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-5">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-6">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-7">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-8">Maintainers</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-2">Configuration</a><ul>
<li><a class="reference internal" href="#children-and-room-capacity" id="toc-entry-3">Children and room capacity</a></li>
</ul>
</li>
<li><a class="reference internal" href="#usage" id="toc-entry-4">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-5">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-6">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-7">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-8">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-9">Maintainers</a></li>
</ul>
</li>
</ul>
Expand All @@ -403,29 +406,42 @@ <h2><a class="toc-backref" href="#toc-entry-1">Installation</a></h2>
<h2><a class="toc-backref" href="#toc-entry-2">Configuration</a></h2>
<p>You will find the hotel settings in PMS Management &gt; Configuration &gt; Properties &gt; Your Property.</p>
<p>This module required additional configuration for company, accounting, invoicing and user privileges.</p>
<div class="section" id="children-and-room-capacity">
<h3><a class="toc-backref" href="#toc-entry-3">Children and room capacity</a></h3>
<p>By default children take no place in the room, so only the adults are checked
against its capacity. Properties that want to count them can set the system
parameter <tt class="docutils literal">pms.children_occupy_capacity</tt> to <tt class="docutils literal">True</tt>, in Settings &gt; Technical
&gt; System Parameters.</p>
<p>Once it is on, children take the regular places of the room first and only
overflow into its children places, the ones where only a child can sleep, such
as child bunk beds. Adults never occupy those, so a room with free children
places can still be full.</p>
<p>Mind that turning it on refuses reservations that the property may have been
taking until then.</p>
</div>
</div>
<div class="section" id="usage">
<h2><a class="toc-backref" href="#toc-entry-3">Usage</a></h2>
<h2><a class="toc-backref" href="#toc-entry-4">Usage</a></h2>
<p>To use this module, please, read the complete user guide at <a class="reference external" href="roomdoo.com">roomdoo.com</a>.</p>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-4">Bug Tracker</a></h2>
<h2><a class="toc-backref" href="#toc-entry-5">Bug Tracker</a></h2>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/pms/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/pms/issues/new?body=module:%20pms%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-5">Credits</a></h2>
<h2><a class="toc-backref" href="#toc-entry-6">Credits</a></h2>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-6">Authors</a></h3>
<h3><a class="toc-backref" href="#toc-entry-7">Authors</a></h3>
<ul class="simple">
<li>Commit [Sun]</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-7">Contributors</a></h3>
<h3><a class="toc-backref" href="#toc-entry-8">Contributors</a></h3>
<ul class="simple">
<li>Alexandre Díaz</li>
<li>Pablo Quesada</li>
Expand All @@ -442,7 +458,7 @@ <h3><a class="toc-backref" href="#toc-entry-7">Contributors</a></h3>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-8">Maintainers</a></h3>
<h3><a class="toc-backref" href="#toc-entry-9">Maintainers</a></h3>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
Expand Down
Loading
Loading