Kaizen
Browse modulesBookingsbookings/serverClasses

Class: AvailabilityService

Defined in: server/bookings/availability-service.ts:183

Open-window resolution + scheduling glue (spec §6.9, §11).

Reads (openWindows/freeSlots) are plain queries; window EDITS and applyWeeklyHours are transactions that take the per-space booking_resources row lock so they serialize against concurrent claims.

Constructors

Constructor

new AvailabilityService(deps: BookingFeatureDeps): AvailabilityService;

Defined in: server/bookings/availability-service.ts:184

Parameters

ParameterType
depsBookingFeatureDeps

Returns

AvailabilityService

Properties

deps

protected readonly deps: BookingFeatureDeps;

Defined in: server/bookings/availability-service.ts:184

Methods

addWindow()

addWindow(input: {
  availabilityId: string;
  endsAt: Date;
  startsAt: Date;
}): Promise<{
  availabilityId: string;
  createdAt: Date;
  createdBy: string | null;
  deletedAt: Date | null;
  deletedBy: string | null;
  endsAt: Date;
  id: string;
  isException: boolean;
  resourceId: string;
  startsAt: Date;
  updatedAt: Date;
  updatedBy: string | null;
}>;

Defined in: server/bookings/availability-service.ts:306

Add a one-off open window (the RDATE analogue, spec §6.9 — e.g. a special midnight session). Always isException: true.

Parameters

ParameterType
input{ availabilityId: string; endsAt: Date; startsAt: Date; }
input.availabilityIdstring
input.endsAtDate
input.startsAtDate

Returns

Promise<{ availabilityId: string; createdAt: Date; createdBy: string | null; deletedAt: Date | null; deletedBy: string | null; endsAt: Date; id: string; isException: boolean; resourceId: string; startsAt: Date; updatedAt: Date; updatedBy: string | null; }>


applyWeeklyHours()

applyWeeklyHours(
   resourceId: string, 
   map: WeeklyHoursMap, 
   opts: WeeklyHoursToSeriesOptions
): Promise<ApplyWeeklyHoursResult>;

Defined in: server/bookings/availability-service.ts:389

Apply a weekly hours map to a resource (spec §6.9 "Weekly hours stay a one-liner — and the EDIT path is specified, not just create"). NOT a destructive overwrite — a real this-and-following split per existing active series:

  • the old series' rule is CAPPED at effectiveFrom (the one capping implementation: lowered COUNT for COUNT-bounded rules, else UNTIL) and its status flips to "ended";
  • its already-materialized future NON-EXCEPTION windows (the machine-generated old-hours rows at/after the split) are removed — they are superseded by the new pattern's fan-out;
  • exception windows — edited "special hours" AND soft-deleted holiday closures (the July-4 row) — are left UNTOUCHED on the capped old series, and the materializer's closure guard keeps the successor from re-opening a closed occurrence: a closure is never silently resurrected (§6.9);
  • new pattern series are minted with supersedesAvailabilityId lineage.

Windows are NOT materialized here — run the availability materializer on the new series; until then the resource correctly fails closed beyond the split (§6.9 safe default).

Parameters

ParameterType
resourceIdstring
mapWeeklyHoursMap
optsWeeklyHoursToSeriesOptions

Returns

Promise<ApplyWeeklyHoursResult>


closeWindow()

closeWindow(windowId: string): Promise<{
  availabilityId: string;
  createdAt: Date;
  createdBy: string | null;
  deletedAt: Date | null;
  deletedBy: string | null;
  endsAt: Date;
  id: string;
  isException: boolean;
  resourceId: string;
  startsAt: Date;
  updatedAt: Date;
  updatedBy: string | null;
}>;

Defined in: server/bookings/availability-service.ts:358

Close one occurrence ("closed for the holiday" — spec §6.9): soft-deletes the window row. The row PERSISTS (isException: true) and blocks regeneration, exactly like a cancelled series child booking.

Parameters

ParameterType
windowIdstring

Returns

Promise<{ availabilityId: string; createdAt: Date; createdBy: string | null; deletedAt: Date | null; deletedBy: string | null; endsAt: Date; id: string; isException: boolean; resourceId: string; startsAt: Date; updatedAt: Date; updatedBy: string | null; }>


freeSlots()

freeSlots(
   resourceId: string, 
   range: TimeRange, 
   opts: FreeSlotsOptions
): Promise<TimeRange[]>;

Defined in: server/bookings/availability-service.ts:237

On-demand slot-stepping (§6.9 — bookable slot-steps are NEVER materialized): subtract exclusive conflicts or shared saturation from open windows, using the same live-occupancy predicate as claims. Results are advisory: claims recheck capacity and hours under locks. Booking-type policy and pricing are not evaluated here.

Parameters

ParameterType
resourceIdstring
rangeTimeRange
optsFreeSlotsOptions

Returns

Promise<TimeRange[]>


openWindows()

openWindows(resourceId: string, range: TimeRange): Promise<TimeRange[]>;

Defined in: server/bookings/availability-service.ts:191

Merged union of live open windows for a resource, clamped to range. Unconfigured hours mean the whole range is open; configured but windowless resources remain closed. Returned in range.start's zone.

Parameters

ParameterType
resourceIdstring
rangeTimeRange

Returns

Promise<TimeRange[]>


updateWindow()

updateWindow(windowId: string, patch: {
  endsAt?: Date;
  startsAt?: Date;
}): Promise<{
  availabilityId: string;
  createdAt: Date;
  createdBy: string | null;
  deletedAt: Date | null;
  deletedBy: string | null;
  endsAt: Date;
  id: string;
  isException: boolean;
  resourceId: string;
  startsAt: Date;
  updatedAt: Date;
  updatedBy: string | null;
}>;

Defined in: server/bookings/availability-service.ts:332

Per-occurrence edit ("special hours" — spec §6.9 this-occurrence scope): patches the window row and flags it isException so series-wide edits skip it. Serializes against claims on the per-space lock.

Parameters

ParameterType
windowIdstring
patch{ endsAt?: Date; startsAt?: Date; }
patch.endsAt?Date
patch.startsAt?Date

Returns

Promise<{ availabilityId: string; createdAt: Date; createdBy: string | null; deletedAt: Date | null; deletedBy: string | null; endsAt: Date; id: string; isException: boolean; resourceId: string; startsAt: Date; updatedAt: Date; updatedBy: string | null; }>

On this page