Pricing engine
One pure function (packages/shared/src/pricing.ts) prices every stay. The public quote box, the booking dialog’s auto-price and (later) owner statements all call the same code — totals can never diverge between what the guest saw and what the backoffice books.
The formula
Section titled “The formula”nightly rate = season price ?? base rate (global season calendar; a season's price conditions target all units, one category or a manual unit list) → holiday rules adjust the resolved rate around moving holidays (±% on it, an absolute amount on top, or a fixed price)accommodation = Σ nightly rate− long-stay discount (≥28 nights: monthly %, else ≥7 nights: weekly %)+ cleaning fee (once per stay)+ Tourism Dirham (fee per bedroom per night, capped at 30 nights; studios count as 1 bedroom)+ VAT (default 5% on accommodation − discount + cleaning; the Tourism Dirham is a government levy outside the VAT base*)= total* Assumption documented for tax-advisor review; both the VAT rate and the Dirham fee/cap are tenant-configurable (tenants.vat_pct, tourism_fee_per_bedroom_night, tourism_fee_max_nights).
Example — Port de La Mer 2BR, 7 nights
Section titled “Example — Port de La Mer 2BR, 7 nights”| Line | Amount |
|---|---|
| 7 nights × AED 425 | AED 2,975 |
| Weekly discount (−6%) | −AED 178.50 |
| Cleaning fee | AED 350 |
| Tourism Dirham (2 BR × 7 nights × AED 10) | AED 140 |
| VAT (5%) | AED 157.33 |
| Total | AED 3,443.83 |
Rules around the price
Section titled “Rules around the price”- Seasons are global recurring periods (month/day, wrap over New Year allowed). Each season carries price conditions — the same price for everyone, one per category (lifestyle/luxury), or a hand-picked unit list; the most specific matching condition wins (units > category > all).
- Holiday rules are an overlay, not date ranges: they follow the synced dates of a moving holiday (Ramadan, Eid, Easter, CNY …) plus days before/after, and adjust the already-resolved nightly price per condition — ±%, an absolute amount, or a fixed price.
- Minimum stay per unit is enforced in the quote endpoint (422 with the required nights); seasons and holiday rules can raise it for the nights they touch.
- Manual override: the backoffice may replace the auto total (e.g. OTA gross amounts); the override is stored on the booking, the engine’s breakdown remains reproducible.
- All amounts are stored as integer minor units (fils); formatting happens at the edge.
Planned extensions (P3)
Section titled “Planned extensions (P3)”Per-day overrides via drag-selection in the price-calendar mode, min-stay per date, and channel-specific rate adjustments.