AstroBaaS

Pricing & promotions

Dynamic Pricing by Season (Hotels)

Paid pluginsize Mplanned, not built

Indicative price, not an offer: €39/mo; seasonal rules, demand-based pricing, blackout dates

Generated from docs/plan/paid/dynamic-pricing-by-season/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.

A paid module for hotels and seasonal businesses that sets different prices for different date ranges (winter €80/night, summer €150/night, shoulder season €110/night). Merchants define seasonal pricing rules in a calendar UI, and the storefront automatically selects the correct price based on checkout dates. Supports booking windows (e.g., advance bookings get 10% discount) and blackout dates.

The problem

A hotel’s revenue per night varies wildly by season: €80 in winter, €150 in summer, but they can only set one price in the system. Currently, they manually update prices monthly or lose margin (underpricing in season, overpricing off-season). Competitors with dynamic pricing capture 20–30% more revenue from the same inventory.

What it does

  • Create seasonal pricing rules: date range (start_date, end_date), base_price, optional modifiers (advance_booking %, walk_in %, group_booking %)
  • Calendar UI in admin: visual timeline showing seasons (color-coded bars: winter blue, summer red, shoulder gray)
  • Set blackout dates: selected dates are unavailable for booking (e.g., maintenance, private event)
  • Storefront checkout: customer selects check-in and check-out dates → system calculates price per night using rule matching the date range
  • Booking window discount: if booked 30+ days in advance, apply advance_booking % discount to base_price
  • Group booking rule: if 10+ rooms booked, apply group % discount (customer provides group size at checkout)
  • Minimum stay rule: some seasons require 3-night minimum; enforce at checkout
  • Audit log: every pricing rule change (created, edited, deleted) with timestamp and merchant who changed it

What it deliberately does NOT do

Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.

  • Real-time yield optimization (pricing algorithm that adjusts price per remaining inventory; too complex, no ML model)
  • Occupancy forecasting or inventory syncing (merchant owns the inventory system; we only set prices)
  • Payment plans or deposit requirements (payment flow is merchant/processor concern)

Data model

Add seasonal_pricing_rules table: { id, shop_id, season_name, start_date, end_date, base_price_minor_units, advance_booking_pct, walk_in_pct, group_size_threshold, group_pct, min_stay_nights }. Add blackout_dates table: { id, shop_id, date, reason }. Schema migration: new tables, no risk.

API

  • POST /admin/seasonal-pricing — create seasonal rule
  • GET /admin/seasonal-pricing — list all rules for the season
  • PUT /admin/seasonal-pricing/:id — edit rule (date, price, modifiers)
  • DELETE /admin/seasonal-pricing/:id — delete rule
  • POST /checkout/calculate-price — { check_in_date, check_out_date, booking_days_advance, group_size } → returns nightly_price, total_price, rule_applied
  • GET /admin/calendar/blackout-dates — list blackout dates
  • POST /admin/calendar/blackout-dates — add blackout date

Every route added here must also appear in src/pages/openapi.json.ts — a test fails the build if it does not.

Admin

Add ‘Seasonal Pricing’ section in Commerce > Pricing. Calendar view (month/year selector): shows seasons as colored bars, blackout dates as red X. Click date range to create/edit rule. Form: season name, start/end dates, base price, advance_booking % (e.g., 10 = 10% discount), group_size_threshold (e.g., 10 rooms), group % discount (e.g., 15%). Click single date to add blackout.

The seam — why this is paid

Paid module owns the seasonal pricing rules engine and the complex calendar/date-range logic. Core owns the checkout flow and price calculation. Merchants without this module can update prices manually via product schema.

Support commitment: pricing algorithm, revenue-management SLA, occupancy forecasting

Dependencies

  • Checkout flow (must call pricing calculator based on dates selected)
  • Product schema (nightly rate or booking product must exist)
  • Audit log (to track pricing rule changes)

Acceptance checks

Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.

  • A rule ‘Summer’ (Jun 1 – Aug 31) with base_price = 15000 (€150) applies to bookings starting Jun 1
  • A booking from Jun 15–Jun 18 (3 nights) at base price €150/night = €450 total
  • If booked on May 10 (36 days in advance) with advance_booking_pct = 10, nightly price = €135 (10% discount), total = €405
  • A blackout date on Jul 4 prevents checkout for check-in/out spanning Jul 4 (error: ‘date unavailable’)
  • If min_stay_nights = 3 for summer, a 2-night booking returns error: ‘minimum 3 nights required’
  • Editing a rule (e.g., changing summer price €150 → €160) does not retroactively change past bookings, only future

Risks

If date range matching is not exclusive (two overlapping rules both match), price is ambiguous (always apply earliest-defined rule, document this). If advance_booking discount is applied as absolute subtraction instead of percentage, calculation is wrong. If blackout dates are stored as strings instead of dates, comparison fails (store as ISO 8601).

Commercial context

Suggested price€39/mo; seasonal rules, demand-based pricing, blackout dates
Rival anchorAirbnb built-in; custom: €2000+; Magento: no app

The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.


Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full catalogue and ../../AI-GUIDE.md for how to work on this repository.