@voyantjs/hospitality 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/schema.js ADDED
@@ -0,0 +1,779 @@
1
+ import { bookingItems } from "@voyantjs/bookings/schema";
2
+ import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
3
+ import { properties } from "@voyantjs/facilities/schema";
4
+ import { relations } from "drizzle-orm";
5
+ import { boolean, char, date, index, integer, jsonb, pgEnum, pgTable, text, timestamp, uniqueIndex, } from "drizzle-orm/pg-core";
6
+ export const hospitalityInventoryModeEnum = pgEnum("hospitality_inventory_mode", [
7
+ "pooled",
8
+ "serialized",
9
+ "virtual",
10
+ ]);
11
+ export const roomUnitStatusEnum = pgEnum("room_unit_status", [
12
+ "active",
13
+ "inactive",
14
+ "out_of_order",
15
+ "archived",
16
+ ]);
17
+ export const ratePlanChargeFrequencyEnum = pgEnum("rate_plan_charge_frequency", [
18
+ "per_night",
19
+ "per_stay",
20
+ "per_person_per_night",
21
+ "per_person_per_stay",
22
+ ]);
23
+ export const hospitalityGuaranteeModeEnum = pgEnum("hospitality_guarantee_mode", [
24
+ "none",
25
+ "card_hold",
26
+ "deposit",
27
+ "full_prepay",
28
+ "on_request",
29
+ ]);
30
+ export const stayBookingItemStatusEnum = pgEnum("stay_booking_item_status", [
31
+ "reserved",
32
+ "checked_in",
33
+ "checked_out",
34
+ "cancelled",
35
+ "no_show",
36
+ ]);
37
+ export const hospitalityRoomBlockStatusEnum = pgEnum("hospitality_room_block_status", [
38
+ "draft",
39
+ "held",
40
+ "confirmed",
41
+ "released",
42
+ "cancelled",
43
+ ]);
44
+ export const hospitalityHousekeepingTaskStatusEnum = pgEnum("hospitality_housekeeping_task_status", ["open", "in_progress", "completed", "cancelled"]);
45
+ export const hospitalityMaintenanceBlockStatusEnum = pgEnum("hospitality_maintenance_block_status", ["open", "in_progress", "resolved", "cancelled"]);
46
+ export const stayOperationStatusEnum = pgEnum("stay_operation_status", [
47
+ "reserved",
48
+ "expected_arrival",
49
+ "checked_in",
50
+ "checked_out",
51
+ "no_show",
52
+ "cancelled",
53
+ ]);
54
+ export const stayCheckpointTypeEnum = pgEnum("stay_checkpoint_type", [
55
+ "arrival",
56
+ "room_assigned",
57
+ "check_in",
58
+ "room_move",
59
+ "charge_posted",
60
+ "check_out",
61
+ "no_show",
62
+ "note",
63
+ ]);
64
+ export const stayServicePostKindEnum = pgEnum("stay_service_post_kind", [
65
+ "lodging",
66
+ "meal",
67
+ "minibar",
68
+ "fee",
69
+ "adjustment",
70
+ "other",
71
+ ]);
72
+ export const stayFolioStatusEnum = pgEnum("stay_folio_status", [
73
+ "open",
74
+ "closed",
75
+ "transferred",
76
+ "void",
77
+ ]);
78
+ export const roomTypes = pgTable("room_types", {
79
+ id: typeId("room_types"),
80
+ propertyId: typeIdRef("property_id")
81
+ .notNull()
82
+ .references(() => properties.id, { onDelete: "cascade" }),
83
+ code: text("code"),
84
+ name: text("name").notNull(),
85
+ description: text("description"),
86
+ inventoryMode: hospitalityInventoryModeEnum("inventory_mode").notNull().default("pooled"),
87
+ roomClass: text("room_class"),
88
+ maxAdults: integer("max_adults"),
89
+ maxChildren: integer("max_children"),
90
+ maxInfants: integer("max_infants"),
91
+ standardOccupancy: integer("standard_occupancy"),
92
+ maxOccupancy: integer("max_occupancy"),
93
+ minOccupancy: integer("min_occupancy"),
94
+ bedroomCount: integer("bedroom_count"),
95
+ bathroomCount: integer("bathroom_count"),
96
+ areaValue: integer("area_value"),
97
+ areaUnit: text("area_unit"),
98
+ accessibilityNotes: text("accessibility_notes"),
99
+ smokingAllowed: boolean("smoking_allowed").notNull().default(false),
100
+ active: boolean("active").notNull().default(true),
101
+ sortOrder: integer("sort_order").notNull().default(0),
102
+ metadata: jsonb("metadata").$type(),
103
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
104
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
105
+ }, (table) => [
106
+ index("idx_room_types_property").on(table.propertyId),
107
+ index("idx_room_types_active").on(table.active),
108
+ index("idx_room_types_inventory_mode").on(table.inventoryMode),
109
+ uniqueIndex("uidx_room_types_property_code").on(table.propertyId, table.code),
110
+ ]);
111
+ export const roomTypeBedConfigs = pgTable("room_type_bed_configs", {
112
+ id: typeId("room_type_bed_configs"),
113
+ roomTypeId: typeIdRef("room_type_id")
114
+ .notNull()
115
+ .references(() => roomTypes.id, { onDelete: "cascade" }),
116
+ bedType: text("bed_type").notNull(),
117
+ quantity: integer("quantity").notNull().default(1),
118
+ isPrimary: boolean("is_primary").notNull().default(false),
119
+ notes: text("notes"),
120
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
121
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
122
+ }, (table) => [
123
+ index("idx_room_type_bed_configs_room_type").on(table.roomTypeId),
124
+ index("idx_room_type_bed_configs_primary").on(table.isPrimary),
125
+ ]);
126
+ export const roomUnits = pgTable("room_units", {
127
+ id: typeId("room_units"),
128
+ propertyId: typeIdRef("property_id")
129
+ .notNull()
130
+ .references(() => properties.id, { onDelete: "cascade" }),
131
+ roomTypeId: typeIdRef("room_type_id")
132
+ .notNull()
133
+ .references(() => roomTypes.id, { onDelete: "cascade" }),
134
+ code: text("code"),
135
+ roomNumber: text("room_number"),
136
+ floor: text("floor"),
137
+ wing: text("wing"),
138
+ status: roomUnitStatusEnum("status").notNull().default("active"),
139
+ viewCode: text("view_code"),
140
+ accessibilityCode: text("accessibility_code"),
141
+ genderRestriction: text("gender_restriction"),
142
+ notes: text("notes"),
143
+ metadata: jsonb("metadata").$type(),
144
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
145
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
146
+ }, (table) => [
147
+ index("idx_room_units_property").on(table.propertyId),
148
+ index("idx_room_units_room_type").on(table.roomTypeId),
149
+ index("idx_room_units_status").on(table.status),
150
+ uniqueIndex("uidx_room_units_property_code").on(table.propertyId, table.code),
151
+ ]);
152
+ export const mealPlans = pgTable("meal_plans", {
153
+ id: typeId("meal_plans"),
154
+ propertyId: typeIdRef("property_id")
155
+ .notNull()
156
+ .references(() => properties.id, { onDelete: "cascade" }),
157
+ code: text("code").notNull(),
158
+ name: text("name").notNull(),
159
+ description: text("description"),
160
+ includesBreakfast: boolean("includes_breakfast").notNull().default(false),
161
+ includesLunch: boolean("includes_lunch").notNull().default(false),
162
+ includesDinner: boolean("includes_dinner").notNull().default(false),
163
+ includesDrinks: boolean("includes_drinks").notNull().default(false),
164
+ active: boolean("active").notNull().default(true),
165
+ sortOrder: integer("sort_order").notNull().default(0),
166
+ metadata: jsonb("metadata").$type(),
167
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
168
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
169
+ }, (table) => [
170
+ index("idx_meal_plans_property").on(table.propertyId),
171
+ index("idx_meal_plans_active").on(table.active),
172
+ uniqueIndex("uidx_meal_plans_property_code").on(table.propertyId, table.code),
173
+ ]);
174
+ export const ratePlans = pgTable("rate_plans", {
175
+ id: typeId("rate_plans"),
176
+ propertyId: typeIdRef("property_id")
177
+ .notNull()
178
+ .references(() => properties.id, { onDelete: "cascade" }),
179
+ code: text("code").notNull(),
180
+ name: text("name").notNull(),
181
+ description: text("description"),
182
+ mealPlanId: typeIdRef("meal_plan_id").references(() => mealPlans.id, { onDelete: "set null" }),
183
+ priceCatalogId: text("price_catalog_id"),
184
+ cancellationPolicyId: text("cancellation_policy_id"),
185
+ marketId: text("market_id"),
186
+ currencyCode: text("currency_code").notNull(),
187
+ chargeFrequency: ratePlanChargeFrequencyEnum("charge_frequency").notNull().default("per_night"),
188
+ guaranteeMode: hospitalityGuaranteeModeEnum("guarantee_mode").notNull().default("none"),
189
+ commissionable: boolean("commissionable").notNull().default(true),
190
+ refundable: boolean("refundable").notNull().default(true),
191
+ active: boolean("active").notNull().default(true),
192
+ sortOrder: integer("sort_order").notNull().default(0),
193
+ metadata: jsonb("metadata").$type(),
194
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
195
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
196
+ }, (table) => [
197
+ index("idx_rate_plans_property").on(table.propertyId),
198
+ index("idx_rate_plans_meal_plan").on(table.mealPlanId),
199
+ index("idx_rate_plans_catalog").on(table.priceCatalogId),
200
+ index("idx_rate_plans_policy").on(table.cancellationPolicyId),
201
+ index("idx_rate_plans_market").on(table.marketId),
202
+ index("idx_rate_plans_active").on(table.active),
203
+ uniqueIndex("uidx_rate_plans_property_code").on(table.propertyId, table.code),
204
+ ]);
205
+ export const ratePlanRoomTypes = pgTable("rate_plan_room_types", {
206
+ id: typeId("rate_plan_room_types"),
207
+ ratePlanId: typeIdRef("rate_plan_id")
208
+ .notNull()
209
+ .references(() => ratePlans.id, { onDelete: "cascade" }),
210
+ roomTypeId: typeIdRef("room_type_id")
211
+ .notNull()
212
+ .references(() => roomTypes.id, { onDelete: "cascade" }),
213
+ productId: text("product_id"),
214
+ optionId: text("option_id"),
215
+ unitId: text("unit_id"),
216
+ active: boolean("active").notNull().default(true),
217
+ sortOrder: integer("sort_order").notNull().default(0),
218
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
219
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
220
+ }, (table) => [
221
+ index("idx_rate_plan_room_types_rate_plan").on(table.ratePlanId),
222
+ index("idx_rate_plan_room_types_room_type").on(table.roomTypeId),
223
+ index("idx_rate_plan_room_types_product").on(table.productId),
224
+ index("idx_rate_plan_room_types_option").on(table.optionId),
225
+ index("idx_rate_plan_room_types_unit").on(table.unitId),
226
+ uniqueIndex("uidx_rate_plan_room_types_pair").on(table.ratePlanId, table.roomTypeId),
227
+ ]);
228
+ export const stayRules = pgTable("stay_rules", {
229
+ id: typeId("stay_rules"),
230
+ propertyId: typeIdRef("property_id")
231
+ .notNull()
232
+ .references(() => properties.id, { onDelete: "cascade" }),
233
+ ratePlanId: typeIdRef("rate_plan_id").references(() => ratePlans.id, { onDelete: "cascade" }),
234
+ roomTypeId: typeIdRef("room_type_id").references(() => roomTypes.id, { onDelete: "cascade" }),
235
+ validFrom: date("valid_from"),
236
+ validTo: date("valid_to"),
237
+ minNights: integer("min_nights"),
238
+ maxNights: integer("max_nights"),
239
+ minAdvanceDays: integer("min_advance_days"),
240
+ maxAdvanceDays: integer("max_advance_days"),
241
+ closedToArrival: boolean("closed_to_arrival").notNull().default(false),
242
+ closedToDeparture: boolean("closed_to_departure").notNull().default(false),
243
+ arrivalWeekdays: jsonb("arrival_weekdays").$type(),
244
+ departureWeekdays: jsonb("departure_weekdays").$type(),
245
+ releaseDays: integer("release_days"),
246
+ active: boolean("active").notNull().default(true),
247
+ priority: integer("priority").notNull().default(0),
248
+ notes: text("notes"),
249
+ metadata: jsonb("metadata").$type(),
250
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
251
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
252
+ }, (table) => [
253
+ index("idx_stay_rules_property").on(table.propertyId),
254
+ index("idx_stay_rules_rate_plan").on(table.ratePlanId),
255
+ index("idx_stay_rules_room_type").on(table.roomTypeId),
256
+ index("idx_stay_rules_active").on(table.active),
257
+ ]);
258
+ export const roomInventory = pgTable("room_inventory", {
259
+ id: typeId("room_inventory"),
260
+ propertyId: typeIdRef("property_id")
261
+ .notNull()
262
+ .references(() => properties.id, { onDelete: "cascade" }),
263
+ roomTypeId: typeIdRef("room_type_id")
264
+ .notNull()
265
+ .references(() => roomTypes.id, { onDelete: "cascade" }),
266
+ date: date("date").notNull(),
267
+ totalUnits: integer("total_units").notNull().default(0),
268
+ availableUnits: integer("available_units").notNull().default(0),
269
+ heldUnits: integer("held_units").notNull().default(0),
270
+ soldUnits: integer("sold_units").notNull().default(0),
271
+ outOfOrderUnits: integer("out_of_order_units").notNull().default(0),
272
+ overbookLimit: integer("overbook_limit"),
273
+ stopSell: boolean("stop_sell").notNull().default(false),
274
+ notes: text("notes"),
275
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
276
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
277
+ }, (table) => [
278
+ index("idx_room_inventory_property").on(table.propertyId),
279
+ index("idx_room_inventory_room_type").on(table.roomTypeId),
280
+ index("idx_room_inventory_date").on(table.date),
281
+ uniqueIndex("uidx_room_inventory_room_type_date").on(table.roomTypeId, table.date),
282
+ ]);
283
+ export const ratePlanInventoryOverrides = pgTable("rate_plan_inventory_overrides", {
284
+ id: typeId("rate_plan_inventory_overrides"),
285
+ ratePlanId: typeIdRef("rate_plan_id")
286
+ .notNull()
287
+ .references(() => ratePlans.id, { onDelete: "cascade" }),
288
+ roomTypeId: typeIdRef("room_type_id")
289
+ .notNull()
290
+ .references(() => roomTypes.id, { onDelete: "cascade" }),
291
+ date: date("date").notNull(),
292
+ stopSell: boolean("stop_sell").notNull().default(false),
293
+ closedToArrival: boolean("closed_to_arrival").notNull().default(false),
294
+ closedToDeparture: boolean("closed_to_departure").notNull().default(false),
295
+ minNightsOverride: integer("min_nights_override"),
296
+ maxNightsOverride: integer("max_nights_override"),
297
+ notes: text("notes"),
298
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
299
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
300
+ }, (table) => [
301
+ index("idx_rate_plan_inventory_overrides_rate_plan").on(table.ratePlanId),
302
+ index("idx_rate_plan_inventory_overrides_room_type").on(table.roomTypeId),
303
+ index("idx_rate_plan_inventory_overrides_date").on(table.date),
304
+ uniqueIndex("uidx_rate_plan_inventory_overrides_unique").on(table.ratePlanId, table.roomTypeId, table.date),
305
+ ]);
306
+ export const stayBookingItems = pgTable("stay_booking_items", {
307
+ id: typeId("stay_booking_items"),
308
+ bookingItemId: typeIdRef("booking_item_id")
309
+ .notNull()
310
+ .references(() => bookingItems.id, { onDelete: "cascade" }),
311
+ propertyId: typeIdRef("property_id")
312
+ .notNull()
313
+ .references(() => properties.id, { onDelete: "cascade" }),
314
+ roomTypeId: typeIdRef("room_type_id")
315
+ .notNull()
316
+ .references(() => roomTypes.id, { onDelete: "cascade" }),
317
+ roomUnitId: typeIdRef("room_unit_id").references(() => roomUnits.id, { onDelete: "set null" }),
318
+ ratePlanId: typeIdRef("rate_plan_id")
319
+ .notNull()
320
+ .references(() => ratePlans.id, { onDelete: "cascade" }),
321
+ checkInDate: date("check_in_date").notNull(),
322
+ checkOutDate: date("check_out_date").notNull(),
323
+ nightCount: integer("night_count").notNull().default(1),
324
+ roomCount: integer("room_count").notNull().default(1),
325
+ adults: integer("adults").notNull().default(1),
326
+ children: integer("children").notNull().default(0),
327
+ infants: integer("infants").notNull().default(0),
328
+ mealPlanId: typeIdRef("meal_plan_id").references(() => mealPlans.id, { onDelete: "set null" }),
329
+ confirmationCode: text("confirmation_code"),
330
+ voucherCode: text("voucher_code"),
331
+ status: stayBookingItemStatusEnum("status").notNull().default("reserved"),
332
+ notes: text("notes"),
333
+ metadata: jsonb("metadata").$type(),
334
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
335
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
336
+ }, (table) => [
337
+ index("idx_stay_booking_items_booking_item").on(table.bookingItemId),
338
+ index("idx_stay_booking_items_property").on(table.propertyId),
339
+ index("idx_stay_booking_items_room_type").on(table.roomTypeId),
340
+ index("idx_stay_booking_items_room_unit").on(table.roomUnitId),
341
+ index("idx_stay_booking_items_rate_plan").on(table.ratePlanId),
342
+ uniqueIndex("uidx_stay_booking_items_booking_item").on(table.bookingItemId),
343
+ ]);
344
+ export const stayDailyRates = pgTable("stay_daily_rates", {
345
+ id: typeId("stay_daily_rates"),
346
+ stayBookingItemId: typeIdRef("stay_booking_item_id")
347
+ .notNull()
348
+ .references(() => stayBookingItems.id, { onDelete: "cascade" }),
349
+ date: date("date").notNull(),
350
+ sellCurrency: text("sell_currency").notNull(),
351
+ sellAmountCents: integer("sell_amount_cents"),
352
+ costCurrency: text("cost_currency"),
353
+ costAmountCents: integer("cost_amount_cents"),
354
+ taxAmountCents: integer("tax_amount_cents"),
355
+ feeAmountCents: integer("fee_amount_cents"),
356
+ commissionAmountCents: integer("commission_amount_cents"),
357
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
358
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
359
+ }, (table) => [
360
+ index("idx_stay_daily_rates_stay_booking_item").on(table.stayBookingItemId),
361
+ index("idx_stay_daily_rates_date").on(table.date),
362
+ uniqueIndex("uidx_stay_daily_rates_item_date").on(table.stayBookingItemId, table.date),
363
+ ]);
364
+ export const roomTypeRates = pgTable("room_type_rates", {
365
+ id: typeId("room_type_rates"),
366
+ ratePlanId: typeIdRef("rate_plan_id")
367
+ .notNull()
368
+ .references(() => ratePlans.id, { onDelete: "cascade" }),
369
+ roomTypeId: typeIdRef("room_type_id")
370
+ .notNull()
371
+ .references(() => roomTypes.id, { onDelete: "cascade" }),
372
+ priceScheduleId: text("price_schedule_id"),
373
+ currencyCode: char("currency_code", { length: 3 }).notNull(),
374
+ baseAmountCents: integer("base_amount_cents"),
375
+ extraAdultAmountCents: integer("extra_adult_amount_cents"),
376
+ extraChildAmountCents: integer("extra_child_amount_cents"),
377
+ extraInfantAmountCents: integer("extra_infant_amount_cents"),
378
+ active: boolean("active").notNull().default(true),
379
+ notes: text("notes"),
380
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
381
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
382
+ }, (table) => [
383
+ index("idx_room_type_rates_rate_plan").on(table.ratePlanId),
384
+ index("idx_room_type_rates_room_type").on(table.roomTypeId),
385
+ index("idx_room_type_rates_price_schedule").on(table.priceScheduleId),
386
+ index("idx_room_type_rates_active").on(table.active),
387
+ uniqueIndex("uidx_room_type_rates_plan_room_schedule").on(table.ratePlanId, table.roomTypeId, table.priceScheduleId),
388
+ ]);
389
+ export const roomBlocks = pgTable("room_blocks", {
390
+ id: typeId("room_blocks"),
391
+ propertyId: typeIdRef("property_id")
392
+ .notNull()
393
+ .references(() => properties.id, { onDelete: "cascade" }),
394
+ roomTypeId: typeIdRef("room_type_id").references(() => roomTypes.id, { onDelete: "set null" }),
395
+ roomUnitId: typeIdRef("room_unit_id").references(() => roomUnits.id, { onDelete: "set null" }),
396
+ startsOn: date("starts_on").notNull(),
397
+ endsOn: date("ends_on").notNull(),
398
+ status: hospitalityRoomBlockStatusEnum("status").notNull().default("draft"),
399
+ blockReason: text("block_reason"),
400
+ quantity: integer("quantity").notNull().default(1),
401
+ releaseAt: timestamp("release_at", { withTimezone: true }),
402
+ notes: text("notes"),
403
+ metadata: jsonb("metadata").$type(),
404
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
405
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
406
+ }, (table) => [
407
+ index("idx_room_blocks_property").on(table.propertyId),
408
+ index("idx_room_blocks_room_type").on(table.roomTypeId),
409
+ index("idx_room_blocks_room_unit").on(table.roomUnitId),
410
+ index("idx_room_blocks_status").on(table.status),
411
+ index("idx_room_blocks_dates").on(table.startsOn, table.endsOn),
412
+ ]);
413
+ export const roomUnitStatusEvents = pgTable("room_unit_status_events", {
414
+ id: typeId("room_unit_status_events"),
415
+ roomUnitId: typeIdRef("room_unit_id")
416
+ .notNull()
417
+ .references(() => roomUnits.id, { onDelete: "cascade" }),
418
+ statusCode: text("status_code").notNull(),
419
+ housekeepingStatus: text("housekeeping_status"),
420
+ effectiveFrom: timestamp("effective_from", { withTimezone: true }).notNull().defaultNow(),
421
+ effectiveTo: timestamp("effective_to", { withTimezone: true }),
422
+ notes: text("notes"),
423
+ metadata: jsonb("metadata").$type(),
424
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
425
+ }, (table) => [
426
+ index("idx_room_unit_status_events_room_unit").on(table.roomUnitId),
427
+ index("idx_room_unit_status_events_status").on(table.statusCode),
428
+ index("idx_room_unit_status_events_effective_from").on(table.effectiveFrom),
429
+ ]);
430
+ export const maintenanceBlocks = pgTable("maintenance_blocks", {
431
+ id: typeId("maintenance_blocks"),
432
+ propertyId: typeIdRef("property_id")
433
+ .notNull()
434
+ .references(() => properties.id, { onDelete: "cascade" }),
435
+ roomTypeId: typeIdRef("room_type_id").references(() => roomTypes.id, { onDelete: "set null" }),
436
+ roomUnitId: typeIdRef("room_unit_id").references(() => roomUnits.id, { onDelete: "set null" }),
437
+ startsOn: date("starts_on").notNull(),
438
+ endsOn: date("ends_on").notNull(),
439
+ status: hospitalityMaintenanceBlockStatusEnum("status").notNull().default("open"),
440
+ reason: text("reason"),
441
+ notes: text("notes"),
442
+ metadata: jsonb("metadata").$type(),
443
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
444
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
445
+ }, (table) => [
446
+ index("idx_maintenance_blocks_property").on(table.propertyId),
447
+ index("idx_maintenance_blocks_room_type").on(table.roomTypeId),
448
+ index("idx_maintenance_blocks_room_unit").on(table.roomUnitId),
449
+ index("idx_maintenance_blocks_status").on(table.status),
450
+ index("idx_maintenance_blocks_dates").on(table.startsOn, table.endsOn),
451
+ ]);
452
+ export const housekeepingTasks = pgTable("housekeeping_tasks", {
453
+ id: typeId("housekeeping_tasks"),
454
+ propertyId: typeIdRef("property_id")
455
+ .notNull()
456
+ .references(() => properties.id, { onDelete: "cascade" }),
457
+ roomUnitId: typeIdRef("room_unit_id")
458
+ .notNull()
459
+ .references(() => roomUnits.id, { onDelete: "cascade" }),
460
+ stayBookingItemId: typeIdRef("stay_booking_item_id").references(() => stayBookingItems.id, {
461
+ onDelete: "set null",
462
+ }),
463
+ taskType: text("task_type").notNull(),
464
+ status: hospitalityHousekeepingTaskStatusEnum("status").notNull().default("open"),
465
+ priority: integer("priority").notNull().default(0),
466
+ dueAt: timestamp("due_at", { withTimezone: true }),
467
+ startedAt: timestamp("started_at", { withTimezone: true }),
468
+ completedAt: timestamp("completed_at", { withTimezone: true }),
469
+ assignedTo: text("assigned_to"),
470
+ notes: text("notes"),
471
+ metadata: jsonb("metadata").$type(),
472
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
473
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
474
+ }, (table) => [
475
+ index("idx_housekeeping_tasks_property").on(table.propertyId),
476
+ index("idx_housekeeping_tasks_room_unit").on(table.roomUnitId),
477
+ index("idx_housekeeping_tasks_stay_booking_item").on(table.stayBookingItemId),
478
+ index("idx_housekeeping_tasks_status").on(table.status),
479
+ index("idx_housekeeping_tasks_due_at").on(table.dueAt),
480
+ ]);
481
+ export const stayOperations = pgTable("stay_operations", {
482
+ id: typeId("stay_operations"),
483
+ stayBookingItemId: typeIdRef("stay_booking_item_id")
484
+ .notNull()
485
+ .references(() => stayBookingItems.id, { onDelete: "cascade" }),
486
+ propertyId: typeIdRef("property_id")
487
+ .notNull()
488
+ .references(() => properties.id, { onDelete: "cascade" }),
489
+ roomUnitId: typeIdRef("room_unit_id").references(() => roomUnits.id, { onDelete: "set null" }),
490
+ operationStatus: stayOperationStatusEnum("operation_status").notNull().default("reserved"),
491
+ expectedArrivalAt: timestamp("expected_arrival_at", { withTimezone: true }),
492
+ expectedDepartureAt: timestamp("expected_departure_at", { withTimezone: true }),
493
+ checkedInAt: timestamp("checked_in_at", { withTimezone: true }),
494
+ checkedOutAt: timestamp("checked_out_at", { withTimezone: true }),
495
+ noShowRecordedAt: timestamp("no_show_recorded_at", { withTimezone: true }),
496
+ notes: text("notes"),
497
+ metadata: jsonb("metadata").$type(),
498
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
499
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
500
+ }, (table) => [
501
+ uniqueIndex("uidx_stay_operations_stay_booking_item").on(table.stayBookingItemId),
502
+ index("idx_stay_operations_property").on(table.propertyId),
503
+ index("idx_stay_operations_room_unit").on(table.roomUnitId),
504
+ index("idx_stay_operations_status").on(table.operationStatus),
505
+ ]);
506
+ export const stayCheckpoints = pgTable("stay_checkpoints", {
507
+ id: typeId("stay_checkpoints"),
508
+ stayOperationId: typeIdRef("stay_operation_id")
509
+ .notNull()
510
+ .references(() => stayOperations.id, { onDelete: "cascade" }),
511
+ checkpointType: stayCheckpointTypeEnum("checkpoint_type").notNull().default("note"),
512
+ occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull().defaultNow(),
513
+ roomUnitId: typeIdRef("room_unit_id").references(() => roomUnits.id, { onDelete: "set null" }),
514
+ notes: text("notes"),
515
+ metadata: jsonb("metadata").$type(),
516
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
517
+ }, (table) => [
518
+ index("idx_stay_checkpoints_operation").on(table.stayOperationId),
519
+ index("idx_stay_checkpoints_type").on(table.checkpointType),
520
+ index("idx_stay_checkpoints_occurred_at").on(table.occurredAt),
521
+ ]);
522
+ export const stayServicePosts = pgTable("stay_service_posts", {
523
+ id: typeId("stay_service_posts"),
524
+ stayOperationId: typeIdRef("stay_operation_id")
525
+ .notNull()
526
+ .references(() => stayOperations.id, { onDelete: "cascade" }),
527
+ bookingItemId: typeIdRef("booking_item_id").references(() => bookingItems.id, {
528
+ onDelete: "set null",
529
+ }),
530
+ serviceDate: date("service_date").notNull(),
531
+ kind: stayServicePostKindEnum("kind").notNull().default("other"),
532
+ description: text("description").notNull(),
533
+ quantity: integer("quantity").notNull().default(1),
534
+ currencyCode: text("currency_code").notNull(),
535
+ sellAmountCents: integer("sell_amount_cents").notNull().default(0),
536
+ costAmountCents: integer("cost_amount_cents"),
537
+ notes: text("notes"),
538
+ metadata: jsonb("metadata").$type(),
539
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
540
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
541
+ }, (table) => [
542
+ index("idx_stay_service_posts_operation").on(table.stayOperationId),
543
+ index("idx_stay_service_posts_booking_item").on(table.bookingItemId),
544
+ index("idx_stay_service_posts_service_date").on(table.serviceDate),
545
+ index("idx_stay_service_posts_kind").on(table.kind),
546
+ ]);
547
+ export const stayFolios = pgTable("stay_folios", {
548
+ id: typeId("stay_folios"),
549
+ stayOperationId: typeIdRef("stay_operation_id")
550
+ .notNull()
551
+ .references(() => stayOperations.id, { onDelete: "cascade" }),
552
+ currencyCode: text("currency_code").notNull(),
553
+ status: stayFolioStatusEnum("status").notNull().default("open"),
554
+ openedAt: timestamp("opened_at", { withTimezone: true }).notNull().defaultNow(),
555
+ closedAt: timestamp("closed_at", { withTimezone: true }),
556
+ notes: text("notes"),
557
+ metadata: jsonb("metadata").$type(),
558
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
559
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
560
+ }, (table) => [
561
+ index("idx_stay_folios_operation").on(table.stayOperationId),
562
+ index("idx_stay_folios_status").on(table.status),
563
+ ]);
564
+ export const stayFolioLines = pgTable("stay_folio_lines", {
565
+ id: typeId("stay_folio_lines"),
566
+ stayFolioId: typeIdRef("stay_folio_id")
567
+ .notNull()
568
+ .references(() => stayFolios.id, { onDelete: "cascade" }),
569
+ servicePostId: typeIdRef("service_post_id").references(() => stayServicePosts.id, {
570
+ onDelete: "set null",
571
+ }),
572
+ postedAt: timestamp("posted_at", { withTimezone: true }).notNull().defaultNow(),
573
+ lineType: text("line_type").notNull(),
574
+ description: text("description").notNull(),
575
+ quantity: integer("quantity").notNull().default(1),
576
+ amountCents: integer("amount_cents").notNull().default(0),
577
+ taxAmountCents: integer("tax_amount_cents"),
578
+ feeAmountCents: integer("fee_amount_cents"),
579
+ notes: text("notes"),
580
+ metadata: jsonb("metadata").$type(),
581
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
582
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
583
+ }, (table) => [
584
+ index("idx_stay_folio_lines_folio").on(table.stayFolioId),
585
+ index("idx_stay_folio_lines_service_post").on(table.servicePostId),
586
+ index("idx_stay_folio_lines_posted_at").on(table.postedAt),
587
+ ]);
588
+ export const roomTypesRelations = relations(roomTypes, ({ one, many }) => ({
589
+ property: one(properties, { fields: [roomTypes.propertyId], references: [properties.id] }),
590
+ bedConfigs: many(roomTypeBedConfigs),
591
+ roomUnits: many(roomUnits),
592
+ ratePlanRoomTypes: many(ratePlanRoomTypes),
593
+ roomTypeRates: many(roomTypeRates),
594
+ stayRules: many(stayRules),
595
+ inventory: many(roomInventory),
596
+ inventoryOverrides: many(ratePlanInventoryOverrides),
597
+ stayBookingItems: many(stayBookingItems),
598
+ }));
599
+ export const roomTypeBedConfigsRelations = relations(roomTypeBedConfigs, ({ one }) => ({
600
+ roomType: one(roomTypes, {
601
+ fields: [roomTypeBedConfigs.roomTypeId],
602
+ references: [roomTypes.id],
603
+ }),
604
+ }));
605
+ export const roomUnitsRelations = relations(roomUnits, ({ one, many }) => ({
606
+ property: one(properties, { fields: [roomUnits.propertyId], references: [properties.id] }),
607
+ roomType: one(roomTypes, { fields: [roomUnits.roomTypeId], references: [roomTypes.id] }),
608
+ stayBookingItems: many(stayBookingItems),
609
+ roomBlocks: many(roomBlocks),
610
+ statusEvents: many(roomUnitStatusEvents),
611
+ maintenanceBlocks: many(maintenanceBlocks),
612
+ housekeepingTasks: many(housekeepingTasks),
613
+ stayOperations: many(stayOperations),
614
+ stayCheckpoints: many(stayCheckpoints),
615
+ }));
616
+ export const mealPlansRelations = relations(mealPlans, ({ one, many }) => ({
617
+ property: one(properties, { fields: [mealPlans.propertyId], references: [properties.id] }),
618
+ ratePlans: many(ratePlans),
619
+ stayBookingItems: many(stayBookingItems),
620
+ }));
621
+ export const ratePlansRelations = relations(ratePlans, ({ one, many }) => ({
622
+ property: one(properties, { fields: [ratePlans.propertyId], references: [properties.id] }),
623
+ mealPlan: one(mealPlans, { fields: [ratePlans.mealPlanId], references: [mealPlans.id] }),
624
+ roomTypes: many(ratePlanRoomTypes),
625
+ roomTypeRates: many(roomTypeRates),
626
+ stayRules: many(stayRules),
627
+ inventoryOverrides: many(ratePlanInventoryOverrides),
628
+ stayBookingItems: many(stayBookingItems),
629
+ }));
630
+ export const ratePlanRoomTypesRelations = relations(ratePlanRoomTypes, ({ one }) => ({
631
+ ratePlan: one(ratePlans, {
632
+ fields: [ratePlanRoomTypes.ratePlanId],
633
+ references: [ratePlans.id],
634
+ }),
635
+ roomType: one(roomTypes, {
636
+ fields: [ratePlanRoomTypes.roomTypeId],
637
+ references: [roomTypes.id],
638
+ }),
639
+ }));
640
+ export const stayRulesRelations = relations(stayRules, ({ one }) => ({
641
+ property: one(properties, { fields: [stayRules.propertyId], references: [properties.id] }),
642
+ ratePlan: one(ratePlans, { fields: [stayRules.ratePlanId], references: [ratePlans.id] }),
643
+ roomType: one(roomTypes, { fields: [stayRules.roomTypeId], references: [roomTypes.id] }),
644
+ }));
645
+ export const roomInventoryRelations = relations(roomInventory, ({ one }) => ({
646
+ property: one(properties, { fields: [roomInventory.propertyId], references: [properties.id] }),
647
+ roomType: one(roomTypes, { fields: [roomInventory.roomTypeId], references: [roomTypes.id] }),
648
+ }));
649
+ export const ratePlanInventoryOverridesRelations = relations(ratePlanInventoryOverrides, ({ one }) => ({
650
+ ratePlan: one(ratePlans, {
651
+ fields: [ratePlanInventoryOverrides.ratePlanId],
652
+ references: [ratePlans.id],
653
+ }),
654
+ roomType: one(roomTypes, {
655
+ fields: [ratePlanInventoryOverrides.roomTypeId],
656
+ references: [roomTypes.id],
657
+ }),
658
+ }));
659
+ export const roomTypeRatesRelations = relations(roomTypeRates, ({ one }) => ({
660
+ ratePlan: one(ratePlans, {
661
+ fields: [roomTypeRates.ratePlanId],
662
+ references: [ratePlans.id],
663
+ }),
664
+ roomType: one(roomTypes, {
665
+ fields: [roomTypeRates.roomTypeId],
666
+ references: [roomTypes.id],
667
+ }),
668
+ }));
669
+ export const stayBookingItemsRelations = relations(stayBookingItems, ({ one, many }) => ({
670
+ bookingItem: one(bookingItems, {
671
+ fields: [stayBookingItems.bookingItemId],
672
+ references: [bookingItems.id],
673
+ }),
674
+ property: one(properties, {
675
+ fields: [stayBookingItems.propertyId],
676
+ references: [properties.id],
677
+ }),
678
+ roomType: one(roomTypes, { fields: [stayBookingItems.roomTypeId], references: [roomTypes.id] }),
679
+ roomUnit: one(roomUnits, { fields: [stayBookingItems.roomUnitId], references: [roomUnits.id] }),
680
+ ratePlan: one(ratePlans, { fields: [stayBookingItems.ratePlanId], references: [ratePlans.id] }),
681
+ mealPlan: one(mealPlans, { fields: [stayBookingItems.mealPlanId], references: [mealPlans.id] }),
682
+ dailyRates: many(stayDailyRates),
683
+ housekeepingTasks: many(housekeepingTasks),
684
+ operations: many(stayOperations),
685
+ }));
686
+ export const stayDailyRatesRelations = relations(stayDailyRates, ({ one }) => ({
687
+ stayBookingItem: one(stayBookingItems, {
688
+ fields: [stayDailyRates.stayBookingItemId],
689
+ references: [stayBookingItems.id],
690
+ }),
691
+ }));
692
+ export const roomBlocksRelations = relations(roomBlocks, ({ one }) => ({
693
+ property: one(properties, { fields: [roomBlocks.propertyId], references: [properties.id] }),
694
+ roomType: one(roomTypes, { fields: [roomBlocks.roomTypeId], references: [roomTypes.id] }),
695
+ roomUnit: one(roomUnits, { fields: [roomBlocks.roomUnitId], references: [roomUnits.id] }),
696
+ }));
697
+ export const roomUnitStatusEventsRelations = relations(roomUnitStatusEvents, ({ one }) => ({
698
+ roomUnit: one(roomUnits, {
699
+ fields: [roomUnitStatusEvents.roomUnitId],
700
+ references: [roomUnits.id],
701
+ }),
702
+ }));
703
+ export const maintenanceBlocksRelations = relations(maintenanceBlocks, ({ one }) => ({
704
+ property: one(properties, {
705
+ fields: [maintenanceBlocks.propertyId],
706
+ references: [properties.id],
707
+ }),
708
+ roomType: one(roomTypes, {
709
+ fields: [maintenanceBlocks.roomTypeId],
710
+ references: [roomTypes.id],
711
+ }),
712
+ roomUnit: one(roomUnits, {
713
+ fields: [maintenanceBlocks.roomUnitId],
714
+ references: [roomUnits.id],
715
+ }),
716
+ }));
717
+ export const housekeepingTasksRelations = relations(housekeepingTasks, ({ one }) => ({
718
+ property: one(properties, {
719
+ fields: [housekeepingTasks.propertyId],
720
+ references: [properties.id],
721
+ }),
722
+ roomUnit: one(roomUnits, {
723
+ fields: [housekeepingTasks.roomUnitId],
724
+ references: [roomUnits.id],
725
+ }),
726
+ stayBookingItem: one(stayBookingItems, {
727
+ fields: [housekeepingTasks.stayBookingItemId],
728
+ references: [stayBookingItems.id],
729
+ }),
730
+ }));
731
+ export const stayOperationsRelations = relations(stayOperations, ({ one, many }) => ({
732
+ stayBookingItem: one(stayBookingItems, {
733
+ fields: [stayOperations.stayBookingItemId],
734
+ references: [stayBookingItems.id],
735
+ }),
736
+ property: one(properties, {
737
+ fields: [stayOperations.propertyId],
738
+ references: [properties.id],
739
+ }),
740
+ roomUnit: one(roomUnits, { fields: [stayOperations.roomUnitId], references: [roomUnits.id] }),
741
+ checkpoints: many(stayCheckpoints),
742
+ servicePosts: many(stayServicePosts),
743
+ folios: many(stayFolios),
744
+ }));
745
+ export const stayCheckpointsRelations = relations(stayCheckpoints, ({ one }) => ({
746
+ stayOperation: one(stayOperations, {
747
+ fields: [stayCheckpoints.stayOperationId],
748
+ references: [stayOperations.id],
749
+ }),
750
+ roomUnit: one(roomUnits, { fields: [stayCheckpoints.roomUnitId], references: [roomUnits.id] }),
751
+ }));
752
+ export const stayServicePostsRelations = relations(stayServicePosts, ({ one, many }) => ({
753
+ stayOperation: one(stayOperations, {
754
+ fields: [stayServicePosts.stayOperationId],
755
+ references: [stayOperations.id],
756
+ }),
757
+ bookingItem: one(bookingItems, {
758
+ fields: [stayServicePosts.bookingItemId],
759
+ references: [bookingItems.id],
760
+ }),
761
+ folioLines: many(stayFolioLines),
762
+ }));
763
+ export const stayFoliosRelations = relations(stayFolios, ({ one, many }) => ({
764
+ stayOperation: one(stayOperations, {
765
+ fields: [stayFolios.stayOperationId],
766
+ references: [stayOperations.id],
767
+ }),
768
+ lines: many(stayFolioLines),
769
+ }));
770
+ export const stayFolioLinesRelations = relations(stayFolioLines, ({ one }) => ({
771
+ stayFolio: one(stayFolios, {
772
+ fields: [stayFolioLines.stayFolioId],
773
+ references: [stayFolios.id],
774
+ }),
775
+ servicePost: one(stayServicePosts, {
776
+ fields: [stayFolioLines.servicePostId],
777
+ references: [stayServicePosts.id],
778
+ }),
779
+ }));