@voyantjs/products 0.6.7 → 0.6.9

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,5 @@
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
3
  async function recalculateProductCost(db, productId) {
4
4
  const [result] = await db
5
5
  .select({
@@ -7,7 +7,8 @@ async function recalculateProductCost(db, productId) {
7
7
  })
8
8
  .from(productDayServices)
9
9
  .innerJoin(productDays, eq(productDayServices.dayId, productDays.id))
10
- .where(eq(productDays.productId, productId));
10
+ .innerJoin(productItineraries, eq(productDays.itineraryId, productItineraries.id))
11
+ .where(eq(productItineraries.productId, productId));
11
12
  const costAmountCents = result?.totalCost ?? 0;
12
13
  const [product] = await db
13
14
  .select({ sellAmountCents: products.sellAmountCents })
@@ -32,6 +33,77 @@ async function ensureProductExists(db, productId) {
32
33
  .limit(1);
33
34
  return product ?? null;
34
35
  }
36
+ async function getDefaultItinerary(db, productId) {
37
+ const [itinerary] = await db
38
+ .select({ id: productItineraries.id })
39
+ .from(productItineraries)
40
+ .where(and(eq(productItineraries.productId, productId), eq(productItineraries.isDefault, true)))
41
+ .orderBy(asc(productItineraries.sortOrder), asc(productItineraries.createdAt))
42
+ .limit(1);
43
+ return itinerary ?? null;
44
+ }
45
+ async function ensureDefaultItinerary(db, productId) {
46
+ const existing = await getDefaultItinerary(db, productId);
47
+ if (existing) {
48
+ return existing;
49
+ }
50
+ const [row] = await db
51
+ .insert(productItineraries)
52
+ .values({
53
+ productId,
54
+ name: "Main itinerary",
55
+ isDefault: true,
56
+ sortOrder: 0,
57
+ })
58
+ .returning({ id: productItineraries.id });
59
+ if (!row) {
60
+ throw new Error(`Failed to create default itinerary for product ${productId}`);
61
+ }
62
+ return row;
63
+ }
64
+ async function getItineraryById(db, itineraryId) {
65
+ const [itinerary] = await db
66
+ .select()
67
+ .from(productItineraries)
68
+ .where(eq(productItineraries.id, itineraryId))
69
+ .limit(1);
70
+ return itinerary ?? null;
71
+ }
72
+ async function getDayById(db, dayId) {
73
+ const [day] = await db
74
+ .select({
75
+ id: productDays.id,
76
+ itineraryId: productDays.itineraryId,
77
+ productId: productItineraries.productId,
78
+ })
79
+ .from(productDays)
80
+ .innerJoin(productItineraries, eq(productDays.itineraryId, productItineraries.id))
81
+ .where(eq(productDays.id, dayId))
82
+ .limit(1);
83
+ return day ?? null;
84
+ }
85
+ async function setDefaultItinerary(db, productId, itineraryId) {
86
+ await db
87
+ .update(productItineraries)
88
+ .set({
89
+ isDefault: sql `${productItineraries.id} = ${itineraryId}`,
90
+ updatedAt: new Date(),
91
+ })
92
+ .where(eq(productItineraries.productId, productId));
93
+ }
94
+ async function promoteFallbackItinerary(db, productId) {
95
+ const [fallback] = await db
96
+ .select({ id: productItineraries.id })
97
+ .from(productItineraries)
98
+ .where(eq(productItineraries.productId, productId))
99
+ .orderBy(asc(productItineraries.sortOrder), asc(productItineraries.createdAt))
100
+ .limit(1);
101
+ if (!fallback) {
102
+ return null;
103
+ }
104
+ await setDefaultItinerary(db, productId, fallback.id);
105
+ return fallback;
106
+ }
35
107
  export const productsService = {
36
108
  async listProducts(db, query) {
37
109
  const conditions = [];
@@ -78,6 +150,10 @@ export const productsService = {
78
150
  },
79
151
  async createProduct(db, data) {
80
152
  const [row] = await db.insert(products).values(data).returning();
153
+ if (!row) {
154
+ throw new Error("Failed to create product");
155
+ }
156
+ await ensureDefaultItinerary(db, row.id);
81
157
  return row;
82
158
  },
83
159
  async updateProduct(db, id, data) {
@@ -1223,25 +1299,227 @@ export const productsService = {
1223
1299
  .returning({ id: optionUnitTranslations.id });
1224
1300
  return row ?? null;
1225
1301
  },
1226
- listDays(db, productId) {
1302
+ listItineraries(db, productId) {
1303
+ return db
1304
+ .select()
1305
+ .from(productItineraries)
1306
+ .where(eq(productItineraries.productId, productId))
1307
+ .orderBy(desc(productItineraries.isDefault), asc(productItineraries.sortOrder));
1308
+ },
1309
+ async createItinerary(db, productId, data) {
1310
+ const product = await ensureProductExists(db, productId);
1311
+ if (!product) {
1312
+ return null;
1313
+ }
1314
+ const [existingCount] = await db
1315
+ .select({ count: sql `count(*)::int` })
1316
+ .from(productItineraries)
1317
+ .where(eq(productItineraries.productId, productId));
1318
+ const shouldBeDefault = (existingCount?.count ?? 0) === 0 || data.isDefault;
1319
+ const insertAsDefault = (existingCount?.count ?? 0) === 0;
1320
+ const [row] = await db
1321
+ .insert(productItineraries)
1322
+ .values({
1323
+ productId,
1324
+ name: data.name,
1325
+ isDefault: insertAsDefault,
1326
+ sortOrder: data.sortOrder,
1327
+ })
1328
+ .returning();
1329
+ if (!row) {
1330
+ throw new Error(`Failed to create itinerary for product ${productId}`);
1331
+ }
1332
+ if (shouldBeDefault && !insertAsDefault) {
1333
+ await setDefaultItinerary(db, productId, row.id);
1334
+ }
1335
+ return shouldBeDefault && !insertAsDefault ? ((await getItineraryById(db, row.id)) ?? row) : row;
1336
+ },
1337
+ async updateItinerary(db, itineraryId, data) {
1338
+ const itinerary = await getItineraryById(db, itineraryId);
1339
+ if (!itinerary) {
1340
+ return null;
1341
+ }
1342
+ const { isDefault, ...rest } = data;
1343
+ const [row] = await db
1344
+ .update(productItineraries)
1345
+ .set({
1346
+ ...rest,
1347
+ ...(isDefault === false ? { isDefault: false } : {}),
1348
+ updatedAt: new Date(),
1349
+ })
1350
+ .where(eq(productItineraries.id, itineraryId))
1351
+ .returning();
1352
+ if (!row) {
1353
+ return null;
1354
+ }
1355
+ if (isDefault === true) {
1356
+ await setDefaultItinerary(db, itinerary.productId, itineraryId);
1357
+ return (await getItineraryById(db, itineraryId));
1358
+ }
1359
+ if (isDefault === false && itinerary.isDefault) {
1360
+ const [fallback] = await db
1361
+ .select({ id: productItineraries.id })
1362
+ .from(productItineraries)
1363
+ .where(and(eq(productItineraries.productId, itinerary.productId), sql `${productItineraries.id} <> ${itineraryId}`))
1364
+ .orderBy(asc(productItineraries.sortOrder), asc(productItineraries.createdAt))
1365
+ .limit(1);
1366
+ if (fallback) {
1367
+ await setDefaultItinerary(db, itinerary.productId, fallback.id);
1368
+ }
1369
+ else {
1370
+ await setDefaultItinerary(db, itinerary.productId, itineraryId);
1371
+ }
1372
+ return (await getItineraryById(db, itineraryId));
1373
+ }
1374
+ return row;
1375
+ },
1376
+ async deleteItinerary(db, itineraryId) {
1377
+ const itinerary = await getItineraryById(db, itineraryId);
1378
+ if (!itinerary) {
1379
+ return null;
1380
+ }
1381
+ const [row] = await db
1382
+ .delete(productItineraries)
1383
+ .where(eq(productItineraries.id, itineraryId))
1384
+ .returning({ id: productItineraries.id });
1385
+ if (!row) {
1386
+ return null;
1387
+ }
1388
+ if (itinerary.isDefault) {
1389
+ await promoteFallbackItinerary(db, itinerary.productId);
1390
+ }
1391
+ return row;
1392
+ },
1393
+ async duplicateItinerary(db, itineraryId, options) {
1394
+ const source = await getItineraryById(db, itineraryId);
1395
+ if (!source) {
1396
+ return null;
1397
+ }
1398
+ const [countRow] = await db
1399
+ .select({ count: sql `count(*)::int` })
1400
+ .from(productItineraries)
1401
+ .where(eq(productItineraries.productId, source.productId));
1402
+ const name = options?.name?.trim() || `${source.name} (Copy)`;
1403
+ const sortOrder = countRow?.count ?? 0;
1404
+ const [created] = await db
1405
+ .insert(productItineraries)
1406
+ .values({
1407
+ productId: source.productId,
1408
+ name,
1409
+ isDefault: false,
1410
+ sortOrder,
1411
+ })
1412
+ .returning();
1413
+ if (!created) {
1414
+ throw new Error(`Failed to duplicate itinerary ${itineraryId}`);
1415
+ }
1416
+ const sourceDays = await db
1417
+ .select()
1418
+ .from(productDays)
1419
+ .where(eq(productDays.itineraryId, source.id))
1420
+ .orderBy(asc(productDays.dayNumber));
1421
+ if (sourceDays.length === 0) {
1422
+ return created;
1423
+ }
1424
+ const dayIdMap = new Map();
1425
+ const insertedDays = await db
1426
+ .insert(productDays)
1427
+ .values(sourceDays.map((day) => ({
1428
+ itineraryId: created.id,
1429
+ dayNumber: day.dayNumber,
1430
+ title: day.title,
1431
+ description: day.description,
1432
+ location: day.location,
1433
+ })))
1434
+ .returning({ id: productDays.id, dayNumber: productDays.dayNumber });
1435
+ for (const sourceDay of sourceDays) {
1436
+ const match = insertedDays.find((day) => day.dayNumber === sourceDay.dayNumber);
1437
+ if (match) {
1438
+ dayIdMap.set(sourceDay.id, match.id);
1439
+ }
1440
+ }
1441
+ const sourceDayIds = sourceDays.map((day) => day.id);
1442
+ const sourceServices = await db
1443
+ .select()
1444
+ .from(productDayServices)
1445
+ .where(inArray(productDayServices.dayId, sourceDayIds))
1446
+ .orderBy(asc(productDayServices.sortOrder));
1447
+ if (sourceServices.length > 0) {
1448
+ await db.insert(productDayServices).values(sourceServices
1449
+ .map((service) => {
1450
+ const newDayId = dayIdMap.get(service.dayId);
1451
+ if (!newDayId)
1452
+ return null;
1453
+ return {
1454
+ dayId: newDayId,
1455
+ supplierServiceId: service.supplierServiceId,
1456
+ serviceType: service.serviceType,
1457
+ name: service.name,
1458
+ description: service.description,
1459
+ costCurrency: service.costCurrency,
1460
+ costAmountCents: service.costAmountCents,
1461
+ quantity: service.quantity,
1462
+ sortOrder: service.sortOrder,
1463
+ notes: service.notes,
1464
+ };
1465
+ })
1466
+ .filter((value) => value !== null));
1467
+ }
1468
+ const sourceDayMedia = await db
1469
+ .select()
1470
+ .from(productMedia)
1471
+ .where(inArray(productMedia.dayId, sourceDayIds))
1472
+ .orderBy(asc(productMedia.sortOrder));
1473
+ if (sourceDayMedia.length > 0) {
1474
+ await db.insert(productMedia).values(sourceDayMedia
1475
+ .map((media) => {
1476
+ const newDayId = media.dayId ? dayIdMap.get(media.dayId) : null;
1477
+ if (!newDayId)
1478
+ return null;
1479
+ return {
1480
+ productId: media.productId,
1481
+ dayId: newDayId,
1482
+ mediaType: media.mediaType,
1483
+ name: media.name,
1484
+ url: media.url,
1485
+ storageKey: media.storageKey,
1486
+ mimeType: media.mimeType,
1487
+ fileSize: media.fileSize,
1488
+ altText: media.altText,
1489
+ sortOrder: media.sortOrder,
1490
+ isCover: media.isCover,
1491
+ isBrochure: false,
1492
+ isBrochureCurrent: false,
1493
+ brochureVersion: null,
1494
+ };
1495
+ })
1496
+ .filter((value) => value !== null));
1497
+ }
1498
+ return created;
1499
+ },
1500
+ async listDays(db, productId) {
1501
+ const itinerary = await ensureDefaultItinerary(db, productId);
1502
+ return productsService.listItineraryDays(db, itinerary.id);
1503
+ },
1504
+ listItineraryDays(db, itineraryId) {
1227
1505
  return db
1228
1506
  .select()
1229
1507
  .from(productDays)
1230
- .where(eq(productDays.productId, productId))
1508
+ .where(eq(productDays.itineraryId, itineraryId))
1231
1509
  .orderBy(asc(productDays.dayNumber));
1232
1510
  },
1233
1511
  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) {
1512
+ const itinerary = await ensureDefaultItinerary(db, productId);
1513
+ return productsService.createItineraryDay(db, productId, itinerary.id, data);
1514
+ },
1515
+ async createItineraryDay(db, productId, itineraryId, data) {
1516
+ const itinerary = await getItineraryById(db, itineraryId);
1517
+ if (!itinerary || itinerary.productId !== productId) {
1240
1518
  return null;
1241
1519
  }
1242
1520
  const [row] = await db
1243
1521
  .insert(productDays)
1244
- .values({ ...data, productId })
1522
+ .values({ ...data, itineraryId })
1245
1523
  .returning();
1246
1524
  return row;
1247
1525
  },
@@ -1268,12 +1546,8 @@ export const productsService = {
1268
1546
  .orderBy(asc(productDayServices.sortOrder));
1269
1547
  },
1270
1548
  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) {
1549
+ const day = await getDayById(db, dayId);
1550
+ if (!day || day.productId !== productId) {
1277
1551
  return null;
1278
1552
  }
1279
1553
  const [row] = await db
@@ -1318,11 +1592,12 @@ export const productsService = {
1318
1592
  if (!product) {
1319
1593
  return null;
1320
1594
  }
1321
- const days = await db
1595
+ const itineraries = await db
1322
1596
  .select()
1323
- .from(productDays)
1324
- .where(eq(productDays.productId, productId))
1325
- .orderBy(asc(productDays.dayNumber));
1597
+ .from(productItineraries)
1598
+ .where(eq(productItineraries.productId, productId))
1599
+ .orderBy(desc(productItineraries.isDefault), asc(productItineraries.sortOrder));
1600
+ const defaultItinerary = itineraries.find((itinerary) => itinerary.isDefault) ?? null;
1326
1601
  const options = await db
1327
1602
  .select()
1328
1603
  .from(productOptions)
@@ -1336,14 +1611,23 @@ export const productsService = {
1336
1611
  .orderBy(asc(optionUnits.sortOrder), asc(optionUnits.createdAt));
1337
1612
  return { ...option, units };
1338
1613
  }));
1339
- const daysWithServices = await Promise.all(days.map(async (day) => {
1340
- const services = await db
1614
+ const itinerariesWithDays = await Promise.all(itineraries.map(async (itinerary) => {
1615
+ const days = await db
1341
1616
  .select()
1342
- .from(productDayServices)
1343
- .where(eq(productDayServices.dayId, day.id))
1344
- .orderBy(asc(productDayServices.sortOrder));
1345
- return { ...day, services };
1617
+ .from(productDays)
1618
+ .where(eq(productDays.itineraryId, itinerary.id))
1619
+ .orderBy(asc(productDays.dayNumber));
1620
+ const daysWithServices = await Promise.all(days.map(async (day) => {
1621
+ const services = await db
1622
+ .select()
1623
+ .from(productDayServices)
1624
+ .where(eq(productDayServices.dayId, day.id))
1625
+ .orderBy(asc(productDayServices.sortOrder));
1626
+ return { ...day, services };
1627
+ }));
1628
+ return { ...itinerary, days: daysWithServices };
1346
1629
  }));
1630
+ const defaultDays = itinerariesWithDays.find((itinerary) => itinerary.id === defaultItinerary?.id)?.days ?? [];
1347
1631
  const [maxVersion] = await db
1348
1632
  .select({ max: sql `coalesce(max(${productVersions.versionNumber}), 0)` })
1349
1633
  .from(productVersions)
@@ -1353,7 +1637,12 @@ export const productsService = {
1353
1637
  .values({
1354
1638
  productId,
1355
1639
  versionNumber: (maxVersion?.max ?? 0) + 1,
1356
- snapshot: { ...product, options: optionsWithUnits, days: daysWithServices },
1640
+ snapshot: {
1641
+ ...product,
1642
+ options: optionsWithUnits,
1643
+ itineraries: itinerariesWithDays,
1644
+ days: defaultDays,
1645
+ },
1357
1646
  authorId: userId,
1358
1647
  notes: data.notes,
1359
1648
  })
@@ -1691,11 +1980,7 @@ export const productsService = {
1691
1980
  if (data.isBrochure) {
1692
1981
  return null;
1693
1982
  }
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);
1983
+ const day = await getDayById(db, data.dayId);
1699
1984
  if (!day || day.productId !== productId) {
1700
1985
  return null;
1701
1986
  }
@@ -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(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/products",
3
- "version": "0.6.7",
3
+ "version": "0.6.9",
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.7",
46
- "@voyantjs/db": "0.6.7",
47
- "@voyantjs/hono": "0.6.7",
48
- "@voyantjs/utils": "0.6.7",
49
- "@voyantjs/voyant-storage": "0.6.7"
45
+ "@voyantjs/core": "0.6.9",
46
+ "@voyantjs/db": "0.6.9",
47
+ "@voyantjs/hono": "0.6.9",
48
+ "@voyantjs/utils": "0.6.9",
49
+ "@voyantjs/voyant-storage": "0.6.9"
50
50
  },
51
51
  "devDependencies": {
52
52
  "typescript": "^6.0.2",