@infuro/cms-core 1.0.42 → 1.0.44
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 +73 -26
- package/dist/admin.d.cts +3 -1
- package/dist/admin.d.ts +3 -1
- package/dist/admin.js +73 -26
- package/dist/api.cjs +32 -32
- package/dist/api.js +1 -1
- package/dist/{chunk-GINYYPXK.cjs → chunk-P2IWWBJV.cjs} +286 -53
- package/dist/{chunk-W2NL365N.js → chunk-SQGBHYJF.js} +286 -53
- package/dist/index.cjs +201 -201
- package/dist/index.js +2 -2
- package/package.json +1 -1
|
@@ -452,6 +452,41 @@ function applyApprovalStatusSideEffects(updatePayload, opts) {
|
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
__name(applyApprovalStatusSideEffects, "applyApprovalStatusSideEffects");
|
|
455
|
+
async function syncProductVariantsStatusWithProduct(dataSource, entityMap, productId, productStatus) {
|
|
456
|
+
if (!entityMap.product_variants || !Number.isFinite(productId) || productId < 1) return;
|
|
457
|
+
const status = String(productStatus || "draft");
|
|
458
|
+
const repo = dataSource.getRepository(entityMap.product_variants);
|
|
459
|
+
if (status === "available") {
|
|
460
|
+
await repo.createQueryBuilder().update().set({
|
|
461
|
+
status: "available"
|
|
462
|
+
}).where('"productId" = :productId', {
|
|
463
|
+
productId
|
|
464
|
+
}).andWhere("status = :from", {
|
|
465
|
+
from: "draft"
|
|
466
|
+
}).execute();
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
if (status === "draft") {
|
|
470
|
+
await repo.createQueryBuilder().update().set({
|
|
471
|
+
status: "draft"
|
|
472
|
+
}).where('"productId" = :productId', {
|
|
473
|
+
productId
|
|
474
|
+
}).andWhere("status = :from", {
|
|
475
|
+
from: "available"
|
|
476
|
+
}).execute();
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
__name(syncProductVariantsStatusWithProduct, "syncProductVariantsStatusWithProduct");
|
|
480
|
+
function coerceVariantStatusForProduct(variantStatus, productStatus, opts) {
|
|
481
|
+
const next = String(variantStatus ?? "draft").trim() || "draft";
|
|
482
|
+
const productLive = String(productStatus ?? "draft") === "available";
|
|
483
|
+
const approvalOk = !opts?.requireApproval || String(opts?.approvalStatus ?? "") === "approved";
|
|
484
|
+
if (!productLive || !approvalOk) {
|
|
485
|
+
return "draft";
|
|
486
|
+
}
|
|
487
|
+
return next;
|
|
488
|
+
}
|
|
489
|
+
__name(coerceVariantStatusForProduct, "coerceVariantStatusForProduct");
|
|
455
490
|
|
|
456
491
|
// src/lib/event-approval.ts
|
|
457
492
|
var EVENT_APPROVAL_STATUSES = [
|
|
@@ -4594,6 +4629,26 @@ function createCrudHandler(dataSource, entityMap, options) {
|
|
|
4594
4629
|
}
|
|
4595
4630
|
}
|
|
4596
4631
|
}
|
|
4632
|
+
if (resource === "product_variants" && entityMap.products) {
|
|
4633
|
+
const productIdRaw = persistBody.productId;
|
|
4634
|
+
const productId = typeof productIdRaw === "number" ? productIdRaw : typeof productIdRaw === "string" && /^\d+$/.test(productIdRaw) ? parseInt(productIdRaw, 10) : NaN;
|
|
4635
|
+
if (Number.isFinite(productId)) {
|
|
4636
|
+
const parent = await dataSource.getRepository(entityMap.products).findOne({
|
|
4637
|
+
where: {
|
|
4638
|
+
id: productId
|
|
4639
|
+
}
|
|
4640
|
+
});
|
|
4641
|
+
const parentStatus = parent?.status;
|
|
4642
|
+
const parentApproval = parent?.approvalStatus;
|
|
4643
|
+
const requireApproval = await getRequireProductApproval(dataSource);
|
|
4644
|
+
persistBody.status = coerceVariantStatusForProduct(persistBody.status, parentStatus, {
|
|
4645
|
+
approvalStatus: parentApproval,
|
|
4646
|
+
requireApproval
|
|
4647
|
+
});
|
|
4648
|
+
} else if (!("status" in persistBody)) {
|
|
4649
|
+
persistBody.status = "draft";
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4597
4652
|
if (resource === "products") {
|
|
4598
4653
|
const scopeForProduct = await resolveScope();
|
|
4599
4654
|
const productFlags = await getVendorCatalogCreateFlags(dataSource);
|
|
@@ -6233,6 +6288,34 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6233
6288
|
delete u.parentId;
|
|
6234
6289
|
}
|
|
6235
6290
|
}
|
|
6291
|
+
if (resource === "product_variants" && entityMap.products) {
|
|
6292
|
+
const currentVariant = await repo.findOne({
|
|
6293
|
+
where: {
|
|
6294
|
+
id: numericId
|
|
6295
|
+
}
|
|
6296
|
+
});
|
|
6297
|
+
if (!currentVariant) return json({
|
|
6298
|
+
message: "Not found"
|
|
6299
|
+
}, {
|
|
6300
|
+
status: 404
|
|
6301
|
+
});
|
|
6302
|
+
const productId = "productId" in updatePayload && updatePayload.productId != null ? Number(updatePayload.productId) : Number(currentVariant.productId);
|
|
6303
|
+
if (Number.isFinite(productId)) {
|
|
6304
|
+
const parent = await dataSource.getRepository(entityMap.products).findOne({
|
|
6305
|
+
where: {
|
|
6306
|
+
id: productId
|
|
6307
|
+
}
|
|
6308
|
+
});
|
|
6309
|
+
const parentStatus = parent?.status;
|
|
6310
|
+
const parentApproval = parent?.approvalStatus;
|
|
6311
|
+
const requireApproval = await getRequireProductApproval(dataSource);
|
|
6312
|
+
const nextStatus = "status" in updatePayload ? updatePayload.status : currentVariant.status;
|
|
6313
|
+
updatePayload.status = coerceVariantStatusForProduct(nextStatus, parentStatus, {
|
|
6314
|
+
approvalStatus: parentApproval,
|
|
6315
|
+
requireApproval
|
|
6316
|
+
});
|
|
6317
|
+
}
|
|
6318
|
+
}
|
|
6236
6319
|
if (resource === "products") {
|
|
6237
6320
|
const currentRow = await repo.findOne({
|
|
6238
6321
|
where: {
|
|
@@ -6588,6 +6671,10 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
|
|
|
6588
6671
|
if (reloaded) updated = reloaded;
|
|
6589
6672
|
}
|
|
6590
6673
|
updated = hydrateProductDisplayName(updated);
|
|
6674
|
+
const productStatus = String(updated.status ?? "draft");
|
|
6675
|
+
if (Number.isFinite(updatedId) && updatedId > 0) {
|
|
6676
|
+
await syncProductVariantsStatusWithProduct(dataSource, entityMap, updatedId, productStatus);
|
|
6677
|
+
}
|
|
6591
6678
|
if (getCms) {
|
|
6592
6679
|
const cms = await getCms();
|
|
6593
6680
|
await queueErpProductUpsertIfEnabled(cms, dataSource, entityMap, updated);
|
|
@@ -8625,6 +8712,12 @@ function createUploadHandler(config) {
|
|
|
8625
8712
|
parentId
|
|
8626
8713
|
});
|
|
8627
8714
|
} catch (err) {
|
|
8715
|
+
console.error("[upload] File upload failed", {
|
|
8716
|
+
error: err instanceof Error ? err.message : String(err),
|
|
8717
|
+
stack: err instanceof Error ? err.stack : void 0,
|
|
8718
|
+
name: err instanceof Error ? err.name : void 0,
|
|
8719
|
+
metadata: err && typeof err === "object" && "$metadata" in err ? err.$metadata : void 0
|
|
8720
|
+
});
|
|
8628
8721
|
return json({
|
|
8629
8722
|
error: "File upload failed"
|
|
8630
8723
|
}, {
|
|
@@ -9330,41 +9423,68 @@ function createUsersApiHandlers(config) {
|
|
|
9330
9423
|
const page = Math.max(1, parseInt(url.searchParams.get("page") || "1", 10));
|
|
9331
9424
|
const limit = Math.min(100, parseInt(url.searchParams.get("limit") || "10", 10));
|
|
9332
9425
|
const skip = (page - 1) * limit;
|
|
9333
|
-
const
|
|
9426
|
+
const sortFieldRaw = url.searchParams.get("sortField") || "createdAt";
|
|
9427
|
+
const allowedSort = /* @__PURE__ */ new Set([
|
|
9428
|
+
"createdAt",
|
|
9429
|
+
"updatedAt",
|
|
9430
|
+
"name",
|
|
9431
|
+
"email",
|
|
9432
|
+
"id",
|
|
9433
|
+
"blocked"
|
|
9434
|
+
]);
|
|
9435
|
+
const sortField = allowedSort.has(sortFieldRaw) ? sortFieldRaw : "createdAt";
|
|
9334
9436
|
const sortOrder = url.searchParams.get("sortOrder") === "desc" ? "DESC" : "ASC";
|
|
9335
|
-
const search = url.searchParams.get("search");
|
|
9336
|
-
const
|
|
9337
|
-
|
|
9338
|
-
name: ILike(`%${search}%`),
|
|
9339
|
-
deleted: false
|
|
9340
|
-
},
|
|
9341
|
-
{
|
|
9342
|
-
email: ILike(`%${search}%`),
|
|
9343
|
-
deleted: false
|
|
9344
|
-
}
|
|
9345
|
-
] : {
|
|
9437
|
+
const search = url.searchParams.get("search")?.trim() || "";
|
|
9438
|
+
const groupName = url.searchParams.get("groupName")?.trim() || "";
|
|
9439
|
+
const qb = userRepo().createQueryBuilder("u").leftJoinAndSelect("u.group", "g").where("u.deleted = :deleted", {
|
|
9346
9440
|
deleted: false
|
|
9347
|
-
}
|
|
9348
|
-
|
|
9349
|
-
|
|
9350
|
-
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9441
|
+
}).orderBy(`u.${sortField}`, sortOrder).skip(skip).take(limit).select([
|
|
9442
|
+
"u.id",
|
|
9443
|
+
"u.name",
|
|
9444
|
+
"u.email",
|
|
9445
|
+
"u.blocked",
|
|
9446
|
+
"u.createdAt",
|
|
9447
|
+
"u.updatedAt",
|
|
9448
|
+
"u.groupId",
|
|
9449
|
+
"g.id",
|
|
9450
|
+
"g.name"
|
|
9451
|
+
]);
|
|
9452
|
+
if (search) {
|
|
9453
|
+
qb.andWhere("(u.name ILIKE :search OR u.email ILIKE :search)", {
|
|
9454
|
+
search: `%${search}%`
|
|
9455
|
+
});
|
|
9456
|
+
}
|
|
9457
|
+
if (groupName) {
|
|
9458
|
+
if (!entityMap.user_groups) {
|
|
9459
|
+
return json({
|
|
9460
|
+
total: 0,
|
|
9461
|
+
page,
|
|
9462
|
+
limit,
|
|
9463
|
+
totalPages: 0,
|
|
9464
|
+
data: []
|
|
9465
|
+
});
|
|
9466
|
+
}
|
|
9467
|
+
const groupRepo = dataSource.getRepository(entityMap.user_groups);
|
|
9468
|
+
const group = await groupRepo.findOne({
|
|
9469
|
+
where: {
|
|
9470
|
+
name: groupName,
|
|
9471
|
+
deleted: false
|
|
9472
|
+
}
|
|
9473
|
+
});
|
|
9474
|
+
if (!group) {
|
|
9475
|
+
return json({
|
|
9476
|
+
total: 0,
|
|
9477
|
+
page,
|
|
9478
|
+
limit,
|
|
9479
|
+
totalPages: 0,
|
|
9480
|
+
data: []
|
|
9481
|
+
});
|
|
9482
|
+
}
|
|
9483
|
+
qb.andWhere("u.groupId = :groupId", {
|
|
9484
|
+
groupId: Number(group.id)
|
|
9485
|
+
});
|
|
9486
|
+
}
|
|
9487
|
+
const [data, total] = await qb.getManyAndCount();
|
|
9368
9488
|
return json({
|
|
9369
9489
|
total,
|
|
9370
9490
|
page,
|
|
@@ -29772,7 +29892,8 @@ function createStorefrontApiHandler(config) {
|
|
|
29772
29892
|
const repo = dataSource.getRepository(entityMap.product_variants);
|
|
29773
29893
|
const rows = await repo.find({
|
|
29774
29894
|
where: {
|
|
29775
|
-
productId
|
|
29895
|
+
productId,
|
|
29896
|
+
status: "available"
|
|
29776
29897
|
},
|
|
29777
29898
|
order: {
|
|
29778
29899
|
id: "ASC"
|
|
@@ -29805,6 +29926,52 @@ function createStorefrontApiHandler(config) {
|
|
|
29805
29926
|
return result;
|
|
29806
29927
|
}
|
|
29807
29928
|
__name(loadProductVariantsWithPricing, "loadProductVariantsWithPricing");
|
|
29929
|
+
async function loadApplicableVendorPolicies(productId, vendorId) {
|
|
29930
|
+
if (!entityMap.refund_policies) return [];
|
|
29931
|
+
const policyRepo = dataSource.getRepository(entityMap.refund_policies);
|
|
29932
|
+
const format = /* @__PURE__ */ __name((row) => ({
|
|
29933
|
+
id: Number(row.id),
|
|
29934
|
+
name: String(row.name ?? "").trim(),
|
|
29935
|
+
desc: row.desc != null ? String(row.desc) : null,
|
|
29936
|
+
refundWindowDays: Number(row.refundWindowDays) || 0,
|
|
29937
|
+
type: String(row.type ?? "percentage"),
|
|
29938
|
+
value: Number(row.value) || 0
|
|
29939
|
+
}), "format");
|
|
29940
|
+
const linkedIds = /* @__PURE__ */ new Set();
|
|
29941
|
+
if (entityMap.product_config) {
|
|
29942
|
+
const configs = await dataSource.getRepository(entityMap.product_config).find({
|
|
29943
|
+
where: {
|
|
29944
|
+
productId
|
|
29945
|
+
}
|
|
29946
|
+
});
|
|
29947
|
+
for (const c of configs) {
|
|
29948
|
+
const id = Number(c.refundPolicyId);
|
|
29949
|
+
if (Number.isFinite(id) && id > 0) linkedIds.add(id);
|
|
29950
|
+
}
|
|
29951
|
+
}
|
|
29952
|
+
if (linkedIds.size > 0) {
|
|
29953
|
+
const rows = await policyRepo.find({
|
|
29954
|
+
where: {
|
|
29955
|
+
id: In([
|
|
29956
|
+
...linkedIds
|
|
29957
|
+
])
|
|
29958
|
+
}
|
|
29959
|
+
});
|
|
29960
|
+
return rows.map((r) => format(r)).filter((p) => p.name).sort((a, b) => a.id - b.id);
|
|
29961
|
+
}
|
|
29962
|
+
if (vendorId == null || !Number.isFinite(Number(vendorId))) return [];
|
|
29963
|
+
const vendorRows = await policyRepo.find({
|
|
29964
|
+
where: {
|
|
29965
|
+
vendorId: Number(vendorId),
|
|
29966
|
+
status: "active"
|
|
29967
|
+
},
|
|
29968
|
+
order: {
|
|
29969
|
+
id: "ASC"
|
|
29970
|
+
}
|
|
29971
|
+
});
|
|
29972
|
+
return vendorRows.map((r) => format(r)).filter((p) => p.name);
|
|
29973
|
+
}
|
|
29974
|
+
__name(loadApplicableVendorPolicies, "loadApplicableVendorPolicies");
|
|
29808
29975
|
return {
|
|
29809
29976
|
async handle(method, path2, req) {
|
|
29810
29977
|
try {
|
|
@@ -29872,13 +30039,11 @@ function createStorefrontApiHandler(config) {
|
|
|
29872
30039
|
const url = new URL(req.url || "", "http://localhost");
|
|
29873
30040
|
const collectionSlug = url.searchParams.get("collection")?.trim();
|
|
29874
30041
|
const collectionId = url.searchParams.get("collectionId");
|
|
30042
|
+
const q = url.searchParams.get("q")?.trim() ?? "";
|
|
29875
30043
|
const limit = Math.min(100, Math.max(1, parseInt(url.searchParams.get("limit") || "20", 10)));
|
|
29876
30044
|
const offset = Math.max(0, parseInt(url.searchParams.get("offset") || "0", 10));
|
|
29877
|
-
const where = {
|
|
29878
|
-
status: "available",
|
|
29879
|
-
deleted: false
|
|
29880
|
-
};
|
|
29881
30045
|
let collectionFilter = null;
|
|
30046
|
+
let collectionIdFilter = null;
|
|
29882
30047
|
if (collectionSlug) {
|
|
29883
30048
|
let col = null;
|
|
29884
30049
|
if (/^\d+$/.test(collectionSlug)) {
|
|
@@ -29905,30 +30070,59 @@ function createStorefrontApiHandler(config) {
|
|
|
29905
30070
|
collection: null
|
|
29906
30071
|
});
|
|
29907
30072
|
}
|
|
29908
|
-
|
|
30073
|
+
collectionIdFilter = Number(col.id);
|
|
29909
30074
|
collectionFilter = {
|
|
29910
30075
|
name: col.name,
|
|
29911
30076
|
slug: col.slug
|
|
29912
30077
|
};
|
|
29913
30078
|
} else if (collectionId) {
|
|
29914
30079
|
const cid = parseInt(collectionId, 10);
|
|
29915
|
-
if (Number.isFinite(cid))
|
|
30080
|
+
if (Number.isFinite(cid)) collectionIdFilter = cid;
|
|
30081
|
+
}
|
|
30082
|
+
let items = [];
|
|
30083
|
+
let total = 0;
|
|
30084
|
+
if (q) {
|
|
30085
|
+
const like = `%${q.replace(/[%_]/g, "\\$&")}%`;
|
|
30086
|
+
const qb = productRepo().createQueryBuilder("p").where("p.status = :status", {
|
|
30087
|
+
status: "available"
|
|
30088
|
+
}).andWhere("p.deleted = :del", {
|
|
30089
|
+
del: false
|
|
30090
|
+
}).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)`, {
|
|
30091
|
+
like
|
|
30092
|
+
}).orderBy("p.id", "ASC").take(limit).skip(offset);
|
|
30093
|
+
if (collectionIdFilter != null) {
|
|
30094
|
+
qb.andWhere("p.collectionId = :cid", {
|
|
30095
|
+
cid: collectionIdFilter
|
|
30096
|
+
});
|
|
30097
|
+
}
|
|
30098
|
+
[items, total] = await qb.getManyAndCount();
|
|
30099
|
+
} else {
|
|
30100
|
+
const where = {
|
|
30101
|
+
status: "available",
|
|
30102
|
+
deleted: false
|
|
30103
|
+
};
|
|
30104
|
+
if (collectionIdFilter != null) where.collectionId = collectionIdFilter;
|
|
30105
|
+
const result = await productRepo().findAndCount({
|
|
30106
|
+
where,
|
|
30107
|
+
order: {
|
|
30108
|
+
id: "ASC"
|
|
30109
|
+
},
|
|
30110
|
+
take: limit,
|
|
30111
|
+
skip: offset
|
|
30112
|
+
});
|
|
30113
|
+
items = result[0];
|
|
30114
|
+
total = result[1];
|
|
29916
30115
|
}
|
|
29917
|
-
const [items, total] = await productRepo().findAndCount({
|
|
29918
|
-
where,
|
|
29919
|
-
order: {
|
|
29920
|
-
id: "ASC"
|
|
29921
|
-
},
|
|
29922
|
-
take: limit,
|
|
29923
|
-
skip: offset
|
|
29924
|
-
});
|
|
29925
30116
|
const products = await Promise.all(items.map((item) => enrichProductPricing(item)));
|
|
29926
30117
|
return json({
|
|
29927
30118
|
products,
|
|
29928
30119
|
total,
|
|
29929
30120
|
...collectionFilter && {
|
|
29930
30121
|
collection: collectionFilter
|
|
29931
|
-
}
|
|
30122
|
+
},
|
|
30123
|
+
...q ? {
|
|
30124
|
+
q
|
|
30125
|
+
} : {}
|
|
29932
30126
|
});
|
|
29933
30127
|
}
|
|
29934
30128
|
if (path2[0] === "products" && path2.length === 2 && method === "GET") {
|
|
@@ -29964,12 +30158,14 @@ function createStorefrontApiHandler(config) {
|
|
|
29964
30158
|
const pricing = await resolveProductEventPricing(Number(p.id));
|
|
29965
30159
|
const enriched = await enrichProductPricing(p, pricing);
|
|
29966
30160
|
const variants = await loadProductVariantsWithPricing(Number(p.id), pricing);
|
|
30161
|
+
const policies = await loadApplicableVendorPolicies(Number(p.id), p.vendorId != null ? Number(p.vendorId) : null);
|
|
29967
30162
|
return json({
|
|
29968
30163
|
...enriched,
|
|
29969
30164
|
attributes: attributeTags,
|
|
29970
30165
|
...variants.length ? {
|
|
29971
30166
|
variants
|
|
29972
|
-
} : {}
|
|
30167
|
+
} : {},
|
|
30168
|
+
policies
|
|
29973
30169
|
});
|
|
29974
30170
|
}
|
|
29975
30171
|
if (path2[0] === "collections" && path2.length === 1 && method === "GET") {
|
|
@@ -30781,24 +30977,61 @@ function createStorefrontApiHandler(config) {
|
|
|
30781
30977
|
}, {
|
|
30782
30978
|
status: 404
|
|
30783
30979
|
});
|
|
30980
|
+
const rawVariantId = body.variantId ?? body.variant_id;
|
|
30981
|
+
const variantIdNum = rawVariantId != null && String(rawVariantId).trim() !== "" ? Number(rawVariantId) : NaN;
|
|
30982
|
+
const hasVariantId = Number.isFinite(variantIdNum) && variantIdNum > 0;
|
|
30983
|
+
const bodyMeta = body.metadata && typeof body.metadata === "object" && !Array.isArray(body.metadata) ? body.metadata : {};
|
|
30984
|
+
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;
|
|
30985
|
+
const options = optionsRaw && Object.fromEntries(Object.entries(optionsRaw).map(([k, v]) => [
|
|
30986
|
+
String(k),
|
|
30987
|
+
String(v ?? "").trim()
|
|
30988
|
+
]).filter(([, v]) => v.length > 0));
|
|
30989
|
+
const lineMetadata = {
|
|
30990
|
+
...bodyMeta,
|
|
30991
|
+
...hasVariantId ? {
|
|
30992
|
+
variantId: variantIdNum
|
|
30993
|
+
} : {},
|
|
30994
|
+
...options && Object.keys(options).length ? {
|
|
30995
|
+
options
|
|
30996
|
+
} : {}
|
|
30997
|
+
};
|
|
30998
|
+
if (typeof bodyMeta.imageUrl === "string" && bodyMeta.imageUrl.trim()) {
|
|
30999
|
+
lineMetadata.imageUrl = bodyMeta.imageUrl.trim();
|
|
31000
|
+
}
|
|
31001
|
+
if (typeof bodyMeta.title === "string" && bodyMeta.title.trim()) {
|
|
31002
|
+
lineMetadata.title = bodyMeta.title.trim();
|
|
31003
|
+
}
|
|
31004
|
+
const metadataPayload = Object.keys(lineMetadata).length ? lineMetadata : null;
|
|
30784
31005
|
const { cart, setCookie, err } = await getOrCreateCart(req);
|
|
30785
31006
|
if (err) return err;
|
|
30786
31007
|
const cartId = cart.id;
|
|
30787
|
-
const
|
|
31008
|
+
const sameProductLines = await cartItemRepo().find({
|
|
30788
31009
|
where: {
|
|
30789
31010
|
cartId,
|
|
30790
31011
|
productId
|
|
30791
31012
|
}
|
|
30792
31013
|
});
|
|
31014
|
+
const existing = sameProductLines.find((row) => {
|
|
31015
|
+
const m = row.metadata;
|
|
31016
|
+
const existingVid = m?.variantId ?? m?.variant_id;
|
|
31017
|
+
if (hasVariantId) {
|
|
31018
|
+
return Number(existingVid) === variantIdNum;
|
|
31019
|
+
}
|
|
31020
|
+
return existingVid == null || existingVid === "";
|
|
31021
|
+
});
|
|
30793
31022
|
if (existing) {
|
|
30794
31023
|
await cartItemRepo().update(existing.id, {
|
|
30795
|
-
quantity: existing.quantity + quantity
|
|
31024
|
+
quantity: existing.quantity + quantity,
|
|
31025
|
+
...metadataPayload ? {
|
|
31026
|
+
metadata: metadataPayload
|
|
31027
|
+
} : {}
|
|
30796
31028
|
});
|
|
30797
31029
|
} else {
|
|
30798
31030
|
await cartItemRepo().save(cartItemRepo().create({
|
|
30799
31031
|
cartId,
|
|
30800
31032
|
productId,
|
|
30801
|
-
quantity
|
|
31033
|
+
quantity,
|
|
31034
|
+
metadata: metadataPayload
|
|
30802
31035
|
}));
|
|
30803
31036
|
}
|
|
30804
31037
|
await cartRepo().update(cartId, {
|