Skip to content

[FIX] pms_sale: min_nights was never actually enforced - #444

Open
bretif wants to merge 1 commit into
OCA:19.0from
bretif:fix-pms-sale-min-nights-enforcement
Open

[FIX] pms_sale: min_nights was never actually enforced#444
bretif wants to merge 1 commit into
OCA:19.0from
bretif:fix-pms-sale-min-nights-enforcement

Conversation

@bretif

@bretif bretif commented Aug 30, 2026

Copy link
Copy Markdown

Bug

pms.reservation._check_no_of_nights() never actually enforces min_nights, regardless of its value. Its condition:

if (
    rec.duration > rec.property_id.min_nights
    and rec.property_id.max_nights < rec.duration
):
    raise ValidationError(...)

only rejects a reservation when its duration exceeds both bounds at the same time — in practice this means only max_nights is ever checked, min_nights is dead code. Verified directly against a pms.property/pms.reservation pair:

min_nights max_nights duration result (before fix)
2 30 1 night accepted (should be rejected)
5 5 3 nights accepted (should be rejected)
1 3 5 nights rejected ✓
0 0 (default) 2 nights rejected

Fix

Corrected condition: duration < min_nights or duration > max_nights, treating 0 on either bound as "no limit" (the common Odoo convention for min/max quantity fields).

Behavior change to flag for review: previously, a property left at the default min_nights=0/max_nights=0 rejected every reservation (with the confusing message "must be between 0 and 0"). With this fix, an unconfigured property now has no stay-length restriction at all, rather than being implicitly unbookable. I don't see anything in the field definitions, views, demo data or existing tests suggesting the old all-rejecting behavior was intentional (nothing marks 0 as a "not for rent" flag), but flagging explicitly in case there's context I'm missing.

Tests

Added 3 regression tests to pms_sale/tests/test_pms_reservation.py covering: a too-short stay against a real min_nights, a fixed-length stay (min_nights == max_nights) below the required length, and an unconfigured (0/0) property. All go through write() (real @api.constrains dispatch), not a direct method call.

Ran the full pms_sale test suite locally (Odoo 19.0, PostgreSQL): 19/19 of the module's own tests pass with this change (one pre-existing, unrelated failure in test_onchange_property_id — a timezone-dependent assertion — is present identically on the unpatched 19.0 branch, confirmed by reverting and re-running).

Found while validating this module for a downstream project's data model.

_check_no_of_nights()'s condition (duration > min_nights and
max_nights < duration) only rejects a reservation when its duration
exceeds *both* bounds at once, so in practice only max_nights was ever
checked: a property with min_nights=2 would happily accept a 1-night
stay, and one with min_nights=max_nights=5 would accept a 3-night stay.

Fix the condition to duration < min_nights or duration > max_nights,
treating 0 as "no bound" on either side (matching the common Odoo
convention for min/max quantity fields), rather than the previous
behavior where min_nights=max_nights=0 rejected every reservation.
@OCA-git-bot

Copy link
Copy Markdown
Contributor

Hi @max3903,
some modules you are maintaining are being modified, check this out!

@bretif
bretif marked this pull request as ready for review August 30, 2026 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants