@voyantjs/products 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/booking-engine/handler.d.ts +203 -0
- package/dist/booking-engine/handler.d.ts.map +1 -0
- package/dist/booking-engine/handler.js +330 -0
- package/dist/booking-engine/index.d.ts +8 -0
- package/dist/booking-engine/index.d.ts.map +1 -0
- package/dist/booking-engine/index.js +7 -0
- package/dist/catalog-policy.d.ts +33 -0
- package/dist/catalog-policy.d.ts.map +1 -0
- package/dist/catalog-policy.js +421 -0
- package/dist/content-shape.d.ts +217 -0
- package/dist/content-shape.d.ts.map +1 -0
- package/dist/content-shape.js +159 -0
- package/dist/draft-shape.d.ts +43 -0
- package/dist/draft-shape.d.ts.map +1 -0
- package/dist/draft-shape.js +46 -0
- package/dist/events.d.ts +37 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +32 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/routes-content.d.ts +74 -0
- package/dist/routes-content.d.ts.map +1 -0
- package/dist/routes-content.js +117 -0
- package/dist/routes.d.ts +47 -26
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +88 -16
- package/dist/schema-core.d.ts +240 -1
- package/dist/schema-core.d.ts.map +1 -1
- package/dist/schema-core.js +49 -0
- package/dist/schema-itinerary.d.ts +18 -1
- package/dist/schema-itinerary.d.ts.map +1 -1
- package/dist/schema-itinerary.js +1 -0
- package/dist/schema-settings.d.ts +1 -1
- package/dist/schema-sourced-content.d.ts +262 -0
- package/dist/schema-sourced-content.d.ts.map +1 -0
- package/dist/schema-sourced-content.js +69 -0
- package/dist/schema-taxonomy.d.ts +17 -0
- package/dist/schema-taxonomy.d.ts.map +1 -1
- package/dist/schema-taxonomy.js +13 -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-catalog-plane.d.ts +129 -0
- package/dist/service-catalog-plane.d.ts.map +1 -0
- package/dist/service-catalog-plane.js +212 -0
- package/dist/service-content-owned.d.ts +68 -0
- package/dist/service-content-owned.d.ts.map +1 -0
- package/dist/service-content-owned.js +224 -0
- package/dist/service-content-synthesizer.d.ts +90 -0
- package/dist/service-content-synthesizer.d.ts.map +1 -0
- package/dist/service-content-synthesizer.js +171 -0
- package/dist/service-content.d.ts +106 -0
- package/dist/service-content.d.ts.map +1 -0
- package/dist/service-content.js +365 -0
- package/dist/service.d.ts +82 -28
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +4 -0
- package/dist/tasks/brochures.d.ts +2 -1
- package/dist/tasks/brochures.d.ts.map +1 -1
- package/dist/tasks/brochures.js +3 -0
- package/dist/validation-catalog.d.ts +4 -4
- package/dist/validation-config.d.ts +3 -3
- package/dist/validation-content.d.ts +34 -4
- package/dist/validation-content.d.ts.map +1 -1
- package/dist/validation-content.js +13 -0
- package/dist/validation-core.d.ts +53 -3
- package/dist/validation-core.d.ts.map +1 -1
- package/dist/validation-core.js +16 -0
- package/dist/validation-public.d.ts +9 -9
- package/dist/validation-shared.d.ts +4 -4
- package/package.json +12 -6
package/dist/routes.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseJsonBody, parseQuery, RequestValidationError, requireUserId } from "@voyantjs/hono";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { emitProductContentChanged } from "./events.js";
|
|
4
5
|
import { productsService } from "./service.js";
|
|
5
6
|
import { destinationListQuerySchema, destinationTranslationListQuerySchema, duplicateItinerarySchema, insertDaySchema, insertDayServiceSchema, insertDestinationSchema, insertDestinationTranslationSchema, insertItinerarySchema, insertOptionUnitSchema, insertOptionUnitTranslationSchema, insertProductActivationSettingSchema, insertProductCapabilitySchema, insertProductCategorySchema, insertProductDeliveryFormatSchema, insertProductDestinationSchema, insertProductFaqSchema, insertProductFeatureSchema, insertProductLocationSchema, insertProductMediaSchema, insertProductNoteSchema, insertProductOptionSchema, insertProductOptionTranslationSchema, insertProductSchema, insertProductTagSchema, insertProductTicketSettingSchema, insertProductTranslationSchema, insertProductTypeSchema, insertProductVisibilitySettingSchema, insertVersionSchema, optionUnitListQuerySchema, optionUnitTranslationListQuerySchema, productActivationSettingListQuerySchema, productAggregatesQuerySchema, productCapabilityListQuerySchema, productCategoryListQuerySchema, productDeliveryFormatListQuerySchema, productDestinationListQuerySchema, productFaqListQuerySchema, productFeatureListQuerySchema, productListQuerySchema, productLocationListQuerySchema, productMediaListQuerySchema, productOptionListQuerySchema, productOptionTranslationListQuerySchema, productTagListQuerySchema, productTicketSettingListQuerySchema, productTranslationListQuerySchema, productTypeListQuerySchema, productVisibilitySettingListQuerySchema, reorderProductMediaSchema, updateDaySchema, updateDayServiceSchema, updateDestinationSchema, updateDestinationTranslationSchema, updateItinerarySchema, updateOptionUnitSchema, updateOptionUnitTranslationSchema, updateProductActivationSettingSchema, updateProductCapabilitySchema, updateProductCategorySchema, updateProductDeliveryFormatSchema, updateProductFaqSchema, updateProductFeatureSchema, updateProductLocationSchema, updateProductMediaSchema, updateProductOptionSchema, updateProductOptionTranslationSchema, updateProductSchema, updateProductTagSchema, updateProductTicketSettingSchema, updateProductTranslationSchema, updateProductTypeSchema, updateProductVisibilitySettingSchema, upsertProductBrochureSchema, } from "./validation.js";
|
|
6
7
|
// ==========================================================================
|
|
@@ -19,9 +20,9 @@ export const productRoutes = new Hono()
|
|
|
19
20
|
})
|
|
20
21
|
// POST / — Create product
|
|
21
22
|
.post("/", async (c) => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}, 201);
|
|
23
|
+
const row = await productsService.createProduct(c.get("db"), await parseJsonBody(c, insertProductSchema));
|
|
24
|
+
await c.get("eventBus")?.emit("product.created", { id: row.id });
|
|
25
|
+
return c.json({ data: row }, 201);
|
|
25
26
|
})
|
|
26
27
|
// ==========================================================================
|
|
27
28
|
// Product operating configuration
|
|
@@ -198,10 +199,12 @@ export const productRoutes = new Hono()
|
|
|
198
199
|
return c.json({ data: row });
|
|
199
200
|
})
|
|
200
201
|
.post("/:id/features", async (c) => {
|
|
201
|
-
const
|
|
202
|
+
const productId = c.req.param("id");
|
|
203
|
+
const row = await productsService.createFeature(c.get("db"), productId, await parseJsonBody(c, insertProductFeatureSchema));
|
|
202
204
|
if (!row) {
|
|
203
205
|
return c.json({ error: "Product not found" }, 404);
|
|
204
206
|
}
|
|
207
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "feature" });
|
|
205
208
|
return c.json({ data: row }, 201);
|
|
206
209
|
})
|
|
207
210
|
.patch("/features/:id", async (c) => {
|
|
@@ -209,6 +212,9 @@ export const productRoutes = new Hono()
|
|
|
209
212
|
if (!row) {
|
|
210
213
|
return c.json({ error: "Product feature not found" }, 404);
|
|
211
214
|
}
|
|
215
|
+
if (row.productId) {
|
|
216
|
+
await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "feature" });
|
|
217
|
+
}
|
|
212
218
|
return c.json({ data: row });
|
|
213
219
|
})
|
|
214
220
|
.delete("/features/:id", async (c) => {
|
|
@@ -216,6 +222,9 @@ export const productRoutes = new Hono()
|
|
|
216
222
|
if (!row) {
|
|
217
223
|
return c.json({ error: "Product feature not found" }, 404);
|
|
218
224
|
}
|
|
225
|
+
if ("productId" in row && typeof row.productId === "string") {
|
|
226
|
+
await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "feature" });
|
|
227
|
+
}
|
|
219
228
|
return c.json({ success: true }, 200);
|
|
220
229
|
})
|
|
221
230
|
.get("/faqs", async (c) => {
|
|
@@ -230,10 +239,12 @@ export const productRoutes = new Hono()
|
|
|
230
239
|
return c.json({ data: row });
|
|
231
240
|
})
|
|
232
241
|
.post("/:id/faqs", async (c) => {
|
|
233
|
-
const
|
|
242
|
+
const productId = c.req.param("id");
|
|
243
|
+
const row = await productsService.createFaq(c.get("db"), productId, await parseJsonBody(c, insertProductFaqSchema));
|
|
234
244
|
if (!row) {
|
|
235
245
|
return c.json({ error: "Product not found" }, 404);
|
|
236
246
|
}
|
|
247
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "faq" });
|
|
237
248
|
return c.json({ data: row }, 201);
|
|
238
249
|
})
|
|
239
250
|
.patch("/faqs/:id", async (c) => {
|
|
@@ -241,6 +252,9 @@ export const productRoutes = new Hono()
|
|
|
241
252
|
if (!row) {
|
|
242
253
|
return c.json({ error: "Product FAQ not found" }, 404);
|
|
243
254
|
}
|
|
255
|
+
if (row.productId) {
|
|
256
|
+
await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "faq" });
|
|
257
|
+
}
|
|
244
258
|
return c.json({ data: row });
|
|
245
259
|
})
|
|
246
260
|
.delete("/faqs/:id", async (c) => {
|
|
@@ -248,6 +262,9 @@ export const productRoutes = new Hono()
|
|
|
248
262
|
if (!row) {
|
|
249
263
|
return c.json({ error: "Product FAQ not found" }, 404);
|
|
250
264
|
}
|
|
265
|
+
if ("productId" in row && typeof row.productId === "string") {
|
|
266
|
+
await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "faq" });
|
|
267
|
+
}
|
|
251
268
|
return c.json({ success: true }, 200);
|
|
252
269
|
})
|
|
253
270
|
.get("/locations", async (c) => {
|
|
@@ -262,10 +279,12 @@ export const productRoutes = new Hono()
|
|
|
262
279
|
return c.json({ data: row });
|
|
263
280
|
})
|
|
264
281
|
.post("/:id/locations", async (c) => {
|
|
265
|
-
const
|
|
282
|
+
const productId = c.req.param("id");
|
|
283
|
+
const row = await productsService.createLocation(c.get("db"), productId, await parseJsonBody(c, insertProductLocationSchema));
|
|
266
284
|
if (!row) {
|
|
267
285
|
return c.json({ error: "Product not found" }, 404);
|
|
268
286
|
}
|
|
287
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "location" });
|
|
269
288
|
return c.json({ data: row }, 201);
|
|
270
289
|
})
|
|
271
290
|
.patch("/locations/:id", async (c) => {
|
|
@@ -273,6 +292,9 @@ export const productRoutes = new Hono()
|
|
|
273
292
|
if (!row) {
|
|
274
293
|
return c.json({ error: "Product location not found" }, 404);
|
|
275
294
|
}
|
|
295
|
+
if (row.productId) {
|
|
296
|
+
await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "location" });
|
|
297
|
+
}
|
|
276
298
|
return c.json({ data: row });
|
|
277
299
|
})
|
|
278
300
|
.delete("/locations/:id", async (c) => {
|
|
@@ -280,6 +302,9 @@ export const productRoutes = new Hono()
|
|
|
280
302
|
if (!row) {
|
|
281
303
|
return c.json({ error: "Product location not found" }, 404);
|
|
282
304
|
}
|
|
305
|
+
if ("productId" in row && typeof row.productId === "string") {
|
|
306
|
+
await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "location" });
|
|
307
|
+
}
|
|
283
308
|
return c.json({ success: true }, 200);
|
|
284
309
|
})
|
|
285
310
|
.get("/destinations", async (c) => {
|
|
@@ -341,17 +366,21 @@ export const productRoutes = new Hono()
|
|
|
341
366
|
return c.json(await productsService.listProductDestinations(c.get("db"), query));
|
|
342
367
|
})
|
|
343
368
|
.post("/:id/destinations", async (c) => {
|
|
344
|
-
const
|
|
369
|
+
const productId = c.req.param("id");
|
|
370
|
+
const row = await productsService.assignProductDestination(c.get("db"), productId, await parseJsonBody(c, insertProductDestinationSchema));
|
|
345
371
|
if (!row) {
|
|
346
372
|
return c.json({ error: "Product or destination not found" }, 404);
|
|
347
373
|
}
|
|
374
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "destination" });
|
|
348
375
|
return c.json({ data: row }, 201);
|
|
349
376
|
})
|
|
350
377
|
.delete("/:id/destinations/:destinationId", async (c) => {
|
|
351
|
-
const
|
|
378
|
+
const productId = c.req.param("id");
|
|
379
|
+
const row = await productsService.removeProductDestination(c.get("db"), productId, c.req.param("destinationId"));
|
|
352
380
|
if (!row) {
|
|
353
381
|
return c.json({ error: "Product destination link not found" }, 404);
|
|
354
382
|
}
|
|
383
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "destination" });
|
|
355
384
|
return c.json({ success: true }, 200);
|
|
356
385
|
})
|
|
357
386
|
// ==========================================================================
|
|
@@ -372,10 +401,12 @@ export const productRoutes = new Hono()
|
|
|
372
401
|
})
|
|
373
402
|
// POST /:id/options — Create option for product
|
|
374
403
|
.post("/:id/options", async (c) => {
|
|
375
|
-
const
|
|
404
|
+
const productId = c.req.param("id");
|
|
405
|
+
const row = await productsService.createOption(c.get("db"), productId, await parseJsonBody(c, insertProductOptionSchema));
|
|
376
406
|
if (!row) {
|
|
377
407
|
return c.json({ error: "Product not found" }, 404);
|
|
378
408
|
}
|
|
409
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "option" });
|
|
379
410
|
return c.json({ data: row }, 201);
|
|
380
411
|
})
|
|
381
412
|
// PATCH /options/:optionId — Update option
|
|
@@ -384,6 +415,9 @@ export const productRoutes = new Hono()
|
|
|
384
415
|
if (!row) {
|
|
385
416
|
return c.json({ error: "Product option not found" }, 404);
|
|
386
417
|
}
|
|
418
|
+
if (row.productId) {
|
|
419
|
+
await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "option" });
|
|
420
|
+
}
|
|
387
421
|
return c.json({ data: row });
|
|
388
422
|
})
|
|
389
423
|
// DELETE /options/:optionId — Delete option
|
|
@@ -392,6 +426,9 @@ export const productRoutes = new Hono()
|
|
|
392
426
|
if (!row) {
|
|
393
427
|
return c.json({ error: "Product option not found" }, 404);
|
|
394
428
|
}
|
|
429
|
+
if ("productId" in row && typeof row.productId === "string") {
|
|
430
|
+
await emitProductContentChanged(c.get("eventBus"), { id: row.productId, axis: "option" });
|
|
431
|
+
}
|
|
395
432
|
return c.json({ success: true }, 200);
|
|
396
433
|
})
|
|
397
434
|
// ==========================================================================
|
|
@@ -449,10 +486,12 @@ export const productRoutes = new Hono()
|
|
|
449
486
|
return c.json({ data: row });
|
|
450
487
|
})
|
|
451
488
|
.post("/:id/translations", async (c) => {
|
|
452
|
-
const
|
|
489
|
+
const productId = c.req.param("id");
|
|
490
|
+
const row = await productsService.createProductTranslation(c.get("db"), productId, await parseJsonBody(c, insertProductTranslationSchema));
|
|
453
491
|
if (!row) {
|
|
454
492
|
return c.json({ error: "Product not found" }, 404);
|
|
455
493
|
}
|
|
494
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "translation" });
|
|
456
495
|
return c.json({ data: row }, 201);
|
|
457
496
|
})
|
|
458
497
|
.patch("/translations/:translationId", async (c) => {
|
|
@@ -460,6 +499,12 @@ export const productRoutes = new Hono()
|
|
|
460
499
|
if (!row) {
|
|
461
500
|
return c.json({ error: "Product translation not found" }, 404);
|
|
462
501
|
}
|
|
502
|
+
if (row.productId) {
|
|
503
|
+
await emitProductContentChanged(c.get("eventBus"), {
|
|
504
|
+
id: row.productId,
|
|
505
|
+
axis: "translation",
|
|
506
|
+
});
|
|
507
|
+
}
|
|
463
508
|
return c.json({ data: row });
|
|
464
509
|
})
|
|
465
510
|
.delete("/translations/:translationId", async (c) => {
|
|
@@ -467,6 +512,12 @@ export const productRoutes = new Hono()
|
|
|
467
512
|
if (!row) {
|
|
468
513
|
return c.json({ error: "Product translation not found" }, 404);
|
|
469
514
|
}
|
|
515
|
+
if ("productId" in row && typeof row.productId === "string") {
|
|
516
|
+
await emitProductContentChanged(c.get("eventBus"), {
|
|
517
|
+
id: row.productId,
|
|
518
|
+
axis: "translation",
|
|
519
|
+
});
|
|
520
|
+
}
|
|
470
521
|
return c.json({ success: true }, 200);
|
|
471
522
|
})
|
|
472
523
|
.get("/option-translations", async (c) => {
|
|
@@ -729,6 +780,8 @@ export const productRoutes = new Hono()
|
|
|
729
780
|
if (!row) {
|
|
730
781
|
return c.json({ error: "Product not found" }, 404);
|
|
731
782
|
}
|
|
783
|
+
await c.get("eventBus")?.emit("product.updated", { id: row.id });
|
|
784
|
+
await emitProductContentChanged(c.get("eventBus"), { id: row.id, axis: "product" });
|
|
732
785
|
return c.json({ data: row });
|
|
733
786
|
})
|
|
734
787
|
// DELETE /:id — Delete product
|
|
@@ -737,6 +790,7 @@ export const productRoutes = new Hono()
|
|
|
737
790
|
if (!row) {
|
|
738
791
|
return c.json({ error: "Product not found" }, 404);
|
|
739
792
|
}
|
|
793
|
+
await c.get("eventBus")?.emit("product.deleted", { id: row.id });
|
|
740
794
|
return c.json({ success: true }, 200);
|
|
741
795
|
})
|
|
742
796
|
// ==========================================================================
|
|
@@ -795,26 +849,32 @@ export const productRoutes = new Hono()
|
|
|
795
849
|
})
|
|
796
850
|
// POST /:id/days — Add day to product
|
|
797
851
|
.post("/:id/days", async (c) => {
|
|
798
|
-
const
|
|
852
|
+
const productId = c.req.param("id");
|
|
853
|
+
const row = await productsService.createDay(c.get("db"), productId, await parseJsonBody(c, insertDaySchema));
|
|
799
854
|
if (!row) {
|
|
800
855
|
return c.json({ error: "Product not found" }, 404);
|
|
801
856
|
}
|
|
857
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
|
|
802
858
|
return c.json({ data: row }, 201);
|
|
803
859
|
})
|
|
804
860
|
// PATCH /:id/days/:dayId — Update day
|
|
805
861
|
.patch("/:id/days/:dayId", async (c) => {
|
|
862
|
+
const productId = c.req.param("id");
|
|
806
863
|
const row = await productsService.updateDay(c.get("db"), c.req.param("dayId"), await parseJsonBody(c, updateDaySchema));
|
|
807
864
|
if (!row) {
|
|
808
865
|
return c.json({ error: "Day not found" }, 404);
|
|
809
866
|
}
|
|
867
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
|
|
810
868
|
return c.json({ data: row });
|
|
811
869
|
})
|
|
812
870
|
// DELETE /:id/days/:dayId — Delete day
|
|
813
871
|
.delete("/:id/days/:dayId", async (c) => {
|
|
872
|
+
const productId = c.req.param("id");
|
|
814
873
|
const row = await productsService.deleteDay(c.get("db"), c.req.param("dayId"));
|
|
815
874
|
if (!row) {
|
|
816
875
|
return c.json({ error: "Day not found" }, 404);
|
|
817
876
|
}
|
|
877
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
|
|
818
878
|
return c.json({ success: true }, 200);
|
|
819
879
|
})
|
|
820
880
|
// ==========================================================================
|
|
@@ -828,26 +888,32 @@ export const productRoutes = new Hono()
|
|
|
828
888
|
})
|
|
829
889
|
// POST /:id/days/:dayId/services — Add service to day
|
|
830
890
|
.post("/:id/days/:dayId/services", async (c) => {
|
|
831
|
-
const
|
|
891
|
+
const productId = c.req.param("id");
|
|
892
|
+
const row = await productsService.createDayService(c.get("db"), productId, c.req.param("dayId"), await parseJsonBody(c, insertDayServiceSchema));
|
|
832
893
|
if (!row) {
|
|
833
894
|
return c.json({ error: "Day not found" }, 404);
|
|
834
895
|
}
|
|
896
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
|
|
835
897
|
return c.json({ data: row }, 201);
|
|
836
898
|
})
|
|
837
899
|
// PATCH /:id/days/:dayId/services/:serviceId — Update service
|
|
838
900
|
.patch("/:id/days/:dayId/services/:serviceId", async (c) => {
|
|
839
|
-
const
|
|
901
|
+
const productId = c.req.param("id");
|
|
902
|
+
const row = await productsService.updateDayService(c.get("db"), productId, c.req.param("serviceId"), await parseJsonBody(c, updateDayServiceSchema));
|
|
840
903
|
if (!row) {
|
|
841
904
|
return c.json({ error: "Service not found" }, 404);
|
|
842
905
|
}
|
|
906
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
|
|
843
907
|
return c.json({ data: row });
|
|
844
908
|
})
|
|
845
909
|
// DELETE /:id/days/:dayId/services/:serviceId — Delete service
|
|
846
910
|
.delete("/:id/days/:dayId/services/:serviceId", async (c) => {
|
|
847
|
-
const
|
|
911
|
+
const productId = c.req.param("id");
|
|
912
|
+
const row = await productsService.deleteDayService(c.get("db"), productId, c.req.param("serviceId"));
|
|
848
913
|
if (!row) {
|
|
849
914
|
return c.json({ error: "Service not found" }, 404);
|
|
850
915
|
}
|
|
916
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "day" });
|
|
851
917
|
return c.json({ success: true }, 200);
|
|
852
918
|
})
|
|
853
919
|
// ==========================================================================
|
|
@@ -950,16 +1016,20 @@ export const productRoutes = new Hono()
|
|
|
950
1016
|
})
|
|
951
1017
|
// POST /:id/media — Create media for product
|
|
952
1018
|
.post("/:id/media", async (c) => {
|
|
953
|
-
const
|
|
1019
|
+
const productId = c.req.param("id");
|
|
1020
|
+
const row = await productsService.createMedia(c.get("db"), productId, await parseJsonBody(c, insertProductMediaSchema));
|
|
954
1021
|
if (!row) {
|
|
955
1022
|
return c.json({ error: "Product not found or invalid dayId" }, 404);
|
|
956
1023
|
}
|
|
1024
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "media" });
|
|
957
1025
|
return c.json({ data: row }, 201);
|
|
958
1026
|
})
|
|
959
1027
|
// POST /:id/media/reorder — Batch reorder media
|
|
960
1028
|
.post("/:id/media/reorder", async (c) => {
|
|
1029
|
+
const productId = c.req.param("id");
|
|
961
1030
|
const data = await parseJsonBody(c, reorderProductMediaSchema);
|
|
962
1031
|
const results = await productsService.reorderMedia(c.get("db"), data);
|
|
1032
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "media" });
|
|
963
1033
|
return c.json({ data: results });
|
|
964
1034
|
})
|
|
965
1035
|
// GET /:id/days/:dayId/media — List day media
|
|
@@ -972,14 +1042,16 @@ export const productRoutes = new Hono()
|
|
|
972
1042
|
})
|
|
973
1043
|
// POST /:id/days/:dayId/media — Create day media
|
|
974
1044
|
.post("/:id/days/:dayId/media", async (c) => {
|
|
1045
|
+
const productId = c.req.param("id");
|
|
975
1046
|
const body = await parseJsonBody(c, insertProductMediaSchema);
|
|
976
|
-
const row = await productsService.createMedia(c.get("db"),
|
|
1047
|
+
const row = await productsService.createMedia(c.get("db"), productId, {
|
|
977
1048
|
...body,
|
|
978
1049
|
dayId: c.req.param("dayId"),
|
|
979
1050
|
});
|
|
980
1051
|
if (!row) {
|
|
981
1052
|
return c.json({ error: "Product or day not found" }, 404);
|
|
982
1053
|
}
|
|
1054
|
+
await emitProductContentChanged(c.get("eventBus"), { id: productId, axis: "media" });
|
|
983
1055
|
return c.json({ data: row }, 201);
|
|
984
1056
|
})
|
|
985
1057
|
// ==========================================================================
|
package/dist/schema-core.d.ts
CHANGED
|
@@ -257,6 +257,23 @@ export declare const products: import("drizzle-orm/pg-core").PgTableWithColumns<
|
|
|
257
257
|
identity: undefined;
|
|
258
258
|
generated: undefined;
|
|
259
259
|
}, {}, {}>;
|
|
260
|
+
supplierId: import("drizzle-orm/pg-core").PgColumn<{
|
|
261
|
+
name: "supplier_id";
|
|
262
|
+
tableName: "products";
|
|
263
|
+
dataType: "string";
|
|
264
|
+
columnType: "PgText";
|
|
265
|
+
data: string;
|
|
266
|
+
driverParam: string;
|
|
267
|
+
notNull: false;
|
|
268
|
+
hasDefault: false;
|
|
269
|
+
isPrimaryKey: false;
|
|
270
|
+
isAutoincrement: false;
|
|
271
|
+
hasRuntimeDefault: false;
|
|
272
|
+
enumValues: [string, ...string[]];
|
|
273
|
+
baseColumn: never;
|
|
274
|
+
identity: undefined;
|
|
275
|
+
generated: undefined;
|
|
276
|
+
}, {}, {}>;
|
|
260
277
|
startDate: import("drizzle-orm/pg-core").PgColumn<{
|
|
261
278
|
name: "start_date";
|
|
262
279
|
tableName: "products";
|
|
@@ -325,6 +342,40 @@ export declare const products: import("drizzle-orm/pg-core").PgTableWithColumns<
|
|
|
325
342
|
identity: undefined;
|
|
326
343
|
generated: undefined;
|
|
327
344
|
}, {}, {}>;
|
|
345
|
+
taxClassId: import("drizzle-orm/pg-core").PgColumn<{
|
|
346
|
+
name: "tax_class_id";
|
|
347
|
+
tableName: "products";
|
|
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
|
+
}, {}, {}>;
|
|
362
|
+
customerPaymentPolicy: import("drizzle-orm/pg-core").PgColumn<{
|
|
363
|
+
name: "customer_payment_policy";
|
|
364
|
+
tableName: "products";
|
|
365
|
+
dataType: "json";
|
|
366
|
+
columnType: "PgJsonb";
|
|
367
|
+
data: unknown;
|
|
368
|
+
driverParam: unknown;
|
|
369
|
+
notNull: false;
|
|
370
|
+
hasDefault: false;
|
|
371
|
+
isPrimaryKey: false;
|
|
372
|
+
isAutoincrement: false;
|
|
373
|
+
hasRuntimeDefault: false;
|
|
374
|
+
enumValues: undefined;
|
|
375
|
+
baseColumn: never;
|
|
376
|
+
identity: undefined;
|
|
377
|
+
generated: undefined;
|
|
378
|
+
}, {}, {}>;
|
|
328
379
|
tags: import("drizzle-orm/pg-core").PgColumn<{
|
|
329
380
|
name: "tags";
|
|
330
381
|
tableName: "products";
|
|
@@ -690,7 +741,7 @@ export declare const optionUnits: import("drizzle-orm/pg-core").PgTableWithColum
|
|
|
690
741
|
tableName: "option_units";
|
|
691
742
|
dataType: "string";
|
|
692
743
|
columnType: "PgEnumColumn";
|
|
693
|
-
data: "service" | "other" | "
|
|
744
|
+
data: "service" | "other" | "group" | "person" | "room" | "vehicle";
|
|
694
745
|
driverParam: string;
|
|
695
746
|
notNull: true;
|
|
696
747
|
hasDefault: true;
|
|
@@ -894,4 +945,192 @@ export declare const optionUnits: import("drizzle-orm/pg-core").PgTableWithColum
|
|
|
894
945
|
}>;
|
|
895
946
|
export type OptionUnit = typeof optionUnits.$inferSelect;
|
|
896
947
|
export type NewOptionUnit = typeof optionUnits.$inferInsert;
|
|
948
|
+
/**
|
|
949
|
+
* Per-product per-occupancy rate tiers for non-cruise verticals.
|
|
950
|
+
* Cruises keep the specialized `cruise_prices` table; everyone else
|
|
951
|
+
* uses this. Per booking-journey-architecture §9.
|
|
952
|
+
*
|
|
953
|
+
* `tier_pax` is the occupancy count the rate applies to (1-supp, 2-default,
|
|
954
|
+
* 3-share, 4). Falls back to `option_unit_tiers` (quantity-based, not
|
|
955
|
+
* occupancy-based) when no occupancy tier exists.
|
|
956
|
+
*/
|
|
957
|
+
export declare const productPaxPricingTiers: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
958
|
+
name: "product_pax_pricing_tiers";
|
|
959
|
+
schema: undefined;
|
|
960
|
+
columns: {
|
|
961
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
962
|
+
name: string;
|
|
963
|
+
tableName: "product_pax_pricing_tiers";
|
|
964
|
+
dataType: "string";
|
|
965
|
+
columnType: "PgText";
|
|
966
|
+
data: string;
|
|
967
|
+
driverParam: string;
|
|
968
|
+
notNull: true;
|
|
969
|
+
hasDefault: true;
|
|
970
|
+
isPrimaryKey: true;
|
|
971
|
+
isAutoincrement: false;
|
|
972
|
+
hasRuntimeDefault: true;
|
|
973
|
+
enumValues: [string, ...string[]];
|
|
974
|
+
baseColumn: never;
|
|
975
|
+
identity: undefined;
|
|
976
|
+
generated: undefined;
|
|
977
|
+
}, {}, {}>;
|
|
978
|
+
productId: import("drizzle-orm/pg-core").PgColumn<{
|
|
979
|
+
name: string;
|
|
980
|
+
tableName: "product_pax_pricing_tiers";
|
|
981
|
+
dataType: "string";
|
|
982
|
+
columnType: "PgText";
|
|
983
|
+
data: string;
|
|
984
|
+
driverParam: string;
|
|
985
|
+
notNull: true;
|
|
986
|
+
hasDefault: false;
|
|
987
|
+
isPrimaryKey: false;
|
|
988
|
+
isAutoincrement: false;
|
|
989
|
+
hasRuntimeDefault: false;
|
|
990
|
+
enumValues: [string, ...string[]];
|
|
991
|
+
baseColumn: never;
|
|
992
|
+
identity: undefined;
|
|
993
|
+
generated: undefined;
|
|
994
|
+
}, {}, {}>;
|
|
995
|
+
optionUnitId: import("drizzle-orm/pg-core").PgColumn<{
|
|
996
|
+
name: string;
|
|
997
|
+
tableName: "product_pax_pricing_tiers";
|
|
998
|
+
dataType: "string";
|
|
999
|
+
columnType: "PgText";
|
|
1000
|
+
data: string;
|
|
1001
|
+
driverParam: string;
|
|
1002
|
+
notNull: false;
|
|
1003
|
+
hasDefault: false;
|
|
1004
|
+
isPrimaryKey: false;
|
|
1005
|
+
isAutoincrement: false;
|
|
1006
|
+
hasRuntimeDefault: false;
|
|
1007
|
+
enumValues: [string, ...string[]];
|
|
1008
|
+
baseColumn: never;
|
|
1009
|
+
identity: undefined;
|
|
1010
|
+
generated: undefined;
|
|
1011
|
+
}, {}, {}>;
|
|
1012
|
+
tierPax: import("drizzle-orm/pg-core").PgColumn<{
|
|
1013
|
+
name: "tier_pax";
|
|
1014
|
+
tableName: "product_pax_pricing_tiers";
|
|
1015
|
+
dataType: "number";
|
|
1016
|
+
columnType: "PgInteger";
|
|
1017
|
+
data: number;
|
|
1018
|
+
driverParam: string | number;
|
|
1019
|
+
notNull: true;
|
|
1020
|
+
hasDefault: false;
|
|
1021
|
+
isPrimaryKey: false;
|
|
1022
|
+
isAutoincrement: false;
|
|
1023
|
+
hasRuntimeDefault: false;
|
|
1024
|
+
enumValues: undefined;
|
|
1025
|
+
baseColumn: never;
|
|
1026
|
+
identity: undefined;
|
|
1027
|
+
generated: undefined;
|
|
1028
|
+
}, {}, {}>;
|
|
1029
|
+
pricePerPaxCents: import("drizzle-orm/pg-core").PgColumn<{
|
|
1030
|
+
name: "price_per_pax_cents";
|
|
1031
|
+
tableName: "product_pax_pricing_tiers";
|
|
1032
|
+
dataType: "number";
|
|
1033
|
+
columnType: "PgInteger";
|
|
1034
|
+
data: number;
|
|
1035
|
+
driverParam: string | number;
|
|
1036
|
+
notNull: true;
|
|
1037
|
+
hasDefault: false;
|
|
1038
|
+
isPrimaryKey: false;
|
|
1039
|
+
isAutoincrement: false;
|
|
1040
|
+
hasRuntimeDefault: false;
|
|
1041
|
+
enumValues: undefined;
|
|
1042
|
+
baseColumn: never;
|
|
1043
|
+
identity: undefined;
|
|
1044
|
+
generated: undefined;
|
|
1045
|
+
}, {}, {}>;
|
|
1046
|
+
promoPricePerPaxCents: import("drizzle-orm/pg-core").PgColumn<{
|
|
1047
|
+
name: "promo_price_per_pax_cents";
|
|
1048
|
+
tableName: "product_pax_pricing_tiers";
|
|
1049
|
+
dataType: "number";
|
|
1050
|
+
columnType: "PgInteger";
|
|
1051
|
+
data: number;
|
|
1052
|
+
driverParam: string | number;
|
|
1053
|
+
notNull: false;
|
|
1054
|
+
hasDefault: false;
|
|
1055
|
+
isPrimaryKey: false;
|
|
1056
|
+
isAutoincrement: false;
|
|
1057
|
+
hasRuntimeDefault: false;
|
|
1058
|
+
enumValues: undefined;
|
|
1059
|
+
baseColumn: never;
|
|
1060
|
+
identity: undefined;
|
|
1061
|
+
generated: undefined;
|
|
1062
|
+
}, {}, {}>;
|
|
1063
|
+
effectiveFrom: import("drizzle-orm/pg-core").PgColumn<{
|
|
1064
|
+
name: "effective_from";
|
|
1065
|
+
tableName: "product_pax_pricing_tiers";
|
|
1066
|
+
dataType: "string";
|
|
1067
|
+
columnType: "PgDateString";
|
|
1068
|
+
data: string;
|
|
1069
|
+
driverParam: string;
|
|
1070
|
+
notNull: false;
|
|
1071
|
+
hasDefault: false;
|
|
1072
|
+
isPrimaryKey: false;
|
|
1073
|
+
isAutoincrement: false;
|
|
1074
|
+
hasRuntimeDefault: false;
|
|
1075
|
+
enumValues: undefined;
|
|
1076
|
+
baseColumn: never;
|
|
1077
|
+
identity: undefined;
|
|
1078
|
+
generated: undefined;
|
|
1079
|
+
}, {}, {}>;
|
|
1080
|
+
effectiveTo: import("drizzle-orm/pg-core").PgColumn<{
|
|
1081
|
+
name: "effective_to";
|
|
1082
|
+
tableName: "product_pax_pricing_tiers";
|
|
1083
|
+
dataType: "string";
|
|
1084
|
+
columnType: "PgDateString";
|
|
1085
|
+
data: string;
|
|
1086
|
+
driverParam: string;
|
|
1087
|
+
notNull: false;
|
|
1088
|
+
hasDefault: false;
|
|
1089
|
+
isPrimaryKey: false;
|
|
1090
|
+
isAutoincrement: false;
|
|
1091
|
+
hasRuntimeDefault: false;
|
|
1092
|
+
enumValues: undefined;
|
|
1093
|
+
baseColumn: never;
|
|
1094
|
+
identity: undefined;
|
|
1095
|
+
generated: undefined;
|
|
1096
|
+
}, {}, {}>;
|
|
1097
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
1098
|
+
name: "created_at";
|
|
1099
|
+
tableName: "product_pax_pricing_tiers";
|
|
1100
|
+
dataType: "date";
|
|
1101
|
+
columnType: "PgTimestamp";
|
|
1102
|
+
data: Date;
|
|
1103
|
+
driverParam: string;
|
|
1104
|
+
notNull: true;
|
|
1105
|
+
hasDefault: true;
|
|
1106
|
+
isPrimaryKey: false;
|
|
1107
|
+
isAutoincrement: false;
|
|
1108
|
+
hasRuntimeDefault: false;
|
|
1109
|
+
enumValues: undefined;
|
|
1110
|
+
baseColumn: never;
|
|
1111
|
+
identity: undefined;
|
|
1112
|
+
generated: undefined;
|
|
1113
|
+
}, {}, {}>;
|
|
1114
|
+
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
1115
|
+
name: "updated_at";
|
|
1116
|
+
tableName: "product_pax_pricing_tiers";
|
|
1117
|
+
dataType: "date";
|
|
1118
|
+
columnType: "PgTimestamp";
|
|
1119
|
+
data: Date;
|
|
1120
|
+
driverParam: string;
|
|
1121
|
+
notNull: true;
|
|
1122
|
+
hasDefault: true;
|
|
1123
|
+
isPrimaryKey: false;
|
|
1124
|
+
isAutoincrement: false;
|
|
1125
|
+
hasRuntimeDefault: false;
|
|
1126
|
+
enumValues: undefined;
|
|
1127
|
+
baseColumn: never;
|
|
1128
|
+
identity: undefined;
|
|
1129
|
+
generated: undefined;
|
|
1130
|
+
}, {}, {}>;
|
|
1131
|
+
};
|
|
1132
|
+
dialect: "pg";
|
|
1133
|
+
}>;
|
|
1134
|
+
export type ProductPaxPricingTier = typeof productPaxPricingTiers.$inferSelect;
|
|
1135
|
+
export type NewProductPaxPricingTier = typeof productPaxPricingTiers.$inferInsert;
|
|
897
1136
|
//# sourceMappingURL=schema-core.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-core.d.ts","sourceRoot":"","sources":["../src/schema-core.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,QAAQ
|
|
1
|
+
{"version":3,"file":"schema-core.d.ts","sourceRoot":"","sources":["../src/schema-core.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgEpB,CAAA;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAClD,MAAM,MAAM,UAAU,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAErD,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyB1B,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,OAAO,cAAc,CAAC,YAAY,CAAA;AAC9D,MAAM,MAAM,gBAAgB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAA;AAEjE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BvB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AACxD,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AAE3D;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuBlC,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,OAAO,sBAAsB,CAAC,YAAY,CAAA;AAC9E,MAAM,MAAM,wBAAwB,GAAG,OAAO,sBAAsB,CAAC,YAAY,CAAA"}
|