@voyantjs/bookings 0.9.0 → 0.11.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 (51) hide show
  1. package/dist/index.d.ts +3 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +2 -1
  4. package/dist/markets-ref.d.ts +151 -0
  5. package/dist/markets-ref.d.ts.map +1 -0
  6. package/dist/markets-ref.js +19 -0
  7. package/dist/pii-redaction.d.ts +89 -0
  8. package/dist/pii-redaction.d.ts.map +1 -0
  9. package/dist/pii-redaction.js +120 -0
  10. package/dist/pii.d.ts +1 -0
  11. package/dist/pii.d.ts.map +1 -1
  12. package/dist/pii.js +20 -1
  13. package/dist/routes-groups.d.ts +3 -2
  14. package/dist/routes-groups.d.ts.map +1 -1
  15. package/dist/routes-public.d.ts +11 -13
  16. package/dist/routes-public.d.ts.map +1 -1
  17. package/dist/routes-public.js +3 -3
  18. package/dist/routes.d.ts +232 -22
  19. package/dist/routes.d.ts.map +1 -1
  20. package/dist/routes.js +100 -24
  21. package/dist/schema/travel-details.d.ts +37 -0
  22. package/dist/schema/travel-details.d.ts.map +1 -1
  23. package/dist/schema/travel-details.js +6 -0
  24. package/dist/schema-core.d.ts +17 -17
  25. package/dist/schema-core.d.ts.map +1 -1
  26. package/dist/schema-core.js +8 -2
  27. package/dist/schema-items.d.ts.map +1 -1
  28. package/dist/schema-items.js +6 -1
  29. package/dist/schema-operations.d.ts +2 -2
  30. package/dist/schema-shared.d.ts +1 -1
  31. package/dist/schema-shared.d.ts.map +1 -1
  32. package/dist/schema-shared.js +3 -0
  33. package/dist/service-public.d.ts +0 -6
  34. package/dist/service-public.d.ts.map +1 -1
  35. package/dist/service-public.js +0 -4
  36. package/dist/service.d.ts +232 -56
  37. package/dist/service.d.ts.map +1 -1
  38. package/dist/service.js +469 -137
  39. package/dist/state-machine.d.ts +29 -0
  40. package/dist/state-machine.d.ts.map +1 -0
  41. package/dist/state-machine.js +39 -0
  42. package/dist/validation-public.d.ts +0 -6
  43. package/dist/validation-public.d.ts.map +1 -1
  44. package/dist/validation-public.js +0 -2
  45. package/dist/validation.d.ts +25 -16
  46. package/dist/validation.d.ts.map +1 -1
  47. package/dist/validation.js +17 -6
  48. package/dist/workflows/refund-booking.d.ts +87 -0
  49. package/dist/workflows/refund-booking.d.ts.map +1 -0
  50. package/dist/workflows/refund-booking.js +210 -0
  51. package/package.json +7 -6
package/dist/routes.js CHANGED
@@ -1,13 +1,14 @@
1
- import { ForbiddenApiError, handleApiError, normalizeValidationError, parseJsonBody, parseQuery, requireUserId, UnauthorizedApiError, } from "@voyantjs/hono";
1
+ import { ForbiddenApiError, handleApiError, idempotencyKey, normalizeValidationError, parseJsonBody, parseQuery, requireUserId, UnauthorizedApiError, } from "@voyantjs/hono";
2
2
  import { Hono } from "hono";
3
3
  import { createBookingPiiService } from "./pii.js";
4
+ import { redactBookingContact, redactTravelerIdentity, shouldRevealBookingPii, } from "./pii-redaction.js";
4
5
  import { BOOKING_ROUTE_RUNTIME_CONTAINER_KEY, buildBookingRouteRuntime, } from "./route-runtime.js";
5
6
  import { bookingGroupRoutes } from "./routes-groups.js";
6
7
  import { bookingPiiAccessLog } from "./schema.js";
7
8
  import { bookingsService } from "./service.js";
8
9
  import { bookingGroupsService } from "./service-groups.js";
9
10
  import { publicBookingsService, resolveSessionPricingSnapshot } from "./service-public.js";
