@infuro/cms-core 1.0.53 → 1.0.55
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 +86 -21
- package/dist/admin.js +86 -21
- package/dist/api.cjs +32 -32
- package/dist/api.js +1 -1
- package/dist/{chunk-3BPD5NGU.cjs → chunk-JGR4ZUON.cjs} +190 -14
- package/dist/{chunk-UO5Q5RXB.js → chunk-LI3CUI54.js} +190 -14
- package/dist/index.cjs +385 -224
- package/dist/index.js +174 -13
- package/package.json +1 -1
|
@@ -1914,6 +1914,32 @@ async function ensureUniqueProductSlug(repo, baseSlug, vendorId, excludeId) {
|
|
|
1914
1914
|
}
|
|
1915
1915
|
}
|
|
1916
1916
|
chunkUSNT2KNT_cjs.__name(ensureUniqueProductSlug, "ensureUniqueProductSlug");
|
|
1917
|
+
function isSlugUniqueViolation(err) {
|
|
1918
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1919
|
+
return /duplicate key|unique constraint/i.test(msg) && /slug/i.test(msg);
|
|
1920
|
+
}
|
|
1921
|
+
chunkUSNT2KNT_cjs.__name(isSlugUniqueViolation, "isSlugUniqueViolation");
|
|
1922
|
+
async function assertUniqueEventSlug(repo, slugRaw, vendorId, excludeId) {
|
|
1923
|
+
const slug = typeof slugRaw === "string" ? slugRaw.trim() : "";
|
|
1924
|
+
if (!slug) return "Slug is required";
|
|
1925
|
+
await chunkOY2YTBMP_cjs.retireSoftDeletedUniqueValue(repo, "slug", slug);
|
|
1926
|
+
const where = excludeId != null ? {
|
|
1927
|
+
slug,
|
|
1928
|
+
vendorId,
|
|
1929
|
+
deleted: false,
|
|
1930
|
+
id: typeorm.Not(excludeId)
|
|
1931
|
+
} : {
|
|
1932
|
+
slug,
|
|
1933
|
+
vendorId,
|
|
1934
|
+
deleted: false
|
|
1935
|
+
};
|
|
1936
|
+
const dup = await repo.findOne({
|
|
1937
|
+
where
|
|
1938
|
+
});
|
|
1939
|
+
if (dup) return "An event with this slug already exists";
|
|
1940
|
+
return null;
|
|
1941
|
+
}
|
|
1942
|
+
chunkUSNT2KNT_cjs.__name(assertUniqueEventSlug, "assertUniqueEventSlug");
|
|
1917
1943
|
async function normalizeComboNameAndSlug(repo, body, vendorId, existing, excludeId) {
|
|
1918
1944
|
const incomingName = typeof body.name === "string" ? body.name.trim() : "";
|
|
1919
1945
|
const incomingSlugRaw = typeof body.slug === "string" ? body.slug.trim() : "";
|
|
@@ -4784,6 +4810,17 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4784
4810
|
status: 400
|
|
4785
4811
|
});
|
|
4786
4812
|
}
|
|
4813
|
+
if (resource === "events") {
|
|
4814
|
+
const vendorIdForSlug = scopeCreate.type === "vendor" ? scopeCreate.vendorId : Number(persistBody.vendorId);
|
|
4815
|
+
if (Number.isFinite(vendorIdForSlug) && vendorIdForSlug > 0) {
|
|
4816
|
+
const eventSlugErr = await assertUniqueEventSlug(repo, persistBody.slug, vendorIdForSlug);
|
|
4817
|
+
if (eventSlugErr) return json({
|
|
4818
|
+
error: eventSlugErr
|
|
4819
|
+
}, {
|
|
4820
|
+
status: 400
|
|
4821
|
+
});
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4787
4824
|
sanitizeBodyForEntity(repo, persistBody);
|
|
4788
4825
|
let created;
|
|
4789
4826
|
try {
|
|
@@ -5063,6 +5100,13 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5063
5100
|
}
|
|
5064
5101
|
} catch (err) {
|
|
5065
5102
|
const message = err instanceof Error ? err.message : String(err);
|
|
5103
|
+
if (resource === "events" && isSlugUniqueViolation(err)) {
|
|
5104
|
+
return json({
|
|
5105
|
+
error: "An event with this slug already exists"
|
|
5106
|
+
}, {
|
|
5107
|
+
status: 400
|
|
5108
|
+
});
|
|
5109
|
+
}
|
|
5066
5110
|
logCrudServerError("POST create save failed", {
|
|
5067
5111
|
resource,
|
|
5068
5112
|
message,
|
|
@@ -6339,6 +6383,17 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6339
6383
|
});
|
|
6340
6384
|
}
|
|
6341
6385
|
}
|
|
6386
|
+
if ("slug" in updatePayload) {
|
|
6387
|
+
const vendorIdForSlug = scopePut.type === "vendor" ? scopePut.vendorId : Number(currentEvent.vendorId);
|
|
6388
|
+
if (Number.isFinite(vendorIdForSlug) && vendorIdForSlug > 0) {
|
|
6389
|
+
const eventSlugErr = await assertUniqueEventSlug(repo, updatePayload.slug, vendorIdForSlug, numericId);
|
|
6390
|
+
if (eventSlugErr) return json({
|
|
6391
|
+
error: eventSlugErr
|
|
6392
|
+
}, {
|
|
6393
|
+
status: 400
|
|
6394
|
+
});
|
|
6395
|
+
}
|
|
6396
|
+
}
|
|
6342
6397
|
}
|
|
6343
6398
|
if (resource === "product_categories" && scopePut.type === "all") {
|
|
6344
6399
|
const existingCatalogCat = await repo.findOne({
|
|
@@ -6502,7 +6557,18 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6502
6557
|
}
|
|
6503
6558
|
sanitizeBodyForEntity(repo, updatePayload);
|
|
6504
6559
|
await retireSoftDeletedUniquesFromBody(repo, updatePayload);
|
|
6505
|
-
|
|
6560
|
+
try {
|
|
6561
|
+
await repo.update(numericId, updatePayload);
|
|
6562
|
+
} catch (err) {
|
|
6563
|
+
if (resource === "events" && isSlugUniqueViolation(err)) {
|
|
6564
|
+
return json({
|
|
6565
|
+
error: "An event with this slug already exists"
|
|
6566
|
+
}, {
|
|
6567
|
+
status: 400
|
|
6568
|
+
});
|
|
6569
|
+
}
|
|
6570
|
+
throw err;
|
|
6571
|
+
}
|
|
6506
6572
|
}
|
|
6507
6573
|
if (resource === "orders" && rawBody && entityMap["order_addresses"]) {
|
|
6508
6574
|
const addressRawScalar = String(rawBody["contact.address"] ?? "").trim();
|
|
@@ -8695,11 +8761,21 @@ function createUploadHandler(config) {
|
|
|
8695
8761
|
const storageService = raw instanceof Promise ? await raw : raw;
|
|
8696
8762
|
if (storageService) {
|
|
8697
8763
|
const fileUrl = await storageService.upload(buffer, `uploads/${relativeUnderUploads}`, contentType);
|
|
8764
|
+
console.info("[upload] stored via storage plugin", {
|
|
8765
|
+
key: `uploads/${relativeUnderUploads}`,
|
|
8766
|
+
contentType,
|
|
8767
|
+
bytes: buffer.length,
|
|
8768
|
+
fileUrl
|
|
8769
|
+
});
|
|
8698
8770
|
return json({
|
|
8699
8771
|
filePath: fileUrl,
|
|
8700
8772
|
parentId
|
|
8701
8773
|
});
|
|
8702
8774
|
}
|
|
8775
|
+
console.warn("[upload] no storage plugin \u2014 writing local disk (broken on most deploys)", {
|
|
8776
|
+
localUploadDir,
|
|
8777
|
+
key: relativeUnderUploads
|
|
8778
|
+
});
|
|
8703
8779
|
const fs2 = await import('fs/promises');
|
|
8704
8780
|
const path2 = await import('path');
|
|
8705
8781
|
const dir = path2.join(process.cwd(), localUploadDir);
|
|
@@ -8715,11 +8791,13 @@ function createUploadHandler(config) {
|
|
|
8715
8791
|
});
|
|
8716
8792
|
} catch (err) {
|
|
8717
8793
|
const message = err instanceof Error ? err.message : String(err);
|
|
8794
|
+
const awsMeta = err && typeof err === "object" && "$metadata" in err ? err.$metadata : void 0;
|
|
8718
8795
|
console.error("[upload] File upload failed", {
|
|
8719
8796
|
error: message,
|
|
8720
8797
|
stack: err instanceof Error ? err.stack : void 0,
|
|
8721
8798
|
name: err instanceof Error ? err.name : void 0,
|
|
8722
|
-
|
|
8799
|
+
code: err && typeof err === "object" && ("Code" in err || "code" in err) ? err.Code ?? err.code : void 0,
|
|
8800
|
+
metadata: awsMeta
|
|
8723
8801
|
});
|
|
8724
8802
|
if (/Failed to parse body as FormData/i.test(message)) {
|
|
8725
8803
|
return json({
|
|
@@ -8729,7 +8807,8 @@ function createUploadHandler(config) {
|
|
|
8729
8807
|
});
|
|
8730
8808
|
}
|
|
8731
8809
|
return json({
|
|
8732
|
-
error: "File upload failed"
|
|
8810
|
+
error: "File upload failed",
|
|
8811
|
+
details: message
|
|
8733
8812
|
}, {
|
|
8734
8813
|
status: 500
|
|
8735
8814
|
});
|
|
@@ -30870,9 +30949,51 @@ function createStorefrontApiHandler(config) {
|
|
|
30870
30949
|
"items.product.taxes",
|
|
30871
30950
|
"items.product.taxes.tax"
|
|
30872
30951
|
];
|
|
30873
|
-
function
|
|
30952
|
+
function comboIdFromCartItem(it) {
|
|
30953
|
+
const meta = it.metadata && typeof it.metadata === "object" && !Array.isArray(it.metadata) ? it.metadata : {};
|
|
30954
|
+
const fromMeta = Number(meta.comboId ?? meta.combo_id);
|
|
30955
|
+
if (Number.isInteger(fromMeta) && fromMeta > 0) return fromMeta;
|
|
30956
|
+
if (meta.isCombo === true || meta.type === "combo" || meta.lineType === "combo") {
|
|
30957
|
+
const pid = Number(it.productId);
|
|
30958
|
+
if (Number.isInteger(pid) && pid > 0) return pid;
|
|
30959
|
+
}
|
|
30960
|
+
return null;
|
|
30961
|
+
}
|
|
30962
|
+
chunkUSNT2KNT_cjs.__name(comboIdFromCartItem, "comboIdFromCartItem");
|
|
30963
|
+
async function resolveSingleVendorIdFromCart(cart) {
|
|
30874
30964
|
const vendorIds = /* @__PURE__ */ new Set();
|
|
30965
|
+
const comboRepo = entityMap.combos ? dataSource.getRepository(entityMap.combos) : null;
|
|
30966
|
+
const comboVendorCache = /* @__PURE__ */ new Map();
|
|
30967
|
+
async function vendorIdForCombo(comboId) {
|
|
30968
|
+
if (comboVendorCache.has(comboId)) return comboVendorCache.get(comboId);
|
|
30969
|
+
if (!comboRepo) return null;
|
|
30970
|
+
const combo = await comboRepo.findOne({
|
|
30971
|
+
where: {
|
|
30972
|
+
id: comboId,
|
|
30973
|
+
deleted: false
|
|
30974
|
+
},
|
|
30975
|
+
select: [
|
|
30976
|
+
"id",
|
|
30977
|
+
"vendorId"
|
|
30978
|
+
]
|
|
30979
|
+
});
|
|
30980
|
+
const vid = Number(combo?.vendorId);
|
|
30981
|
+
if (Number.isInteger(vid) && vid > 0) {
|
|
30982
|
+
comboVendorCache.set(comboId, vid);
|
|
30983
|
+
return vid;
|
|
30984
|
+
}
|
|
30985
|
+
return null;
|
|
30986
|
+
}
|
|
30987
|
+
chunkUSNT2KNT_cjs.__name(vendorIdForCombo, "vendorIdForCombo");
|
|
30875
30988
|
for (const it of cart.items || []) {
|
|
30989
|
+
const comboId = comboIdFromCartItem(it);
|
|
30990
|
+
if (comboId != null) {
|
|
30991
|
+
const comboVendorId = await vendorIdForCombo(comboId);
|
|
30992
|
+
if (comboVendorId != null) {
|
|
30993
|
+
vendorIds.add(comboVendorId);
|
|
30994
|
+
continue;
|
|
30995
|
+
}
|
|
30996
|
+
}
|
|
30876
30997
|
const p = it.product;
|
|
30877
30998
|
if (!p || p.deleted || p.status !== "available") continue;
|
|
30878
30999
|
const vid = Number(p.vendorId);
|
|
@@ -33198,7 +33319,7 @@ function createStorefrontApiHandler(config) {
|
|
|
33198
33319
|
}, {
|
|
33199
33320
|
status: prepOrd.status
|
|
33200
33321
|
});
|
|
33201
|
-
const vendorRes = resolveSingleVendorIdFromCart(cart);
|
|
33322
|
+
const vendorRes = await resolveSingleVendorIdFromCart(cart);
|
|
33202
33323
|
if ("error" in vendorRes) return json({
|
|
33203
33324
|
error: vendorRes.error
|
|
33204
33325
|
}, {
|
|
@@ -33274,7 +33395,7 @@ function createStorefrontApiHandler(config) {
|
|
|
33274
33395
|
}, {
|
|
33275
33396
|
status: prepChk.status
|
|
33276
33397
|
});
|
|
33277
|
-
const vendorResChk = resolveSingleVendorIdFromCart(cart);
|
|
33398
|
+
const vendorResChk = await resolveSingleVendorIdFromCart(cart);
|
|
33278
33399
|
if ("error" in vendorResChk) return json({
|
|
33279
33400
|
error: vendorResChk.error
|
|
33280
33401
|
}, {
|
|
@@ -33344,17 +33465,48 @@ function createStorefrontApiHandler(config) {
|
|
|
33344
33465
|
if (!contact) return json({
|
|
33345
33466
|
orders: []
|
|
33346
33467
|
});
|
|
33347
|
-
|
|
33348
|
-
|
|
33349
|
-
|
|
33350
|
-
|
|
33351
|
-
|
|
33352
|
-
|
|
33468
|
+
let linkedCustomerContactIds = [];
|
|
33469
|
+
if (entityMap.customer && entityMap.customer_contacts) {
|
|
33470
|
+
const rows = await dataSource.query(`SELECT cc.id
|
|
33471
|
+
FROM customer_contacts cc
|
|
33472
|
+
JOIN customer c ON c.id = cc."customerId"
|
|
33473
|
+
WHERE c."userId" = $1`, [
|
|
33474
|
+
uid
|
|
33475
|
+
]);
|
|
33476
|
+
linkedCustomerContactIds = rows.map((row) => Number(row.id)).filter((id) => Number.isFinite(id) && id > 0);
|
|
33477
|
+
}
|
|
33478
|
+
const visibleOrders = await orderRepo().find({
|
|
33479
|
+
where: [
|
|
33480
|
+
{
|
|
33481
|
+
contactId: contact.id,
|
|
33482
|
+
deleted: false,
|
|
33483
|
+
orderKind: "sale"
|
|
33484
|
+
},
|
|
33485
|
+
...linkedCustomerContactIds.length ? [
|
|
33486
|
+
{
|
|
33487
|
+
customerContactId: typeorm.In(linkedCustomerContactIds),
|
|
33488
|
+
deleted: false,
|
|
33489
|
+
orderKind: "sale"
|
|
33490
|
+
}
|
|
33491
|
+
] : []
|
|
33492
|
+
],
|
|
33353
33493
|
order: {
|
|
33354
33494
|
createdAt: "DESC"
|
|
33355
33495
|
},
|
|
33356
33496
|
take: 50
|
|
33357
33497
|
});
|
|
33498
|
+
const orders = visibleOrders.filter((o) => {
|
|
33499
|
+
const row = o;
|
|
33500
|
+
const orderContactId = Number(row.contactId);
|
|
33501
|
+
const customerContactId = Number(row.customerContactId);
|
|
33502
|
+
if (Number.isFinite(orderContactId) && orderContactId > 0 && orderContactId === Number(contact.id)) {
|
|
33503
|
+
return true;
|
|
33504
|
+
}
|
|
33505
|
+
if (Number.isFinite(customerContactId) && customerContactId > 0) {
|
|
33506
|
+
return linkedCustomerContactIds.includes(customerContactId);
|
|
33507
|
+
}
|
|
33508
|
+
return false;
|
|
33509
|
+
});
|
|
33358
33510
|
const orderIds = orders.map((o) => o.id);
|
|
33359
33511
|
const previewByOrder = {};
|
|
33360
33512
|
if (orderIds.length) {
|
|
@@ -33447,10 +33599,19 @@ function createStorefrontApiHandler(config) {
|
|
|
33447
33599
|
status: 404
|
|
33448
33600
|
});
|
|
33449
33601
|
const orderId = parseInt(path2[1], 10);
|
|
33602
|
+
let linkedCustomerContactIds = [];
|
|
33603
|
+
if (entityMap.customer && entityMap.customer_contacts) {
|
|
33604
|
+
const rows = await dataSource.query(`SELECT cc.id
|
|
33605
|
+
FROM customer_contacts cc
|
|
33606
|
+
JOIN customer c ON c.id = cc."customerId"
|
|
33607
|
+
WHERE c."userId" = $1`, [
|
|
33608
|
+
uid
|
|
33609
|
+
]);
|
|
33610
|
+
linkedCustomerContactIds = rows.map((row) => Number(row.id)).filter((id) => Number.isFinite(id) && id > 0);
|
|
33611
|
+
}
|
|
33450
33612
|
let order = await orderRepo().findOne({
|
|
33451
33613
|
where: {
|
|
33452
33614
|
id: orderId,
|
|
33453
|
-
contactId: contact.id,
|
|
33454
33615
|
deleted: false
|
|
33455
33616
|
},
|
|
33456
33617
|
relations: [
|
|
@@ -33463,13 +33624,20 @@ function createStorefrontApiHandler(config) {
|
|
|
33463
33624
|
}, {
|
|
33464
33625
|
status: 404
|
|
33465
33626
|
});
|
|
33627
|
+
const orderContactId = Number(order.contactId);
|
|
33628
|
+
const orderCustomerContactId = Number(order.customerContactId);
|
|
33629
|
+
const isOwner = Number.isFinite(orderContactId) && orderContactId > 0 && orderContactId === Number(contact.id) || Number.isFinite(orderCustomerContactId) && orderCustomerContactId > 0 && linkedCustomerContactIds.includes(orderCustomerContactId);
|
|
33630
|
+
if (!isOwner) return json({
|
|
33631
|
+
error: "Not found"
|
|
33632
|
+
}, {
|
|
33633
|
+
status: 404
|
|
33634
|
+
});
|
|
33466
33635
|
if (getCms) {
|
|
33467
33636
|
const cms = await getCms();
|
|
33468
33637
|
await tryRefreshOrderFromErpForStorefront(cms, dataSource, entityMap, order);
|
|
33469
33638
|
order = await orderRepo().findOne({
|
|
33470
33639
|
where: {
|
|
33471
33640
|
id: orderId,
|
|
33472
|
-
contactId: contact.id,
|
|
33473
33641
|
deleted: false
|
|
33474
33642
|
},
|
|
33475
33643
|
relations: [
|
|
@@ -33483,6 +33651,14 @@ function createStorefrontApiHandler(config) {
|
|
|
33483
33651
|
}, {
|
|
33484
33652
|
status: 404
|
|
33485
33653
|
});
|
|
33654
|
+
const refreshedOrderContactId = Number(order.contactId);
|
|
33655
|
+
const refreshedCustomerContactId = Number(order.customerContactId);
|
|
33656
|
+
const isOwnerAfterRefresh = Number.isFinite(refreshedOrderContactId) && refreshedOrderContactId > 0 && refreshedOrderContactId === Number(contact.id) || Number.isFinite(refreshedCustomerContactId) && refreshedCustomerContactId > 0 && linkedCustomerContactIds.includes(refreshedCustomerContactId);
|
|
33657
|
+
if (!isOwnerAfterRefresh) return json({
|
|
33658
|
+
error: "Not found"
|
|
33659
|
+
}, {
|
|
33660
|
+
status: 404
|
|
33661
|
+
});
|
|
33486
33662
|
const o = order;
|
|
33487
33663
|
const lines = (o.items || []).map((line) => {
|
|
33488
33664
|
const p = line.product;
|
|
@@ -1904,6 +1904,32 @@ async function ensureUniqueProductSlug(repo, baseSlug, vendorId, excludeId) {
|
|
|
1904
1904
|
}
|
|
1905
1905
|
}
|
|
1906
1906
|
__name(ensureUniqueProductSlug, "ensureUniqueProductSlug");
|
|
1907
|
+
function isSlugUniqueViolation(err) {
|
|
1908
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1909
|
+
return /duplicate key|unique constraint/i.test(msg) && /slug/i.test(msg);
|
|
1910
|
+
}
|
|
1911
|
+
__name(isSlugUniqueViolation, "isSlugUniqueViolation");
|
|
1912
|
+
async function assertUniqueEventSlug(repo, slugRaw, vendorId, excludeId) {
|
|
1913
|
+
const slug = typeof slugRaw === "string" ? slugRaw.trim() : "";
|
|
1914
|
+
if (!slug) return "Slug is required";
|
|
1915
|
+
await retireSoftDeletedUniqueValue(repo, "slug", slug);
|
|
1916
|
+
const where = excludeId != null ? {
|
|
1917
|
+
slug,
|
|
1918
|
+
vendorId,
|
|
1919
|
+
deleted: false,
|
|
1920
|
+
id: Not(excludeId)
|
|
1921
|
+
} : {
|
|
1922
|
+
slug,
|
|
1923
|
+
vendorId,
|
|
1924
|
+
deleted: false
|
|
1925
|
+
};
|
|
1926
|
+
const dup = await repo.findOne({
|
|
1927
|
+
where
|
|
1928
|
+
});
|
|
1929
|
+
if (dup) return "An event with this slug already exists";
|
|
1930
|
+
return null;
|
|
1931
|
+
}
|
|
1932
|
+
__name(assertUniqueEventSlug, "assertUniqueEventSlug");
|
|
1907
1933
|
async function normalizeComboNameAndSlug(repo, body, vendorId, existing, excludeId) {
|
|
1908
1934
|
const incomingName = typeof body.name === "string" ? body.name.trim() : "";
|
|
1909
1935
|
const incomingSlugRaw = typeof body.slug === "string" ? body.slug.trim() : "";
|
|
@@ -4774,6 +4800,17 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4774
4800
|
status: 400
|
|
4775
4801
|
});
|
|
4776
4802
|
}
|
|
4803
|
+
if (resource === "events") {
|
|
4804
|
+
const vendorIdForSlug = scopeCreate.type === "vendor" ? scopeCreate.vendorId : Number(persistBody.vendorId);
|
|
4805
|
+
if (Number.isFinite(vendorIdForSlug) && vendorIdForSlug > 0) {
|
|
4806
|
+
const eventSlugErr = await assertUniqueEventSlug(repo, persistBody.slug, vendorIdForSlug);
|
|
4807
|
+
if (eventSlugErr) return json({
|
|
4808
|
+
error: eventSlugErr
|
|
4809
|
+
}, {
|
|
4810
|
+
status: 400
|
|
4811
|
+
});
|
|
4812
|
+
}
|
|
4813
|
+
}
|
|
4777
4814
|
sanitizeBodyForEntity(repo, persistBody);
|
|
4778
4815
|
let created;
|
|
4779
4816
|
try {
|
|
@@ -5053,6 +5090,13 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
5053
5090
|
}
|
|
5054
5091
|
} catch (err) {
|
|
5055
5092
|
const message = err instanceof Error ? err.message : String(err);
|
|
5093
|
+
if (resource === "events" && isSlugUniqueViolation(err)) {
|
|
5094
|
+
return json({
|
|
5095
|
+
error: "An event with this slug already exists"
|
|
5096
|
+
}, {
|
|
5097
|
+
status: 400
|
|
5098
|
+
});
|
|
5099
|
+
}
|
|
5056
5100
|
logCrudServerError("POST create save failed", {
|
|
5057
5101
|
resource,
|
|
5058
5102
|
message,
|
|
@@ -6329,6 +6373,17 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6329
6373
|
});
|
|
6330
6374
|
}
|
|
6331
6375
|
}
|
|
6376
|
+
if ("slug" in updatePayload) {
|
|
6377
|
+
const vendorIdForSlug = scopePut.type === "vendor" ? scopePut.vendorId : Number(currentEvent.vendorId);
|
|
6378
|
+
if (Number.isFinite(vendorIdForSlug) && vendorIdForSlug > 0) {
|
|
6379
|
+
const eventSlugErr = await assertUniqueEventSlug(repo, updatePayload.slug, vendorIdForSlug, numericId);
|
|
6380
|
+
if (eventSlugErr) return json({
|
|
6381
|
+
error: eventSlugErr
|
|
6382
|
+
}, {
|
|
6383
|
+
status: 400
|
|
6384
|
+
});
|
|
6385
|
+
}
|
|
6386
|
+
}
|
|
6332
6387
|
}
|
|
6333
6388
|
if (resource === "product_categories" && scopePut.type === "all") {
|
|
6334
6389
|
const existingCatalogCat = await repo.findOne({
|
|
@@ -6492,7 +6547,18 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6492
6547
|
}
|
|
6493
6548
|
sanitizeBodyForEntity(repo, updatePayload);
|
|
6494
6549
|
await retireSoftDeletedUniquesFromBody(repo, updatePayload);
|
|
6495
|
-
|
|
6550
|
+
try {
|
|
6551
|
+
await repo.update(numericId, updatePayload);
|
|
6552
|
+
} catch (err) {
|
|
6553
|
+
if (resource === "events" && isSlugUniqueViolation(err)) {
|
|
6554
|
+
return json({
|
|
6555
|
+
error: "An event with this slug already exists"
|
|
6556
|
+
}, {
|
|
6557
|
+
status: 400
|
|
6558
|
+
});
|
|
6559
|
+
}
|
|
6560
|
+
throw err;
|
|
6561
|
+
}
|
|
6496
6562
|
}
|
|
6497
6563
|
if (resource === "orders" && rawBody && entityMap["order_addresses"]) {
|
|
6498
6564
|
const addressRawScalar = String(rawBody["contact.address"] ?? "").trim();
|
|
@@ -8685,11 +8751,21 @@ function createUploadHandler(config) {
|
|
|
8685
8751
|
const storageService = raw instanceof Promise ? await raw : raw;
|
|
8686
8752
|
if (storageService) {
|
|
8687
8753
|
const fileUrl = await storageService.upload(buffer, `uploads/${relativeUnderUploads}`, contentType);
|
|
8754
|
+
console.info("[upload] stored via storage plugin", {
|
|
8755
|
+
key: `uploads/${relativeUnderUploads}`,
|
|
8756
|
+
contentType,
|
|
8757
|
+
bytes: buffer.length,
|
|
8758
|
+
fileUrl
|
|
8759
|
+
});
|
|
8688
8760
|
return json({
|
|
8689
8761
|
filePath: fileUrl,
|
|
8690
8762
|
parentId
|
|
8691
8763
|
});
|
|
8692
8764
|
}
|
|
8765
|
+
console.warn("[upload] no storage plugin \u2014 writing local disk (broken on most deploys)", {
|
|
8766
|
+
localUploadDir,
|
|
8767
|
+
key: relativeUnderUploads
|
|
8768
|
+
});
|
|
8693
8769
|
const fs2 = await import('fs/promises');
|
|
8694
8770
|
const path2 = await import('path');
|
|
8695
8771
|
const dir = path2.join(process.cwd(), localUploadDir);
|
|
@@ -8705,11 +8781,13 @@ function createUploadHandler(config) {
|
|
|
8705
8781
|
});
|
|
8706
8782
|
} catch (err) {
|
|
8707
8783
|
const message = err instanceof Error ? err.message : String(err);
|
|
8784
|
+
const awsMeta = err && typeof err === "object" && "$metadata" in err ? err.$metadata : void 0;
|
|
8708
8785
|
console.error("[upload] File upload failed", {
|
|
8709
8786
|
error: message,
|
|
8710
8787
|
stack: err instanceof Error ? err.stack : void 0,
|
|
8711
8788
|
name: err instanceof Error ? err.name : void 0,
|
|
8712
|
-
|
|
8789
|
+
code: err && typeof err === "object" && ("Code" in err || "code" in err) ? err.Code ?? err.code : void 0,
|
|
8790
|
+
metadata: awsMeta
|
|
8713
8791
|
});
|
|
8714
8792
|
if (/Failed to parse body as FormData/i.test(message)) {
|
|
8715
8793
|
return json({
|
|
@@ -8719,7 +8797,8 @@ function createUploadHandler(config) {
|
|
|
8719
8797
|
});
|
|
8720
8798
|
}
|
|
8721
8799
|
return json({
|
|
8722
|
-
error: "File upload failed"
|
|
8800
|
+
error: "File upload failed",
|
|
8801
|
+
details: message
|
|
8723
8802
|
}, {
|
|
8724
8803
|
status: 500
|
|
8725
8804
|
});
|
|
@@ -30860,9 +30939,51 @@ function createStorefrontApiHandler(config) {
|
|
|
30860
30939
|
"items.product.taxes",
|
|
30861
30940
|
"items.product.taxes.tax"
|
|
30862
30941
|
];
|
|
30863
|
-
function
|
|
30942
|
+
function comboIdFromCartItem(it) {
|
|
30943
|
+
const meta = it.metadata && typeof it.metadata === "object" && !Array.isArray(it.metadata) ? it.metadata : {};
|
|
30944
|
+
const fromMeta = Number(meta.comboId ?? meta.combo_id);
|
|
30945
|
+
if (Number.isInteger(fromMeta) && fromMeta > 0) return fromMeta;
|
|
30946
|
+
if (meta.isCombo === true || meta.type === "combo" || meta.lineType === "combo") {
|
|
30947
|
+
const pid = Number(it.productId);
|
|
30948
|
+
if (Number.isInteger(pid) && pid > 0) return pid;
|
|
30949
|
+
}
|
|
30950
|
+
return null;
|
|
30951
|
+
}
|
|
30952
|
+
__name(comboIdFromCartItem, "comboIdFromCartItem");
|
|
30953
|
+
async function resolveSingleVendorIdFromCart(cart) {
|
|
30864
30954
|
const vendorIds = /* @__PURE__ */ new Set();
|
|
30955
|
+
const comboRepo = entityMap.combos ? dataSource.getRepository(entityMap.combos) : null;
|
|
30956
|
+
const comboVendorCache = /* @__PURE__ */ new Map();
|
|
30957
|
+
async function vendorIdForCombo(comboId) {
|
|
30958
|
+
if (comboVendorCache.has(comboId)) return comboVendorCache.get(comboId);
|
|
30959
|
+
if (!comboRepo) return null;
|
|
30960
|
+
const combo = await comboRepo.findOne({
|
|
30961
|
+
where: {
|
|
30962
|
+
id: comboId,
|
|
30963
|
+
deleted: false
|
|
30964
|
+
},
|
|
30965
|
+
select: [
|
|
30966
|
+
"id",
|
|
30967
|
+
"vendorId"
|
|
30968
|
+
]
|
|
30969
|
+
});
|
|
30970
|
+
const vid = Number(combo?.vendorId);
|
|
30971
|
+
if (Number.isInteger(vid) && vid > 0) {
|
|
30972
|
+
comboVendorCache.set(comboId, vid);
|
|
30973
|
+
return vid;
|
|
30974
|
+
}
|
|
30975
|
+
return null;
|
|
30976
|
+
}
|
|
30977
|
+
__name(vendorIdForCombo, "vendorIdForCombo");
|
|
30865
30978
|
for (const it of cart.items || []) {
|
|
30979
|
+
const comboId = comboIdFromCartItem(it);
|
|
30980
|
+
if (comboId != null) {
|
|
30981
|
+
const comboVendorId = await vendorIdForCombo(comboId);
|
|
30982
|
+
if (comboVendorId != null) {
|
|
30983
|
+
vendorIds.add(comboVendorId);
|
|
30984
|
+
continue;
|
|
30985
|
+
}
|
|
30986
|
+
}
|
|
30866
30987
|
const p = it.product;
|
|
30867
30988
|
if (!p || p.deleted || p.status !== "available") continue;
|
|
30868
30989
|
const vid = Number(p.vendorId);
|
|
@@ -33188,7 +33309,7 @@ function createStorefrontApiHandler(config) {
|
|
|
33188
33309
|
}, {
|
|
33189
33310
|
status: prepOrd.status
|
|
33190
33311
|
});
|
|
33191
|
-
const vendorRes = resolveSingleVendorIdFromCart(cart);
|
|
33312
|
+
const vendorRes = await resolveSingleVendorIdFromCart(cart);
|
|
33192
33313
|
if ("error" in vendorRes) return json({
|
|
33193
33314
|
error: vendorRes.error
|
|
33194
33315
|
}, {
|
|
@@ -33264,7 +33385,7 @@ function createStorefrontApiHandler(config) {
|
|
|
33264
33385
|
}, {
|
|
33265
33386
|
status: prepChk.status
|
|
33266
33387
|
});
|
|
33267
|
-
const vendorResChk = resolveSingleVendorIdFromCart(cart);
|
|
33388
|
+
const vendorResChk = await resolveSingleVendorIdFromCart(cart);
|
|
33268
33389
|
if ("error" in vendorResChk) return json({
|
|
33269
33390
|
error: vendorResChk.error
|
|
33270
33391
|
}, {
|
|
@@ -33334,17 +33455,48 @@ function createStorefrontApiHandler(config) {
|
|
|
33334
33455
|
if (!contact) return json({
|
|
33335
33456
|
orders: []
|
|
33336
33457
|
});
|
|
33337
|
-
|
|
33338
|
-
|
|
33339
|
-
|
|
33340
|
-
|
|
33341
|
-
|
|
33342
|
-
|
|
33458
|
+
let linkedCustomerContactIds = [];
|
|
33459
|
+
if (entityMap.customer && entityMap.customer_contacts) {
|
|
33460
|
+
const rows = await dataSource.query(`SELECT cc.id
|
|
33461
|
+
FROM customer_contacts cc
|
|
33462
|
+
JOIN customer c ON c.id = cc."customerId"
|
|
33463
|
+
WHERE c."userId" = $1`, [
|
|
33464
|
+
uid
|
|
33465
|
+
]);
|
|
33466
|
+
linkedCustomerContactIds = rows.map((row) => Number(row.id)).filter((id) => Number.isFinite(id) && id > 0);
|
|
33467
|
+
}
|
|
33468
|
+
const visibleOrders = await orderRepo().find({
|
|
33469
|
+
where: [
|
|
33470
|
+
{
|
|
33471
|
+
contactId: contact.id,
|
|
33472
|
+
deleted: false,
|
|
33473
|
+
orderKind: "sale"
|
|
33474
|
+
},
|
|
33475
|
+
...linkedCustomerContactIds.length ? [
|
|
33476
|
+
{
|
|
33477
|
+
customerContactId: In(linkedCustomerContactIds),
|
|
33478
|
+
deleted: false,
|
|
33479
|
+
orderKind: "sale"
|
|
33480
|
+
}
|
|
33481
|
+
] : []
|
|
33482
|
+
],
|
|
33343
33483
|
order: {
|
|
33344
33484
|
createdAt: "DESC"
|
|
33345
33485
|
},
|
|
33346
33486
|
take: 50
|
|
33347
33487
|
});
|
|
33488
|
+
const orders = visibleOrders.filter((o) => {
|
|
33489
|
+
const row = o;
|
|
33490
|
+
const orderContactId = Number(row.contactId);
|
|
33491
|
+
const customerContactId = Number(row.customerContactId);
|
|
33492
|
+
if (Number.isFinite(orderContactId) && orderContactId > 0 && orderContactId === Number(contact.id)) {
|
|
33493
|
+
return true;
|
|
33494
|
+
}
|
|
33495
|
+
if (Number.isFinite(customerContactId) && customerContactId > 0) {
|
|
33496
|
+
return linkedCustomerContactIds.includes(customerContactId);
|
|
33497
|
+
}
|
|
33498
|
+
return false;
|
|
33499
|
+
});
|
|
33348
33500
|
const orderIds = orders.map((o) => o.id);
|
|
33349
33501
|
const previewByOrder = {};
|
|
33350
33502
|
if (orderIds.length) {
|
|
@@ -33437,10 +33589,19 @@ function createStorefrontApiHandler(config) {
|
|
|
33437
33589
|
status: 404
|
|
33438
33590
|
});
|
|
33439
33591
|
const orderId = parseInt(path2[1], 10);
|
|
33592
|
+
let linkedCustomerContactIds = [];
|
|
33593
|
+
if (entityMap.customer && entityMap.customer_contacts) {
|
|
33594
|
+
const rows = await dataSource.query(`SELECT cc.id
|
|
33595
|
+
FROM customer_contacts cc
|
|
33596
|
+
JOIN customer c ON c.id = cc."customerId"
|
|
33597
|
+
WHERE c."userId" = $1`, [
|
|
33598
|
+
uid
|
|
33599
|
+
]);
|
|
33600
|
+
linkedCustomerContactIds = rows.map((row) => Number(row.id)).filter((id) => Number.isFinite(id) && id > 0);
|
|
33601
|
+
}
|
|
33440
33602
|
let order = await orderRepo().findOne({
|
|
33441
33603
|
where: {
|
|
33442
33604
|
id: orderId,
|
|
33443
|
-
contactId: contact.id,
|
|
33444
33605
|
deleted: false
|
|
33445
33606
|
},
|
|
33446
33607
|
relations: [
|
|
@@ -33453,13 +33614,20 @@ function createStorefrontApiHandler(config) {
|
|
|
33453
33614
|
}, {
|
|
33454
33615
|
status: 404
|
|
33455
33616
|
});
|
|
33617
|
+
const orderContactId = Number(order.contactId);
|
|
33618
|
+
const orderCustomerContactId = Number(order.customerContactId);
|
|
33619
|
+
const isOwner = Number.isFinite(orderContactId) && orderContactId > 0 && orderContactId === Number(contact.id) || Number.isFinite(orderCustomerContactId) && orderCustomerContactId > 0 && linkedCustomerContactIds.includes(orderCustomerContactId);
|
|
33620
|
+
if (!isOwner) return json({
|
|
33621
|
+
error: "Not found"
|
|
33622
|
+
}, {
|
|
33623
|
+
status: 404
|
|
33624
|
+
});
|
|
33456
33625
|
if (getCms) {
|
|
33457
33626
|
const cms = await getCms();
|
|
33458
33627
|
await tryRefreshOrderFromErpForStorefront(cms, dataSource, entityMap, order);
|
|
33459
33628
|
order = await orderRepo().findOne({
|
|
33460
33629
|
where: {
|
|
33461
33630
|
id: orderId,
|
|
33462
|
-
contactId: contact.id,
|
|
33463
33631
|
deleted: false
|
|
33464
33632
|
},
|
|
33465
33633
|
relations: [
|
|
@@ -33473,6 +33641,14 @@ function createStorefrontApiHandler(config) {
|
|
|
33473
33641
|
}, {
|
|
33474
33642
|
status: 404
|
|
33475
33643
|
});
|
|
33644
|
+
const refreshedOrderContactId = Number(order.contactId);
|
|
33645
|
+
const refreshedCustomerContactId = Number(order.customerContactId);
|
|
33646
|
+
const isOwnerAfterRefresh = Number.isFinite(refreshedOrderContactId) && refreshedOrderContactId > 0 && refreshedOrderContactId === Number(contact.id) || Number.isFinite(refreshedCustomerContactId) && refreshedCustomerContactId > 0 && linkedCustomerContactIds.includes(refreshedCustomerContactId);
|
|
33647
|
+
if (!isOwnerAfterRefresh) return json({
|
|
33648
|
+
error: "Not found"
|
|
33649
|
+
}, {
|
|
33650
|
+
status: 404
|
|
33651
|
+
});
|
|
33476
33652
|
const o = order;
|
|
33477
33653
|
const lines = (o.items || []).map((line) => {
|
|
33478
33654
|
const p = line.product;
|