@voyantjs/bookings 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.
Files changed (42) hide show
  1. package/LICENSE +109 -0
  2. package/README.md +42 -0
  3. package/dist/availability-ref.d.ts +418 -0
  4. package/dist/availability-ref.d.ts.map +1 -0
  5. package/dist/availability-ref.js +28 -0
  6. package/dist/extensions/suppliers.d.ts +3 -0
  7. package/dist/extensions/suppliers.d.ts.map +1 -0
  8. package/dist/extensions/suppliers.js +103 -0
  9. package/dist/index.d.ts +20 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +25 -0
  12. package/dist/pii.d.ts +29 -0
  13. package/dist/pii.d.ts.map +1 -0
  14. package/dist/pii.js +131 -0
  15. package/dist/products-ref.d.ts +1043 -0
  16. package/dist/products-ref.d.ts.map +1 -0
  17. package/dist/products-ref.js +76 -0
  18. package/dist/routes.d.ts +2171 -0
  19. package/dist/routes.d.ts.map +1 -0
  20. package/dist/routes.js +659 -0
  21. package/dist/schema/travel-details.d.ts +179 -0
  22. package/dist/schema/travel-details.d.ts.map +1 -0
  23. package/dist/schema/travel-details.js +46 -0
  24. package/dist/schema.d.ts +3180 -0
  25. package/dist/schema.d.ts.map +1 -0
  26. package/dist/schema.js +509 -0
  27. package/dist/service.d.ts +5000 -0
  28. package/dist/service.d.ts.map +1 -0
  29. package/dist/service.js +2016 -0
  30. package/dist/tasks/expire-stale-holds.d.ts +12 -0
  31. package/dist/tasks/expire-stale-holds.d.ts.map +1 -0
  32. package/dist/tasks/expire-stale-holds.js +7 -0
  33. package/dist/tasks/index.d.ts +2 -0
  34. package/dist/tasks/index.d.ts.map +1 -0
  35. package/dist/tasks/index.js +1 -0
  36. package/dist/transactions-ref.d.ts +2223 -0
  37. package/dist/transactions-ref.d.ts.map +1 -0
  38. package/dist/transactions-ref.js +147 -0
  39. package/dist/validation.d.ts +643 -0
  40. package/dist/validation.d.ts.map +1 -0
  41. package/dist/validation.js +355 -0
  42. package/package.json +68 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
