@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/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/routes.d.ts +220 -4
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +48 -1
- package/dist/schema-core.d.ts.map +1 -1
- package/dist/schema-core.js +10 -0
- package/dist/schema-itinerary.d.ts +129 -1
- package/dist/schema-itinerary.d.ts.map +1 -1
- package/dist/schema-itinerary.js +38 -6
- package/dist/schema-relations.d.ts +6 -2
- package/dist/schema-relations.d.ts.map +1 -1
- package/dist/schema-relations.js +13 -3
- package/dist/schema-settings.d.ts.map +1 -1
- package/dist/schema-settings.js +40 -3
- package/dist/schema-taxonomy.d.ts.map +1 -1
- package/dist/schema-taxonomy.js +14 -1
- package/dist/service.d.ts +311 -8
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +318 -33
- package/dist/tasks/brochure-templates.d.ts.map +1 -1
- package/dist/tasks/brochure-templates.js +15 -3
- package/dist/tasks/generate-pdf.d.ts.map +1 -1
- package/dist/tasks/generate-pdf.js +14 -7
- package/dist/validation-content.d.ts +16 -0
- package/dist/validation-content.d.ts.map +1 -1
- package/dist/validation-content.js +10 -0
- package/package.json +6 -6
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
|
-
.
|
|
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
|
-
|
|
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.
|
|
1508
|
+
.where(eq(productDays.itineraryId, itineraryId))
|
|
1231
1509
|
.orderBy(asc(productDays.dayNumber));
|
|
1232
1510
|
},
|
|
1233
1511
|
async createDay(db, productId, data) {
|
|
1234
|
-
const
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
if (!
|
|
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,
|
|
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
|
|
1272
|
-
|
|
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
|
|
1595
|
+
const itineraries = await db
|
|
1322
1596
|
.select()
|
|
1323
|
-
.from(
|
|
1324
|
-
.where(eq(
|
|
1325
|
-
.orderBy(asc(
|
|
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
|
|
1340
|
-
const
|
|
1614
|
+
const itinerariesWithDays = await Promise.all(itineraries.map(async (itinerary) => {
|
|
1615
|
+
const days = await db
|
|
1341
1616
|
.select()
|
|
1342
|
-
.from(
|
|
1343
|
-
.where(eq(
|
|
1344
|
-
.orderBy(asc(
|
|
1345
|
-
|
|
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: {
|
|
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
|
|
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,
|
|
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.
|
|
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,
|
|
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 =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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.
|
|
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.
|
|
46
|
-
"@voyantjs/db": "0.6.
|
|
47
|
-
"@voyantjs/hono": "0.6.
|
|
48
|
-
"@voyantjs/utils": "0.6.
|
|
49
|
-
"@voyantjs/voyant-storage": "0.6.
|
|
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",
|