@infuro/cms-core 1.0.44 → 1.0.46
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/README.md +19 -2
- package/dist/admin.cjs +1413 -620
- package/dist/admin.d.cts +8 -2
- package/dist/admin.d.ts +8 -2
- package/dist/admin.js +1414 -621
- package/dist/api.cjs +40 -37
- package/dist/api.d.cts +3 -1
- package/dist/api.d.ts +3 -1
- package/dist/api.js +8 -5
- package/dist/auth.cjs +23 -23
- package/dist/auth.d.cts +1 -0
- package/dist/auth.d.ts +1 -0
- package/dist/auth.js +2 -2
- package/dist/chunk-2KUCQVAQ.js +936 -0
- package/dist/chunk-3K5AIEIZ.js +256 -0
- package/dist/{chunk-I6NH72MO.js → chunk-57O3HZPG.js} +9 -1
- package/dist/chunk-7PMHZRF3.cjs +872 -0
- package/dist/chunk-BXYZDMTZ.cjs +953 -0
- package/dist/chunk-CQHXW4TR.js +107 -0
- package/dist/{chunk-NNQBWDCI.js → chunk-CRYKVJTO.js} +55 -959
- package/dist/chunk-DBPSJYLZ.js +47 -0
- package/dist/{chunk-TAHX46EI.cjs → chunk-FBKDMRQL.cjs} +9 -1
- package/dist/chunk-GUSHM5HN.js +862 -0
- package/dist/chunk-HY3AXLOI.cjs +265 -0
- package/dist/chunk-L3525VXI.js +243 -0
- package/dist/{chunk-ZMRQ72F6.cjs → chunk-NBY4NVTY.cjs} +3 -3
- package/dist/chunk-OY2YTBMP.cjs +50 -0
- package/dist/{chunk-BLR6H5GL.js → chunk-SF2XKMCI.js} +3 -3
- package/dist/{chunk-22FFHLTO.cjs → chunk-TCSGFAWB.cjs} +56 -970
- package/dist/{chunk-P2IWWBJV.cjs → chunk-UDVLFVEC.cjs} +1314 -601
- package/dist/{chunk-SQGBHYJF.js → chunk-UKC3HYXI.js} +1245 -548
- package/dist/chunk-V25RDUOU.cjs +248 -0
- package/dist/chunk-XMRMZ6NQ.cjs +109 -0
- package/dist/cli.cjs +9 -4
- package/dist/cli.js +9 -4
- package/dist/{email-queue-TPZWLTIV.cjs → email-queue-6NJY6HNM.cjs} +7 -5
- package/dist/email-queue-OI2HSCGE.js +4 -0
- package/dist/erp-order-invoice-3GXDE443.js +3 -0
- package/dist/erp-order-invoice-EYYNR526.cjs +24 -0
- package/dist/index.cjs +426 -359
- package/dist/index.d.cts +308 -20
- package/dist/index.d.ts +308 -20
- package/dist/index.js +31 -110
- package/dist/migrations/1781800000000-CustomerPhoneNullable.ts +53 -0
- package/dist/migrations/1781810000000-OrderItemsVariantId.ts +44 -0
- package/dist/migrations/1781900000000-UserInviteStatusToken.ts +46 -0
- package/dist/migrations/1782000000000-ComboSlug.ts +58 -0
- package/dist/migrations/1782100000000-DiscountDeviceType.ts +20 -0
- package/dist/order-inventory-2MYRKEPC.cjs +39 -0
- package/dist/order-inventory-76V4XIGW.js +2 -0
- package/dist/order-notification-dispatcher-SBQAMM5V.cjs +21 -0
- package/dist/{order-notification-dispatcher-XWIJYDGA.js → order-notification-dispatcher-ZJZB2HUN.js} +5 -2
- package/dist/retire-soft-deleted-unique-5VXBA5XX.cjs +15 -0
- package/dist/retire-soft-deleted-unique-NXQIH4BC.js +2 -0
- package/dist/send-order-placed-emails-B5ZVJT7T.cjs +15 -0
- package/dist/send-order-placed-emails-WPI37KRZ.js +6 -0
- package/package.json +5 -4
- package/src/admin/admin.css +27 -24
- package/dist/chunk-5ELSW2UP.js +0 -150
- package/dist/chunk-PNOKNSG2.cjs +0 -222
- package/dist/chunk-WEMDMVHQ.js +0 -216
- package/dist/chunk-XW5ATPRW.cjs +0 -155
- package/dist/email-queue-CGZBVVAS.js +0 -2
- package/dist/erp-order-invoice-3YISSOWW.js +0 -3
- package/dist/erp-order-invoice-ZR5F2KTA.cjs +0 -12
- package/dist/order-notification-dispatcher-RU7BTGGX.cjs +0 -18
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkHY3AXLOI_cjs = require('./chunk-HY3AXLOI.cjs');
|
|
4
|
+
var chunkOY2YTBMP_cjs = require('./chunk-OY2YTBMP.cjs');
|
|
5
|
+
var chunk7PMHZRF3_cjs = require('./chunk-7PMHZRF3.cjs');
|
|
6
|
+
var chunkTCSGFAWB_cjs = require('./chunk-TCSGFAWB.cjs');
|
|
4
7
|
var chunk7NMT3GBR_cjs = require('./chunk-7NMT3GBR.cjs');
|
|
5
|
-
var
|
|
6
|
-
var
|
|
8
|
+
var chunkV25RDUOU_cjs = require('./chunk-V25RDUOU.cjs');
|
|
9
|
+
var chunkBXYZDMTZ_cjs = require('./chunk-BXYZDMTZ.cjs');
|
|
7
10
|
var chunk3DZRIZOD_cjs = require('./chunk-3DZRIZOD.cjs');
|
|
8
11
|
var chunkSPQFNIYJ_cjs = require('./chunk-SPQFNIYJ.cjs');
|
|
9
12
|
var chunkXQ3QUHWR_cjs = require('./chunk-XQ3QUHWR.cjs');
|
|
10
|
-
var
|
|
13
|
+
var chunkNBY4NVTY_cjs = require('./chunk-NBY4NVTY.cjs');
|
|
11
14
|
var chunkX6UQFV4X_cjs = require('./chunk-X6UQFV4X.cjs');
|
|
12
15
|
var chunkD5FBNKQM_cjs = require('./chunk-D5FBNKQM.cjs');
|
|
13
16
|
var chunkUPLVMVRX_cjs = require('./chunk-UPLVMVRX.cjs');
|
|
@@ -46,6 +49,7 @@ async function queryVendorLinks(dataSource, userId) {
|
|
|
46
49
|
vr."name" AS "vendorRoleName",
|
|
47
50
|
vr."isOwnerRole" AS "isOwnerRole"
|
|
48
51
|
FROM "vendor_users" vu
|
|
52
|
+
INNER JOIN "vendors" v ON v.id = vu."vendorId" AND v.deleted = false
|
|
49
53
|
LEFT JOIN "vendor_roles" vr ON vr.id = vu."vendorRoleId" AND vr.deleted = false
|
|
50
54
|
WHERE vu."userId" = $1
|
|
51
55
|
ORDER BY vu.id ASC
|
|
@@ -55,10 +59,11 @@ async function queryVendorLinks(dataSource, userId) {
|
|
|
55
59
|
} catch (err) {
|
|
56
60
|
if (!isMissingVendorRoleSchemaError(err)) throw err;
|
|
57
61
|
const legacy = await dataSource.query(`
|
|
58
|
-
SELECT "vendorId", "role"
|
|
59
|
-
FROM "vendor_users"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
SELECT vu."vendorId" AS "vendorId", vu."role" AS "role"
|
|
63
|
+
FROM "vendor_users" vu
|
|
64
|
+
INNER JOIN "vendors" v ON v.id = vu."vendorId" AND v.deleted = false
|
|
65
|
+
WHERE vu."userId" = $1
|
|
66
|
+
ORDER BY vu.id ASC
|
|
62
67
|
`, [
|
|
63
68
|
userId
|
|
64
69
|
]);
|
|
@@ -72,8 +77,36 @@ async function queryVendorLinks(dataSource, userId) {
|
|
|
72
77
|
}
|
|
73
78
|
}
|
|
74
79
|
chunkUSNT2KNT_cjs.__name(queryVendorLinks, "queryVendorLinks");
|
|
80
|
+
async function queryOwnedVendorIds(dataSource, userId) {
|
|
81
|
+
try {
|
|
82
|
+
const rows = await dataSource.query(`
|
|
83
|
+
SELECT id
|
|
84
|
+
FROM "vendors"
|
|
85
|
+
WHERE "userId" = $1 AND deleted = false
|
|
86
|
+
ORDER BY id ASC
|
|
87
|
+
`, [
|
|
88
|
+
userId
|
|
89
|
+
]);
|
|
90
|
+
return rows.map((r) => Number(r.id)).filter((id) => Number.isFinite(id) && id > 0);
|
|
91
|
+
} catch {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
chunkUSNT2KNT_cjs.__name(queryOwnedVendorIds, "queryOwnedVendorIds");
|
|
75
96
|
async function loadUserVendorContext(dataSource, userId, preferredVendorId) {
|
|
76
97
|
const rows = await queryVendorLinks(dataSource, userId);
|
|
98
|
+
const linkIds = new Set(rows.map((r) => Number(r.vendorId)));
|
|
99
|
+
for (const ownedId of await queryOwnedVendorIds(dataSource, userId)) {
|
|
100
|
+
if (linkIds.has(ownedId)) continue;
|
|
101
|
+
rows.push({
|
|
102
|
+
vendorId: ownedId,
|
|
103
|
+
role: "owner",
|
|
104
|
+
vendorRoleId: null,
|
|
105
|
+
vendorRoleName: null,
|
|
106
|
+
isOwnerRole: true
|
|
107
|
+
});
|
|
108
|
+
linkIds.add(ownedId);
|
|
109
|
+
}
|
|
77
110
|
const vendorIds = rows.map((r) => Number(r.vendorId));
|
|
78
111
|
const activeRow = preferredVendorId != null ? rows.find((r) => Number(r.vendorId) === preferredVendorId) : void 0;
|
|
79
112
|
const primary = activeRow ?? rows[0];
|
|
@@ -626,6 +659,144 @@ function applyEventApprovalStatusSideEffects(updatePayload, opts) {
|
|
|
626
659
|
}
|
|
627
660
|
chunkUSNT2KNT_cjs.__name(applyEventApprovalStatusSideEffects, "applyEventApprovalStatusSideEffects");
|
|
628
661
|
|
|
662
|
+
// src/lib/discount-usage.ts
|
|
663
|
+
async function countDiscountOrdersForContact(dataSource, discountId, contactId) {
|
|
664
|
+
try {
|
|
665
|
+
const rows = await dataSource.query(`SELECT COUNT(DISTINCT od."orderId")::int AS count
|
|
666
|
+
FROM order_discounts od
|
|
667
|
+
WHERE od."discountId" = $1 AND od."userId" = $2`, [
|
|
668
|
+
discountId,
|
|
669
|
+
contactId
|
|
670
|
+
]);
|
|
671
|
+
return Number(rows?.[0]?.count ?? 0);
|
|
672
|
+
} catch {
|
|
673
|
+
return 0;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
chunkUSNT2KNT_cjs.__name(countDiscountOrdersForContact, "countDiscountOrdersForContact");
|
|
677
|
+
function isMaxTotalUsageReached(discount) {
|
|
678
|
+
if (discount.maxTotalUsage == null) return false;
|
|
679
|
+
return Number(discount.usedCount ?? 0) >= Number(discount.maxTotalUsage);
|
|
680
|
+
}
|
|
681
|
+
chunkUSNT2KNT_cjs.__name(isMaxTotalUsageReached, "isMaxTotalUsageReached");
|
|
682
|
+
async function isMaxPerUserUsageReached(dataSource, discount, contactId) {
|
|
683
|
+
if (discount.maxUsagePerUser == null || contactId == null) return false;
|
|
684
|
+
const count = await countDiscountOrdersForContact(dataSource, discount.id, contactId);
|
|
685
|
+
return count >= Number(discount.maxUsagePerUser);
|
|
686
|
+
}
|
|
687
|
+
chunkUSNT2KNT_cjs.__name(isMaxPerUserUsageReached, "isMaxPerUserUsageReached");
|
|
688
|
+
async function checkAndIncrementDiscountUsage(dataSource, entityMap, discountId, contactId) {
|
|
689
|
+
if (!entityMap.discounts) return null;
|
|
690
|
+
const discountRepo = dataSource.getRepository(entityMap.discounts);
|
|
691
|
+
const discount = await discountRepo.findOne({
|
|
692
|
+
where: {
|
|
693
|
+
id: discountId
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
if (!discount) return `Discount #${discountId} not found`;
|
|
697
|
+
const d = discount;
|
|
698
|
+
if (d.maxUsagePerUser != null) {
|
|
699
|
+
const usageCount = await countDiscountOrdersForContact(dataSource, discountId, contactId);
|
|
700
|
+
if (usageCount >= Number(d.maxUsagePerUser)) {
|
|
701
|
+
return "You have reached the maximum usage limit for this discount";
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
const updated = await dataSource.query(`UPDATE discounts
|
|
705
|
+
SET "usedCount" = "usedCount" + 1
|
|
706
|
+
WHERE id = $1
|
|
707
|
+
AND ("maxTotalUsage" IS NULL OR "usedCount" < "maxTotalUsage")
|
|
708
|
+
RETURNING id`, [
|
|
709
|
+
discountId
|
|
710
|
+
]);
|
|
711
|
+
if (!Array.isArray(updated) || updated.length === 0) {
|
|
712
|
+
return "Discount usage limit has been reached";
|
|
713
|
+
}
|
|
714
|
+
return null;
|
|
715
|
+
}
|
|
716
|
+
chunkUSNT2KNT_cjs.__name(checkAndIncrementDiscountUsage, "checkAndIncrementDiscountUsage");
|
|
717
|
+
async function decrementDiscountUsage(dataSource, entityMap, discountId, orderId) {
|
|
718
|
+
if (!entityMap.discounts) return;
|
|
719
|
+
try {
|
|
720
|
+
await dataSource.query(`UPDATE discounts SET "usedCount" = GREATEST("usedCount" - 1, 0) WHERE id = $1`, [
|
|
721
|
+
discountId
|
|
722
|
+
]);
|
|
723
|
+
if (entityMap.order_discounts) {
|
|
724
|
+
await dataSource.getRepository(entityMap.order_discounts).delete({
|
|
725
|
+
orderId,
|
|
726
|
+
discountId
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
} catch (err) {
|
|
730
|
+
console.error("[discountEngine] decrementDiscountUsage failed:", err);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
chunkUSNT2KNT_cjs.__name(decrementDiscountUsage, "decrementDiscountUsage");
|
|
734
|
+
async function recordDiscountUsage(dataSource, entityMap, orderId, discountId, contactId, discountAmount) {
|
|
735
|
+
if (!entityMap.order_discounts) return;
|
|
736
|
+
try {
|
|
737
|
+
let discountCode = "";
|
|
738
|
+
if (entityMap.discounts) {
|
|
739
|
+
const discountRow = await dataSource.getRepository(entityMap.discounts).findOne({
|
|
740
|
+
where: {
|
|
741
|
+
id: discountId
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
discountCode = discountRow?.couponCode ?? "";
|
|
745
|
+
}
|
|
746
|
+
const odRepo = dataSource.getRepository(entityMap.order_discounts);
|
|
747
|
+
const orderItemRepo = dataSource.getRepository(entityMap.order_items);
|
|
748
|
+
const items = await orderItemRepo.find({
|
|
749
|
+
where: {
|
|
750
|
+
orderId
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
const discountedItems = items.filter((item) => Number(item.discount ?? 0) > 0);
|
|
754
|
+
if (discountedItems.length === 0) {
|
|
755
|
+
const firstItem = items[0];
|
|
756
|
+
if (!firstItem) return;
|
|
757
|
+
await odRepo.save(odRepo.create({
|
|
758
|
+
orderId,
|
|
759
|
+
orderItemId: firstItem.id,
|
|
760
|
+
discountId,
|
|
761
|
+
discountCode,
|
|
762
|
+
discountAmount,
|
|
763
|
+
userId: contactId
|
|
764
|
+
}));
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
for (const item of discountedItems) {
|
|
768
|
+
const i = item;
|
|
769
|
+
await odRepo.save(odRepo.create({
|
|
770
|
+
orderId,
|
|
771
|
+
orderItemId: i.id,
|
|
772
|
+
discountId,
|
|
773
|
+
discountCode,
|
|
774
|
+
discountAmount: Number(i.discount ?? 0),
|
|
775
|
+
userId: contactId
|
|
776
|
+
}));
|
|
777
|
+
}
|
|
778
|
+
} catch (err) {
|
|
779
|
+
console.error("[discountEngine] recordDiscountUsage failed:", err);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
chunkUSNT2KNT_cjs.__name(recordDiscountUsage, "recordDiscountUsage");
|
|
783
|
+
async function consumeAppliedDiscountUsages(dataSource, entityMap, orderId, contactId, applied) {
|
|
784
|
+
const unique = /* @__PURE__ */ new Map();
|
|
785
|
+
for (const row of applied) {
|
|
786
|
+
const id = Number(row.id);
|
|
787
|
+
if (!Number.isFinite(id) || id < 1) continue;
|
|
788
|
+
const amount = Math.max(0, Number(row.calculatedDiscount) || 0);
|
|
789
|
+
unique.set(id, (unique.get(id) ?? 0) + amount);
|
|
790
|
+
}
|
|
791
|
+
for (const [discountId, discountAmount] of unique) {
|
|
792
|
+
const usageErr = await checkAndIncrementDiscountUsage(dataSource, entityMap, discountId, contactId);
|
|
793
|
+
if (usageErr) return usageErr;
|
|
794
|
+
await recordDiscountUsage(dataSource, entityMap, orderId, discountId, contactId, discountAmount);
|
|
795
|
+
}
|
|
796
|
+
return null;
|
|
797
|
+
}
|
|
798
|
+
chunkUSNT2KNT_cjs.__name(consumeAppliedDiscountUsages, "consumeAppliedDiscountUsages");
|
|
799
|
+
|
|
629
800
|
// src/lib/default-vendor-id.ts
|
|
630
801
|
function getDefaultVendorId() {
|
|
631
802
|
const raw = process.env.DEFAULT_VENDOR_ID;
|
|
@@ -1100,11 +1271,118 @@ function pgErrorCode(err) {
|
|
|
1100
1271
|
return driver?.code ?? err.code;
|
|
1101
1272
|
}
|
|
1102
1273
|
chunkUSNT2KNT_cjs.__name(pgErrorCode, "pgErrorCode");
|
|
1103
|
-
function
|
|
1274
|
+
function normalizeCustomerPhone(phone) {
|
|
1104
1275
|
const p = typeof phone === "string" ? phone.trim() : "";
|
|
1105
|
-
return p ||
|
|
1276
|
+
return p || null;
|
|
1277
|
+
}
|
|
1278
|
+
chunkUSNT2KNT_cjs.__name(normalizeCustomerPhone, "normalizeCustomerPhone");
|
|
1279
|
+
function isSyntheticCustomerPhone(phone) {
|
|
1280
|
+
const p = String(phone ?? "").trim();
|
|
1281
|
+
if (!p) return true;
|
|
1282
|
+
if (p.startsWith("e-") || p.startsWith("u-")) return true;
|
|
1283
|
+
if (p.includes("@")) return true;
|
|
1284
|
+
return false;
|
|
1285
|
+
}
|
|
1286
|
+
chunkUSNT2KNT_cjs.__name(isSyntheticCustomerPhone, "isSyntheticCustomerPhone");
|
|
1287
|
+
function customerPhoneForUser(_userId, phone) {
|
|
1288
|
+
return normalizeCustomerPhone(phone);
|
|
1106
1289
|
}
|
|
1107
1290
|
chunkUSNT2KNT_cjs.__name(customerPhoneForUser, "customerPhoneForUser");
|
|
1291
|
+
function customerPhoneForEmail(_email, phone) {
|
|
1292
|
+
return normalizeCustomerPhone(phone);
|
|
1293
|
+
}
|
|
1294
|
+
chunkUSNT2KNT_cjs.__name(customerPhoneForEmail, "customerPhoneForEmail");
|
|
1295
|
+
function resolveNextPhone(inputPhone, existingPhone) {
|
|
1296
|
+
if (inputPhone) return inputPhone;
|
|
1297
|
+
const existing = normalizeCustomerPhone(existingPhone);
|
|
1298
|
+
if (!existing || isSyntheticCustomerPhone(existing)) return null;
|
|
1299
|
+
return existing;
|
|
1300
|
+
}
|
|
1301
|
+
chunkUSNT2KNT_cjs.__name(resolveNextPhone, "resolveNextPhone");
|
|
1302
|
+
async function ensureCustomerRecord(dsOrEm, customerEntity, input) {
|
|
1303
|
+
const repo = dsOrEm.getRepository(customerEntity);
|
|
1304
|
+
const email = normalizeEmail(input.email);
|
|
1305
|
+
if (!email) return null;
|
|
1306
|
+
const name = String(input.name ?? "").trim() || email.split("@")[0] || "Customer";
|
|
1307
|
+
const userId = input.userId != null && Number.isFinite(Number(input.userId)) && Number(input.userId) > 0 ? Number(input.userId) : null;
|
|
1308
|
+
const phone = normalizeCustomerPhone(input.phone);
|
|
1309
|
+
let row = await repo.findOne({
|
|
1310
|
+
where: {
|
|
1311
|
+
email,
|
|
1312
|
+
deleted: false
|
|
1313
|
+
}
|
|
1314
|
+
});
|
|
1315
|
+
if (!row) {
|
|
1316
|
+
row = await repo.findOne({
|
|
1317
|
+
where: {
|
|
1318
|
+
email
|
|
1319
|
+
}
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
if (row) {
|
|
1323
|
+
const existingUserId = row.userId;
|
|
1324
|
+
if (userId != null && existingUserId != null && existingUserId !== userId) {
|
|
1325
|
+
return null;
|
|
1326
|
+
}
|
|
1327
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
1328
|
+
const patch = {
|
|
1329
|
+
name,
|
|
1330
|
+
phone: nextPhone,
|
|
1331
|
+
deleted: false,
|
|
1332
|
+
deletedAt: null,
|
|
1333
|
+
deletedBy: null,
|
|
1334
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1335
|
+
};
|
|
1336
|
+
if (userId != null && existingUserId == null) {
|
|
1337
|
+
patch.userId = userId;
|
|
1338
|
+
}
|
|
1339
|
+
await repo.update(row.id, patch);
|
|
1340
|
+
return {
|
|
1341
|
+
id: row.id
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
try {
|
|
1345
|
+
const created = await repo.save(repo.create({
|
|
1346
|
+
userId,
|
|
1347
|
+
name,
|
|
1348
|
+
email,
|
|
1349
|
+
phone,
|
|
1350
|
+
deleted: false
|
|
1351
|
+
}));
|
|
1352
|
+
return {
|
|
1353
|
+
id: created.id
|
|
1354
|
+
};
|
|
1355
|
+
} catch (err) {
|
|
1356
|
+
const code = pgErrorCode(err);
|
|
1357
|
+
if (code === "25P02") throw err;
|
|
1358
|
+
row = await repo.findOne({
|
|
1359
|
+
where: {
|
|
1360
|
+
email
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
if (row) {
|
|
1364
|
+
const existingUserId = row.userId;
|
|
1365
|
+
if (userId != null && existingUserId != null && existingUserId !== userId) return null;
|
|
1366
|
+
await repo.update(row.id, {
|
|
1367
|
+
name,
|
|
1368
|
+
phone: resolveNextPhone(phone, row.phone),
|
|
1369
|
+
...userId != null && existingUserId == null ? {
|
|
1370
|
+
userId
|
|
1371
|
+
} : {},
|
|
1372
|
+
deleted: false,
|
|
1373
|
+
deletedAt: null,
|
|
1374
|
+
deletedBy: null,
|
|
1375
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1376
|
+
});
|
|
1377
|
+
return {
|
|
1378
|
+
id: row.id
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
if (code === "23505") return null;
|
|
1382
|
+
throw err;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
chunkUSNT2KNT_cjs.__name(ensureCustomerRecord, "ensureCustomerRecord");
|
|
1108
1386
|
async function restoreCustomerRow(repo, row, user, name, email, phone) {
|
|
1109
1387
|
const id = row.id;
|
|
1110
1388
|
await repo.update(id, {
|
|
@@ -1126,7 +1404,7 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1126
1404
|
const repo = dsOrEm.getRepository(customerEntity);
|
|
1127
1405
|
const email = normalizeEmail(user.email);
|
|
1128
1406
|
const name = String(user.name ?? "").trim() || email.split("@")[0] || "User";
|
|
1129
|
-
const phone =
|
|
1407
|
+
const phone = normalizeCustomerPhone(overrides?.phone ?? user.phone);
|
|
1130
1408
|
let row = await repo.findOne({
|
|
1131
1409
|
where: {
|
|
1132
1410
|
userId: user.id,
|
|
@@ -1134,10 +1412,11 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1134
1412
|
}
|
|
1135
1413
|
});
|
|
1136
1414
|
if (row) {
|
|
1415
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
1137
1416
|
await repo.update(row.id, {
|
|
1138
1417
|
name,
|
|
1139
1418
|
email,
|
|
1140
|
-
phone,
|
|
1419
|
+
phone: nextPhone,
|
|
1141
1420
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1142
1421
|
});
|
|
1143
1422
|
return {
|
|
@@ -1155,10 +1434,11 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1155
1434
|
if (existingUserId != null && existingUserId !== user.id) {
|
|
1156
1435
|
return null;
|
|
1157
1436
|
}
|
|
1437
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
1158
1438
|
await repo.update(row.id, {
|
|
1159
1439
|
userId: user.id,
|
|
1160
1440
|
name,
|
|
1161
|
-
phone,
|
|
1441
|
+
phone: nextPhone,
|
|
1162
1442
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1163
1443
|
});
|
|
1164
1444
|
return {
|
|
@@ -1173,21 +1453,23 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1173
1453
|
if (deletedByEmail) {
|
|
1174
1454
|
const existingUserId = deletedByEmail.userId;
|
|
1175
1455
|
if (existingUserId != null && existingUserId !== user.id) return null;
|
|
1176
|
-
return restoreCustomerRow(repo, deletedByEmail, user, name, email, phone);
|
|
1456
|
+
return restoreCustomerRow(repo, deletedByEmail, user, name, email, resolveNextPhone(phone, deletedByEmail.phone));
|
|
1177
1457
|
}
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1458
|
+
if (phone) {
|
|
1459
|
+
const deletedByPhone = await repo.findOne({
|
|
1460
|
+
where: {
|
|
1461
|
+
phone
|
|
1462
|
+
}
|
|
1463
|
+
});
|
|
1464
|
+
if (deletedByPhone) {
|
|
1465
|
+
const existingUserId = deletedByPhone.userId;
|
|
1466
|
+
if (existingUserId != null && existingUserId !== user.id) {
|
|
1467
|
+
return ensureCustomerForUser(dsOrEm, customerEntity, user, {
|
|
1468
|
+
phone: null
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
return restoreCustomerRow(repo, deletedByPhone, user, name, email, phone);
|
|
1189
1472
|
}
|
|
1190
|
-
return restoreCustomerRow(repo, deletedByPhone, user, name, email, phone);
|
|
1191
1473
|
}
|
|
1192
1474
|
try {
|
|
1193
1475
|
const created = await repo.save(repo.create({
|
|
@@ -1208,34 +1490,22 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1208
1490
|
userId: user.id
|
|
1209
1491
|
}
|
|
1210
1492
|
});
|
|
1211
|
-
if (row)
|
|
1493
|
+
if (row) {
|
|
1494
|
+
return restoreCustomerRow(repo, row, user, name, email, resolveNextPhone(phone, row.phone));
|
|
1495
|
+
}
|
|
1212
1496
|
row = await repo.findOne({
|
|
1213
1497
|
where: {
|
|
1214
1498
|
email
|
|
1215
1499
|
}
|
|
1216
1500
|
});
|
|
1217
1501
|
if (row && (row.userId ?? user.id) === user.id) {
|
|
1218
|
-
return restoreCustomerRow(repo, row, user, name, email, phone);
|
|
1502
|
+
return restoreCustomerRow(repo, row, user, name, email, resolveNextPhone(phone, row.phone));
|
|
1219
1503
|
}
|
|
1220
1504
|
if (code === "23505") return null;
|
|
1221
1505
|
throw err;
|
|
1222
1506
|
}
|
|
1223
1507
|
}
|
|
1224
1508
|
chunkUSNT2KNT_cjs.__name(ensureCustomerForUser, "ensureCustomerForUser");
|
|
1225
|
-
async function linkUnclaimedContactToUser(dataSource, contactsEntity, userId, email) {
|
|
1226
|
-
const repo = dataSource.getRepository(contactsEntity);
|
|
1227
|
-
const found = await repo.findOne({
|
|
1228
|
-
where: {
|
|
1229
|
-
email,
|
|
1230
|
-
userId: typeorm.IsNull(),
|
|
1231
|
-
deleted: false
|
|
1232
|
-
}
|
|
1233
|
-
});
|
|
1234
|
-
if (found) await repo.update(found.id, {
|
|
1235
|
-
userId
|
|
1236
|
-
});
|
|
1237
|
-
}
|
|
1238
|
-
chunkUSNT2KNT_cjs.__name(linkUnclaimedContactToUser, "linkUnclaimedContactToUser");
|
|
1239
1509
|
|
|
1240
1510
|
// src/lib/vendor-customer-contacts.ts
|
|
1241
1511
|
function isCustomerTypeContact(type) {
|
|
@@ -1328,8 +1598,27 @@ function resolveVendorIdForContactCheck(scope, bodyOrRow) {
|
|
|
1328
1598
|
return Number.isFinite(n) ? n : null;
|
|
1329
1599
|
}
|
|
1330
1600
|
chunkUSNT2KNT_cjs.__name(resolveVendorIdForContactCheck, "resolveVendorIdForContactCheck");
|
|
1601
|
+
function uniquePositiveIds(ids) {
|
|
1602
|
+
const out = [];
|
|
1603
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1604
|
+
for (const raw of ids) {
|
|
1605
|
+
const n = Number(raw);
|
|
1606
|
+
if (!Number.isFinite(n) || n <= 0 || seen.has(n)) continue;
|
|
1607
|
+
seen.add(n);
|
|
1608
|
+
out.push(n);
|
|
1609
|
+
}
|
|
1610
|
+
return out;
|
|
1611
|
+
}
|
|
1612
|
+
chunkUSNT2KNT_cjs.__name(uniquePositiveIds, "uniquePositiveIds");
|
|
1331
1613
|
async function ensureVendorCustomerForOrderContact(dataSource, entityMap, vendorId, contactId, details) {
|
|
1332
|
-
|
|
1614
|
+
await ensureVendorCustomersForOrder(dataSource, entityMap, [
|
|
1615
|
+
vendorId
|
|
1616
|
+
], contactId, details);
|
|
1617
|
+
}
|
|
1618
|
+
chunkUSNT2KNT_cjs.__name(ensureVendorCustomerForOrderContact, "ensureVendorCustomerForOrderContact");
|
|
1619
|
+
async function ensureVendorCustomersForOrder(dataSource, entityMap, vendorIds, contactId, details) {
|
|
1620
|
+
const vendors = uniquePositiveIds(vendorIds);
|
|
1621
|
+
if (vendors.length === 0 || !Number.isFinite(contactId) || contactId <= 0) return;
|
|
1333
1622
|
const vcEntity = entityMap.vendor_customers;
|
|
1334
1623
|
const contactEntity = entityMap.contacts;
|
|
1335
1624
|
if (!vcEntity || !contactEntity) return;
|
|
@@ -1355,96 +1644,61 @@ async function ensureVendorCustomerForOrderContact(dataSource, entityMap, vendor
|
|
|
1355
1644
|
}
|
|
1356
1645
|
let customerId = null;
|
|
1357
1646
|
if (entityMap.customer) {
|
|
1358
|
-
const
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
}
|
|
1647
|
+
const ensured = await ensureCustomerRecord(dataSource, entityMap.customer, {
|
|
1648
|
+
name,
|
|
1649
|
+
email,
|
|
1650
|
+
phone,
|
|
1651
|
+
userId: null
|
|
1364
1652
|
});
|
|
1365
|
-
if (
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1653
|
+
if (ensured) customerId = ensured.id;
|
|
1654
|
+
}
|
|
1655
|
+
for (const vendorId of vendors) {
|
|
1656
|
+
if (customerId != null) {
|
|
1657
|
+
const byCustomer = await vcRepo.findOne({
|
|
1370
1658
|
where: {
|
|
1371
|
-
|
|
1372
|
-
|
|
1659
|
+
vendorId,
|
|
1660
|
+
customerId
|
|
1373
1661
|
}
|
|
1374
1662
|
});
|
|
1375
|
-
if (
|
|
1376
|
-
|
|
1377
|
-
if (
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
where: {
|
|
1381
|
-
name: "Customer",
|
|
1382
|
-
deleted: false
|
|
1383
|
-
}
|
|
1663
|
+
if (byCustomer) {
|
|
1664
|
+
const existingContactId = byCustomer.contactId;
|
|
1665
|
+
if (existingContactId == null) {
|
|
1666
|
+
await vcRepo.update(byCustomer.id, {
|
|
1667
|
+
contactId
|
|
1384
1668
|
});
|
|
1385
|
-
if (customerGroup) groupId = Number(customerGroup.id);
|
|
1386
1669
|
}
|
|
1387
|
-
|
|
1388
|
-
name,
|
|
1389
|
-
email,
|
|
1390
|
-
phone,
|
|
1391
|
-
password: null,
|
|
1392
|
-
blocked: false,
|
|
1393
|
-
groupId,
|
|
1394
|
-
adminAccess: false
|
|
1395
|
-
}));
|
|
1670
|
+
continue;
|
|
1396
1671
|
}
|
|
1397
|
-
const userId = Number(user.id);
|
|
1398
|
-
await linkUnclaimedContactToUser(dataSource, contactEntity, userId, email);
|
|
1399
|
-
const ensured = await ensureCustomerForUser(dataSource, entityMap.customer, {
|
|
1400
|
-
id: userId,
|
|
1401
|
-
name,
|
|
1402
|
-
email,
|
|
1403
|
-
phone
|
|
1404
|
-
}, {
|
|
1405
|
-
phone
|
|
1406
|
-
});
|
|
1407
|
-
if (ensured) customerId = ensured.id;
|
|
1408
1672
|
}
|
|
1409
|
-
|
|
1410
|
-
if (customerId != null) {
|
|
1411
|
-
const byCustomer = await vcRepo.findOne({
|
|
1673
|
+
const byContact = await vcRepo.findOne({
|
|
1412
1674
|
where: {
|
|
1413
1675
|
vendorId,
|
|
1414
|
-
|
|
1676
|
+
contactId
|
|
1415
1677
|
}
|
|
1416
1678
|
});
|
|
1417
|
-
if (
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
contactId
|
|
1679
|
+
if (byContact) {
|
|
1680
|
+
if (customerId != null && byContact.customerId == null) {
|
|
1681
|
+
await vcRepo.update(byContact.id, {
|
|
1682
|
+
customerId
|
|
1422
1683
|
});
|
|
1423
1684
|
}
|
|
1424
|
-
|
|
1685
|
+
continue;
|
|
1425
1686
|
}
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1687
|
+
if (customerId != null) {
|
|
1688
|
+
await vcRepo.save(vcRepo.create({
|
|
1689
|
+
vendorId,
|
|
1690
|
+
customerId,
|
|
1691
|
+
contactId
|
|
1692
|
+
}));
|
|
1693
|
+
} else {
|
|
1694
|
+
await vcRepo.save(vcRepo.create({
|
|
1695
|
+
vendorId,
|
|
1696
|
+
contactId
|
|
1697
|
+
}));
|
|
1431
1698
|
}
|
|
1432
|
-
});
|
|
1433
|
-
if (byContact) return;
|
|
1434
|
-
if (customerId != null) {
|
|
1435
|
-
await vcRepo.save(vcRepo.create({
|
|
1436
|
-
vendorId,
|
|
1437
|
-
customerId,
|
|
1438
|
-
contactId
|
|
1439
|
-
}));
|
|
1440
|
-
return;
|
|
1441
1699
|
}
|
|
1442
|
-
await vcRepo.save(vcRepo.create({
|
|
1443
|
-
vendorId,
|
|
1444
|
-
contactId
|
|
1445
|
-
}));
|
|
1446
1700
|
}
|
|
1447
|
-
chunkUSNT2KNT_cjs.__name(
|
|
1701
|
+
chunkUSNT2KNT_cjs.__name(ensureVendorCustomersForOrder, "ensureVendorCustomersForOrder");
|
|
1448
1702
|
|
|
1449
1703
|
// src/lib/currency-prices.ts
|
|
1450
1704
|
function normalizeCurrencyCode(code) {
|
|
@@ -1886,6 +2140,7 @@ async function ensureUniqueProductSlug(repo, baseSlug, vendorId, excludeId) {
|
|
|
1886
2140
|
let slug = baseSlug;
|
|
1887
2141
|
let suffix = 0;
|
|
1888
2142
|
while (true) {
|
|
2143
|
+
await chunkOY2YTBMP_cjs.retireSoftDeletedUniqueValue(repo, "slug", slug);
|
|
1889
2144
|
const where = excludeId != null ? {
|
|
1890
2145
|
slug,
|
|
1891
2146
|
vendorId,
|
|
@@ -1905,6 +2160,21 @@ async function ensureUniqueProductSlug(repo, baseSlug, vendorId, excludeId) {
|
|
|
1905
2160
|
}
|
|
1906
2161
|
}
|
|
1907
2162
|
chunkUSNT2KNT_cjs.__name(ensureUniqueProductSlug, "ensureUniqueProductSlug");
|
|
2163
|
+
async function normalizeComboNameAndSlug(repo, body, vendorId, existing, excludeId) {
|
|
2164
|
+
const incomingName = typeof body.name === "string" ? body.name.trim() : "";
|
|
2165
|
+
const incomingSlugRaw = typeof body.slug === "string" ? body.slug.trim() : "";
|
|
2166
|
+
const existingName = typeof existing?.name === "string" ? existing.name.trim() : "";
|
|
2167
|
+
const existingSlug = typeof existing?.slug === "string" ? existing.slug.trim() : "";
|
|
2168
|
+
const name = incomingName || existingName;
|
|
2169
|
+
if (!name) return "Name is required";
|
|
2170
|
+
if (incomingName) body.name = name;
|
|
2171
|
+
const nameBasedSlug = slugifyProductLabel(name);
|
|
2172
|
+
const typedSlug = incomingSlugRaw ? slugifyProductLabel(incomingSlugRaw) : "";
|
|
2173
|
+
const slug = typedSlug || (excludeId != null ? existingSlug : "") || nameBasedSlug;
|
|
2174
|
+
body.slug = await ensureUniqueProductSlug(repo, slug, vendorId, excludeId);
|
|
2175
|
+
return null;
|
|
2176
|
+
}
|
|
2177
|
+
chunkUSNT2KNT_cjs.__name(normalizeComboNameAndSlug, "normalizeComboNameAndSlug");
|
|
1908
2178
|
async function hydrateProductEventNames(dataSource, entityMap, products) {
|
|
1909
2179
|
if (!products.length) return products;
|
|
1910
2180
|
if (!entityMap.event_products || !entityMap.events) {
|
|
@@ -2151,6 +2421,20 @@ async function normalizeProductNameAndSlug(repo, body, vendorId, existing, exclu
|
|
|
2151
2421
|
return null;
|
|
2152
2422
|
}
|
|
2153
2423
|
chunkUSNT2KNT_cjs.__name(normalizeProductNameAndSlug, "normalizeProductNameAndSlug");
|
|
2424
|
+
async function retireSoftDeletedUniquesFromBody(repo, body) {
|
|
2425
|
+
const cols = new Set(repo.metadata.columns.map((c) => c.propertyName));
|
|
2426
|
+
if (!cols.has("deleted")) return;
|
|
2427
|
+
for (const col of [
|
|
2428
|
+
"slug",
|
|
2429
|
+
"email"
|
|
2430
|
+
]) {
|
|
2431
|
+
if (!cols.has(col)) continue;
|
|
2432
|
+
const raw = body[col];
|
|
2433
|
+
if (typeof raw !== "string" || !raw.trim()) continue;
|
|
2434
|
+
await chunkOY2YTBMP_cjs.retireSoftDeletedUniqueValue(repo, col, raw.trim());
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
chunkUSNT2KNT_cjs.__name(retireSoftDeletedUniquesFromBody, "retireSoftDeletedUniquesFromBody");
|
|
2154
2438
|
function buildSoftDeletePayload(meta, deletedBy) {
|
|
2155
2439
|
const payload = {
|
|
2156
2440
|
deleted: true
|
|
@@ -2387,6 +2671,7 @@ function discountEvaluateRule(rule, cartLines, cartTotal) {
|
|
|
2387
2671
|
case "category":
|
|
2388
2672
|
case "cart":
|
|
2389
2673
|
case "paymentMethod":
|
|
2674
|
+
case "deviceType":
|
|
2390
2675
|
case "order": {
|
|
2391
2676
|
if (rule.subType === "nthOrder") {
|
|
2392
2677
|
return true;
|
|
@@ -2570,87 +2855,22 @@ function applyDiscountToOrderLines(lines, evalResult, maxDiscountAmount) {
|
|
|
2570
2855
|
return totalDiscountApplied;
|
|
2571
2856
|
}
|
|
2572
2857
|
chunkUSNT2KNT_cjs.__name(applyDiscountToOrderLines, "applyDiscountToOrderLines");
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
const discountRepo = dataSource.getRepository(entityMap["discounts"]);
|
|
2576
|
-
const discount = await discountRepo.findOne({
|
|
2577
|
-
where: {
|
|
2578
|
-
id: discountId
|
|
2579
|
-
}
|
|
2580
|
-
});
|
|
2581
|
-
if (!discount) return `Discount #${discountId} not found`;
|
|
2582
|
-
await dataSource.query(`UPDATE discounts SET "usedCount" = "usedCount" + 1 WHERE id = $1`, [
|
|
2583
|
-
discountId
|
|
2584
|
-
]);
|
|
2585
|
-
return null;
|
|
2858
|
+
function asDiscountUsageEntityMap(entityMap) {
|
|
2859
|
+
return entityMap;
|
|
2586
2860
|
}
|
|
2587
|
-
chunkUSNT2KNT_cjs.__name(
|
|
2588
|
-
async function
|
|
2589
|
-
|
|
2590
|
-
try {
|
|
2591
|
-
await dataSource.query(`UPDATE discounts SET "usedCount" = GREATEST("usedCount" - 1, 0) WHERE id = $1`, [
|
|
2592
|
-
discountId
|
|
2593
|
-
]);
|
|
2594
|
-
if (entityMap["order_discounts"]) {
|
|
2595
|
-
await dataSource.getRepository(entityMap["order_discounts"]).delete({
|
|
2596
|
-
orderId,
|
|
2597
|
-
discountId
|
|
2598
|
-
});
|
|
2599
|
-
}
|
|
2600
|
-
} catch (err) {
|
|
2601
|
-
console.error("[discountEngine] decrementDiscountUsage failed:", err);
|
|
2602
|
-
}
|
|
2861
|
+
chunkUSNT2KNT_cjs.__name(asDiscountUsageEntityMap, "asDiscountUsageEntityMap");
|
|
2862
|
+
async function checkAndIncrementDiscountUsage2(dataSource, entityMap, discountId, contactId) {
|
|
2863
|
+
return checkAndIncrementDiscountUsage(dataSource, asDiscountUsageEntityMap(entityMap), discountId, contactId);
|
|
2603
2864
|
}
|
|
2604
|
-
chunkUSNT2KNT_cjs.__name(
|
|
2605
|
-
async function
|
|
2606
|
-
|
|
2607
|
-
try {
|
|
2608
|
-
let discountCode = "";
|
|
2609
|
-
if (entityMap["discounts"]) {
|
|
2610
|
-
const discountRow = await dataSource.getRepository(entityMap["discounts"]).findOne({
|
|
2611
|
-
where: {
|
|
2612
|
-
id: discountId
|
|
2613
|
-
}
|
|
2614
|
-
});
|
|
2615
|
-
discountCode = discountRow?.couponCode ?? "";
|
|
2616
|
-
}
|
|
2617
|
-
const odRepo = dataSource.getRepository(entityMap["order_discounts"]);
|
|
2618
|
-
const orderItemRepo = dataSource.getRepository(entityMap.order_items);
|
|
2619
|
-
const items = await orderItemRepo.find({
|
|
2620
|
-
where: {
|
|
2621
|
-
orderId
|
|
2622
|
-
}
|
|
2623
|
-
});
|
|
2624
|
-
const discountedItems = items.filter((item) => Number(item.discount ?? 0) > 0);
|
|
2625
|
-
if (discountedItems.length === 0) {
|
|
2626
|
-
const firstItem = items[0];
|
|
2627
|
-
if (!firstItem) return;
|
|
2628
|
-
await odRepo.save(odRepo.create({
|
|
2629
|
-
orderId,
|
|
2630
|
-
orderItemId: firstItem.id,
|
|
2631
|
-
discountId,
|
|
2632
|
-
discountCode,
|
|
2633
|
-
discountAmount,
|
|
2634
|
-
userId: contactId
|
|
2635
|
-
}));
|
|
2636
|
-
return;
|
|
2637
|
-
}
|
|
2638
|
-
for (const item of discountedItems) {
|
|
2639
|
-
const i = item;
|
|
2640
|
-
await odRepo.save(odRepo.create({
|
|
2641
|
-
orderId,
|
|
2642
|
-
orderItemId: i.id,
|
|
2643
|
-
discountId,
|
|
2644
|
-
discountCode,
|
|
2645
|
-
discountAmount: Number(i.discount ?? 0),
|
|
2646
|
-
userId: contactId
|
|
2647
|
-
}));
|
|
2648
|
-
}
|
|
2649
|
-
} catch (err) {
|
|
2650
|
-
console.error("[discountEngine] recordDiscountUsage failed:", err);
|
|
2651
|
-
}
|
|
2865
|
+
chunkUSNT2KNT_cjs.__name(checkAndIncrementDiscountUsage2, "checkAndIncrementDiscountUsage");
|
|
2866
|
+
async function decrementDiscountUsage2(dataSource, entityMap, discountId, orderId) {
|
|
2867
|
+
return decrementDiscountUsage(dataSource, asDiscountUsageEntityMap(entityMap), discountId, orderId);
|
|
2652
2868
|
}
|
|
2653
|
-
chunkUSNT2KNT_cjs.__name(
|
|
2869
|
+
chunkUSNT2KNT_cjs.__name(decrementDiscountUsage2, "decrementDiscountUsage");
|
|
2870
|
+
async function recordDiscountUsage2(dataSource, entityMap, orderId, discountId, contactId, discountAmount) {
|
|
2871
|
+
return recordDiscountUsage(dataSource, asDiscountUsageEntityMap(entityMap), orderId, discountId, contactId, discountAmount);
|
|
2872
|
+
}
|
|
2873
|
+
chunkUSNT2KNT_cjs.__name(recordDiscountUsage2, "recordDiscountUsage");
|
|
2654
2874
|
async function validateCoupon(dataSource, entityMap, couponCode, orderLines, currency = "INR", contactId, isAutomatic, discountId, vendorId) {
|
|
2655
2875
|
if (!entityMap["discounts"]) return {
|
|
2656
2876
|
valid: false,
|
|
@@ -2695,21 +2915,12 @@ async function validateCoupon(dataSource, entityMap, couponCode, orderLines, cur
|
|
|
2695
2915
|
};
|
|
2696
2916
|
}
|
|
2697
2917
|
if (contactId != null && d.maxUsagePerUser != null) {
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
]);
|
|
2705
|
-
const usageCount = Number(userUsage?.[0]?.count ?? 0);
|
|
2706
|
-
if (usageCount >= d.maxUsagePerUser) {
|
|
2707
|
-
return {
|
|
2708
|
-
valid: false,
|
|
2709
|
-
error: "You have reached the maximum usage limit for this discount"
|
|
2710
|
-
};
|
|
2711
|
-
}
|
|
2712
|
-
} catch {
|
|
2918
|
+
const usageCount = await countDiscountOrdersForContact(dataSource, d.id, contactId);
|
|
2919
|
+
if (usageCount >= d.maxUsagePerUser) {
|
|
2920
|
+
return {
|
|
2921
|
+
valid: false,
|
|
2922
|
+
error: "You have reached the maximum usage limit for this discount"
|
|
2923
|
+
};
|
|
2713
2924
|
}
|
|
2714
2925
|
}
|
|
2715
2926
|
const flatRules = entityMap["discount_rules"] ? await dataSource.getRepository(entityMap["discount_rules"]).find({
|
|
@@ -2787,128 +2998,32 @@ function normalizeOrderLinesInput(raw) {
|
|
|
2787
2998
|
if (!Number.isFinite(productId) || productId <= 0) continue;
|
|
2788
2999
|
const qRaw = Number(r.quantity ?? 1);
|
|
2789
3000
|
const q = Number.isFinite(qRaw) ? Math.min(99999, Math.max(1, Math.floor(qRaw))) : 1;
|
|
2790
|
-
|
|
3001
|
+
const vidRaw = r.variantId ?? r.variant_id;
|
|
3002
|
+
const vid = vidRaw != null && String(vidRaw).trim() !== "" ? Number(vidRaw) : NaN;
|
|
3003
|
+
const variantId = Number.isFinite(vid) && vid > 0 ? vid : null;
|
|
3004
|
+
const key = `${productId}:${variantId ?? 0}`;
|
|
3005
|
+
const prev = merged.get(key);
|
|
3006
|
+
if (prev) prev.quantity += q;
|
|
3007
|
+
else merged.set(key, {
|
|
3008
|
+
productId,
|
|
3009
|
+
quantity: q,
|
|
3010
|
+
variantId
|
|
3011
|
+
});
|
|
2791
3012
|
}
|
|
2792
3013
|
return [
|
|
2793
|
-
...merged.
|
|
2794
|
-
]
|
|
2795
|
-
productId,
|
|
2796
|
-
quantity
|
|
2797
|
-
}));
|
|
3014
|
+
...merged.values()
|
|
3015
|
+
];
|
|
2798
3016
|
}
|
|
2799
3017
|
chunkUSNT2KNT_cjs.__name(normalizeOrderLinesInput, "normalizeOrderLinesInput");
|
|
2800
|
-
var ORDER_STATUS_CONFIRMED = "confirmed";
|
|
2801
|
-
function
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
})).filter((l) => l.productId > 0 && l.quantity > 0)
|
|
2808
|
-
};
|
|
2809
|
-
}
|
|
2810
|
-
chunkUSNT2KNT_cjs.__name(orderInventorySnapshotFromRow, "orderInventorySnapshotFromRow");
|
|
2811
|
-
function mergeInventoryLinesByProduct(lines) {
|
|
2812
|
-
const m = /* @__PURE__ */ new Map();
|
|
2813
|
-
for (const { productId, quantity } of lines) {
|
|
2814
|
-
if (!Number.isFinite(productId) || productId <= 0 || quantity <= 0) continue;
|
|
2815
|
-
m.set(productId, (m.get(productId) ?? 0) + quantity);
|
|
2816
|
-
}
|
|
2817
|
-
return m;
|
|
2818
|
-
}
|
|
2819
|
-
chunkUSNT2KNT_cjs.__name(mergeInventoryLinesByProduct, "mergeInventoryLinesByProduct");
|
|
2820
|
-
async function validateInventoryForConfirmedOrderLines(dataSource, entityMap, calcLines) {
|
|
2821
|
-
const productRepo = dataSource.getRepository(entityMap.products);
|
|
2822
|
-
const merged = mergeInventoryLinesByProduct(calcLines.filter((l) => l.found && l.productId != null).map((l) => ({
|
|
2823
|
-
productId: l.productId,
|
|
2824
|
-
quantity: l.quantity
|
|
2825
|
-
})));
|
|
2826
|
-
for (const [productId, qty] of merged) {
|
|
2827
|
-
const row = await productRepo.findOne({
|
|
2828
|
-
where: {
|
|
2829
|
-
id: productId,
|
|
2830
|
-
deleted: false
|
|
2831
|
-
}
|
|
2832
|
-
});
|
|
2833
|
-
if (!row) return `Product #${productId} not found`;
|
|
2834
|
-
if (row.type === "service") continue;
|
|
2835
|
-
const cur = Number(row.quantity ?? 0);
|
|
2836
|
-
if (cur < qty) {
|
|
2837
|
-
const name = row.name ?? String(productId);
|
|
2838
|
-
return `Insufficient stock for ${name}: available ${cur}, required ${qty}`;
|
|
2839
|
-
}
|
|
2840
|
-
}
|
|
2841
|
-
return null;
|
|
2842
|
-
}
|
|
2843
|
-
chunkUSNT2KNT_cjs.__name(validateInventoryForConfirmedOrderLines, "validateInventoryForConfirmedOrderLines");
|
|
2844
|
-
async function applyInventoryDeltaForMergedLines(dataSource, entityMap, merged, sign, validateDeduct) {
|
|
2845
|
-
const productRepo = dataSource.getRepository(entityMap.products);
|
|
2846
|
-
for (const [productId, qty] of merged) {
|
|
2847
|
-
const row = await productRepo.findOne({
|
|
2848
|
-
where: {
|
|
2849
|
-
id: productId,
|
|
2850
|
-
deleted: false
|
|
2851
|
-
}
|
|
2852
|
-
});
|
|
2853
|
-
if (!row) return `Product #${productId} not found`;
|
|
2854
|
-
if (row.type === "service") continue;
|
|
2855
|
-
const cur = Number(row.quantity ?? 0);
|
|
2856
|
-
if (sign === -1) {
|
|
2857
|
-
if (validateDeduct && cur < qty) {
|
|
2858
|
-
const name = row.name ?? String(productId);
|
|
2859
|
-
return `Insufficient stock for ${name}: available ${cur}, required ${qty}`;
|
|
2860
|
-
}
|
|
2861
|
-
await productRepo.update(productId, {
|
|
2862
|
-
quantity: Math.max(0, cur - qty)
|
|
2863
|
-
});
|
|
2864
|
-
} else {
|
|
2865
|
-
await productRepo.update(productId, {
|
|
2866
|
-
quantity: cur + qty
|
|
2867
|
-
});
|
|
2868
|
-
}
|
|
2869
|
-
}
|
|
2870
|
-
return null;
|
|
2871
|
-
}
|
|
2872
|
-
chunkUSNT2KNT_cjs.__name(applyInventoryDeltaForMergedLines, "applyInventoryDeltaForMergedLines");
|
|
2873
|
-
async function validateInventoryForOrderBecomingConfirmed(dataSource, entityMap, prevSnap, nextLines) {
|
|
2874
|
-
const mergedNext = mergeInventoryLinesByProduct(nextLines);
|
|
2875
|
-
const productRepo = dataSource.getRepository(entityMap.products);
|
|
2876
|
-
const prevByProduct = prevSnap?.status === ORDER_STATUS_CONFIRMED ? mergeInventoryLinesByProduct(prevSnap.lines) : /* @__PURE__ */ new Map();
|
|
2877
|
-
for (const [productId, need] of mergedNext) {
|
|
2878
|
-
const row = await productRepo.findOne({
|
|
2879
|
-
where: {
|
|
2880
|
-
id: productId,
|
|
2881
|
-
deleted: false
|
|
2882
|
-
}
|
|
2883
|
-
});
|
|
2884
|
-
if (!row) return `Product #${productId} not found`;
|
|
2885
|
-
if (row.type === "service") continue;
|
|
2886
|
-
let available = Number(row.quantity ?? 0);
|
|
2887
|
-
available += prevByProduct.get(productId) ?? 0;
|
|
2888
|
-
if (available < need) {
|
|
2889
|
-
const name = row.name ?? String(productId);
|
|
2890
|
-
return `Insufficient stock for ${name}: available ${available}, required ${need}`;
|
|
2891
|
-
}
|
|
2892
|
-
}
|
|
2893
|
-
return null;
|
|
2894
|
-
}
|
|
2895
|
-
chunkUSNT2KNT_cjs.__name(validateInventoryForOrderBecomingConfirmed, "validateInventoryForOrderBecomingConfirmed");
|
|
2896
|
-
async function reconcileOrderInventoryBetweenSnapshots(dataSource, entityMap, prev, next) {
|
|
2897
|
-
const wasConfirmed = prev.status === ORDER_STATUS_CONFIRMED;
|
|
2898
|
-
const isConfirmed = next.status === ORDER_STATUS_CONFIRMED;
|
|
2899
|
-
if (wasConfirmed) {
|
|
2900
|
-
const merged = mergeInventoryLinesByProduct(prev.lines);
|
|
2901
|
-
const err = await applyInventoryDeltaForMergedLines(dataSource, entityMap, merged, 1, false);
|
|
2902
|
-
if (err) return err;
|
|
2903
|
-
}
|
|
2904
|
-
if (isConfirmed) {
|
|
2905
|
-
const merged = mergeInventoryLinesByProduct(next.lines);
|
|
2906
|
-
const err = await applyInventoryDeltaForMergedLines(dataSource, entityMap, merged, -1, true);
|
|
2907
|
-
if (err) return err;
|
|
2908
|
-
}
|
|
2909
|
-
return null;
|
|
3018
|
+
var ORDER_STATUS_CONFIRMED = "confirmed";
|
|
3019
|
+
async function validateInventoryForConfirmedOrderLines2(dataSource, entityMap, calcLines) {
|
|
3020
|
+
const lines = calcLines.filter((l) => l.found && l.productId != null).map((l) => ({
|
|
3021
|
+
productId: l.productId,
|
|
3022
|
+
quantity: l.quantity
|
|
3023
|
+
}));
|
|
3024
|
+
return chunkHY3AXLOI_cjs.validateInventoryForConfirmedOrderLines(dataSource, entityMap, lines);
|
|
2910
3025
|
}
|
|
2911
|
-
chunkUSNT2KNT_cjs.__name(
|
|
3026
|
+
chunkUSNT2KNT_cjs.__name(validateInventoryForConfirmedOrderLines2, "validateInventoryForConfirmedOrderLines");
|
|
2912
3027
|
async function resolveProductTaxRate(dataSource, entityMap, productId, productVendorId) {
|
|
2913
3028
|
if (!entityMap.product_config || !entityMap.taxes) {
|
|
2914
3029
|
return {
|
|
@@ -3810,23 +3925,24 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
3810
3925
|
if (resource === "vendor_customers" && entityMap["customer"]) {
|
|
3811
3926
|
const scope = await resolveVendorCustomersScope(dataSource, entityMap, resolveScope);
|
|
3812
3927
|
const repo2 = dataSource.getRepository(entity);
|
|
3813
|
-
const qb = repo2.createQueryBuilder("vc").leftJoinAndSelect("vc.customer", "customer").leftJoinAndSelect("customer.user", "user").orderBy("vc.createdAt", sortOrder === "DESC" ? "DESC" : "ASC").skip(skip).take(limit);
|
|
3928
|
+
const qb = repo2.createQueryBuilder("vc").leftJoinAndSelect("vc.customer", "customer").leftJoinAndSelect("customer.user", "user").leftJoinAndSelect("vc.contact", "contact").orderBy("vc.createdAt", sortOrder === "DESC" ? "DESC" : "ASC").skip(skip).take(limit);
|
|
3814
3929
|
applyVendorScopeToQueryBuilder(qb, "vc", scope);
|
|
3815
3930
|
if (search && typeof search === "string" && search.trim()) {
|
|
3816
3931
|
const term = `%${search.trim()}%`;
|
|
3817
|
-
qb.andWhere("(customer.name ILIKE :term OR customer.email ILIKE :term OR customer.phone ILIKE :term)", {
|
|
3932
|
+
qb.andWhere("(customer.name ILIKE :term OR customer.email ILIKE :term OR customer.phone ILIKE :term OR contact.name ILIKE :term OR contact.email ILIKE :term OR contact.phone ILIKE :term)", {
|
|
3818
3933
|
term
|
|
3819
3934
|
});
|
|
3820
3935
|
}
|
|
3821
3936
|
const [rows, total2] = await qb.getManyAndCount();
|
|
3822
3937
|
const data2 = rows.map((row) => {
|
|
3823
3938
|
const customer = row.customer;
|
|
3939
|
+
const contact = row.contact;
|
|
3824
3940
|
return {
|
|
3825
3941
|
...row,
|
|
3826
|
-
name: customer?.name ?? null,
|
|
3827
|
-
email: customer?.email ?? null,
|
|
3828
|
-
phone: customer?.phone ?? null,
|
|
3829
|
-
company: customer?.company ?? null
|
|
3942
|
+
name: customer?.name ?? contact?.name ?? null,
|
|
3943
|
+
email: customer?.email ?? contact?.email ?? null,
|
|
3944
|
+
phone: customer?.phone ?? contact?.phone ?? null,
|
|
3945
|
+
company: customer?.company ?? contact?.company ?? null
|
|
3830
3946
|
};
|
|
3831
3947
|
});
|
|
3832
3948
|
return json({
|
|
@@ -4160,7 +4276,11 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4160
4276
|
} else if (resource === "collections") {
|
|
4161
4277
|
if (scope.type === "vendor") {
|
|
4162
4278
|
where = mergeVendorScopeIntoWhere(where, scope, resource, catalogFlags);
|
|
4163
|
-
} else if (searchParams.get("isCatalog")
|
|
4279
|
+
} else if (searchParams.get("isCatalog") === "true") {
|
|
4280
|
+
where = mergeListWhereAnd(where, {
|
|
4281
|
+
isCatalog: true
|
|
4282
|
+
});
|
|
4283
|
+
} else if (searchParams.get("isCatalog") === "false") {
|
|
4164
4284
|
where = mergeListWhereAnd(where, {
|
|
4165
4285
|
isCatalog: false
|
|
4166
4286
|
});
|
|
@@ -4357,41 +4477,17 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4357
4477
|
status: 503
|
|
4358
4478
|
});
|
|
4359
4479
|
}
|
|
4360
|
-
if (!entityMap["
|
|
4361
|
-
return json({
|
|
4362
|
-
error: "Users entity not configured"
|
|
4363
|
-
}, {
|
|
4364
|
-
status: 503
|
|
4365
|
-
});
|
|
4366
|
-
}
|
|
4367
|
-
let customerGroupId = null;
|
|
4368
|
-
if (entityMap["user_groups"]) {
|
|
4369
|
-
const userGroupRepo = dataSource.getRepository(entityMap["user_groups"]);
|
|
4370
|
-
const customerGroup = await userGroupRepo.findOne({
|
|
4371
|
-
where: {
|
|
4372
|
-
name: "Customer",
|
|
4373
|
-
deleted: false
|
|
4374
|
-
}
|
|
4375
|
-
});
|
|
4376
|
-
if (!customerGroup) {
|
|
4377
|
-
return json({
|
|
4378
|
-
error: "User group 'customer' not found"
|
|
4379
|
-
}, {
|
|
4380
|
-
status: 500
|
|
4381
|
-
});
|
|
4382
|
-
}
|
|
4383
|
-
customerGroupId = Number(customerGroup.id);
|
|
4384
|
-
} else {
|
|
4480
|
+
if (!entityMap["contacts"]) {
|
|
4385
4481
|
return json({
|
|
4386
|
-
error: "
|
|
4482
|
+
error: "Contacts entity not configured"
|
|
4387
4483
|
}, {
|
|
4388
4484
|
status: 503
|
|
4389
4485
|
});
|
|
4390
4486
|
}
|
|
4391
4487
|
const name = String(body.name ?? "").trim();
|
|
4392
|
-
const email = String(body.email ?? "").trim();
|
|
4393
|
-
const
|
|
4394
|
-
const
|
|
4488
|
+
const email = String(body.email ?? "").trim().toLowerCase();
|
|
4489
|
+
const phoneRaw = String(body.phone ?? "").trim();
|
|
4490
|
+
const phone = phoneRaw || null;
|
|
4395
4491
|
if (!name) return json({
|
|
4396
4492
|
error: "name is required"
|
|
4397
4493
|
}, {
|
|
@@ -4402,25 +4498,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4402
4498
|
}, {
|
|
4403
4499
|
status: 400
|
|
4404
4500
|
});
|
|
4405
|
-
if (!phone) return json({
|
|
4406
|
-
error: "phone is required"
|
|
4407
|
-
}, {
|
|
4408
|
-
status: 400
|
|
4409
|
-
});
|
|
4410
|
-
if (!rawPw) return json({
|
|
4411
|
-
error: "password is required"
|
|
4412
|
-
}, {
|
|
4413
|
-
status: 400
|
|
4414
|
-
});
|
|
4415
|
-
if (rawPw.length < 6) {
|
|
4416
|
-
return json({
|
|
4417
|
-
error: "Password must be at least 6 characters"
|
|
4418
|
-
}, {
|
|
4419
|
-
status: 400
|
|
4420
|
-
});
|
|
4421
|
-
}
|
|
4422
4501
|
const customerRepo = dataSource.getRepository(entityMap["customer"]);
|
|
4423
|
-
const userRepo = dataSource.getRepository(entityMap["users"]);
|
|
4424
4502
|
const dupCustEmail = await customerRepo.findOne({
|
|
4425
4503
|
where: {
|
|
4426
4504
|
email,
|
|
@@ -4434,49 +4512,26 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4434
4512
|
status: 409
|
|
4435
4513
|
});
|
|
4436
4514
|
}
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
if (dupCustPhone) {
|
|
4444
|
-
return json({
|
|
4445
|
-
error: "A customer with this phone number already exists"
|
|
4446
|
-
}, {
|
|
4447
|
-
status: 409
|
|
4515
|
+
if (phone) {
|
|
4516
|
+
const dupCustPhone = await customerRepo.findOne({
|
|
4517
|
+
where: {
|
|
4518
|
+
phone,
|
|
4519
|
+
deleted: false
|
|
4520
|
+
}
|
|
4448
4521
|
});
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4522
|
+
if (dupCustPhone) {
|
|
4523
|
+
return json({
|
|
4524
|
+
error: "A customer with this phone number already exists"
|
|
4525
|
+
}, {
|
|
4526
|
+
status: 409
|
|
4527
|
+
});
|
|
4455
4528
|
}
|
|
4456
|
-
});
|
|
4457
|
-
if (dupUser) {
|
|
4458
|
-
userId = Number(dupUser.id);
|
|
4459
|
-
} else {
|
|
4460
|
-
const bcrypt = await import('bcryptjs');
|
|
4461
|
-
const hashedPassword = await bcrypt.hash(rawPw, 10);
|
|
4462
|
-
const savedUser = await userRepo.save(userRepo.create({
|
|
4463
|
-
name,
|
|
4464
|
-
email,
|
|
4465
|
-
phone,
|
|
4466
|
-
password: hashedPassword,
|
|
4467
|
-
groupId: customerGroupId,
|
|
4468
|
-
adminAccess: false,
|
|
4469
|
-
blocked: false
|
|
4470
|
-
}));
|
|
4471
|
-
userId = Number(savedUser.id);
|
|
4472
4529
|
}
|
|
4473
|
-
const savedCustomer = await
|
|
4474
|
-
id: userId,
|
|
4530
|
+
const savedCustomer = await ensureCustomerRecord(dataSource, entityMap["customer"], {
|
|
4475
4531
|
name,
|
|
4476
4532
|
email,
|
|
4477
|
-
phone
|
|
4478
|
-
|
|
4479
|
-
phone
|
|
4533
|
+
phone,
|
|
4534
|
+
userId: null
|
|
4480
4535
|
});
|
|
4481
4536
|
if (!savedCustomer) {
|
|
4482
4537
|
return json({
|
|
@@ -4485,37 +4540,37 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4485
4540
|
status: 409
|
|
4486
4541
|
});
|
|
4487
4542
|
}
|
|
4488
|
-
const
|
|
4489
|
-
|
|
4543
|
+
const contactRepo = dataSource.getRepository(entityMap["contacts"]);
|
|
4544
|
+
let contact = await contactRepo.findOne({
|
|
4490
4545
|
where: {
|
|
4491
|
-
|
|
4546
|
+
email,
|
|
4492
4547
|
deleted: false
|
|
4493
4548
|
}
|
|
4494
|
-
})
|
|
4495
|
-
if (
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
}
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
}
|
|
4549
|
+
});
|
|
4550
|
+
if (!contact) {
|
|
4551
|
+
contact = await contactRepo.save(contactRepo.create({
|
|
4552
|
+
name,
|
|
4553
|
+
email,
|
|
4554
|
+
phone: phone || null,
|
|
4555
|
+
type: "customer"
|
|
4556
|
+
}));
|
|
4557
|
+
} else {
|
|
4558
|
+
const t = contact.type;
|
|
4559
|
+
const patch = {
|
|
4560
|
+
name,
|
|
4561
|
+
phone: phone || contact.phone || null
|
|
4562
|
+
};
|
|
4563
|
+
if (t == null || t === "" || String(t).toLowerCase() !== "customer") {
|
|
4564
|
+
patch.type = "customer";
|
|
4565
|
+
}
|
|
4566
|
+
await contactRepo.update(contact.id, patch);
|
|
4567
|
+
contact = {
|
|
4568
|
+
...contact,
|
|
4569
|
+
...patch,
|
|
4570
|
+
id: contact.id
|
|
4571
|
+
};
|
|
4518
4572
|
}
|
|
4573
|
+
const contactId = Number(contact.id);
|
|
4519
4574
|
const scope = await resolveVendorCustomersScope(dataSource, entityMap, resolveScope);
|
|
4520
4575
|
let vendorId = null;
|
|
4521
4576
|
if (scope.type === "vendor") {
|
|
@@ -4531,19 +4586,25 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4531
4586
|
status: 400
|
|
4532
4587
|
});
|
|
4533
4588
|
}
|
|
4534
|
-
|
|
4535
|
-
|
|
4589
|
+
await ensureVendorCustomersForOrder(dataSource, entityMap, [
|
|
4590
|
+
vendorId
|
|
4591
|
+
], contactId, {
|
|
4592
|
+
name,
|
|
4593
|
+
email,
|
|
4594
|
+
phone
|
|
4595
|
+
});
|
|
4596
|
+
const customerRow = await customerRepo.findOne({
|
|
4536
4597
|
where: {
|
|
4537
|
-
|
|
4598
|
+
id: savedCustomer.id,
|
|
4599
|
+
deleted: false
|
|
4538
4600
|
}
|
|
4539
4601
|
});
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
}
|
|
4546
|
-
return json(customerRow, {
|
|
4602
|
+
return json(customerRow ?? {
|
|
4603
|
+
id: savedCustomer.id,
|
|
4604
|
+
name,
|
|
4605
|
+
email,
|
|
4606
|
+
phone
|
|
4607
|
+
}, {
|
|
4547
4608
|
status: 201
|
|
4548
4609
|
});
|
|
4549
4610
|
}
|
|
@@ -4948,6 +5009,22 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4948
5009
|
status: 400
|
|
4949
5010
|
});
|
|
4950
5011
|
}
|
|
5012
|
+
if (resource === "combos") {
|
|
5013
|
+
const vendorIdForSlug = scopeCreate.type === "vendor" ? scopeCreate.vendorId : Number(persistBody.vendorId);
|
|
5014
|
+
if (!Number.isFinite(vendorIdForSlug) || vendorIdForSlug <= 0) {
|
|
5015
|
+
return json({
|
|
5016
|
+
error: "vendorId is required"
|
|
5017
|
+
}, {
|
|
5018
|
+
status: 400
|
|
5019
|
+
});
|
|
5020
|
+
}
|
|
5021
|
+
const comboSlugErr = await normalizeComboNameAndSlug(repo, persistBody, vendorIdForSlug);
|
|
5022
|
+
if (comboSlugErr) return json({
|
|
5023
|
+
error: comboSlugErr
|
|
5024
|
+
}, {
|
|
5025
|
+
status: 400
|
|
5026
|
+
});
|
|
5027
|
+
}
|
|
4951
5028
|
sanitizeBodyForEntity(repo, persistBody);
|
|
4952
5029
|
let created;
|
|
4953
5030
|
try {
|
|
@@ -4991,6 +5068,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4991
5068
|
}
|
|
4992
5069
|
const nameRaw = String(body["contact.name"] ?? contact.name ?? "").trim();
|
|
4993
5070
|
const phoneRaw = body["contact.phone"] ?? contact.phone;
|
|
5071
|
+
const emailForVc = (emailRaw || String(contact.email ?? "")).trim().toLowerCase();
|
|
4994
5072
|
const phoneToSave = phoneRaw == null || phoneRaw === "" ? null : String(phoneRaw).trim();
|
|
4995
5073
|
if (phoneToSave && contact.phone !== phoneToSave) {
|
|
4996
5074
|
await contactRepo.update(contact.id, {
|
|
@@ -4999,21 +5077,45 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4999
5077
|
contact.phone = phoneToSave;
|
|
5000
5078
|
}
|
|
5001
5079
|
const vendorIdForCustomer = resolveVendorIdForContactCheck(scopeCreate, persistBody);
|
|
5002
|
-
const
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5080
|
+
const orderLinesForVendors = normalizeOrderLinesInput(body.orderLines);
|
|
5081
|
+
const vendorIdsForVc = [];
|
|
5082
|
+
if (vendorIdForCustomer != null) vendorIdsForVc.push(vendorIdForCustomer);
|
|
5083
|
+
if (orderLinesForVendors?.length && entityMap.products) {
|
|
5084
|
+
const productRepoForVc = dataSource.getRepository(entityMap.products);
|
|
5085
|
+
for (const line of orderLinesForVendors) {
|
|
5086
|
+
const pid = Number(line.productId);
|
|
5087
|
+
if (!Number.isFinite(pid)) continue;
|
|
5088
|
+
const product = await productRepoForVc.findOne({
|
|
5089
|
+
where: {
|
|
5090
|
+
id: pid
|
|
5091
|
+
}
|
|
5092
|
+
});
|
|
5093
|
+
const pVid = Number(product?.vendorId);
|
|
5094
|
+
if (Number.isFinite(pVid) && pVid > 0) vendorIdsForVc.push(pVid);
|
|
5095
|
+
}
|
|
5096
|
+
}
|
|
5097
|
+
if (vendorIdsForVc.length > 0 && emailForVc) {
|
|
5098
|
+
await ensureVendorCustomersForOrder(dataSource, entityMap, vendorIdsForVc, contact.id, {
|
|
5099
|
+
name: nameRaw || emailForVc.split("@")[0] || "Customer",
|
|
5100
|
+
email: emailForVc,
|
|
5007
5101
|
phone: phoneRaw == null || phoneRaw === "" ? null : String(phoneRaw)
|
|
5008
5102
|
});
|
|
5009
|
-
}
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5103
|
+
}
|
|
5104
|
+
const accountCustomerId = Number(body.accountCustomerId);
|
|
5105
|
+
if (entityMap.customer_contacts && Number.isFinite(accountCustomerId) && accountCustomerId > 0) {
|
|
5106
|
+
const ccRepo = dataSource.getRepository(entityMap.customer_contacts);
|
|
5107
|
+
const orderContactId = contact.id;
|
|
5108
|
+
const existingLink = await ccRepo.findOne({
|
|
5109
|
+
where: {
|
|
5110
|
+
customerId: accountCustomerId,
|
|
5111
|
+
contactId: orderContactId
|
|
5112
|
+
}
|
|
5113
|
+
});
|
|
5114
|
+
if (!existingLink) {
|
|
5115
|
+
await ccRepo.save(ccRepo.create({
|
|
5116
|
+
customerId: accountCustomerId,
|
|
5117
|
+
contactId: orderContactId
|
|
5118
|
+
}));
|
|
5017
5119
|
}
|
|
5018
5120
|
}
|
|
5019
5121
|
const randomPart = Math.floor(1e4 + Math.random() * 9e4);
|
|
@@ -5021,6 +5123,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5021
5123
|
persistBody.orderNumber = `ORD00${randomPart}`;
|
|
5022
5124
|
persistBody.qrToken = crypto2__default.default.randomBytes(16).toString("hex");
|
|
5023
5125
|
}
|
|
5126
|
+
await retireSoftDeletedUniquesFromBody(repo, persistBody);
|
|
5024
5127
|
created = await repo.save(repo.create(persistBody));
|
|
5025
5128
|
if (resource === "orders") {
|
|
5026
5129
|
const orderItemRepo = dataSource.getRepository(entityMap.order_items);
|
|
@@ -5062,8 +5165,8 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5062
5165
|
}
|
|
5063
5166
|
}
|
|
5064
5167
|
const createdStatus = String(persistBody.status ?? "pending");
|
|
5065
|
-
if (createdStatus
|
|
5066
|
-
const stockErr = await
|
|
5168
|
+
if (chunkHY3AXLOI_cjs.orderStatusHoldsStock(createdStatus)) {
|
|
5169
|
+
const stockErr = await validateInventoryForConfirmedOrderLines2(dataSource, entityMap, lines);
|
|
5067
5170
|
if (stockErr) {
|
|
5068
5171
|
await repo.delete(created.id);
|
|
5069
5172
|
return json({
|
|
@@ -5085,6 +5188,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5085
5188
|
await orderItemRepo.save(orderItemRepo.create({
|
|
5086
5189
|
orderId: created.id,
|
|
5087
5190
|
productId: line.productId,
|
|
5191
|
+
variantId: null,
|
|
5088
5192
|
quantity: line.quantity,
|
|
5089
5193
|
unitPrice: line.unitPrice,
|
|
5090
5194
|
subTotal: line.subtotal,
|
|
@@ -5160,10 +5264,10 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5160
5264
|
]
|
|
5161
5265
|
});
|
|
5162
5266
|
if (reloadedOrder) {
|
|
5163
|
-
const invErr = await reconcileOrderInventoryBetweenSnapshots(dataSource, entityMap, {
|
|
5267
|
+
const invErr = await chunkHY3AXLOI_cjs.reconcileOrderInventoryBetweenSnapshots(dataSource, entityMap, {
|
|
5164
5268
|
status: "pending",
|
|
5165
5269
|
lines: []
|
|
5166
|
-
}, orderInventorySnapshotFromRow(reloadedOrder));
|
|
5270
|
+
}, chunkHY3AXLOI_cjs.orderInventorySnapshotFromRow(reloadedOrder));
|
|
5167
5271
|
if (invErr) {
|
|
5168
5272
|
logCrudServerError("POST order inventory reconcile failed", {
|
|
5169
5273
|
message: invErr,
|
|
@@ -5178,7 +5282,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5178
5282
|
}
|
|
5179
5283
|
if (orderDiscountId) {
|
|
5180
5284
|
if (createdStatus === ORDER_STATUS_CONFIRMED) {
|
|
5181
|
-
const usageErr = await
|
|
5285
|
+
const usageErr = await checkAndIncrementDiscountUsage2(dataSource, entityMap, orderDiscountId, persistBody.contactId);
|
|
5182
5286
|
if (usageErr) {
|
|
5183
5287
|
await repo.delete(created.id);
|
|
5184
5288
|
return json({
|
|
@@ -5188,7 +5292,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5188
5292
|
});
|
|
5189
5293
|
}
|
|
5190
5294
|
}
|
|
5191
|
-
await
|
|
5295
|
+
await recordDiscountUsage2(dataSource, entityMap, created.id, orderDiscountId, persistBody.contactId, discount);
|
|
5192
5296
|
}
|
|
5193
5297
|
const orderIdForNotify = created.id;
|
|
5194
5298
|
void import('./emit-order-notification-trigger-D2N3KFHL.cjs').then(({ fireOrderNotificationTrigger }) => {
|
|
@@ -5197,6 +5301,16 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5197
5301
|
entityMap
|
|
5198
5302
|
});
|
|
5199
5303
|
});
|
|
5304
|
+
if (getCms) {
|
|
5305
|
+
void import('./send-order-placed-emails-B5ZVJT7T.cjs').then(({ sendOrderPlacedEmailsAfterConfirmation }) => {
|
|
5306
|
+
return sendOrderPlacedEmailsAfterConfirmation(orderIdForNotify, {
|
|
5307
|
+
getDataSource: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => dataSource, "getDataSource"),
|
|
5308
|
+
entityMap,
|
|
5309
|
+
getCms: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => await getCms(), "getCms")
|
|
5310
|
+
});
|
|
5311
|
+
}).catch(() => {
|
|
5312
|
+
});
|
|
5313
|
+
}
|
|
5200
5314
|
}
|
|
5201
5315
|
} catch (err) {
|
|
5202
5316
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -5842,6 +5956,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5842
5956
|
}
|
|
5843
5957
|
}
|
|
5844
5958
|
sanitizeBodyForEntity(repo, updatePayload2);
|
|
5959
|
+
await retireSoftDeletedUniquesFromBody(repo, updatePayload2);
|
|
5845
5960
|
await repo.update(numericId, updatePayload2);
|
|
5846
5961
|
if (Array.isArray(rawBody.tags)) {
|
|
5847
5962
|
const tagNames = rawBody.tags.map((t) => String(t).trim()).filter(Boolean);
|
|
@@ -5903,7 +6018,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5903
6018
|
status: 404
|
|
5904
6019
|
});
|
|
5905
6020
|
if (resource === "orders") {
|
|
5906
|
-
orderInvPrev = orderInventorySnapshotFromRow(cur);
|
|
6021
|
+
orderInvPrev = chunkHY3AXLOI_cjs.orderInventorySnapshotFromRow(cur);
|
|
5907
6022
|
}
|
|
5908
6023
|
}
|
|
5909
6024
|
if (resource === "orders" && rawBody && typeof rawBody === "object" && Array.isArray(rawBody.orderLines)) {
|
|
@@ -5930,8 +6045,8 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
5930
6045
|
} : await calculateOrderTotalsFromLines(dataSource, entityMap, orderLinesNorm, effectiveCurrency, putDiscountId, Number.isFinite(putOrderVendorId) ? putOrderVendorId : null);
|
|
5931
6046
|
const scalarUpdate = pickColumnUpdates(repo, rawBody);
|
|
5932
6047
|
const nextStatus = typeof scalarUpdate.status === "string" && scalarUpdate.status ? String(scalarUpdate.status) : orderInvPrev?.status ?? "pending";
|
|
5933
|
-
if (nextStatus
|
|
5934
|
-
const verr = await validateInventoryForOrderBecomingConfirmed(dataSource, entityMap, orderInvPrev, lines.filter((l) => l.found && l.productId != null).map((l) => ({
|
|
6048
|
+
if (chunkHY3AXLOI_cjs.orderStatusHoldsStock(nextStatus) && lines.length > 0) {
|
|
6049
|
+
const verr = await chunkHY3AXLOI_cjs.validateInventoryForOrderBecomingConfirmed(dataSource, entityMap, orderInvPrev, lines.filter((l) => l.found && l.productId != null).map((l) => ({
|
|
5935
6050
|
productId: l.productId,
|
|
5936
6051
|
quantity: l.quantity
|
|
5937
6052
|
})));
|
|
@@ -6035,7 +6150,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6035
6150
|
status: 404
|
|
6036
6151
|
});
|
|
6037
6152
|
if (orderInvPrev) {
|
|
6038
|
-
const invErr = await reconcileOrderInventoryBetweenSnapshots(dataSource, entityMap, orderInvPrev, orderInventorySnapshotFromRow(updatedOrder));
|
|
6153
|
+
const invErr = await chunkHY3AXLOI_cjs.reconcileOrderInventoryBetweenSnapshots(dataSource, entityMap, orderInvPrev, chunkHY3AXLOI_cjs.orderInventorySnapshotFromRow(updatedOrder));
|
|
6039
6154
|
if (invErr) return json({
|
|
6040
6155
|
error: invErr
|
|
6041
6156
|
}, {
|
|
@@ -6059,17 +6174,17 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6059
6174
|
}) : null;
|
|
6060
6175
|
const existingDiscountId = existingOd ? existingOd.discountId : null;
|
|
6061
6176
|
if (!putDiscountId && existingDiscountId && wasConfirmed) {
|
|
6062
|
-
await
|
|
6177
|
+
await decrementDiscountUsage2(dataSource, entityMap, existingDiscountId, numericId);
|
|
6063
6178
|
if (entityMap["order_discounts"] && existingOd) {
|
|
6064
6179
|
await dataSource.getRepository(entityMap["order_discounts"]).delete(existingOd.id);
|
|
6065
6180
|
}
|
|
6066
6181
|
}
|
|
6067
6182
|
if (putDiscountId && existingDiscountId && putDiscountId !== existingDiscountId) {
|
|
6068
6183
|
if (wasConfirmed) {
|
|
6069
|
-
await
|
|
6184
|
+
await decrementDiscountUsage2(dataSource, entityMap, existingDiscountId, numericId);
|
|
6070
6185
|
}
|
|
6071
6186
|
if (isNowConfirmed) {
|
|
6072
|
-
const usageErr = await
|
|
6187
|
+
const usageErr = await checkAndIncrementDiscountUsage2(dataSource, entityMap, putDiscountId, cid);
|
|
6073
6188
|
if (usageErr) return json({
|
|
6074
6189
|
error: usageErr
|
|
6075
6190
|
}, {
|
|
@@ -6082,12 +6197,12 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6082
6197
|
discountAmount: discount
|
|
6083
6198
|
});
|
|
6084
6199
|
} else {
|
|
6085
|
-
await
|
|
6200
|
+
await recordDiscountUsage2(dataSource, entityMap, numericId, putDiscountId, cid, discount);
|
|
6086
6201
|
}
|
|
6087
6202
|
}
|
|
6088
6203
|
if (putDiscountId && existingDiscountId && putDiscountId === existingDiscountId) {
|
|
6089
6204
|
if (!wasConfirmed && isNowConfirmed) {
|
|
6090
|
-
const usageErr = await
|
|
6205
|
+
const usageErr = await checkAndIncrementDiscountUsage2(dataSource, entityMap, putDiscountId, cid);
|
|
6091
6206
|
if (usageErr) return json({
|
|
6092
6207
|
error: usageErr
|
|
6093
6208
|
}, {
|
|
@@ -6095,7 +6210,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6095
6210
|
});
|
|
6096
6211
|
}
|
|
6097
6212
|
if (wasConfirmed && !isNowConfirmed) {
|
|
6098
|
-
await
|
|
6213
|
+
await decrementDiscountUsage2(dataSource, entityMap, putDiscountId, numericId);
|
|
6099
6214
|
}
|
|
6100
6215
|
if (existingOd && entityMap["order_discounts"]) {
|
|
6101
6216
|
await dataSource.getRepository(entityMap["order_discounts"]).update(existingOd.id, {
|
|
@@ -6105,14 +6220,14 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6105
6220
|
}
|
|
6106
6221
|
if (putDiscountId && !existingDiscountId) {
|
|
6107
6222
|
if (isNowConfirmed) {
|
|
6108
|
-
const usageErr = await
|
|
6223
|
+
const usageErr = await checkAndIncrementDiscountUsage2(dataSource, entityMap, putDiscountId, cid);
|
|
6109
6224
|
if (usageErr) return json({
|
|
6110
6225
|
error: usageErr
|
|
6111
6226
|
}, {
|
|
6112
6227
|
status: 400
|
|
6113
6228
|
});
|
|
6114
6229
|
}
|
|
6115
|
-
await
|
|
6230
|
+
await recordDiscountUsage2(dataSource, entityMap, numericId, putDiscountId, cid, discount);
|
|
6116
6231
|
}
|
|
6117
6232
|
}
|
|
6118
6233
|
}
|
|
@@ -6583,8 +6698,8 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6583
6698
|
}
|
|
6584
6699
|
if (resource === "orders" && orderInvPrev) {
|
|
6585
6700
|
const nextSt = typeof updatePayload.status === "string" && updatePayload.status ? String(updatePayload.status) : orderInvPrev.status;
|
|
6586
|
-
if (nextSt
|
|
6587
|
-
const verr = await validateInventoryForOrderBecomingConfirmed(dataSource, entityMap, orderInvPrev, orderInvPrev.lines);
|
|
6701
|
+
if (chunkHY3AXLOI_cjs.orderStatusHoldsStock(nextSt) && orderInvPrev.lines.length > 0) {
|
|
6702
|
+
const verr = await chunkHY3AXLOI_cjs.validateInventoryForOrderBecomingConfirmed(dataSource, entityMap, orderInvPrev, orderInvPrev.lines);
|
|
6588
6703
|
if (verr) return json({
|
|
6589
6704
|
error: verr
|
|
6590
6705
|
}, {
|
|
@@ -6592,6 +6707,33 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6592
6707
|
});
|
|
6593
6708
|
}
|
|
6594
6709
|
}
|
|
6710
|
+
if (resource === "combos") {
|
|
6711
|
+
const currentCombo = await repo.findOne({
|
|
6712
|
+
where: {
|
|
6713
|
+
id: numericId,
|
|
6714
|
+
deleted: false
|
|
6715
|
+
}
|
|
6716
|
+
});
|
|
6717
|
+
if (!currentCombo) return json({
|
|
6718
|
+
message: "Not found"
|
|
6719
|
+
}, {
|
|
6720
|
+
status: 404
|
|
6721
|
+
});
|
|
6722
|
+
const vendorIdForSlug = scopePut.type === "vendor" ? scopePut.vendorId : Number(currentCombo.vendorId);
|
|
6723
|
+
if (!Number.isFinite(vendorIdForSlug) || vendorIdForSlug <= 0) {
|
|
6724
|
+
return json({
|
|
6725
|
+
error: "vendorId is required"
|
|
6726
|
+
}, {
|
|
6727
|
+
status: 400
|
|
6728
|
+
});
|
|
6729
|
+
}
|
|
6730
|
+
const comboSlugErr = await normalizeComboNameAndSlug(repo, updatePayload, vendorIdForSlug, currentCombo, numericId);
|
|
6731
|
+
if (comboSlugErr) return json({
|
|
6732
|
+
error: comboSlugErr
|
|
6733
|
+
}, {
|
|
6734
|
+
status: 400
|
|
6735
|
+
});
|
|
6736
|
+
}
|
|
6595
6737
|
if (Object.keys(updatePayload).length > 0) {
|
|
6596
6738
|
if (resource === "payments" && updatePayload.status === "paid" && updatePayload.paidAt == null) {
|
|
6597
6739
|
const existingPayment = await repo.findOne({
|
|
@@ -6605,6 +6747,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6605
6747
|
}
|
|
6606
6748
|
}
|
|
6607
6749
|
sanitizeBodyForEntity(repo, updatePayload);
|
|
6750
|
+
await retireSoftDeletedUniquesFromBody(repo, updatePayload);
|
|
6608
6751
|
await repo.update(numericId, updatePayload);
|
|
6609
6752
|
}
|
|
6610
6753
|
if (resource === "orders" && rawBody && entityMap["order_addresses"]) {
|
|
@@ -6657,7 +6800,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6657
6800
|
}
|
|
6658
6801
|
});
|
|
6659
6802
|
if (resource === "orders" && orderInvPrev && updated) {
|
|
6660
|
-
const invErr = await reconcileOrderInventoryBetweenSnapshots(dataSource, entityMap, orderInvPrev, orderInventorySnapshotFromRow(updated));
|
|
6803
|
+
const invErr = await chunkHY3AXLOI_cjs.reconcileOrderInventoryBetweenSnapshots(dataSource, entityMap, orderInvPrev, chunkHY3AXLOI_cjs.orderInventorySnapshotFromRow(updated));
|
|
6661
6804
|
if (invErr) return json({
|
|
6662
6805
|
error: invErr
|
|
6663
6806
|
}, {
|
|
@@ -6780,7 +6923,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6780
6923
|
});
|
|
6781
6924
|
if (od) {
|
|
6782
6925
|
const odRow = od;
|
|
6783
|
-
await
|
|
6926
|
+
await decrementDiscountUsage2(dataSource, entityMap, odRow.discountId, numericId);
|
|
6784
6927
|
}
|
|
6785
6928
|
}
|
|
6786
6929
|
}
|
|
@@ -6793,6 +6936,22 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6793
6936
|
}
|
|
6794
6937
|
}
|
|
6795
6938
|
await repo.update(numericId, buildSoftDeletePayload(repo.metadata, deletedBy));
|
|
6939
|
+
const softDeletedCols = repo.metadata.columns.map((c) => c.propertyName);
|
|
6940
|
+
const uniqueColsToRetire = [
|
|
6941
|
+
"slug",
|
|
6942
|
+
"email"
|
|
6943
|
+
].filter((col) => softDeletedCols.includes(col));
|
|
6944
|
+
if (existing && uniqueColsToRetire.length > 0) {
|
|
6945
|
+
for (const col of uniqueColsToRetire) {
|
|
6946
|
+
const raw = existing[col];
|
|
6947
|
+
if (typeof raw !== "string") continue;
|
|
6948
|
+
const value = raw.trim();
|
|
6949
|
+
if (!value || value.includes("__deleted_")) continue;
|
|
6950
|
+
await repo.update(numericId, {
|
|
6951
|
+
[col]: `${value}__deleted_${numericId}`
|
|
6952
|
+
});
|
|
6953
|
+
}
|
|
6954
|
+
}
|
|
6796
6955
|
return json({
|
|
6797
6956
|
message: "Deleted successfully"
|
|
6798
6957
|
}, {
|
|
@@ -6823,6 +6982,63 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6823
6982
|
};
|
|
6824
6983
|
}
|
|
6825
6984
|
chunkUSNT2KNT_cjs.__name(createCrudByIdHandler, "createCrudByIdHandler");
|
|
6985
|
+
async function linkUnclaimedContactToUser(dataSource, contactsEntity, userId, email) {
|
|
6986
|
+
const repo = dataSource.getRepository(contactsEntity);
|
|
6987
|
+
const found = await repo.findOne({
|
|
6988
|
+
where: {
|
|
6989
|
+
email,
|
|
6990
|
+
userId: typeorm.IsNull(),
|
|
6991
|
+
deleted: false
|
|
6992
|
+
}
|
|
6993
|
+
});
|
|
6994
|
+
if (found) await repo.update(found.id, {
|
|
6995
|
+
userId
|
|
6996
|
+
});
|
|
6997
|
+
}
|
|
6998
|
+
chunkUSNT2KNT_cjs.__name(linkUnclaimedContactToUser, "linkUnclaimedContactToUser");
|
|
6999
|
+
function buildUserInviteLink(baseUrl, token) {
|
|
7000
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
7001
|
+
return `${base}/admin/invite?token=${encodeURIComponent(token)}`;
|
|
7002
|
+
}
|
|
7003
|
+
chunkUSNT2KNT_cjs.__name(buildUserInviteLink, "buildUserInviteLink");
|
|
7004
|
+
function newUserInviteToken() {
|
|
7005
|
+
return crypto2.randomBytes(32).toString("hex");
|
|
7006
|
+
}
|
|
7007
|
+
chunkUSNT2KNT_cjs.__name(newUserInviteToken, "newUserInviteToken");
|
|
7008
|
+
async function findUserByInviteToken(dataSource, userEntity, token) {
|
|
7009
|
+
const trimmed = token.trim();
|
|
7010
|
+
if (!trimmed) return null;
|
|
7011
|
+
const repo = dataSource.getRepository(userEntity);
|
|
7012
|
+
const row = await repo.findOne({
|
|
7013
|
+
where: {
|
|
7014
|
+
inviteToken: trimmed,
|
|
7015
|
+
deleted: false
|
|
7016
|
+
},
|
|
7017
|
+
select: [
|
|
7018
|
+
"id",
|
|
7019
|
+
"email",
|
|
7020
|
+
"blocked",
|
|
7021
|
+
"password",
|
|
7022
|
+
"inviteStatus",
|
|
7023
|
+
"inviteToken"
|
|
7024
|
+
]
|
|
7025
|
+
});
|
|
7026
|
+
if (!row) return null;
|
|
7027
|
+
const u = row;
|
|
7028
|
+
return u;
|
|
7029
|
+
}
|
|
7030
|
+
chunkUSNT2KNT_cjs.__name(findUserByInviteToken, "findUserByInviteToken");
|
|
7031
|
+
async function completeUserInviteAccept(dataSource, userEntity, userId, passwordHash) {
|
|
7032
|
+
await dataSource.getRepository(userEntity).update(userId, {
|
|
7033
|
+
password: passwordHash,
|
|
7034
|
+
blocked: false,
|
|
7035
|
+
inviteStatus: "active",
|
|
7036
|
+
inviteToken: null
|
|
7037
|
+
});
|
|
7038
|
+
}
|
|
7039
|
+
chunkUSNT2KNT_cjs.__name(completeUserInviteAccept, "completeUserInviteAccept");
|
|
7040
|
+
|
|
7041
|
+
// src/lib/vendor-invite-token.ts
|
|
6826
7042
|
var VENDOR_INVITE_METADATA_TOKEN = "inviteToken";
|
|
6827
7043
|
var VENDOR_INVITE_METADATA_EXPIRES = "inviteExpiresAt";
|
|
6828
7044
|
var VENDOR_INVITE_METADATA_SENT = "inviteSentAt";
|
|
@@ -6847,6 +7063,13 @@ function invalidatedInviteMessage() {
|
|
|
6847
7063
|
return "This invitation is no longer valid. Ask an admin to resend the invite.";
|
|
6848
7064
|
}
|
|
6849
7065
|
chunkUSNT2KNT_cjs.__name(invalidatedInviteMessage, "invalidatedInviteMessage");
|
|
7066
|
+
function userAlreadyActive(user) {
|
|
7067
|
+
const hasPassword = !!(user.password && String(user.password).trim());
|
|
7068
|
+
if (user.inviteStatus === "active" && hasPassword) return true;
|
|
7069
|
+
if (user.inviteStatus === "pending") return false;
|
|
7070
|
+
return !user.blocked && hasPassword;
|
|
7071
|
+
}
|
|
7072
|
+
chunkUSNT2KNT_cjs.__name(userAlreadyActive, "userAlreadyActive");
|
|
6850
7073
|
async function validateInviteTokenForActivation(dataSource, entityMap, token) {
|
|
6851
7074
|
const trimmedToken = String(token ?? "").trim();
|
|
6852
7075
|
if (!trimmedToken) {
|
|
@@ -6893,15 +7116,15 @@ async function validateInviteTokenForActivation(dataSource, entityMap, token) {
|
|
|
6893
7116
|
"id",
|
|
6894
7117
|
"email",
|
|
6895
7118
|
"blocked",
|
|
6896
|
-
"password"
|
|
7119
|
+
"password",
|
|
7120
|
+
"inviteStatus"
|
|
6897
7121
|
]
|
|
6898
7122
|
});
|
|
6899
7123
|
if (!user2) return {
|
|
6900
7124
|
ok: false,
|
|
6901
7125
|
error: "User not found"
|
|
6902
7126
|
};
|
|
6903
|
-
|
|
6904
|
-
if (!user2.blocked && hasPassword2) {
|
|
7127
|
+
if (userAlreadyActive(user2)) {
|
|
6905
7128
|
return {
|
|
6906
7129
|
ok: false,
|
|
6907
7130
|
error: "User is already active"
|
|
@@ -6917,6 +7140,24 @@ async function validateInviteTokenForActivation(dataSource, entityMap, token) {
|
|
|
6917
7140
|
};
|
|
6918
7141
|
}
|
|
6919
7142
|
}
|
|
7143
|
+
if (userRepo && entityMap.users) {
|
|
7144
|
+
const userMatch = await findUserByInviteToken(dataSource, entityMap.users, trimmedToken);
|
|
7145
|
+
if (userMatch) {
|
|
7146
|
+
if (userMatch.inviteStatus === "active" || userAlreadyActive(userMatch)) {
|
|
7147
|
+
return {
|
|
7148
|
+
ok: false,
|
|
7149
|
+
error: "This invitation has already been accepted"
|
|
7150
|
+
};
|
|
7151
|
+
}
|
|
7152
|
+
return {
|
|
7153
|
+
ok: true,
|
|
7154
|
+
target: {
|
|
7155
|
+
userId: userMatch.id,
|
|
7156
|
+
email: userMatch.email
|
|
7157
|
+
}
|
|
7158
|
+
};
|
|
7159
|
+
}
|
|
7160
|
+
}
|
|
6920
7161
|
let email;
|
|
6921
7162
|
try {
|
|
6922
7163
|
email = Buffer.from(trimmedToken, "base64").toString("utf8").trim();
|
|
@@ -6946,22 +7187,30 @@ async function validateInviteTokenForActivation(dataSource, entityMap, token) {
|
|
|
6946
7187
|
"id",
|
|
6947
7188
|
"email",
|
|
6948
7189
|
"blocked",
|
|
6949
|
-
"password"
|
|
7190
|
+
"password",
|
|
7191
|
+
"inviteStatus",
|
|
7192
|
+
"inviteToken"
|
|
6950
7193
|
]
|
|
6951
7194
|
});
|
|
6952
7195
|
if (!user) return {
|
|
6953
7196
|
ok: false,
|
|
6954
7197
|
error: "User not found"
|
|
6955
7198
|
};
|
|
6956
|
-
const
|
|
6957
|
-
if (
|
|
7199
|
+
const u = user;
|
|
7200
|
+
if (userAlreadyActive(u)) {
|
|
6958
7201
|
return {
|
|
6959
7202
|
ok: false,
|
|
6960
7203
|
error: "User is already active"
|
|
6961
7204
|
};
|
|
6962
7205
|
}
|
|
7206
|
+
if (u.inviteToken && String(u.inviteToken).trim()) {
|
|
7207
|
+
return {
|
|
7208
|
+
ok: false,
|
|
7209
|
+
error: invalidatedInviteMessage()
|
|
7210
|
+
};
|
|
7211
|
+
}
|
|
6963
7212
|
if (entityMap.vendors) {
|
|
6964
|
-
const ownerVendor = await loadOwnerVendorForUser(dataSource, entityMap.vendors,
|
|
7213
|
+
const ownerVendor = await loadOwnerVendorForUser(dataSource, entityMap.vendors, u.id);
|
|
6965
7214
|
if (ownerVendor && readVendorInviteToken(ownerVendor.metadata)) {
|
|
6966
7215
|
return {
|
|
6967
7216
|
ok: false,
|
|
@@ -6972,8 +7221,8 @@ async function validateInviteTokenForActivation(dataSource, entityMap, token) {
|
|
|
6972
7221
|
return {
|
|
6973
7222
|
ok: true,
|
|
6974
7223
|
target: {
|
|
6975
|
-
userId:
|
|
6976
|
-
email: String(
|
|
7224
|
+
userId: u.id,
|
|
7225
|
+
email: String(u.email)
|
|
6977
7226
|
}
|
|
6978
7227
|
};
|
|
6979
7228
|
}
|
|
@@ -7191,10 +7440,7 @@ function createInviteAcceptHandler(config) {
|
|
|
7191
7440
|
}
|
|
7192
7441
|
if (beforeActivate) await beforeActivate(email, userId);
|
|
7193
7442
|
const hashedPassword = await hashPassword(password);
|
|
7194
|
-
await dataSource
|
|
7195
|
-
password: hashedPassword,
|
|
7196
|
-
blocked: false
|
|
7197
|
-
});
|
|
7443
|
+
await completeUserInviteAccept(dataSource, entityMap.users, userId, hashedPassword);
|
|
7198
7444
|
if (vendorId != null && entityMap.vendors) {
|
|
7199
7445
|
await completeVendorInviteAccept(dataSource, entityMap.vendors, vendorId);
|
|
7200
7446
|
}
|
|
@@ -8621,6 +8867,9 @@ function createUploadHandler(config) {
|
|
|
8621
8867
|
"image/png",
|
|
8622
8868
|
"image/gif",
|
|
8623
8869
|
"image/webp",
|
|
8870
|
+
"video/mp4",
|
|
8871
|
+
"video/webm",
|
|
8872
|
+
"video/quicktime",
|
|
8624
8873
|
"application/pdf",
|
|
8625
8874
|
"text/plain",
|
|
8626
8875
|
"application/zip",
|
|
@@ -8648,8 +8897,11 @@ function createUploadHandler(config) {
|
|
|
8648
8897
|
});
|
|
8649
8898
|
const defaultMax = 10 * 1024 * 1024;
|
|
8650
8899
|
const maxZipBytes = 80 * 1024 * 1024;
|
|
8900
|
+
const maxVideoBytes = 100 * 1024 * 1024;
|
|
8651
8901
|
const baseMax = maxSizeBytes ?? defaultMax;
|
|
8652
|
-
const
|
|
8902
|
+
const isZip = file.type === "application/zip" || file.type === "application/x-zip-compressed";
|
|
8903
|
+
const isVideo = file.type === "video/mp4" || file.type === "video/webm" || file.type === "video/quicktime";
|
|
8904
|
+
const effectiveMax = isZip ? Math.max(baseMax, maxZipBytes) : isVideo ? Math.max(baseMax, maxVideoBytes) : baseMax;
|
|
8653
8905
|
if (file.size > effectiveMax) return json({
|
|
8654
8906
|
error: "File size exceeds limit"
|
|
8655
8907
|
}, {
|
|
@@ -8722,12 +8974,20 @@ function createUploadHandler(config) {
|
|
|
8722
8974
|
parentId
|
|
8723
8975
|
});
|
|
8724
8976
|
} catch (err) {
|
|
8977
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8725
8978
|
console.error("[upload] File upload failed", {
|
|
8726
|
-
error:
|
|
8979
|
+
error: message,
|
|
8727
8980
|
stack: err instanceof Error ? err.stack : void 0,
|
|
8728
8981
|
name: err instanceof Error ? err.name : void 0,
|
|
8729
8982
|
metadata: err && typeof err === "object" && "$metadata" in err ? err.$metadata : void 0
|
|
8730
8983
|
});
|
|
8984
|
+
if (/Failed to parse body as FormData/i.test(message)) {
|
|
8985
|
+
return json({
|
|
8986
|
+
error: "File upload failed: request body could not be read as FormData. Exclude /api/upload from middleware matcher and raise proxyClientMaxBodySize."
|
|
8987
|
+
}, {
|
|
8988
|
+
status: 500
|
|
8989
|
+
});
|
|
8990
|
+
}
|
|
8731
8991
|
return json({
|
|
8732
8992
|
error: "File upload failed"
|
|
8733
8993
|
}, {
|
|
@@ -8948,6 +9208,17 @@ function createFormSaveHandlers(config) {
|
|
|
8948
9208
|
});
|
|
8949
9209
|
const fields = Array.isArray(body.fields) ? body.fields : [];
|
|
8950
9210
|
const { fields: _f, ...formRow } = body;
|
|
9211
|
+
const slug = typeof formRow.slug === "string" ? formRow.slug.trim() : "";
|
|
9212
|
+
if (slug) {
|
|
9213
|
+
if (await chunkOY2YTBMP_cjs.activeUniqueValueExists(formRepo(), "slug", slug)) {
|
|
9214
|
+
return json({
|
|
9215
|
+
error: "A form with this slug already exists"
|
|
9216
|
+
}, {
|
|
9217
|
+
status: 400
|
|
9218
|
+
});
|
|
9219
|
+
}
|
|
9220
|
+
await chunkOY2YTBMP_cjs.retireSoftDeletedUniqueValue(formRepo(), "slug", slug);
|
|
9221
|
+
}
|
|
8951
9222
|
const form = await formRepo().save(formRepo().create(formRow));
|
|
8952
9223
|
for (let i = 0; i < fields.length; i++) {
|
|
8953
9224
|
const row = normalizeFieldRow(fields[i], form.id);
|
|
@@ -8971,6 +9242,14 @@ function createFormSaveHandlers(config) {
|
|
|
8971
9242
|
status: 201
|
|
8972
9243
|
});
|
|
8973
9244
|
} catch (e) {
|
|
9245
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
9246
|
+
if (/duplicate key|unique constraint/i.test(msg) && /slug/i.test(msg)) {
|
|
9247
|
+
return json({
|
|
9248
|
+
error: "A form with this slug already exists"
|
|
9249
|
+
}, {
|
|
9250
|
+
status: 400
|
|
9251
|
+
});
|
|
9252
|
+
}
|
|
8974
9253
|
return json({
|
|
8975
9254
|
error: "Server Error"
|
|
8976
9255
|
}, {
|
|
@@ -9019,6 +9298,20 @@ function createFormSaveHandlers(config) {
|
|
|
9019
9298
|
]) {
|
|
9020
9299
|
if (body[key] !== void 0) formRow[key] = body[key];
|
|
9021
9300
|
}
|
|
9301
|
+
if (typeof formRow.slug === "string") {
|
|
9302
|
+
const slug = formRow.slug.trim();
|
|
9303
|
+
formRow.slug = slug;
|
|
9304
|
+
if (slug) {
|
|
9305
|
+
if (await chunkOY2YTBMP_cjs.activeUniqueValueExists(formRepo(), "slug", slug, formId)) {
|
|
9306
|
+
return json({
|
|
9307
|
+
error: "A form with this slug already exists"
|
|
9308
|
+
}, {
|
|
9309
|
+
status: 400
|
|
9310
|
+
});
|
|
9311
|
+
}
|
|
9312
|
+
await chunkOY2YTBMP_cjs.retireSoftDeletedUniqueValue(formRepo(), "slug", slug);
|
|
9313
|
+
}
|
|
9314
|
+
}
|
|
9022
9315
|
if (Object.keys(formRow).length > 0) await formRepo().update(formId, formRow);
|
|
9023
9316
|
await fieldRepo().delete({
|
|
9024
9317
|
formId
|
|
@@ -9047,6 +9340,14 @@ function createFormSaveHandlers(config) {
|
|
|
9047
9340
|
status: 404
|
|
9048
9341
|
});
|
|
9049
9342
|
} catch (e) {
|
|
9343
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
9344
|
+
if (/duplicate key|unique constraint/i.test(msg) && /slug/i.test(msg)) {
|
|
9345
|
+
return json({
|
|
9346
|
+
error: "A form with this slug already exists"
|
|
9347
|
+
}, {
|
|
9348
|
+
status: 400
|
|
9349
|
+
});
|
|
9350
|
+
}
|
|
9050
9351
|
return json({
|
|
9051
9352
|
error: "Server Error"
|
|
9052
9353
|
}, {
|
|
@@ -9351,7 +9652,7 @@ function createFormSubmissionHandler(config) {
|
|
|
9351
9652
|
label: f.label && String(f.label).trim() || `Field ${f.id}`,
|
|
9352
9653
|
value: formatSubmissionFieldValue(data[String(f.id)])
|
|
9353
9654
|
}));
|
|
9354
|
-
await
|
|
9655
|
+
await chunkV25RDUOU_cjs.queueEmail(cms, {
|
|
9355
9656
|
to,
|
|
9356
9657
|
templateName: "formSubmission",
|
|
9357
9658
|
ctx: {
|
|
@@ -9405,7 +9706,7 @@ function createUsersApiHandlers(config) {
|
|
|
9405
9706
|
try {
|
|
9406
9707
|
const cms = await getCms();
|
|
9407
9708
|
const companyDetails = getCompanyDetails ? await getCompanyDetails() : {};
|
|
9408
|
-
await
|
|
9709
|
+
await chunkV25RDUOU_cjs.queueEmail(cms, {
|
|
9409
9710
|
to: toEmail,
|
|
9410
9711
|
templateName: "invite",
|
|
9411
9712
|
ctx: {
|
|
@@ -9440,7 +9741,8 @@ function createUsersApiHandlers(config) {
|
|
|
9440
9741
|
"name",
|
|
9441
9742
|
"email",
|
|
9442
9743
|
"id",
|
|
9443
|
-
"blocked"
|
|
9744
|
+
"blocked",
|
|
9745
|
+
"inviteStatus"
|
|
9444
9746
|
]);
|
|
9445
9747
|
const sortField = allowedSort.has(sortFieldRaw) ? sortFieldRaw : "createdAt";
|
|
9446
9748
|
const sortOrder = url.searchParams.get("sortOrder") === "desc" ? "DESC" : "ASC";
|
|
@@ -9453,6 +9755,7 @@ function createUsersApiHandlers(config) {
|
|
|
9453
9755
|
"u.name",
|
|
9454
9756
|
"u.email",
|
|
9455
9757
|
"u.blocked",
|
|
9758
|
+
"u.inviteStatus",
|
|
9456
9759
|
"u.createdAt",
|
|
9457
9760
|
"u.updatedAt",
|
|
9458
9761
|
"u.groupId",
|
|
@@ -9548,6 +9851,7 @@ function createUsersApiHandlers(config) {
|
|
|
9548
9851
|
const isCustomer = !!(customerG && gid === customerG.id);
|
|
9549
9852
|
const adminAccess = isCustomer ? false : body.adminAccess === false ? false : true;
|
|
9550
9853
|
const blocked = body.blocked === true || body.blocked === "true" || body.blocked === 1 || body.blocked === "1";
|
|
9854
|
+
const inviteToken = newUserInviteToken();
|
|
9551
9855
|
const newUser = existing?.deleted ? await (async () => {
|
|
9552
9856
|
await userRepo().update(existing.id, {
|
|
9553
9857
|
deleted: false,
|
|
@@ -9557,6 +9861,8 @@ function createUsersApiHandlers(config) {
|
|
|
9557
9861
|
email,
|
|
9558
9862
|
password: null,
|
|
9559
9863
|
blocked,
|
|
9864
|
+
inviteStatus: "pending",
|
|
9865
|
+
inviteToken,
|
|
9560
9866
|
groupId: gid,
|
|
9561
9867
|
adminAccess,
|
|
9562
9868
|
updatedAt: /* @__PURE__ */ new Date()
|
|
@@ -9573,6 +9879,8 @@ function createUsersApiHandlers(config) {
|
|
|
9573
9879
|
email,
|
|
9574
9880
|
password: null,
|
|
9575
9881
|
blocked,
|
|
9882
|
+
inviteStatus: "pending",
|
|
9883
|
+
inviteToken,
|
|
9576
9884
|
groupId: gid,
|
|
9577
9885
|
adminAccess
|
|
9578
9886
|
}));
|
|
@@ -9590,13 +9898,12 @@ function createUsersApiHandlers(config) {
|
|
|
9590
9898
|
phone
|
|
9591
9899
|
});
|
|
9592
9900
|
}
|
|
9593
|
-
const
|
|
9594
|
-
const inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;
|
|
9595
|
-
await trySendInviteEmail(newUser.email, inviteLink, newUser.name ?? "");
|
|
9901
|
+
const inviteLink = buildUserInviteLink(baseUrl, inviteToken);
|
|
9596
9902
|
return json({
|
|
9597
|
-
message:
|
|
9903
|
+
message: "User created successfully. Invite is pending until they set a password.",
|
|
9598
9904
|
user: newUser,
|
|
9599
|
-
inviteLink
|
|
9905
|
+
inviteLink,
|
|
9906
|
+
emailSent: false
|
|
9600
9907
|
}, {
|
|
9601
9908
|
status: 201
|
|
9602
9909
|
});
|
|
@@ -9628,7 +9935,9 @@ function createUsersApiHandlers(config) {
|
|
|
9628
9935
|
"id",
|
|
9629
9936
|
"name",
|
|
9630
9937
|
"email",
|
|
9938
|
+
"phone",
|
|
9631
9939
|
"blocked",
|
|
9940
|
+
"inviteStatus",
|
|
9632
9941
|
"createdAt",
|
|
9633
9942
|
"updatedAt",
|
|
9634
9943
|
"groupId"
|
|
@@ -9657,6 +9966,11 @@ function createUsersApiHandlers(config) {
|
|
|
9657
9966
|
}
|
|
9658
9967
|
try {
|
|
9659
9968
|
const uid = parseInt(id, 10);
|
|
9969
|
+
if (!Number.isFinite(uid)) return json({
|
|
9970
|
+
error: "Invalid id"
|
|
9971
|
+
}, {
|
|
9972
|
+
status: 400
|
|
9973
|
+
});
|
|
9660
9974
|
const existing = await userRepo().findOne({
|
|
9661
9975
|
where: {
|
|
9662
9976
|
id: uid,
|
|
@@ -9669,8 +9983,59 @@ function createUsersApiHandlers(config) {
|
|
|
9669
9983
|
status: 404
|
|
9670
9984
|
});
|
|
9671
9985
|
const body = await req.json();
|
|
9672
|
-
const
|
|
9673
|
-
|
|
9986
|
+
const patch = {
|
|
9987
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
9988
|
+
};
|
|
9989
|
+
if (typeof body.name === "string") patch.name = body.name.trim();
|
|
9990
|
+
if (typeof body.email === "string") patch.email = body.email.trim().toLowerCase();
|
|
9991
|
+
if (body.blocked !== void 0) {
|
|
9992
|
+
patch.blocked = body.blocked === true || body.blocked === "true" || body.blocked === 1 || body.blocked === "1";
|
|
9993
|
+
}
|
|
9994
|
+
if (body.adminAccess !== void 0) {
|
|
9995
|
+
patch.adminAccess = body.adminAccess === true || body.adminAccess === "true" || body.adminAccess === 1 || body.adminAccess === "1";
|
|
9996
|
+
}
|
|
9997
|
+
if (body.groupId !== void 0) {
|
|
9998
|
+
if (body.groupId === null || body.groupId === "") {
|
|
9999
|
+
patch.groupId = null;
|
|
10000
|
+
} else {
|
|
10001
|
+
const gid = Number(body.groupId);
|
|
10002
|
+
if (!Number.isFinite(gid)) {
|
|
10003
|
+
return json({
|
|
10004
|
+
error: "Invalid groupId"
|
|
10005
|
+
}, {
|
|
10006
|
+
status: 400
|
|
10007
|
+
});
|
|
10008
|
+
}
|
|
10009
|
+
patch.groupId = gid;
|
|
10010
|
+
}
|
|
10011
|
+
}
|
|
10012
|
+
if (body.phone !== void 0) {
|
|
10013
|
+
const phone = body.phone == null ? null : String(body.phone).trim();
|
|
10014
|
+
patch.phone = phone || null;
|
|
10015
|
+
}
|
|
10016
|
+
if (Object.keys(patch).length <= 1) {
|
|
10017
|
+
return json({
|
|
10018
|
+
error: "No valid fields to update"
|
|
10019
|
+
}, {
|
|
10020
|
+
status: 400
|
|
10021
|
+
});
|
|
10022
|
+
}
|
|
10023
|
+
if (typeof patch.email === "string" && patch.email !== existing.email) {
|
|
10024
|
+
const emailTaken = await userRepo().findOne({
|
|
10025
|
+
where: {
|
|
10026
|
+
email: patch.email,
|
|
10027
|
+
deleted: false
|
|
10028
|
+
}
|
|
10029
|
+
});
|
|
10030
|
+
if (emailTaken && Number(emailTaken.id) !== uid) {
|
|
10031
|
+
return json({
|
|
10032
|
+
error: "Email already in use"
|
|
10033
|
+
}, {
|
|
10034
|
+
status: 400
|
|
10035
|
+
});
|
|
10036
|
+
}
|
|
10037
|
+
}
|
|
10038
|
+
await userRepo().update(uid, patch);
|
|
9674
10039
|
const updated = await userRepo().findOne({
|
|
9675
10040
|
where: {
|
|
9676
10041
|
id: uid,
|
|
@@ -9683,7 +10048,9 @@ function createUsersApiHandlers(config) {
|
|
|
9683
10048
|
"id",
|
|
9684
10049
|
"name",
|
|
9685
10050
|
"email",
|
|
10051
|
+
"phone",
|
|
9686
10052
|
"blocked",
|
|
10053
|
+
"inviteStatus",
|
|
9687
10054
|
"createdAt",
|
|
9688
10055
|
"updatedAt",
|
|
9689
10056
|
"groupId"
|
|
@@ -9694,7 +10061,8 @@ function createUsersApiHandlers(config) {
|
|
|
9694
10061
|
}, {
|
|
9695
10062
|
status: 404
|
|
9696
10063
|
});
|
|
9697
|
-
} catch {
|
|
10064
|
+
} catch (err) {
|
|
10065
|
+
console.error("[users.update]", err);
|
|
9698
10066
|
return json({
|
|
9699
10067
|
error: "Server Error"
|
|
9700
10068
|
}, {
|
|
@@ -9750,13 +10118,21 @@ function createUsersApiHandlers(config) {
|
|
|
9750
10118
|
});
|
|
9751
10119
|
}
|
|
9752
10120
|
},
|
|
9753
|
-
async regenerateInvite(
|
|
9754
|
-
const authErr = await requireAuth(new Request(
|
|
10121
|
+
async regenerateInvite(req, id) {
|
|
10122
|
+
const authErr = await requireAuth(new Request(req.url));
|
|
9755
10123
|
if (authErr) return authErr;
|
|
9756
10124
|
if (requireEntityPermission) {
|
|
9757
|
-
const pe = await requireEntityPermission(
|
|
10125
|
+
const pe = await requireEntityPermission(req, "users", "update");
|
|
9758
10126
|
if (pe) return pe;
|
|
9759
10127
|
}
|
|
10128
|
+
let sendEmail = true;
|
|
10129
|
+
let rotate = true;
|
|
10130
|
+
try {
|
|
10131
|
+
const body = await req.json().catch(() => ({}));
|
|
10132
|
+
if (body.sendEmail === false) sendEmail = false;
|
|
10133
|
+
if (body.rotate === false) rotate = false;
|
|
10134
|
+
} catch {
|
|
10135
|
+
}
|
|
9760
10136
|
try {
|
|
9761
10137
|
const user = await userRepo().findOne({
|
|
9762
10138
|
where: {
|
|
@@ -9766,7 +10142,11 @@ function createUsersApiHandlers(config) {
|
|
|
9766
10142
|
select: [
|
|
9767
10143
|
"id",
|
|
9768
10144
|
"email",
|
|
9769
|
-
"name"
|
|
10145
|
+
"name",
|
|
10146
|
+
"password",
|
|
10147
|
+
"inviteStatus",
|
|
10148
|
+
"inviteToken",
|
|
10149
|
+
"blocked"
|
|
9770
10150
|
]
|
|
9771
10151
|
});
|
|
9772
10152
|
if (!user) return json({
|
|
@@ -9774,34 +10154,75 @@ function createUsersApiHandlers(config) {
|
|
|
9774
10154
|
}, {
|
|
9775
10155
|
status: 404
|
|
9776
10156
|
});
|
|
9777
|
-
|
|
10157
|
+
const u = user;
|
|
10158
|
+
const hasPassword = !!(u.password && String(u.password).trim());
|
|
10159
|
+
if (u.inviteStatus === "active" && hasPassword) {
|
|
10160
|
+
return json({
|
|
10161
|
+
error: "User has already accepted the invite"
|
|
10162
|
+
}, {
|
|
10163
|
+
status: 400
|
|
10164
|
+
});
|
|
10165
|
+
}
|
|
10166
|
+
let inviteLink = "";
|
|
9778
10167
|
if (entityMap.vendors) {
|
|
9779
10168
|
const vendorRepo = dataSource.getRepository(entityMap.vendors);
|
|
9780
10169
|
const vendor = await vendorRepo.findOne({
|
|
9781
10170
|
where: {
|
|
9782
|
-
userId:
|
|
10171
|
+
userId: u.id,
|
|
9783
10172
|
deleted: false
|
|
9784
10173
|
}
|
|
9785
10174
|
});
|
|
9786
10175
|
const v = vendor;
|
|
9787
10176
|
if (v && (v.inviteStatus === "pending" || v.inviteStatus === "expired")) {
|
|
9788
|
-
const
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
10177
|
+
const nextMetadata = rotate ? applyRotatingVendorInvite(v.metadata) : {
|
|
10178
|
+
...v.metadata ?? {}
|
|
10179
|
+
};
|
|
10180
|
+
if (rotate || v.inviteStatus !== "pending") {
|
|
10181
|
+
await vendorRepo.update(v.id, {
|
|
10182
|
+
metadata: nextMetadata,
|
|
10183
|
+
inviteStatus: "pending"
|
|
10184
|
+
});
|
|
10185
|
+
}
|
|
10186
|
+
const token = readVendorInviteToken(nextMetadata);
|
|
9794
10187
|
if (token) {
|
|
9795
10188
|
inviteLink = buildVendorInviteLink(baseUrl, token);
|
|
9796
10189
|
}
|
|
10190
|
+
const { markVendorInvitePendingForUser } = await import('./vendor-invite-status-77O7ZQ3U.cjs');
|
|
10191
|
+
await markVendorInvitePendingForUser(dataSource, entityMap.vendors, u.id);
|
|
10192
|
+
}
|
|
10193
|
+
}
|
|
10194
|
+
if (!inviteLink) {
|
|
10195
|
+
let token = u.inviteToken?.trim() || "";
|
|
10196
|
+
if (rotate || !token) {
|
|
10197
|
+
token = newUserInviteToken();
|
|
10198
|
+
await userRepo().update(u.id, {
|
|
10199
|
+
inviteToken: token,
|
|
10200
|
+
inviteStatus: "pending",
|
|
10201
|
+
password: null
|
|
10202
|
+
});
|
|
10203
|
+
} else if (u.inviteStatus !== "pending") {
|
|
10204
|
+
await userRepo().update(u.id, {
|
|
10205
|
+
inviteStatus: "pending"
|
|
10206
|
+
});
|
|
9797
10207
|
}
|
|
9798
|
-
|
|
9799
|
-
|
|
10208
|
+
inviteLink = buildUserInviteLink(baseUrl, token);
|
|
10209
|
+
} else if (rotate) {
|
|
10210
|
+
await userRepo().update(u.id, {
|
|
10211
|
+
inviteStatus: "pending",
|
|
10212
|
+
password: null
|
|
10213
|
+
});
|
|
9800
10214
|
}
|
|
9801
|
-
|
|
10215
|
+
let emailSent = false;
|
|
10216
|
+
if (sendEmail && inviteLink) {
|
|
10217
|
+
await trySendInviteEmail(u.email, inviteLink, u.name ?? "");
|
|
10218
|
+
emailSent = true;
|
|
10219
|
+
}
|
|
10220
|
+
const rotatedNote = rotate ? " Previous invite link is no longer valid." : "";
|
|
9802
10221
|
return json({
|
|
9803
|
-
message: "New invite link
|
|
9804
|
-
|
|
10222
|
+
message: emailSent ? `Invite email sent.${rotatedNote}` : sendEmail ? `Invite link ready (email may not have been sent \u2014 check email plugin).${rotatedNote}` : rotate ? "New invite link created. Previous invite link is no longer valid." : "Invite link ready.",
|
|
10223
|
+
emailSent,
|
|
10224
|
+
inviteLink,
|
|
10225
|
+
inviteStatus: "pending"
|
|
9805
10226
|
});
|
|
9806
10227
|
} catch {
|
|
9807
10228
|
return json({
|
|
@@ -10558,7 +10979,7 @@ function createChatHandlers(config) {
|
|
|
10558
10979
|
const notifyEmailAgent = await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT, {
|
|
10559
10980
|
enabledOnly: false
|
|
10560
10981
|
});
|
|
10561
|
-
const emailTool =
|
|
10982
|
+
const emailTool = chunkTCSGFAWB_cjs.resolveChatEmailToolSettings(llmSettings, {
|
|
10562
10983
|
chatbotValidationRules: agentRow?.validationRules ?? null,
|
|
10563
10984
|
notifyAgent: notifyEmailAgent ? {
|
|
10564
10985
|
systemInstruction: notifyEmailAgent.systemInstruction,
|
|
@@ -10568,7 +10989,7 @@ function createChatHandlers(config) {
|
|
|
10568
10989
|
const emailPlugin2 = cms.getPlugin("email");
|
|
10569
10990
|
const convLeadSent = conv.leadEmailSentAt;
|
|
10570
10991
|
const chatAgentFn = llm.chatAgent?.bind(llm);
|
|
10571
|
-
console.info(
|
|
10992
|
+
console.info(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "pipeline check", {
|
|
10572
10993
|
conversationId,
|
|
10573
10994
|
enabled: emailTool.enabled,
|
|
10574
10995
|
intentCount: emailTool.intents.length,
|
|
@@ -10582,27 +11003,27 @@ function createChatHandlers(config) {
|
|
|
10582
11003
|
mergedPromptIncludesNotify: Boolean(notifyEmailAgent?.systemInstruction?.trim())
|
|
10583
11004
|
});
|
|
10584
11005
|
if (!emailTool.enabled) {
|
|
10585
|
-
console.info(
|
|
11006
|
+
console.info(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
|
|
10586
11007
|
conversationId,
|
|
10587
11008
|
reason: "email_tool_disabled"
|
|
10588
11009
|
});
|
|
10589
11010
|
} else if (emailTool.intents.length === 0) {
|
|
10590
|
-
console.info(
|
|
11011
|
+
console.info(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
|
|
10591
11012
|
conversationId,
|
|
10592
11013
|
reason: "no_intents_configured"
|
|
10593
11014
|
});
|
|
10594
11015
|
} else if (!emailPlugin2) {
|
|
10595
|
-
console.info(
|
|
11016
|
+
console.info(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
|
|
10596
11017
|
conversationId,
|
|
10597
11018
|
reason: "email_plugin_missing"
|
|
10598
11019
|
});
|
|
10599
11020
|
} else if (!chatAgentFn) {
|
|
10600
|
-
console.info(
|
|
11021
|
+
console.info(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
|
|
10601
11022
|
conversationId,
|
|
10602
11023
|
reason: "llm_chat_agent_unavailable"
|
|
10603
11024
|
});
|
|
10604
11025
|
} else if (convLeadSent) {
|
|
10605
|
-
console.info(
|
|
11026
|
+
console.info(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
|
|
10606
11027
|
conversationId,
|
|
10607
11028
|
reason: "lead_email_already_sent",
|
|
10608
11029
|
leadEmailSentAt: convLeadSent
|
|
@@ -10615,7 +11036,7 @@ function createChatHandlers(config) {
|
|
|
10615
11036
|
}
|
|
10616
11037
|
});
|
|
10617
11038
|
if (!contactRow) {
|
|
10618
|
-
console.warn(
|
|
11039
|
+
console.warn(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
|
|
10619
11040
|
conversationId,
|
|
10620
11041
|
reason: "contact_not_found",
|
|
10621
11042
|
contactId
|
|
@@ -10623,7 +11044,7 @@ function createChatHandlers(config) {
|
|
|
10623
11044
|
} else {
|
|
10624
11045
|
const c = contactRow;
|
|
10625
11046
|
try {
|
|
10626
|
-
const intent = await
|
|
11047
|
+
const intent = await chunkTCSGFAWB_cjs.detectChatLeadIntent({
|
|
10627
11048
|
chatAgent: chatAgentFn
|
|
10628
11049
|
}, {
|
|
10629
11050
|
settings: emailTool,
|
|
@@ -10637,15 +11058,15 @@ function createChatHandlers(config) {
|
|
|
10637
11058
|
model: agentRow?.model?.trim() || notifyEmailAgent?.model?.trim() || void 0
|
|
10638
11059
|
});
|
|
10639
11060
|
if (!intent.intent || !intent.emailTo) {
|
|
10640
|
-
console.info(
|
|
11061
|
+
console.info(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "no email sent", {
|
|
10641
11062
|
conversationId,
|
|
10642
11063
|
reason: intent.intent ? "missing_email_to" : "no_intent_match",
|
|
10643
11064
|
intentLabel: intent.intentLabel,
|
|
10644
11065
|
classifierReason: intent.reason
|
|
10645
11066
|
});
|
|
10646
11067
|
} else {
|
|
10647
|
-
const intentRecipients =
|
|
10648
|
-
console.info(
|
|
11068
|
+
const intentRecipients = chunkTCSGFAWB_cjs.parseIntentRecipientEmails(intent.emailTo);
|
|
11069
|
+
console.info(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "intent matched \u2014 sending", {
|
|
10649
11070
|
conversationId,
|
|
10650
11071
|
intent: intent.intent,
|
|
10651
11072
|
emailTo: intent.emailTo,
|
|
@@ -10654,8 +11075,8 @@ function createChatHandlers(config) {
|
|
|
10654
11075
|
});
|
|
10655
11076
|
const emailSettings = await loadSettingsGroupMap(dataSource, entityMap, "email");
|
|
10656
11077
|
const brandingSettings = await loadSettingsGroupMap(dataSource, entityMap, "branding");
|
|
10657
|
-
const companyDetails =
|
|
10658
|
-
const leadResult = await
|
|
11078
|
+
const companyDetails = chunkBXYZDMTZ_cjs.mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);
|
|
11079
|
+
const leadResult = await chunkTCSGFAWB_cjs.sendChatLeadEmail(cms, emailSettings, brandingSettings, {
|
|
10659
11080
|
contactName: String(c.name ?? "").trim() || "Visitor",
|
|
10660
11081
|
contactEmail: String(c.email ?? "").trim(),
|
|
10661
11082
|
contactPhone: c.phone ?? null,
|
|
@@ -10663,7 +11084,7 @@ function createChatHandlers(config) {
|
|
|
10663
11084
|
latestMessage: message,
|
|
10664
11085
|
intentCode: intent.intent,
|
|
10665
11086
|
intentReason: intent.intentLabel || intent.reason,
|
|
10666
|
-
transcript:
|
|
11087
|
+
transcript: chunkTCSGFAWB_cjs.buildTranscriptForLeadEmail(history, message),
|
|
10667
11088
|
companyDetails,
|
|
10668
11089
|
recipients: intentRecipients.length > 0 ? intentRecipients : void 0
|
|
10669
11090
|
});
|
|
@@ -10671,13 +11092,13 @@ function createChatHandlers(config) {
|
|
|
10671
11092
|
await convRepo().update(conversationId, {
|
|
10672
11093
|
leadEmailSentAt: /* @__PURE__ */ new Date()
|
|
10673
11094
|
});
|
|
10674
|
-
console.info(
|
|
11095
|
+
console.info(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "lead email recorded", {
|
|
10675
11096
|
conversationId,
|
|
10676
11097
|
sent: true,
|
|
10677
11098
|
recipients: leadResult.recipients
|
|
10678
11099
|
});
|
|
10679
11100
|
} else {
|
|
10680
|
-
console.warn(
|
|
11101
|
+
console.warn(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "lead email not sent", {
|
|
10681
11102
|
conversationId,
|
|
10682
11103
|
sent: false,
|
|
10683
11104
|
error: leadResult.error ?? "unknown",
|
|
@@ -10686,7 +11107,7 @@ function createChatHandlers(config) {
|
|
|
10686
11107
|
}
|
|
10687
11108
|
}
|
|
10688
11109
|
} catch (intentErr) {
|
|
10689
|
-
console.warn(
|
|
11110
|
+
console.warn(chunkTCSGFAWB_cjs.CHAT_EMAIL_LOG, "pipeline error", {
|
|
10690
11111
|
conversationId,
|
|
10691
11112
|
error: intentErr instanceof Error ? intentErr.message : String(intentErr)
|
|
10692
11113
|
});
|
|
@@ -10703,7 +11124,7 @@ function createChatHandlers(config) {
|
|
|
10703
11124
|
});
|
|
10704
11125
|
if (agentRow && llm.chatAgent) {
|
|
10705
11126
|
const fromAgent = llmAgentToChatAgentOptions(agentRow);
|
|
10706
|
-
const systemPrompt =
|
|
11127
|
+
const systemPrompt = chunkTCSGFAWB_cjs.buildChatbotSystemPromptWithEmailTool(fromAgent.systemPrompt, parsedValidation.guardrailsForPrompt, emailTool);
|
|
10707
11128
|
const res = await llm.chatAgent({
|
|
10708
11129
|
...fromAgent,
|
|
10709
11130
|
systemPrompt: systemPrompt || void 0,
|
|
@@ -10724,7 +11145,7 @@ ${contextParts.join("\n\n")}` : "";
|
|
|
10724
11145
|
agentRow.systemInstruction?.trim(),
|
|
10725
11146
|
ragSystem
|
|
10726
11147
|
].filter(Boolean).join("\n\n");
|
|
10727
|
-
systemContent =
|
|
11148
|
+
systemContent = chunkTCSGFAWB_cjs.buildChatbotSystemPromptWithEmailTool(mergedBase || defaultSystem, parsedValidation.guardrailsForPrompt, emailTool) || defaultSystem;
|
|
10728
11149
|
} else {
|
|
10729
11150
|
systemContent = ragSystem || defaultSystem;
|
|
10730
11151
|
}
|
|
@@ -12150,7 +12571,7 @@ function createAdminRolesHandlers(config) {
|
|
|
12150
12571
|
}, {
|
|
12151
12572
|
status: 401
|
|
12152
12573
|
});
|
|
12153
|
-
if (!
|
|
12574
|
+
if (!chunkNBY4NVTY_cjs.canManageRoles(u) && !chunkX6UQFV4X_cjs.canManageVendorRoles(u)) {
|
|
12154
12575
|
return json({
|
|
12155
12576
|
error: "Forbidden"
|
|
12156
12577
|
}, {
|
|
@@ -12161,7 +12582,7 @@ function createAdminRolesHandlers(config) {
|
|
|
12161
12582
|
}
|
|
12162
12583
|
chunkUSNT2KNT_cjs.__name(gate, "gate");
|
|
12163
12584
|
function isVendorRolesOnly(u) {
|
|
12164
|
-
return chunkX6UQFV4X_cjs.canManageVendorRoles(u) && !
|
|
12585
|
+
return chunkX6UQFV4X_cjs.canManageVendorRoles(u) && !chunkNBY4NVTY_cjs.canManageRoles(u);
|
|
12165
12586
|
}
|
|
12166
12587
|
chunkUSNT2KNT_cjs.__name(isVendorRolesOnly, "isVendorRolesOnly");
|
|
12167
12588
|
const vendorRoleEntities = [
|
|
@@ -12518,12 +12939,12 @@ async function sendVendorOnboardEmails(input, deps) {
|
|
|
12518
12939
|
getSettingsGroup(deps, "branding"),
|
|
12519
12940
|
getSettingsGroup(deps, "email")
|
|
12520
12941
|
]);
|
|
12521
|
-
const companyDetails =
|
|
12522
|
-
const notifyEmails =
|
|
12942
|
+
const companyDetails = chunkBXYZDMTZ_cjs.mergeEmailLayoutCompanyDetails(branding, emailSettings);
|
|
12943
|
+
const notifyEmails = chunkTCSGFAWB_cjs.parseEmailRecipientsFromConfig(emailSettings.salesTeamEmails ?? emailSettings.salesTeamEmail);
|
|
12523
12944
|
const sendToOwner = input.sendToOwner !== false;
|
|
12524
12945
|
const ownerEmail = input.ownerEmail?.trim() || "";
|
|
12525
12946
|
const cms = await deps.getCms();
|
|
12526
|
-
await
|
|
12947
|
+
await chunkV25RDUOU_cjs.queueVendorOnboardEmails(cms, {
|
|
12527
12948
|
vendorName: input.vendorName,
|
|
12528
12949
|
vendorSlug: input.vendorSlug,
|
|
12529
12950
|
ownerName: input.ownerName,
|
|
@@ -12742,6 +13163,39 @@ function slugify(input) {
|
|
|
12742
13163
|
return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
12743
13164
|
}
|
|
12744
13165
|
chunkUSNT2KNT_cjs.__name(slugify, "slugify");
|
|
13166
|
+
async function userHasActiveVendor(em, entityMap, userId) {
|
|
13167
|
+
const vendorRepo = em.getRepository(entityMap.vendors);
|
|
13168
|
+
const owned = await vendorRepo.findOne({
|
|
13169
|
+
where: {
|
|
13170
|
+
userId,
|
|
13171
|
+
deleted: false
|
|
13172
|
+
}
|
|
13173
|
+
});
|
|
13174
|
+
if (owned) return true;
|
|
13175
|
+
if (!entityMap.vendor_users) return false;
|
|
13176
|
+
const link = await em.getRepository(entityMap.vendor_users).createQueryBuilder("vu").innerJoin("vendors", "v", 'v.id = vu."vendorId" AND v.deleted = false').where('vu."userId" = :userId', {
|
|
13177
|
+
userId
|
|
13178
|
+
}).getOne();
|
|
13179
|
+
return !!link;
|
|
13180
|
+
}
|
|
13181
|
+
chunkUSNT2KNT_cjs.__name(userHasActiveVendor, "userHasActiveVendor");
|
|
13182
|
+
async function userHadAnyVendor(em, entityMap, userId) {
|
|
13183
|
+
const vendorRepo = em.getRepository(entityMap.vendors);
|
|
13184
|
+
const owned = await vendorRepo.findOne({
|
|
13185
|
+
where: {
|
|
13186
|
+
userId
|
|
13187
|
+
}
|
|
13188
|
+
});
|
|
13189
|
+
if (owned) return true;
|
|
13190
|
+
if (!entityMap.vendor_users) return false;
|
|
13191
|
+
const link = await em.getRepository(entityMap.vendor_users).findOne({
|
|
13192
|
+
where: {
|
|
13193
|
+
userId
|
|
13194
|
+
}
|
|
13195
|
+
});
|
|
13196
|
+
return !!link;
|
|
13197
|
+
}
|
|
13198
|
+
chunkUSNT2KNT_cjs.__name(userHadAnyVendor, "userHadAnyVendor");
|
|
12745
13199
|
function vendorOnboardErrorResponse(json, err) {
|
|
12746
13200
|
const msg = err instanceof Error ? err.message : String(err);
|
|
12747
13201
|
console.error("[vendor-onboard]", err);
|
|
@@ -12840,14 +13294,80 @@ function createVendorOnboardHandlers(config) {
|
|
|
12840
13294
|
chunkUSNT2KNT_cjs.__name(gateAdmin, "gateAdmin");
|
|
12841
13295
|
async function resolveActiveVendorId(u) {
|
|
12842
13296
|
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u);
|
|
12843
|
-
|
|
12844
|
-
if (scope.type === "
|
|
12845
|
-
|
|
12846
|
-
|
|
13297
|
+
const candidates = [];
|
|
13298
|
+
if (scope.type === "vendor") candidates.push(scope.vendorId);
|
|
13299
|
+
if (scope.type === "all" || scope.type === "vendor") {
|
|
13300
|
+
const preferred = u.activeVendorId ?? u.vendorIds?.[0];
|
|
13301
|
+
if (preferred != null && Number.isFinite(preferred)) candidates.push(Number(preferred));
|
|
13302
|
+
for (const id of u.vendorIds ?? []) {
|
|
13303
|
+
if (Number.isFinite(id)) candidates.push(Number(id));
|
|
13304
|
+
}
|
|
13305
|
+
}
|
|
13306
|
+
if (entityMap.vendors && candidates.length > 0) {
|
|
13307
|
+
const unique = [
|
|
13308
|
+
...new Set(candidates.filter((id) => id > 0))
|
|
13309
|
+
];
|
|
13310
|
+
for (const id of unique) {
|
|
13311
|
+
try {
|
|
13312
|
+
const row = await dataSource.getRepository(entityMap.vendors).findOne({
|
|
13313
|
+
where: {
|
|
13314
|
+
id,
|
|
13315
|
+
deleted: false
|
|
13316
|
+
}
|
|
13317
|
+
});
|
|
13318
|
+
if (row) return id;
|
|
13319
|
+
} catch {
|
|
13320
|
+
}
|
|
13321
|
+
}
|
|
13322
|
+
}
|
|
13323
|
+
const uid = u.id != null ? Number(u.id) : NaN;
|
|
13324
|
+
if (Number.isFinite(uid) && entityMap.vendors) {
|
|
13325
|
+
try {
|
|
13326
|
+
const owned = await dataSource.getRepository(entityMap.vendors).findOne({
|
|
13327
|
+
where: {
|
|
13328
|
+
userId: uid,
|
|
13329
|
+
deleted: false
|
|
13330
|
+
},
|
|
13331
|
+
order: {
|
|
13332
|
+
id: "ASC"
|
|
13333
|
+
}
|
|
13334
|
+
});
|
|
13335
|
+
const vid = owned ? Number(owned.id) : NaN;
|
|
13336
|
+
if (Number.isFinite(vid) && vid > 0) return vid;
|
|
13337
|
+
} catch {
|
|
13338
|
+
}
|
|
12847
13339
|
}
|
|
12848
13340
|
return null;
|
|
12849
13341
|
}
|
|
12850
13342
|
chunkUSNT2KNT_cjs.__name(resolveActiveVendorId, "resolveActiveVendorId");
|
|
13343
|
+
async function gateVendorPortal() {
|
|
13344
|
+
const u = await getSessionUser();
|
|
13345
|
+
if (!u?.email) return json({
|
|
13346
|
+
error: "Unauthorized"
|
|
13347
|
+
}, {
|
|
13348
|
+
status: 401
|
|
13349
|
+
});
|
|
13350
|
+
if (!chunkX6UQFV4X_cjs.isVendorPortalUser(u) && !chunkX6UQFV4X_cjs.isPlatformAdministrator(u)) {
|
|
13351
|
+
return json({
|
|
13352
|
+
error: "Forbidden"
|
|
13353
|
+
}, {
|
|
13354
|
+
status: 403
|
|
13355
|
+
});
|
|
13356
|
+
}
|
|
13357
|
+
const vendorId = await resolveActiveVendorId(u);
|
|
13358
|
+
if (vendorId == null) {
|
|
13359
|
+
return json({
|
|
13360
|
+
error: "No vendor is linked to your account."
|
|
13361
|
+
}, {
|
|
13362
|
+
status: 400
|
|
13363
|
+
});
|
|
13364
|
+
}
|
|
13365
|
+
return {
|
|
13366
|
+
user: u,
|
|
13367
|
+
vendorId
|
|
13368
|
+
};
|
|
13369
|
+
}
|
|
13370
|
+
chunkUSNT2KNT_cjs.__name(gateVendorPortal, "gateVendorPortal");
|
|
12851
13371
|
async function gateVendorTeam() {
|
|
12852
13372
|
const u = await getSessionUser();
|
|
12853
13373
|
if (!u?.email) return json({
|
|
@@ -12901,6 +13421,40 @@ function createVendorOnboardHandlers(config) {
|
|
|
12901
13421
|
}
|
|
12902
13422
|
chunkUSNT2KNT_cjs.__name(trySendVendorOnboardEmails, "trySendVendorOnboardEmails");
|
|
12903
13423
|
return {
|
|
13424
|
+
/** GET /api/admin/vendor/profile — current user's store (server-resolved vendor id). */
|
|
13425
|
+
async getProfile() {
|
|
13426
|
+
const gated = await gateVendorPortal();
|
|
13427
|
+
if (gated instanceof Response) return gated;
|
|
13428
|
+
const { vendorId } = gated;
|
|
13429
|
+
if (!entityMap.vendors) {
|
|
13430
|
+
return json({
|
|
13431
|
+
error: "Vendors not configured"
|
|
13432
|
+
}, {
|
|
13433
|
+
status: 500
|
|
13434
|
+
});
|
|
13435
|
+
}
|
|
13436
|
+
try {
|
|
13437
|
+
const row = await dataSource.getRepository(entityMap.vendors).findOne({
|
|
13438
|
+
where: {
|
|
13439
|
+
id: vendorId,
|
|
13440
|
+
deleted: false
|
|
13441
|
+
}
|
|
13442
|
+
});
|
|
13443
|
+
if (!row) return json({
|
|
13444
|
+
error: "Vendor not found"
|
|
13445
|
+
}, {
|
|
13446
|
+
status: 404
|
|
13447
|
+
});
|
|
13448
|
+
return json(row);
|
|
13449
|
+
} catch (e) {
|
|
13450
|
+
console.error("[vendor.profile]", e);
|
|
13451
|
+
return json({
|
|
13452
|
+
error: "Failed to load vendor profile"
|
|
13453
|
+
}, {
|
|
13454
|
+
status: 500
|
|
13455
|
+
});
|
|
13456
|
+
}
|
|
13457
|
+
},
|
|
12904
13458
|
/** POST /api/admin/vendors/onboard — create vendor + owner user + vendor_users + invite */
|
|
12905
13459
|
async onboard(req) {
|
|
12906
13460
|
const err = await gateAdmin();
|
|
@@ -12969,6 +13523,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12969
13523
|
}
|
|
12970
13524
|
});
|
|
12971
13525
|
if (dupVendor) throw new Error("VENDOR_SLUG_EXISTS");
|
|
13526
|
+
await chunkOY2YTBMP_cjs.retireSoftDeletedUniqueValue(vendorRepo, "slug", slug);
|
|
12972
13527
|
let ownerGroup = await groupRepo.findOne({
|
|
12973
13528
|
where: {
|
|
12974
13529
|
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
@@ -12997,8 +13552,15 @@ function createVendorOnboardHandlers(config) {
|
|
|
12997
13552
|
email: userEmail
|
|
12998
13553
|
}
|
|
12999
13554
|
});
|
|
13000
|
-
if (existingUser && !existingUser.deleted)
|
|
13001
|
-
|
|
13555
|
+
if (existingUser && !existingUser.deleted) {
|
|
13556
|
+
if (await userHasActiveVendor(em, entityMap, existingUser.id)) {
|
|
13557
|
+
throw new Error("USER_EMAIL_EXISTS");
|
|
13558
|
+
}
|
|
13559
|
+
if (!await userHadAnyVendor(em, entityMap, existingUser.id)) {
|
|
13560
|
+
throw new Error("USER_EMAIL_EXISTS");
|
|
13561
|
+
}
|
|
13562
|
+
}
|
|
13563
|
+
const newUser = existingUser ? await (async () => {
|
|
13002
13564
|
await userRepo.update(existingUser.id, {
|
|
13003
13565
|
deleted: false,
|
|
13004
13566
|
deletedAt: null,
|
|
@@ -14365,6 +14927,13 @@ exports.User = class User {
|
|
|
14365
14927
|
phoneVerifiedAt;
|
|
14366
14928
|
emailVerifiedAt;
|
|
14367
14929
|
password;
|
|
14930
|
+
/**
|
|
14931
|
+
* `pending` = invite outstanding (cannot sign in until password is set).
|
|
14932
|
+
* `active` = invite accepted / account usable (subject to `blocked`).
|
|
14933
|
+
*/
|
|
14934
|
+
inviteStatus;
|
|
14935
|
+
/** Rotating invite token; null when active or no invite outstanding. */
|
|
14936
|
+
inviteToken;
|
|
14368
14937
|
blocked;
|
|
14369
14938
|
adminAccess;
|
|
14370
14939
|
groupId;
|
|
@@ -14417,6 +14986,24 @@ _ts_decorate4([
|
|
|
14417
14986
|
}),
|
|
14418
14987
|
_ts_metadata4("design:type", Object)
|
|
14419
14988
|
], exports.User.prototype, "password", void 0);
|
|
14989
|
+
_ts_decorate4([
|
|
14990
|
+
typeorm.Column({
|
|
14991
|
+
type: "enum",
|
|
14992
|
+
enum: [
|
|
14993
|
+
"pending",
|
|
14994
|
+
"active"
|
|
14995
|
+
],
|
|
14996
|
+
enumName: "users_invitestatus_enum",
|
|
14997
|
+
default: "active"
|
|
14998
|
+
}),
|
|
14999
|
+
_ts_metadata4("design:type", typeof UserInviteStatus === "undefined" ? Object : UserInviteStatus)
|
|
15000
|
+
], exports.User.prototype, "inviteStatus", void 0);
|
|
15001
|
+
_ts_decorate4([
|
|
15002
|
+
typeorm.Column("varchar", {
|
|
15003
|
+
nullable: true
|
|
15004
|
+
}),
|
|
15005
|
+
_ts_metadata4("design:type", Object)
|
|
15006
|
+
], exports.User.prototype, "inviteToken", void 0);
|
|
14420
15007
|
_ts_decorate4([
|
|
14421
15008
|
typeorm.Column("boolean", {
|
|
14422
15009
|
default: false
|
|
@@ -16081,10 +16668,12 @@ exports.Customer = class Customer {
|
|
|
16081
16668
|
chunkUSNT2KNT_cjs.__name(this, "Customer");
|
|
16082
16669
|
}
|
|
16083
16670
|
id;
|
|
16671
|
+
/** Set only when the customer can log in (linked `users` row). Admin/guest customers stay null. */
|
|
16084
16672
|
userId;
|
|
16085
16673
|
user;
|
|
16086
16674
|
name;
|
|
16087
16675
|
email;
|
|
16676
|
+
/** Optional; multiple customers may have null (PostgreSQL UNIQUE allows multiple NULLs). */
|
|
16088
16677
|
phone;
|
|
16089
16678
|
createdAt;
|
|
16090
16679
|
updatedAt;
|
|
@@ -16099,8 +16688,10 @@ _ts_decorate18([
|
|
|
16099
16688
|
_ts_metadata18("design:type", Number)
|
|
16100
16689
|
], exports.Customer.prototype, "id", void 0);
|
|
16101
16690
|
_ts_decorate18([
|
|
16102
|
-
typeorm.Column("int"
|
|
16103
|
-
|
|
16691
|
+
typeorm.Column("int", {
|
|
16692
|
+
nullable: true
|
|
16693
|
+
}),
|
|
16694
|
+
_ts_metadata18("design:type", Object)
|
|
16104
16695
|
], exports.Customer.prototype, "userId", void 0);
|
|
16105
16696
|
_ts_decorate18([
|
|
16106
16697
|
typeorm.ManyToOne(() => exports.User, {
|
|
@@ -16123,9 +16714,10 @@ _ts_decorate18([
|
|
|
16123
16714
|
], exports.Customer.prototype, "email", void 0);
|
|
16124
16715
|
_ts_decorate18([
|
|
16125
16716
|
typeorm.Column("varchar", {
|
|
16126
|
-
unique: true
|
|
16717
|
+
unique: true,
|
|
16718
|
+
nullable: true
|
|
16127
16719
|
}),
|
|
16128
|
-
_ts_metadata18("design:type",
|
|
16720
|
+
_ts_metadata18("design:type", Object)
|
|
16129
16721
|
], exports.Customer.prototype, "phone", void 0);
|
|
16130
16722
|
_ts_decorate18([
|
|
16131
16723
|
typeorm.Column({
|
|
@@ -19145,6 +19737,8 @@ exports.OrderItem = class OrderItem {
|
|
|
19145
19737
|
id;
|
|
19146
19738
|
orderId;
|
|
19147
19739
|
productId;
|
|
19740
|
+
/** Selected product variant at order time (optional). */
|
|
19741
|
+
variantId;
|
|
19148
19742
|
discountIds;
|
|
19149
19743
|
vendorId;
|
|
19150
19744
|
vendor;
|
|
@@ -19180,6 +19774,12 @@ _ts_decorate39([
|
|
|
19180
19774
|
typeorm.Column("int"),
|
|
19181
19775
|
_ts_metadata39("design:type", Number)
|
|
19182
19776
|
], exports.OrderItem.prototype, "productId", void 0);
|
|
19777
|
+
_ts_decorate39([
|
|
19778
|
+
typeorm.Column("int", {
|
|
19779
|
+
nullable: true
|
|
19780
|
+
}),
|
|
19781
|
+
_ts_metadata39("design:type", Object)
|
|
19782
|
+
], exports.OrderItem.prototype, "variantId", void 0);
|
|
19183
19783
|
_ts_decorate39([
|
|
19184
19784
|
typeorm.Column({
|
|
19185
19785
|
type: "int",
|
|
@@ -19989,6 +20589,7 @@ var Type = /* @__PURE__ */ (function(Type2) {
|
|
|
19989
20589
|
Type2["CATEGORY"] = "category";
|
|
19990
20590
|
Type2["CART"] = "cart";
|
|
19991
20591
|
Type2["PAYMENT_METHOD"] = "paymentMethod";
|
|
20592
|
+
Type2["DEVICE_TYPE"] = "deviceType";
|
|
19992
20593
|
Type2["ORDER"] = "order";
|
|
19993
20594
|
Type2["QUANTITY"] = "quantity";
|
|
19994
20595
|
Type2["TIME"] = "time";
|
|
@@ -22011,6 +22612,7 @@ exports.Combo = class Combo {
|
|
|
22011
22612
|
vendorId;
|
|
22012
22613
|
vendor;
|
|
22013
22614
|
name;
|
|
22615
|
+
slug;
|
|
22014
22616
|
desc;
|
|
22015
22617
|
eventId;
|
|
22016
22618
|
event;
|
|
@@ -22054,6 +22656,12 @@ _ts_decorate63([
|
|
|
22054
22656
|
}),
|
|
22055
22657
|
_ts_metadata63("design:type", String)
|
|
22056
22658
|
], exports.Combo.prototype, "name", void 0);
|
|
22659
|
+
_ts_decorate63([
|
|
22660
|
+
typeorm.Column({
|
|
22661
|
+
type: "varchar"
|
|
22662
|
+
}),
|
|
22663
|
+
_ts_metadata63("design:type", String)
|
|
22664
|
+
], exports.Combo.prototype, "slug", void 0);
|
|
22057
22665
|
_ts_decorate63([
|
|
22058
22666
|
typeorm.Column({
|
|
22059
22667
|
type: "text",
|
|
@@ -22191,7 +22799,11 @@ _ts_decorate63([
|
|
|
22191
22799
|
_ts_metadata63("design:type", Number)
|
|
22192
22800
|
], exports.Combo.prototype, "deletedBy", void 0);
|
|
22193
22801
|
exports.Combo = _ts_decorate63([
|
|
22194
|
-
typeorm.Entity("combos")
|
|
22802
|
+
typeorm.Entity("combos"),
|
|
22803
|
+
typeorm.Unique("UQ_combos_vendor_slug", [
|
|
22804
|
+
"vendorId",
|
|
22805
|
+
"slug"
|
|
22806
|
+
])
|
|
22195
22807
|
], exports.Combo);
|
|
22196
22808
|
function _ts_decorate64(decorators, target, key, desc) {
|
|
22197
22809
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -26036,16 +26648,16 @@ function whatsappPlugin(config = {}) {
|
|
|
26036
26648
|
db = await getWhatsAppSettings?.() ?? {};
|
|
26037
26649
|
} catch {
|
|
26038
26650
|
}
|
|
26039
|
-
if (!
|
|
26651
|
+
if (!chunk7PMHZRF3_cjs.isWhatsAppPluginEnabled(db)) {
|
|
26040
26652
|
context.logger.warn("WhatsApp plugin skipped: disabled in Plugins \u2192 WhatsApp");
|
|
26041
26653
|
return null;
|
|
26042
26654
|
}
|
|
26043
|
-
const merged =
|
|
26044
|
-
if (!getWhatsAppSettings && !
|
|
26655
|
+
const merged = chunk7PMHZRF3_cjs.mergeWhatsAppConfigLayers(env, db, staticRest);
|
|
26656
|
+
if (!getWhatsAppSettings && !chunk7PMHZRF3_cjs.whatsAppConfigured(merged)) {
|
|
26045
26657
|
context.logger.warn("WhatsApp plugin skipped: set WHATSAPP_ACCESS_TOKEN and WHATSAPP_PHONE_NUMBER_ID, or pass getWhatsAppSettings");
|
|
26046
26658
|
return null;
|
|
26047
26659
|
}
|
|
26048
|
-
const svc = new
|
|
26660
|
+
const svc = new chunk7PMHZRF3_cjs.WhatsAppService(env, staticRest, getWhatsAppSettings, getMessageTemplateRow);
|
|
26049
26661
|
return {
|
|
26050
26662
|
send: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name((opts) => svc.send(opts), "send")
|
|
26051
26663
|
};
|
|
@@ -26117,9 +26729,12 @@ function createMessageTemplateRowLoader(dataSource, entityMap) {
|
|
|
26117
26729
|
};
|
|
26118
26730
|
}
|
|
26119
26731
|
chunkUSNT2KNT_cjs.__name(createMessageTemplateRowLoader, "createMessageTemplateRowLoader");
|
|
26120
|
-
function registerMessagingQueueProcessors(cms) {
|
|
26121
|
-
|
|
26122
|
-
|
|
26732
|
+
function registerMessagingQueueProcessors(cms, entityMap) {
|
|
26733
|
+
chunkV25RDUOU_cjs.registerEmailQueueProcessor(cms, {
|
|
26734
|
+
getDataSource: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => cms.dataSource, "getDataSource"),
|
|
26735
|
+
entityMap
|
|
26736
|
+
});
|
|
26737
|
+
chunk7PMHZRF3_cjs.registerWhatsAppQueueProcessor(cms);
|
|
26123
26738
|
}
|
|
26124
26739
|
chunkUSNT2KNT_cjs.__name(registerMessagingQueueProcessors, "registerMessagingQueueProcessors");
|
|
26125
26740
|
async function ensureMessagingPluginsOnCms(base, options) {
|
|
@@ -26148,7 +26763,7 @@ async function ensureMessagingPluginsOnCms(base, options) {
|
|
|
26148
26763
|
}
|
|
26149
26764
|
if (!cms.getPlugin("email")) {
|
|
26150
26765
|
try {
|
|
26151
|
-
const instance = await
|
|
26766
|
+
const instance = await chunkTCSGFAWB_cjs.emailPlugin({
|
|
26152
26767
|
type: "SMTP",
|
|
26153
26768
|
from: config.SMTP_FROM ?? "no-reply@localhost",
|
|
26154
26769
|
to: config.SMTP_TO ?? ""
|
|
@@ -26170,7 +26785,7 @@ async function ensureMessagingPluginsOnCms(base, options) {
|
|
|
26170
26785
|
}
|
|
26171
26786
|
}
|
|
26172
26787
|
const merged = Object.keys(overlay).length > 0 ? overlayCmsPlugins(cms, overlay) : cms;
|
|
26173
|
-
registerMessagingQueueProcessors(merged);
|
|
26788
|
+
registerMessagingQueueProcessors(merged, entityMap);
|
|
26174
26789
|
return merged;
|
|
26175
26790
|
}
|
|
26176
26791
|
chunkUSNT2KNT_cjs.__name(ensureMessagingPluginsOnCms, "ensureMessagingPluginsOnCms");
|
|
@@ -26189,7 +26804,7 @@ function messagingPlugins(options) {
|
|
|
26189
26804
|
const config = options.config ?? (typeof process !== "undefined" ? process.env : {});
|
|
26190
26805
|
return [
|
|
26191
26806
|
queuePlugin(),
|
|
26192
|
-
|
|
26807
|
+
chunkTCSGFAWB_cjs.emailPlugin({
|
|
26193
26808
|
type: "SMTP",
|
|
26194
26809
|
from: config.SMTP_FROM ?? "no-reply@localhost",
|
|
26195
26810
|
to: config.SMTP_TO ?? ""
|
|
@@ -26219,7 +26834,7 @@ async function createCmsAppWithMessaging(options) {
|
|
|
26219
26834
|
logger,
|
|
26220
26835
|
plugins: mergedPlugins
|
|
26221
26836
|
});
|
|
26222
|
-
registerMessagingQueueProcessors(cms);
|
|
26837
|
+
registerMessagingQueueProcessors(cms, entityMap);
|
|
26223
26838
|
return cms;
|
|
26224
26839
|
}
|
|
26225
26840
|
chunkUSNT2KNT_cjs.__name(createCmsAppWithMessaging, "createCmsAppWithMessaging");
|
|
@@ -26323,7 +26938,7 @@ function createCmsApiHandler(config) {
|
|
|
26323
26938
|
} : void 0;
|
|
26324
26939
|
const entityMap = withLlmKnowledgeEntityFallbacks(rawEntityMap);
|
|
26325
26940
|
if (getCms) {
|
|
26326
|
-
|
|
26941
|
+
chunk7PMHZRF3_cjs.initWhatsappTriggerDispatcher({
|
|
26327
26942
|
dataSource,
|
|
26328
26943
|
entityMap,
|
|
26329
26944
|
getCms
|
|
@@ -26356,7 +26971,7 @@ function createCmsApiHandler(config) {
|
|
|
26356
26971
|
status: 401
|
|
26357
26972
|
});
|
|
26358
26973
|
}
|
|
26359
|
-
const allowed =
|
|
26974
|
+
const allowed = chunkNBY4NVTY_cjs.sessionHasEntityAccess(u, entity, action);
|
|
26360
26975
|
await chunkX6UQFV4X_cjs.logEntityAccessDecision(dataSource, "cmsApi.requireEntityPermission", u, entity, action, {
|
|
26361
26976
|
allowed,
|
|
26362
26977
|
resolvePath: "hydrated_session"
|
|
@@ -26416,7 +27031,7 @@ function createCmsApiHandler(config) {
|
|
|
26416
27031
|
companyDetails
|
|
26417
27032
|
};
|
|
26418
27033
|
if (queue) {
|
|
26419
|
-
const { queueEmail: queueEmail2 } = await import('./email-queue-
|
|
27034
|
+
const { queueEmail: queueEmail2 } = await import('./email-queue-6NJY6HNM.cjs');
|
|
26420
27035
|
await queueEmail2(cms, {
|
|
26421
27036
|
to: opts.to,
|
|
26422
27037
|
templateName: "passwordReset",
|
|
@@ -26709,6 +27324,14 @@ function createCmsApiHandler(config) {
|
|
|
26709
27324
|
});
|
|
26710
27325
|
return vendorHandlers.switchVendor(req);
|
|
26711
27326
|
}
|
|
27327
|
+
if (path2[0] === "admin" && path2[1] === "vendor" && path2[2] === "profile" && path2.length === 3 && m === "GET") {
|
|
27328
|
+
if (!vendorHandlers) return config.json({
|
|
27329
|
+
error: "Not found"
|
|
27330
|
+
}, {
|
|
27331
|
+
status: 404
|
|
27332
|
+
});
|
|
27333
|
+
return vendorHandlers.getProfile();
|
|
27334
|
+
}
|
|
26712
27335
|
if (path2[0] === "admin" && path2[1] === "vendor" && path2[2] === "roles" && vendorRolesHandlers) {
|
|
26713
27336
|
if (path2.length === 3 && m === "GET") return vendorRolesHandlers.list();
|
|
26714
27337
|
if (path2.length === 3 && m === "POST") return vendorRolesHandlers.create(req);
|
|
@@ -27662,14 +28285,27 @@ function createCmsApiHandler(config) {
|
|
|
27662
28285
|
const pe = await requireEntityPermissionEffective(req, "orders", "read");
|
|
27663
28286
|
if (pe) return pe;
|
|
27664
28287
|
const cms = await getCms();
|
|
27665
|
-
const { streamOrderInvoicePdf: streamOrderInvoicePdf2 } = await import('./erp-order-invoice-
|
|
28288
|
+
const { streamOrderInvoicePdf: streamOrderInvoicePdf2 } = await import('./erp-order-invoice-EYYNR526.cjs');
|
|
27666
28289
|
const oid = Number(path2[1]);
|
|
27667
28290
|
if (!Number.isFinite(oid)) return config.json({
|
|
27668
28291
|
error: "Invalid id"
|
|
27669
28292
|
}, {
|
|
27670
28293
|
status: 400
|
|
27671
28294
|
});
|
|
27672
|
-
|
|
28295
|
+
try {
|
|
28296
|
+
return await streamOrderInvoicePdf2(cms, dataSource, entityMap, oid, {});
|
|
28297
|
+
} catch (err) {
|
|
28298
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
28299
|
+
console.error("[invoice] route failed", {
|
|
28300
|
+
orderId: oid,
|
|
28301
|
+
error: msg
|
|
28302
|
+
});
|
|
28303
|
+
return config.json({
|
|
28304
|
+
error: `Invoice failed: ${msg}`
|
|
28305
|
+
}, {
|
|
28306
|
+
status: 500
|
|
28307
|
+
});
|
|
28308
|
+
}
|
|
27673
28309
|
}
|
|
27674
28310
|
if (path2[0] === "orders" && path2.length === 3 && path2[2] === "repost-erp" && getCms) {
|
|
27675
28311
|
const a = await config.requireAuth(req);
|
|
@@ -28016,7 +28652,7 @@ function createCmsApiHandler(config) {
|
|
|
28016
28652
|
status: 400
|
|
28017
28653
|
});
|
|
28018
28654
|
}
|
|
28019
|
-
const { resendOrderNotification } = await import('./order-notification-dispatcher-
|
|
28655
|
+
const { resendOrderNotification } = await import('./order-notification-dispatcher-SBQAMM5V.cjs');
|
|
28020
28656
|
const result = await resendOrderNotification(triggerKey, orderId, {
|
|
28021
28657
|
dataSource,
|
|
28022
28658
|
entityMap,
|
|
@@ -28088,6 +28724,30 @@ function createCmsApiHandler(config) {
|
|
|
28088
28724
|
paymentId = Number(payment.id);
|
|
28089
28725
|
}
|
|
28090
28726
|
}
|
|
28727
|
+
const orderWithItems = await orderRepo.findOne({
|
|
28728
|
+
where: {
|
|
28729
|
+
id: orderId,
|
|
28730
|
+
deleted: false
|
|
28731
|
+
},
|
|
28732
|
+
relations: [
|
|
28733
|
+
"items"
|
|
28734
|
+
]
|
|
28735
|
+
});
|
|
28736
|
+
if (orderWithItems) {
|
|
28737
|
+
const { reconcileOrderInventoryBetweenSnapshots: reconcileOrderInventoryBetweenSnapshots2, orderInventorySnapshotFromRow: orderInventorySnapshotFromRow2 } = await import('./order-inventory-2MYRKEPC.cjs');
|
|
28738
|
+
const prevSnap = orderInventorySnapshotFromRow2(orderWithItems);
|
|
28739
|
+
const invErr = await reconcileOrderInventoryBetweenSnapshots2(dataSource, entityMap, prevSnap, {
|
|
28740
|
+
status: "cancelled",
|
|
28741
|
+
lines: prevSnap.lines
|
|
28742
|
+
});
|
|
28743
|
+
if (invErr) {
|
|
28744
|
+
return config.json({
|
|
28745
|
+
error: invErr
|
|
28746
|
+
}, {
|
|
28747
|
+
status: 400
|
|
28748
|
+
});
|
|
28749
|
+
}
|
|
28750
|
+
}
|
|
28091
28751
|
await orderRepo.update(orderId, {
|
|
28092
28752
|
status: "cancelled"
|
|
28093
28753
|
});
|
|
@@ -28747,12 +29407,12 @@ async function refreshOrderFromErp(cms, dataSource, entityMap, submission, order
|
|
|
28747
29407
|
const r1 = await submission.postErpReadAction("get-order-status", {
|
|
28748
29408
|
platformOrderId: refId
|
|
28749
29409
|
});
|
|
28750
|
-
const d1 = r1.ok ?
|
|
29410
|
+
const d1 = r1.ok ? chunkBXYZDMTZ_cjs.unwrapErpReadData(r1.json) : null;
|
|
28751
29411
|
if (d1) {
|
|
28752
29412
|
const mapped = mapErpSaleStatusToOrderStatus(typeof d1.status === "string" ? d1.status : typeof d1.orderStatus === "string" ? d1.orderStatus : typeof d1.state === "string" ? d1.state : void 0);
|
|
28753
29413
|
if (mapped) newStatus = mapped;
|
|
28754
|
-
fulfillment =
|
|
28755
|
-
const refs =
|
|
29414
|
+
fulfillment = chunkBXYZDMTZ_cjs.mapErpPayloadToFulfillment(d1);
|
|
29415
|
+
const refs = chunkBXYZDMTZ_cjs.extractChildOrderRefsFromSalePayload(d1);
|
|
28756
29416
|
if (refs.length) {
|
|
28757
29417
|
await ensureChildOrdersFromRefs(orderRepo, order, refs, order.contactId, String(order.currency || "INR"));
|
|
28758
29418
|
}
|
|
@@ -28760,16 +29420,16 @@ async function refreshOrderFromErp(cms, dataSource, entityMap, submission, order
|
|
|
28760
29420
|
const r2 = await submission.postErpReadAction("get-fulfillment-status", {
|
|
28761
29421
|
platformOrderId: refId
|
|
28762
29422
|
});
|
|
28763
|
-
const d2 = r2.ok ?
|
|
29423
|
+
const d2 = r2.ok ? chunkBXYZDMTZ_cjs.unwrapErpReadData(r2.json) : null;
|
|
28764
29424
|
if (d2) {
|
|
28765
|
-
fulfillment = deepMergeFulfillment(fulfillment,
|
|
29425
|
+
fulfillment = deepMergeFulfillment(fulfillment, chunkBXYZDMTZ_cjs.mapErpPayloadToFulfillment(d2));
|
|
28766
29426
|
}
|
|
28767
29427
|
const r3 = await submission.postErpReadAction("get-invoice", {
|
|
28768
29428
|
platformOrderId: refId
|
|
28769
29429
|
});
|
|
28770
|
-
const d3 = r3.ok ?
|
|
29430
|
+
const d3 = r3.ok ? chunkBXYZDMTZ_cjs.unwrapErpReadData(r3.json) : null;
|
|
28771
29431
|
if (d3) {
|
|
28772
|
-
invoiceNumber =
|
|
29432
|
+
invoiceNumber = chunkBXYZDMTZ_cjs.mapErpPayloadToInvoiceNumber(d3);
|
|
28773
29433
|
invoiceId = pickInvoiceId(d3);
|
|
28774
29434
|
}
|
|
28775
29435
|
const oid = order.id;
|
|
@@ -28805,10 +29465,10 @@ async function refreshOrderFromErp(cms, dataSource, entityMap, submission, order
|
|
|
28805
29465
|
const r = await submission.postErpReadAction("get-return-status", {
|
|
28806
29466
|
platformReturnId
|
|
28807
29467
|
});
|
|
28808
|
-
const d = r.ok ?
|
|
29468
|
+
const d = r.ok ? chunkBXYZDMTZ_cjs.unwrapErpReadData(r.json) : null;
|
|
28809
29469
|
if (!d) return;
|
|
28810
29470
|
const mapped = mapErpSaleStatusToOrderStatus(typeof d.status === "string" ? d.status : typeof d.returnStatus === "string" ? d.returnStatus : void 0);
|
|
28811
|
-
const fulfillment =
|
|
29471
|
+
const fulfillment = chunkBXYZDMTZ_cjs.mapErpPayloadToFulfillment(d);
|
|
28812
29472
|
const patch = {};
|
|
28813
29473
|
if (fulfillment !== void 0) patch.fulfillment = fulfillment;
|
|
28814
29474
|
const nextMeta = Object.keys(patch).length ? mergeOrderMetadataPatch(meta, patch) : meta;
|
|
@@ -29131,6 +29791,14 @@ function createStorefrontApiHandler(config) {
|
|
|
29131
29791
|
entityMap
|
|
29132
29792
|
});
|
|
29133
29793
|
}).catch((err) => console.error("[notification-triggers] import failed", err));
|
|
29794
|
+
if (!getCms) return;
|
|
29795
|
+
void import('./send-order-placed-emails-B5ZVJT7T.cjs').then(({ sendOrderPlacedEmailsAfterConfirmation }) => {
|
|
29796
|
+
return sendOrderPlacedEmailsAfterConfirmation(orderId, {
|
|
29797
|
+
getDataSource: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => dataSource, "getDataSource"),
|
|
29798
|
+
entityMap,
|
|
29799
|
+
getCms
|
|
29800
|
+
});
|
|
29801
|
+
}).catch((err) => console.error("[order-emails] sendOrderPlacedEmailsAfterConfirmation failed", err));
|
|
29134
29802
|
}
|
|
29135
29803
|
chunkUSNT2KNT_cjs.__name(fireOrderPlacedNotification, "fireOrderPlacedNotification");
|
|
29136
29804
|
const otpAllowPhoneLogin = config.otpAllowPhoneLogin !== false;
|
|
@@ -29178,13 +29846,36 @@ function createStorefrontApiHandler(config) {
|
|
|
29178
29846
|
status: 400
|
|
29179
29847
|
};
|
|
29180
29848
|
}
|
|
29849
|
+
const list = [
|
|
29850
|
+
...vendorIds
|
|
29851
|
+
];
|
|
29181
29852
|
return {
|
|
29182
|
-
vendorId: [
|
|
29183
|
-
|
|
29184
|
-
][0]
|
|
29853
|
+
vendorId: list[0],
|
|
29854
|
+
vendorIds: list
|
|
29185
29855
|
};
|
|
29186
29856
|
}
|
|
29187
29857
|
chunkUSNT2KNT_cjs.__name(resolveSingleVendorIdFromCart, "resolveSingleVendorIdFromCart");
|
|
29858
|
+
async function linkOrderContactToVendors(contactId, vendorIds) {
|
|
29859
|
+
try {
|
|
29860
|
+
const contact = await contactRepo().findOne({
|
|
29861
|
+
where: {
|
|
29862
|
+
id: contactId,
|
|
29863
|
+
deleted: false
|
|
29864
|
+
}
|
|
29865
|
+
});
|
|
29866
|
+
if (!contact) return;
|
|
29867
|
+
const email = String(contact.email ?? "").trim().toLowerCase();
|
|
29868
|
+
if (!email) return;
|
|
29869
|
+
await ensureVendorCustomersForOrder(dataSource, entityMap, vendorIds, contactId, {
|
|
29870
|
+
name: String(contact.name ?? "").trim() || email.split("@")[0] || "Customer",
|
|
29871
|
+
email,
|
|
29872
|
+
phone: contact.phone ?? null
|
|
29873
|
+
});
|
|
29874
|
+
} catch (err) {
|
|
29875
|
+
console.error("[storefront] vendor_customers link failed", err);
|
|
29876
|
+
}
|
|
29877
|
+
}
|
|
29878
|
+
chunkUSNT2KNT_cjs.__name(linkOrderContactToVendors, "linkOrderContactToVendors");
|
|
29188
29879
|
function roundMoney3(n) {
|
|
29189
29880
|
return Math.round(n * 100) / 100;
|
|
29190
29881
|
}
|
|
@@ -30709,7 +31400,7 @@ function createStorefrontApiHandler(config) {
|
|
|
30709
31400
|
status: 503
|
|
30710
31401
|
});
|
|
30711
31402
|
const companyDetails = getCompanyDetails ? await getCompanyDetails() : {};
|
|
30712
|
-
await
|
|
31403
|
+
await chunkV25RDUOU_cjs.queueEmail(cms, {
|
|
30713
31404
|
to: identifier,
|
|
30714
31405
|
templateName: "otp",
|
|
30715
31406
|
ctx: {
|
|
@@ -30876,9 +31567,12 @@ function createStorefrontApiHandler(config) {
|
|
|
30876
31567
|
}, {
|
|
30877
31568
|
status: 400
|
|
30878
31569
|
});
|
|
31570
|
+
const { retireSoftDeletedUniqueValue: retireSoftDeletedUniqueValue2 } = await import('./retire-soft-deleted-unique-5VXBA5XX.cjs');
|
|
31571
|
+
await retireSoftDeletedUniqueValue2(userRepo(), "email", email);
|
|
30879
31572
|
const existing = await userRepo().findOne({
|
|
30880
31573
|
where: {
|
|
30881
|
-
email
|
|
31574
|
+
email,
|
|
31575
|
+
deleted: false
|
|
30882
31576
|
}
|
|
30883
31577
|
});
|
|
30884
31578
|
if (existing) return json({
|
|
@@ -30931,7 +31625,7 @@ function createStorefrontApiHandler(config) {
|
|
|
30931
31625
|
const companyDetails = getCompanyDetails ? await getCompanyDetails() : {};
|
|
30932
31626
|
const base = (publicSiteUrl || "").replace(/\/$/, "").trim() || "http://localhost:3000";
|
|
30933
31627
|
const verifyEmailUrl = `${base}/verify-email?token=${encodeURIComponent(rawToken)}`;
|
|
30934
|
-
await
|
|
31628
|
+
await chunkV25RDUOU_cjs.queueEmail(cms, {
|
|
30935
31629
|
to: email,
|
|
30936
31630
|
templateName: "signup",
|
|
30937
31631
|
ctx: {
|
|
@@ -31506,6 +32200,7 @@ function createStorefrontApiHandler(config) {
|
|
|
31506
32200
|
taxCode: line.taxCode
|
|
31507
32201
|
}));
|
|
31508
32202
|
}
|
|
32203
|
+
await linkOrderContactToVendors(contactId, vendorRes.vendorIds);
|
|
31509
32204
|
fireOrderPlacedNotification(oid);
|
|
31510
32205
|
return json({
|
|
31511
32206
|
orderId: oid,
|
|
@@ -31578,6 +32273,7 @@ function createStorefrontApiHandler(config) {
|
|
|
31578
32273
|
taxCode: line.taxCode
|
|
31579
32274
|
}));
|
|
31580
32275
|
}
|
|
32276
|
+
await linkOrderContactToVendors(contactId, vendorResChk.vendorIds);
|
|
31581
32277
|
await cartItemRepo().delete({
|
|
31582
32278
|
cartId: cart.id
|
|
31583
32279
|
});
|
|
@@ -31687,7 +32383,7 @@ function createStorefrontApiHandler(config) {
|
|
|
31687
32383
|
status: 400
|
|
31688
32384
|
});
|
|
31689
32385
|
const cms = await getCms();
|
|
31690
|
-
return
|
|
32386
|
+
return chunkBXYZDMTZ_cjs.streamOrderInvoicePdf(cms, dataSource, entityMap, orderId, {
|
|
31691
32387
|
ownerContactId: contact.id
|
|
31692
32388
|
});
|
|
31693
32389
|
}
|
|
@@ -31757,6 +32453,7 @@ function createStorefrontApiHandler(config) {
|
|
|
31757
32453
|
unitPrice: line.unitPrice,
|
|
31758
32454
|
tax: line.tax,
|
|
31759
32455
|
total: line.total,
|
|
32456
|
+
metadata: line.metadata ?? null,
|
|
31760
32457
|
product: p ? {
|
|
31761
32458
|
name: p.name,
|
|
31762
32459
|
slug: p.slug,
|
|
@@ -31849,12 +32546,17 @@ exports.assertProductApprovalUpdate = assertProductApprovalUpdate;
|
|
|
31849
32546
|
exports.buildBlogMetadataUserPrompt = buildBlogMetadataUserPrompt;
|
|
31850
32547
|
exports.buildCronFromSchedule = buildCronFromSchedule;
|
|
31851
32548
|
exports.buildRssUserPromptFromFeeds = buildRssUserPromptFromFeeds;
|
|
32549
|
+
exports.buildUserInviteLink = buildUserInviteLink;
|
|
31852
32550
|
exports.buildVendorInviteLink = buildVendorInviteLink;
|
|
31853
32551
|
exports.calculateOrderRefundPreview = calculateOrderRefundPreview;
|
|
31854
32552
|
exports.calculateRefundFromPolicy = calculateRefundFromPolicy;
|
|
32553
|
+
exports.checkAndIncrementDiscountUsage = checkAndIncrementDiscountUsage;
|
|
31855
32554
|
exports.checkEventsEnabled = checkEventsEnabled;
|
|
31856
32555
|
exports.checkMultiVendorEnabled = checkMultiVendorEnabled;
|
|
32556
|
+
exports.completeUserInviteAccept = completeUserInviteAccept;
|
|
32557
|
+
exports.consumeAppliedDiscountUsages = consumeAppliedDiscountUsages;
|
|
31857
32558
|
exports.contactIsVendorCustomer = contactIsVendorCustomer;
|
|
32559
|
+
exports.countDiscountOrdersForContact = countDiscountOrdersForContact;
|
|
31858
32560
|
exports.countRecentOtpSends = countRecentOtpSends;
|
|
31859
32561
|
exports.createAnalyticsHandlers = createAnalyticsHandlers;
|
|
31860
32562
|
exports.createBlogBySlugHandler = createBlogBySlugHandler;
|
|
@@ -31886,14 +32588,19 @@ exports.createUserProfileHandler = createUserProfileHandler;
|
|
|
31886
32588
|
exports.createUsersApiHandlers = createUsersApiHandlers;
|
|
31887
32589
|
exports.createVendorDashboardHandler = createVendorDashboardHandler;
|
|
31888
32590
|
exports.createVendorOnboardHandlers = createVendorOnboardHandlers;
|
|
32591
|
+
exports.customerPhoneForEmail = customerPhoneForEmail;
|
|
31889
32592
|
exports.customerPhoneForUser = customerPhoneForUser;
|
|
31890
32593
|
exports.daysBeforeEventStart = daysBeforeEventStart;
|
|
32594
|
+
exports.decrementDiscountUsage = decrementDiscountUsage;
|
|
31891
32595
|
exports.describeEventTierPolicy = describeEventTierPolicy;
|
|
31892
32596
|
exports.ensureCustomerForUser = ensureCustomerForUser;
|
|
32597
|
+
exports.ensureCustomerRecord = ensureCustomerRecord;
|
|
31893
32598
|
exports.ensureMessagingPluginsOnCms = ensureMessagingPluginsOnCms;
|
|
31894
32599
|
exports.ensureScheduleQueueWorker = ensureScheduleQueueWorker;
|
|
31895
32600
|
exports.ensureVendorCustomerForOrderContact = ensureVendorCustomerForOrderContact;
|
|
32601
|
+
exports.ensureVendorCustomersForOrder = ensureVendorCustomersForOrder;
|
|
31896
32602
|
exports.findActiveRefundPolicyForVendor = findActiveRefundPolicyForVendor;
|
|
32603
|
+
exports.findUserByInviteToken = findUserByInviteToken;
|
|
31897
32604
|
exports.findVendorByInviteToken = findVendorByInviteToken;
|
|
31898
32605
|
exports.formatTierRange = formatTierRange;
|
|
31899
32606
|
exports.generateNumericOtp = generateNumericOtp;
|
|
@@ -31910,6 +32617,9 @@ exports.invalidateRequireEventApprovalCache = invalidateRequireEventApprovalCach
|
|
|
31910
32617
|
exports.invalidateRequireProductApprovalCache = invalidateRequireProductApprovalCache;
|
|
31911
32618
|
exports.invalidateVendorCatalogCreateFlagsCache = invalidateVendorCatalogCreateFlagsCache;
|
|
31912
32619
|
exports.isCustomerTypeContact = isCustomerTypeContact;
|
|
32620
|
+
exports.isMaxPerUserUsageReached = isMaxPerUserUsageReached;
|
|
32621
|
+
exports.isMaxTotalUsageReached = isMaxTotalUsageReached;
|
|
32622
|
+
exports.isSyntheticCustomerPhone = isSyntheticCustomerPhone;
|
|
31913
32623
|
exports.isZipMedia = isZipMedia;
|
|
31914
32624
|
exports.linkUnclaimedContactToUser = linkUnclaimedContactToUser;
|
|
31915
32625
|
exports.llmAgentToChatAgentOptions = llmAgentToChatAgentOptions;
|
|
@@ -31921,6 +32631,8 @@ exports.metaFetchUserManagedPages = metaFetchUserManagedPages;
|
|
|
31921
32631
|
exports.metaPostPageFeed = metaPostPageFeed;
|
|
31922
32632
|
exports.metaPostPagePhoto = metaPostPagePhoto;
|
|
31923
32633
|
exports.metaResolvePageAccessToken = metaResolvePageAccessToken;
|
|
32634
|
+
exports.newUserInviteToken = newUserInviteToken;
|
|
32635
|
+
exports.normalizeCustomerPhone = normalizeCustomerPhone;
|
|
31924
32636
|
exports.normalizePhoneE164 = normalizePhoneE164;
|
|
31925
32637
|
exports.normalizeRefundTiers = normalizeRefundTiers;
|
|
31926
32638
|
exports.overlayCmsPlugins = overlayCmsPlugins;
|
|
@@ -31933,6 +32645,7 @@ exports.queueErpCreateContactIfEnabled = queueErpCreateContactIfEnabled;
|
|
|
31933
32645
|
exports.queueJobScheduleNow = queueJobScheduleNow;
|
|
31934
32646
|
exports.queuePlugin = queuePlugin;
|
|
31935
32647
|
exports.queueSms = queueSms;
|
|
32648
|
+
exports.recordDiscountUsage = recordDiscountUsage;
|
|
31936
32649
|
exports.registerJobRunnerWorker = registerJobRunnerWorker;
|
|
31937
32650
|
exports.registerMessagingQueueProcessors = registerMessagingQueueProcessors;
|
|
31938
32651
|
exports.registerSmsQueueProcessor = registerSmsQueueProcessor;
|