Repository navigation
[WIP][16.0] Refactor board services - #467
Draft
jesusVMayor wants to merge 4 commits into
Draft
jesusVMayor wants to merge 4 commits into
jesusVMayor wants to merge 4 commits into
Conversation
Rooms declared how many people fit, with no way to say how many of those places are for children only, such as child bunk beds. Children were meant to be counted through the reservation children_occupying, but nothing kept that field in sync with children and it was left empty, so children did not count towards the room capacity at all. Rooms get children_capacity now. capacity keeps its meaning, the places where anyone can sleep, and children take those first, overflowing into the children places only once they are full. Adults never occupy them, so a room with free children places can still be full for adults. Whether children take a place at all is up to the property, through the pms.children_occupy_capacity system parameter, and off unless it says otherwise: counting them refuses reservations that properties have been taking all along, so it cannot be something an upgrade decides for them. children_occupying is dropped. A reservation could declare an occupying child without counting it in children, so the migration folds it into children before the column goes away. Assisted-by: Claude Opus 5
The INE extra bed count subtracted the children occupying the room from the extra beds sold for that date. Nothing ever filled children_occupying in, so the subtraction always took zero, and the field is gone now. Assisted-by: Claude Opus 5
A pricelist gave a room type one price per night, whoever stayed in it. Selling a double for less when a single guest takes it, or charging for a third one, could only be done by hand on every reservation. Room types get the occupancy their rooms guarantee (max_occupancy, the smallest capacity among them, as any of them can be the one assigned) and the occupancy their price is given for (default_occupancy). A pricelist then carries, per room type, how much each guest above or below that default changes the price, as a percentage or as an amount. The modifier is linear, applying once per guest of difference, which is what channel managers derive from a default occupancy as well. A price asked for without an occupancy, or a room type with no modifiers, is the plain one of the pricelist, so this is transparent to everything pricing a room type without guests in hand. Changing the adults leaves the prices of the nights as they are, the same as changing the pricelist or the room type does: the form flags them as outdated, and updating them prices the nights for the adults staying. Nights added afterwards are priced for them already. A price is never rewritten behind the back of whoever wrote it, such as a channel manager writing what an OTA sold. The birthdate of the guests checking in never takes part in it: nobody reprices at the desk because a guest had a birthday.
A board service was a model of its own, pms.board.service, copied for each room type in pms.board.service.room.type with a fixed amount per line that no pricelist could change. It becomes a product template flagged as a board service, priced by the pricelist on each consumption date like any product. - Adults and children consume their own variant through the Guest attribute that pms provides. A board service without it is a single product for every guest. - Pricelists list the board services they sell and a default one. Room Only, created by data, is listed like the rest and never adds a service: it is there to be sold, or closed to force a board service. - Availability plans close board services on date ranges. - A reservation keeps the board services it generates, marked with the guests they count, and leaves alone the ones added by other means. - board_service_room_type_id is removed from pricelist items. Rule selection had ignored it since 2025. There is no migration yet: the existing board services, their copies per room type and the board service of each reservation are not carried over.
jesusVMayor
force-pushed
the
16.0-ref-board-service-products
branch
from
October 21, 2026 10:33
c082734 to
87fb806
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
A board service (breakfast, half board…) was a model of its own,
pms.board.service: a list of products with a fixed amount for adults orchildren. To be sold it had to be copied to every room type
(
pms.board.service.room.type), and that copy, with its own fixed amounts, iswhat reservations, services and pricelist items pointed to. Its price could not
be changed per pricelist or per date, and keeping the copies in step across room
types was tedious.
This PR turns a board service into a product: a product template flagged
with
is_board_service, priced by the pricelist on each consumption date likeany other product. The four board service models are removed.
Adults and children
pmsships a Guest attribute (Adult, Child). A board service:its own price (a pricelist rule per variant, or the
price_extraof thevalue);
Each guest consumes the variant for them, counted per person and per night as
the product says. Adding or removing children adds or removes their variant
without touching the adults'.
Composed board services (half board as a breakfast and a dinner service) are
left to an optional module on top of
product_pack:product.template._get_board_service_productsis the hook for it.Pricelists
board_service_ids: the board services the pricelist sells. It is anexplicit list, and a new pricelist starts with Room Only.
default_board_service_id: the board service of its reservations unlessanother one is chosen. Empty means Room Only.
board_service_room_type_idis removed from pricelist items. Rule selectionhad ignored it since 2025, so a rule on a product already applied to every
board service.
Room Only is a product template created by data. It never adds a service
to a reservation: it exists to be listed in pricelists and closed in
availability plans.
Availability plans
A new model,
pms.availability.plan.board.rule, closes a board service on adate range for the pricelists of the plan, with a single
closedfield. Rulescan overlap, and the last one written wins, so a rule that is not closed reopens
what an earlier one closes. The checkout night is not part of the stay.
Closing Room Only is how a property forces a board service on some dates.
Reservations
board_service_id(a product template) replacesboard_service_room_id.It takes the default of the pricelist if the pricelist sells it for the stay,
and once chosen by the user (even empty) it is kept.
the guests they count (
board_guest_type). Board services added by othermeans are left alone.
what is offered and defaulted, not what a reservation can hold.
A board service menu stays under Services, as a filtered view of the products.
Fixed on the way
_compute_board_service_idsreturned from inside the loop, so the rest of abatch was skipped, and children added after the board service never got
their services.
pms.reservation.createused the values of the last reservation of thebatch for all of them, and returned only the last record.
list, so it never matched.
Breaking changes
pms.board.service,pms.board.service.line,pms.board.service.room.typeand
pms.board.service.room.type.lineare removed, together withpms.room.type.board_service_room_type_idsandget_default_board_service.pms.reservation.board_service_room_idbecomesboard_service_id, andpms.service.board_service_line_idbecomesboard_guest_type.variants are priced as services.
Pending
their prices, and the board service of each reservation and service.
Depends on
#463 and #464, whose commits show up in this diff until they are merged.
Testing
pms/tests/test_pms_board_service.py, rewritten: consumption by variants,adding and removing children, Room Only, prices from the pricelist and from
price_extra, the constraints, the default of the reservation, closings,reopening, the checkout night and properties.
pmssuite passes on a fresh database with demo data, but for thetwo tests that already fail on
16.0(
test_pms_folio_priority_fiscal_position_propertyandtest_do_payment_sets_payment_method_line), and so doespms_l10n_es.