@voyantjs/bookings 0.5.0 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extensions/suppliers.d.ts.map +1 -1
- package/dist/extensions/suppliers.js +3 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -6
- package/dist/route-runtime.d.ts +8 -0
- package/dist/route-runtime.d.ts.map +1 -0
- package/dist/route-runtime.js +17 -0
- package/dist/routes-groups.d.ts +2 -2
- package/dist/routes-groups.d.ts.map +1 -1
- package/dist/routes-groups.js +5 -4
- package/dist/routes-public.d.ts +5 -5
- package/dist/routes-public.d.ts.map +1 -1
- package/dist/routes-public.js +8 -7
- package/dist/routes-shared.d.ts +2 -0
- package/dist/routes-shared.d.ts.map +1 -1
- package/dist/routes.d.ts +37 -258
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +88 -91
- package/dist/schema-core.d.ts +1 -1
- package/dist/schema-items.d.ts +2 -2
- package/dist/service-public.d.ts +14 -14
- package/dist/service.d.ts +21 -21
- package/dist/validation-public.d.ts +11 -11
- package/dist/validation-shared.d.ts +3 -3
- package/dist/validation.d.ts +12 -12
- package/package.json +6 -6
package/dist/routes.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ForbiddenApiError, handleApiError, normalizeValidationError, parseJsonBody, parseQuery, requireUserId, UnauthorizedApiError, } from "@voyantjs/hono";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { createBookingPiiService } from "./pii.js";
|
|
4
|
+
import { BOOKING_ROUTE_RUNTIME_CONTAINER_KEY, buildBookingRouteRuntime, } from "./route-runtime.js";
|
|
4
5
|
import { bookingGroupRoutes } from "./routes-groups.js";
|
|
5
|
-
import { getRuntimeEnv } from "./routes-shared.js";
|
|
6
6
|
import { bookingPiiAccessLog } from "./schema.js";
|
|
7
7
|
import { bookingsService } from "./service.js";
|
|
8
8
|
import { bookingGroupsService } from "./service-groups.js";
|
|
@@ -43,7 +43,10 @@ async function authorizeBookingPiiAccess(c, input) {
|
|
|
43
43
|
outcome: "denied",
|
|
44
44
|
reason: "missing_user",
|
|
45
45
|
});
|
|
46
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
allowed: false,
|
|
48
|
+
response: handleApiError(new UnauthorizedApiError(), c),
|
|
49
|
+
};
|
|
47
50
|
}
|
|
48
51
|
const customAuthorizer = c.get("authorizeBookingPii");
|
|
49
52
|
if (customAuthorizer) {
|
|
@@ -62,7 +65,10 @@ async function authorizeBookingPiiAccess(c, input) {
|
|
|
62
65
|
outcome: "denied",
|
|
63
66
|
reason: "custom_policy_denied",
|
|
64
67
|
});
|
|
65
|
-
return {
|
|
68
|
+
return {
|
|
69
|
+
allowed: false,
|
|
70
|
+
response: handleApiError(new ForbiddenApiError(), c),
|
|
71
|
+
};
|
|
66
72
|
}
|
|
67
73
|
return { allowed: true };
|
|
68
74
|
}
|
|
@@ -76,7 +82,10 @@ async function authorizeBookingPiiAccess(c, input) {
|
|
|
76
82
|
reason: "insufficient_scope",
|
|
77
83
|
metadata: { actor: actor ?? null },
|
|
78
84
|
});
|
|
79
|
-
return {
|
|
85
|
+
return {
|
|
86
|
+
allowed: false,
|
|
87
|
+
response: handleApiError(new ForbiddenApiError(), c),
|
|
88
|
+
};
|
|
80
89
|
}
|
|
81
90
|
return { allowed: true };
|
|
82
91
|
}
|
|
@@ -89,6 +98,33 @@ function handleKmsConfigError(c, error) {
|
|
|
89
98
|
}
|
|
90
99
|
return c.json({ error: "Booking PII encryption is not configured" }, 500);
|
|
91
100
|
}
|
|
101
|
+
function getRouteRuntime(c) {
|
|
102
|
+
try {
|
|
103
|
+
return (c.var.container?.resolve(BOOKING_ROUTE_RUNTIME_CONTAINER_KEY) ??
|
|
104
|
+
buildBookingRouteRuntime(c.env));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return buildBookingRouteRuntime(c.env);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function createAuditedBookingPiiService(c, bookingId) {
|
|
111
|
+
const runtime = getRouteRuntime(c);
|
|
112
|
+
return createBookingPiiService({
|
|
113
|
+
kms: runtime.getKmsProvider(),
|
|
114
|
+
onAudit: async (event) => {
|
|
115
|
+
await logBookingPiiAccess(c, {
|
|
116
|
+
bookingId,
|
|
117
|
+
participantId: event.participantId,
|
|
118
|
+
action: event.action === "encrypt"
|
|
119
|
+
? "update"
|
|
120
|
+
: event.action === "decrypt"
|
|
121
|
+
? "read"
|
|
122
|
+
: event.action,
|
|
123
|
+
outcome: "allowed",
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
92
128
|
// ==========================================================================
|
|
93
129
|
// Bookings — method-chained for Hono RPC type inference
|
|
94
130
|
// ==========================================================================
|
|
@@ -98,12 +134,12 @@ export const bookingRoutes = new Hono()
|
|
|
98
134
|
// ==========================================================================
|
|
99
135
|
// 1. GET / — List bookings
|
|
100
136
|
.get("/", async (c) => {
|
|
101
|
-
const query =
|
|
137
|
+
const query = parseQuery(c, bookingListQuerySchema);
|
|
102
138
|
return c.json(await bookingsService.listBookings(c.get("db"), query));
|
|
103
139
|
})
|
|
104
140
|
// 1a. GET /overview — Internal/admin booking overview lookup
|
|
105
141
|
.get("/overview", async (c) => {
|
|
106
|
-
const overview = await publicBookingsService.getOverviewByLookup(c.get("db"),
|
|
142
|
+
const overview = await publicBookingsService.getOverviewByLookup(c.get("db"), parseQuery(c, internalBookingOverviewLookupQuerySchema));
|
|
107
143
|
if (!overview) {
|
|
108
144
|
return c.json({ error: "Booking overview not found" }, 404);
|
|
109
145
|
}
|
|
@@ -119,7 +155,7 @@ export const bookingRoutes = new Hono()
|
|
|
119
155
|
})
|
|
120
156
|
// 3. POST /reserve — Reserve inventory and create on-hold booking
|
|
121
157
|
.post("/reserve", async (c) => {
|
|
122
|
-
const result = await bookingsService.reserveBooking(c.get("db"),
|
|
158
|
+
const result = await bookingsService.reserveBooking(c.get("db"), await parseJsonBody(c, reserveBookingSchema), c.get("userId"));
|
|
123
159
|
if ("booking" in result) {
|
|
124
160
|
return c.json({ data: result.booking }, 201);
|
|
125
161
|
}
|
|
@@ -139,7 +175,7 @@ export const bookingRoutes = new Hono()
|
|
|
139
175
|
})
|
|
140
176
|
// 3a. POST /from-product — Create booking draft from product definition
|
|
141
177
|
.post("/from-product", async (c) => {
|
|
142
|
-
const row = await bookingsService.createBookingFromProduct(c.get("db"),
|
|
178
|
+
const row = await bookingsService.createBookingFromProduct(c.get("db"), await parseJsonBody(c, convertProductSchema), c.get("userId"));
|
|
143
179
|
if (!row) {
|
|
144
180
|
return c.json({ error: "Product or option not found" }, 404);
|
|
145
181
|
}
|
|
@@ -147,7 +183,7 @@ export const bookingRoutes = new Hono()
|
|
|
147
183
|
})
|
|
148
184
|
// 3b. POST /from-offer/:offerId/reserve — Reserve booking from transaction offer
|
|
149
185
|
.post("/from-offer/:offerId/reserve", async (c) => {
|
|
150
|
-
const result = await bookingsService.reserveBookingFromOffer(c.get("db"), c.req.param("offerId"),
|
|
186
|
+
const result = await bookingsService.reserveBookingFromOffer(c.get("db"), c.req.param("offerId"), await parseJsonBody(c, reserveBookingFromTransactionSchema), c.get("userId"));
|
|
151
187
|
if (result.status === "not_found") {
|
|
152
188
|
return c.json({ error: "Offer not found" }, 404);
|
|
153
189
|
}
|
|
@@ -170,7 +206,7 @@ export const bookingRoutes = new Hono()
|
|
|
170
206
|
})
|
|
171
207
|
// 3c. POST /from-order/:orderId/reserve — Reserve booking from transaction order
|
|
172
208
|
.post("/from-order/:orderId/reserve", async (c) => {
|
|
173
|
-
const result = await bookingsService.reserveBookingFromOrder(c.get("db"), c.req.param("orderId"),
|
|
209
|
+
const result = await bookingsService.reserveBookingFromOrder(c.get("db"), c.req.param("orderId"), await parseJsonBody(c, reserveBookingFromTransactionSchema), c.get("userId"));
|
|
174
210
|
if (result.status === "not_found") {
|
|
175
211
|
return c.json({ error: "Order not found" }, 404);
|
|
176
212
|
}
|
|
@@ -193,21 +229,27 @@ export const bookingRoutes = new Hono()
|
|
|
193
229
|
})
|
|
194
230
|
// 4. POST / — Create booking (manual/backoffice only)
|
|
195
231
|
.post("/", async (c) => {
|
|
196
|
-
|
|
197
|
-
const parsed = createBookingSchema.safeParse(payload);
|
|
198
|
-
if (!parsed.success) {
|
|
232
|
+
try {
|
|
199
233
|
return c.json({
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
234
|
+
data: await bookingsService.createBooking(c.get("db"), await parseJsonBody(c, createBookingSchema, {
|
|
235
|
+
invalidBodyMessage: "Invalid booking create payload",
|
|
236
|
+
}), c.get("userId")),
|
|
237
|
+
}, 201);
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
const validationError = normalizeValidationError(error);
|
|
241
|
+
if (validationError?.status === 400) {
|
|
242
|
+
return c.json({
|
|
243
|
+
error: validationError.message,
|
|
244
|
+
details: validationError.details?.fields ?? validationError.details,
|
|
245
|
+
}, 400);
|
|
246
|
+
}
|
|
247
|
+
throw error;
|
|
203
248
|
}
|
|
204
|
-
return c.json({
|
|
205
|
-
data: await bookingsService.createBooking(c.get("db"), parsed.data, c.get("userId")),
|
|
206
|
-
}, 201);
|
|
207
249
|
})
|
|
208
250
|
// 5. PATCH /:id — Update booking
|
|
209
251
|
.patch("/:id", async (c) => {
|
|
210
|
-
const row = await bookingsService.updateBooking(c.get("db"), c.req.param("id"),
|
|
252
|
+
const row = await bookingsService.updateBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, updateBookingSchema));
|
|
211
253
|
if (!row) {
|
|
212
254
|
return c.json({ error: "Booking not found" }, 404);
|
|
213
255
|
}
|
|
@@ -226,7 +268,7 @@ export const bookingRoutes = new Hono()
|
|
|
226
268
|
// ==========================================================================
|
|
227
269
|
// 7. PATCH /:id/status — Change booking status
|
|
228
270
|
.patch("/:id/status", async (c) => {
|
|
229
|
-
const result = await bookingsService.updateBookingStatus(c.get("db"), c.req.param("id"),
|
|
271
|
+
const result = await bookingsService.updateBookingStatus(c.get("db"), c.req.param("id"), await parseJsonBody(c, updateBookingStatusSchema), c.get("userId"));
|
|
230
272
|
if (result.status === "not_found") {
|
|
231
273
|
return c.json({ error: "Booking not found" }, 404);
|
|
232
274
|
}
|
|
@@ -240,7 +282,7 @@ export const bookingRoutes = new Hono()
|
|
|
240
282
|
})
|
|
241
283
|
// 8. POST /:id/confirm — Confirm an on-hold booking
|
|
242
284
|
.post("/:id/confirm", async (c) => {
|
|
243
|
-
const result = await bookingsService.confirmBooking(c.get("db"), c.req.param("id"),
|
|
285
|
+
const result = await bookingsService.confirmBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, confirmBookingSchema), c.get("userId"));
|
|
244
286
|
if (result.status === "not_found") {
|
|
245
287
|
return c.json({ error: "Booking not found" }, 404);
|
|
246
288
|
}
|
|
@@ -257,7 +299,7 @@ export const bookingRoutes = new Hono()
|
|
|
257
299
|
})
|
|
258
300
|
// 9. POST /:id/extend-hold — Extend booking hold expiry
|
|
259
301
|
.post("/:id/extend-hold", async (c) => {
|
|
260
|
-
const result = await bookingsService.extendBookingHold(c.get("db"), c.req.param("id"),
|
|
302
|
+
const result = await bookingsService.extendBookingHold(c.get("db"), c.req.param("id"), await parseJsonBody(c, extendBookingHoldSchema), c.get("userId"));
|
|
261
303
|
if (result.status === "not_found") {
|
|
262
304
|
return c.json({ error: "Booking not found" }, 404);
|
|
263
305
|
}
|
|
@@ -274,7 +316,7 @@ export const bookingRoutes = new Hono()
|
|
|
274
316
|
})
|
|
275
317
|
// 10. POST /:id/expire — Expire an on-hold booking
|
|
276
318
|
.post("/:id/expire", async (c) => {
|
|
277
|
-
const result = await bookingsService.expireBooking(c.get("db"), c.req.param("id"),
|
|
319
|
+
const result = await bookingsService.expireBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, expireBookingSchema), c.get("userId"));
|
|
278
320
|
if (result.status === "not_found") {
|
|
279
321
|
return c.json({ error: "Booking not found" }, 404);
|
|
280
322
|
}
|
|
@@ -288,11 +330,11 @@ export const bookingRoutes = new Hono()
|
|
|
288
330
|
})
|
|
289
331
|
// 10b. POST /expire-stale — Expire all stale on-hold bookings up to a cutoff
|
|
290
332
|
.post("/expire-stale", async (c) => {
|
|
291
|
-
return c.json(await bookingsService.expireStaleBookings(c.get("db"),
|
|
333
|
+
return c.json(await bookingsService.expireStaleBookings(c.get("db"), await parseJsonBody(c, expireStaleBookingsSchema), c.get("userId")));
|
|
292
334
|
})
|
|
293
335
|
// 11. POST /:id/cancel — Cancel a booking and release allocations
|
|
294
336
|
.post("/:id/cancel", async (c) => {
|
|
295
|
-
const result = await bookingsService.cancelBooking(c.get("db"), c.req.param("id"),
|
|
337
|
+
const result = await bookingsService.cancelBooking(c.get("db"), c.req.param("id"), await parseJsonBody(c, cancelBookingSchema), c.get("userId"));
|
|
296
338
|
if (result.status === "not_found") {
|
|
297
339
|
return c.json({ error: "Booking not found" }, 404);
|
|
298
340
|
}
|
|
@@ -337,21 +379,7 @@ export const bookingRoutes = new Hono()
|
|
|
337
379
|
return c.json({ error: "Participant not found" }, 404);
|
|
338
380
|
}
|
|
339
381
|
try {
|
|
340
|
-
const pii =
|
|
341
|
-
kms: createKmsProviderFromEnv(getRuntimeEnv(c)),
|
|
342
|
-
onAudit: async (event) => {
|
|
343
|
-
await logBookingPiiAccess(c, {
|
|
344
|
-
bookingId: participant.bookingId,
|
|
345
|
-
participantId: event.participantId,
|
|
346
|
-
action: event.action === "encrypt"
|
|
347
|
-
? "update"
|
|
348
|
-
: event.action === "decrypt"
|
|
349
|
-
? "read"
|
|
350
|
-
: event.action,
|
|
351
|
-
outcome: "allowed",
|
|
352
|
-
});
|
|
353
|
-
},
|
|
354
|
-
});
|
|
382
|
+
const pii = createAuditedBookingPiiService(c, participant.bookingId);
|
|
355
383
|
const details = await pii.getParticipantTravelDetails(c.get("db"), participant.id, c.get("userId"));
|
|
356
384
|
if (!details) {
|
|
357
385
|
await logBookingPiiAccess(c, {
|
|
@@ -371,7 +399,7 @@ export const bookingRoutes = new Hono()
|
|
|
371
399
|
})
|
|
372
400
|
// 9. POST /:id/participants — Add participant
|
|
373
401
|
.post("/:id/participants", async (c) => {
|
|
374
|
-
const row = await bookingsService.createParticipant(c.get("db"), c.req.param("id"),
|
|
402
|
+
const row = await bookingsService.createParticipant(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertParticipantSchema), c.get("userId"));
|
|
375
403
|
if (!row) {
|
|
376
404
|
return c.json({ error: "Booking not found" }, 404);
|
|
377
405
|
}
|
|
@@ -399,22 +427,8 @@ export const bookingRoutes = new Hono()
|
|
|
399
427
|
return c.json({ error: "Participant not found" }, 404);
|
|
400
428
|
}
|
|
401
429
|
try {
|
|
402
|
-
const pii =
|
|
403
|
-
|
|
404
|
-
onAudit: async (event) => {
|
|
405
|
-
await logBookingPiiAccess(c, {
|
|
406
|
-
bookingId: participant.bookingId,
|
|
407
|
-
participantId: event.participantId,
|
|
408
|
-
action: event.action === "encrypt"
|
|
409
|
-
? "update"
|
|
410
|
-
: event.action === "decrypt"
|
|
411
|
-
? "read"
|
|
412
|
-
: event.action,
|
|
413
|
-
outcome: "allowed",
|
|
414
|
-
});
|
|
415
|
-
},
|
|
416
|
-
});
|
|
417
|
-
const row = await pii.upsertParticipantTravelDetails(c.get("db"), participant.id, upsertParticipantTravelDetailsSchema.parse(await c.req.json()), c.get("userId"));
|
|
430
|
+
const pii = createAuditedBookingPiiService(c, participant.bookingId);
|
|
431
|
+
const row = await pii.upsertParticipantTravelDetails(c.get("db"), participant.id, await parseJsonBody(c, upsertParticipantTravelDetailsSchema), c.get("userId"));
|
|
418
432
|
if (!row) {
|
|
419
433
|
return c.json({ error: "Participant not found" }, 404);
|
|
420
434
|
}
|
|
@@ -426,7 +440,7 @@ export const bookingRoutes = new Hono()
|
|
|
426
440
|
})
|
|
427
441
|
// 10. PATCH /:id/participants/:participantId — Update participant
|
|
428
442
|
.patch("/:id/participants/:participantId", async (c) => {
|
|
429
|
-
const row = await bookingsService.updateParticipant(c.get("db"), c.req.param("participantId"),
|
|
443
|
+
const row = await bookingsService.updateParticipant(c.get("db"), c.req.param("participantId"), await parseJsonBody(c, updateParticipantSchema));
|
|
430
444
|
if (!row) {
|
|
431
445
|
return c.json({ error: "Participant not found" }, 404);
|
|
432
446
|
}
|
|
@@ -454,21 +468,7 @@ export const bookingRoutes = new Hono()
|
|
|
454
468
|
return c.json({ error: "Participant not found" }, 404);
|
|
455
469
|
}
|
|
456
470
|
try {
|
|
457
|
-
const pii =
|
|
458
|
-
kms: createKmsProviderFromEnv(getRuntimeEnv(c)),
|
|
459
|
-
onAudit: async (event) => {
|
|
460
|
-
await logBookingPiiAccess(c, {
|
|
461
|
-
bookingId: participant.bookingId,
|
|
462
|
-
participantId: event.participantId,
|
|
463
|
-
action: event.action === "encrypt"
|
|
464
|
-
? "update"
|
|
465
|
-
: event.action === "decrypt"
|
|
466
|
-
? "read"
|
|
467
|
-
: event.action,
|
|
468
|
-
outcome: "allowed",
|
|
469
|
-
});
|
|
470
|
-
},
|
|
471
|
-
});
|
|
471
|
+
const pii = createAuditedBookingPiiService(c, participant.bookingId);
|
|
472
472
|
const row = await pii.deleteParticipantTravelDetails(c.get("db"), participant.id, c.get("userId"));
|
|
473
473
|
if (!row) {
|
|
474
474
|
return c.json({ error: "Participant travel details not found" }, 404);
|
|
@@ -496,7 +496,7 @@ export const bookingRoutes = new Hono()
|
|
|
496
496
|
})
|
|
497
497
|
// 13. POST /:id/passengers — Add passenger
|
|
498
498
|
.post("/:id/passengers", async (c) => {
|
|
499
|
-
const row = await bookingsService.createPassenger(c.get("db"), c.req.param("id"),
|
|
499
|
+
const row = await bookingsService.createPassenger(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertPassengerSchema), c.get("userId"));
|
|
500
500
|
if (!row) {
|
|
501
501
|
return c.json({ error: "Booking not found" }, 404);
|
|
502
502
|
}
|
|
@@ -504,7 +504,7 @@ export const bookingRoutes = new Hono()
|
|
|
504
504
|
})
|
|
505
505
|
// 14. PATCH /:id/passengers/:passengerId — Update passenger
|
|
506
506
|
.patch("/:id/passengers/:passengerId", async (c) => {
|
|
507
|
-
const row = await bookingsService.updatePassenger(c.get("db"), c.req.param("passengerId"),
|
|
507
|
+
const row = await bookingsService.updatePassenger(c.get("db"), c.req.param("passengerId"), await parseJsonBody(c, updatePassengerSchema));
|
|
508
508
|
if (!row) {
|
|
509
509
|
return c.json({ error: "Passenger not found" }, 404);
|
|
510
510
|
}
|
|
@@ -527,7 +527,7 @@ export const bookingRoutes = new Hono()
|
|
|
527
527
|
})
|
|
528
528
|
// 17. POST /:id/items — Add booking item
|
|
529
529
|
.post("/:id/items", async (c) => {
|
|
530
|
-
const row = await bookingsService.createItem(c.get("db"), c.req.param("id"),
|
|
530
|
+
const row = await bookingsService.createItem(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertBookingItemSchema), c.get("userId"));
|
|
531
531
|
if (!row) {
|
|
532
532
|
return c.json({ error: "Booking not found" }, 404);
|
|
533
533
|
}
|
|
@@ -535,7 +535,7 @@ export const bookingRoutes = new Hono()
|
|
|
535
535
|
})
|
|
536
536
|
// 18. PATCH /:id/items/:itemId — Update booking item
|
|
537
537
|
.patch("/:id/items/:itemId", async (c) => {
|
|
538
|
-
const row = await bookingsService.updateItem(c.get("db"), c.req.param("itemId"),
|
|
538
|
+
const row = await bookingsService.updateItem(c.get("db"), c.req.param("itemId"), await parseJsonBody(c, updateBookingItemSchema));
|
|
539
539
|
if (!row) {
|
|
540
540
|
return c.json({ error: "Booking item not found" }, 404);
|
|
541
541
|
}
|
|
@@ -557,7 +557,7 @@ export const bookingRoutes = new Hono()
|
|
|
557
557
|
})
|
|
558
558
|
// 21. POST /:id/items/:itemId/participants — Link participant to item
|
|
559
559
|
.post("/:id/items/:itemId/participants", async (c) => {
|
|
560
|
-
const row = await bookingsService.addItemParticipant(c.get("db"), c.req.param("itemId"),
|
|
560
|
+
const row = await bookingsService.addItemParticipant(c.get("db"), c.req.param("itemId"), await parseJsonBody(c, insertBookingItemParticipantSchema));
|
|
561
561
|
if (!row) {
|
|
562
562
|
return c.json({ error: "Booking item or participant not found" }, 404);
|
|
563
563
|
}
|
|
@@ -580,14 +580,14 @@ export const bookingRoutes = new Hono()
|
|
|
580
580
|
});
|
|
581
581
|
})
|
|
582
582
|
.post("/:id/supplier-statuses", async (c) => {
|
|
583
|
-
const row = await bookingsService.createSupplierStatus(c.get("db"), c.req.param("id"),
|
|
583
|
+
const row = await bookingsService.createSupplierStatus(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertSupplierStatusSchema), c.get("userId"));
|
|
584
584
|
if (!row) {
|
|
585
585
|
return c.json({ error: "Booking not found" }, 404);
|
|
586
586
|
}
|
|
587
587
|
return c.json({ data: row }, 201);
|
|
588
588
|
})
|
|
589
589
|
.patch("/:id/supplier-statuses/:statusId", async (c) => {
|
|
590
|
-
const row = await bookingsService.updateSupplierStatus(c.get("db"), c.req.param("id"), c.req.param("statusId"),
|
|
590
|
+
const row = await bookingsService.updateSupplierStatus(c.get("db"), c.req.param("id"), c.req.param("statusId"), await parseJsonBody(c, updateSupplierStatusSchema), c.get("userId"));
|
|
591
591
|
if (!row) {
|
|
592
592
|
return c.json({ error: "Supplier status not found" }, 404);
|
|
593
593
|
}
|
|
@@ -600,14 +600,14 @@ export const bookingRoutes = new Hono()
|
|
|
600
600
|
return c.json({ data: await bookingsService.listFulfillments(c.get("db"), c.req.param("id")) });
|
|
601
601
|
})
|
|
602
602
|
.post("/:id/fulfillments", async (c) => {
|
|
603
|
-
const row = await bookingsService.issueFulfillment(c.get("db"), c.req.param("id"),
|
|
603
|
+
const row = await bookingsService.issueFulfillment(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertBookingFulfillmentSchema), c.get("userId"));
|
|
604
604
|
if (!row) {
|
|
605
605
|
return c.json({ error: "Booking, item, or participant not found" }, 404);
|
|
606
606
|
}
|
|
607
607
|
return c.json({ data: row }, 201);
|
|
608
608
|
})
|
|
609
609
|
.patch("/:id/fulfillments/:fulfillmentId", async (c) => {
|
|
610
|
-
const row = await bookingsService.updateFulfillment(c.get("db"), c.req.param("id"), c.req.param("fulfillmentId"),
|
|
610
|
+
const row = await bookingsService.updateFulfillment(c.get("db"), c.req.param("id"), c.req.param("fulfillmentId"), await parseJsonBody(c, updateBookingFulfillmentSchema), c.get("userId"));
|
|
611
611
|
if (!row) {
|
|
612
612
|
return c.json({ error: "Fulfillment, item, or participant not found" }, 404);
|
|
613
613
|
}
|
|
@@ -622,7 +622,7 @@ export const bookingRoutes = new Hono()
|
|
|
622
622
|
});
|
|
623
623
|
})
|
|
624
624
|
.post("/:id/redemptions", async (c) => {
|
|
625
|
-
const row = await bookingsService.recordRedemption(c.get("db"), c.req.param("id"),
|
|
625
|
+
const row = await bookingsService.recordRedemption(c.get("db"), c.req.param("id"), await parseJsonBody(c, recordBookingRedemptionSchema), c.get("userId"));
|
|
626
626
|
if (!row) {
|
|
627
627
|
return c.json({ error: "Booking, item, or participant not found" }, 404);
|
|
628
628
|
}
|
|
@@ -649,11 +649,8 @@ export const bookingRoutes = new Hono()
|
|
|
649
649
|
})
|
|
650
650
|
// 28. POST /:id/notes — Add note
|
|
651
651
|
.post("/:id/notes", async (c) => {
|
|
652
|
-
const userId = c
|
|
653
|
-
|
|
654
|
-
return c.json({ error: "User ID required to create notes" }, 400);
|
|
655
|
-
}
|
|
656
|
-
const row = await bookingsService.createNote(c.get("db"), c.req.param("id"), userId, insertBookingNoteSchema.parse(await c.req.json()));
|
|
652
|
+
const userId = requireUserId(c);
|
|
653
|
+
const row = await bookingsService.createNote(c.get("db"), c.req.param("id"), userId, await parseJsonBody(c, insertBookingNoteSchema));
|
|
657
654
|
if (!row) {
|
|
658
655
|
return c.json({ error: "Booking not found" }, 404);
|
|
659
656
|
}
|
|
@@ -668,7 +665,7 @@ export const bookingRoutes = new Hono()
|
|
|
668
665
|
})
|
|
669
666
|
// 30. POST /:id/documents — Add document to booking
|
|
670
667
|
.post("/:id/documents", async (c) => {
|
|
671
|
-
const row = await bookingsService.createDocument(c.get("db"), c.req.param("id"),
|
|
668
|
+
const row = await bookingsService.createDocument(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertBookingDocumentSchema));
|
|
672
669
|
if (!row) {
|
|
673
670
|
return c.json({ error: "Booking not found" }, 404);
|
|
674
671
|
}
|
package/dist/schema-core.d.ts
CHANGED
|
@@ -92,7 +92,7 @@ export declare const bookings: import("drizzle-orm/pg-core").PgTableWithColumns<
|
|
|
92
92
|
tableName: "bookings";
|
|
93
93
|
dataType: "string";
|
|
94
94
|
columnType: "PgEnumColumn";
|
|
95
|
-
data: "internal" | "
|
|
95
|
+
data: "internal" | "reseller" | "direct" | "manual" | "affiliate" | "ota" | "api_partner";
|
|
96
96
|
driverParam: string;
|
|
97
97
|
notNull: true;
|
|
98
98
|
hasDefault: true;
|
package/dist/schema-items.d.ts
CHANGED
|
@@ -75,7 +75,7 @@ export declare const bookingItems: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
75
75
|
tableName: "booking_items";
|
|
76
76
|
dataType: "string";
|
|
77
77
|
columnType: "PgEnumColumn";
|
|
78
|
-
data: "
|
|
78
|
+
data: "service" | "other" | "unit" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
|
|
79
79
|
driverParam: string;
|
|
80
80
|
notNull: true;
|
|
81
81
|
hasDefault: true;
|
|
@@ -611,7 +611,7 @@ export declare const bookingAllocations: import("drizzle-orm/pg-core").PgTableWi
|
|
|
611
611
|
tableName: "booking_allocations";
|
|
612
612
|
dataType: "string";
|
|
613
613
|
columnType: "PgEnumColumn";
|
|
614
|
-
data: "
|
|
614
|
+
data: "resource" | "unit" | "pickup";
|
|
615
615
|
driverParam: string;
|
|
616
616
|
notNull: true;
|
|
617
617
|
hasDefault: true;
|
package/dist/service-public.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export declare const publicBookingsService: {
|
|
|
39
39
|
id: string;
|
|
40
40
|
title: string;
|
|
41
41
|
description: string | null;
|
|
42
|
-
itemType: "
|
|
42
|
+
itemType: "service" | "other" | "unit" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
|
|
43
43
|
status: "cancelled" | "draft" | "on_hold" | "confirmed" | "expired" | "fulfilled";
|
|
44
44
|
serviceDate: string | null;
|
|
45
45
|
startsAt: string | null;
|
|
@@ -72,7 +72,7 @@ export declare const publicBookingsService: {
|
|
|
72
72
|
pricingCategoryId: string | null;
|
|
73
73
|
availabilitySlotId: string | null;
|
|
74
74
|
quantity: number;
|
|
75
|
-
allocationType: "
|
|
75
|
+
allocationType: "resource" | "unit" | "pickup";
|
|
76
76
|
status: "cancelled" | "confirmed" | "expired" | "fulfilled" | "held" | "released";
|
|
77
77
|
holdExpiresAt: string | null;
|
|
78
78
|
confirmedAt: string | null;
|
|
@@ -132,7 +132,7 @@ export declare const publicBookingsService: {
|
|
|
132
132
|
id: string;
|
|
133
133
|
title: string;
|
|
134
134
|
description: string | null;
|
|
135
|
-
itemType: "
|
|
135
|
+
itemType: "service" | "other" | "unit" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
|
|
136
136
|
status: "cancelled" | "draft" | "on_hold" | "confirmed" | "expired" | "fulfilled";
|
|
137
137
|
serviceDate: string | null;
|
|
138
138
|
startsAt: string | null;
|
|
@@ -165,7 +165,7 @@ export declare const publicBookingsService: {
|
|
|
165
165
|
pricingCategoryId: string | null;
|
|
166
166
|
availabilitySlotId: string | null;
|
|
167
167
|
quantity: number;
|
|
168
|
-
allocationType: "
|
|
168
|
+
allocationType: "resource" | "unit" | "pickup";
|
|
169
169
|
status: "cancelled" | "confirmed" | "expired" | "fulfilled" | "held" | "released";
|
|
170
170
|
holdExpiresAt: string | null;
|
|
171
171
|
confirmedAt: string | null;
|
|
@@ -254,7 +254,7 @@ export declare const publicBookingsService: {
|
|
|
254
254
|
id: string;
|
|
255
255
|
title: string;
|
|
256
256
|
description: string | null;
|
|
257
|
-
itemType: "
|
|
257
|
+
itemType: "service" | "other" | "unit" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
|
|
258
258
|
status: "cancelled" | "draft" | "on_hold" | "confirmed" | "expired" | "fulfilled";
|
|
259
259
|
serviceDate: string | null;
|
|
260
260
|
startsAt: string | null;
|
|
@@ -287,7 +287,7 @@ export declare const publicBookingsService: {
|
|
|
287
287
|
pricingCategoryId: string | null;
|
|
288
288
|
availabilitySlotId: string | null;
|
|
289
289
|
quantity: number;
|
|
290
|
-
allocationType: "
|
|
290
|
+
allocationType: "resource" | "unit" | "pickup";
|
|
291
291
|
status: "cancelled" | "confirmed" | "expired" | "fulfilled" | "held" | "released";
|
|
292
292
|
holdExpiresAt: string | null;
|
|
293
293
|
confirmedAt: string | null;
|
|
@@ -388,7 +388,7 @@ export declare const publicBookingsService: {
|
|
|
388
388
|
id: string;
|
|
389
389
|
title: string;
|
|
390
390
|
description: string | null;
|
|
391
|
-
itemType: "
|
|
391
|
+
itemType: "service" | "other" | "unit" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
|
|
392
392
|
status: "cancelled" | "draft" | "on_hold" | "confirmed" | "expired" | "fulfilled";
|
|
393
393
|
serviceDate: string | null;
|
|
394
394
|
startsAt: string | null;
|
|
@@ -421,7 +421,7 @@ export declare const publicBookingsService: {
|
|
|
421
421
|
pricingCategoryId: string | null;
|
|
422
422
|
availabilitySlotId: string | null;
|
|
423
423
|
quantity: number;
|
|
424
|
-
allocationType: "
|
|
424
|
+
allocationType: "resource" | "unit" | "pickup";
|
|
425
425
|
status: "cancelled" | "confirmed" | "expired" | "fulfilled" | "held" | "released";
|
|
426
426
|
holdExpiresAt: string | null;
|
|
427
427
|
confirmedAt: string | null;
|
|
@@ -485,7 +485,7 @@ export declare const publicBookingsService: {
|
|
|
485
485
|
id: string;
|
|
486
486
|
title: string;
|
|
487
487
|
description: string | null;
|
|
488
|
-
itemType: "
|
|
488
|
+
itemType: "service" | "other" | "unit" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
|
|
489
489
|
status: "cancelled" | "draft" | "on_hold" | "confirmed" | "expired" | "fulfilled";
|
|
490
490
|
serviceDate: string | null;
|
|
491
491
|
startsAt: string | null;
|
|
@@ -518,7 +518,7 @@ export declare const publicBookingsService: {
|
|
|
518
518
|
pricingCategoryId: string | null;
|
|
519
519
|
availabilitySlotId: string | null;
|
|
520
520
|
quantity: number;
|
|
521
|
-
allocationType: "
|
|
521
|
+
allocationType: "resource" | "unit" | "pickup";
|
|
522
522
|
status: "cancelled" | "confirmed" | "expired" | "fulfilled" | "held" | "released";
|
|
523
523
|
holdExpiresAt: string | null;
|
|
524
524
|
confirmedAt: string | null;
|
|
@@ -582,7 +582,7 @@ export declare const publicBookingsService: {
|
|
|
582
582
|
id: string;
|
|
583
583
|
title: string;
|
|
584
584
|
description: string | null;
|
|
585
|
-
itemType: "
|
|
585
|
+
itemType: "service" | "other" | "unit" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
|
|
586
586
|
status: "cancelled" | "draft" | "on_hold" | "confirmed" | "expired" | "fulfilled";
|
|
587
587
|
serviceDate: string | null;
|
|
588
588
|
startsAt: string | null;
|
|
@@ -615,7 +615,7 @@ export declare const publicBookingsService: {
|
|
|
615
615
|
pricingCategoryId: string | null;
|
|
616
616
|
availabilitySlotId: string | null;
|
|
617
617
|
quantity: number;
|
|
618
|
-
allocationType: "
|
|
618
|
+
allocationType: "resource" | "unit" | "pickup";
|
|
619
619
|
status: "cancelled" | "confirmed" | "expired" | "fulfilled" | "held" | "released";
|
|
620
620
|
holdExpiresAt: string | null;
|
|
621
621
|
confirmedAt: string | null;
|
|
@@ -664,7 +664,7 @@ export declare const publicBookingsService: {
|
|
|
664
664
|
id: string;
|
|
665
665
|
title: string;
|
|
666
666
|
description: string | null;
|
|
667
|
-
itemType: "
|
|
667
|
+
itemType: "service" | "other" | "unit" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
|
|
668
668
|
status: "cancelled" | "draft" | "on_hold" | "confirmed" | "expired" | "fulfilled";
|
|
669
669
|
serviceDate: string | null;
|
|
670
670
|
startsAt: string | null;
|
|
@@ -728,7 +728,7 @@ export declare const publicBookingsService: {
|
|
|
728
728
|
id: string;
|
|
729
729
|
title: string;
|
|
730
730
|
description: string | null;
|
|
731
|
-
itemType: "
|
|
731
|
+
itemType: "service" | "other" | "unit" | "extra" | "fee" | "tax" | "discount" | "adjustment" | "accommodation" | "transport";
|
|
732
732
|
status: "cancelled" | "draft" | "on_hold" | "confirmed" | "expired" | "fulfilled";
|
|
733
733
|
serviceDate: string | null;
|
|
734
734
|
startsAt: string | null;
|