@voyantjs/products 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/dist/service.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { and, asc, desc, eq, ilike, inArray, or, sql } from "drizzle-orm";
2
- import { destinations, destinationTranslations, optionUnits, optionUnitTranslations, productActivationSettings, productCapabilities, productCategories, productCategoryProducts, productDayServices, productDays, productDeliveryFormats, productDestinations, productFaqs, productFeatures, productLocations, productMedia, productNotes, productOptions, productOptionTranslations, products, productTagProducts, productTags, productTicketSettings, productTranslations, productTypes, productVersions, productVisibilitySettings, } from "./schema.js";
2
+ import { destinations, destinationTranslations, optionUnits, optionUnitTranslations, productActivationSettings, productCapabilities, productCategories, productCategoryProducts, productDayServices, productDays, productDeliveryFormats, productDestinations, productFaqs, productFeatures, productItineraries, productLocations, productMedia, productNotes, productOptions, productOptionTranslations, products, productTagProducts, productTags, productTicketSettings, productTranslations, productTypes, productVersions, productVisibilitySettings, } from "./schema.js";
3
+ import { getProductAggregates } from "./service-aggregates.js";
3
4
  async function recalculateProductCost(db, productId) {
4
5
  const [result] = await db
5
6
  .select({
@@ -7,7 +8,8 @@ async function recalculateProductCost(db, productId) {
7
8
  })
8
9
  .from(productDayServices)
9
10
  .innerJoin(productDays, eq(productDayServices.dayId, productDays.id))
10
- .where(eq(productDays.productId, productId));
11
+ .innerJoin(productItineraries, eq(productDays.itineraryId, productItineraries.id))
12
+ .where(eq(productItineraries.productId, productId));
11
13
  const costAmountCents = result?.totalCost ?? 0;
12
14
  const [product] = await db
13
15
  .select({ sellAmountCents: products.sellAmountCents })
@@ -32,7 +34,79 @@ async function ensureProductExists(db, productId) {
32
34
  .limit(1);
33
35
  return product ?? null;
34
36
  }
37
+ async function getDefaultItinerary(db, productId) {
38
+ const [itinerary] = await db
39
+ .select({ id: productItineraries.id })
40
+ .from(productItineraries)
41
+ .where(and(eq(productItineraries.productId, productId), eq(productItineraries.isDefault, true)))
42
+ .orderBy(asc(productItineraries.sortOrder), asc(productItineraries.createdAt))
43
+ .limit(1);
44
+ return itinerary ?? null;
45
+ }
46
+ async function ensureDefaultItinerary(db, productId) {
47
+ const existing = await getDefaultItinerary(db, productId);
48
+ if (existing) {
49
+ return existing;
50
+ }
51
+ const [row] = await db
52
+ .insert(productItineraries)
53
+ .values({
54
+ productId,
55
+ name: "Main itinerary",
56
+ isDefault: true,
57
+ sortOrder: 0,
58
+ })
59
+ .returning({ id: productItineraries.id });
60
+ if (!row) {
61
+ throw new Error(`Failed to create default itinerary for product ${productId}`);
62
+ }
63
+ return row;
64
+ }
65
+ async function getItineraryById(db, itineraryId) {
66
+ const [itinerary] = await db
67
+ .select()
68
+ .from(productItineraries)
69
+ .where(eq(productItineraries.id, itineraryId))
70
+ .limit(1);
71
+ return itinerary ?? null;
72
+ }
73
+ async function getDayById(db, dayId) {
74
+ const [day] = await db
75
+ .select({
76
+ id: productDays.id,
77
+ itineraryId: productDays.itineraryId,
78
+ productId: productItineraries.productId,
79
+ })
80
+ .from(productDays)
81
+ .innerJoin(productItineraries, eq(productDays.itineraryId, productItineraries.id))
82
+ .where(eq(productDays.id, dayId))
83
+ .limit(1);
84
+ return day ?? null;
85
+ }
86
+ async function setDefaultItinerary(db, productId, itineraryId) {
87
+ await db
88
+ .update(productItineraries)
89
+ .set({
90
+ isDefault: sql `${productItineraries.id} = ${itineraryId}`,
91
+ updatedAt: new Date(),
92
+ })
93
+ .where(eq(productItineraries.productId, productId));
94
+ }
95
+ async function promoteFallbackItinerary(db, productId) {
96
+ const [fallback] = await db
97
+ .select({ id: productItineraries.id })
98
+ .from(productItineraries)
99
+ .where(eq(productItineraries.productId, productId))
100
+ .orderBy(asc(productItineraries.sortOrder), asc(productItineraries.createdAt))
101
+ .limit(1);
102
+ if (!fallback) {
103
+ return null;
104
+ }
105
+ await setDefaultItinerary(db, productId, fallback.id);
106
+ return fallback;
107
+ }
35
108
  export const productsService = {
109
+ getProductAggregates,
36
110
  async listProducts(db, query) {
37
111
  const conditions = [];
38
112
  if (query.status) {
@@ -78,6 +152,10 @@ export const productsService = {
78
152
  },
79
153
  async createProduct(db, data) {
80
154
  const [row] = await db.insert(products).values(data).returning();
155
+ if (!row) {
156
+ throw new Error("Failed to create product");
157
+ }
158
+ await ensureDefaultItinerary(db, row.id);
81
159
  return row;
82
160
  },
83
161
  async updateProduct(db, id, data) {
@@ -1223,25 +1301,227 @@ export const productsService = {
1223
1301
  .returning({ id: optionUnitTranslations.id });
1224
1302
  return row ?? null;
1225
1303
  },
1226
- listDays(db, productId) {
1304
+ listItineraries(db, productId) {
1305
+ return db
1306
+ .select()
1307
+ .from(productItineraries)
1308
+ .where(eq(productItineraries.productId, productId))
1309
+ .orderBy(desc(productItineraries.isDefault), asc(productItineraries.sortOrder));
1310
+ },
1311
+ async createItinerary(db, productId, data) {
1312
+ const product = await ensureProductExists(db, productId);
1313
+ if (!product) {
1314
+ return null;
1315
+ }
1316
+ const [existingCount] = await db
1317
+ .select({ count: sql `count(*)::int` })
1318
+ .from(productItineraries)
1319
+ .where(eq(productItineraries.productId, productId));
1320
+ const shouldBeDefault = (existingCount?.count ?? 0) === 0 || data.isDefault;
1321
+ const insertAsDefault = (existingCount?.count ?? 0) === 0;
1322
+ const [row] = await db
1323
+ .insert(productItineraries)
1324
+ .values({
1325
+ productId,
1326
+ name: data.name,
1327
+ isDefault: insertAsDefault,
1328
+ sortOrder: data.sortOrder,
1329
+ })
1330
+ .returning();
1331
+ if (!row) {
1332
+ throw new Error(`Failed to create itinerary for product ${productId}`);
1333
+ }
1334
+ if (shouldBeDefault && !insertAsDefault) {
1335
+ await setDefaultItinerary(db, productId, row.id);
1336
+ }
1337
+ return shouldBeDefault && !insertAsDefault ? ((await getItineraryById(db, row.id)) ?? row) : row;
1338
+ },
1339
+ async updateItinerary(db, itineraryId, data) {
1340
+ const itinerary = await getItineraryById(db, itineraryId);
1341
+ if (!itinerary) {
1342
+ return null;
1343
+ }
1344
+ const { isDefault, ...rest } = data;
1345
+ const [row] = await db
1346
+ .update(productItineraries)
1347
+ .set({
1348
+ ...rest,
1349
+ ...(isDefault === false ? { isDefault: false } : {}),
1350
+ updatedAt: new Date(),
1351
+ })
1352
+ .where(eq(productItineraries.id, itineraryId))
1353
+ .returning();
1354
+ if (!row) {
1355
+ return null;
1356
+ }
1357
+ if (isDefault === true) {
1358
+ await setDefaultItinerary(db, itinerary.productId, itineraryId);
1359
+ return (await getItineraryById(db, itineraryId));
1360
+ }
1361
+ if (isDefault === false && itinerary.isDefault) {
1362
+ const [fallback] = await db
1363
+ .select({ id: productItineraries.id })
1364
+ .from(productItineraries)
1365
+ .where(and(eq(productItineraries.productId, itinerary.productId), sql `${productItineraries.id} <> ${itineraryId}`))
1366
+ .orderBy(asc(productItineraries.sortOrder), asc(productItineraries.createdAt))
1367
+ .limit(1);
1368
+ if (fallback) {
1369
+ await setDefaultItinerary(db, itinerary.productId, fallback.id);
1370
+ }
1371
+ else {
1372
+ await setDefaultItinerary(db, itinerary.productId, itineraryId);
1373
+ }
1374
+ return (await getItineraryById(db, itineraryId));
1375
+ }
1376
+ return row;
1377
+ },
1378
+ async deleteItinerary(db, itineraryId) {
1379
+ const itinerary = await getItineraryById(db, itineraryId);
1380
+ if (!itinerary) {
1381
+ return null;
1382
+ }
1383
+ const [row] = await db
1384
+ .delete(productItineraries)
1385
+ .where(eq(productItineraries.id, itineraryId))
1386
+ .returning({ id: productItineraries.id });
1387
+ if (!row) {
1388
+ return null;
1389
+ }
1390
+ if (itinerary.isDefault) {
1391
+ await promoteFallbackItinerary(db, itinerary.productId);
1392
+ }
1393
+ return row;
1394
+ },
1395
+ async duplicateItinerary(db, itineraryId, options) {
1396
+ const source = await getItineraryById(db, itineraryId);
1397
+ if (!source) {
1398
+ return null;
1399
+ }
1400
+ const [countRow] = await db
1401
+ .select({ count: sql `count(*)::int` })
1402
+ .from(productItineraries)
1403
+ .where(eq(productItineraries.productId, source.productId));
1404
+ const name = options?.name?.trim() || `${source.name} (Copy)`;
1405
+ const sortOrder = countRow?.count ?? 0;
1406
+ const [created] = await db
1407
+ .insert(productItineraries)
1408
+ .values({
1409
+ productId: source.productId,
1410
+ name,
1411
+ isDefault: false,
1412
+ sortOrder,
1413
+ })
1414
+ .returning();
1415
+ if (!created) {
1416
+ throw new Error(`Failed to duplicate itinerary ${itineraryId}`);
1417
+ }
1418
+ const sourceDays = await db
1419
+ .select()
1420
+ .from(productDays)
1421
+ .where(eq(productDays.itineraryId, source.id))
1422
+ .orderBy(asc(productDays.dayNumber));
1423
+ if (sourceDays.length === 0) {
1424
+ return created;
1425
+ }
1426
+ const dayIdMap = new Map();
1427
+ const insertedDays = await db
1428
+ .insert(productDays)
1429
+ .values(sourceDays.map((day) => ({
1430
+ itineraryId: created.id,
1431
+ dayNumber: day.dayNumber,
1432
+ title: day.title,
1433
+ description: day.description,
1434
+ location: day.location,
1435
+ })))
1436
+ .returning({ id: productDays.id, dayNumber: productDays.dayNumber });
1437
+ for (const sourceDay of sourceDays) {
1438
+ const match = insertedDays.find((day) => day.dayNumber === sourceDay.dayNumber);
1439
+ if (match) {
1440
+ dayIdMap.set(sourceDay.id, match.id);
1441
+ }
1442
+ }
1443
+ const sourceDayIds = sourceDays.map((day) => day.id);
1444
+ const sourceServices = await db
1445
+ .select()
1446
+ .from(productDayServices)
1447
+ .where(inArray(productDayServices.dayId, sourceDayIds))
1448
+ .orderBy(asc(productDayServices.sortOrder));
1449
+ if (sourceServices.length > 0) {
1450
+ await db.insert(productDayServices).values(sourceServices
1451
+ .map((service) => {
1452
+ const newDayId = dayIdMap.get(service.dayId);
1453
+ if (!newDayId)
1454
+ return null;
1455
+ return {
1456
+ dayId: newDayId,
1457
+ supplierServiceId: service.supplierServiceId,
1458
+ serviceType: service.serviceType,
1459
+ name: service.name,
1460
+ description: service.description,
1461
+ costCurrency: service.costCurrency,
1462
+ costAmountCents: service.costAmountCents,
1463
+ quantity: service.quantity,
1464
+ sortOrder: service.sortOrder,
1465
+ notes: service.notes,
1466
+ };
1467
+ })
1468
+ .filter((value) => value !== null));
1469
+ }
1470
+ const sourceDayMedia = await db
1471
+ .select()
1472
+ .from(productMedia)
1473
+ .where(inArray(productMedia.dayId, sourceDayIds))
1474
+ .orderBy(asc(productMedia.sortOrder));
1475
+ if (sourceDayMedia.length > 0) {
1476
+ await db.insert(productMedia).values(sourceDayMedia
1477
+ .map((media) => {
1478
+ const newDayId = media.dayId ? dayIdMap.get(media.dayId) : null;
1479
+ if (!newDayId)
1480
+ return null;
1481
+ return {
1482
+ productId: media.productId,
1483
+ dayId: newDayId,
1484
+ mediaType: media.mediaType,
1485
+ name: media.name,
1486
+ url: media.url,
1487
+ storageKey: media.storageKey,
1488
+ mimeType: media.mimeType,
1489
+ fileSize: media.fileSize,
1490
+ altText: media.altText,
1491
+ sortOrder: media.sortOrder,
1492
+ isCover: media.isCover,
1493
+ isBrochure: false,
1494
+ isBrochureCurrent: false,
1495
+ brochureVersion: null,
1496
+ };
1497
+ })
1498
+ .filter((value) => value !== null));
1499
+ }
1500
+ return created;
1501
+ },
1502
+ async listDays(db, productId) {
1503
+ const itinerary = await ensureDefaultItinerary(db, productId);
1504
+ return productsService.listItineraryDays(db, itinerary.id);
1505
+ },
1506
+ listItineraryDays(db, itineraryId) {
1227
1507
  return db
1228
1508
  .select()
1229
1509
  .from(productDays)
1230
- .where(eq(productDays.productId, productId))
1510
+ .where(eq(productDays.itineraryId, itineraryId))
1231
1511
  .orderBy(asc(productDays.dayNumber));
1232
1512
  },
1233
1513
  async createDay(db, productId, data) {
1234
- const [product] = await db
1235
- .select({ id: products.id })
1236
- .from(products)
1237
- .where(eq(products.id, productId))
1238
- .limit(1);
1239
- if (!product) {
1514
+ const itinerary = await ensureDefaultItinerary(db, productId);
1515
+ return productsService.createItineraryDay(db, productId, itinerary.id, data);
1516
+ },
1517
+ async createItineraryDay(db, productId, itineraryId, data) {
1518
+ const itinerary = await getItineraryById(db, itineraryId);
1519
+ if (!itinerary || itinerary.productId !== productId) {
1240
1520
  return null;
1241
1521
  }
1242
1522
  const [row] = await db
1243
1523
  .insert(productDays)
1244
- .values({ ...data, productId })
1524
+ .values({ ...data, itineraryId })
1245
1525
  .returning();
1246
1526
  return row;
1247
1527
  },
@@ -1268,12 +1548,8 @@ export const productsService = {
1268
1548
  .orderBy(asc(productDayServices.sortOrder));
1269
1549
  },
1270
1550
  async createDayService(db, productId, dayId, data) {
1271
- const [day] = await db
1272
- .select({ id: productDays.id })
1273
- .from(productDays)
1274
- .where(eq(productDays.id, dayId))
1275
- .limit(1);
1276
- if (!day) {
1551
+ const day = await getDayById(db, dayId);
1552
+ if (!day || day.productId !== productId) {
1277
1553
  return null;
1278
1554
  }
1279
1555
  const [row] = await db
@@ -1318,11 +1594,12 @@ export const productsService = {
1318
1594
  if (!product) {
1319
1595
  return null;
1320
1596
  }
1321
- const days = await db
1597
+ const itineraries = await db
1322
1598
  .select()
1323
- .from(productDays)
1324
- .where(eq(productDays.productId, productId))
1325
- .orderBy(asc(productDays.dayNumber));
1599
+ .from(productItineraries)
1600
+ .where(eq(productItineraries.productId, productId))
1601
+ .orderBy(desc(productItineraries.isDefault), asc(productItineraries.sortOrder));
1602
+ const defaultItinerary = itineraries.find((itinerary) => itinerary.isDefault) ?? null;
1326
1603
  const options = await db
1327
1604
  .select()
1328
1605
  .from(productOptions)
@@ -1336,14 +1613,23 @@ export const productsService = {
1336
1613
  .orderBy(asc(optionUnits.sortOrder), asc(optionUnits.createdAt));
1337
1614
  return { ...option, units };
1338
1615
  }));
1339
- const daysWithServices = await Promise.all(days.map(async (day) => {
1340
- const services = await db
1616
+ const itinerariesWithDays = await Promise.all(itineraries.map(async (itinerary) => {
1617
+ const days = await db
1341
1618
  .select()
1342
- .from(productDayServices)
1343
- .where(eq(productDayServices.dayId, day.id))
1344
- .orderBy(asc(productDayServices.sortOrder));
1345
- return { ...day, services };
1619
+ .from(productDays)
1620
+ .where(eq(productDays.itineraryId, itinerary.id))
1621
+ .orderBy(asc(productDays.dayNumber));
1622
+ const daysWithServices = await Promise.all(days.map(async (day) => {
1623
+ const services = await db
1624
+ .select()
1625
+ .from(productDayServices)
1626
+ .where(eq(productDayServices.dayId, day.id))
1627
+ .orderBy(asc(productDayServices.sortOrder));
1628
+ return { ...day, services };
1629
+ }));
1630
+ return { ...itinerary, days: daysWithServices };
1346
1631
  }));
1632
+ const defaultDays = itinerariesWithDays.find((itinerary) => itinerary.id === defaultItinerary?.id)?.days ?? [];
1347
1633
  const [maxVersion] = await db
1348
1634
  .select({ max: sql `coalesce(max(${productVersions.versionNumber}), 0)` })
1349
1635
  .from(productVersions)
@@ -1353,7 +1639,12 @@ export const productsService = {
1353
1639
  .values({
1354
1640
  productId,
1355
1641
  versionNumber: (maxVersion?.max ?? 0) + 1,
1356
- snapshot: { ...product, options: optionsWithUnits, days: daysWithServices },
1642
+ snapshot: {
1643
+ ...product,
1644
+ options: optionsWithUnits,
1645
+ itineraries: itinerariesWithDays,
1646
+ days: defaultDays,
1647
+ },
1357
1648
  authorId: userId,
1358
1649
  notes: data.notes,
1359
1650
  })
@@ -1691,11 +1982,7 @@ export const productsService = {
1691
1982
  if (data.isBrochure) {
1692
1983
  return null;
1693
1984
  }
1694
- const [day] = await db
1695
- .select({ id: productDays.id, productId: productDays.productId })
1696
- .from(productDays)
1697
- .where(eq(productDays.id, data.dayId))
1698
- .limit(1);
1985
+ const day = await getDayById(db, data.dayId);
1699
1986
  if (!day || day.productId !== productId) {
1700
1987
  return null;
1701
1988
  }
@@ -1 +1 @@
1
- {"version":3,"file":"brochure-templates.d.ts","sourceRoot":"","sources":["../../src/tasks/brochure-templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,mCAAmC,CAAA;AAE1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAExE,KAAK,gBAAgB,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AACvD,KAAK,uBAAuB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACrE,KAAK,aAAa,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAEjD,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IACjE,QAAQ,EAAE,KAAK,CAAC,uBAAuB,CAAC,CAAA;CACzC;AAED,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,aAAa,CAAA;IACtB,IAAI,EAAE,yBAAyB,EAAE,CAAA;IACjC,WAAW,EAAE,IAAI,CAAA;CAClB;AAED,KAAK,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,8BAA8B,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;AAE5F,MAAM,WAAW,iCAAiC;IAChD,UAAU,EAAE,4BAA4B,CAAA;IACxC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAC9B,SAAS,CAAC,EACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,CACC,OAAO,EAAE,8BAA8B,KACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACpE,KAAK,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAChC,QAAQ,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACnC,aAAa,CAAC,EAAE,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAA;CAC3C;AAED,MAAM,WAAW,+BAA+B;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,4BAA4B,CAAA;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB;AAmBD,wBAAsB,kCAAkC,CACtD,EAAE,EAAE,kBAAkB,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,8BAA8B,CAAC,CAiCzC;AAED,wBAAgB,oCAAoC,IAAI,iCAAiC,CAqCxF;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,iCAAiC,EAC3C,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,+BAA+B,CAAC,CAuB1C"}
1
+ {"version":3,"file":"brochure-templates.d.ts","sourceRoot":"","sources":["../../src/tasks/brochure-templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,mCAAmC,CAAA;AAE1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAsB,QAAQ,EAAE,MAAM,cAAc,CAAA;AAE5F,KAAK,gBAAgB,GAAG,OAAO,WAAW,CAAC,YAAY,CAAA;AACvD,KAAK,uBAAuB,GAAG,OAAO,kBAAkB,CAAC,YAAY,CAAA;AACrE,KAAK,aAAa,GAAG,OAAO,QAAQ,CAAC,YAAY,CAAA;AAEjD,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IACjE,QAAQ,EAAE,KAAK,CAAC,uBAAuB,CAAC,CAAA;CACzC;AAED,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,aAAa,CAAA;IACtB,IAAI,EAAE,yBAAyB,EAAE,CAAA;IACjC,WAAW,EAAE,IAAI,CAAA;CAClB;AAED,KAAK,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,8BAA8B,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;AAE5F,MAAM,WAAW,iCAAiC;IAChD,UAAU,EAAE,4BAA4B,CAAA;IACxC,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAC9B,SAAS,CAAC,EACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvB,CAAC,CACC,OAAO,EAAE,8BAA8B,KACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACpE,KAAK,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IAChC,QAAQ,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAA;IACnC,aAAa,CAAC,EAAE,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAA;CAC3C;AAED,MAAM,WAAW,+BAA+B;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,4BAA4B,CAAA;IACxC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,aAAa,EAAE,MAAM,EAAE,CAAA;CACxB;AAmBD,wBAAsB,kCAAkC,CACtD,EAAE,EAAE,kBAAkB,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,8BAA8B,CAAC,CA+CzC;AAED,wBAAgB,oCAAoC,IAAI,iCAAiC,CAqCxF;AAED,wBAAsB,6BAA6B,CACjD,QAAQ,EAAE,iCAAiC,EAC3C,OAAO,EAAE,8BAA8B,GACtC,OAAO,CAAC,+BAA+B,CAAC,CAuB1C"}
@@ -1,6 +1,6 @@
1
1
  import { renderStructuredTemplate, } from "@voyantjs/utils/template-renderer";
2
- import { asc, eq } from "drizzle-orm";
3
- import { productDayServices, productDays, products } from "../schema.js";
2
+ import { and, asc, eq } from "drizzle-orm";
3
+ import { productDayServices, productDays, productItineraries, products } from "../schema.js";
4
4
  async function resolveTemplateValue(value, context) {
5
5
  if (typeof value === "function") {
6
6
  return await value(context);
@@ -17,10 +17,22 @@ export async function loadProductBrochureTemplateContext(db, productId) {
17
17
  if (!product) {
18
18
  throw new Error(`Product not found: ${productId}`);
19
19
  }
20
+ const [defaultItinerary] = await db
21
+ .select({ id: productItineraries.id })
22
+ .from(productItineraries)
23
+ .where(and(eq(productItineraries.productId, productId), eq(productItineraries.isDefault, true)))
24
+ .limit(1);
25
+ if (!defaultItinerary) {
26
+ return {
27
+ product,
28
+ days: [],
29
+ generatedAt: new Date(),
30
+ };
31
+ }
20
32
  const days = await db
21
33
  .select()
22
34
  .from(productDays)
23
- .where(eq(productDays.productId, productId))
35
+ .where(eq(productDays.itineraryId, defaultItinerary.id))
24
36
  .orderBy(asc(productDays.dayNumber));
25
37
  const daysWithServices = await Promise.all(days.map(async (day) => {
26
38
  const services = await db
@@ -1 +1 @@
1
- {"version":3,"file":"generate-pdf.d.ts","sourceRoot":"","sources":["../../src/tasks/generate-pdf.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAKjE,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,UAAU,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,kBAAkB,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,wBAAwB,CAAC,CAmHnC"}
1
+ {"version":3,"file":"generate-pdf.d.ts","sourceRoot":"","sources":["../../src/tasks/generate-pdf.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAKjE,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,EAAE,UAAU,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,kBAAkB,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,wBAAwB,CAAC,CA2HnC"}
@@ -1,18 +1,25 @@
1
- import { asc, eq } from "drizzle-orm";
1
+ import { and, asc, eq } from "drizzle-orm";
2
2
  import { PDFDocument, rgb, StandardFonts } from "pdf-lib";
3
- import { productDayServices, productDays, products } from "../schema.js";
3
+ import { productDayServices, productDays, productItineraries, products } from "../schema.js";
4
4
  export async function generateProductPdf(db, productId) {
5
5
  // 1. Fetch product
6
6
  const [product] = await db.select().from(products).where(eq(products.id, productId)).limit(1);
7
7
  if (!product) {
8
8
  throw new Error(`Product not found: ${productId}`);
9
9
  }
10
+ const [defaultItinerary] = await db
11
+ .select({ id: productItineraries.id })
12
+ .from(productItineraries)
13
+ .where(and(eq(productItineraries.productId, productId), eq(productItineraries.isDefault, true)))
14
+ .limit(1);
10
15
  // 2. Fetch days with services
11
- const days = await db
12
- .select()
13
- .from(productDays)
14
- .where(eq(productDays.productId, productId))
15
- .orderBy(asc(productDays.dayNumber));
16
+ const days = defaultItinerary
17
+ ? await db
18
+ .select()
19
+ .from(productDays)
20
+ .where(eq(productDays.itineraryId, defaultItinerary.id))
21
+ .orderBy(asc(productDays.dayNumber))
22
+ : [];
16
23
  const daysWithServices = await Promise.all(days.map(async (day) => {
17
24
  const services = await db
18
25
  .select()
@@ -259,6 +259,22 @@ export type InsertProductOptionTranslation = z.infer<typeof insertProductOptionT
259
259
  export type UpdateProductOptionTranslation = z.infer<typeof updateProductOptionTranslationSchema>;
260
260
  export type InsertOptionUnitTranslation = z.infer<typeof insertOptionUnitTranslationSchema>;
261
261
  export type UpdateOptionUnitTranslation = z.infer<typeof updateOptionUnitTranslationSchema>;
262
+ export declare const insertItinerarySchema: z.ZodObject<{
263
+ name: z.ZodString;
264
+ isDefault: z.ZodDefault<z.ZodBoolean>;
265
+ sortOrder: z.ZodDefault<z.ZodNumber>;
266
+ }, z.core.$strip>;
267
+ export declare const updateItinerarySchema: z.ZodObject<{
268
+ name: z.ZodOptional<z.ZodString>;
269
+ isDefault: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
270
+ sortOrder: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
271
+ }, z.core.$strip>;
272
+ export declare const duplicateItinerarySchema: z.ZodObject<{
273
+ name: z.ZodOptional<z.ZodString>;
274
+ }, z.core.$strip>;
275
+ export type InsertItinerary = z.infer<typeof insertItinerarySchema>;
276
+ export type UpdateItinerary = z.infer<typeof updateItinerarySchema>;
277
+ export type DuplicateItinerary = z.infer<typeof duplicateItinerarySchema>;
262
278
  export declare const insertDaySchema: z.ZodObject<{
263
279
  dayNumber: z.ZodNumber;
264
280
  title: z.ZodNullable<z.ZodOptional<z.ZodString>>;
@@ -1 +1 @@
1
- {"version":3,"file":"validation-content.d.ts","sourceRoot":"","sources":["../src/validation-content.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"validation-content.d.ts","sourceRoot":"","sources":["../src/validation-content.ts"],"names":[],"mappings":"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"}
@@ -131,6 +131,16 @@ export const optionUnitTranslationListQuerySchema = z.object({
131
131
  limit: z.coerce.number().int().min(1).max(100).default(50),
132
132
  offset: z.coerce.number().int().min(0).default(0),
133
133
  });
134
+ const itineraryCoreSchema = z.object({
135
+ name: z.string().min(1).max(255),
136
+ isDefault: z.boolean().default(false),
137
+ sortOrder: z.number().int().default(0),
138
+ });
139
+ export const insertItinerarySchema = itineraryCoreSchema;
140
+ export const updateItinerarySchema = itineraryCoreSchema.partial();
141
+ export const duplicateItinerarySchema = z.object({
142
+ name: z.string().min(1).max(255).optional(),
143
+ });
134
144
  const dayCoreSchema = z.object({
135
145
  dayNumber: z.number().int().positive(),
136
146
  title: z.string().max(255).optional().nullable(),
@@ -156,6 +156,10 @@ export declare const productListQuerySchema: z.ZodObject<{
156
156
  limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
157
157
  offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
158
158
  }, z.core.$strip>;
159
+ export declare const productAggregatesQuerySchema: z.ZodObject<{
160
+ from: z.ZodOptional<z.ZodString>;
161
+ to: z.ZodOptional<z.ZodString>;
162
+ }, z.core.$strip>;
159
163
  export type InsertProduct = z.infer<typeof insertProductSchema>;
160
164
  export type UpdateProduct = z.infer<typeof updateProductSchema>;
161
165
  export type SelectProduct = z.infer<typeof selectProductSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"validation-core.d.ts","sourceRoot":"","sources":["../src/validation-core.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,CAAC,EACF,MAAM,wBAAwB,CAAA;AA2B/B,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAiD,CAAA;AACjF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA2D,CAAA;AAC3F,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAO9B,CAAA;AACF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASjC,CAAA;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC/D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC/D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAY/D,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;iBAA0B,CAAA;AAChE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;iBAAoC,CAAA;AAC1E,eAAO,MAAM,4BAA4B;;;;;;;;;iBAKvC,CAAA;AACF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAC3E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAiB3E,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;iBAAuB,CAAA;AAC1D,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;iBAAiC,CAAA;AACpE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;iBAKpC,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AACrE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAErE,eAAO,MAAM,mBAAmB;;iBAE9B,CAAA;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAE/D,eAAO,MAAM,uBAAuB;;iBAElC,CAAA"}
1
+ {"version":3,"file":"validation-core.d.ts","sourceRoot":"","sources":["../src/validation-core.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,CAAC,EACF,MAAM,wBAAwB,CAAA;AA2B/B,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAiD,CAAA;AACjF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAA2D,CAAA;AAC3F,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAO9B,CAAA;AACF,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBASjC,CAAA;AAEF,eAAO,MAAM,4BAA4B;;;iBAGvC,CAAA;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC/D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAC/D,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAY/D,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;iBAA0B,CAAA;AAChE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;iBAAoC,CAAA;AAC1E,eAAO,MAAM,4BAA4B;;;;;;;;;iBAKvC,CAAA;AACF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAC3E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAiB3E,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;iBAAuB,CAAA;AAC1D,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;iBAAiC,CAAA;AACpE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;iBAKpC,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AACrE,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAA;AAErE,eAAO,MAAM,mBAAmB;;iBAE9B,CAAA;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAE/D,eAAO,MAAM,uBAAuB;;iBAElC,CAAA"}
@@ -42,6 +42,10 @@ export const productListQuerySchema = z.object({
42
42
  limit: z.coerce.number().int().min(1).max(100).default(50),
43
43
  offset: z.coerce.number().int().min(0).default(0),
44
44
  });
45
+ export const productAggregatesQuerySchema = z.object({
46
+ from: z.string().datetime().optional(),
47
+ to: z.string().datetime().optional(),
48
+ });
45
49
  const productOptionCoreSchema = z.object({
46
50
  name: z.string().min(1).max(255),
47
51
  code: z.string().max(100).optional().nullable(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/products",
3
- "version": "0.6.8",
3
+ "version": "0.7.0",
4
4
  "license": "FSL-1.1-Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -42,11 +42,11 @@
42
42
  "hono": "^4.12.10",
43
43
  "pdf-lib": "^1.17.1",
44
44
  "zod": "^4.3.6",
45
- "@voyantjs/core": "0.6.8",
46
- "@voyantjs/db": "0.6.8",
47
- "@voyantjs/hono": "0.6.8",
48
- "@voyantjs/utils": "0.6.8",
49
- "@voyantjs/voyant-storage": "0.6.8"
45
+ "@voyantjs/core": "0.7.0",
46
+ "@voyantjs/db": "0.7.0",
47
+ "@voyantjs/hono": "0.7.0",
48
+ "@voyantjs/utils": "0.7.0",
49
+ "@voyantjs/voyant-storage": "0.7.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "typescript": "^6.0.2",