@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/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/routes.d.ts +243 -4
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +53 -1
- package/dist/schema-itinerary.d.ts +129 -1
- package/dist/schema-itinerary.d.ts.map +1 -1
- package/dist/schema-itinerary.js +24 -5
- 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/service-aggregates.d.ts +29 -0
- package/dist/service-aggregates.d.ts.map +1 -0
- package/dist/service-aggregates.js +53 -0
- package/dist/service.d.ts +313 -8
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +320 -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/dist/validation-core.d.ts +4 -0
- package/dist/validation-core.d.ts.map +1 -1
- package/dist/validation-core.js +4 -0
- package/package.json +6 -6
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
|
-
.
|
|
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
|
-
|
|
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.
|
|
1510
|
+
.where(eq(productDays.itineraryId, itineraryId))
|
|
1231
1511
|
.orderBy(asc(productDays.dayNumber));
|
|
1232
1512
|
},
|
|
1233
1513
|
async createDay(db, productId, data) {
|
|
1234
|
-
const
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
if (!
|
|
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,
|
|
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
|
|
1272
|
-
|
|
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
|
|
1597
|
+
const itineraries = await db
|
|
1322
1598
|
.select()
|
|
1323
|
-
.from(
|
|
1324
|
-
.where(eq(
|
|
1325
|
-
.orderBy(asc(
|
|
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
|
|
1340
|
-
const
|
|
1616
|
+
const itinerariesWithDays = await Promise.all(itineraries.map(async (itinerary) => {
|
|
1617
|
+
const days = await db
|
|
1341
1618
|
.select()
|
|
1342
|
-
.from(
|
|
1343
|
-
.where(eq(
|
|
1344
|
-
.orderBy(asc(
|
|
1345
|
-
|
|
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: {
|
|
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
|
|
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,
|
|
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(),
|
|
@@ -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"}
|
package/dist/validation-core.js
CHANGED
|
@@ -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.
|
|
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.
|
|
46
|
-
"@voyantjs/db": "0.
|
|
47
|
-
"@voyantjs/hono": "0.
|
|
48
|
-
"@voyantjs/utils": "0.
|
|
49
|
-
"@voyantjs/voyant-storage": "0.
|
|
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",
|