10
- import { bookingAggregatesQuerySchema, bookingListQuerySchema, cancelBookingSchema, confirmBookingSchema, convertProductSchema, createBookingSchema, expireBookingSchema, expireStaleBookingsSchema, extendBookingHoldSchema, insertBookingDocumentSchema, insertBookingFulfillmentSchema, insertBookingItemSchema, insertBookingItemTravelerSchema, insertBookingNoteSchema, insertSupplierStatusSchema, insertTravelerSchema, internalBookingOverviewLookupQuerySchema, pricingPreviewSchema, recordBookingRedemptionSchema, reserveBookingFromTransactionSchema, reserveBookingSchema, updateBookingFulfillmentSchema, updateBookingItemSchema, updateBookingSchema, updateBookingStatusSchema, updateSupplierStatusSchema, updateTravelerSchema, upsertTravelerTravelDetailsSchema, } from "./validation.js";
11
+ import { bookingAggregatesQuerySchema, bookingListQuerySchema, cancelBookingSchema, completeBookingSchema, confirmBookingSchema, convertProductSchema, createBookingSchema, expireBookingSchema, expireStaleBookingsSchema, extendBookingHoldSchema, insertBookingDocumentSchema, insertBookingFulfillmentSchema, insertBookingItemSchema, insertBookingItemTravelerSchema, insertBookingNoteSchema, insertSupplierStatusSchema, insertTravelerSchema, internalBookingOverviewLookupQuerySchema, overrideBookingStatusSchema, pricingPreviewSchema, recordBookingRedemptionSchema, reserveBookingFromTransactionSchema, reserveBookingSchema, startBookingSchema, updateBookingFulfillmentSchema, updateBookingItemSchema, updateBookingSchema, updateSupplierStatusSchema, updateTravelerSchema, upsertTravelerTravelDetailsSchema, } from "./validation.js";
11
12
  function hasPiiScope(scopes, action) {
12
13
  if (!scopes || scopes.length === 0) {
13
14
  return false;
@@ -135,7 +136,25 @@ export const bookingRoutes = new Hono()
135
136
  // 1. GET / — List bookings
136
137
  .get("/", async (c) => {
137
138
  const query = parseQuery(c, bookingListQuerySchema);
138
- return c.json(await bookingsService.listBookings(c.get("db"), query));
139
+ const result = await bookingsService.listBookings(c.get("db"), query);
140
+ const reveal = shouldRevealBookingPii({
141
+ actor: c.get("actor"),
142
+ scopes: c.get("scopes"),
143
+ callerType: c.get("callerType"),
144
+ isInternalRequest: c.get("isInternalRequest"),
145
+ });
146
+ await logBookingPiiAccess(c, {
147
+ action: "read",
148
+ outcome: "allowed",
149
+ reason: reveal ? "list_reveal" : "list_redacted",
150
+ metadata: { rowCount: result.data.length, reveal },
151
+ });
152
+ if (reveal)
153
+ return c.json(result);
154
+ return c.json({
155
+ ...result,
156
+ data: result.data.map((row) => redactBookingContact(row)),
157
+ });
139
158
  })
140
159
  // 1a. POST /pricing-preview — Resolve a pricing snapshot without creating a session.
141
160
  .post("/pricing-preview", async (c) => {
@@ -168,10 +187,23 @@ export const bookingRoutes = new Hono()
168
187
  if (!row) {
169
188
  return c.json({ error: "Booking not found" }, 404);
170
189
  }
171
- return c.json({ data: row });
190
+ const reveal = shouldRevealBookingPii({
191
+ actor: c.get("actor"),
192
+ scopes: c.get("scopes"),
193
+ callerType: c.get("callerType"),
194
+ isInternalRequest: c.get("isInternalRequest"),
195
+ });
196
+ await logBookingPiiAccess(c, {
197
+ bookingId: row.id,
198
+ action: "read",
199
+ outcome: "allowed",
200
+ reason: reveal ? "detail_reveal" : "detail_redacted",
201
+ metadata: { reveal },
202
+ });
203
+ return c.json({ data: reveal ? row : redactBookingContact(row) });
172
204
  })
173
205
  // 3. POST /reserve — Reserve inventory and create on-hold booking
174
- .post("/reserve", async (c) => {
206
+ .post("/reserve", idempotencyKey({ scope: "POST /v1/admin/bookings/reserve" }), async (c) => {
175
207
  const result = await bookingsService.reserveBooking(c.get("db"), await parseJsonBody(c, reserveBookingSchema), c.get("userId"));
176
208
  if ("booking" in result) {
177
209
  return c.json({ data: result.booking }, 201);
@@ -191,7 +223,7 @@ export const bookingRoutes = new Hono()
191
223
  return c.json({ error: "Unable to reserve booking" }, 400);
192
224
  })
193
225
  // 3a. POST /from-product — Create booking draft from product definition
194
- .post("/from-product", async (c) => {
226
+ .post("/from-product", idempotencyKey({ scope: "POST /v1/admin/bookings/from-product" }), async (c) => {
195
227
  const row = await bookingsService.createBookingFromProduct(c.get("db"), await parseJsonBody(c, convertProductSchema), c.get("userId"));
196
228
  if (!row) {
197
229
  return c.json({ error: "Product or option not found" }, 404);
@@ -199,7 +231,7 @@ export const bookingRoutes = new Hono()
199
231
  return c.json({ data: row }, 201);
200
232
  })
201
233
  // 3b. POST /from-offer/:offerId/reserve — Reserve booking from transaction offer
202
- .post("/from-offer/:offerId/reserve", async (c) => {
234
+ .post("/from-offer/:offerId/reserve", idempotencyKey({ scope: "POST /v1/admin/bookings/from-offer" }), async (c) => {
203
235
  const result = await bookingsService.reserveBookingFromOffer(c.get("db"), c.req.param("offerId"), await parseJsonBody(c, reserveBookingFromTransactionSchema), c.get("userId"));
204
236
  if (result.status === "not_found") {
205
237
  return c.json({ error: "Offer not found" }, 404);
@@ -222,7 +254,7 @@ export const bookingRoutes = new Hono()
222
254
  return c.json({ error: "Unable to reserve booking from offer" }, 400);
223
255
  })
224
256
  // 3c. POST /from-order/:orderId/reserve — Reserve booking from transaction order
225
- .post("/from-order/:orderId/reserve", async (c) => {
257
+ .post("/from-order/:orderId/reserve", idempotencyKey({ scope: "POST /v1/admin/bookings/from-order" }), async (c) => {
226
258
  const result = await bookingsService.reserveBookingFromOrder(c.get("db"), c.req.param("orderId"), await parseJsonBody(c, reserveBookingFromTransactionSchema), c.get("userId"));
227
259
  if (result.status === "not_found") {
228
260
  return c.json({ error: "Order not found" }, 404);
@@ -245,7 +277,7 @@ export const bookingRoutes = new Hono()
245
277
  return c.json({ error: "Unable to reserve booking from order" }, 400);
246
278
  })
247
279
  // 4. POST / — Create booking (manual/backoffice only)
248
- .post("/", async (c) => {
280
+ .post("/", idempotencyKey({ scope: "POST /v1/admin/bookings" }), async (c) => {
249
281
  try {
250
282
  return c.json({
251
283
  data: await bookingsService.createBooking(c.get("db"), await parseJsonBody(c, createBookingSchema, {
@@ -283,20 +315,6 @@ export const bookingRoutes = new Hono()
283
315
  // ==========================================================================
284
316
  // Status
285
317
  // ==========================================================================
286
- // 7. PATCH /:id/status — Change booking status
287
- .patch("/:id/status", async (c) => {
288
- const result = await bookingsService.updateBookingStatus(c.get("db"), c.req.param("id"), await parseJsonBody(c, updateBookingStatusSchema), c.get("userId"), { eventBus: c.get("eventBus") });
289
- if (result.status === "not_found") {
290
- return c.json({ error: "Booking not found" }, 404);
291
- }
292
- if (result.status === "invalid_transition") {
293
- return c.json({ error: "Invalid booking status transition" }, 409);
294
- }
295
- if ("booking" in result) {
296
- return c.json({ data: result.booking });
297
- }
298
- return c.json({ error: "Unable to update booking status" }, 400);
299
- })
300
318
  // 8. POST /:id/confirm — Confirm an on-hold booking
301
319
  .post("/:id/confirm", async (c) => {
302
320
  const result = await bookingsService.confirmBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, confirmBookingSchema), c.get("userId"), { eventBus: c.get("eventBus") });
@@ -362,6 +380,48 @@ export const bookingRoutes = new Hono()
362
380
  return c.json({ data: result.booking });
363
381
  }
364
382
  return c.json({ error: "Unable to cancel booking" }, 400);
383
+ })
384
+ // 11a. POST /:id/start — Mark a confirmed booking as in-progress
385
+ .post("/:id/start", async (c) => {
386
+ const result = await bookingsService.startBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, startBookingSchema), c.get("userId"), { eventBus: c.get("eventBus") });
387
+ if (result.status === "not_found") {
388
+ return c.json({ error: "Booking not found" }, 404);
389
+ }
390
+ if (result.status === "invalid_transition") {
391
+ return c.json({ error: "Booking is not in a confirmed state" }, 409);
392
+ }
393
+ if ("booking" in result) {
394
+ return c.json({ data: result.booking });
395
+ }
396
+ return c.json({ error: "Unable to start booking" }, 400);
397
+ })
398
+ // 11b. POST /:id/complete — Mark an in-progress booking as completed
399
+ .post("/:id/complete", async (c) => {
400
+ const result = await bookingsService.completeBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, completeBookingSchema), c.get("userId"), { eventBus: c.get("eventBus") });
401
+ if (result.status === "not_found") {
402
+ return c.json({ error: "Booking not found" }, 404);
403
+ }
404
+ if (result.status === "invalid_transition") {
405
+ return c.json({ error: "Booking is not in an in-progress state" }, 409);
406
+ }
407
+ if ("booking" in result) {
408
+ return c.json({ data: result.booking });
409
+ }
410
+ return c.json({ error: "Unable to complete booking" }, 400);
411
+ })
412
+ // 11c. POST /:id/override-status — Admin override that bypasses the
413
+ // transition graph. Updates the booking row only — no cascade to items,
414
+ // allocations, or fulfillments. Always emits booking.status_overridden for
415
+ // audit. Requires a non-empty `reason`.
416
+ .post("/:id/override-status", async (c) => {
417
+ const result = await bookingsService.overrideBookingStatus(c.get("db"), c.req.param("id"), await parseJsonBody(c, overrideBookingStatusSchema), c.get("userId"), { eventBus: c.get("eventBus") });
418
+ if (result.status === "not_found") {
419
+ return c.json({ error: "Booking not found" }, 404);
420
+ }
421
+ if ("booking" in result) {
422
+ return c.json({ data: result.booking });
423
+ }
424
+ return c.json({ error: "Unable to override booking status" }, 400);
365
425
  })
366
426
  // 12. GET /:id/allocations — List booking allocations
367
427
  .get("/:id/allocations", async (c) => {
@@ -371,7 +431,23 @@ export const bookingRoutes = new Hono()
371
431
  // Travelers
372
432
  // ==========================================================================
373
433
  .get("/:id/travelers", async (c) => {
374
- return c.json({ data: await bookingsService.listTravelers(c.get("db"), c.req.param("id")) });
434
+ const travelers = await bookingsService.listTravelers(c.get("db"), c.req.param("id"));
435
+ const reveal = shouldRevealBookingPii({
436
+ actor: c.get("actor"),
437
+ scopes: c.get("scopes"),
438
+ callerType: c.get("callerType"),
439
+ isInternalRequest: c.get("isInternalRequest"),
440
+ });
441
+ await logBookingPiiAccess(c, {
442
+ bookingId: c.req.param("id"),
443
+ action: "read",
444
+ outcome: "allowed",
445
+ reason: reveal ? "travelers_reveal" : "travelers_redacted",
446
+ metadata: { rowCount: travelers.length, reveal },
447
+ });
448
+ if (reveal)
449
+ return c.json({ data: travelers });
450
+ return c.json({ data: travelers.map((row) => redactTravelerIdentity(row)) });
375
451
  })
376
452
  .get("/:id/travelers/:travelerId/travel-details", async (c) => {
377
453
  const auth = await authorizeBookingPiiAccess(c, {
@@ -8,6 +8,9 @@ export declare const bookingTravelerIdentitySchema: z.ZodObject<{
8
8
  export declare const bookingTravelerDietarySchema: z.ZodObject<{
9
9
  dietaryRequirements: z.ZodNullable<z.ZodOptional<z.ZodString>>;
10
10
  }, z.core.$strip>;
11
+ export declare const bookingTravelerAccessibilitySchema: z.ZodObject<{
12
+ accessibilityNeeds: z.ZodNullable<z.ZodOptional<z.ZodString>>;
13
+ }, z.core.$strip>;
11
14
  export declare const decryptedBookingTravelerTravelDetailSchema: z.ZodObject<{
12
15
  travelerId: z.ZodString;
13
16
  nationality: z.ZodNullable<z.ZodString>;
@@ -15,6 +18,7 @@ export declare const decryptedBookingTravelerTravelDetailSchema: z.ZodObject<{
15
18
  passportExpiry: z.ZodNullable<z.ZodString>;
16
19
  dateOfBirth: z.ZodNullable<z.ZodString>;
17
20
  dietaryRequirements: z.ZodNullable<z.ZodString>;
21
+ accessibilityNeeds: z.ZodNullable<z.ZodString>;
18
22
  isLeadTraveler: z.ZodBoolean;
19
23
  createdAt: z.ZodDate;
20
24
  updatedAt: z.ZodDate;
@@ -86,6 +90,29 @@ export declare const bookingTravelerTravelDetails: import("drizzle-orm/pg-core")
86
90
  enc: string;
87
91
  } | null;
88
92
  }>;
93
+ accessibilityEncrypted: import("drizzle-orm/pg-core").PgColumn<{
94
+ name: "accessibility_encrypted";
95
+ tableName: "booking_traveler_travel_details";
96
+ dataType: "json";
97
+ columnType: "PgJsonb";
98
+ data: {
99
+ enc: string;
100
+ } | null;
101
+ driverParam: unknown;
102
+ notNull: false;
103
+ hasDefault: false;
104
+ isPrimaryKey: false;
105
+ isAutoincrement: false;
106
+ hasRuntimeDefault: false;
107
+ enumValues: undefined;
108
+ baseColumn: never;
109
+ identity: undefined;
110
+ generated: undefined;
111
+ }, {}, {
112
+ $type: {
113
+ enc: string;
114
+ } | null;
115
+ }>;
89
116
  isLeadTraveler: import("drizzle-orm/pg-core").PgColumn<{
90
117
  name: "is_lead_traveler";
91
118
  tableName: "booking_traveler_travel_details";
@@ -141,6 +168,9 @@ export declare const bookingTravelerTravelDetails: import("drizzle-orm/pg-core")
141
168
  dialect: "pg";
142
169
  }>;
143
170
  export declare const bookingTravelerTravelDetailInsertSchema: z.ZodObject<{
171
+ accessibilityEncrypted: z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
172
+ enc: z.ZodString;
173
+ }, z.core.$strip>>>>;
144
174
  dietaryEncrypted: z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
145
175
  enc: z.ZodString;
146
176
  }, z.core.$strip>>>>;
@@ -151,6 +181,9 @@ export declare const bookingTravelerTravelDetailInsertSchema: z.ZodObject<{
151
181
  travelerId: z.ZodString;
152
182
  }, z.core.$strip>;
153
183
  export declare const bookingTravelerTravelDetailUpdateSchema: z.ZodObject<{
184
+ accessibilityEncrypted: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
185
+ enc: z.ZodString;
186
+ }, z.core.$strip>>>>>;
154
187
  dietaryEncrypted: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
155
188
  enc: z.ZodString;
156
189
  }, z.core.$strip>>>>>;
@@ -167,12 +200,16 @@ export declare const bookingTravelerTravelDetailSelectSchema: z.ZodObject<{
167
200
  dietaryEncrypted: z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
168
201
  enc: z.ZodString;
169
202
  }, z.core.$strip>>>>;
203
+ accessibilityEncrypted: z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
204
+ enc: z.ZodString;
205
+ }, z.core.$strip>>>>;
170
206
  isLeadTraveler: z.ZodDefault<z.ZodBoolean>;
171
207
  createdAt: z.ZodDate;
172
208
  updatedAt: z.ZodDate;
173
209
  }, z.core.$strip>;
174
210
  export type BookingTravelerIdentity = z.infer<typeof bookingTravelerIdentitySchema>;
175
211
  export type BookingTravelerDietary = z.infer<typeof bookingTravelerDietarySchema>;
212
+ export type BookingTravelerAccessibility = z.infer<typeof bookingTravelerAccessibilitySchema>;
176
213
  export type BookingTravelerTravelDetail = z.infer<typeof bookingTravelerTravelDetailSelectSchema>;
177
214
  export type NewBookingTravelerTravelDetail = z.infer<typeof bookingTravelerTravelDetailInsertSchema>;
178
215
  export type DecryptedBookingTravelerTravelDetail = z.infer<typeof decryptedBookingTravelerTravelDetailSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"travel-details.d.ts","sourceRoot":"","sources":["../../src/schema/travel-details.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,6BAA6B;;;;;iBAKxC,CAAA;AAEF,eAAO,MAAM,4BAA4B;;iBAEvC,CAAA;AAcF,eAAO,MAAM,0CAA0C;;;;;;;;;;iBACL,CAAA;AAElD,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAaxC,CAAA;AASD,eAAO,MAAM,uCAAuC;;;;;;;;;iBAIhD,CAAA;AAEJ,eAAO,MAAM,uCAAuC;;;;;;;;iBAEvB,CAAA;AAE7B,eAAO,MAAM,uCAAuC;;;;;;;;;;;iBAIhD,CAAA;AAEJ,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAA;AACnF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACjF,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uCAAuC,CAAC,CAAA;AACjG,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uCAAuC,CAAC,CAAA;AACpG,MAAM,MAAM,oCAAoC,GAAG,CAAC,CAAC,KAAK,CACxD,OAAO,0CAA0C,CAClD,CAAA"}
1
+ {"version":3,"file":"travel-details.d.ts","sourceRoot":"","sources":["../../src/schema/travel-details.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,6BAA6B;;;;;iBAKxC,CAAA;AAEF,eAAO,MAAM,4BAA4B;;iBAEvC,CAAA;AAEF,eAAO,MAAM,kCAAkC;;iBAE7C,CAAA;AAeF,eAAO,MAAM,0CAA0C;;;;;;;;;;;iBACL,CAAA;AAElD,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcxC,CAAA;AAUD,eAAO,MAAM,uCAAuC;;;;;;;;;;;;iBAIhD,CAAA;AAEJ,eAAO,MAAM,uCAAuC;;;;;;;;;;;iBAEvB,CAAA;AAE7B,eAAO,MAAM,uCAAuC;;;;;;;;;;;;;;iBAIhD,CAAA;AAEJ,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAA;AACnF,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAA;AACjF,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAA;AAC7F,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uCAAuC,CAAC,CAAA;AACjG,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uCAAuC,CAAC,CAAA;AACpG,MAAM,MAAM,oCAAoC,GAAG,CAAC,CAAC,KAAK,CACxD,OAAO,0CAA0C,CAClD,CAAA"}
@@ -11,6 +11,9 @@ export const bookingTravelerIdentitySchema = z.object({
11
11
  export const bookingTravelerDietarySchema = z.object({
12
12
  dietaryRequirements: z.string().optional().nullable(),
13
13
  });
14
+ export const bookingTravelerAccessibilitySchema = z.object({
15
+ accessibilityNeeds: z.string().optional().nullable(),
16
+ });
14
17
  const decryptedBookingTravelerTravelDetailRecordSchema = z.object({
15
18
  travelerId: z.string(),
16
19
  nationality: z.string().nullable(),
@@ -18,6 +21,7 @@ const decryptedBookingTravelerTravelDetailRecordSchema = z.object({
18
21
  passportExpiry: z.string().nullable(),
19
22
  dateOfBirth: z.string().nullable(),
20
23
  dietaryRequirements: z.string().nullable(),
24
+ accessibilityNeeds: z.string().nullable(),
21
25
  isLeadTraveler: z.boolean(),
22
26
  createdAt: z.date(),
23
27
  updatedAt: z.date(),
@@ -29,6 +33,7 @@ export const bookingTravelerTravelDetails = pgTable("booking_traveler_travel_det
29
33
  .references(() => bookingTravelers.id, { onDelete: "cascade" }),
30
34
  identityEncrypted: jsonb("identity_encrypted").$type(),
31
35
  dietaryEncrypted: jsonb("dietary_encrypted").$type(),
36
+ accessibilityEncrypted: jsonb("accessibility_encrypted").$type(),
32
37
  isLeadTraveler: boolean("is_lead_traveler").notNull().default(false),
33
38
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
34
39
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
@@ -37,6 +42,7 @@ const bookingTravelerTravelDetailRecordCoreSchema = z.object({
37
42
  travelerId: z.string().min(1),
38
43
  identityEncrypted: kmsEnvelopeSchema.optional().nullable(),
39
44
  dietaryEncrypted: kmsEnvelopeSchema.optional().nullable(),
45
+ accessibilityEncrypted: kmsEnvelopeSchema.optional().nullable(),
40
46
  isLeadTraveler: z.boolean().default(false),
41
47
  });
42
48
  export const bookingTravelerTravelDetailInsertSchema = bookingTravelerTravelDetailRecordCoreSchema
@@ -342,6 +342,23 @@ export declare const bookings: import("drizzle-orm/pg-core").PgTableWithColumns<
342
342
  identity: undefined;
343
343
  generated: undefined;
344
344
  }, {}, {}>;
345
+ fxRateSetId: import("drizzle-orm/pg-core").PgColumn<{
346
+ name: "fx_rate_set_id";
347
+ tableName: "bookings";
348
+ dataType: "string";
349
+ columnType: "PgText";
350
+ data: string;
351
+ driverParam: string;
352
+ notNull: false;
353
+ hasDefault: false;
354
+ isPrimaryKey: false;
355
+ isAutoincrement: false;
356
+ hasRuntimeDefault: false;
357
+ enumValues: [string, ...string[]];
358
+ baseColumn: never;
359
+ identity: undefined;
360
+ generated: undefined;
361
+ }, {}, {}>;
345
362
  sellAmountCents: import("drizzle-orm/pg-core").PgColumn<{
346
363
  name: "sell_amount_cents";
347
364
  tableName: "bookings";
@@ -808,23 +825,6 @@ export declare const bookingTravelers: import("drizzle-orm/pg-core").PgTableWith
808
825
  identity: undefined;
809
826
  generated: undefined;
810
827
  }, {}, {}>;
811
- accessibilityNeeds: import("drizzle-orm/pg-core").PgColumn<{
812
- name: "accessibility_needs";
813
- tableName: "booking_travelers";
814
- dataType: "string";
815
- columnType: "PgText";
816
- data: string;
817
- driverParam: string;
818
- notNull: false;
819
- hasDefault: false;
820
- isPrimaryKey: false;
821
- isAutoincrement: false;
822
- hasRuntimeDefault: false;
823
- enumValues: [string, ...string[]];
824
- baseColumn: never;
825
- identity: undefined;
826
- generated: undefined;
827
- }, {}, {}>;
828
828
  specialRequests: import("drizzle-orm/pg-core").PgColumn<{
829
829
  name: "special_requests";
830
830
  tableName: "booking_travelers";
@@ -1 +1 @@
1
- {"version":3,"file":"schema-core.d.ts","sourceRoot":"","sources":["../src/schema-core.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiDpB,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqC5B,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqB/B,CAAA;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAClD,MAAM,MAAM,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AACrD,MAAM,MAAM,eAAe,GAAG,OAAO,gBAAgB,CAAC,YAAY,CAAA;AAClE,MAAM,MAAM,kBAAkB,GAAG,OAAO,gBAAgB,CAAC,YAAY,CAAA;AACrE,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAA;AACzE,MAAM,MAAM,sBAAsB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAA"}
1
+ {"version":3,"file":"schema-core.d.ts","sourceRoot":"","sources":["../src/schema-core.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0DpB,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoC5B,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqB/B,CAAA;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAClD,MAAM,MAAM,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AACrD,MAAM,MAAM,eAAe,GAAG,OAAO,gBAAgB,CAAC,YAAY,CAAA;AAClE,MAAM,MAAM,kBAAkB,GAAG,OAAO,gBAAgB,CAAC,YAAY,CAAA;AACrE,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAA;AACzE,MAAM,MAAM,sBAAsB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
2
- import { boolean, date, index, integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
2
+ import { sql } from "drizzle-orm";
3
+ import { boolean, check, date, index, integer, jsonb, pgTable, text, timestamp, } from "drizzle-orm/pg-core";
3
4
  import { bookingParticipantTypeEnum, bookingPiiAccessActionEnum, bookingPiiAccessOutcomeEnum, bookingSourceTypeEnum, bookingStatusEnum, bookingTravelerCategoryEnum, } from "./schema-shared";
4
5
  export const bookings = pgTable("bookings", {
5
6
  id: typeId("bookings"),
@@ -22,6 +23,7 @@ export const bookings = pgTable("bookings", {
22
23
  contactPostalCode: text("contact_postal_code"),
23
24
  sellCurrency: text("sell_currency").notNull(),
24
25
  baseCurrency: text("base_currency"),
26
+ fxRateSetId: text("fx_rate_set_id"),
25
27
  sellAmountCents: integer("sell_amount_cents"),
26
28
  baseSellAmountCents: integer("base_sell_amount_cents"),
27
29
  costAmountCents: integer("cost_amount_cents"),
@@ -46,6 +48,11 @@ export const bookings = pgTable("bookings", {
46
48
  index("idx_bookings_organization").on(table.organizationId),
47
49
  index("idx_bookings_source_type").on(table.sourceType),
48
50
  index("idx_bookings_number").on(table.bookingNumber),
51
+ // base_currency covers the base_*_amount_cents columns. If any base
52
+ // amount is set, base_currency must be set so downstream FX/reporting
53
+ // code can interpret it. Both null is fine (FX deferred until quote
54
+ // becomes a confirmed booking).
55
+ check("ck_bookings_base_currency_amounts", sql `(${table.baseSellAmountCents} IS NULL AND ${table.baseCostAmountCents} IS NULL) OR ${table.baseCurrency} IS NOT NULL`),
49
56
  ]);
50
57
  export const bookingTravelers = pgTable("booking_travelers", {
51
58
  id: typeId("booking_travelers"),
@@ -60,7 +67,6 @@ export const bookingTravelers = pgTable("booking_travelers", {
60
67
  email: text("email"),
61
68
  phone: text("phone"),
62
69
  preferredLanguage: text("preferred_language"),
63
- accessibilityNeeds: text("accessibility_needs"),
64
70
  specialRequests: text("special_requests"),
65
71
  isPrimary: boolean("is_primary").notNull().default(false),
66
72
  notes: text("notes"),
@@ -1 +1 @@
1
- {"version":3,"file":"schema-items.d.ts","sourceRoot":"","sources":["../src/schema-items.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqCxB,CAAA;AAED,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmC9B,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8B/B,CAAA;AAED,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BnC,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBhC,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC7D,MAAM,MAAM,iBAAiB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACtE,MAAM,MAAM,oBAAoB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACzE,MAAM,MAAM,kBAAkB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAA;AACxE,MAAM,MAAM,qBAAqB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAA;AAC3E,MAAM,MAAM,sBAAsB,GAAG,OAAO,uBAAuB,CAAC,YAAY,CAAA;AAChF,MAAM,MAAM,yBAAyB,GAAG,OAAO,uBAAuB,CAAC,YAAY,CAAA;AACnF,MAAM,MAAM,mBAAmB,GAAG,OAAO,oBAAoB,CAAC,YAAY,CAAA;AAC1E,MAAM,MAAM,sBAAsB,GAAG,OAAO,oBAAoB,CAAC,YAAY,CAAA"}
1
+ {"version":3,"file":"schema-items.d.ts","sourceRoot":"","sources":["../src/schema-items.ts"],"names":[],"mappings":"AA4BA,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CxB,CAAA;AAED,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmC9B,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8B/B,CAAA;AAED,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BnC,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBhC,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAA;AAC7D,MAAM,MAAM,iBAAiB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACtE,MAAM,MAAM,oBAAoB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACzE,MAAM,MAAM,kBAAkB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAA;AACxE,MAAM,MAAM,qBAAqB,GAAG,OAAO,mBAAmB,CAAC,YAAY,CAAA;AAC3E,MAAM,MAAM,sBAAsB,GAAG,OAAO,uBAAuB,CAAC,YAAY,CAAA;AAChF,MAAM,MAAM,yBAAyB,GAAG,OAAO,uBAAuB,CAAC,YAAY,CAAA;AACnF,MAAM,MAAM,mBAAmB,GAAG,OAAO,oBAAoB,CAAC,YAAY,CAAA;AAC1E,MAAM,MAAM,sBAAsB,GAAG,OAAO,oBAAoB,CAAC,YAAY,CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
2
- import { boolean, date, index, integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
2
+ import { sql } from "drizzle-orm";
3
+ import { boolean, check, date, index, integer, jsonb, pgTable, text, timestamp, } from "drizzle-orm/pg-core";
3
4
  import { availabilitySlotsRef } from "./availability-ref.js";
4
5
  import { bookings, bookingTravelers } from "./schema-core";
5
6
  import { bookingAllocationStatusEnum, bookingAllocationTypeEnum, bookingFulfillmentDeliveryChannelEnum, bookingFulfillmentStatusEnum, bookingFulfillmentTypeEnum, bookingItemParticipantRoleEnum, bookingItemStatusEnum, bookingItemTypeEnum, bookingRedemptionMethodEnum, } from "./schema-shared";
@@ -36,6 +37,10 @@ export const bookingItems = pgTable("booking_items", {
36
37
  index("idx_booking_items_booking").on(table.bookingId),
37
38
  index("idx_booking_items_booking_created").on(table.bookingId, table.createdAt),
38
39
  index("idx_booking_items_status").on(table.status),
40
+ // cost_currency is optional on items (not every line has cost data) but
41
+ // if any cost amount is set, the currency MUST be set so reporting can
42
+ // interpret it.
43
+ check("ck_booking_items_cost_currency_amounts", sql `(${table.unitCostAmountCents} IS NULL AND ${table.totalCostAmountCents} IS NULL) OR ${table.costCurrency} IS NOT NULL`),
39
44
  ]);
40
45
  export const bookingAllocations = pgTable("booking_allocations", {
41
46
  id: typeId("booking_allocations"),
@@ -269,14 +269,14 @@ export declare const bookingActivityLog: import("drizzle-orm/pg-core").PgTableWi
269
269
  tableName: "booking_activity_log";
270
270
  dataType: "string";
271
271
  columnType: "PgEnumColumn";
272
- data: "booking_created" | "booking_reserved" | "booking_converted" | "booking_confirmed" | "hold_extended" | "hold_expired" | "status_change" | "item_update" | "allocation_released" | "fulfillment_issued" | "fulfillment_updated" | "redemption_recorded" | "supplier_update" | "passenger_update" | "note_added";
272
+ data: "booking_created" | "booking_reserved" | "booking_converted" | "booking_confirmed" | "booking_started" | "booking_completed" | "hold_extended" | "hold_expired" | "status_change" | "status_overridden" | "item_update" | "allocation_released" | "fulfillment_issued" | "fulfillment_updated" | "redemption_recorded" | "supplier_update" | "passenger_update" | "note_added";
273
273
  driverParam: string;
274
274
  notNull: true;
275
275
  hasDefault: false;
276
276
  isPrimaryKey: false;
277
277
  isAutoincrement: false;
278
278
  hasRuntimeDefault: false;
279
- enumValues: ["booking_created", "booking_reserved", "booking_converted", "booking_confirmed", "hold_extended", "hold_expired", "status_change", "item_update", "allocation_released", "fulfillment_issued", "fulfillment_updated", "redemption_recorded", "supplier_update", "passenger_update", "note_added"];
279
+ enumValues: ["booking_created", "booking_reserved", "booking_converted", "booking_confirmed", "booking_started", "booking_completed", "hold_extended", "hold_expired", "status_change", "status_overridden", "item_update", "allocation_released", "fulfillment_issued", "fulfillment_updated", "redemption_recorded", "supplier_update", "passenger_update", "note_added"];
280
280
  baseColumn: never;
281
281
  identity: undefined;
282
282
  generated: undefined;
@@ -1,6 +1,6 @@
1
1
  export declare const bookingStatusEnum: import("drizzle-orm/pg-core").PgEnum<["draft", "on_hold", "confirmed", "in_progress", "completed", "expired", "cancelled"]>;
2
2
  export declare const supplierConfirmationStatusEnum: import("drizzle-orm/pg-core").PgEnum<["pending", "confirmed", "rejected", "cancelled"]>;
3
- export declare const bookingActivityTypeEnum: import("drizzle-orm/pg-core").PgEnum<["booking_created", "booking_reserved", "booking_converted", "booking_confirmed", "hold_extended", "hold_expired", "status_change", "item_update", "allocation_released", "fulfillment_issued", "fulfillment_updated", "redemption_recorded", "supplier_update", "passenger_update", "note_added"]>;
3
+ export declare const bookingActivityTypeEnum: import("drizzle-orm/pg-core").PgEnum<["booking_created", "booking_reserved", "booking_converted", "booking_confirmed", "booking_started", "booking_completed", "hold_extended", "hold_expired", "status_change", "status_overridden", "item_update", "allocation_released", "fulfillment_issued", "fulfillment_updated", "redemption_recorded", "supplier_update", "passenger_update", "note_added"]>;
4
4
  export declare const bookingDocumentTypeEnum: import("drizzle-orm/pg-core").PgEnum<["visa", "insurance", "health", "passport_copy", "other"]>;
5
5
  export declare const bookingSourceTypeEnum: import("drizzle-orm/pg-core").PgEnum<["direct", "manual", "affiliate", "ota", "reseller", "api_partner", "internal"]>;
6
6
  export declare const bookingParticipantTypeEnum: import("drizzle-orm/pg-core").PgEnum<["traveler", "occupant", "other"]>;
@@ -1 +1 @@
1
- {"version":3,"file":"schema-shared.d.ts","sourceRoot":"","sources":["../src/schema-shared.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,6HAQ5B,CAAA;AAEF,eAAO,MAAM,8BAA8B,yFAKzC,CAAA;AAEF,eAAO,MAAM,uBAAuB,0UAgBlC,CAAA;AAEF,eAAO,MAAM,uBAAuB,iGAMlC,CAAA;AAEF,eAAO,MAAM,qBAAqB,uHAQhC,CAAA;AAEF,eAAO,MAAM,0BAA0B,yEAIrC,CAAA;AAEF,eAAO,MAAM,2BAA2B,uFAMtC,CAAA;AAEF,eAAO,MAAM,mBAAmB,mJAW9B,CAAA;AAEF,eAAO,MAAM,qBAAqB,8GAOhC,CAAA;AAEF,eAAO,MAAM,yBAAyB,sEAIpC,CAAA;AAEF,eAAO,MAAM,2BAA2B,8GAOtC,CAAA;AAEF,eAAO,MAAM,0BAA0B,6GAQrC,CAAA;AAEF,eAAO,MAAM,qCAAqC,uFAGjD,CAAA;AAED,eAAO,MAAM,4BAA4B,8FAMvC,CAAA;AAEF,eAAO,MAAM,2BAA2B,0EAKtC,CAAA;AAEF,eAAO,MAAM,8BAA8B,wFAKzC,CAAA;AAEF,eAAO,MAAM,8BAA8B,qEAGzC,CAAA;AAEF,eAAO,MAAM,0BAA0B,oEAIrC,CAAA;AAEF,eAAO,MAAM,2BAA2B,6DAGtC,CAAA"}
1
+ {"version":3,"file":"schema-shared.d.ts","sourceRoot":"","sources":["../src/schema-shared.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,6HAQ5B,CAAA;AAEF,eAAO,MAAM,8BAA8B,yFAKzC,CAAA;AAEF,eAAO,MAAM,uBAAuB,uYAmBlC,CAAA;AAEF,eAAO,MAAM,uBAAuB,iGAMlC,CAAA;AAEF,eAAO,MAAM,qBAAqB,uHAQhC,CAAA;AAEF,eAAO,MAAM,0BAA0B,yEAIrC,CAAA;AAEF,eAAO,MAAM,2BAA2B,uFAMtC,CAAA;AAEF,eAAO,MAAM,mBAAmB,mJAW9B,CAAA;AAEF,eAAO,MAAM,qBAAqB,8GAOhC,CAAA;AAEF,eAAO,MAAM,yBAAyB,sEAIpC,CAAA;AAEF,eAAO,MAAM,2BAA2B,8GAOtC,CAAA;AAEF,eAAO,MAAM,0BAA0B,6GAQrC,CAAA;AAEF,eAAO,MAAM,qCAAqC,uFAGjD,CAAA;AAED,eAAO,MAAM,4BAA4B,8FAMvC,CAAA;AAEF,eAAO,MAAM,2BAA2B,0EAKtC,CAAA;AAEF,eAAO,MAAM,8BAA8B,wFAKzC,CAAA;AAEF,eAAO,MAAM,8BAA8B,qEAGzC,CAAA;AAEF,eAAO,MAAM,0BAA0B,oEAIrC,CAAA;AAEF,eAAO,MAAM,2BAA2B,6DAGtC,CAAA"}
@@ -19,9 +19,12 @@ export const bookingActivityTypeEnum = pgEnum("booking_activity_type", [
19
19
  "booking_reserved",
20
20
  "booking_converted",
21
21
  "booking_confirmed",
22
+ "booking_started",
23
+ "booking_completed",
22
24
  "hold_extended",
23
25
  "hold_expired",
24
26
  "status_change",
27
+ "status_overridden",
25
28
  "item_update",
26
29
  "allocation_released",
27
30
  "fulfillment_issued",
@@ -83,7 +83,6 @@ export declare const publicBookingsService: {
83
83
  email: string | null;
84
84
  phone: string | null;
85
85
  preferredLanguage: string | null;
86
- accessibilityNeeds: string | null;
87
86
  specialRequests: string | null;
88
87
  isPrimary: boolean;
89
88
  notes: string | null;
@@ -175,7 +174,6 @@ export declare const publicBookingsService: {
175
174
  email: string | null;
176
175
  phone: string | null;
177
176
  preferredLanguage: string | null;
178
- accessibilityNeeds: string | null;
179
177
  specialRequests: string | null;
180
178
  isPrimary: boolean;
181
179
  notes: string | null;
@@ -296,7 +294,6 @@ export declare const publicBookingsService: {
296
294
  email: string | null;
297
295
  phone: string | null;
298
296
  preferredLanguage: string | null;
299
- accessibilityNeeds: string | null;
300
297
  specialRequests: string | null;
301
298
  isPrimary: boolean;
302
299
  notes: string | null;
@@ -429,7 +426,6 @@ export declare const publicBookingsService: {
429
426
  email: string | null;
430
427
  phone: string | null;
431
428
  preferredLanguage: string | null;
432
- accessibilityNeeds: string | null;
433
429
  specialRequests: string | null;
434
430
  isPrimary: boolean;
435
431
  notes: string | null;
@@ -525,7 +521,6 @@ export declare const publicBookingsService: {
525
521
  email: string | null;
526
522
  phone: string | null;
527
523
  preferredLanguage: string | null;
528
- accessibilityNeeds: string | null;
529
524
  specialRequests: string | null;
530
525
  isPrimary: boolean;
531
526
  notes: string | null;
@@ -621,7 +616,6 @@ export declare const publicBookingsService: {
621
616
  email: string | null;
622
617
  phone: string | null;
623
618
  preferredLanguage: string | null;
624
- accessibilityNeeds: string | null;
625
619
  specialRequests: string | null;
626
620
  isPrimary: boolean;
627
621
  notes: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"service-public.d.ts","sourceRoot":"","sources":["../src/service-public.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service-public.d.ts","sourceRoot":"","sources":["../src/service-public.ts"],"names":[],"mappings":"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"}
@@ -515,7 +515,6 @@ async function buildSessionSnapshot(db, bookingId) {
515
515
  email: participant.email ?? null,
516
516
  phone: participant.phone ?? null,
517
517
  preferredLanguage: participant.preferredLanguage ?? null,
518
- accessibilityNeeds: participant.accessibilityNeeds ?? null,
519
518
  specialRequests: participant.specialRequests ?? null,
520
519
  isPrimary: participant.isPrimary,
521
520
  notes: participant.notes ?? null,
@@ -623,7 +622,6 @@ export const publicBookingsService = {
623
622
  email: participant.email ?? null,
624
623
  phone: participant.phone ?? null,
625
624
  preferredLanguage: participant.preferredLanguage ?? null,
626
- accessibilityNeeds: participant.accessibilityNeeds ?? null,
627
625
  specialRequests: participant.specialRequests ?? null,
628
626
  isPrimary: participant.isPrimary,
629
627
  notes: participant.notes ?? null,
@@ -695,7 +693,6 @@ export const publicBookingsService = {
695
693
  email: participant.email ?? null,
696
694
  phone: participant.phone ?? null,
697
695
  preferredLanguage: participant.preferredLanguage ?? null,
698
- accessibilityNeeds: participant.accessibilityNeeds ?? null,
699
696
  specialRequests: participant.specialRequests ?? null,
700
697
  isPrimary: participant.isPrimary,
701
698
  notes: participant.notes ?? null,
@@ -710,7 +707,6 @@ export const publicBookingsService = {
710
707
  email: participant.email ?? null,
711
708
  phone: participant.phone ?? null,
712
709
  preferredLanguage: participant.preferredLanguage ?? null,
713
- accessibilityNeeds: participant.accessibilityNeeds ?? null,
714
710
  specialRequests: participant.specialRequests ?? null,
715
711
  isPrimary: participant.isPrimary,
716
712
  notes: participant.notes ?? null,