@infuro/cms-core 1.0.43 → 1.0.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin.cjs +557 -416
- package/dist/admin.d.cts +1 -1
- package/dist/admin.d.ts +1 -1
- package/dist/admin.js +557 -416
- package/dist/api.cjs +32 -32
- package/dist/api.d.cts +2 -0
- package/dist/api.d.ts +2 -0
- package/dist/api.js +1 -1
- package/dist/{chunk-SCPKMZG5.cjs → chunk-F5XFHYTG.cjs} +924 -290
- package/dist/{chunk-IX7X4ILO.js → chunk-MVXLRANV.js} +921 -292
- package/dist/index.cjs +241 -201
- package/dist/index.d.cts +42 -7
- package/dist/index.d.ts +42 -7
- package/dist/index.js +21 -2
- package/dist/migrations/1781800000000-CustomerPhoneNullable.ts +53 -0
- package/package.json +1 -1
|
@@ -46,6 +46,7 @@ async function queryVendorLinks(dataSource, userId) {
|
|
|
46
46
|
vr."name" AS "vendorRoleName",
|
|
47
47
|
vr."isOwnerRole" AS "isOwnerRole"
|
|
48
48
|
FROM "vendor_users" vu
|
|
49
|
+
INNER JOIN "vendors" v ON v.id = vu."vendorId" AND v.deleted = false
|
|
49
50
|
LEFT JOIN "vendor_roles" vr ON vr.id = vu."vendorRoleId" AND vr.deleted = false
|
|
50
51
|
WHERE vu."userId" = $1
|
|
51
52
|
ORDER BY vu.id ASC
|
|
@@ -55,10 +56,11 @@ async function queryVendorLinks(dataSource, userId) {
|
|
|
55
56
|
} catch (err) {
|
|
56
57
|
if (!isMissingVendorRoleSchemaError(err)) throw err;
|
|
57
58
|
const legacy = await dataSource.query(`
|
|
58
|
-
SELECT "vendorId", "role"
|
|
59
|
-
FROM "vendor_users"
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
SELECT vu."vendorId" AS "vendorId", vu."role" AS "role"
|
|
60
|
+
FROM "vendor_users" vu
|
|
61
|
+
INNER JOIN "vendors" v ON v.id = vu."vendorId" AND v.deleted = false
|
|
62
|
+
WHERE vu."userId" = $1
|
|
63
|
+
ORDER BY vu.id ASC
|
|
62
64
|
`, [
|
|
63
65
|
userId
|
|
64
66
|
]);
|
|
@@ -72,8 +74,36 @@ async function queryVendorLinks(dataSource, userId) {
|
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
76
|
chunkUSNT2KNT_cjs.__name(queryVendorLinks, "queryVendorLinks");
|
|
77
|
+
async function queryOwnedVendorIds(dataSource, userId) {
|
|
78
|
+
try {
|
|
79
|
+
const rows = await dataSource.query(`
|
|
80
|
+
SELECT id
|
|
81
|
+
FROM "vendors"
|
|
82
|
+
WHERE "userId" = $1 AND deleted = false
|
|
83
|
+
ORDER BY id ASC
|
|
84
|
+
`, [
|
|
85
|
+
userId
|
|
86
|
+
]);
|
|
87
|
+
return rows.map((r) => Number(r.id)).filter((id) => Number.isFinite(id) && id > 0);
|
|
88
|
+
} catch {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
chunkUSNT2KNT_cjs.__name(queryOwnedVendorIds, "queryOwnedVendorIds");
|
|
75
93
|
async function loadUserVendorContext(dataSource, userId, preferredVendorId) {
|
|
76
94
|
const rows = await queryVendorLinks(dataSource, userId);
|
|
95
|
+
const linkIds = new Set(rows.map((r) => Number(r.vendorId)));
|
|
96
|
+
for (const ownedId of await queryOwnedVendorIds(dataSource, userId)) {
|
|
97
|
+
if (linkIds.has(ownedId)) continue;
|
|
98
|
+
rows.push({
|
|
99
|
+
vendorId: ownedId,
|
|
100
|
+
role: "owner",
|
|
101
|
+
vendorRoleId: null,
|
|
102
|
+
vendorRoleName: null,
|
|
103
|
+
isOwnerRole: true
|
|
104
|
+
});
|
|
105
|
+
linkIds.add(ownedId);
|
|
106
|
+
}
|
|
77
107
|
const vendorIds = rows.map((r) => Number(r.vendorId));
|
|
78
108
|
const activeRow = preferredVendorId != null ? rows.find((r) => Number(r.vendorId) === preferredVendorId) : void 0;
|
|
79
109
|
const primary = activeRow ?? rows[0];
|
|
@@ -462,6 +492,41 @@ function applyApprovalStatusSideEffects(updatePayload, opts) {
|
|
|
462
492
|
}
|
|
463
493
|
}
|
|
464
494
|
chunkUSNT2KNT_cjs.__name(applyApprovalStatusSideEffects, "applyApprovalStatusSideEffects");
|
|
495
|
+
async function syncProductVariantsStatusWithProduct(dataSource, entityMap, productId, productStatus) {
|
|
496
|
+
if (!entityMap.product_variants || !Number.isFinite(productId) || productId < 1) return;
|
|
497
|
+
const status = String(productStatus || "draft");
|
|
498
|
+
const repo = dataSource.getRepository(entityMap.product_variants);
|
|
499
|
+
if (status === "available") {
|
|
500
|
+
await repo.createQueryBuilder().update().set({
|
|
501
|
+
status: "available"
|
|
502
|
+
}).where('"productId" = :productId', {
|
|
503
|
+
productId
|
|
504
|
+
}).andWhere("status = :from", {
|
|
505
|
+
from: "draft"
|
|
506
|
+
}).execute();
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (status === "draft") {
|
|
510
|
+
await repo.createQueryBuilder().update().set({
|
|
511
|
+
status: "draft"
|
|
512
|
+
}).where('"productId" = :productId', {
|
|
513
|
+
productId
|
|
514
|
+
}).andWhere("status = :from", {
|
|
515
|
+
from: "available"
|
|
516
|
+
}).execute();
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
chunkUSNT2KNT_cjs.__name(syncProductVariantsStatusWithProduct, "syncProductVariantsStatusWithProduct");
|
|
520
|
+
function coerceVariantStatusForProduct(variantStatus, productStatus, opts) {
|
|
521
|
+
const next = String(variantStatus ?? "draft").trim() || "draft";
|
|
522
|
+
const productLive = String(productStatus ?? "draft") === "available";
|
|
523
|
+
const approvalOk = !opts?.requireApproval || String(opts?.approvalStatus ?? "") === "approved";
|
|
524
|
+
if (!productLive || !approvalOk) {
|
|
525
|
+
return "draft";
|
|
526
|
+
}
|
|
527
|
+
return next;
|
|
528
|
+
}
|
|
529
|
+
chunkUSNT2KNT_cjs.__name(coerceVariantStatusForProduct, "coerceVariantStatusForProduct");
|
|
465
530
|
|
|
466
531
|
// src/lib/event-approval.ts
|
|
467
532
|
var EVENT_APPROVAL_STATUSES = [
|
|
@@ -1065,11 +1130,118 @@ function pgErrorCode(err) {
|
|
|
1065
1130
|
return driver?.code ?? err.code;
|
|
1066
1131
|
}
|
|
1067
1132
|
chunkUSNT2KNT_cjs.__name(pgErrorCode, "pgErrorCode");
|
|
1068
|
-
function
|
|
1133
|
+
function normalizeCustomerPhone(phone) {
|
|
1069
1134
|
const p = typeof phone === "string" ? phone.trim() : "";
|
|
1070
|
-
return p ||
|
|
1135
|
+
return p || null;
|
|
1136
|
+
}
|
|
1137
|
+
chunkUSNT2KNT_cjs.__name(normalizeCustomerPhone, "normalizeCustomerPhone");
|
|
1138
|
+
function isSyntheticCustomerPhone(phone) {
|
|
1139
|
+
const p = String(phone ?? "").trim();
|
|
1140
|
+
if (!p) return true;
|
|
1141
|
+
if (p.startsWith("e-") || p.startsWith("u-")) return true;
|
|
1142
|
+
if (p.includes("@")) return true;
|
|
1143
|
+
return false;
|
|
1144
|
+
}
|
|
1145
|
+
chunkUSNT2KNT_cjs.__name(isSyntheticCustomerPhone, "isSyntheticCustomerPhone");
|
|
1146
|
+
function customerPhoneForUser(_userId, phone) {
|
|
1147
|
+
return normalizeCustomerPhone(phone);
|
|
1071
1148
|
}
|
|
1072
1149
|
chunkUSNT2KNT_cjs.__name(customerPhoneForUser, "customerPhoneForUser");
|
|
1150
|
+
function customerPhoneForEmail(_email, phone) {
|
|
1151
|
+
return normalizeCustomerPhone(phone);
|
|
1152
|
+
}
|
|
1153
|
+
chunkUSNT2KNT_cjs.__name(customerPhoneForEmail, "customerPhoneForEmail");
|
|
1154
|
+
function resolveNextPhone(inputPhone, existingPhone) {
|
|
1155
|
+
if (inputPhone) return inputPhone;
|
|
1156
|
+
const existing = normalizeCustomerPhone(existingPhone);
|
|
1157
|
+
if (!existing || isSyntheticCustomerPhone(existing)) return null;
|
|
1158
|
+
return existing;
|
|
1159
|
+
}
|
|
1160
|
+
chunkUSNT2KNT_cjs.__name(resolveNextPhone, "resolveNextPhone");
|
|
1161
|
+
async function ensureCustomerRecord(dsOrEm, customerEntity, input) {
|
|
1162
|
+
const repo = dsOrEm.getRepository(customerEntity);
|
|
1163
|
+
const email = normalizeEmail(input.email);
|
|
1164
|
+
if (!email) return null;
|
|
1165
|
+
const name = String(input.name ?? "").trim() || email.split("@")[0] || "Customer";
|
|
1166
|
+
const userId = input.userId != null && Number.isFinite(Number(input.userId)) && Number(input.userId) > 0 ? Number(input.userId) : null;
|
|
1167
|
+
const phone = normalizeCustomerPhone(input.phone);
|
|
1168
|
+
let row = await repo.findOne({
|
|
1169
|
+
where: {
|
|
1170
|
+
email,
|
|
1171
|
+
deleted: false
|
|
1172
|
+
}
|
|
1173
|
+
});
|
|
1174
|
+
if (!row) {
|
|
1175
|
+
row = await repo.findOne({
|
|
1176
|
+
where: {
|
|
1177
|
+
email
|
|
1178
|
+
}
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
if (row) {
|
|
1182
|
+
const existingUserId = row.userId;
|
|
1183
|
+
if (userId != null && existingUserId != null && existingUserId !== userId) {
|
|
1184
|
+
return null;
|
|
1185
|
+
}
|
|
1186
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
1187
|
+
const patch = {
|
|
1188
|
+
name,
|
|
1189
|
+
phone: nextPhone,
|
|
1190
|
+
deleted: false,
|
|
1191
|
+
deletedAt: null,
|
|
1192
|
+
deletedBy: null,
|
|
1193
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1194
|
+
};
|
|
1195
|
+
if (userId != null && existingUserId == null) {
|
|
1196
|
+
patch.userId = userId;
|
|
1197
|
+
}
|
|
1198
|
+
await repo.update(row.id, patch);
|
|
1199
|
+
return {
|
|
1200
|
+
id: row.id
|
|
1201
|
+
};
|
|
1202
|
+
}
|
|
1203
|
+
try {
|
|
1204
|
+
const created = await repo.save(repo.create({
|
|
1205
|
+
userId,
|
|
1206
|
+
name,
|
|
1207
|
+
email,
|
|
1208
|
+
phone,
|
|
1209
|
+
deleted: false
|
|
1210
|
+
}));
|
|
1211
|
+
return {
|
|
1212
|
+
id: created.id
|
|
1213
|
+
};
|
|
1214
|
+
} catch (err) {
|
|
1215
|
+
const code = pgErrorCode(err);
|
|
1216
|
+
if (code === "25P02") throw err;
|
|
1217
|
+
row = await repo.findOne({
|
|
1218
|
+
where: {
|
|
1219
|
+
email
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1222
|
+
if (row) {
|
|
1223
|
+
const existingUserId = row.userId;
|
|
1224
|
+
if (userId != null && existingUserId != null && existingUserId !== userId) return null;
|
|
1225
|
+
await repo.update(row.id, {
|
|
1226
|
+
name,
|
|
1227
|
+
phone: resolveNextPhone(phone, row.phone),
|
|
1228
|
+
...userId != null && existingUserId == null ? {
|
|
1229
|
+
userId
|
|
1230
|
+
} : {},
|
|
1231
|
+
deleted: false,
|
|
1232
|
+
deletedAt: null,
|
|
1233
|
+
deletedBy: null,
|
|
1234
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1235
|
+
});
|
|
1236
|
+
return {
|
|
1237
|
+
id: row.id
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
if (code === "23505") return null;
|
|
1241
|
+
throw err;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
chunkUSNT2KNT_cjs.__name(ensureCustomerRecord, "ensureCustomerRecord");
|
|
1073
1245
|
async function restoreCustomerRow(repo, row, user, name, email, phone) {
|
|
1074
1246
|
const id = row.id;
|
|
1075
1247
|
await repo.update(id, {
|
|
@@ -1091,7 +1263,7 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1091
1263
|
const repo = dsOrEm.getRepository(customerEntity);
|
|
1092
1264
|
const email = normalizeEmail(user.email);
|
|
1093
1265
|
const name = String(user.name ?? "").trim() || email.split("@")[0] || "User";
|
|
1094
|
-
const phone =
|
|
1266
|
+
const phone = normalizeCustomerPhone(overrides?.phone ?? user.phone);
|
|
1095
1267
|
let row = await repo.findOne({
|
|
1096
1268
|
where: {
|
|
1097
1269
|
userId: user.id,
|
|
@@ -1099,10 +1271,11 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1099
1271
|
}
|
|
1100
1272
|
});
|
|
1101
1273
|
if (row) {
|
|
1274
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
1102
1275
|
await repo.update(row.id, {
|
|
1103
1276
|
name,
|
|
1104
1277
|
email,
|
|
1105
|
-
phone,
|
|
1278
|
+
phone: nextPhone,
|
|
1106
1279
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1107
1280
|
});
|
|
1108
1281
|
return {
|
|
@@ -1120,10 +1293,11 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1120
1293
|
if (existingUserId != null && existingUserId !== user.id) {
|
|
1121
1294
|
return null;
|
|
1122
1295
|
}
|
|
1296
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
1123
1297
|
await repo.update(row.id, {
|
|
1124
1298
|
userId: user.id,
|
|
1125
1299
|
name,
|
|
1126
|
-
phone,
|
|
1300
|
+
phone: nextPhone,
|
|
1127
1301
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1128
1302
|
});
|
|
1129
1303
|
return {
|
|
@@ -1138,21 +1312,23 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1138
1312
|
if (deletedByEmail) {
|
|
1139
1313
|
const existingUserId = deletedByEmail.userId;
|
|
1140
1314
|
if (existingUserId != null && existingUserId !== user.id) return null;
|
|
1141
|
-
return restoreCustomerRow(repo, deletedByEmail, user, name, email, phone);
|
|
1315
|
+
return restoreCustomerRow(repo, deletedByEmail, user, name, email, resolveNextPhone(phone, deletedByEmail.phone));
|
|
1142
1316
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1317
|
+
if (phone) {
|
|
1318
|
+
const deletedByPhone = await repo.findOne({
|
|
1319
|
+
where: {
|
|
1320
|
+
phone
|
|
1321
|
+
}
|
|
1322
|
+
});
|
|
1323
|
+
if (deletedByPhone) {
|
|
1324
|
+
const existingUserId = deletedByPhone.userId;
|
|
1325
|
+
if (existingUserId != null && existingUserId !== user.id) {
|
|
1326
|
+
return ensureCustomerForUser(dsOrEm, customerEntity, user, {
|
|
1327
|
+
phone: null
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
return restoreCustomerRow(repo, deletedByPhone, user, name, email, phone);
|
|
1154
1331
|
}
|
|
1155
|
-
return restoreCustomerRow(repo, deletedByPhone, user, name, email, phone);
|
|
1156
1332
|
}
|
|
1157
1333
|
try {
|
|
1158
1334
|
const created = await repo.save(repo.create({
|
|
@@ -1173,34 +1349,22 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1173
1349
|
userId: user.id
|
|
1174
1350
|
}
|
|
1175
1351
|
});
|
|
1176
|
-
if (row)
|
|
1352
|
+
if (row) {
|
|
1353
|
+
return restoreCustomerRow(repo, row, user, name, email, resolveNextPhone(phone, row.phone));
|
|
1354
|
+
}
|
|
1177
1355
|
row = await repo.findOne({
|
|
1178
1356
|
where: {
|
|
1179
1357
|
email
|
|
1180
1358
|
}
|
|
1181
1359
|
});
|
|
1182
1360
|
if (row && (row.userId ?? user.id) === user.id) {
|
|
1183
|
-
return restoreCustomerRow(repo, row, user, name, email, phone);
|
|
1361
|
+
return restoreCustomerRow(repo, row, user, name, email, resolveNextPhone(phone, row.phone));
|
|
1184
1362
|
}
|
|
1185
1363
|
if (code === "23505") return null;
|
|
1186
1364
|
throw err;
|
|
1187
1365
|
}
|
|
1188
1366
|
}
|
|
1189
1367
|
chunkUSNT2KNT_cjs.__name(ensureCustomerForUser, "ensureCustomerForUser");
|
|
1190
|
-
async function linkUnclaimedContactToUser(dataSource, contactsEntity, userId, email) {
|
|
1191
|
-
const repo = dataSource.getRepository(contactsEntity);
|
|
1192
|
-
const found = await repo.findOne({
|
|
1193
|
-
where: {
|
|
1194
|
-
email,
|
|
1195
|
-
userId: typeorm.IsNull(),
|
|
1196
|
-
deleted: false
|
|
1197
|
-
}
|
|
1198
|
-
});
|
|
1199
|
-
if (found) await repo.update(found.id, {
|
|
1200
|
-
userId
|
|
1201
|
-
});
|
|
1202
|
-
}
|
|
1203
|
-
chunkUSNT2KNT_cjs.__name(linkUnclaimedContactToUser, "linkUnclaimedContactToUser");
|
|
1204
1368
|
|
|
1205
1369
|
// src/lib/vendor-customer-contacts.ts
|
|
1206
1370
|
function isCustomerTypeContact(type) {
|
|
@@ -1293,8 +1457,27 @@ function resolveVendorIdForContactCheck(scope, bodyOrRow) {
|
|
|
1293
1457
|
return Number.isFinite(n) ? n : null;
|
|
1294
1458
|
}
|
|
1295
1459
|
chunkUSNT2KNT_cjs.__name(resolveVendorIdForContactCheck, "resolveVendorIdForContactCheck");
|
|
1460
|
+
function uniquePositiveIds(ids) {
|
|
1461
|
+
const out = [];
|
|
1462
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1463
|
+
for (const raw of ids) {
|
|
1464
|
+
const n = Number(raw);
|
|
1465
|
+
if (!Number.isFinite(n) || n <= 0 || seen.has(n)) continue;
|
|
1466
|
+
seen.add(n);
|
|
1467
|
+
out.push(n);
|
|
1468
|
+
}
|
|
1469
|
+
return out;
|
|
1470
|
+
}
|
|
1471
|
+
chunkUSNT2KNT_cjs.__name(uniquePositiveIds, "uniquePositiveIds");
|
|
1296
1472
|
async function ensureVendorCustomerForOrderContact(dataSource, entityMap, vendorId, contactId, details) {
|
|
1297
|
-
|
|
1473
|
+
await ensureVendorCustomersForOrder(dataSource, entityMap, [
|
|
1474
|
+
vendorId
|
|
1475
|
+
], contactId, details);
|
|
1476
|
+
}
|
|
1477
|
+
chunkUSNT2KNT_cjs.__name(ensureVendorCustomerForOrderContact, "ensureVendorCustomerForOrderContact");
|
|
1478
|
+
async function ensureVendorCustomersForOrder(dataSource, entityMap, vendorIds, contactId, details) {
|
|
1479
|
+
const vendors = uniquePositiveIds(vendorIds);
|
|
1480
|
+
if (vendors.length === 0 || !Number.isFinite(contactId) || contactId <= 0) return;
|
|
1298
1481
|
const vcEntity = entityMap.vendor_customers;
|
|
1299
1482
|
const contactEntity = entityMap.contacts;
|
|
1300
1483
|
if (!vcEntity || !contactEntity) return;
|
|
@@ -1320,96 +1503,61 @@ async function ensureVendorCustomerForOrderContact(dataSource, entityMap, vendor
|
|
|
1320
1503
|
}
|
|
1321
1504
|
let customerId = null;
|
|
1322
1505
|
if (entityMap.customer) {
|
|
1323
|
-
const
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
}
|
|
1506
|
+
const ensured = await ensureCustomerRecord(dataSource, entityMap.customer, {
|
|
1507
|
+
name,
|
|
1508
|
+
email,
|
|
1509
|
+
phone,
|
|
1510
|
+
userId: null
|
|
1329
1511
|
});
|
|
1330
|
-
if (
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1512
|
+
if (ensured) customerId = ensured.id;
|
|
1513
|
+
}
|
|
1514
|
+
for (const vendorId of vendors) {
|
|
1515
|
+
if (customerId != null) {
|
|
1516
|
+
const byCustomer = await vcRepo.findOne({
|
|
1335
1517
|
where: {
|
|
1336
|
-
|
|
1337
|
-
|
|
1518
|
+
vendorId,
|
|
1519
|
+
customerId
|
|
1338
1520
|
}
|
|
1339
1521
|
});
|
|
1340
|
-
if (
|
|
1341
|
-
|
|
1342
|
-
if (
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
where: {
|
|
1346
|
-
name: "Customer",
|
|
1347
|
-
deleted: false
|
|
1348
|
-
}
|
|
1522
|
+
if (byCustomer) {
|
|
1523
|
+
const existingContactId = byCustomer.contactId;
|
|
1524
|
+
if (existingContactId == null) {
|
|
1525
|
+
await vcRepo.update(byCustomer.id, {
|
|
1526
|
+
contactId
|
|
1349
1527
|
});
|
|
1350
|
-
if (customerGroup) groupId = Number(customerGroup.id);
|
|
1351
1528
|
}
|
|
1352
|
-
|
|
1353
|
-
name,
|
|
1354
|
-
email,
|
|
1355
|
-
phone,
|
|
1356
|
-
password: null,
|
|
1357
|
-
blocked: false,
|
|
1358
|
-
groupId,
|
|
1359
|
-
adminAccess: false
|
|
1360
|
-
}));
|
|
1529
|
+
continue;
|
|
1361
1530
|
}
|
|
1362
|
-
const userId = Number(user.id);
|
|
1363
|
-
await linkUnclaimedContactToUser(dataSource, contactEntity, userId, email);
|
|
1364
|
-
const ensured = await ensureCustomerForUser(dataSource, entityMap.customer, {
|
|
1365
|
-
id: userId,
|
|
1366
|
-
name,
|
|
1367
|
-
email,
|
|
1368
|
-
phone
|
|
1369
|
-
}, {
|
|
1370
|
-
phone
|
|
1371
|
-
});
|
|
1372
|
-
if (ensured) customerId = ensured.id;
|
|
1373
1531
|
}
|
|
1374
|
-
|
|
1375
|
-
if (customerId != null) {
|
|
1376
|
-
const byCustomer = await vcRepo.findOne({
|
|
1532
|
+
const byContact = await vcRepo.findOne({
|
|
1377
1533
|
where: {
|
|
1378
1534
|
vendorId,
|
|
1379
|
-
|
|
1535
|
+
contactId
|
|
1380
1536
|
}
|
|
1381
1537
|
});
|
|
1382
|
-
if (
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
contactId
|
|
1538
|
+
if (byContact) {
|
|
1539
|
+
if (customerId != null && byContact.customerId == null) {
|
|
1540
|
+
await vcRepo.update(byContact.id, {
|
|
1541
|
+
customerId
|
|
1387
1542
|
});
|
|
1388
1543
|
}
|
|
1389
|
-
|
|
1544
|
+
continue;
|
|
1390
1545
|
}
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1546
|
+
if (customerId != null) {
|
|
1547
|
+
await vcRepo.save(vcRepo.create({
|
|
1548
|
+
vendorId,
|
|
1549
|
+
customerId,
|
|
1550
|
+
contactId
|
|
1551
|
+
}));
|
|
1552
|
+
} else {
|
|
1553
|
+
await vcRepo.save(vcRepo.create({
|
|
1554
|
+
vendorId,
|
|
1555
|
+
contactId
|
|
1556
|
+
}));
|
|
1396
1557
|
}
|
|
1397
|
-
});
|
|
1398
|
-
if (byContact) return;
|
|
1399
|
-
if (customerId != null) {
|
|
1400
|
-
await vcRepo.save(vcRepo.create({
|
|
1401
|
-
vendorId,
|
|
1402
|
-
customerId,
|
|
1403
|
-
contactId
|
|
1404
|
-
}));
|
|
1405
|
-
return;
|
|
1406
1558
|
}
|
|
1407
|
-
await vcRepo.save(vcRepo.create({
|
|
1408
|
-
vendorId,
|
|
1409
|
-
contactId
|
|
1410
|
-
}));
|
|
1411
1559
|
}
|
|
1412
|
-
chunkUSNT2KNT_cjs.__name(
|
|
1560
|
+
chunkUSNT2KNT_cjs.__name(ensureVendorCustomersForOrder, "ensureVendorCustomersForOrder");
|
|
1413
1561
|
|
|
1414
1562
|
// src/lib/currency-prices.ts
|
|
1415
1563
|
function normalizeCurrencyCode(code) {
|
|
@@ -3775,23 +3923,24 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
3775
3923
|
if (resource === "vendor_customers" && entityMap["customer"]) {
|
|
3776
3924
|
const scope = await resolveVendorCustomersScope(dataSource, entityMap, resolveScope);
|
|
3777
3925
|
const repo2 = dataSource.getRepository(entity);
|
|
3778
|
-
const qb = repo2.createQueryBuilder("vc").leftJoinAndSelect("vc.customer", "customer").leftJoinAndSelect("customer.user", "user").orderBy("vc.createdAt", sortOrder === "DESC" ? "DESC" : "ASC").skip(skip).take(limit);
|
|
3926
|
+
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);
|
|
3779
3927
|
applyVendorScopeToQueryBuilder(qb, "vc", scope);
|
|
3780
3928
|
if (search && typeof search === "string" && search.trim()) {
|
|
3781
3929
|
const term = `%${search.trim()}%`;
|
|
3782
|
-
qb.andWhere("(customer.name ILIKE :term OR customer.email ILIKE :term OR customer.phone ILIKE :term)", {
|
|
3930
|
+
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)", {
|
|
3783
3931
|
term
|
|
3784
3932
|
});
|
|
3785
3933
|
}
|
|
3786
3934
|
const [rows, total2] = await qb.getManyAndCount();
|
|
3787
3935
|
const data2 = rows.map((row) => {
|
|
3788
3936
|
const customer = row.customer;
|
|
3937
|
+
const contact = row.contact;
|
|
3789
3938
|
return {
|
|
3790
3939
|
...row,
|
|
3791
|
-
name: customer?.name ?? null,
|
|
3792
|
-
email: customer?.email ?? null,
|
|
3793
|
-
phone: customer?.phone ?? null,
|
|
3794
|
-
company: customer?.company ?? null
|
|
3940
|
+
name: customer?.name ?? contact?.name ?? null,
|
|
3941
|
+
email: customer?.email ?? contact?.email ?? null,
|
|
3942
|
+
phone: customer?.phone ?? contact?.phone ?? null,
|
|
3943
|
+
company: customer?.company ?? contact?.company ?? null
|
|
3795
3944
|
};
|
|
3796
3945
|
});
|
|
3797
3946
|
return json({
|
|
@@ -4125,7 +4274,11 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4125
4274
|
} else if (resource === "collections") {
|
|
4126
4275
|
if (scope.type === "vendor") {
|
|
4127
4276
|
where = mergeVendorScopeIntoWhere(where, scope, resource, catalogFlags);
|
|
4128
|
-
} else if (searchParams.get("isCatalog")
|
|
4277
|
+
} else if (searchParams.get("isCatalog") === "true") {
|
|
4278
|
+
where = mergeListWhereAnd(where, {
|
|
4279
|
+
isCatalog: true
|
|
4280
|
+
});
|
|
4281
|
+
} else if (searchParams.get("isCatalog") === "false") {
|
|
4129
4282
|
where = mergeListWhereAnd(where, {
|
|
4130
4283
|
isCatalog: false
|
|
4131
4284
|
});
|
|
@@ -4322,41 +4475,17 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4322
4475
|
status: 503
|
|
4323
4476
|
});
|
|
4324
4477
|
}
|
|
4325
|
-
if (!entityMap["
|
|
4326
|
-
return json({
|
|
4327
|
-
error: "Users entity not configured"
|
|
4328
|
-
}, {
|
|
4329
|
-
status: 503
|
|
4330
|
-
});
|
|
4331
|
-
}
|
|
4332
|
-
let customerGroupId = null;
|
|
4333
|
-
if (entityMap["user_groups"]) {
|
|
4334
|
-
const userGroupRepo = dataSource.getRepository(entityMap["user_groups"]);
|
|
4335
|
-
const customerGroup = await userGroupRepo.findOne({
|
|
4336
|
-
where: {
|
|
4337
|
-
name: "Customer",
|
|
4338
|
-
deleted: false
|
|
4339
|
-
}
|
|
4340
|
-
});
|
|
4341
|
-
if (!customerGroup) {
|
|
4342
|
-
return json({
|
|
4343
|
-
error: "User group 'customer' not found"
|
|
4344
|
-
}, {
|
|
4345
|
-
status: 500
|
|
4346
|
-
});
|
|
4347
|
-
}
|
|
4348
|
-
customerGroupId = Number(customerGroup.id);
|
|
4349
|
-
} else {
|
|
4478
|
+
if (!entityMap["contacts"]) {
|
|
4350
4479
|
return json({
|
|
4351
|
-
error: "
|
|
4480
|
+
error: "Contacts entity not configured"
|
|
4352
4481
|
}, {
|
|
4353
4482
|
status: 503
|
|
4354
4483
|
});
|
|
4355
4484
|
}
|
|
4356
4485
|
const name = String(body.name ?? "").trim();
|
|
4357
|
-
const email = String(body.email ?? "").trim();
|
|
4358
|
-
const
|
|
4359
|
-
const
|
|
4486
|
+
const email = String(body.email ?? "").trim().toLowerCase();
|
|
4487
|
+
const phoneRaw = String(body.phone ?? "").trim();
|
|
4488
|
+
const phone = phoneRaw || null;
|
|
4360
4489
|
if (!name) return json({
|
|
4361
4490
|
error: "name is required"
|
|
4362
4491
|
}, {
|
|
@@ -4367,25 +4496,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4367
4496
|
}, {
|
|
4368
4497
|
status: 400
|
|
4369
4498
|
});
|
|
4370
|
-
if (!phone) return json({
|
|
4371
|
-
error: "phone is required"
|
|
4372
|
-
}, {
|
|
4373
|
-
status: 400
|
|
4374
|
-
});
|
|
4375
|
-
if (!rawPw) return json({
|
|
4376
|
-
error: "password is required"
|
|
4377
|
-
}, {
|
|
4378
|
-
status: 400
|
|
4379
|
-
});
|
|
4380
|
-
if (rawPw.length < 6) {
|
|
4381
|
-
return json({
|
|
4382
|
-
error: "Password must be at least 6 characters"
|
|
4383
|
-
}, {
|
|
4384
|
-
status: 400
|
|
4385
|
-
});
|
|
4386
|
-
}
|
|
4387
4499
|
const customerRepo = dataSource.getRepository(entityMap["customer"]);
|
|
4388
|
-
const userRepo = dataSource.getRepository(entityMap["users"]);
|
|
4389
4500
|
const dupCustEmail = await customerRepo.findOne({
|
|
4390
4501
|
where: {
|
|
4391
4502
|
email,
|
|
@@ -4399,49 +4510,26 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4399
4510
|
status: 409
|
|
4400
4511
|
});
|
|
4401
4512
|
}
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
if (dupCustPhone) {
|
|
4409
|
-
return json({
|
|
4410
|
-
error: "A customer with this phone number already exists"
|
|
4411
|
-
}, {
|
|
4412
|
-
status: 409
|
|
4513
|
+
if (phone) {
|
|
4514
|
+
const dupCustPhone = await customerRepo.findOne({
|
|
4515
|
+
where: {
|
|
4516
|
+
phone,
|
|
4517
|
+
deleted: false
|
|
4518
|
+
}
|
|
4413
4519
|
});
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4520
|
+
if (dupCustPhone) {
|
|
4521
|
+
return json({
|
|
4522
|
+
error: "A customer with this phone number already exists"
|
|
4523
|
+
}, {
|
|
4524
|
+
status: 409
|
|
4525
|
+
});
|
|
4420
4526
|
}
|
|
4421
|
-
});
|
|
4422
|
-
if (dupUser) {
|
|
4423
|
-
userId = Number(dupUser.id);
|
|
4424
|
-
} else {
|
|
4425
|
-
const bcrypt = await import('bcryptjs');
|
|
4426
|
-
const hashedPassword = await bcrypt.hash(rawPw, 10);
|
|
4427
|
-
const savedUser = await userRepo.save(userRepo.create({
|
|
4428
|
-
name,
|
|
4429
|
-
email,
|
|
4430
|
-
phone,
|
|
4431
|
-
password: hashedPassword,
|
|
4432
|
-
groupId: customerGroupId,
|
|
4433
|
-
adminAccess: false,
|
|
4434
|
-
blocked: false
|
|
4435
|
-
}));
|
|
4436
|
-
userId = Number(savedUser.id);
|
|
4437
4527
|
}
|
|
4438
|
-
const savedCustomer = await
|
|
4439
|
-
id: userId,
|
|
4528
|
+
const savedCustomer = await ensureCustomerRecord(dataSource, entityMap["customer"], {
|
|
4440
4529
|
name,
|
|
4441
4530
|
email,
|
|
4442
|
-
phone
|
|
4443
|
-
|
|
4444
|
-
phone
|
|
4531
|
+
phone,
|
|
4532
|
+
userId: null
|
|
4445
4533
|
});
|
|
4446
4534
|
if (!savedCustomer) {
|
|
4447
4535
|
return json({
|
|
@@ -4450,37 +4538,37 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4450
4538
|
status: 409
|
|
4451
4539
|
});
|
|
4452
4540
|
}
|
|
4453
|
-
const
|
|
4454
|
-
|
|
4541
|
+
const contactRepo = dataSource.getRepository(entityMap["contacts"]);
|
|
4542
|
+
let contact = await contactRepo.findOne({
|
|
4455
4543
|
where: {
|
|
4456
|
-
|
|
4544
|
+
email,
|
|
4457
4545
|
deleted: false
|
|
4458
4546
|
}
|
|
4459
|
-
})
|
|
4460
|
-
if (
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
}
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
}
|
|
4547
|
+
});
|
|
4548
|
+
if (!contact) {
|
|
4549
|
+
contact = await contactRepo.save(contactRepo.create({
|
|
4550
|
+
name,
|
|
4551
|
+
email,
|
|
4552
|
+
phone: phone || null,
|
|
4553
|
+
type: "customer"
|
|
4554
|
+
}));
|
|
4555
|
+
} else {
|
|
4556
|
+
const t = contact.type;
|
|
4557
|
+
const patch = {
|
|
4558
|
+
name,
|
|
4559
|
+
phone: phone || contact.phone || null
|
|
4560
|
+
};
|
|
4561
|
+
if (t == null || t === "" || String(t).toLowerCase() !== "customer") {
|
|
4562
|
+
patch.type = "customer";
|
|
4563
|
+
}
|
|
4564
|
+
await contactRepo.update(contact.id, patch);
|
|
4565
|
+
contact = {
|
|
4566
|
+
...contact,
|
|
4567
|
+
...patch,
|
|
4568
|
+
id: contact.id
|
|
4569
|
+
};
|
|
4483
4570
|
}
|
|
4571
|
+
const contactId = Number(contact.id);
|
|
4484
4572
|
const scope = await resolveVendorCustomersScope(dataSource, entityMap, resolveScope);
|
|
4485
4573
|
let vendorId = null;
|
|
4486
4574
|
if (scope.type === "vendor") {
|
|
@@ -4496,19 +4584,25 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4496
4584
|
status: 400
|
|
4497
4585
|
});
|
|
4498
4586
|
}
|
|
4499
|
-
|
|
4500
|
-
|
|
4587
|
+
await ensureVendorCustomersForOrder(dataSource, entityMap, [
|
|
4588
|
+
vendorId
|
|
4589
|
+
], contactId, {
|
|
4590
|
+
name,
|
|
4591
|
+
email,
|
|
4592
|
+
phone
|
|
4593
|
+
});
|
|
4594
|
+
const customerRow = await customerRepo.findOne({
|
|
4501
4595
|
where: {
|
|
4502
|
-
|
|
4596
|
+
id: savedCustomer.id,
|
|
4597
|
+
deleted: false
|
|
4503
4598
|
}
|
|
4504
4599
|
});
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
}
|
|
4511
|
-
return json(customerRow, {
|
|
4600
|
+
return json(customerRow ?? {
|
|
4601
|
+
id: savedCustomer.id,
|
|
4602
|
+
name,
|
|
4603
|
+
email,
|
|
4604
|
+
phone
|
|
4605
|
+
}, {
|
|
4512
4606
|
status: 201
|
|
4513
4607
|
});
|
|
4514
4608
|
}
|
|
@@ -4604,6 +4698,26 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4604
4698
|
}
|
|
4605
4699
|
}
|
|
4606
4700
|
}
|
|
4701
|
+
if (resource === "product_variants" && entityMap.products) {
|
|
4702
|
+
const productIdRaw = persistBody.productId;
|
|
4703
|
+
const productId = typeof productIdRaw === "number" ? productIdRaw : typeof productIdRaw === "string" && /^\d+$/.test(productIdRaw) ? parseInt(productIdRaw, 10) : NaN;
|
|
4704
|
+
if (Number.isFinite(productId)) {
|
|
4705
|
+
const parent = await dataSource.getRepository(entityMap.products).findOne({
|
|
4706
|
+
where: {
|
|
4707
|
+
id: productId
|
|
4708
|
+
}
|
|
4709
|
+
});
|
|
4710
|
+
const parentStatus = parent?.status;
|
|
4711
|
+
const parentApproval = parent?.approvalStatus;
|
|
4712
|
+
const requireApproval = await getRequireProductApproval(dataSource);
|
|
4713
|
+
persistBody.status = coerceVariantStatusForProduct(persistBody.status, parentStatus, {
|
|
4714
|
+
approvalStatus: parentApproval,
|
|
4715
|
+
requireApproval
|
|
4716
|
+
});
|
|
4717
|
+
} else if (!("status" in persistBody)) {
|
|
4718
|
+
persistBody.status = "draft";
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4607
4721
|
if (resource === "products") {
|
|
4608
4722
|
const scopeForProduct = await resolveScope();
|
|
4609
4723
|
const productFlags = await getVendorCatalogCreateFlags(dataSource);
|
|
@@ -4936,6 +5050,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4936
5050
|
}
|
|
4937
5051
|
const nameRaw = String(body["contact.name"] ?? contact.name ?? "").trim();
|
|
4938
5052
|
const phoneRaw = body["contact.phone"] ?? contact.phone;
|
|
5053
|
+
const emailForVc = (emailRaw || String(contact.email ?? "")).trim().toLowerCase();
|
|
4939
5054
|
const phoneToSave = phoneRaw == null || phoneRaw === "" ? null : String(phoneRaw).trim();
|
|
4940
5055
|
if (phoneToSave && contact.phone !== phoneToSave) {
|
|
4941
5056
|
await contactRepo.update(contact.id, {
|
|
@@ -4944,21 +5059,45 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4944
5059
|
contact.phone = phoneToSave;
|
|
4945
5060
|
}
|
|
4946
5061
|
const vendorIdForCustomer = resolveVendorIdForContactCheck(scopeCreate, persistBody);
|
|
4947
|
-
const
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
5062
|
+
const orderLinesForVendors = normalizeOrderLinesInput(body.orderLines);
|
|
5063
|
+
const vendorIdsForVc = [];
|
|
5064
|
+
if (vendorIdForCustomer != null) vendorIdsForVc.push(vendorIdForCustomer);
|
|
5065
|
+
if (orderLinesForVendors?.length && entityMap.products) {
|
|
5066
|
+
const productRepoForVc = dataSource.getRepository(entityMap.products);
|
|
5067
|
+
for (const line of orderLinesForVendors) {
|
|
5068
|
+
const pid = Number(line.productId);
|
|
5069
|
+
if (!Number.isFinite(pid)) continue;
|
|
5070
|
+
const product = await productRepoForVc.findOne({
|
|
5071
|
+
where: {
|
|
5072
|
+
id: pid
|
|
5073
|
+
}
|
|
5074
|
+
});
|
|
5075
|
+
const pVid = Number(product?.vendorId);
|
|
5076
|
+
if (Number.isFinite(pVid) && pVid > 0) vendorIdsForVc.push(pVid);
|
|
5077
|
+
}
|
|
5078
|
+
}
|
|
5079
|
+
if (vendorIdsForVc.length > 0 && emailForVc) {
|
|
5080
|
+
await ensureVendorCustomersForOrder(dataSource, entityMap, vendorIdsForVc, contact.id, {
|
|
5081
|
+
name: nameRaw || emailForVc.split("@")[0] || "Customer",
|
|
5082
|
+
email: emailForVc,
|
|
4952
5083
|
phone: phoneRaw == null || phoneRaw === "" ? null : String(phoneRaw)
|
|
4953
5084
|
});
|
|
4954
|
-
}
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
5085
|
+
}
|
|
5086
|
+
const accountCustomerId = Number(body.accountCustomerId);
|
|
5087
|
+
if (entityMap.customer_contacts && Number.isFinite(accountCustomerId) && accountCustomerId > 0) {
|
|
5088
|
+
const ccRepo = dataSource.getRepository(entityMap.customer_contacts);
|
|
5089
|
+
const orderContactId = contact.id;
|
|
5090
|
+
const existingLink = await ccRepo.findOne({
|
|
5091
|
+
where: {
|
|
5092
|
+
customerId: accountCustomerId,
|
|
5093
|
+
contactId: orderContactId
|
|
5094
|
+
}
|
|
5095
|
+
});
|
|
5096
|
+
if (!existingLink) {
|
|
5097
|
+
await ccRepo.save(ccRepo.create({
|
|
5098
|
+
customerId: accountCustomerId,
|
|
5099
|
+
contactId: orderContactId
|
|
5100
|
+
}));
|
|
4962
5101
|
}
|
|
4963
5102
|
}
|
|
4964
5103
|
const randomPart = Math.floor(1e4 + Math.random() * 9e4);
|
|
@@ -6243,6 +6382,34 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6243
6382
|
delete u.parentId;
|
|
6244
6383
|
}
|
|
6245
6384
|
}
|
|
6385
|
+
if (resource === "product_variants" && entityMap.products) {
|
|
6386
|
+
const currentVariant = await repo.findOne({
|
|
6387
|
+
where: {
|
|
6388
|
+
id: numericId
|
|
6389
|
+
}
|
|
6390
|
+
});
|
|
6391
|
+
if (!currentVariant) return json({
|
|
6392
|
+
message: "Not found"
|
|
6393
|
+
}, {
|
|
6394
|
+
status: 404
|
|
6395
|
+
});
|
|
6396
|
+
const productId = "productId" in updatePayload && updatePayload.productId != null ? Number(updatePayload.productId) : Number(currentVariant.productId);
|
|
6397
|
+
if (Number.isFinite(productId)) {
|
|
6398
|
+
const parent = await dataSource.getRepository(entityMap.products).findOne({
|
|
6399
|
+
where: {
|
|
6400
|
+
id: productId
|
|
6401
|
+
}
|
|
6402
|
+
});
|
|
6403
|
+
const parentStatus = parent?.status;
|
|
6404
|
+
const parentApproval = parent?.approvalStatus;
|
|
6405
|
+
const requireApproval = await getRequireProductApproval(dataSource);
|
|
6406
|
+
const nextStatus = "status" in updatePayload ? updatePayload.status : currentVariant.status;
|
|
6407
|
+
updatePayload.status = coerceVariantStatusForProduct(nextStatus, parentStatus, {
|
|
6408
|
+
approvalStatus: parentApproval,
|
|
6409
|
+
requireApproval
|
|
6410
|
+
});
|
|
6411
|
+
}
|
|
6412
|
+
}
|
|
6246
6413
|
if (resource === "products") {
|
|
6247
6414
|
const currentRow = await repo.findOne({
|
|
6248
6415
|
where: {
|
|
@@ -6598,6 +6765,10 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6598
6765
|
if (reloaded) updated = reloaded;
|
|
6599
6766
|
}
|
|
6600
6767
|
updated = hydrateProductDisplayName(updated);
|
|
6768
|
+
const productStatus = String(updated.status ?? "draft");
|
|
6769
|
+
if (Number.isFinite(updatedId) && updatedId > 0) {
|
|
6770
|
+
await syncProductVariantsStatusWithProduct(dataSource, entityMap, updatedId, productStatus);
|
|
6771
|
+
}
|
|
6601
6772
|
if (getCms) {
|
|
6602
6773
|
const cms = await getCms();
|
|
6603
6774
|
await queueErpProductUpsertIfEnabled(cms, dataSource, entityMap, updated);
|
|
@@ -6706,6 +6877,14 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6706
6877
|
}
|
|
6707
6878
|
}
|
|
6708
6879
|
await repo.update(numericId, buildSoftDeletePayload(repo.metadata, deletedBy));
|
|
6880
|
+
if ((resource === "forms" || resource === "vendors") && existing && typeof existing.slug === "string") {
|
|
6881
|
+
const slug = String(existing.slug).trim();
|
|
6882
|
+
if (slug && !slug.includes("__deleted_")) {
|
|
6883
|
+
await repo.update(numericId, {
|
|
6884
|
+
slug: `${slug}__deleted_${numericId}`
|
|
6885
|
+
});
|
|
6886
|
+
}
|
|
6887
|
+
}
|
|
6709
6888
|
return json({
|
|
6710
6889
|
message: "Deleted successfully"
|
|
6711
6890
|
}, {
|
|
@@ -6735,7 +6914,21 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6735
6914
|
}
|
|
6736
6915
|
};
|
|
6737
6916
|
}
|
|
6738
|
-
chunkUSNT2KNT_cjs.__name(createCrudByIdHandler, "createCrudByIdHandler");
|
|
6917
|
+
chunkUSNT2KNT_cjs.__name(createCrudByIdHandler, "createCrudByIdHandler");
|
|
6918
|
+
async function linkUnclaimedContactToUser(dataSource, contactsEntity, userId, email) {
|
|
6919
|
+
const repo = dataSource.getRepository(contactsEntity);
|
|
6920
|
+
const found = await repo.findOne({
|
|
6921
|
+
where: {
|
|
6922
|
+
email,
|
|
6923
|
+
userId: typeorm.IsNull(),
|
|
6924
|
+
deleted: false
|
|
6925
|
+
}
|
|
6926
|
+
});
|
|
6927
|
+
if (found) await repo.update(found.id, {
|
|
6928
|
+
userId
|
|
6929
|
+
});
|
|
6930
|
+
}
|
|
6931
|
+
chunkUSNT2KNT_cjs.__name(linkUnclaimedContactToUser, "linkUnclaimedContactToUser");
|
|
6739
6932
|
var VENDOR_INVITE_METADATA_TOKEN = "inviteToken";
|
|
6740
6933
|
var VENDOR_INVITE_METADATA_EXPIRES = "inviteExpiresAt";
|
|
6741
6934
|
var VENDOR_INVITE_METADATA_SENT = "inviteSentAt";
|
|
@@ -7468,6 +7661,50 @@ async function findLlmAgentByScope(dataSource, entityMap, scope, options = {}) {
|
|
|
7468
7661
|
}
|
|
7469
7662
|
chunkUSNT2KNT_cjs.__name(findLlmAgentByScope, "findLlmAgentByScope");
|
|
7470
7663
|
|
|
7664
|
+
// src/lib/retire-soft-deleted-unique.ts
|
|
7665
|
+
async function retireSoftDeletedUniqueValue(repo, column, value) {
|
|
7666
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
7667
|
+
if (!trimmed) return;
|
|
7668
|
+
const cols = new Set(repo.metadata.columns.map((c) => c.propertyName));
|
|
7669
|
+
if (!cols.has(column) || !cols.has("deleted")) return;
|
|
7670
|
+
const rows = await repo.find({
|
|
7671
|
+
where: {
|
|
7672
|
+
[column]: trimmed,
|
|
7673
|
+
deleted: true
|
|
7674
|
+
}
|
|
7675
|
+
});
|
|
7676
|
+
for (const row of rows) {
|
|
7677
|
+
const id = row.id;
|
|
7678
|
+
if (!Number.isFinite(id)) continue;
|
|
7679
|
+
const current = String(row[column] ?? "");
|
|
7680
|
+
if (current.includes("__deleted_")) continue;
|
|
7681
|
+
await repo.update(id, {
|
|
7682
|
+
[column]: `${trimmed}__deleted_${id}`
|
|
7683
|
+
});
|
|
7684
|
+
}
|
|
7685
|
+
}
|
|
7686
|
+
chunkUSNT2KNT_cjs.__name(retireSoftDeletedUniqueValue, "retireSoftDeletedUniqueValue");
|
|
7687
|
+
async function activeUniqueValueExists(repo, column, value, excludeId) {
|
|
7688
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
7689
|
+
if (!trimmed) return false;
|
|
7690
|
+
const cols = new Set(repo.metadata.columns.map((c) => c.propertyName));
|
|
7691
|
+
if (!cols.has(column)) return false;
|
|
7692
|
+
const qb = repo.createQueryBuilder("row").where(`row.${column} = :value`, {
|
|
7693
|
+
value: trimmed
|
|
7694
|
+
});
|
|
7695
|
+
if (cols.has("deleted")) {
|
|
7696
|
+
qb.andWhere("row.deleted = false");
|
|
7697
|
+
}
|
|
7698
|
+
if (excludeId != null && Number.isFinite(excludeId) && excludeId > 0) {
|
|
7699
|
+
qb.andWhere("row.id != :excludeId", {
|
|
7700
|
+
excludeId
|
|
7701
|
+
});
|
|
7702
|
+
}
|
|
7703
|
+
const hit = await qb.getOne();
|
|
7704
|
+
return !!hit;
|
|
7705
|
+
}
|
|
7706
|
+
chunkUSNT2KNT_cjs.__name(activeUniqueValueExists, "activeUniqueValueExists");
|
|
7707
|
+
|
|
7471
7708
|
// src/lib/media-folder-path.ts
|
|
7472
7709
|
function sanitizeMediaFolderPath(input) {
|
|
7473
7710
|
if (input == null) return "";
|
|
@@ -8861,6 +9098,17 @@ function createFormSaveHandlers(config) {
|
|
|
8861
9098
|
});
|
|
8862
9099
|
const fields = Array.isArray(body.fields) ? body.fields : [];
|
|
8863
9100
|
const { fields: _f, ...formRow } = body;
|
|
9101
|
+
const slug = typeof formRow.slug === "string" ? formRow.slug.trim() : "";
|
|
9102
|
+
if (slug) {
|
|
9103
|
+
if (await activeUniqueValueExists(formRepo(), "slug", slug)) {
|
|
9104
|
+
return json({
|
|
9105
|
+
error: "A form with this slug already exists"
|
|
9106
|
+
}, {
|
|
9107
|
+
status: 400
|
|
9108
|
+
});
|
|
9109
|
+
}
|
|
9110
|
+
await retireSoftDeletedUniqueValue(formRepo(), "slug", slug);
|
|
9111
|
+
}
|
|
8864
9112
|
const form = await formRepo().save(formRepo().create(formRow));
|
|
8865
9113
|
for (let i = 0; i < fields.length; i++) {
|
|
8866
9114
|
const row = normalizeFieldRow(fields[i], form.id);
|
|
@@ -8884,6 +9132,14 @@ function createFormSaveHandlers(config) {
|
|
|
8884
9132
|
status: 201
|
|
8885
9133
|
});
|
|
8886
9134
|
} catch (e) {
|
|
9135
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
9136
|
+
if (/duplicate key|unique constraint/i.test(msg) && /slug/i.test(msg)) {
|
|
9137
|
+
return json({
|
|
9138
|
+
error: "A form with this slug already exists"
|
|
9139
|
+
}, {
|
|
9140
|
+
status: 400
|
|
9141
|
+
});
|
|
9142
|
+
}
|
|
8887
9143
|
return json({
|
|
8888
9144
|
error: "Server Error"
|
|
8889
9145
|
}, {
|
|
@@ -8932,6 +9188,20 @@ function createFormSaveHandlers(config) {
|
|
|
8932
9188
|
]) {
|
|
8933
9189
|
if (body[key] !== void 0) formRow[key] = body[key];
|
|
8934
9190
|
}
|
|
9191
|
+
if (typeof formRow.slug === "string") {
|
|
9192
|
+
const slug = formRow.slug.trim();
|
|
9193
|
+
formRow.slug = slug;
|
|
9194
|
+
if (slug) {
|
|
9195
|
+
if (await activeUniqueValueExists(formRepo(), "slug", slug, formId)) {
|
|
9196
|
+
return json({
|
|
9197
|
+
error: "A form with this slug already exists"
|
|
9198
|
+
}, {
|
|
9199
|
+
status: 400
|
|
9200
|
+
});
|
|
9201
|
+
}
|
|
9202
|
+
await retireSoftDeletedUniqueValue(formRepo(), "slug", slug);
|
|
9203
|
+
}
|
|
9204
|
+
}
|
|
8935
9205
|
if (Object.keys(formRow).length > 0) await formRepo().update(formId, formRow);
|
|
8936
9206
|
await fieldRepo().delete({
|
|
8937
9207
|
formId
|
|
@@ -8960,6 +9230,14 @@ function createFormSaveHandlers(config) {
|
|
|
8960
9230
|
status: 404
|
|
8961
9231
|
});
|
|
8962
9232
|
} catch (e) {
|
|
9233
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
9234
|
+
if (/duplicate key|unique constraint/i.test(msg) && /slug/i.test(msg)) {
|
|
9235
|
+
return json({
|
|
9236
|
+
error: "A form with this slug already exists"
|
|
9237
|
+
}, {
|
|
9238
|
+
status: 400
|
|
9239
|
+
});
|
|
9240
|
+
}
|
|
8963
9241
|
return json({
|
|
8964
9242
|
error: "Server Error"
|
|
8965
9243
|
}, {
|
|
@@ -9541,6 +9819,7 @@ function createUsersApiHandlers(config) {
|
|
|
9541
9819
|
"id",
|
|
9542
9820
|
"name",
|
|
9543
9821
|
"email",
|
|
9822
|
+
"phone",
|
|
9544
9823
|
"blocked",
|
|
9545
9824
|
"createdAt",
|
|
9546
9825
|
"updatedAt",
|
|
@@ -9570,6 +9849,11 @@ function createUsersApiHandlers(config) {
|
|
|
9570
9849
|
}
|
|
9571
9850
|
try {
|
|
9572
9851
|
const uid = parseInt(id, 10);
|
|
9852
|
+
if (!Number.isFinite(uid)) return json({
|
|
9853
|
+
error: "Invalid id"
|
|
9854
|
+
}, {
|
|
9855
|
+
status: 400
|
|
9856
|
+
});
|
|
9573
9857
|
const existing = await userRepo().findOne({
|
|
9574
9858
|
where: {
|
|
9575
9859
|
id: uid,
|
|
@@ -9582,8 +9866,59 @@ function createUsersApiHandlers(config) {
|
|
|
9582
9866
|
status: 404
|
|
9583
9867
|
});
|
|
9584
9868
|
const body = await req.json();
|
|
9585
|
-
const
|
|
9586
|
-
|
|
9869
|
+
const patch = {
|
|
9870
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
9871
|
+
};
|
|
9872
|
+
if (typeof body.name === "string") patch.name = body.name.trim();
|
|
9873
|
+
if (typeof body.email === "string") patch.email = body.email.trim().toLowerCase();
|
|
9874
|
+
if (body.blocked !== void 0) {
|
|
9875
|
+
patch.blocked = body.blocked === true || body.blocked === "true" || body.blocked === 1 || body.blocked === "1";
|
|
9876
|
+
}
|
|
9877
|
+
if (body.adminAccess !== void 0) {
|
|
9878
|
+
patch.adminAccess = body.adminAccess === true || body.adminAccess === "true" || body.adminAccess === 1 || body.adminAccess === "1";
|
|
9879
|
+
}
|
|
9880
|
+
if (body.groupId !== void 0) {
|
|
9881
|
+
if (body.groupId === null || body.groupId === "") {
|
|
9882
|
+
patch.groupId = null;
|
|
9883
|
+
} else {
|
|
9884
|
+
const gid = Number(body.groupId);
|
|
9885
|
+
if (!Number.isFinite(gid)) {
|
|
9886
|
+
return json({
|
|
9887
|
+
error: "Invalid groupId"
|
|
9888
|
+
}, {
|
|
9889
|
+
status: 400
|
|
9890
|
+
});
|
|
9891
|
+
}
|
|
9892
|
+
patch.groupId = gid;
|
|
9893
|
+
}
|
|
9894
|
+
}
|
|
9895
|
+
if (body.phone !== void 0) {
|
|
9896
|
+
const phone = body.phone == null ? null : String(body.phone).trim();
|
|
9897
|
+
patch.phone = phone || null;
|
|
9898
|
+
}
|
|
9899
|
+
if (Object.keys(patch).length <= 1) {
|
|
9900
|
+
return json({
|
|
9901
|
+
error: "No valid fields to update"
|
|
9902
|
+
}, {
|
|
9903
|
+
status: 400
|
|
9904
|
+
});
|
|
9905
|
+
}
|
|
9906
|
+
if (typeof patch.email === "string" && patch.email !== existing.email) {
|
|
9907
|
+
const emailTaken = await userRepo().findOne({
|
|
9908
|
+
where: {
|
|
9909
|
+
email: patch.email,
|
|
9910
|
+
deleted: false
|
|
9911
|
+
}
|
|
9912
|
+
});
|
|
9913
|
+
if (emailTaken && Number(emailTaken.id) !== uid) {
|
|
9914
|
+
return json({
|
|
9915
|
+
error: "Email already in use"
|
|
9916
|
+
}, {
|
|
9917
|
+
status: 400
|
|
9918
|
+
});
|
|
9919
|
+
}
|
|
9920
|
+
}
|
|
9921
|
+
await userRepo().update(uid, patch);
|
|
9587
9922
|
const updated = await userRepo().findOne({
|
|
9588
9923
|
where: {
|
|
9589
9924
|
id: uid,
|
|
@@ -9596,6 +9931,7 @@ function createUsersApiHandlers(config) {
|
|
|
9596
9931
|
"id",
|
|
9597
9932
|
"name",
|
|
9598
9933
|
"email",
|
|
9934
|
+
"phone",
|
|
9599
9935
|
"blocked",
|
|
9600
9936
|
"createdAt",
|
|
9601
9937
|
"updatedAt",
|
|
@@ -9607,7 +9943,8 @@ function createUsersApiHandlers(config) {
|
|
|
9607
9943
|
}, {
|
|
9608
9944
|
status: 404
|
|
9609
9945
|
});
|
|
9610
|
-
} catch {
|
|
9946
|
+
} catch (err) {
|
|
9947
|
+
console.error("[users.update]", err);
|
|
9611
9948
|
return json({
|
|
9612
9949
|
error: "Server Error"
|
|
9613
9950
|
}, {
|
|
@@ -12655,6 +12992,39 @@ function slugify(input) {
|
|
|
12655
12992
|
return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
12656
12993
|
}
|
|
12657
12994
|
chunkUSNT2KNT_cjs.__name(slugify, "slugify");
|
|
12995
|
+
async function userHasActiveVendor(em, entityMap, userId) {
|
|
12996
|
+
const vendorRepo = em.getRepository(entityMap.vendors);
|
|
12997
|
+
const owned = await vendorRepo.findOne({
|
|
12998
|
+
where: {
|
|
12999
|
+
userId,
|
|
13000
|
+
deleted: false
|
|
13001
|
+
}
|
|
13002
|
+
});
|
|
13003
|
+
if (owned) return true;
|
|
13004
|
+
if (!entityMap.vendor_users) return false;
|
|
13005
|
+
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', {
|
|
13006
|
+
userId
|
|
13007
|
+
}).getOne();
|
|
13008
|
+
return !!link;
|
|
13009
|
+
}
|
|
13010
|
+
chunkUSNT2KNT_cjs.__name(userHasActiveVendor, "userHasActiveVendor");
|
|
13011
|
+
async function userHadAnyVendor(em, entityMap, userId) {
|
|
13012
|
+
const vendorRepo = em.getRepository(entityMap.vendors);
|
|
13013
|
+
const owned = await vendorRepo.findOne({
|
|
13014
|
+
where: {
|
|
13015
|
+
userId
|
|
13016
|
+
}
|
|
13017
|
+
});
|
|
13018
|
+
if (owned) return true;
|
|
13019
|
+
if (!entityMap.vendor_users) return false;
|
|
13020
|
+
const link = await em.getRepository(entityMap.vendor_users).findOne({
|
|
13021
|
+
where: {
|
|
13022
|
+
userId
|
|
13023
|
+
}
|
|
13024
|
+
});
|
|
13025
|
+
return !!link;
|
|
13026
|
+
}
|
|
13027
|
+
chunkUSNT2KNT_cjs.__name(userHadAnyVendor, "userHadAnyVendor");
|
|
12658
13028
|
function vendorOnboardErrorResponse(json, err) {
|
|
12659
13029
|
const msg = err instanceof Error ? err.message : String(err);
|
|
12660
13030
|
console.error("[vendor-onboard]", err);
|
|
@@ -12753,14 +13123,80 @@ function createVendorOnboardHandlers(config) {
|
|
|
12753
13123
|
chunkUSNT2KNT_cjs.__name(gateAdmin, "gateAdmin");
|
|
12754
13124
|
async function resolveActiveVendorId(u) {
|
|
12755
13125
|
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u);
|
|
12756
|
-
|
|
12757
|
-
if (scope.type === "
|
|
12758
|
-
|
|
12759
|
-
|
|
13126
|
+
const candidates = [];
|
|
13127
|
+
if (scope.type === "vendor") candidates.push(scope.vendorId);
|
|
13128
|
+
if (scope.type === "all" || scope.type === "vendor") {
|
|
13129
|
+
const preferred = u.activeVendorId ?? u.vendorIds?.[0];
|
|
13130
|
+
if (preferred != null && Number.isFinite(preferred)) candidates.push(Number(preferred));
|
|
13131
|
+
for (const id of u.vendorIds ?? []) {
|
|
13132
|
+
if (Number.isFinite(id)) candidates.push(Number(id));
|
|
13133
|
+
}
|
|
13134
|
+
}
|
|
13135
|
+
if (entityMap.vendors && candidates.length > 0) {
|
|
13136
|
+
const unique = [
|
|
13137
|
+
...new Set(candidates.filter((id) => id > 0))
|
|
13138
|
+
];
|
|
13139
|
+
for (const id of unique) {
|
|
13140
|
+
try {
|
|
13141
|
+
const row = await dataSource.getRepository(entityMap.vendors).findOne({
|
|
13142
|
+
where: {
|
|
13143
|
+
id,
|
|
13144
|
+
deleted: false
|
|
13145
|
+
}
|
|
13146
|
+
});
|
|
13147
|
+
if (row) return id;
|
|
13148
|
+
} catch {
|
|
13149
|
+
}
|
|
13150
|
+
}
|
|
13151
|
+
}
|
|
13152
|
+
const uid = u.id != null ? Number(u.id) : NaN;
|
|
13153
|
+
if (Number.isFinite(uid) && entityMap.vendors) {
|
|
13154
|
+
try {
|
|
13155
|
+
const owned = await dataSource.getRepository(entityMap.vendors).findOne({
|
|
13156
|
+
where: {
|
|
13157
|
+
userId: uid,
|
|
13158
|
+
deleted: false
|
|
13159
|
+
},
|
|
13160
|
+
order: {
|
|
13161
|
+
id: "ASC"
|
|
13162
|
+
}
|
|
13163
|
+
});
|
|
13164
|
+
const vid = owned ? Number(owned.id) : NaN;
|
|
13165
|
+
if (Number.isFinite(vid) && vid > 0) return vid;
|
|
13166
|
+
} catch {
|
|
13167
|
+
}
|
|
12760
13168
|
}
|
|
12761
13169
|
return null;
|
|
12762
13170
|
}
|
|
12763
13171
|
chunkUSNT2KNT_cjs.__name(resolveActiveVendorId, "resolveActiveVendorId");
|
|
13172
|
+
async function gateVendorPortal() {
|
|
13173
|
+
const u = await getSessionUser();
|
|
13174
|
+
if (!u?.email) return json({
|
|
13175
|
+
error: "Unauthorized"
|
|
13176
|
+
}, {
|
|
13177
|
+
status: 401
|
|
13178
|
+
});
|
|
13179
|
+
if (!chunkX6UQFV4X_cjs.isVendorPortalUser(u) && !chunkX6UQFV4X_cjs.isPlatformAdministrator(u)) {
|
|
13180
|
+
return json({
|
|
13181
|
+
error: "Forbidden"
|
|
13182
|
+
}, {
|
|
13183
|
+
status: 403
|
|
13184
|
+
});
|
|
13185
|
+
}
|
|
13186
|
+
const vendorId = await resolveActiveVendorId(u);
|
|
13187
|
+
if (vendorId == null) {
|
|
13188
|
+
return json({
|
|
13189
|
+
error: "No vendor is linked to your account."
|
|
13190
|
+
}, {
|
|
13191
|
+
status: 400
|
|
13192
|
+
});
|
|
13193
|
+
}
|
|
13194
|
+
return {
|
|
13195
|
+
user: u,
|
|
13196
|
+
vendorId
|
|
13197
|
+
};
|
|
13198
|
+
}
|
|
13199
|
+
chunkUSNT2KNT_cjs.__name(gateVendorPortal, "gateVendorPortal");
|
|
12764
13200
|
async function gateVendorTeam() {
|
|
12765
13201
|
const u = await getSessionUser();
|
|
12766
13202
|
if (!u?.email) return json({
|
|
@@ -12814,6 +13250,40 @@ function createVendorOnboardHandlers(config) {
|
|
|
12814
13250
|
}
|
|
12815
13251
|
chunkUSNT2KNT_cjs.__name(trySendVendorOnboardEmails, "trySendVendorOnboardEmails");
|
|
12816
13252
|
return {
|
|
13253
|
+
/** GET /api/admin/vendor/profile — current user's store (server-resolved vendor id). */
|
|
13254
|
+
async getProfile() {
|
|
13255
|
+
const gated = await gateVendorPortal();
|
|
13256
|
+
if (gated instanceof Response) return gated;
|
|
13257
|
+
const { vendorId } = gated;
|
|
13258
|
+
if (!entityMap.vendors) {
|
|
13259
|
+
return json({
|
|
13260
|
+
error: "Vendors not configured"
|
|
13261
|
+
}, {
|
|
13262
|
+
status: 500
|
|
13263
|
+
});
|
|
13264
|
+
}
|
|
13265
|
+
try {
|
|
13266
|
+
const row = await dataSource.getRepository(entityMap.vendors).findOne({
|
|
13267
|
+
where: {
|
|
13268
|
+
id: vendorId,
|
|
13269
|
+
deleted: false
|
|
13270
|
+
}
|
|
13271
|
+
});
|
|
13272
|
+
if (!row) return json({
|
|
13273
|
+
error: "Vendor not found"
|
|
13274
|
+
}, {
|
|
13275
|
+
status: 404
|
|
13276
|
+
});
|
|
13277
|
+
return json(row);
|
|
13278
|
+
} catch (e) {
|
|
13279
|
+
console.error("[vendor.profile]", e);
|
|
13280
|
+
return json({
|
|
13281
|
+
error: "Failed to load vendor profile"
|
|
13282
|
+
}, {
|
|
13283
|
+
status: 500
|
|
13284
|
+
});
|
|
13285
|
+
}
|
|
13286
|
+
},
|
|
12817
13287
|
/** POST /api/admin/vendors/onboard — create vendor + owner user + vendor_users + invite */
|
|
12818
13288
|
async onboard(req) {
|
|
12819
13289
|
const err = await gateAdmin();
|
|
@@ -12882,6 +13352,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12882
13352
|
}
|
|
12883
13353
|
});
|
|
12884
13354
|
if (dupVendor) throw new Error("VENDOR_SLUG_EXISTS");
|
|
13355
|
+
await retireSoftDeletedUniqueValue(vendorRepo, "slug", slug);
|
|
12885
13356
|
let ownerGroup = await groupRepo.findOne({
|
|
12886
13357
|
where: {
|
|
12887
13358
|
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
@@ -12910,8 +13381,15 @@ function createVendorOnboardHandlers(config) {
|
|
|
12910
13381
|
email: userEmail
|
|
12911
13382
|
}
|
|
12912
13383
|
});
|
|
12913
|
-
if (existingUser && !existingUser.deleted)
|
|
12914
|
-
|
|
13384
|
+
if (existingUser && !existingUser.deleted) {
|
|
13385
|
+
if (await userHasActiveVendor(em, entityMap, existingUser.id)) {
|
|
13386
|
+
throw new Error("USER_EMAIL_EXISTS");
|
|
13387
|
+
}
|
|
13388
|
+
if (!await userHadAnyVendor(em, entityMap, existingUser.id)) {
|
|
13389
|
+
throw new Error("USER_EMAIL_EXISTS");
|
|
13390
|
+
}
|
|
13391
|
+
}
|
|
13392
|
+
const newUser = existingUser ? await (async () => {
|
|
12915
13393
|
await userRepo.update(existingUser.id, {
|
|
12916
13394
|
deleted: false,
|
|
12917
13395
|
deletedAt: null,
|
|
@@ -15994,10 +16472,12 @@ exports.Customer = class Customer {
|
|
|
15994
16472
|
chunkUSNT2KNT_cjs.__name(this, "Customer");
|
|
15995
16473
|
}
|
|
15996
16474
|
id;
|
|
16475
|
+
/** Set only when the customer can log in (linked `users` row). Admin/guest customers stay null. */
|
|
15997
16476
|
userId;
|
|
15998
16477
|
user;
|
|
15999
16478
|
name;
|
|
16000
16479
|
email;
|
|
16480
|
+
/** Optional; multiple customers may have null (PostgreSQL UNIQUE allows multiple NULLs). */
|
|
16001
16481
|
phone;
|
|
16002
16482
|
createdAt;
|
|
16003
16483
|
updatedAt;
|
|
@@ -16012,8 +16492,10 @@ _ts_decorate18([
|
|
|
16012
16492
|
_ts_metadata18("design:type", Number)
|
|
16013
16493
|
], exports.Customer.prototype, "id", void 0);
|
|
16014
16494
|
_ts_decorate18([
|
|
16015
|
-
typeorm.Column("int"
|
|
16016
|
-
|
|
16495
|
+
typeorm.Column("int", {
|
|
16496
|
+
nullable: true
|
|
16497
|
+
}),
|
|
16498
|
+
_ts_metadata18("design:type", Object)
|
|
16017
16499
|
], exports.Customer.prototype, "userId", void 0);
|
|
16018
16500
|
_ts_decorate18([
|
|
16019
16501
|
typeorm.ManyToOne(() => exports.User, {
|
|
@@ -16036,9 +16518,10 @@ _ts_decorate18([
|
|
|
16036
16518
|
], exports.Customer.prototype, "email", void 0);
|
|
16037
16519
|
_ts_decorate18([
|
|
16038
16520
|
typeorm.Column("varchar", {
|
|
16039
|
-
unique: true
|
|
16521
|
+
unique: true,
|
|
16522
|
+
nullable: true
|
|
16040
16523
|
}),
|
|
16041
|
-
_ts_metadata18("design:type",
|
|
16524
|
+
_ts_metadata18("design:type", Object)
|
|
16042
16525
|
], exports.Customer.prototype, "phone", void 0);
|
|
16043
16526
|
_ts_decorate18([
|
|
16044
16527
|
typeorm.Column({
|
|
@@ -26622,6 +27105,14 @@ function createCmsApiHandler(config) {
|
|
|
26622
27105
|
});
|
|
26623
27106
|
return vendorHandlers.switchVendor(req);
|
|
26624
27107
|
}
|
|
27108
|
+
if (path2[0] === "admin" && path2[1] === "vendor" && path2[2] === "profile" && path2.length === 3 && m === "GET") {
|
|
27109
|
+
if (!vendorHandlers) return config.json({
|
|
27110
|
+
error: "Not found"
|
|
27111
|
+
}, {
|
|
27112
|
+
status: 404
|
|
27113
|
+
});
|
|
27114
|
+
return vendorHandlers.getProfile();
|
|
27115
|
+
}
|
|
26625
27116
|
if (path2[0] === "admin" && path2[1] === "vendor" && path2[2] === "roles" && vendorRolesHandlers) {
|
|
26626
27117
|
if (path2.length === 3 && m === "GET") return vendorRolesHandlers.list();
|
|
26627
27118
|
if (path2.length === 3 && m === "POST") return vendorRolesHandlers.create(req);
|
|
@@ -29091,13 +29582,36 @@ function createStorefrontApiHandler(config) {
|
|
|
29091
29582
|
status: 400
|
|
29092
29583
|
};
|
|
29093
29584
|
}
|
|
29585
|
+
const list = [
|
|
29586
|
+
...vendorIds
|
|
29587
|
+
];
|
|
29094
29588
|
return {
|
|
29095
|
-
vendorId: [
|
|
29096
|
-
|
|
29097
|
-
][0]
|
|
29589
|
+
vendorId: list[0],
|
|
29590
|
+
vendorIds: list
|
|
29098
29591
|
};
|
|
29099
29592
|
}
|
|
29100
29593
|
chunkUSNT2KNT_cjs.__name(resolveSingleVendorIdFromCart, "resolveSingleVendorIdFromCart");
|
|
29594
|
+
async function linkOrderContactToVendors(contactId, vendorIds) {
|
|
29595
|
+
try {
|
|
29596
|
+
const contact = await contactRepo().findOne({
|
|
29597
|
+
where: {
|
|
29598
|
+
id: contactId,
|
|
29599
|
+
deleted: false
|
|
29600
|
+
}
|
|
29601
|
+
});
|
|
29602
|
+
if (!contact) return;
|
|
29603
|
+
const email = String(contact.email ?? "").trim().toLowerCase();
|
|
29604
|
+
if (!email) return;
|
|
29605
|
+
await ensureVendorCustomersForOrder(dataSource, entityMap, vendorIds, contactId, {
|
|
29606
|
+
name: String(contact.name ?? "").trim() || email.split("@")[0] || "Customer",
|
|
29607
|
+
email,
|
|
29608
|
+
phone: contact.phone ?? null
|
|
29609
|
+
});
|
|
29610
|
+
} catch (err) {
|
|
29611
|
+
console.error("[storefront] vendor_customers link failed", err);
|
|
29612
|
+
}
|
|
29613
|
+
}
|
|
29614
|
+
chunkUSNT2KNT_cjs.__name(linkOrderContactToVendors, "linkOrderContactToVendors");
|
|
29101
29615
|
function roundMoney3(n) {
|
|
29102
29616
|
return Math.round(n * 100) / 100;
|
|
29103
29617
|
}
|
|
@@ -29815,7 +30329,8 @@ function createStorefrontApiHandler(config) {
|
|
|
29815
30329
|
const repo = dataSource.getRepository(entityMap.product_variants);
|
|
29816
30330
|
const rows = await repo.find({
|
|
29817
30331
|
where: {
|
|
29818
|
-
productId
|
|
30332
|
+
productId,
|
|
30333
|
+
status: "available"
|
|
29819
30334
|
},
|
|
29820
30335
|
order: {
|
|
29821
30336
|
id: "ASC"
|
|
@@ -29848,6 +30363,52 @@ function createStorefrontApiHandler(config) {
|
|
|
29848
30363
|
return result;
|
|
29849
30364
|
}
|
|
29850
30365
|
chunkUSNT2KNT_cjs.__name(loadProductVariantsWithPricing, "loadProductVariantsWithPricing");
|
|
30366
|
+
async function loadApplicableVendorPolicies(productId, vendorId) {
|
|
30367
|
+
if (!entityMap.refund_policies) return [];
|
|
30368
|
+
const policyRepo = dataSource.getRepository(entityMap.refund_policies);
|
|
30369
|
+
const format = /* @__PURE__ */ chunkUSNT2KNT_cjs.__name((row) => ({
|
|
30370
|
+
id: Number(row.id),
|
|
30371
|
+
name: String(row.name ?? "").trim(),
|
|
30372
|
+
desc: row.desc != null ? String(row.desc) : null,
|
|
30373
|
+
refundWindowDays: Number(row.refundWindowDays) || 0,
|
|
30374
|
+
type: String(row.type ?? "percentage"),
|
|
30375
|
+
value: Number(row.value) || 0
|
|
30376
|
+
}), "format");
|
|
30377
|
+
const linkedIds = /* @__PURE__ */ new Set();
|
|
30378
|
+
if (entityMap.product_config) {
|
|
30379
|
+
const configs = await dataSource.getRepository(entityMap.product_config).find({
|
|
30380
|
+
where: {
|
|
30381
|
+
productId
|
|
30382
|
+
}
|
|
30383
|
+
});
|
|
30384
|
+
for (const c of configs) {
|
|
30385
|
+
const id = Number(c.refundPolicyId);
|
|
30386
|
+
if (Number.isFinite(id) && id > 0) linkedIds.add(id);
|
|
30387
|
+
}
|
|
30388
|
+
}
|
|
30389
|
+
if (linkedIds.size > 0) {
|
|
30390
|
+
const rows = await policyRepo.find({
|
|
30391
|
+
where: {
|
|
30392
|
+
id: typeorm.In([
|
|
30393
|
+
...linkedIds
|
|
30394
|
+
])
|
|
30395
|
+
}
|
|
30396
|
+
});
|
|
30397
|
+
return rows.map((r) => format(r)).filter((p) => p.name).sort((a, b) => a.id - b.id);
|
|
30398
|
+
}
|
|
30399
|
+
if (vendorId == null || !Number.isFinite(Number(vendorId))) return [];
|
|
30400
|
+
const vendorRows = await policyRepo.find({
|
|
30401
|
+
where: {
|
|
30402
|
+
vendorId: Number(vendorId),
|
|
30403
|
+
status: "active"
|
|
30404
|
+
},
|
|
30405
|
+
order: {
|
|
30406
|
+
id: "ASC"
|
|
30407
|
+
}
|
|
30408
|
+
});
|
|
30409
|
+
return vendorRows.map((r) => format(r)).filter((p) => p.name);
|
|
30410
|
+
}
|
|
30411
|
+
chunkUSNT2KNT_cjs.__name(loadApplicableVendorPolicies, "loadApplicableVendorPolicies");
|
|
29851
30412
|
return {
|
|
29852
30413
|
async handle(method, path2, req) {
|
|
29853
30414
|
try {
|
|
@@ -29915,13 +30476,11 @@ function createStorefrontApiHandler(config) {
|
|
|
29915
30476
|
const url = new URL(req.url || "", "http://localhost");
|
|
29916
30477
|
const collectionSlug = url.searchParams.get("collection")?.trim();
|
|
29917
30478
|
const collectionId = url.searchParams.get("collectionId");
|
|
30479
|
+
const q = url.searchParams.get("q")?.trim() ?? "";
|
|
29918
30480
|
const limit = Math.min(100, Math.max(1, parseInt(url.searchParams.get("limit") || "20", 10)));
|
|
29919
30481
|
const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0", 10));
|
|
29920
|
-
const where = {
|
|
29921
|
-
status: "available",
|
|
29922
|
-
deleted: false
|
|
29923
|
-
};
|
|
29924
30482
|
let collectionFilter = null;
|
|
30483
|
+
let collectionIdFilter = null;
|
|
29925
30484
|
if (collectionSlug) {
|
|
29926
30485
|
let col = null;
|
|
29927
30486
|
if (/^\d+$/.test(collectionSlug)) {
|
|
@@ -29948,30 +30507,59 @@ function createStorefrontApiHandler(config) {
|
|
|
29948
30507
|
collection: null
|
|
29949
30508
|
});
|
|
29950
30509
|
}
|
|
29951
|
-
|
|
30510
|
+
collectionIdFilter = Number(col.id);
|
|
29952
30511
|
collectionFilter = {
|
|
29953
30512
|
name: col.name,
|
|
29954
30513
|
slug: col.slug
|
|
29955
30514
|
};
|
|
29956
30515
|
} else if (collectionId) {
|
|
29957
30516
|
const cid = parseInt(collectionId, 10);
|
|
29958
|
-
if (Number.isFinite(cid))
|
|
30517
|
+
if (Number.isFinite(cid)) collectionIdFilter = cid;
|
|
30518
|
+
}
|
|
30519
|
+
let items = [];
|
|
30520
|
+
let total = 0;
|
|
30521
|
+
if (q) {
|
|
30522
|
+
const like = `%${q.replace(/[%_]/g, "\\$&")}%`;
|
|
30523
|
+
const qb = productRepo().createQueryBuilder("p").where("p.status = :status", {
|
|
30524
|
+
status: "available"
|
|
30525
|
+
}).andWhere("p.deleted = :del", {
|
|
30526
|
+
del: false
|
|
30527
|
+
}).andWhere(`(p.name ILIKE :like OR p.slug ILIKE :like OR COALESCE(p.sku, '') ILIKE :like OR COALESCE(p.title, '') ILIKE :like OR COALESCE(p.metadata->>'description', '') ILIKE :like)`, {
|
|
30528
|
+
like
|
|
30529
|
+
}).orderBy("p.id", "ASC").take(limit).skip(offset);
|
|
30530
|
+
if (collectionIdFilter != null) {
|
|
30531
|
+
qb.andWhere("p.collectionId = :cid", {
|
|
30532
|
+
cid: collectionIdFilter
|
|
30533
|
+
});
|
|
30534
|
+
}
|
|
30535
|
+
[items, total] = await qb.getManyAndCount();
|
|
30536
|
+
} else {
|
|
30537
|
+
const where = {
|
|
30538
|
+
status: "available",
|
|
30539
|
+
deleted: false
|
|
30540
|
+
};
|
|
30541
|
+
if (collectionIdFilter != null) where.collectionId = collectionIdFilter;
|
|
30542
|
+
const result = await productRepo().findAndCount({
|
|
30543
|
+
where,
|
|
30544
|
+
order: {
|
|
30545
|
+
id: "ASC"
|
|
30546
|
+
},
|
|
30547
|
+
take: limit,
|
|
30548
|
+
skip: offset
|
|
30549
|
+
});
|
|
30550
|
+
items = result[0];
|
|
30551
|
+
total = result[1];
|
|
29959
30552
|
}
|
|
29960
|
-
const [items, total] = await productRepo().findAndCount({
|
|
29961
|
-
where,
|
|
29962
|
-
order: {
|
|
29963
|
-
id: "ASC"
|
|
29964
|
-
},
|
|
29965
|
-
take: limit,
|
|
29966
|
-
skip: offset
|
|
29967
|
-
});
|
|
29968
30553
|
const products = await Promise.all(items.map((item) => enrichProductPricing(item)));
|
|
29969
30554
|
return json({
|
|
29970
30555
|
products,
|
|
29971
30556
|
total,
|
|
29972
30557
|
...collectionFilter && {
|
|
29973
30558
|
collection: collectionFilter
|
|
29974
|
-
}
|
|
30559
|
+
},
|
|
30560
|
+
...q ? {
|
|
30561
|
+
q
|
|
30562
|
+
} : {}
|
|
29975
30563
|
});
|
|
29976
30564
|
}
|
|
29977
30565
|
if (path2[0] === "products" && path2.length === 2 && method === "GET") {
|
|
@@ -30007,12 +30595,14 @@ function createStorefrontApiHandler(config) {
|
|
|
30007
30595
|
const pricing = await resolveProductEventPricing(Number(p.id));
|
|
30008
30596
|
const enriched = await enrichProductPricing(p, pricing);
|
|
30009
30597
|
const variants = await loadProductVariantsWithPricing(Number(p.id), pricing);
|
|
30598
|
+
const policies = await loadApplicableVendorPolicies(Number(p.id), p.vendorId != null ? Number(p.vendorId) : null);
|
|
30010
30599
|
return json({
|
|
30011
30600
|
...enriched,
|
|
30012
30601
|
attributes: attributeTags,
|
|
30013
30602
|
...variants.length ? {
|
|
30014
30603
|
variants
|
|
30015
|
-
} : {}
|
|
30604
|
+
} : {},
|
|
30605
|
+
policies
|
|
30016
30606
|
});
|
|
30017
30607
|
}
|
|
30018
30608
|
if (path2[0] === "collections" && path2.length === 1 && method === "GET") {
|
|
@@ -30824,24 +31414,61 @@ function createStorefrontApiHandler(config) {
|
|
|
30824
31414
|
}, {
|
|
30825
31415
|
status: 404
|
|
30826
31416
|
});
|
|
31417
|
+
const rawVariantId = body.variantId ?? body.variant_id;
|
|
31418
|
+
const variantIdNum = rawVariantId != null && String(rawVariantId).trim() !== "" ? Number(rawVariantId) : NaN;
|
|
31419
|
+
const hasVariantId = Number.isFinite(variantIdNum) && variantIdNum > 0;
|
|
31420
|
+
const bodyMeta = body.metadata && typeof body.metadata === "object" && !Array.isArray(body.metadata) ? body.metadata : {};
|
|
31421
|
+
const optionsRaw = body.options && typeof body.options === "object" && !Array.isArray(body.options) ? body.options : bodyMeta.options && typeof bodyMeta.options === "object" && !Array.isArray(bodyMeta.options) ? bodyMeta.options : null;
|
|
31422
|
+
const options = optionsRaw && Object.fromEntries(Object.entries(optionsRaw).map(([k, v]) => [
|
|
31423
|
+
String(k),
|
|
31424
|
+
String(v ?? "").trim()
|
|
31425
|
+
]).filter(([, v]) => v.length > 0));
|
|
31426
|
+
const lineMetadata = {
|
|
31427
|
+
...bodyMeta,
|
|
31428
|
+
...hasVariantId ? {
|
|
31429
|
+
variantId: variantIdNum
|
|
31430
|
+
} : {},
|
|
31431
|
+
...options && Object.keys(options).length ? {
|
|
31432
|
+
options
|
|
31433
|
+
} : {}
|
|
31434
|
+
};
|
|
31435
|
+
if (typeof bodyMeta.imageUrl === "string" && bodyMeta.imageUrl.trim()) {
|
|
31436
|
+
lineMetadata.imageUrl = bodyMeta.imageUrl.trim();
|
|
31437
|
+
}
|
|
31438
|
+
if (typeof bodyMeta.title === "string" && bodyMeta.title.trim()) {
|
|
31439
|
+
lineMetadata.title = bodyMeta.title.trim();
|
|
31440
|
+
}
|
|
31441
|
+
const metadataPayload = Object.keys(lineMetadata).length ? lineMetadata : null;
|
|
30827
31442
|
const { cart, setCookie, err } = await getOrCreateCart(req);
|
|
30828
31443
|
if (err) return err;
|
|
30829
31444
|
const cartId = cart.id;
|
|
30830
|
-
const
|
|
31445
|
+
const sameProductLines = await cartItemRepo().find({
|
|
30831
31446
|
where: {
|
|
30832
31447
|
cartId,
|
|
30833
31448
|
productId
|
|
30834
31449
|
}
|
|
30835
31450
|
});
|
|
31451
|
+
const existing = sameProductLines.find((row) => {
|
|
31452
|
+
const m = row.metadata;
|
|
31453
|
+
const existingVid = m?.variantId ?? m?.variant_id;
|
|
31454
|
+
if (hasVariantId) {
|
|
31455
|
+
return Number(existingVid) === variantIdNum;
|
|
31456
|
+
}
|
|
31457
|
+
return existingVid == null || existingVid === "";
|
|
31458
|
+
});
|
|
30836
31459
|
if (existing) {
|
|
30837
31460
|
await cartItemRepo().update(existing.id, {
|
|
30838
|
-
quantity: existing.quantity + quantity
|
|
31461
|
+
quantity: existing.quantity + quantity,
|
|
31462
|
+
...metadataPayload ? {
|
|
31463
|
+
metadata: metadataPayload
|
|
31464
|
+
} : {}
|
|
30839
31465
|
});
|
|
30840
31466
|
} else {
|
|
30841
31467
|
await cartItemRepo().save(cartItemRepo().create({
|
|
30842
31468
|
cartId,
|
|
30843
31469
|
productId,
|
|
30844
|
-
quantity
|
|
31470
|
+
quantity,
|
|
31471
|
+
metadata: metadataPayload
|
|
30845
31472
|
}));
|
|
30846
31473
|
}
|
|
30847
31474
|
await cartRepo().update(cartId, {
|
|
@@ -31306,6 +31933,7 @@ function createStorefrontApiHandler(config) {
|
|
|
31306
31933
|
taxCode: line.taxCode
|
|
31307
31934
|
}));
|
|
31308
31935
|
}
|
|
31936
|
+
await linkOrderContactToVendors(contactId, vendorRes.vendorIds);
|
|
31309
31937
|
fireOrderPlacedNotification(oid);
|
|
31310
31938
|
return json({
|
|
31311
31939
|
orderId: oid,
|
|
@@ -31378,6 +32006,7 @@ function createStorefrontApiHandler(config) {
|
|
|
31378
32006
|
taxCode: line.taxCode
|
|
31379
32007
|
}));
|
|
31380
32008
|
}
|
|
32009
|
+
await linkOrderContactToVendors(contactId, vendorResChk.vendorIds);
|
|
31381
32010
|
await cartItemRepo().delete({
|
|
31382
32011
|
cartId: cart.id
|
|
31383
32012
|
});
|
|
@@ -31686,13 +32315,16 @@ exports.createUserProfileHandler = createUserProfileHandler;
|
|
|
31686
32315
|
exports.createUsersApiHandlers = createUsersApiHandlers;
|
|
31687
32316
|
exports.createVendorDashboardHandler = createVendorDashboardHandler;
|
|
31688
32317
|
exports.createVendorOnboardHandlers = createVendorOnboardHandlers;
|
|
32318
|
+
exports.customerPhoneForEmail = customerPhoneForEmail;
|
|
31689
32319
|
exports.customerPhoneForUser = customerPhoneForUser;
|
|
31690
32320
|
exports.daysBeforeEventStart = daysBeforeEventStart;
|
|
31691
32321
|
exports.describeEventTierPolicy = describeEventTierPolicy;
|
|
31692
32322
|
exports.ensureCustomerForUser = ensureCustomerForUser;
|
|
32323
|
+
exports.ensureCustomerRecord = ensureCustomerRecord;
|
|
31693
32324
|
exports.ensureMessagingPluginsOnCms = ensureMessagingPluginsOnCms;
|
|
31694
32325
|
exports.ensureScheduleQueueWorker = ensureScheduleQueueWorker;
|
|
31695
32326
|
exports.ensureVendorCustomerForOrderContact = ensureVendorCustomerForOrderContact;
|
|
32327
|
+
exports.ensureVendorCustomersForOrder = ensureVendorCustomersForOrder;
|
|
31696
32328
|
exports.findActiveRefundPolicyForVendor = findActiveRefundPolicyForVendor;
|
|
31697
32329
|
exports.findVendorByInviteToken = findVendorByInviteToken;
|
|
31698
32330
|
exports.formatTierRange = formatTierRange;
|
|
@@ -31710,6 +32342,7 @@ exports.invalidateRequireEventApprovalCache = invalidateRequireEventApprovalCach
|
|
|
31710
32342
|
exports.invalidateRequireProductApprovalCache = invalidateRequireProductApprovalCache;
|
|
31711
32343
|
exports.invalidateVendorCatalogCreateFlagsCache = invalidateVendorCatalogCreateFlagsCache;
|
|
31712
32344
|
exports.isCustomerTypeContact = isCustomerTypeContact;
|
|
32345
|
+
exports.isSyntheticCustomerPhone = isSyntheticCustomerPhone;
|
|
31713
32346
|
exports.isZipMedia = isZipMedia;
|
|
31714
32347
|
exports.linkUnclaimedContactToUser = linkUnclaimedContactToUser;
|
|
31715
32348
|
exports.llmAgentToChatAgentOptions = llmAgentToChatAgentOptions;
|
|
@@ -31721,6 +32354,7 @@ exports.metaFetchUserManagedPages = metaFetchUserManagedPages;
|
|
|
31721
32354
|
exports.metaPostPageFeed = metaPostPageFeed;
|
|
31722
32355
|
exports.metaPostPagePhoto = metaPostPagePhoto;
|
|
31723
32356
|
exports.metaResolvePageAccessToken = metaResolvePageAccessToken;
|
|
32357
|
+
exports.normalizeCustomerPhone = normalizeCustomerPhone;
|
|
31724
32358
|
exports.normalizePhoneE164 = normalizePhoneE164;
|
|
31725
32359
|
exports.normalizeRefundTiers = normalizeRefundTiers;
|
|
31726
32360
|
exports.overlayCmsPlugins = overlayCmsPlugins;
|