package/dist/schema.js ADDED
@@ -0,0 +1,509 @@
1
+ import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
2
+ import { relations } from "drizzle-orm";
3
+ import { boolean, date, index, integer, jsonb, pgEnum, pgTable, text, timestamp, } from "drizzle-orm/pg-core";
4
+ import { availabilitySlotsRef } from "./availability-ref.js";
5
+ export const bookingStatusEnum = pgEnum("booking_status", [
6
+ "draft",
7
+ "on_hold",
8
+ "confirmed",
9
+ "in_progress",
10
+ "completed",
11
+ "expired",
12
+ "cancelled",
13
+ ]);
14
+ export const supplierConfirmationStatusEnum = pgEnum("supplier_confirmation_status", [
15
+ "pending",
16
+ "confirmed",
17
+ "rejected",
18
+ "cancelled",
19
+ ]);
20
+ export const bookingActivityTypeEnum = pgEnum("booking_activity_type", [
21
+ "booking_created",
22
+ "booking_reserved",
23
+ "booking_converted",
24
+ "booking_confirmed",
25
+ "hold_extended",
26
+ "hold_expired",
27
+ "status_change",
28
+ "item_update",
29
+ "allocation_released",
30
+ "fulfillment_issued",
31
+ "fulfillment_updated",
32
+ "redemption_recorded",
33
+ "supplier_update",
34
+ "passenger_update",
35
+ "note_added",
36
+ ]);
37
+ export const bookingDocumentTypeEnum = pgEnum("booking_document_type", [
38
+ "visa",
39
+ "insurance",
40
+ "health",
41
+ "passport_copy",
42
+ "other",
43
+ ]);
44
+ export const bookingSourceTypeEnum = pgEnum("booking_source_type", [
45
+ "direct",
46
+ "manual",
47
+ "affiliate",
48
+ "ota",
49
+ "reseller",
50
+ "api_partner",
51
+ "internal",
52
+ ]);
53
+ export const bookingParticipantTypeEnum = pgEnum("booking_participant_type", [
54
+ "traveler",
55
+ "booker",
56
+ "contact",
57
+ "occupant",
58
+ "staff",
59
+ "other",
60
+ ]);
61
+ export const bookingTravelerCategoryEnum = pgEnum("booking_traveler_category", [
62
+ "adult",
63
+ "child",
64
+ "infant",
65
+ "senior",
66
+ "other",
67
+ ]);
68
+ export const bookingItemTypeEnum = pgEnum("booking_item_type", [
69
+ "unit",
70
+ "extra",
71
+ "service",
72
+ "fee",
73
+ "tax",
74
+ "discount",
75
+ "adjustment",
76
+ "accommodation",
77
+ "transport",
78
+ "other",
79
+ ]);
80
+ export const bookingItemStatusEnum = pgEnum("booking_item_status", [
81
+ "draft",
82
+ "on_hold",
83
+ "confirmed",
84
+ "cancelled",
85
+ "expired",
86
+ "fulfilled",
87
+ ]);
88
+ export const bookingAllocationTypeEnum = pgEnum("booking_allocation_type", [
89
+ "unit",
90
+ "pickup",
91
+ "resource",
92
+ ]);
93
+ export const bookingAllocationStatusEnum = pgEnum("booking_allocation_status", [
94
+ "held",
95
+ "confirmed",
96
+ "released",
97
+ "expired",
98
+ "cancelled",
99
+ "fulfilled",
100
+ ]);
101
+ export const bookingFulfillmentTypeEnum = pgEnum("booking_fulfillment_type", [
102
+ "voucher",
103
+ "ticket",
104
+ "pdf",
105
+ "qr_code",
106
+ "barcode",
107
+ "mobile",
108
+ "other",
109
+ ]);
110
+ export const bookingFulfillmentDeliveryChannelEnum = pgEnum("booking_fulfillment_delivery_channel", ["download", "email", "api", "wallet", "other"]);
111
+ export const bookingFulfillmentStatusEnum = pgEnum("booking_fulfillment_status", [
112
+ "pending",
113
+ "issued",
114
+ "reissued",
115
+ "revoked",
116
+ "failed",
117
+ ]);
118
+ export const bookingRedemptionMethodEnum = pgEnum("booking_redemption_method", [
119
+ "manual",
120
+ "scan",
121
+ "api",
122
+ "other",
123
+ ]);
124
+ export const bookingItemParticipantRoleEnum = pgEnum("booking_item_participant_role", [
125
+ "traveler",
126
+ "occupant",
127
+ "primary_contact",
128
+ "service_assignee",
129
+ "beneficiary",
130
+ "other",
131
+ ]);
132
+ export const bookingPiiAccessActionEnum = pgEnum("booking_pii_access_action", [
133
+ "read",
134
+ "update",
135
+ "delete",
136
+ ]);
137
+ export const bookingPiiAccessOutcomeEnum = pgEnum("booking_pii_access_outcome", [
138
+ "allowed",
139
+ "denied",
140
+ ]);
141
+ // ---------- bookings ----------
142
+ export const bookings = pgTable("bookings", {
143
+ id: typeId("bookings"),
144
+ bookingNumber: text("booking_number").notNull().unique(),
145
+ status: bookingStatusEnum("status").notNull().default("draft"),
146
+ // Client link
147
+ personId: text("person_id"),
148
+ organizationId: text("organization_id"),
149
+ sourceType: bookingSourceTypeEnum("source_type").notNull().default("manual"),
150
+ externalBookingRef: text("external_booking_ref"),
151
+ communicationLanguage: text("communication_language"),
152
+ // Financial
153
+ sellCurrency: text("sell_currency").notNull(),
154
+ baseCurrency: text("base_currency"),
155
+ sellAmountCents: integer("sell_amount_cents"),
156
+ baseSellAmountCents: integer("base_sell_amount_cents"),
157
+ costAmountCents: integer("cost_amount_cents"),
158
+ baseCostAmountCents: integer("base_cost_amount_cents"),
159
+ marginPercent: integer("margin_percent"),
160
+ // Trip details
161
+ startDate: date("start_date"),
162
+ endDate: date("end_date"),
163
+ pax: integer("pax"),
164
+ internalNotes: text("internal_notes"),
165
+ holdExpiresAt: timestamp("hold_expires_at", { withTimezone: true }),
166
+ confirmedAt: timestamp("confirmed_at", { withTimezone: true }),
167
+ expiredAt: timestamp("expired_at", { withTimezone: true }),
168
+ cancelledAt: timestamp("cancelled_at", { withTimezone: true }),
169
+ completedAt: timestamp("completed_at", { withTimezone: true }),
170
+ redeemedAt: timestamp("redeemed_at", { withTimezone: true }),
171
+ // Timestamps
172
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
173
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
174
+ }, (table) => [
175
+ index("idx_bookings_status").on(table.status),
176
+ index("idx_bookings_person").on(table.personId),
177
+ index("idx_bookings_organization").on(table.organizationId),
178
+ index("idx_bookings_source_type").on(table.sourceType),
179
+ index("idx_bookings_number").on(table.bookingNumber),
180
+ ]);
181
+ // ---------- booking_participants ----------
182
+ export const bookingParticipants = pgTable("booking_participants", {
183
+ id: typeId("booking_participants"),
184
+ bookingId: typeIdRef("booking_id")
185
+ .notNull()
186
+ .references(() => bookings.id, { onDelete: "cascade" }),
187
+ personId: text("person_id"),
188
+ participantType: bookingParticipantTypeEnum("participant_type").notNull().default("traveler"),
189
+ travelerCategory: bookingTravelerCategoryEnum("traveler_category"),
190
+ firstName: text("first_name").notNull(),
191
+ lastName: text("last_name").notNull(),
192
+ email: text("email"),
193
+ phone: text("phone"),
194
+ preferredLanguage: text("preferred_language"),
195
+ accessibilityNeeds: text("accessibility_needs"),
196
+ specialRequests: text("special_requests"),
197
+ isPrimary: boolean("is_primary").notNull().default(false),
198
+ notes: text("notes"),
199
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
200
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
201
+ }, (table) => [
202
+ index("idx_booking_participants_booking").on(table.bookingId),
203
+ index("idx_booking_participants_type").on(table.participantType),
204
+ index("idx_booking_participants_person").on(table.personId),
205
+ ]);
206
+ export const bookingPassengers = bookingParticipants;
207
+ // ---------- booking_pii_access_log ----------
208
+ export const bookingPiiAccessLog = pgTable("booking_pii_access_log", {
209
+ id: typeId("booking_pii_access_log"),
210
+ bookingId: text("booking_id"),
211
+ participantId: text("participant_id"),
212
+ actorId: text("actor_id"),
213
+ actorType: text("actor_type"),
214
+ callerType: text("caller_type"),
215
+ action: bookingPiiAccessActionEnum("action").notNull(),
216
+ outcome: bookingPiiAccessOutcomeEnum("outcome").notNull(),
217
+ reason: text("reason"),
218
+ metadata: jsonb("metadata").$type(),
219
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
220
+ }, (table) => [
221
+ index("idx_booking_pii_access_log_booking").on(table.bookingId),
222
+ index("idx_booking_pii_access_log_participant").on(table.participantId),
223
+ index("idx_booking_pii_access_log_actor").on(table.actorId),
224
+ index("idx_booking_pii_access_log_created_at").on(table.createdAt),
225
+ ]);
226
+ // ---------- booking_items ----------
227
+ export const bookingItems = pgTable("booking_items", {
228
+ id: typeId("booking_items"),
229
+ bookingId: typeIdRef("booking_id")
230
+ .notNull()
231
+ .references(() => bookings.id, { onDelete: "cascade" }),
232
+ title: text("title").notNull(),
233
+ description: text("description"),
234
+ itemType: bookingItemTypeEnum("item_type").notNull().default("unit"),
235
+ status: bookingItemStatusEnum("status").notNull().default("draft"),
236
+ serviceDate: date("service_date"),
237
+ startsAt: timestamp("starts_at", { withTimezone: true }),
238
+ endsAt: timestamp("ends_at", { withTimezone: true }),
239
+ quantity: integer("quantity").notNull().default(1),
240
+ sellCurrency: text("sell_currency").notNull(),
241
+ unitSellAmountCents: integer("unit_sell_amount_cents"),
242
+ totalSellAmountCents: integer("total_sell_amount_cents"),
243
+ costCurrency: text("cost_currency"),
244
+ unitCostAmountCents: integer("unit_cost_amount_cents"),
245
+ totalCostAmountCents: integer("total_cost_amount_cents"),
246
+ notes: text("notes"),
247
+ productId: text("product_id"),
248
+ optionId: text("option_id"),
249
+ optionUnitId: text("option_unit_id"),
250
+ pricingCategoryId: text("pricing_category_id"),
251
+ sourceSnapshotId: text("source_snapshot_id"),
252
+ sourceOfferId: text("source_offer_id"),
253
+ metadata: jsonb("metadata").$type(),
254
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
255
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
256
+ }, (table) => [
257
+ index("idx_booking_items_booking").on(table.bookingId),
258
+ index("idx_booking_items_status").on(table.status),
259
+ ]);
260
+ // ---------- booking_allocations ----------
261
+ export const bookingAllocations = pgTable("booking_allocations", {
262
+ id: typeId("booking_allocations"),
263
+ bookingId: typeIdRef("booking_id")
264
+ .notNull()
265
+ .references(() => bookings.id, { onDelete: "cascade" }),
266
+ bookingItemId: typeIdRef("booking_item_id")
267
+ .notNull()
268
+ .references(() => bookingItems.id, { onDelete: "cascade" }),
269
+ productId: text("product_id"),
270
+ optionId: text("option_id"),
271
+ optionUnitId: text("option_unit_id"),
272
+ pricingCategoryId: text("pricing_category_id"),
273
+ availabilitySlotId: typeIdRef("availability_slot_id").references(() => availabilitySlotsRef.id, {
274
+ onDelete: "set null",
275
+ }),
276
+ quantity: integer("quantity").notNull().default(1),
277
+ allocationType: bookingAllocationTypeEnum("allocation_type").notNull().default("unit"),
278
+ status: bookingAllocationStatusEnum("status").notNull().default("held"),
279
+ holdExpiresAt: timestamp("hold_expires_at", { withTimezone: true }),
280
+ confirmedAt: timestamp("confirmed_at", { withTimezone: true }),
281
+ releasedAt: timestamp("released_at", { withTimezone: true }),
282
+ metadata: jsonb("metadata").$type(),
283
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
284
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
285
+ }, (table) => [
286
+ index("idx_booking_allocations_booking").on(table.bookingId),
287
+ index("idx_booking_allocations_item").on(table.bookingItemId),
288
+ index("idx_booking_allocations_slot").on(table.availabilitySlotId),
289
+ index("idx_booking_allocations_status").on(table.status),
290
+ ]);
291
+ // ---------- booking_fulfillments ----------
292
+ export const bookingFulfillments = pgTable("booking_fulfillments", {
293
+ id: typeId("booking_fulfillments"),
294
+ bookingId: typeIdRef("booking_id")
295
+ .notNull()
296
+ .references(() => bookings.id, { onDelete: "cascade" }),
297
+ bookingItemId: typeIdRef("booking_item_id").references(() => bookingItems.id, {
298
+ onDelete: "set null",
299
+ }),
300
+ participantId: typeIdRef("participant_id").references(() => bookingParticipants.id, {
301
+ onDelete: "set null",
302
+ }),
303
+ fulfillmentType: bookingFulfillmentTypeEnum("fulfillment_type").notNull(),
304
+ deliveryChannel: bookingFulfillmentDeliveryChannelEnum("delivery_channel").notNull(),
305
+ status: bookingFulfillmentStatusEnum("status").notNull().default("pending"),
306
+ artifactUrl: text("artifact_url"),
307
+ payload: jsonb("payload").$type(),
308
+ issuedAt: timestamp("issued_at", { withTimezone: true }),
309
+ revokedAt: timestamp("revoked_at", { withTimezone: true }),
310
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
311
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
312
+ }, (table) => [
313
+ index("idx_booking_fulfillments_booking").on(table.bookingId),
314
+ index("idx_booking_fulfillments_item").on(table.bookingItemId),
315
+ index("idx_booking_fulfillments_participant").on(table.participantId),
316
+ index("idx_booking_fulfillments_status").on(table.status),
317
+ ]);
318
+ // ---------- booking_redemption_events ----------
319
+ export const bookingRedemptionEvents = pgTable("booking_redemption_events", {
320
+ id: typeId("booking_redemption_events"),
321
+ bookingId: typeIdRef("booking_id")
322
+ .notNull()
323
+ .references(() => bookings.id, { onDelete: "cascade" }),
324
+ bookingItemId: typeIdRef("booking_item_id").references(() => bookingItems.id, {
325
+ onDelete: "set null",
326
+ }),
327
+ participantId: typeIdRef("participant_id").references(() => bookingParticipants.id, {
328
+ onDelete: "set null",
329
+ }),
330
+ redeemedAt: timestamp("redeemed_at", { withTimezone: true }).notNull().defaultNow(),
331
+ redeemedBy: text("redeemed_by"),
332
+ location: text("location"),
333
+ method: bookingRedemptionMethodEnum("method").notNull().default("manual"),
334
+ metadata: jsonb("metadata").$type(),
335
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
336
+ }, (table) => [
337
+ index("idx_booking_redemption_events_booking").on(table.bookingId),
338
+ index("idx_booking_redemption_events_item").on(table.bookingItemId),
339
+ index("idx_booking_redemption_events_participant").on(table.participantId),
340
+ index("idx_booking_redemption_events_redeemed_at").on(table.redeemedAt),
341
+ ]);
342
+ // ---------- booking_item_participants ----------
343
+ export const bookingItemParticipants = pgTable("booking_item_participants", {
344
+ id: typeId("booking_item_participants"),
345
+ bookingItemId: typeIdRef("booking_item_id")
346
+ .notNull()
347
+ .references(() => bookingItems.id, { onDelete: "cascade" }),
348
+ participantId: typeIdRef("participant_id")
349
+ .notNull()
350
+ .references(() => bookingParticipants.id, { onDelete: "cascade" }),
351
+ role: bookingItemParticipantRoleEnum("role").notNull().default("traveler"),
352
+ isPrimary: boolean("is_primary").notNull().default(false),
353
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
354
+ }, (table) => [
355
+ index("idx_booking_item_participants_item").on(table.bookingItemId),
356
+ index("idx_booking_item_participants_participant").on(table.participantId),
357
+ ]);
358
+ // ---------- booking_supplier_statuses ----------
359
+ export const bookingSupplierStatuses = pgTable("booking_supplier_statuses", {
360
+ id: typeId("booking_supplier_statuses"),
361
+ bookingId: typeIdRef("booking_id")
362
+ .notNull()
363
+ .references(() => bookings.id, { onDelete: "cascade" }),
364
+ supplierServiceId: text("supplier_service_id"),
365
+ serviceName: text("service_name").notNull(),
366
+ status: supplierConfirmationStatusEnum("status").notNull().default("pending"),
367
+ supplierReference: text("supplier_reference"),
368
+ costCurrency: text("cost_currency").notNull(),
369
+ costAmountCents: integer("cost_amount_cents").notNull(),
370
+ notes: text("notes"),
371
+ confirmedAt: timestamp("confirmed_at", { withTimezone: true }),
372
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
373
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
374
+ }, (table) => [
375
+ index("idx_booking_supplier_statuses_booking").on(table.bookingId),
376
+ index("idx_booking_supplier_statuses_service").on(table.supplierServiceId),
377
+ ]);
378
+ // ---------- booking_activity_log ----------
379
+ export const bookingActivityLog = pgTable("booking_activity_log", {
380
+ id: typeId("booking_activity_log"),
381
+ bookingId: typeIdRef("booking_id")
382
+ .notNull()
383
+ .references(() => bookings.id, { onDelete: "cascade" }),
384
+ actorId: text("actor_id"),
385
+ activityType: bookingActivityTypeEnum("activity_type").notNull(),
386
+ description: text("description").notNull(),
387
+ metadata: jsonb("metadata").$type(),
388
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
389
+ }, (table) => [index("idx_booking_activity_log_booking").on(table.bookingId)]);
390
+ // ---------- booking_notes ----------
391
+ export const bookingNotes = pgTable("booking_notes", {
392
+ id: typeId("booking_notes"),
393
+ bookingId: typeIdRef("booking_id")
394
+ .notNull()
395
+ .references(() => bookings.id, { onDelete: "cascade" }),
396
+ authorId: text("author_id").notNull(),
397
+ content: text("content").notNull(),
398
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
399
+ }, (table) => [index("idx_booking_notes_booking").on(table.bookingId)]);
400
+ // ---------- booking_documents ----------
401
+ export const bookingDocuments = pgTable("booking_documents", {
402
+ id: typeId("booking_documents"),
403
+ bookingId: typeIdRef("booking_id")
404
+ .notNull()
405
+ .references(() => bookings.id, { onDelete: "cascade" }),
406
+ participantId: typeIdRef("participant_id").references(() => bookingParticipants.id, {
407
+ onDelete: "set null",
408
+ }),
409
+ type: bookingDocumentTypeEnum("type").notNull(),
410
+ fileName: text("file_name").notNull(),
411
+ fileUrl: text("file_url").notNull(),
412
+ expiresAt: timestamp("expires_at", { withTimezone: true }),
413
+ notes: text("notes"),
414
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
415
+ }, (table) => [
416
+ index("idx_booking_documents_booking").on(table.bookingId),
417
+ index("idx_booking_documents_participant").on(table.participantId),
418
+ ]);
419
+ // ---------- relations ----------
420
+ export const bookingsRelations = relations(bookings, ({ many }) => ({
421
+ participants: many(bookingParticipants),
422
+ supplierStatuses: many(bookingSupplierStatuses),
423
+ activityLog: many(bookingActivityLog),
424
+ notes: many(bookingNotes),
425
+ documents: many(bookingDocuments),
426
+ fulfillments: many(bookingFulfillments),
427
+ redemptionEvents: many(bookingRedemptionEvents),
428
+ items: many(bookingItems),
429
+ allocations: many(bookingAllocations),
430
+ }));
431
+ export const bookingParticipantsRelations = relations(bookingParticipants, ({ one, many }) => ({
432
+ booking: one(bookings, { fields: [bookingParticipants.bookingId], references: [bookings.id] }),
433
+ documents: many(bookingDocuments),
434
+ fulfillments: many(bookingFulfillments),
435
+ redemptionEvents: many(bookingRedemptionEvents),
436
+ itemLinks: many(bookingItemParticipants),
437
+ }));
438
+ export const bookingItemsRelations = relations(bookingItems, ({ one, many }) => ({
439
+ booking: one(bookings, { fields: [bookingItems.bookingId], references: [bookings.id] }),
440
+ participantLinks: many(bookingItemParticipants),
441
+ allocations: many(bookingAllocations),
442
+ fulfillments: many(bookingFulfillments),
443
+ redemptionEvents: many(bookingRedemptionEvents),
444
+ }));
445
+ export const bookingAllocationsRelations = relations(bookingAllocations, ({ one }) => ({
446
+ booking: one(bookings, { fields: [bookingAllocations.bookingId], references: [bookings.id] }),
447
+ bookingItem: one(bookingItems, {
448
+ fields: [bookingAllocations.bookingItemId],
449
+ references: [bookingItems.id],
450
+ }),
451
+ availabilitySlot: one(availabilitySlotsRef, {
452
+ fields: [bookingAllocations.availabilitySlotId],
453
+ references: [availabilitySlotsRef.id],
454
+ }),
455
+ }));
456
+ export const bookingItemParticipantsRelations = relations(bookingItemParticipants, ({ one }) => ({
457
+ bookingItem: one(bookingItems, {
458
+ fields: [bookingItemParticipants.bookingItemId],
459
+ references: [bookingItems.id],
460
+ }),
461
+ participant: one(bookingParticipants, {
462
+ fields: [bookingItemParticipants.participantId],
463
+ references: [bookingParticipants.id],
464
+ }),
465
+ }));
466
+ export const bookingSupplierStatusesRelations = relations(bookingSupplierStatuses, ({ one }) => ({
467
+ booking: one(bookings, {
468
+ fields: [bookingSupplierStatuses.bookingId],
469
+ references: [bookings.id],
470
+ }),
471
+ }));
472
+ export const bookingFulfillmentsRelations = relations(bookingFulfillments, ({ one }) => ({
473
+ booking: one(bookings, { fields: [bookingFulfillments.bookingId], references: [bookings.id] }),
474
+ bookingItem: one(bookingItems, {
475
+ fields: [bookingFulfillments.bookingItemId],
476
+ references: [bookingItems.id],
477
+ }),
478
+ participant: one(bookingParticipants, {
479
+ fields: [bookingFulfillments.participantId],
480
+ references: [bookingParticipants.id],
481
+ }),
482
+ }));
483
+ export const bookingRedemptionEventsRelations = relations(bookingRedemptionEvents, ({ one }) => ({
484
+ booking: one(bookings, {
485
+ fields: [bookingRedemptionEvents.bookingId],
486
+ references: [bookings.id],
487
+ }),
488
+ bookingItem: one(bookingItems, {
489
+ fields: [bookingRedemptionEvents.bookingItemId],
490
+ references: [bookingItems.id],
491
+ }),
492
+ participant: one(bookingParticipants, {
493
+ fields: [bookingRedemptionEvents.participantId],
494
+ references: [bookingParticipants.id],
495
+ }),
496
+ }));
497
+ export const bookingActivityLogRelations = relations(bookingActivityLog, ({ one }) => ({
498
+ booking: one(bookings, { fields: [bookingActivityLog.bookingId], references: [bookings.id] }),
499
+ }));
500
+ export const bookingNotesRelations = relations(bookingNotes, ({ one }) => ({
501
+ booking: one(bookings, { fields: [bookingNotes.bookingId], references: [bookings.id] }),
502
+ }));
503
+ export const bookingDocumentsRelations = relations(bookingDocuments, ({ one }) => ({
504
+ booking: one(bookings, { fields: [bookingDocuments.bookingId], references: [bookings.id] }),
505
+ participant: one(bookingParticipants, {
506
+ fields: [bookingDocuments.participantId],
507
+ references: [bookingParticipants.id],
508
+ }),
509
+ }));