@voyantjs/bookings 0.6.8 → 0.7.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/README.md +2 -2
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/pii.d.ts +10 -9
- package/dist/pii.d.ts.map +1 -1
- package/dist/pii.js +33 -33
- package/dist/products-ref.d.ts +93 -1
- package/dist/products-ref.d.ts.map +1 -1
- package/dist/products-ref.js +12 -1
- package/dist/routes-groups.d.ts +25 -5
- package/dist/routes-groups.d.ts.map +1 -1
- package/dist/routes-groups.js +3 -3
- package/dist/routes-public.d.ts +19 -21
- package/dist/routes-public.d.ts.map +1 -1
- package/dist/routes-public.js +1 -1
- package/dist/routes-shared.d.ts +3 -2
- package/dist/routes-shared.d.ts.map +1 -1
- package/dist/routes.d.ts +283 -188
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +89 -102
- package/dist/schema/travel-details.d.ts +27 -27
- package/dist/schema/travel-details.d.ts.map +1 -1
- package/dist/schema/travel-details.js +19 -14
- package/dist/schema-core.d.ts +194 -305
- package/dist/schema-core.d.ts.map +1 -1
- package/dist/schema-core.js +19 -10
- package/dist/schema-items.d.ts +15 -15
- package/dist/schema-items.d.ts.map +1 -1
- package/dist/schema-items.js +12 -12
- package/dist/schema-operations.d.ts +1 -1
- package/dist/schema-operations.js +3 -3
- package/dist/schema-relations.d.ts +26 -9
- package/dist/schema-relations.d.ts.map +1 -1
- package/dist/schema-relations.js +36 -21
- package/dist/schema-shared.d.ts +3 -2
- package/dist/schema-shared.d.ts.map +1 -1
- package/dist/schema-shared.js +4 -5
- package/dist/schema-staff.d.ts +267 -0
- package/dist/schema-staff.d.ts.map +1 -0
- package/dist/schema-staff.js +31 -0
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +1 -0
- package/dist/service-groups.d.ts +3 -7
- package/dist/service-groups.d.ts.map +1 -1
- package/dist/service-groups.js +6 -10
- package/dist/service-public.d.ts +102 -55
- package/dist/service-public.d.ts.map +1 -1
- package/dist/service-public.js +119 -54
- package/dist/service.d.ts +327 -104
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +530 -130
- package/dist/transactions-ref.d.ts +930 -66
- package/dist/transactions-ref.d.ts.map +1 -1
- package/dist/transactions-ref.js +56 -2
- package/dist/validation-public.d.ts +29 -69
- package/dist/validation-public.d.ts.map +1 -1
- package/dist/validation-public.js +21 -20
- package/dist/validation-shared.d.ts +4 -5
- package/dist/validation-shared.d.ts.map +1 -1
- package/dist/validation-shared.js +2 -10
- package/dist/validation.d.ts +248 -44
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +103 -28
- package/package.json +6 -6
package/dist/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AAqM7C,eAAO,MAAM,aAAa
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AAqM7C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iDAi1Ba,CAAA;AAEvC,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAA;AAChD,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAA"}
|
package/dist/routes.js
CHANGED
|
@@ -6,8 +6,8 @@ import { bookingGroupRoutes } from "./routes-groups.js";
|
|
|
6
6
|
import { bookingPiiAccessLog } from "./schema.js";
|
|
7
7
|
import { bookingsService } from "./service.js";
|
|
8
8
|
import { bookingGroupsService } from "./service-groups.js";
|
|
9
|
-
import { publicBookingsService } from "./service-public.js";
|
|
10
|
-
import { bookingListQuerySchema, cancelBookingSchema, confirmBookingSchema, convertProductSchema, createBookingSchema, expireBookingSchema, expireStaleBookingsSchema, extendBookingHoldSchema, insertBookingDocumentSchema, insertBookingFulfillmentSchema,
|
|
9
|
+
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
11
|
function hasPiiScope(scopes, action) {
|
|
12
12
|
if (!scopes || scopes.length === 0) {
|
|
13
13
|
return false;
|
|
@@ -22,7 +22,7 @@ async function logBookingPiiAccess(c, input) {
|
|
|
22
22
|
.insert(bookingPiiAccessLog)
|
|
23
23
|
.values({
|
|
24
24
|
bookingId: input.bookingId ?? null,
|
|
25
|
-
|
|
25
|
+
travelerId: input.travelerId ?? null,
|
|
26
26
|
actorId: c.get("userId") ?? null,
|
|
27
27
|
actorType: c.get("actor") ?? null,
|
|
28
28
|
callerType: c.get("callerType") ?? null,
|
|
@@ -114,7 +114,7 @@ function createAuditedBookingPiiService(c, bookingId) {
|
|
|
114
114
|
onAudit: async (event) => {
|
|
115
115
|
await logBookingPiiAccess(c, {
|
|
116
116
|
bookingId,
|
|
117
|
-
|
|
117
|
+
travelerId: event.travelerId,
|
|
118
118
|
action: event.action === "encrypt"
|
|
119
119
|
? "update"
|
|
120
120
|
: event.action === "decrypt"
|
|
@@ -137,7 +137,24 @@ export const bookingRoutes = new Hono()
|
|
|
137
137
|
const query = parseQuery(c, bookingListQuerySchema);
|
|
138
138
|
return c.json(await bookingsService.listBookings(c.get("db"), query));
|
|
139
139
|
})
|
|
140
|
-
// 1a.
|
|
140
|
+
// 1a. POST /pricing-preview — Resolve a pricing snapshot without creating a session.
|
|
141
|
+
.post("/pricing-preview", async (c) => {
|
|
142
|
+
const body = await parseJsonBody(c, pricingPreviewSchema);
|
|
143
|
+
const snapshot = await resolveSessionPricingSnapshot(c.get("db"), body.productId, {
|
|
144
|
+
optionId: body.optionId ?? undefined,
|
|
145
|
+
catalogId: body.catalogId ?? undefined,
|
|
146
|
+
});
|
|
147
|
+
if (!snapshot) {
|
|
148
|
+
return c.json({ error: "Pricing unavailable for this selection" }, 404);
|
|
149
|
+
}
|
|
150
|
+
return c.json({ data: snapshot });
|
|
151
|
+
})
|
|
152
|
+
// 1b. GET /aggregates — Pre-aggregated dashboard metrics
|
|
153
|
+
.get("/aggregates", async (c) => {
|
|
154
|
+
const query = parseQuery(c, bookingAggregatesQuerySchema);
|
|
155
|
+
return c.json({ data: await bookingsService.getBookingAggregates(c.get("db"), query) });
|
|
156
|
+
})
|
|
157
|
+
// 1b. GET /overview — Internal/admin booking overview lookup
|
|
141
158
|
.get("/overview", async (c) => {
|
|
142
159
|
const overview = await publicBookingsService.getOverviewByLookup(c.get("db"), parseQuery(c, internalBookingOverviewLookupQuerySchema));
|
|
143
160
|
if (!overview) {
|
|
@@ -268,7 +285,7 @@ export const bookingRoutes = new Hono()
|
|
|
268
285
|
// ==========================================================================
|
|
269
286
|
// 7. PATCH /:id/status — Change booking status
|
|
270
287
|
.patch("/:id/status", async (c) => {
|
|
271
|
-
const result = await bookingsService.updateBookingStatus(c.get("db"), c.req.param("id"), await parseJsonBody(c, updateBookingStatusSchema), c.get("userId"));
|
|
288
|
+
const result = await bookingsService.updateBookingStatus(c.get("db"), c.req.param("id"), await parseJsonBody(c, updateBookingStatusSchema), c.get("userId"), { eventBus: c.get("eventBus") });
|
|
272
289
|
if (result.status === "not_found") {
|
|
273
290
|
return c.json({ error: "Booking not found" }, 404);
|
|
274
291
|
}
|
|
@@ -282,7 +299,7 @@ export const bookingRoutes = new Hono()
|
|
|
282
299
|
})
|
|
283
300
|
// 8. POST /:id/confirm — Confirm an on-hold booking
|
|
284
301
|
.post("/:id/confirm", async (c) => {
|
|
285
|
-
const result = await bookingsService.confirmBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, confirmBookingSchema), c.get("userId"));
|
|
302
|
+
const result = await bookingsService.confirmBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, confirmBookingSchema), c.get("userId"), { eventBus: c.get("eventBus") });
|
|
286
303
|
if (result.status === "not_found") {
|
|
287
304
|
return c.json({ error: "Booking not found" }, 404);
|
|
288
305
|
}
|
|
@@ -316,7 +333,7 @@ export const bookingRoutes = new Hono()
|
|
|
316
333
|
})
|
|
317
334
|
// 10. POST /:id/expire — Expire an on-hold booking
|
|
318
335
|
.post("/:id/expire", async (c) => {
|
|
319
|
-
const result = await bookingsService.expireBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, expireBookingSchema), c.get("userId"));
|
|
336
|
+
const result = await bookingsService.expireBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, expireBookingSchema), c.get("userId"), { eventBus: c.get("eventBus"), cause: "route" });
|
|
320
337
|
if (result.status === "not_found") {
|
|
321
338
|
return c.json({ error: "Booking not found" }, 404);
|
|
322
339
|
}
|
|
@@ -330,11 +347,11 @@ export const bookingRoutes = new Hono()
|
|
|
330
347
|
})
|
|
331
348
|
// 10b. POST /expire-stale — Expire all stale on-hold bookings up to a cutoff
|
|
332
349
|
.post("/expire-stale", async (c) => {
|
|
333
|
-
return c.json(await bookingsService.expireStaleBookings(c.get("db"), await parseJsonBody(c, expireStaleBookingsSchema), c.get("userId")));
|
|
350
|
+
return c.json(await bookingsService.expireStaleBookings(c.get("db"), await parseJsonBody(c, expireStaleBookingsSchema), c.get("userId"), { eventBus: c.get("eventBus") }));
|
|
334
351
|
})
|
|
335
352
|
// 11. POST /:id/cancel — Cancel a booking and release allocations
|
|
336
353
|
.post("/:id/cancel", async (c) => {
|
|
337
|
-
const result = await bookingsService.cancelBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, cancelBookingSchema), c.get("userId"));
|
|
354
|
+
const result = await bookingsService.cancelBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, cancelBookingSchema), c.get("userId"), { eventBus: c.get("eventBus") });
|
|
338
355
|
if (result.status === "not_found") {
|
|
339
356
|
return c.json({ error: "Booking not found" }, 404);
|
|
340
357
|
}
|
|
@@ -346,50 +363,48 @@ export const bookingRoutes = new Hono()
|
|
|
346
363
|
}
|
|
347
364
|
return c.json({ error: "Unable to cancel booking" }, 400);
|
|
348
365
|
})
|
|
349
|
-
// ==========================================================================
|
|
350
|
-
// Participants
|
|
351
|
-
// ==========================================================================
|
|
352
366
|
// 12. GET /:id/allocations — List booking allocations
|
|
353
367
|
.get("/:id/allocations", async (c) => {
|
|
354
368
|
return c.json({ data: await bookingsService.listAllocations(c.get("db"), c.req.param("id")) });
|
|
355
369
|
})
|
|
356
|
-
//
|
|
357
|
-
|
|
358
|
-
|
|
370
|
+
// ==========================================================================
|
|
371
|
+
// Travelers
|
|
372
|
+
// ==========================================================================
|
|
373
|
+
.get("/:id/travelers", async (c) => {
|
|
374
|
+
return c.json({ data: await bookingsService.listTravelers(c.get("db"), c.req.param("id")) });
|
|
359
375
|
})
|
|
360
|
-
|
|
361
|
-
.get("/:id/participants/:participantId/travel-details", async (c) => {
|
|
376
|
+
.get("/:id/travelers/:travelerId/travel-details", async (c) => {
|
|
362
377
|
const auth = await authorizeBookingPiiAccess(c, {
|
|
363
378
|
bookingId: c.req.param("id"),
|
|
364
|
-
|
|
379
|
+
travelerId: c.req.param("travelerId"),
|
|
365
380
|
action: "read",
|
|
366
381
|
});
|
|
367
382
|
if (!auth.allowed) {
|
|
368
383
|
return auth.response;
|
|
369
384
|
}
|
|
370
|
-
const
|
|
371
|
-
if (!
|
|
385
|
+
const traveler = await bookingsService.getTravelerRecordById(c.get("db"), c.req.param("id"), c.req.param("travelerId"));
|
|
386
|
+
if (!traveler) {
|
|
372
387
|
await logBookingPiiAccess(c, {
|
|
373
388
|
bookingId: c.req.param("id"),
|
|
374
|
-
|
|
389
|
+
travelerId: c.req.param("travelerId"),
|
|
375
390
|
action: "read",
|
|
376
391
|
outcome: "denied",
|
|
377
392
|
reason: "participant_not_found",
|
|
378
393
|
});
|
|
379
|
-
return c.json({ error: "
|
|
394
|
+
return c.json({ error: "Traveler not found" }, 404);
|
|
380
395
|
}
|
|
381
396
|
try {
|
|
382
|
-
const pii = createAuditedBookingPiiService(c,
|
|
383
|
-
const details = await pii.
|
|
397
|
+
const pii = createAuditedBookingPiiService(c, traveler.bookingId);
|
|
398
|
+
const details = await pii.getTravelerTravelDetails(c.get("db"), traveler.id, c.get("userId"));
|
|
384
399
|
if (!details) {
|
|
385
400
|
await logBookingPiiAccess(c, {
|
|
386
|
-
bookingId:
|
|
387
|
-
|
|
401
|
+
bookingId: traveler.bookingId,
|
|
402
|
+
travelerId: traveler.id,
|
|
388
403
|
action: "read",
|
|
389
404
|
outcome: "denied",
|
|
390
405
|
reason: "travel_details_not_found",
|
|
391
406
|
});
|
|
392
|
-
return c.json({ error: "
|
|
407
|
+
return c.json({ error: "Traveler travel details not found" }, 404);
|
|
393
408
|
}
|
|
394
409
|
return c.json({ data: details });
|
|
395
410
|
}
|
|
@@ -397,40 +412,38 @@ export const bookingRoutes = new Hono()
|
|
|
397
412
|
return handleKmsConfigError(c, error);
|
|
398
413
|
}
|
|
399
414
|
})
|
|
400
|
-
|
|
401
|
-
.
|
|
402
|
-
const row = await bookingsService.createParticipant(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertParticipantSchema), c.get("userId"));
|
|
415
|
+
.post("/:id/travelers", async (c) => {
|
|
416
|
+
const row = await bookingsService.createTraveler(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertTravelerSchema), c.get("userId"));
|
|
403
417
|
if (!row) {
|
|
404
418
|
return c.json({ error: "Booking not found" }, 404);
|
|
405
419
|
}
|
|
406
420
|
return c.json({ data: row }, 201);
|
|
407
421
|
})
|
|
408
|
-
|
|
409
|
-
.patch("/:id/participants/:participantId/travel-details", async (c) => {
|
|
422
|
+
.patch("/:id/travelers/:travelerId/travel-details", async (c) => {
|
|
410
423
|
const auth = await authorizeBookingPiiAccess(c, {
|
|
411
424
|
bookingId: c.req.param("id"),
|
|
412
|
-
|
|
425
|
+
travelerId: c.req.param("travelerId"),
|
|
413
426
|
action: "update",
|
|
414
427
|
});
|
|
415
428
|
if (!auth.allowed) {
|
|
416
429
|
return auth.response;
|
|
417
430
|
}
|
|
418
|
-
const
|
|
419
|
-
if (!
|
|
431
|
+
const traveler = await bookingsService.getTravelerRecordById(c.get("db"), c.req.param("id"), c.req.param("travelerId"));
|
|
432
|
+
if (!traveler) {
|
|
420
433
|
await logBookingPiiAccess(c, {
|
|
421
434
|
bookingId: c.req.param("id"),
|
|
422
|
-
|
|
435
|
+
travelerId: c.req.param("travelerId"),
|
|
423
436
|
action: "update",
|
|
424
437
|
outcome: "denied",
|
|
425
438
|
reason: "participant_not_found",
|
|
426
439
|
});
|
|
427
|
-
return c.json({ error: "
|
|
440
|
+
return c.json({ error: "Traveler not found" }, 404);
|
|
428
441
|
}
|
|
429
442
|
try {
|
|
430
|
-
const pii = createAuditedBookingPiiService(c,
|
|
431
|
-
const row = await pii.
|
|
443
|
+
const pii = createAuditedBookingPiiService(c, traveler.bookingId);
|
|
444
|
+
const row = await pii.upsertTravelerTravelDetails(c.get("db"), traveler.id, await parseJsonBody(c, upsertTravelerTravelDetailsSchema), c.get("userId"));
|
|
432
445
|
if (!row) {
|
|
433
|
-
return c.json({ error: "
|
|
446
|
+
return c.json({ error: "Traveler not found" }, 404);
|
|
434
447
|
}
|
|
435
448
|
return c.json({ data: row });
|
|
436
449
|
}
|
|
@@ -438,40 +451,38 @@ export const bookingRoutes = new Hono()
|
|
|
438
451
|
return handleKmsConfigError(c, error);
|
|
439
452
|
}
|
|
440
453
|
})
|
|
441
|
-
|
|
442
|
-
.
|
|
443
|
-
const row = await bookingsService.updateParticipant(c.get("db"), c.req.param("participantId"), await parseJsonBody(c, updateParticipantSchema));
|
|
454
|
+
.patch("/:id/travelers/:travelerId", async (c) => {
|
|
455
|
+
const row = await bookingsService.updateTraveler(c.get("db"), c.req.param("travelerId"), await parseJsonBody(c, updateTravelerSchema));
|
|
444
456
|
if (!row) {
|
|
445
|
-
return c.json({ error: "
|
|
457
|
+
return c.json({ error: "Traveler not found" }, 404);
|
|
446
458
|
}
|
|
447
459
|
return c.json({ data: row });
|
|
448
460
|
})
|
|
449
|
-
|
|
450
|
-
.delete("/:id/participants/:participantId/travel-details", async (c) => {
|
|
461
|
+
.delete("/:id/travelers/:travelerId/travel-details", async (c) => {
|
|
451
462
|
const auth = await authorizeBookingPiiAccess(c, {
|
|
452
463
|
bookingId: c.req.param("id"),
|
|
453
|
-
|
|
464
|
+
travelerId: c.req.param("travelerId"),
|
|
454
465
|
action: "delete",
|
|
455
466
|
});
|
|
456
467
|
if (!auth.allowed) {
|
|
457
468
|
return auth.response;
|
|
458
469
|
}
|
|
459
|
-
const
|
|
460
|
-
if (!
|
|
470
|
+
const traveler = await bookingsService.getTravelerRecordById(c.get("db"), c.req.param("id"), c.req.param("travelerId"));
|
|
471
|
+
if (!traveler) {
|
|
461
472
|
await logBookingPiiAccess(c, {
|
|
462
473
|
bookingId: c.req.param("id"),
|
|
463
|
-
|
|
474
|
+
travelerId: c.req.param("travelerId"),
|
|
464
475
|
action: "delete",
|
|
465
476
|
outcome: "denied",
|
|
466
477
|
reason: "participant_not_found",
|
|
467
478
|
});
|
|
468
|
-
return c.json({ error: "
|
|
479
|
+
return c.json({ error: "Traveler not found" }, 404);
|
|
469
480
|
}
|
|
470
481
|
try {
|
|
471
|
-
const pii = createAuditedBookingPiiService(c,
|
|
472
|
-
const row = await pii.
|
|
482
|
+
const pii = createAuditedBookingPiiService(c, traveler.bookingId);
|
|
483
|
+
const row = await pii.deleteTravelerTravelDetails(c.get("db"), traveler.id, c.get("userId"));
|
|
473
484
|
if (!row) {
|
|
474
|
-
return c.json({ error: "
|
|
485
|
+
return c.json({ error: "Traveler travel details not found" }, 404);
|
|
475
486
|
}
|
|
476
487
|
return c.json({ success: true }, 200);
|
|
477
488
|
}
|
|
@@ -479,42 +490,10 @@ export const bookingRoutes = new Hono()
|
|
|
479
490
|
return handleKmsConfigError(c, error);
|
|
480
491
|
}
|
|
481
492
|
})
|
|
482
|
-
|
|
483
|
-
.
|
|
484
|
-
const row = await bookingsService.deleteParticipant(c.get("db"), c.req.param("participantId"));
|
|
485
|
-
if (!row) {
|
|
486
|
-
return c.json({ error: "Participant not found" }, 404);
|
|
487
|
-
}
|
|
488
|
-
return c.json({ success: true }, 200);
|
|
489
|
-
})
|
|
490
|
-
// ==========================================================================
|
|
491
|
-
// Passengers (legacy compatibility)
|
|
492
|
-
// ==========================================================================
|
|
493
|
-
// 12. GET /:id/passengers — List passengers
|
|
494
|
-
.get("/:id/passengers", async (c) => {
|
|
495
|
-
return c.json({ data: await bookingsService.listPassengers(c.get("db"), c.req.param("id")) });
|
|
496
|
-
})
|
|
497
|
-
// 13. POST /:id/passengers — Add passenger
|
|
498
|
-
.post("/:id/passengers", async (c) => {
|
|
499
|
-
const row = await bookingsService.createPassenger(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertPassengerSchema), c.get("userId"));
|
|
500
|
-
if (!row) {
|
|
501
|
-
return c.json({ error: "Booking not found" }, 404);
|
|
502
|
-
}
|
|
503
|
-
return c.json({ data: row }, 201);
|
|
504
|
-
})
|
|
505
|
-
// 14. PATCH /:id/passengers/:passengerId — Update passenger
|
|
506
|
-
.patch("/:id/passengers/:passengerId", async (c) => {
|
|
507
|
-
const row = await bookingsService.updatePassenger(c.get("db"), c.req.param("passengerId"), await parseJsonBody(c, updatePassengerSchema));
|
|
508
|
-
if (!row) {
|
|
509
|
-
return c.json({ error: "Passenger not found" }, 404);
|
|
510
|
-
}
|
|
511
|
-
return c.json({ data: row });
|
|
512
|
-
})
|
|
513
|
-
// 15. DELETE /:id/passengers/:passengerId — Delete passenger
|
|
514
|
-
.delete("/:id/passengers/:passengerId", async (c) => {
|
|
515
|
-
const row = await bookingsService.deletePassenger(c.get("db"), c.req.param("passengerId"));
|
|
493
|
+
.delete("/:id/travelers/:travelerId", async (c) => {
|
|
494
|
+
const row = await bookingsService.deleteTraveler(c.get("db"), c.req.param("travelerId"));
|
|
516
495
|
if (!row) {
|
|
517
|
-
return c.json({ error: "
|
|
496
|
+
return c.json({ error: "Traveler not found" }, 404);
|
|
518
497
|
}
|
|
519
498
|
return c.json({ success: true }, 200);
|
|
520
499
|
})
|
|
@@ -549,25 +528,25 @@ export const bookingRoutes = new Hono()
|
|
|
549
528
|
}
|
|
550
529
|
return c.json({ success: true }, 200);
|
|
551
530
|
})
|
|
552
|
-
// 20. GET /:id/items/:itemId/
|
|
553
|
-
.get("/:id/items/:itemId/
|
|
531
|
+
// 20. GET /:id/items/:itemId/travelers — List item travelers
|
|
532
|
+
.get("/:id/items/:itemId/travelers", async (c) => {
|
|
554
533
|
return c.json({
|
|
555
534
|
data: await bookingsService.listItemParticipants(c.get("db"), c.req.param("itemId")),
|
|
556
535
|
});
|
|
557
536
|
})
|
|
558
|
-
// 21. POST /:id/items/:itemId/
|
|
559
|
-
.post("/:id/items/:itemId/
|
|
560
|
-
const row = await bookingsService.addItemParticipant(c.get("db"), c.req.param("itemId"), await parseJsonBody(c,
|
|
537
|
+
// 21. POST /:id/items/:itemId/travelers — Link traveler to item
|
|
538
|
+
.post("/:id/items/:itemId/travelers", async (c) => {
|
|
539
|
+
const row = await bookingsService.addItemParticipant(c.get("db"), c.req.param("itemId"), await parseJsonBody(c, insertBookingItemTravelerSchema));
|
|
561
540
|
if (!row) {
|
|
562
|
-
return c.json({ error: "Booking item or
|
|
541
|
+
return c.json({ error: "Booking item or traveler not found" }, 404);
|
|
563
542
|
}
|
|
564
543
|
return c.json({ data: row }, 201);
|
|
565
544
|
})
|
|
566
|
-
// 22. DELETE /:id/items/:itemId/
|
|
567
|
-
.delete("/:id/items/:itemId/
|
|
545
|
+
// 22. DELETE /:id/items/:itemId/travelers/:linkId — Unlink traveler from item
|
|
546
|
+
.delete("/:id/items/:itemId/travelers/:linkId", async (c) => {
|
|
568
547
|
const row = await bookingsService.removeItemParticipant(c.get("db"), c.req.param("linkId"));
|
|
569
548
|
if (!row) {
|
|
570
|
-
return c.json({ error: "Booking item
|
|
549
|
+
return c.json({ error: "Booking item traveler link not found" }, 404);
|
|
571
550
|
}
|
|
572
551
|
return c.json({ success: true }, 200);
|
|
573
552
|
})
|
|
@@ -602,14 +581,14 @@ export const bookingRoutes = new Hono()
|
|
|
602
581
|
.post("/:id/fulfillments", async (c) => {
|
|
603
582
|
const row = await bookingsService.issueFulfillment(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertBookingFulfillmentSchema), c.get("userId"));
|
|
604
583
|
if (!row) {
|
|
605
|
-
return c.json({ error: "Booking, item, or
|
|
584
|
+
return c.json({ error: "Booking, item, or traveler not found" }, 404);
|
|
606
585
|
}
|
|
607
586
|
return c.json({ data: row }, 201);
|
|
608
587
|
})
|
|
609
588
|
.patch("/:id/fulfillments/:fulfillmentId", async (c) => {
|
|
610
589
|
const row = await bookingsService.updateFulfillment(c.get("db"), c.req.param("id"), c.req.param("fulfillmentId"), await parseJsonBody(c, updateBookingFulfillmentSchema), c.get("userId"));
|
|
611
590
|
if (!row) {
|
|
612
|
-
return c.json({ error: "Fulfillment, item, or
|
|
591
|
+
return c.json({ error: "Fulfillment, item, or traveler not found" }, 404);
|
|
613
592
|
}
|
|
614
593
|
return c.json({ data: row });
|
|
615
594
|
})
|
|
@@ -624,7 +603,7 @@ export const bookingRoutes = new Hono()
|
|
|
624
603
|
.post("/:id/redemptions", async (c) => {
|
|
625
604
|
const row = await bookingsService.recordRedemption(c.get("db"), c.req.param("id"), await parseJsonBody(c, recordBookingRedemptionSchema), c.get("userId"));
|
|
626
605
|
if (!row) {
|
|
627
|
-
return c.json({ error: "Booking, item, or
|
|
606
|
+
return c.json({ error: "Booking, item, or traveler not found" }, 404);
|
|
628
607
|
}
|
|
629
608
|
return c.json({ data: row }, 201);
|
|
630
609
|
})
|
|
@@ -655,6 +634,14 @@ export const bookingRoutes = new Hono()
|
|
|
655
634
|
return c.json({ error: "Booking not found" }, 404);
|
|
656
635
|
}
|
|
657
636
|
return c.json({ data: row }, 201);
|
|
637
|
+
})
|
|
638
|
+
// 28b. DELETE /:id/notes/:noteId — Delete note
|
|
639
|
+
.delete("/:id/notes/:noteId", async (c) => {
|
|
640
|
+
const row = await bookingsService.deleteNote(c.get("db"), c.req.param("noteId"));
|
|
641
|
+
if (!row) {
|
|
642
|
+
return c.json({ error: "Note not found" }, 404);
|
|
643
|
+
}
|
|
644
|
+
return c.json({ success: true }, 200);
|
|
658
645
|
})
|
|
659
646
|
// ==========================================================================
|
|
660
647
|
// Documents
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const bookingTravelerIdentitySchema: z.ZodObject<{
|
|
3
3
|
nationality: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
4
4
|
passportNumber: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
5
5
|
passportExpiry: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
6
6
|
dateOfBirth: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
7
7
|
}, z.core.$strip>;
|
|
8
|
-
export declare const
|
|
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
|
|
12
|
-
|
|
11
|
+
export declare const decryptedBookingTravelerTravelDetailSchema: z.ZodObject<{
|
|
12
|
+
travelerId: z.ZodString;
|
|
13
13
|
nationality: z.ZodNullable<z.ZodString>;
|
|
14
14
|
passportNumber: z.ZodNullable<z.ZodString>;
|
|
15
15
|
passportExpiry: z.ZodNullable<z.ZodString>;
|
|
@@ -19,13 +19,13 @@ export declare const decryptedBookingParticipantTravelDetailSchema: z.ZodObject<
|
|
|
19
19
|
createdAt: z.ZodDate;
|
|
20
20
|
updatedAt: z.ZodDate;
|
|
21
21
|
}, z.core.$strip>;
|
|
22
|
-
export declare const
|
|
23
|
-
name: "
|
|
22
|
+
export declare const bookingTravelerTravelDetails: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
23
|
+
name: "booking_traveler_travel_details";
|
|
24
24
|
schema: undefined;
|
|
25
25
|
columns: {
|
|
26
|
-
|
|
27
|
-
name: "
|
|
28
|
-
tableName: "
|
|
26
|
+
travelerId: import("drizzle-orm/pg-core").PgColumn<{
|
|
27
|
+
name: "traveler_id";
|
|
28
|
+
tableName: "booking_traveler_travel_details";
|
|
29
29
|
dataType: "string";
|
|
30
30
|
columnType: "PgText";
|
|
31
31
|
data: string;
|
|
@@ -42,7 +42,7 @@ export declare const bookingParticipantTravelDetails: import("drizzle-orm/pg-cor
|
|
|
42
42
|
}, {}, {}>;
|
|
43
43
|
identityEncrypted: import("drizzle-orm/pg-core").PgColumn<{
|
|
44
44
|
name: "identity_encrypted";
|
|
45
|
-
tableName: "
|
|
45
|
+
tableName: "booking_traveler_travel_details";
|
|
46
46
|
dataType: "json";
|
|
47
47
|
columnType: "PgJsonb";
|
|
48
48
|
data: {
|
|
@@ -65,7 +65,7 @@ export declare const bookingParticipantTravelDetails: import("drizzle-orm/pg-cor
|
|
|
65
65
|
}>;
|
|
66
66
|
dietaryEncrypted: import("drizzle-orm/pg-core").PgColumn<{
|
|
67
67
|
name: "dietary_encrypted";
|
|
68
|
-
tableName: "
|
|
68
|
+
tableName: "booking_traveler_travel_details";
|
|
69
69
|
dataType: "json";
|
|
70
70
|
columnType: "PgJsonb";
|
|
71
71
|
data: {
|
|
@@ -88,7 +88,7 @@ export declare const bookingParticipantTravelDetails: import("drizzle-orm/pg-cor
|
|
|
88
88
|
}>;
|
|
89
89
|
isLeadTraveler: import("drizzle-orm/pg-core").PgColumn<{
|
|
90
90
|
name: "is_lead_traveler";
|
|
91
|
-
tableName: "
|
|
91
|
+
tableName: "booking_traveler_travel_details";
|
|
92
92
|
dataType: "boolean";
|
|
93
93
|
columnType: "PgBoolean";
|
|
94
94
|
data: boolean;
|
|
@@ -105,7 +105,7 @@ export declare const bookingParticipantTravelDetails: import("drizzle-orm/pg-cor
|
|
|
105
105
|
}, {}, {}>;
|
|
106
106
|
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
107
107
|
name: "created_at";
|
|
108
|
-
tableName: "
|
|
108
|
+
tableName: "booking_traveler_travel_details";
|
|
109
109
|
dataType: "date";
|
|
110
110
|
columnType: "PgTimestamp";
|
|
111
111
|
data: Date;
|
|
@@ -122,7 +122,7 @@ export declare const bookingParticipantTravelDetails: import("drizzle-orm/pg-cor
|
|
|
122
122
|
}, {}, {}>;
|
|
123
123
|
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
124
124
|
name: "updated_at";
|
|
125
|
-
tableName: "
|
|
125
|
+
tableName: "booking_traveler_travel_details";
|
|
126
126
|
dataType: "date";
|
|
127
127
|
columnType: "PgTimestamp";
|
|
128
128
|
data: Date;
|
|
@@ -140,17 +140,17 @@ export declare const bookingParticipantTravelDetails: import("drizzle-orm/pg-cor
|
|
|
140
140
|
};
|
|
141
141
|
dialect: "pg";
|
|
142
142
|
}>;
|
|
143
|
-
export declare const
|
|
144
|
-
participantId: z.ZodString;
|
|
145
|
-
identityEncrypted: z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
146
|
-
enc: z.ZodString;
|
|
147
|
-
}, z.core.$strip>>>>;
|
|
143
|
+
export declare const bookingTravelerTravelDetailInsertSchema: z.ZodObject<{
|
|
148
144
|
dietaryEncrypted: z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
149
145
|
enc: z.ZodString;
|
|
150
146
|
}, z.core.$strip>>>>;
|
|
151
147
|
isLeadTraveler: z.ZodDefault<z.ZodBoolean>;
|
|
148
|
+
identityEncrypted: z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
149
|
+
enc: z.ZodString;
|
|
150
|
+
}, z.core.$strip>>>>;
|
|
151
|
+
travelerId: z.ZodString;
|
|
152
152
|
}, z.core.$strip>;
|
|
153
|
-
export declare const
|
|
153
|
+
export declare const bookingTravelerTravelDetailUpdateSchema: z.ZodObject<{
|
|
154
154
|
dietaryEncrypted: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
155
155
|
enc: z.ZodString;
|
|
156
156
|
}, z.core.$strip>>>>>;
|
|
@@ -159,8 +159,8 @@ export declare const bookingParticipantTravelDetailUpdateSchema: z.ZodObject<{
|
|
|
159
159
|
enc: z.ZodString;
|
|
160
160
|
}, z.core.$strip>>>>>;
|
|
161
161
|
}, z.core.$strip>;
|
|
162
|
-
export declare const
|
|
163
|
-
|
|
162
|
+
export declare const bookingTravelerTravelDetailSelectSchema: z.ZodObject<{
|
|
163
|
+
travelerId: z.ZodString;
|
|
164
164
|
identityEncrypted: z.ZodNullable<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
165
165
|
enc: z.ZodString;
|
|
166
166
|
}, z.core.$strip>>>>;
|
|
@@ -171,9 +171,9 @@ export declare const bookingParticipantTravelDetailSelectSchema: z.ZodObject<{
|
|
|
171
171
|
createdAt: z.ZodDate;
|
|
172
172
|
updatedAt: z.ZodDate;
|
|
173
173
|
}, z.core.$strip>;
|
|
174
|
-
export type
|
|
175
|
-
export type
|
|
176
|
-
export type
|
|
177
|
-
export type
|
|
178
|
-
export type
|
|
174
|
+
export type BookingTravelerIdentity = z.infer<typeof bookingTravelerIdentitySchema>;
|
|
175
|
+
export type BookingTravelerDietary = z.infer<typeof bookingTravelerDietarySchema>;
|
|
176
|
+
export type BookingTravelerTravelDetail = z.infer<typeof bookingTravelerTravelDetailSelectSchema>;
|
|
177
|
+
export type NewBookingTravelerTravelDetail = z.infer<typeof bookingTravelerTravelDetailInsertSchema>;
|
|
178
|
+
export type DecryptedBookingTravelerTravelDetail = z.infer<typeof decryptedBookingTravelerTravelDetailSchema>;
|
|
179
179
|
//# sourceMappingURL=travel-details.d.ts.map
|
|
@@ -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,
|
|
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,18 +1,18 @@
|
|
|
1
1
|
import { kmsEnvelopeSchema } from "@voyantjs/db/schema/iam";
|
|
2
2
|
import { boolean, index, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import {
|
|
5
|
-
export const
|
|
4
|
+
import { bookingTravelers } from "../schema.js";
|
|
5
|
+
export const bookingTravelerIdentitySchema = z.object({
|
|
6
6
|
nationality: z.string().optional().nullable(),
|
|
7
7
|
passportNumber: z.string().optional().nullable(),
|
|
8
8
|
passportExpiry: z.string().optional().nullable(),
|
|
9
9
|
dateOfBirth: z.string().optional().nullable(),
|
|
10
10
|
});
|
|
11
|
-
export const
|
|
11
|
+
export const bookingTravelerDietarySchema = z.object({
|
|
12
12
|
dietaryRequirements: z.string().optional().nullable(),
|
|
13
13
|
});
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const decryptedBookingTravelerTravelDetailRecordSchema = z.object({
|
|
15
|
+
travelerId: z.string(),
|
|
16
16
|
nationality: z.string().nullable(),
|
|
17
17
|
passportNumber: z.string().nullable(),
|
|
18
18
|
passportExpiry: z.string().nullable(),
|
|
@@ -22,27 +22,32 @@ export const decryptedBookingParticipantTravelDetailSchema = z.object({
|
|
|
22
22
|
createdAt: z.date(),
|
|
23
23
|
updatedAt: z.date(),
|
|
24
24
|
});
|
|
25
|
-
export const
|
|
26
|
-
|
|
25
|
+
export const decryptedBookingTravelerTravelDetailSchema = decryptedBookingTravelerTravelDetailRecordSchema;
|
|
26
|
+
export const bookingTravelerTravelDetails = pgTable("booking_traveler_travel_details", {
|
|
27
|
+
travelerId: text("traveler_id")
|
|
27
28
|
.primaryKey()
|
|
28
|
-
.references(() =>
|
|
29
|
+
.references(() => bookingTravelers.id, { onDelete: "cascade" }),
|
|
29
30
|
identityEncrypted: jsonb("identity_encrypted").$type(),
|
|
30
31
|
dietaryEncrypted: jsonb("dietary_encrypted").$type(),
|
|
31
32
|
isLeadTraveler: boolean("is_lead_traveler").notNull().default(false),
|
|
32
33
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
33
34
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
34
35
|
}, (t) => [index("idx_bptd_lead_traveler").on(t.isLeadTraveler)]);
|
|
35
|
-
const
|
|
36
|
-
|
|
36
|
+
const bookingTravelerTravelDetailRecordCoreSchema = z.object({
|
|
37
|
+
travelerId: z.string().min(1),
|
|
37
38
|
identityEncrypted: kmsEnvelopeSchema.optional().nullable(),
|
|
38
39
|
dietaryEncrypted: kmsEnvelopeSchema.optional().nullable(),
|
|
39
40
|
isLeadTraveler: z.boolean().default(false),
|
|
40
41
|
});
|
|
41
|
-
export const
|
|
42
|
-
|
|
42
|
+
export const bookingTravelerTravelDetailInsertSchema = bookingTravelerTravelDetailRecordCoreSchema
|
|
43
|
+
.omit({ travelerId: true })
|
|
44
|
+
.extend({
|
|
45
|
+
travelerId: z.string().min(1),
|
|
46
|
+
});
|
|
47
|
+
export const bookingTravelerTravelDetailUpdateSchema = bookingTravelerTravelDetailRecordCoreSchema
|
|
43
48
|
.partial()
|
|
44
|
-
.omit({
|
|
45
|
-
export const
|
|
49
|
+
.omit({ travelerId: true });
|
|
50
|
+
export const bookingTravelerTravelDetailSelectSchema = bookingTravelerTravelDetailRecordCoreSchema.extend({
|
|
46
51
|
createdAt: z.date(),
|
|
47
52
|
updatedAt: z.date(),
|
|
48
53
|
});
|