@infuro/cms-core 1.0.44 → 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 +541 -407
- package/dist/admin.d.cts +1 -1
- package/dist/admin.d.ts +1 -1
- package/dist/admin.js +541 -407
- 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-P2IWWBJV.cjs → chunk-F5XFHYTG.cjs} +703 -269
- package/dist/{chunk-SQGBHYJF.js → chunk-MVXLRANV.js} +700 -271
- 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];
|
|
@@ -1100,11 +1130,118 @@ function pgErrorCode(err) {
|
|
|
1100
1130
|
return driver?.code ?? err.code;
|
|
1101
1131
|
}
|
|
1102
1132
|
chunkUSNT2KNT_cjs.__name(pgErrorCode, "pgErrorCode");
|
|
1103
|
-
function
|
|
1133
|
+
function normalizeCustomerPhone(phone) {
|
|
1104
1134
|
const p = typeof phone === "string" ? phone.trim() : "";
|
|
1105
|
-
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);
|
|
1106
1148
|
}
|
|
1107
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");
|
|
1108
1245
|
async function restoreCustomerRow(repo, row, user, name, email, phone) {
|
|
1109
1246
|
const id = row.id;
|
|
1110
1247
|
await repo.update(id, {
|
|
@@ -1126,7 +1263,7 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1126
1263
|
const repo = dsOrEm.getRepository(customerEntity);
|
|
1127
1264
|
const email = normalizeEmail(user.email);
|
|
1128
1265
|
const name = String(user.name ?? "").trim() || email.split("@")[0] || "User";
|
|
1129
|
-
const phone =
|
|
1266
|
+
const phone = normalizeCustomerPhone(overrides?.phone ?? user.phone);
|
|
1130
1267
|
let row = await repo.findOne({
|
|
1131
1268
|
where: {
|
|
1132
1269
|
userId: user.id,
|
|
@@ -1134,10 +1271,11 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1134
1271
|
}
|
|
1135
1272
|
});
|
|
1136
1273
|
if (row) {
|
|
1274
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
1137
1275
|
await repo.update(row.id, {
|
|
1138
1276
|
name,
|
|
1139
1277
|
email,
|
|
1140
|
-
phone,
|
|
1278
|
+
phone: nextPhone,
|
|
1141
1279
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1142
1280
|
});
|
|
1143
1281
|
return {
|
|
@@ -1155,10 +1293,11 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1155
1293
|
if (existingUserId != null && existingUserId !== user.id) {
|
|
1156
1294
|
return null;
|
|
1157
1295
|
}
|
|
1296
|
+
const nextPhone = resolveNextPhone(phone, row.phone);
|
|
1158
1297
|
await repo.update(row.id, {
|
|
1159
1298
|
userId: user.id,
|
|
1160
1299
|
name,
|
|
1161
|
-
phone,
|
|
1300
|
+
phone: nextPhone,
|
|
1162
1301
|
updatedAt: /* @__PURE__ */ new Date()
|
|
1163
1302
|
});
|
|
1164
1303
|
return {
|
|
@@ -1173,21 +1312,23 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1173
1312
|
if (deletedByEmail) {
|
|
1174
1313
|
const existingUserId = deletedByEmail.userId;
|
|
1175
1314
|
if (existingUserId != null && existingUserId !== user.id) return null;
|
|
1176
|
-
return restoreCustomerRow(repo, deletedByEmail, user, name, email, phone);
|
|
1315
|
+
return restoreCustomerRow(repo, deletedByEmail, user, name, email, resolveNextPhone(phone, deletedByEmail.phone));
|
|
1177
1316
|
}
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
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);
|
|
1189
1331
|
}
|
|
1190
|
-
return restoreCustomerRow(repo, deletedByPhone, user, name, email, phone);
|
|
1191
1332
|
}
|
|
1192
1333
|
try {
|
|
1193
1334
|
const created = await repo.save(repo.create({
|
|
@@ -1208,34 +1349,22 @@ async function ensureCustomerForUser(dsOrEm, customerEntity, user, overrides) {
|
|
|
1208
1349
|
userId: user.id
|
|
1209
1350
|
}
|
|
1210
1351
|
});
|
|
1211
|
-
if (row)
|
|
1352
|
+
if (row) {
|
|
1353
|
+
return restoreCustomerRow(repo, row, user, name, email, resolveNextPhone(phone, row.phone));
|
|
1354
|
+
}
|
|
1212
1355
|
row = await repo.findOne({
|
|
1213
1356
|
where: {
|
|
1214
1357
|
email
|
|
1215
1358
|
}
|
|
1216
1359
|
});
|
|
1217
1360
|
if (row && (row.userId ?? user.id) === user.id) {
|
|
1218
|
-
return restoreCustomerRow(repo, row, user, name, email, phone);
|
|
1361
|
+
return restoreCustomerRow(repo, row, user, name, email, resolveNextPhone(phone, row.phone));
|
|
1219
1362
|
}
|
|
1220
1363
|
if (code === "23505") return null;
|
|
1221
1364
|
throw err;
|
|
1222
1365
|
}
|
|
1223
1366
|
}
|
|
1224
1367
|
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
1368
|
|
|
1240
1369
|
// src/lib/vendor-customer-contacts.ts
|
|
1241
1370
|
function isCustomerTypeContact(type) {
|
|
@@ -1328,8 +1457,27 @@ function resolveVendorIdForContactCheck(scope, bodyOrRow) {
|
|
|
1328
1457
|
return Number.isFinite(n) ? n : null;
|
|
1329
1458
|
}
|
|
1330
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");
|
|
1331
1472
|
async function ensureVendorCustomerForOrderContact(dataSource, entityMap, vendorId, contactId, details) {
|
|
1332
|
-
|
|
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;
|
|
1333
1481
|
const vcEntity = entityMap.vendor_customers;
|
|
1334
1482
|
const contactEntity = entityMap.contacts;
|
|
1335
1483
|
if (!vcEntity || !contactEntity) return;
|
|
@@ -1355,96 +1503,61 @@ async function ensureVendorCustomerForOrderContact(dataSource, entityMap, vendor
|
|
|
1355
1503
|
}
|
|
1356
1504
|
let customerId = null;
|
|
1357
1505
|
if (entityMap.customer) {
|
|
1358
|
-
const
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
}
|
|
1506
|
+
const ensured = await ensureCustomerRecord(dataSource, entityMap.customer, {
|
|
1507
|
+
name,
|
|
1508
|
+
email,
|
|
1509
|
+
phone,
|
|
1510
|
+
userId: null
|
|
1364
1511
|
});
|
|
1365
|
-
if (
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1512
|
+
if (ensured) customerId = ensured.id;
|
|
1513
|
+
}
|
|
1514
|
+
for (const vendorId of vendors) {
|
|
1515
|
+
if (customerId != null) {
|
|
1516
|
+
const byCustomer = await vcRepo.findOne({
|
|
1370
1517
|
where: {
|
|
1371
|
-
|
|
1372
|
-
|
|
1518
|
+
vendorId,
|
|
1519
|
+
customerId
|
|
1373
1520
|
}
|
|
1374
1521
|
});
|
|
1375
|
-
if (
|
|
1376
|
-
|
|
1377
|
-
if (
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
where: {
|
|
1381
|
-
name: "Customer",
|
|
1382
|
-
deleted: false
|
|
1383
|
-
}
|
|
1522
|
+
if (byCustomer) {
|
|
1523
|
+
const existingContactId = byCustomer.contactId;
|
|
1524
|
+
if (existingContactId == null) {
|
|
1525
|
+
await vcRepo.update(byCustomer.id, {
|
|
1526
|
+
contactId
|
|
1384
1527
|
});
|
|
1385
|
-
if (customerGroup) groupId = Number(customerGroup.id);
|
|
1386
1528
|
}
|
|
1387
|
-
|
|
1388
|
-
name,
|
|
1389
|
-
email,
|
|
1390
|
-
phone,
|
|
1391
|
-
password: null,
|
|
1392
|
-
blocked: false,
|
|
1393
|
-
groupId,
|
|
1394
|
-
adminAccess: false
|
|
1395
|
-
}));
|
|
1529
|
+
continue;
|
|
1396
1530
|
}
|
|
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
1531
|
}
|
|
1409
|
-
|
|
1410
|
-
if (customerId != null) {
|
|
1411
|
-
const byCustomer = await vcRepo.findOne({
|
|
1532
|
+
const byContact = await vcRepo.findOne({
|
|
1412
1533
|
where: {
|
|
1413
1534
|
vendorId,
|
|
1414
|
-
|
|
1535
|
+
contactId
|
|
1415
1536
|
}
|
|
1416
1537
|
});
|
|
1417
|
-
if (
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
contactId
|
|
1538
|
+
if (byContact) {
|
|
1539
|
+
if (customerId != null && byContact.customerId == null) {
|
|
1540
|
+
await vcRepo.update(byContact.id, {
|
|
1541
|
+
customerId
|
|
1422
1542
|
});
|
|
1423
1543
|
}
|
|
1424
|
-
|
|
1544
|
+
continue;
|
|
1425
1545
|
}
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
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
|
+
}));
|
|
1431
1557
|
}
|
|
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
1558
|
}
|
|
1442
|
-
await vcRepo.save(vcRepo.create({
|
|
1443
|
-
vendorId,
|
|
1444
|
-
contactId
|
|
1445
|
-
}));
|
|
1446
1559
|
}
|
|
1447
|
-
chunkUSNT2KNT_cjs.__name(
|
|
1560
|
+
chunkUSNT2KNT_cjs.__name(ensureVendorCustomersForOrder, "ensureVendorCustomersForOrder");
|
|
1448
1561
|
|
|
1449
1562
|
// src/lib/currency-prices.ts
|
|
1450
1563
|
function normalizeCurrencyCode(code) {
|
|
@@ -3810,23 +3923,24 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
3810
3923
|
if (resource === "vendor_customers" && entityMap["customer"]) {
|
|
3811
3924
|
const scope = await resolveVendorCustomersScope(dataSource, entityMap, resolveScope);
|
|
3812
3925
|
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);
|
|
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);
|
|
3814
3927
|
applyVendorScopeToQueryBuilder(qb, "vc", scope);
|
|
3815
3928
|
if (search && typeof search === "string" && search.trim()) {
|
|
3816
3929
|
const term = `%${search.trim()}%`;
|
|
3817
|
-
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)", {
|
|
3818
3931
|
term
|
|
3819
3932
|
});
|
|
3820
3933
|
}
|
|
3821
3934
|
const [rows, total2] = await qb.getManyAndCount();
|
|
3822
3935
|
const data2 = rows.map((row) => {
|
|
3823
3936
|
const customer = row.customer;
|
|
3937
|
+
const contact = row.contact;
|
|
3824
3938
|
return {
|
|
3825
3939
|
...row,
|
|
3826
|
-
name: customer?.name ?? null,
|
|
3827
|
-
email: customer?.email ?? null,
|
|
3828
|
-
phone: customer?.phone ?? null,
|
|
3829
|
-
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
|
|
3830
3944
|
};
|
|
3831
3945
|
});
|
|
3832
3946
|
return json({
|
|
@@ -4160,7 +4274,11 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4160
4274
|
} else if (resource === "collections") {
|
|
4161
4275
|
if (scope.type === "vendor") {
|
|
4162
4276
|
where = mergeVendorScopeIntoWhere(where, scope, resource, catalogFlags);
|
|
4163
|
-
} 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") {
|
|
4164
4282
|
where = mergeListWhereAnd(where, {
|
|
4165
4283
|
isCatalog: false
|
|
4166
4284
|
});
|
|
@@ -4357,41 +4475,17 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4357
4475
|
status: 503
|
|
4358
4476
|
});
|
|
4359
4477
|
}
|
|
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 {
|
|
4478
|
+
if (!entityMap["contacts"]) {
|
|
4385
4479
|
return json({
|
|
4386
|
-
error: "
|
|
4480
|
+
error: "Contacts entity not configured"
|
|
4387
4481
|
}, {
|
|
4388
4482
|
status: 503
|
|
4389
4483
|
});
|
|
4390
4484
|
}
|
|
4391
4485
|
const name = String(body.name ?? "").trim();
|
|
4392
|
-
const email = String(body.email ?? "").trim();
|
|
4393
|
-
const
|
|
4394
|
-
const
|
|
4486
|
+
const email = String(body.email ?? "").trim().toLowerCase();
|
|
4487
|
+
const phoneRaw = String(body.phone ?? "").trim();
|
|
4488
|
+
const phone = phoneRaw || null;
|
|
4395
4489
|
if (!name) return json({
|
|
4396
4490
|
error: "name is required"
|
|
4397
4491
|
}, {
|
|
@@ -4402,25 +4496,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4402
4496
|
}, {
|
|
4403
4497
|
status: 400
|
|
4404
4498
|
});
|
|
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
4499
|
const customerRepo = dataSource.getRepository(entityMap["customer"]);
|
|
4423
|
-
const userRepo = dataSource.getRepository(entityMap["users"]);
|
|
4424
4500
|
const dupCustEmail = await customerRepo.findOne({
|
|
4425
4501
|
where: {
|
|
4426
4502
|
email,
|
|
@@ -4434,49 +4510,26 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4434
4510
|
status: 409
|
|
4435
4511
|
});
|
|
4436
4512
|
}
|
|
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
|
|
4513
|
+
if (phone) {
|
|
4514
|
+
const dupCustPhone = await customerRepo.findOne({
|
|
4515
|
+
where: {
|
|
4516
|
+
phone,
|
|
4517
|
+
deleted: false
|
|
4518
|
+
}
|
|
4448
4519
|
});
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4520
|
+
if (dupCustPhone) {
|
|
4521
|
+
return json({
|
|
4522
|
+
error: "A customer with this phone number already exists"
|
|
4523
|
+
}, {
|
|
4524
|
+
status: 409
|
|
4525
|
+
});
|
|
4455
4526
|
}
|
|
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
4527
|
}
|
|
4473
|
-
const savedCustomer = await
|
|
4474
|
-
id: userId,
|
|
4528
|
+
const savedCustomer = await ensureCustomerRecord(dataSource, entityMap["customer"], {
|
|
4475
4529
|
name,
|
|
4476
4530
|
email,
|
|
4477
|
-
phone
|
|
4478
|
-
|
|
4479
|
-
phone
|
|
4531
|
+
phone,
|
|
4532
|
+
userId: null
|
|
4480
4533
|
});
|
|
4481
4534
|
if (!savedCustomer) {
|
|
4482
4535
|
return json({
|
|
@@ -4485,37 +4538,37 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4485
4538
|
status: 409
|
|
4486
4539
|
});
|
|
4487
4540
|
}
|
|
4488
|
-
const
|
|
4489
|
-
|
|
4541
|
+
const contactRepo = dataSource.getRepository(entityMap["contacts"]);
|
|
4542
|
+
let contact = await contactRepo.findOne({
|
|
4490
4543
|
where: {
|
|
4491
|
-
|
|
4544
|
+
email,
|
|
4492
4545
|
deleted: false
|
|
4493
4546
|
}
|
|
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
|
-
}
|
|
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
|
+
};
|
|
4518
4570
|
}
|
|
4571
|
+
const contactId = Number(contact.id);
|
|
4519
4572
|
const scope = await resolveVendorCustomersScope(dataSource, entityMap, resolveScope);
|
|
4520
4573
|
let vendorId = null;
|
|
4521
4574
|
if (scope.type === "vendor") {
|
|
@@ -4531,19 +4584,25 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4531
4584
|
status: 400
|
|
4532
4585
|
});
|
|
4533
4586
|
}
|
|
4534
|
-
|
|
4535
|
-
|
|
4587
|
+
await ensureVendorCustomersForOrder(dataSource, entityMap, [
|
|
4588
|
+
vendorId
|
|
4589
|
+
], contactId, {
|
|
4590
|
+
name,
|
|
4591
|
+
email,
|
|
4592
|
+
phone
|
|
4593
|
+
});
|
|
4594
|
+
const customerRow = await customerRepo.findOne({
|
|
4536
4595
|
where: {
|
|
4537
|
-
|
|
4596
|
+
id: savedCustomer.id,
|
|
4597
|
+
deleted: false
|
|
4538
4598
|
}
|
|
4539
4599
|
});
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
}
|
|
4546
|
-
return json(customerRow, {
|
|
4600
|
+
return json(customerRow ?? {
|
|
4601
|
+
id: savedCustomer.id,
|
|
4602
|
+
name,
|
|
4603
|
+
email,
|
|
4604
|
+
phone
|
|
4605
|
+
}, {
|
|
4547
4606
|
status: 201
|
|
4548
4607
|
});
|
|
4549
4608
|
}
|
|
@@ -4991,6 +5050,7 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4991
5050
|
}
|
|
4992
5051
|
const nameRaw = String(body["contact.name"] ?? contact.name ?? "").trim();
|
|
4993
5052
|
const phoneRaw = body["contact.phone"] ?? contact.phone;
|
|
5053
|
+
const emailForVc = (emailRaw || String(contact.email ?? "")).trim().toLowerCase();
|
|
4994
5054
|
const phoneToSave = phoneRaw == null || phoneRaw === "" ? null : String(phoneRaw).trim();
|
|
4995
5055
|
if (phoneToSave && contact.phone !== phoneToSave) {
|
|
4996
5056
|
await contactRepo.update(contact.id, {
|
|
@@ -4999,21 +5059,45 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4999
5059
|
contact.phone = phoneToSave;
|
|
5000
5060
|
}
|
|
5001
5061
|
const vendorIdForCustomer = resolveVendorIdForContactCheck(scopeCreate, persistBody);
|
|
5002
|
-
const
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
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,
|
|
5007
5083
|
phone: phoneRaw == null || phoneRaw === "" ? null : String(phoneRaw)
|
|
5008
5084
|
});
|
|
5009
|
-
}
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
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
|
+
}));
|
|
5017
5101
|
}
|
|
5018
5102
|
}
|
|
5019
5103
|
const randomPart = Math.floor(1e4 + Math.random() * 9e4);
|
|
@@ -6793,6 +6877,14 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6793
6877
|
}
|
|
6794
6878
|
}
|
|
6795
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
|
+
}
|
|
6796
6888
|
return json({
|
|
6797
6889
|
message: "Deleted successfully"
|
|
6798
6890
|
}, {
|
|
@@ -6823,6 +6915,20 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6823
6915
|
};
|
|
6824
6916
|
}
|
|
6825
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");
|
|
6826
6932
|
var VENDOR_INVITE_METADATA_TOKEN = "inviteToken";
|
|
6827
6933
|
var VENDOR_INVITE_METADATA_EXPIRES = "inviteExpiresAt";
|
|
6828
6934
|
var VENDOR_INVITE_METADATA_SENT = "inviteSentAt";
|
|
@@ -7555,6 +7661,50 @@ async function findLlmAgentByScope(dataSource, entityMap, scope, options = {}) {
|
|
|
7555
7661
|
}
|
|
7556
7662
|
chunkUSNT2KNT_cjs.__name(findLlmAgentByScope, "findLlmAgentByScope");
|
|
7557
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
|
+
|
|
7558
7708
|
// src/lib/media-folder-path.ts
|
|
7559
7709
|
function sanitizeMediaFolderPath(input) {
|
|
7560
7710
|
if (input == null) return "";
|
|
@@ -8948,6 +9098,17 @@ function createFormSaveHandlers(config) {
|
|
|
8948
9098
|
});
|
|
8949
9099
|
const fields = Array.isArray(body.fields) ? body.fields : [];
|
|
8950
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
|
+
}
|
|
8951
9112
|
const form = await formRepo().save(formRepo().create(formRow));
|
|
8952
9113
|
for (let i = 0; i < fields.length; i++) {
|
|
8953
9114
|
const row = normalizeFieldRow(fields[i], form.id);
|
|
@@ -8971,6 +9132,14 @@ function createFormSaveHandlers(config) {
|
|
|
8971
9132
|
status: 201
|
|
8972
9133
|
});
|
|
8973
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
|
+
}
|
|
8974
9143
|
return json({
|
|
8975
9144
|
error: "Server Error"
|
|
8976
9145
|
}, {
|
|
@@ -9019,6 +9188,20 @@ function createFormSaveHandlers(config) {
|
|
|
9019
9188
|
]) {
|
|
9020
9189
|
if (body[key] !== void 0) formRow[key] = body[key];
|
|
9021
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
|
+
}
|
|
9022
9205
|
if (Object.keys(formRow).length > 0) await formRepo().update(formId, formRow);
|
|
9023
9206
|
await fieldRepo().delete({
|
|
9024
9207
|
formId
|
|
@@ -9047,6 +9230,14 @@ function createFormSaveHandlers(config) {
|
|
|
9047
9230
|
status: 404
|
|
9048
9231
|
});
|
|
9049
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
|
+
}
|
|
9050
9241
|
return json({
|
|
9051
9242
|
error: "Server Error"
|
|
9052
9243
|
}, {
|
|
@@ -9628,6 +9819,7 @@ function createUsersApiHandlers(config) {
|
|
|
9628
9819
|
"id",
|
|
9629
9820
|
"name",
|
|
9630
9821
|
"email",
|
|
9822
|
+
"phone",
|
|
9631
9823
|
"blocked",
|
|
9632
9824
|
"createdAt",
|
|
9633
9825
|
"updatedAt",
|
|
@@ -9657,6 +9849,11 @@ function createUsersApiHandlers(config) {
|
|
|
9657
9849
|
}
|
|
9658
9850
|
try {
|
|
9659
9851
|
const uid = parseInt(id, 10);
|
|
9852
|
+
if (!Number.isFinite(uid)) return json({
|
|
9853
|
+
error: "Invalid id"
|
|
9854
|
+
}, {
|
|
9855
|
+
status: 400
|
|
9856
|
+
});
|
|
9660
9857
|
const existing = await userRepo().findOne({
|
|
9661
9858
|
where: {
|
|
9662
9859
|
id: uid,
|
|
@@ -9669,8 +9866,59 @@ function createUsersApiHandlers(config) {
|
|
|
9669
9866
|
status: 404
|
|
9670
9867
|
});
|
|
9671
9868
|
const body = await req.json();
|
|
9672
|
-
const
|
|
9673
|
-
|
|
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);
|
|
9674
9922
|
const updated = await userRepo().findOne({
|
|
9675
9923
|
where: {
|
|
9676
9924
|
id: uid,
|
|
@@ -9683,6 +9931,7 @@ function createUsersApiHandlers(config) {
|
|
|
9683
9931
|
"id",
|
|
9684
9932
|
"name",
|
|
9685
9933
|
"email",
|
|
9934
|
+
"phone",
|
|
9686
9935
|
"blocked",
|
|
9687
9936
|
"createdAt",
|
|
9688
9937
|
"updatedAt",
|
|
@@ -9694,7 +9943,8 @@ function createUsersApiHandlers(config) {
|
|
|
9694
9943
|
}, {
|
|
9695
9944
|
status: 404
|
|
9696
9945
|
});
|
|
9697
|
-
} catch {
|
|
9946
|
+
} catch (err) {
|
|
9947
|
+
console.error("[users.update]", err);
|
|
9698
9948
|
return json({
|
|
9699
9949
|
error: "Server Error"
|
|
9700
9950
|
}, {
|
|
@@ -12742,6 +12992,39 @@ function slugify(input) {
|
|
|
12742
12992
|
return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
12743
12993
|
}
|
|
12744
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");
|
|
12745
13028
|
function vendorOnboardErrorResponse(json, err) {
|
|
12746
13029
|
const msg = err instanceof Error ? err.message : String(err);
|
|
12747
13030
|
console.error("[vendor-onboard]", err);
|
|
@@ -12840,14 +13123,80 @@ function createVendorOnboardHandlers(config) {
|
|
|
12840
13123
|
chunkUSNT2KNT_cjs.__name(gateAdmin, "gateAdmin");
|
|
12841
13124
|
async function resolveActiveVendorId(u) {
|
|
12842
13125
|
const scope = chunkX6UQFV4X_cjs.resolveVendorScopeFromSessionUser(u);
|
|
12843
|
-
|
|
12844
|
-
if (scope.type === "
|
|
12845
|
-
|
|
12846
|
-
|
|
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
|
+
}
|
|
12847
13168
|
}
|
|
12848
13169
|
return null;
|
|
12849
13170
|
}
|
|
12850
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");
|
|
12851
13200
|
async function gateVendorTeam() {
|
|
12852
13201
|
const u = await getSessionUser();
|
|
12853
13202
|
if (!u?.email) return json({
|
|
@@ -12901,6 +13250,40 @@ function createVendorOnboardHandlers(config) {
|
|
|
12901
13250
|
}
|
|
12902
13251
|
chunkUSNT2KNT_cjs.__name(trySendVendorOnboardEmails, "trySendVendorOnboardEmails");
|
|
12903
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
|
+
},
|
|
12904
13287
|
/** POST /api/admin/vendors/onboard — create vendor + owner user + vendor_users + invite */
|
|
12905
13288
|
async onboard(req) {
|
|
12906
13289
|
const err = await gateAdmin();
|
|
@@ -12969,6 +13352,7 @@ function createVendorOnboardHandlers(config) {
|
|
|
12969
13352
|
}
|
|
12970
13353
|
});
|
|
12971
13354
|
if (dupVendor) throw new Error("VENDOR_SLUG_EXISTS");
|
|
13355
|
+
await retireSoftDeletedUniqueValue(vendorRepo, "slug", slug);
|
|
12972
13356
|
let ownerGroup = await groupRepo.findOne({
|
|
12973
13357
|
where: {
|
|
12974
13358
|
name: chunkX6UQFV4X_cjs.VENDOR_OWNER_GROUP_NAME,
|
|
@@ -12997,8 +13381,15 @@ function createVendorOnboardHandlers(config) {
|
|
|
12997
13381
|
email: userEmail
|
|
12998
13382
|
}
|
|
12999
13383
|
});
|
|
13000
|
-
if (existingUser && !existingUser.deleted)
|
|
13001
|
-
|
|
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 () => {
|
|
13002
13393
|
await userRepo.update(existingUser.id, {
|
|
13003
13394
|
deleted: false,
|
|
13004
13395
|
deletedAt: null,
|
|
@@ -16081,10 +16472,12 @@ exports.Customer = class Customer {
|
|
|
16081
16472
|
chunkUSNT2KNT_cjs.__name(this, "Customer");
|
|
16082
16473
|
}
|
|
16083
16474
|
id;
|
|
16475
|
+
/** Set only when the customer can log in (linked `users` row). Admin/guest customers stay null. */
|
|
16084
16476
|
userId;
|
|
16085
16477
|
user;
|
|
16086
16478
|
name;
|
|
16087
16479
|
email;
|
|
16480
|
+
/** Optional; multiple customers may have null (PostgreSQL UNIQUE allows multiple NULLs). */
|
|
16088
16481
|
phone;
|
|
16089
16482
|
createdAt;
|
|
16090
16483
|
updatedAt;
|
|
@@ -16099,8 +16492,10 @@ _ts_decorate18([
|
|
|
16099
16492
|
_ts_metadata18("design:type", Number)
|
|
16100
16493
|
], exports.Customer.prototype, "id", void 0);
|
|
16101
16494
|
_ts_decorate18([
|
|
16102
|
-
typeorm.Column("int"
|
|
16103
|
-
|
|
16495
|
+
typeorm.Column("int", {
|
|
16496
|
+
nullable: true
|
|
16497
|
+
}),
|
|
16498
|
+
_ts_metadata18("design:type", Object)
|
|
16104
16499
|
], exports.Customer.prototype, "userId", void 0);
|
|
16105
16500
|
_ts_decorate18([
|
|
16106
16501
|
typeorm.ManyToOne(() => exports.User, {
|
|
@@ -16123,9 +16518,10 @@ _ts_decorate18([
|
|
|
16123
16518
|
], exports.Customer.prototype, "email", void 0);
|
|
16124
16519
|
_ts_decorate18([
|
|
16125
16520
|
typeorm.Column("varchar", {
|
|
16126
|
-
unique: true
|
|
16521
|
+
unique: true,
|
|
16522
|
+
nullable: true
|
|
16127
16523
|
}),
|
|
16128
|
-
_ts_metadata18("design:type",
|
|
16524
|
+
_ts_metadata18("design:type", Object)
|
|
16129
16525
|
], exports.Customer.prototype, "phone", void 0);
|
|
16130
16526
|
_ts_decorate18([
|
|
16131
16527
|
typeorm.Column({
|
|
@@ -26709,6 +27105,14 @@ function createCmsApiHandler(config) {
|
|
|
26709
27105
|
});
|
|
26710
27106
|
return vendorHandlers.switchVendor(req);
|
|
26711
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
|
+
}
|
|
26712
27116
|
if (path2[0] === "admin" && path2[1] === "vendor" && path2[2] === "roles" && vendorRolesHandlers) {
|
|
26713
27117
|
if (path2.length === 3 && m === "GET") return vendorRolesHandlers.list();
|
|
26714
27118
|
if (path2.length === 3 && m === "POST") return vendorRolesHandlers.create(req);
|
|
@@ -29178,13 +29582,36 @@ function createStorefrontApiHandler(config) {
|
|
|
29178
29582
|
status: 400
|
|
29179
29583
|
};
|
|
29180
29584
|
}
|
|
29585
|
+
const list = [
|
|
29586
|
+
...vendorIds
|
|
29587
|
+
];
|
|
29181
29588
|
return {
|
|
29182
|
-
vendorId: [
|
|
29183
|
-
|
|
29184
|
-
][0]
|
|
29589
|
+
vendorId: list[0],
|
|
29590
|
+
vendorIds: list
|
|
29185
29591
|
};
|
|
29186
29592
|
}
|
|
29187
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");
|
|
29188
29615
|
function roundMoney3(n) {
|
|
29189
29616
|
return Math.round(n * 100) / 100;
|
|
29190
29617
|
}
|
|
@@ -31506,6 +31933,7 @@ function createStorefrontApiHandler(config) {
|
|
|
31506
31933
|
taxCode: line.taxCode
|
|
31507
31934
|
}));
|
|
31508
31935
|
}
|
|
31936
|
+
await linkOrderContactToVendors(contactId, vendorRes.vendorIds);
|
|
31509
31937
|
fireOrderPlacedNotification(oid);
|
|
31510
31938
|
return json({
|
|
31511
31939
|
orderId: oid,
|
|
@@ -31578,6 +32006,7 @@ function createStorefrontApiHandler(config) {
|
|
|
31578
32006
|
taxCode: line.taxCode
|
|
31579
32007
|
}));
|
|
31580
32008
|
}
|
|
32009
|
+
await linkOrderContactToVendors(contactId, vendorResChk.vendorIds);
|
|
31581
32010
|
await cartItemRepo().delete({
|
|
31582
32011
|
cartId: cart.id
|
|
31583
32012
|
});
|
|
@@ -31886,13 +32315,16 @@ exports.createUserProfileHandler = createUserProfileHandler;
|
|
|
31886
32315
|
exports.createUsersApiHandlers = createUsersApiHandlers;
|
|
31887
32316
|
exports.createVendorDashboardHandler = createVendorDashboardHandler;
|
|
31888
32317
|
exports.createVendorOnboardHandlers = createVendorOnboardHandlers;
|
|
32318
|
+
exports.customerPhoneForEmail = customerPhoneForEmail;
|
|
31889
32319
|
exports.customerPhoneForUser = customerPhoneForUser;
|
|
31890
32320
|
exports.daysBeforeEventStart = daysBeforeEventStart;
|
|
31891
32321
|
exports.describeEventTierPolicy = describeEventTierPolicy;
|
|
31892
32322
|
exports.ensureCustomerForUser = ensureCustomerForUser;
|
|
32323
|
+
exports.ensureCustomerRecord = ensureCustomerRecord;
|
|
31893
32324
|
exports.ensureMessagingPluginsOnCms = ensureMessagingPluginsOnCms;
|
|
31894
32325
|
exports.ensureScheduleQueueWorker = ensureScheduleQueueWorker;
|
|
31895
32326
|
exports.ensureVendorCustomerForOrderContact = ensureVendorCustomerForOrderContact;
|
|
32327
|
+
exports.ensureVendorCustomersForOrder = ensureVendorCustomersForOrder;
|
|
31896
32328
|
exports.findActiveRefundPolicyForVendor = findActiveRefundPolicyForVendor;
|
|
31897
32329
|
exports.findVendorByInviteToken = findVendorByInviteToken;
|
|
31898
32330
|
exports.formatTierRange = formatTierRange;
|
|
@@ -31910,6 +32342,7 @@ exports.invalidateRequireEventApprovalCache = invalidateRequireEventApprovalCach
|
|
|
31910
32342
|
exports.invalidateRequireProductApprovalCache = invalidateRequireProductApprovalCache;
|
|
31911
32343
|
exports.invalidateVendorCatalogCreateFlagsCache = invalidateVendorCatalogCreateFlagsCache;
|
|
31912
32344
|
exports.isCustomerTypeContact = isCustomerTypeContact;
|
|
32345
|
+
exports.isSyntheticCustomerPhone = isSyntheticCustomerPhone;
|
|
31913
32346
|
exports.isZipMedia = isZipMedia;
|
|
31914
32347
|
exports.linkUnclaimedContactToUser = linkUnclaimedContactToUser;
|
|
31915
32348
|
exports.llmAgentToChatAgentOptions = llmAgentToChatAgentOptions;
|
|
@@ -31921,6 +32354,7 @@ exports.metaFetchUserManagedPages = metaFetchUserManagedPages;
|
|
|
31921
32354
|
exports.metaPostPageFeed = metaPostPageFeed;
|
|
31922
32355
|
exports.metaPostPagePhoto = metaPostPagePhoto;
|
|
31923
32356
|
exports.metaResolvePageAccessToken = metaResolvePageAccessToken;
|
|
32357
|
+
exports.normalizeCustomerPhone = normalizeCustomerPhone;
|
|
31924
32358
|
exports.normalizePhoneE164 = normalizePhoneE164;
|
|
31925
32359
|
exports.normalizeRefundTiers = normalizeRefundTiers;
|
|
31926
32360
|
exports.overlayCmsPlugins = overlayCmsPlugins;
|