@webbycrown/webbycommerce 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -7
- package/dist/_chunks/{Settings-BTffXkdF.mjs → Settings-DpLvkyId.mjs} +114 -93
- package/dist/_chunks/{Settings-CHavEmCV.js → Settings-FFmXhBSE.js} +92 -113
- package/dist/_chunks/{en-CN5945VW.mjs → en-BsbZxjAR.mjs} +61 -8
- package/dist/_chunks/{en-Dj8IzRXD.js → en-CwvqDxF2.js} +61 -8
- package/dist/_chunks/{index-DXM6qeJr.js → index-DaVBMS-M.js} +3 -3
- package/dist/_chunks/{index-BFH1VuAA.mjs → index-rT-5a8Cs.mjs} +3 -3
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +1126 -236
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -1350,6 +1350,153 @@ var require_check_ecommerce_permission = __commonJS({
|
|
|
1350
1350
|
}
|
|
1351
1351
|
});
|
|
1352
1352
|
|
|
1353
|
+
// server/src/utils/extend-user-schema.js
|
|
1354
|
+
var require_extend_user_schema = __commonJS({
|
|
1355
|
+
"server/src/utils/extend-user-schema.js"(exports2, module2) {
|
|
1356
|
+
"use strict";
|
|
1357
|
+
async function extendUserSchemaWithOtpFields(strapi2) {
|
|
1358
|
+
try {
|
|
1359
|
+
const db = strapi2.db;
|
|
1360
|
+
const client = db.config.connection.client;
|
|
1361
|
+
const tableName = "up_users";
|
|
1362
|
+
let fieldsExist = false;
|
|
1363
|
+
try {
|
|
1364
|
+
const contentType = strapi2.contentTypes["plugin::users-permissions.user"];
|
|
1365
|
+
if (contentType && contentType.attributes) {
|
|
1366
|
+
fieldsExist = "otp" in contentType.attributes && "isOtpVerified" in contentType.attributes;
|
|
1367
|
+
}
|
|
1368
|
+
} catch (err) {
|
|
1369
|
+
try {
|
|
1370
|
+
await db.query("plugin::users-permissions.user").findOne({
|
|
1371
|
+
select: ["id", "otp", "isOtpVerified"],
|
|
1372
|
+
limit: 1
|
|
1373
|
+
});
|
|
1374
|
+
fieldsExist = true;
|
|
1375
|
+
} catch (queryErr) {
|
|
1376
|
+
fieldsExist = false;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
if (fieldsExist) {
|
|
1380
|
+
strapi2.log.info("[webbycommerce] OTP fields already exist in user schema");
|
|
1381
|
+
return true;
|
|
1382
|
+
}
|
|
1383
|
+
strapi2.log.info("[webbycommerce] OTP fields not found, adding them to user schema...");
|
|
1384
|
+
const connection = db.connection;
|
|
1385
|
+
const knex = connection;
|
|
1386
|
+
let otpAdded = false;
|
|
1387
|
+
let isOtpVerifiedAdded = false;
|
|
1388
|
+
if (client === "sqlite" || client === "sqlite3") {
|
|
1389
|
+
const tableInfo = await knex.raw(`PRAGMA table_info(${tableName})`);
|
|
1390
|
+
const columns = tableInfo.map((col) => col.name);
|
|
1391
|
+
if (!columns.includes("otp")) {
|
|
1392
|
+
await knex.schema.alterTable(tableName, (table) => {
|
|
1393
|
+
table.integer("otp").nullable();
|
|
1394
|
+
});
|
|
1395
|
+
otpAdded = true;
|
|
1396
|
+
strapi2.log.info('[webbycommerce] Added "otp" column to user table');
|
|
1397
|
+
}
|
|
1398
|
+
if (!columns.includes("is_otp_verified")) {
|
|
1399
|
+
await knex.schema.alterTable(tableName, (table) => {
|
|
1400
|
+
table.boolean("is_otp_verified").defaultTo(false);
|
|
1401
|
+
});
|
|
1402
|
+
isOtpVerifiedAdded = true;
|
|
1403
|
+
strapi2.log.info('[webbycommerce] Added "is_otp_verified" column to user table');
|
|
1404
|
+
}
|
|
1405
|
+
} else if (client === "postgres") {
|
|
1406
|
+
const otpExists = await knex.raw(`
|
|
1407
|
+
SELECT column_name
|
|
1408
|
+
FROM information_schema.columns
|
|
1409
|
+
WHERE table_name='${tableName}' AND column_name='otp'
|
|
1410
|
+
`);
|
|
1411
|
+
if (otpExists.rows.length === 0) {
|
|
1412
|
+
await knex.raw(`ALTER TABLE ${tableName} ADD COLUMN otp INTEGER`);
|
|
1413
|
+
otpAdded = true;
|
|
1414
|
+
strapi2.log.info('[webbycommerce] Added "otp" column to user table');
|
|
1415
|
+
}
|
|
1416
|
+
const isOtpVerifiedExists = await knex.raw(`
|
|
1417
|
+
SELECT column_name
|
|
1418
|
+
FROM information_schema.columns
|
|
1419
|
+
WHERE table_name='${tableName}' AND column_name='is_otp_verified'
|
|
1420
|
+
`);
|
|
1421
|
+
if (isOtpVerifiedExists.rows.length === 0) {
|
|
1422
|
+
await knex.raw(`ALTER TABLE ${tableName} ADD COLUMN is_otp_verified BOOLEAN DEFAULT false`);
|
|
1423
|
+
isOtpVerifiedAdded = true;
|
|
1424
|
+
strapi2.log.info('[webbycommerce] Added "is_otp_verified" column to user table');
|
|
1425
|
+
}
|
|
1426
|
+
} else if (client === "mysql" || client === "mysql2") {
|
|
1427
|
+
const otpExists = await knex.raw(`
|
|
1428
|
+
SELECT COLUMN_NAME
|
|
1429
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
1430
|
+
WHERE TABLE_SCHEMA = DATABASE()
|
|
1431
|
+
AND TABLE_NAME = '${tableName}'
|
|
1432
|
+
AND COLUMN_NAME = 'otp'
|
|
1433
|
+
`);
|
|
1434
|
+
if (otpExists[0].length === 0) {
|
|
1435
|
+
await knex.raw(`ALTER TABLE \`${tableName}\` ADD COLUMN \`otp\` INT NULL`);
|
|
1436
|
+
otpAdded = true;
|
|
1437
|
+
strapi2.log.info('[webbycommerce] Added "otp" column to user table');
|
|
1438
|
+
}
|
|
1439
|
+
const isOtpVerifiedExists = await knex.raw(`
|
|
1440
|
+
SELECT COLUMN_NAME
|
|
1441
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
|
1442
|
+
WHERE TABLE_SCHEMA = DATABASE()
|
|
1443
|
+
AND TABLE_NAME = '${tableName}'
|
|
1444
|
+
AND COLUMN_NAME = 'is_otp_verified'
|
|
1445
|
+
`);
|
|
1446
|
+
if (isOtpVerifiedExists[0].length === 0) {
|
|
1447
|
+
await knex.raw(`ALTER TABLE \`${tableName}\` ADD COLUMN \`is_otp_verified\` BOOLEAN DEFAULT false`);
|
|
1448
|
+
isOtpVerifiedAdded = true;
|
|
1449
|
+
strapi2.log.info('[webbycommerce] Added "is_otp_verified" column to user table');
|
|
1450
|
+
}
|
|
1451
|
+
} else {
|
|
1452
|
+
strapi2.log.warn(
|
|
1453
|
+
`[webbycommerce] Database client "${client}" not supported for automatic schema extension. Please manually add OTP fields to user schema.`
|
|
1454
|
+
);
|
|
1455
|
+
return false;
|
|
1456
|
+
}
|
|
1457
|
+
try {
|
|
1458
|
+
const contentType = strapi2.contentTypes["plugin::users-permissions.user"];
|
|
1459
|
+
if (contentType && contentType.attributes) {
|
|
1460
|
+
if (otpAdded || !("otp" in contentType.attributes)) {
|
|
1461
|
+
contentType.attributes.otp = {
|
|
1462
|
+
type: "integer",
|
|
1463
|
+
required: false,
|
|
1464
|
+
private: true
|
|
1465
|
+
};
|
|
1466
|
+
strapi2.log.info('[webbycommerce] Registered "otp" field in Strapi content-type');
|
|
1467
|
+
}
|
|
1468
|
+
if (isOtpVerifiedAdded || !("isOtpVerified" in contentType.attributes)) {
|
|
1469
|
+
contentType.attributes.isOtpVerified = {
|
|
1470
|
+
type: "boolean",
|
|
1471
|
+
default: false,
|
|
1472
|
+
required: false,
|
|
1473
|
+
private: true
|
|
1474
|
+
};
|
|
1475
|
+
strapi2.log.info('[webbycommerce] Registered "isOtpVerified" field in Strapi content-type');
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
} catch (schemaError) {
|
|
1479
|
+
strapi2.log.warn("[webbycommerce] Could not register fields in content-type schema:", schemaError.message);
|
|
1480
|
+
strapi2.log.warn("[webbycommerce] Database columns were added, but schema registration failed.");
|
|
1481
|
+
strapi2.log.warn(
|
|
1482
|
+
"[webbycommerce] You may need to restart Strapi or create a schema extension file in your main Strapi project."
|
|
1483
|
+
);
|
|
1484
|
+
}
|
|
1485
|
+
strapi2.log.info("[webbycommerce] User schema extension completed successfully");
|
|
1486
|
+
return true;
|
|
1487
|
+
} catch (error) {
|
|
1488
|
+
strapi2.log.error("[webbycommerce] Failed to extend user schema with OTP fields:", error);
|
|
1489
|
+
strapi2.log.error("[webbycommerce] Error details:", error.message);
|
|
1490
|
+
strapi2.log.error(
|
|
1491
|
+
"[webbycommerce] Please manually extend the user schema by creating a schema extension file in your Strapi project."
|
|
1492
|
+
);
|
|
1493
|
+
return false;
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
module2.exports = { extendUserSchemaWithOtpFields };
|
|
1497
|
+
}
|
|
1498
|
+
});
|
|
1499
|
+
|
|
1353
1500
|
// server/src/content-types/address/schema.json
|
|
1354
1501
|
var require_schema = __commonJS({
|
|
1355
1502
|
"server/src/content-types/address/schema.json"(exports2, module2) {
|
|
@@ -2945,11 +3092,21 @@ var require_bootstrap = __commonJS({
|
|
|
2945
3092
|
"server/src/bootstrap.js"(exports2, module2) {
|
|
2946
3093
|
"use strict";
|
|
2947
3094
|
var { registerEcommerceActions, ensureEcommercePermission } = require_check_ecommerce_permission();
|
|
3095
|
+
var { extendUserSchemaWithOtpFields } = require_extend_user_schema();
|
|
2948
3096
|
module2.exports = async ({ strapi: strapi2 }) => {
|
|
2949
3097
|
try {
|
|
2950
3098
|
strapi2.log.info("[webbycommerce] ========================================");
|
|
2951
3099
|
strapi2.log.info("[webbycommerce] Bootstrapping plugin...");
|
|
2952
|
-
|
|
3100
|
+
try {
|
|
3101
|
+
await extendUserSchemaWithOtpFields(strapi2);
|
|
3102
|
+
} catch (schemaError) {
|
|
3103
|
+
strapi2.log.warn("[webbycommerce] Could not automatically extend user schema:", schemaError.message);
|
|
3104
|
+
strapi2.log.warn(
|
|
3105
|
+
"[webbycommerce] Please manually extend the user schema. See README for instructions."
|
|
3106
|
+
);
|
|
3107
|
+
}
|
|
3108
|
+
const disableSeeding = process.env.STRAPI_PLUGIN_ADVANCED_ECOMMERCE_DISABLE_SEED_DEMO === "true" || process.env.STRAPI_PLUGIN_ADVANCED_ECOMMERCE_DISABLE_SEED_DEMO === "1" || process.env.STRAPI_PLUGIN_ADVANCED_ECOMMERCE_DISABLE_SEED_DEMO === "yes";
|
|
3109
|
+
if (!disableSeeding && process.env.STRAPI_PLUGIN_ADVANCED_ECOMMERCE_SEED_DATA === "true") {
|
|
2953
3110
|
try {
|
|
2954
3111
|
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
2955
3112
|
strapi2.log.info("[webbycommerce] Auto-seeding demo data as requested by environment variable...");
|
|
@@ -2963,6 +3120,10 @@ var require_bootstrap = __commonJS({
|
|
|
2963
3120
|
strapi2.log.error("[webbycommerce] Auto-seeding failed:", seedError.message);
|
|
2964
3121
|
strapi2.log.error("[webbycommerce] Stack:", seedError.stack);
|
|
2965
3122
|
}
|
|
3123
|
+
} else if (disableSeeding && process.env.STRAPI_PLUGIN_ADVANCED_ECOMMERCE_SEED_DATA === "true") {
|
|
3124
|
+
strapi2.log.info(
|
|
3125
|
+
"[webbycommerce] Demo seeding is disabled by STRAPI_PLUGIN_ADVANCED_ECOMMERCE_DISABLE_SEED_DEMO; skipping auto-seed."
|
|
3126
|
+
);
|
|
2966
3127
|
}
|
|
2967
3128
|
const contentTypes2 = require_content_types();
|
|
2968
3129
|
strapi2.log.info("[webbycommerce] Content types loaded:", Object.keys(contentTypes2));
|
|
@@ -4903,17 +5064,61 @@ var require_auth = __commonJS({
|
|
|
4903
5064
|
const otp = Math.floor(1e5 + Math.random() * 9e5);
|
|
4904
5065
|
const otpDigits = otp.toString().split("");
|
|
4905
5066
|
try {
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
5067
|
+
const db = strapi.db;
|
|
5068
|
+
const knex = db.connection;
|
|
5069
|
+
const tableName = "up_users";
|
|
5070
|
+
const client = db.config.connection.client;
|
|
5071
|
+
if (client === "postgres") {
|
|
5072
|
+
await knex.raw(
|
|
5073
|
+
`UPDATE ${tableName} SET otp = ?, is_otp_verified = ? WHERE id = ?`,
|
|
5074
|
+
[otp, false, user.id]
|
|
5075
|
+
);
|
|
5076
|
+
} else if (client === "mysql" || client === "mysql2") {
|
|
5077
|
+
await knex.raw(
|
|
5078
|
+
`UPDATE \`${tableName}\` SET \`otp\` = ?, \`is_otp_verified\` = ? WHERE \`id\` = ?`,
|
|
5079
|
+
[otp, false, user.id]
|
|
5080
|
+
);
|
|
5081
|
+
} else {
|
|
5082
|
+
await knex.raw(
|
|
5083
|
+
`UPDATE ${tableName} SET otp = ?, is_otp_verified = ? WHERE id = ?`,
|
|
5084
|
+
[otp, false, user.id]
|
|
5085
|
+
);
|
|
5086
|
+
}
|
|
4910
5087
|
} catch (err) {
|
|
4911
5088
|
strapi.log.warn(
|
|
4912
|
-
`[${PLUGIN_ID}] OTP fields not found in
|
|
4913
|
-
);
|
|
4914
|
-
throw new Error(
|
|
4915
|
-
"OTP fields are not available in the user schema. Please extend the user schema as described in the plugin README."
|
|
5089
|
+
`[${PLUGIN_ID}] OTP fields not found in database. Attempting to add them...`
|
|
4916
5090
|
);
|
|
5091
|
+
try {
|
|
5092
|
+
const { extendUserSchemaWithOtpFields } = require_extend_user_schema();
|
|
5093
|
+
await extendUserSchemaWithOtpFields(strapi);
|
|
5094
|
+
const db = strapi.db;
|
|
5095
|
+
const knex = db.connection;
|
|
5096
|
+
const tableName = "up_users";
|
|
5097
|
+
const client = db.config.connection.client;
|
|
5098
|
+
if (client === "postgres") {
|
|
5099
|
+
await knex.raw(
|
|
5100
|
+
`UPDATE ${tableName} SET otp = ?, is_otp_verified = ? WHERE id = ?`,
|
|
5101
|
+
[otp, false, user.id]
|
|
5102
|
+
);
|
|
5103
|
+
} else if (client === "mysql" || client === "mysql2") {
|
|
5104
|
+
await knex.raw(
|
|
5105
|
+
`UPDATE \`${tableName}\` SET \`otp\` = ?, \`is_otp_verified\` = ? WHERE \`id\` = ?`,
|
|
5106
|
+
[otp, false, user.id]
|
|
5107
|
+
);
|
|
5108
|
+
} else {
|
|
5109
|
+
await knex.raw(
|
|
5110
|
+
`UPDATE ${tableName} SET otp = ?, is_otp_verified = ? WHERE id = ?`,
|
|
5111
|
+
[otp, false, user.id]
|
|
5112
|
+
);
|
|
5113
|
+
}
|
|
5114
|
+
} catch (retryErr) {
|
|
5115
|
+
strapi.log.error(
|
|
5116
|
+
`[${PLUGIN_ID}] Failed to add OTP fields: ${retryErr.message}`
|
|
5117
|
+
);
|
|
5118
|
+
throw new Error(
|
|
5119
|
+
"OTP fields are not available in the user schema. Please extend the user schema as described in the plugin README."
|
|
5120
|
+
);
|
|
5121
|
+
}
|
|
4917
5122
|
}
|
|
4918
5123
|
let emailSent = false;
|
|
4919
5124
|
if (type === "email") {
|
|
@@ -4996,7 +5201,7 @@ var require_auth = __commonJS({
|
|
|
4996
5201
|
try {
|
|
4997
5202
|
await sendEmail({
|
|
4998
5203
|
to: email,
|
|
4999
|
-
subject: "Your OTP Code - Strapi
|
|
5204
|
+
subject: "Your OTP Code - Strapi WebbyCommerce",
|
|
5000
5205
|
html: otpEmailHTML
|
|
5001
5206
|
});
|
|
5002
5207
|
emailSent = true;
|
|
@@ -5045,21 +5250,110 @@ var require_auth = __commonJS({
|
|
|
5045
5250
|
where: { [type === "email" ? "email" : "phone_no"]: identifier }
|
|
5046
5251
|
});
|
|
5047
5252
|
if (!user) return ctx.badRequest("User not found.");
|
|
5048
|
-
|
|
5253
|
+
const db = strapi.db;
|
|
5254
|
+
const knex = db.connection;
|
|
5255
|
+
const tableName = "up_users";
|
|
5256
|
+
const client = db.config.connection.client;
|
|
5257
|
+
let userOtpData;
|
|
5258
|
+
let columnsExist = false;
|
|
5259
|
+
try {
|
|
5260
|
+
if (client === "postgres") {
|
|
5261
|
+
const result = await knex.raw(
|
|
5262
|
+
`SELECT otp, is_otp_verified FROM ${tableName} WHERE id = ?`,
|
|
5263
|
+
[user.id]
|
|
5264
|
+
);
|
|
5265
|
+
userOtpData = result.rows[0];
|
|
5266
|
+
columnsExist = userOtpData && userOtpData.hasOwnProperty("otp") && userOtpData.hasOwnProperty("is_otp_verified");
|
|
5267
|
+
} else if (client === "mysql" || client === "mysql2") {
|
|
5268
|
+
const result = await knex.raw(
|
|
5269
|
+
`SELECT \`otp\`, \`is_otp_verified\` FROM \`${tableName}\` WHERE \`id\` = ?`,
|
|
5270
|
+
[user.id]
|
|
5271
|
+
);
|
|
5272
|
+
userOtpData = result[0][0];
|
|
5273
|
+
columnsExist = userOtpData && userOtpData.hasOwnProperty("otp") && userOtpData.hasOwnProperty("is_otp_verified");
|
|
5274
|
+
} else {
|
|
5275
|
+
const result = await knex.raw(
|
|
5276
|
+
`SELECT otp, is_otp_verified FROM ${tableName} WHERE id = ?`,
|
|
5277
|
+
[user.id]
|
|
5278
|
+
);
|
|
5279
|
+
userOtpData = result[0];
|
|
5280
|
+
columnsExist = userOtpData && userOtpData.hasOwnProperty("otp") && userOtpData.hasOwnProperty("is_otp_verified");
|
|
5281
|
+
}
|
|
5282
|
+
} catch (queryErr) {
|
|
5283
|
+
strapi.log.warn(`[${PLUGIN_ID}] OTP columns not found, attempting to add them:`, queryErr.message);
|
|
5284
|
+
columnsExist = false;
|
|
5285
|
+
}
|
|
5286
|
+
if (!columnsExist) {
|
|
5287
|
+
const { extendUserSchemaWithOtpFields } = require_extend_user_schema();
|
|
5288
|
+
const schemaExtended = await extendUserSchemaWithOtpFields(strapi);
|
|
5289
|
+
if (!schemaExtended) {
|
|
5290
|
+
return ctx.badRequest(
|
|
5291
|
+
"OTP fields are not available in the user schema. Please extend the user schema as described in the plugin README."
|
|
5292
|
+
);
|
|
5293
|
+
}
|
|
5294
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
5295
|
+
try {
|
|
5296
|
+
if (client === "postgres") {
|
|
5297
|
+
const result = await knex.raw(
|
|
5298
|
+
`SELECT otp, is_otp_verified FROM ${tableName} WHERE id = ?`,
|
|
5299
|
+
[user.id]
|
|
5300
|
+
);
|
|
5301
|
+
userOtpData = result.rows[0];
|
|
5302
|
+
columnsExist = userOtpData && userOtpData.hasOwnProperty("otp") && userOtpData.hasOwnProperty("is_otp_verified");
|
|
5303
|
+
} else if (client === "mysql" || client === "mysql2") {
|
|
5304
|
+
const result = await knex.raw(
|
|
5305
|
+
`SELECT \`otp\`, \`is_otp_verified\` FROM \`${tableName}\` WHERE \`id\` = ?`,
|
|
5306
|
+
[user.id]
|
|
5307
|
+
);
|
|
5308
|
+
userOtpData = result[0][0];
|
|
5309
|
+
columnsExist = userOtpData && userOtpData.hasOwnProperty("otp") && userOtpData.hasOwnProperty("is_otp_verified");
|
|
5310
|
+
} else {
|
|
5311
|
+
const result = await knex.raw(
|
|
5312
|
+
`SELECT otp, is_otp_verified FROM ${tableName} WHERE id = ?`,
|
|
5313
|
+
[user.id]
|
|
5314
|
+
);
|
|
5315
|
+
userOtpData = result[0];
|
|
5316
|
+
columnsExist = userOtpData && userOtpData.hasOwnProperty("otp") && userOtpData.hasOwnProperty("is_otp_verified");
|
|
5317
|
+
}
|
|
5318
|
+
if (!columnsExist) {
|
|
5319
|
+
return ctx.badRequest(
|
|
5320
|
+
"OTP fields were added but could not be queried. Please restart Strapi."
|
|
5321
|
+
);
|
|
5322
|
+
}
|
|
5323
|
+
} catch (retryErr) {
|
|
5324
|
+
strapi.log.error(`[${PLUGIN_ID}] Failed to query OTP fields after extension:`, retryErr);
|
|
5325
|
+
return ctx.badRequest(
|
|
5326
|
+
"OTP fields are not available. Please restart Strapi after extending the user schema."
|
|
5327
|
+
);
|
|
5328
|
+
}
|
|
5329
|
+
}
|
|
5330
|
+
const userOtp = userOtpData?.otp;
|
|
5331
|
+
const isOtpVerified = userOtpData?.is_otp_verified;
|
|
5332
|
+
if (isOtpVerified) return ctx.badRequest("User already verified.");
|
|
5333
|
+
if (userOtp !== parseInt(otp, 10)) return ctx.badRequest("Invalid OTP.");
|
|
5334
|
+
try {
|
|
5335
|
+
if (client === "postgres") {
|
|
5336
|
+
await knex.raw(
|
|
5337
|
+
`UPDATE ${tableName} SET is_otp_verified = ?, confirmed = true, otp = NULL WHERE id = ?`,
|
|
5338
|
+
[true, user.id]
|
|
5339
|
+
);
|
|
5340
|
+
} else if (client === "mysql" || client === "mysql2") {
|
|
5341
|
+
await knex.raw(
|
|
5342
|
+
`UPDATE \`${tableName}\` SET \`is_otp_verified\` = ?, \`confirmed\` = true, \`otp\` = NULL WHERE \`id\` = ?`,
|
|
5343
|
+
[true, user.id]
|
|
5344
|
+
);
|
|
5345
|
+
} else {
|
|
5346
|
+
await knex.raw(
|
|
5347
|
+
`UPDATE ${tableName} SET is_otp_verified = ?, confirmed = 1, otp = NULL WHERE id = ?`,
|
|
5348
|
+
[true, user.id]
|
|
5349
|
+
);
|
|
5350
|
+
}
|
|
5351
|
+
} catch (dbErr) {
|
|
5352
|
+
strapi.log.error(`[${PLUGIN_ID}] Database error during OTP verification:`, dbErr);
|
|
5049
5353
|
return ctx.badRequest(
|
|
5050
5354
|
"OTP fields are not available in the user schema. Please extend the user schema as described in the plugin README."
|
|
5051
5355
|
);
|
|
5052
5356
|
}
|
|
5053
|
-
if (user.isOtpVerified) return ctx.badRequest("User already verified.");
|
|
5054
|
-
if (user.otp !== parseInt(otp, 10)) return ctx.badRequest("Invalid OTP.");
|
|
5055
|
-
await strapi.db.query("plugin::users-permissions.user").update({
|
|
5056
|
-
where: { id: user.id },
|
|
5057
|
-
data: {
|
|
5058
|
-
isOtpVerified: true,
|
|
5059
|
-
confirmed: true,
|
|
5060
|
-
otp: null
|
|
5061
|
-
}
|
|
5062
|
-
});
|
|
5063
5357
|
const jwt = strapi.plugins["users-permissions"].services.jwt.issue({
|
|
5064
5358
|
id: user.id
|
|
5065
5359
|
});
|
|
@@ -5602,7 +5896,7 @@ var require_compare2 = __commonJS({
|
|
|
5602
5896
|
ctx.send({
|
|
5603
5897
|
data: compare,
|
|
5604
5898
|
meta: {
|
|
5605
|
-
totalProducts: compare
|
|
5899
|
+
totalProducts: compare?.products?.length || 0,
|
|
5606
5900
|
comparisonData: compareData.comparisonData
|
|
5607
5901
|
}
|
|
5608
5902
|
});
|
|
@@ -5626,7 +5920,7 @@ var require_compare2 = __commonJS({
|
|
|
5626
5920
|
ctx.send({
|
|
5627
5921
|
data: compare,
|
|
5628
5922
|
meta: {
|
|
5629
|
-
totalProducts: compare
|
|
5923
|
+
totalProducts: compare?.products?.length || 0,
|
|
5630
5924
|
comparisonData: compareData.comparisonData
|
|
5631
5925
|
},
|
|
5632
5926
|
message: "Product added to compare list successfully"
|
|
@@ -5651,7 +5945,7 @@ var require_compare2 = __commonJS({
|
|
|
5651
5945
|
ctx.send({
|
|
5652
5946
|
data: compare,
|
|
5653
5947
|
meta: {
|
|
5654
|
-
totalProducts: compare
|
|
5948
|
+
totalProducts: compare?.products?.length || 0,
|
|
5655
5949
|
comparisonData: compareData.comparisonData
|
|
5656
5950
|
},
|
|
5657
5951
|
message: "Product removed from compare list successfully"
|
|
@@ -5726,9 +6020,12 @@ var require_compare2 = __commonJS({
|
|
|
5726
6020
|
const compare = await strapi2.plugin("webbycommerce").service("compare").findUserCompare(user.id);
|
|
5727
6021
|
const productIdArray = Array.isArray(productIds) ? productIds.map((id) => parseInt(id)) : [parseInt(productIds)];
|
|
5728
6022
|
const inCompare = {};
|
|
5729
|
-
if (compare) {
|
|
6023
|
+
if (compare && compare.products && Array.isArray(compare.products)) {
|
|
5730
6024
|
productIdArray.forEach((productId) => {
|
|
5731
|
-
inCompare[productId] = compare.products.some((product) =>
|
|
6025
|
+
inCompare[productId] = compare.products.some((product) => {
|
|
6026
|
+
const productIdValue = typeof product === "object" && product !== null ? product.id : product;
|
|
6027
|
+
return productIdValue === productId;
|
|
6028
|
+
});
|
|
5732
6029
|
});
|
|
5733
6030
|
} else {
|
|
5734
6031
|
productIdArray.forEach((productId) => {
|
|
@@ -5770,12 +6067,22 @@ var require_order2 = __commonJS({
|
|
|
5770
6067
|
shipping_address,
|
|
5771
6068
|
payment_method,
|
|
5772
6069
|
shipping_method,
|
|
5773
|
-
notes
|
|
6070
|
+
notes,
|
|
6071
|
+
tax_amount,
|
|
6072
|
+
shipping_amount,
|
|
6073
|
+
discount_amount
|
|
5774
6074
|
} = ctx.request.body;
|
|
5775
6075
|
if (!billing_address || !shipping_address || !payment_method) {
|
|
5776
6076
|
return ctx.badRequest("Billing address, shipping address, and payment method are required");
|
|
5777
6077
|
}
|
|
5778
|
-
|
|
6078
|
+
let normalizedPaymentMethod = "COD";
|
|
6079
|
+
if (payment_method) {
|
|
6080
|
+
if (typeof payment_method === "object" && payment_method !== null) {
|
|
6081
|
+
normalizedPaymentMethod = payment_method.type || payment_method.method || payment_method.name || "COD";
|
|
6082
|
+
} else if (typeof payment_method === "string") {
|
|
6083
|
+
normalizedPaymentMethod = payment_method;
|
|
6084
|
+
}
|
|
6085
|
+
}
|
|
5779
6086
|
const cart = await strapi.db.query("plugin::webbycommerce.cart").findOne({
|
|
5780
6087
|
where: { user: user.id },
|
|
5781
6088
|
select: ["id"]
|
|
@@ -5816,30 +6123,37 @@ var require_order2 = __commonJS({
|
|
|
5816
6123
|
product_image: product.images?.[0]?.url || null
|
|
5817
6124
|
});
|
|
5818
6125
|
}
|
|
5819
|
-
const taxAmount = 0;
|
|
5820
|
-
const
|
|
5821
|
-
const
|
|
5822
|
-
const total = subtotal + taxAmount +
|
|
6126
|
+
const taxAmount = tax_amount != null ? parseFloat(tax_amount) || 0 : 0;
|
|
6127
|
+
const finalShippingAmount = shipping_amount != null ? parseFloat(shipping_amount) || 0 : 0;
|
|
6128
|
+
const finalDiscountAmount = discount_amount != null ? parseFloat(discount_amount) || 0 : 0;
|
|
6129
|
+
const total = subtotal + taxAmount + finalShippingAmount - finalDiscountAmount;
|
|
5823
6130
|
const orderNumber = await this.generateOrderNumber();
|
|
6131
|
+
const itemsConnect = cartItems.length > 0 ? { connect: cartItems.map((item) => ({ id: item.product.id })) } : void 0;
|
|
6132
|
+
const orderData = {
|
|
6133
|
+
order_number: orderNumber,
|
|
6134
|
+
status: "pending",
|
|
6135
|
+
user: user.id,
|
|
6136
|
+
subtotal: subtotal.toFixed(2),
|
|
6137
|
+
tax_amount: taxAmount.toFixed(2),
|
|
6138
|
+
shipping_amount: finalShippingAmount.toFixed(2),
|
|
6139
|
+
// Use from request
|
|
6140
|
+
discount_amount: finalDiscountAmount.toFixed(2),
|
|
6141
|
+
// Use from request
|
|
6142
|
+
total: total.toFixed(2),
|
|
6143
|
+
currency: "USD",
|
|
6144
|
+
billing_address,
|
|
6145
|
+
shipping_address,
|
|
6146
|
+
payment_method: normalizedPaymentMethod,
|
|
6147
|
+
// Store as string
|
|
6148
|
+
payment_status: "pending",
|
|
6149
|
+
shipping_method: shipping_method || null,
|
|
6150
|
+
notes: notes || null
|
|
6151
|
+
};
|
|
6152
|
+
if (itemsConnect) {
|
|
6153
|
+
orderData.items = itemsConnect;
|
|
6154
|
+
}
|
|
5824
6155
|
const order = await strapi.db.query("plugin::webbycommerce.order").create({
|
|
5825
|
-
data:
|
|
5826
|
-
order_number: orderNumber,
|
|
5827
|
-
status: "pending",
|
|
5828
|
-
user: user.id,
|
|
5829
|
-
items: cartItems.map((item) => item.product.id),
|
|
5830
|
-
subtotal: subtotal.toFixed(2),
|
|
5831
|
-
tax_amount: taxAmount.toFixed(2),
|
|
5832
|
-
shipping_amount: shippingAmount.toFixed(2),
|
|
5833
|
-
discount_amount: discountAmount.toFixed(2),
|
|
5834
|
-
total: total.toFixed(2),
|
|
5835
|
-
currency: "USD",
|
|
5836
|
-
billing_address,
|
|
5837
|
-
shipping_address,
|
|
5838
|
-
payment_method: normalizedPaymentMethod,
|
|
5839
|
-
payment_status: "pending",
|
|
5840
|
-
shipping_method: shipping_method || null,
|
|
5841
|
-
notes: notes || null
|
|
5842
|
-
}
|
|
6156
|
+
data: orderData
|
|
5843
6157
|
});
|
|
5844
6158
|
for (const cartItem of cartItems) {
|
|
5845
6159
|
const newStockQuantity = cartItem.product.stock_quantity - cartItem.quantity;
|
|
@@ -5865,8 +6179,15 @@ var require_order2 = __commonJS({
|
|
|
5865
6179
|
order_id: order.id,
|
|
5866
6180
|
order_number: order.order_number,
|
|
5867
6181
|
status: order.status,
|
|
6182
|
+
subtotal: parseFloat(order.subtotal),
|
|
6183
|
+
tax_amount: parseFloat(order.tax_amount),
|
|
6184
|
+
shipping_amount: parseFloat(order.shipping_amount),
|
|
6185
|
+
discount_amount: parseFloat(order.discount_amount),
|
|
5868
6186
|
total: parseFloat(order.total),
|
|
5869
6187
|
currency: order.currency,
|
|
6188
|
+
payment_method: order.payment_method,
|
|
6189
|
+
// Return payment method as string
|
|
6190
|
+
shipping_method: order.shipping_method,
|
|
5870
6191
|
items: order.items,
|
|
5871
6192
|
created_at: order.createdAt
|
|
5872
6193
|
},
|
|
@@ -5892,7 +6213,7 @@ var require_order2 = __commonJS({
|
|
|
5892
6213
|
const query = {
|
|
5893
6214
|
where: { user: user.id },
|
|
5894
6215
|
orderBy: { createdAt: "desc" },
|
|
5895
|
-
populate: ["items"],
|
|
6216
|
+
populate: ["items", "billing_address", "shipping_address", "user", "payment_transactions"],
|
|
5896
6217
|
limit: parseInt(limit),
|
|
5897
6218
|
offset: (parseInt(page) - 1) * parseInt(limit)
|
|
5898
6219
|
};
|
|
@@ -5903,17 +6224,80 @@ var require_order2 = __commonJS({
|
|
|
5903
6224
|
const total = await strapi.db.query("plugin::webbycommerce.order").count({
|
|
5904
6225
|
where: { user: user.id, ...status && { status } }
|
|
5905
6226
|
});
|
|
5906
|
-
const formattedOrders = orders.map((order) =>
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
6227
|
+
const formattedOrders = await Promise.all(orders.map(async (order) => {
|
|
6228
|
+
let formattedItems = [];
|
|
6229
|
+
if (order.items && order.items.length > 0) {
|
|
6230
|
+
const itemIds = order.items.map((item) => typeof item === "object" && item.id ? item.id : item);
|
|
6231
|
+
const products = await strapi.db.query("plugin::webbycommerce.product").findMany({
|
|
6232
|
+
where: {
|
|
6233
|
+
id: { $in: itemIds }
|
|
6234
|
+
},
|
|
6235
|
+
populate: {
|
|
6236
|
+
images: true
|
|
6237
|
+
}
|
|
6238
|
+
});
|
|
6239
|
+
formattedItems = products.map((product) => ({
|
|
6240
|
+
id: product.id,
|
|
6241
|
+
name: product.name,
|
|
6242
|
+
sku: product.sku,
|
|
6243
|
+
price: parseFloat(product.price || 0),
|
|
6244
|
+
sale_price: product.sale_price ? parseFloat(product.sale_price) : null,
|
|
6245
|
+
images: product.images || [],
|
|
6246
|
+
slug: product.slug,
|
|
6247
|
+
description: product.description
|
|
6248
|
+
}));
|
|
6249
|
+
} else if (order.items && Array.isArray(order.items)) {
|
|
6250
|
+
formattedItems = order.items.map((item) => ({
|
|
6251
|
+
id: item.id,
|
|
6252
|
+
name: item.name,
|
|
6253
|
+
sku: item.sku,
|
|
6254
|
+
price: parseFloat(item.price || 0),
|
|
6255
|
+
sale_price: item.sale_price ? parseFloat(item.sale_price) : null,
|
|
6256
|
+
images: item.images || [],
|
|
6257
|
+
slug: item.slug,
|
|
6258
|
+
description: item.description
|
|
6259
|
+
}));
|
|
6260
|
+
}
|
|
6261
|
+
const shippingAmount = parseFloat(order.shipping_amount || 0);
|
|
6262
|
+
const subtotalAmount = parseFloat(order.subtotal || 0);
|
|
6263
|
+
const discountAmount = parseFloat(order.discount_amount || 0);
|
|
6264
|
+
return {
|
|
6265
|
+
id: order.id,
|
|
6266
|
+
order_number: order.order_number,
|
|
6267
|
+
status: order.status,
|
|
6268
|
+
payment_status: order.payment_status,
|
|
6269
|
+
items: formattedItems,
|
|
6270
|
+
items_count: formattedItems.length,
|
|
6271
|
+
subtotal: subtotalAmount,
|
|
6272
|
+
tax_amount: parseFloat(order.tax_amount || 0),
|
|
6273
|
+
shipping: shippingAmount,
|
|
6274
|
+
shipping_amount: shippingAmount,
|
|
6275
|
+
discount: discountAmount,
|
|
6276
|
+
discount_amount: discountAmount,
|
|
6277
|
+
total: parseFloat(order.total || 0),
|
|
6278
|
+
currency: order.currency,
|
|
6279
|
+
billing_address: order.billing_address,
|
|
6280
|
+
shipping_address: order.shipping_address,
|
|
6281
|
+
payment_method: (() => {
|
|
6282
|
+
if (!order.payment_method) return "N/A";
|
|
6283
|
+
if (typeof order.payment_method === "object" && order.payment_method !== null) {
|
|
6284
|
+
return order.payment_method.type || order.payment_method.method || order.payment_method.name || String(order.payment_method);
|
|
6285
|
+
}
|
|
6286
|
+
return String(order.payment_method);
|
|
6287
|
+
})(),
|
|
6288
|
+
shipping_method: order.shipping_method,
|
|
6289
|
+
notes: order.notes,
|
|
6290
|
+
tracking_number: order.tracking_number,
|
|
6291
|
+
estimated_delivery: order.estimated_delivery,
|
|
6292
|
+
payment_transactions: order.payment_transactions || [],
|
|
6293
|
+
user: order.user ? {
|
|
6294
|
+
id: order.user.id,
|
|
6295
|
+
username: order.user.username,
|
|
6296
|
+
email: order.user.email
|
|
6297
|
+
} : null,
|
|
6298
|
+
created_at: order.createdAt,
|
|
6299
|
+
updated_at: order.updatedAt
|
|
6300
|
+
};
|
|
5917
6301
|
}));
|
|
5918
6302
|
ctx.send({
|
|
5919
6303
|
data: formattedOrders,
|
|
@@ -5944,34 +6328,86 @@ var require_order2 = __commonJS({
|
|
|
5944
6328
|
}
|
|
5945
6329
|
const { id } = ctx.params;
|
|
5946
6330
|
if (!id) {
|
|
5947
|
-
return ctx.badRequest("Order ID is required");
|
|
6331
|
+
return ctx.badRequest("Order ID or order number is required");
|
|
5948
6332
|
}
|
|
5949
|
-
const
|
|
5950
|
-
|
|
5951
|
-
|
|
6333
|
+
const isOrderNumber = id.toString().startsWith("ORD-");
|
|
6334
|
+
const whereClause = {
|
|
6335
|
+
user: user.id
|
|
6336
|
+
// Filter by user ID directly for security
|
|
6337
|
+
};
|
|
6338
|
+
if (isOrderNumber) {
|
|
6339
|
+
whereClause.order_number = id;
|
|
6340
|
+
} else {
|
|
6341
|
+
whereClause.id = id;
|
|
6342
|
+
}
|
|
6343
|
+
let order = await strapi.db.query("plugin::webbycommerce.order").findOne({
|
|
6344
|
+
where: whereClause,
|
|
6345
|
+
populate: ["billing_address", "shipping_address", "items", "user"]
|
|
5952
6346
|
});
|
|
5953
6347
|
if (!order) {
|
|
5954
6348
|
return ctx.notFound("Order not found");
|
|
5955
6349
|
}
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
6350
|
+
let formattedItems = [];
|
|
6351
|
+
if (order.items && order.items.length > 0) {
|
|
6352
|
+
const itemIds = order.items.map((item) => typeof item === "object" && item.id ? item.id : item);
|
|
6353
|
+
const products = await strapi.db.query("plugin::webbycommerce.product").findMany({
|
|
6354
|
+
where: {
|
|
6355
|
+
id: { $in: itemIds }
|
|
6356
|
+
},
|
|
6357
|
+
populate: {
|
|
6358
|
+
images: true
|
|
6359
|
+
}
|
|
6360
|
+
});
|
|
6361
|
+
formattedItems = products.map((product) => ({
|
|
6362
|
+
id: product.id,
|
|
6363
|
+
name: product.name,
|
|
6364
|
+
sku: product.sku,
|
|
6365
|
+
price: parseFloat(product.price || 0),
|
|
6366
|
+
sale_price: product.sale_price ? parseFloat(product.sale_price) : null,
|
|
6367
|
+
images: product.images || [],
|
|
6368
|
+
slug: product.slug,
|
|
6369
|
+
description: product.description
|
|
6370
|
+
}));
|
|
6371
|
+
} else if (order.items && Array.isArray(order.items)) {
|
|
6372
|
+
formattedItems = order.items.map((item) => ({
|
|
6373
|
+
id: item.id,
|
|
6374
|
+
name: item.name,
|
|
6375
|
+
sku: item.sku,
|
|
6376
|
+
price: parseFloat(item.price || 0),
|
|
6377
|
+
sale_price: item.sale_price ? parseFloat(item.sale_price) : null,
|
|
6378
|
+
images: item.images || [],
|
|
6379
|
+
slug: item.slug,
|
|
6380
|
+
description: item.description
|
|
6381
|
+
}));
|
|
6382
|
+
}
|
|
6383
|
+
const shippingAmount = parseFloat(order.shipping_amount || 0);
|
|
6384
|
+
const subtotalAmount = parseFloat(order.subtotal || 0);
|
|
6385
|
+
const discountAmount = parseFloat(order.discount_amount || 0);
|
|
5959
6386
|
ctx.send({
|
|
5960
6387
|
data: {
|
|
5961
6388
|
id: order.id,
|
|
5962
6389
|
order_number: order.order_number,
|
|
5963
6390
|
status: order.status,
|
|
5964
6391
|
payment_status: order.payment_status,
|
|
5965
|
-
items:
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
6392
|
+
items: formattedItems,
|
|
6393
|
+
items_count: formattedItems.length,
|
|
6394
|
+
subtotal: subtotalAmount,
|
|
6395
|
+
tax_amount: parseFloat(order.tax_amount || 0),
|
|
6396
|
+
shipping: shippingAmount,
|
|
6397
|
+
shipping_amount: shippingAmount,
|
|
6398
|
+
discount: discountAmount,
|
|
6399
|
+
discount_amount: discountAmount,
|
|
6400
|
+
total: parseFloat(order.total || 0),
|
|
5971
6401
|
currency: order.currency,
|
|
5972
6402
|
billing_address: order.billing_address,
|
|
5973
6403
|
shipping_address: order.shipping_address,
|
|
5974
|
-
payment_method:
|
|
6404
|
+
payment_method: (() => {
|
|
6405
|
+
if (!order.payment_method) return "N/A";
|
|
6406
|
+
if (typeof order.payment_method === "object" && order.payment_method !== null) {
|
|
6407
|
+
return order.payment_method.type || order.payment_method.method || order.payment_method.name || String(order.payment_method);
|
|
6408
|
+
}
|
|
6409
|
+
return String(order.payment_method);
|
|
6410
|
+
})(),
|
|
5975
6411
|
shipping_method: order.shipping_method,
|
|
5976
6412
|
notes: order.notes,
|
|
5977
6413
|
tracking_number: order.tracking_number,
|
|
@@ -5985,64 +6421,162 @@ var require_order2 = __commonJS({
|
|
|
5985
6421
|
ctx.badRequest("Failed to retrieve order");
|
|
5986
6422
|
}
|
|
5987
6423
|
},
|
|
5988
|
-
// Cancel order (only if pending)
|
|
6424
|
+
// Cancel order (only if pending or processing)
|
|
5989
6425
|
async cancelOrder(ctx) {
|
|
5990
6426
|
try {
|
|
5991
6427
|
const user = ctx.state.user;
|
|
5992
6428
|
if (!user) {
|
|
5993
6429
|
return ctx.unauthorized("Authentication required");
|
|
5994
6430
|
}
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
6431
|
+
try {
|
|
6432
|
+
const hasPermission = await ensureEcommercePermission(ctx);
|
|
6433
|
+
if (!hasPermission) {
|
|
6434
|
+
return;
|
|
6435
|
+
}
|
|
6436
|
+
} catch (permissionError) {
|
|
6437
|
+
strapi.log.error(`[cancelOrder] Error checking permission:`, permissionError);
|
|
6438
|
+
return ctx.badRequest("Permission check failed");
|
|
5998
6439
|
}
|
|
5999
6440
|
const { id } = ctx.params;
|
|
6000
6441
|
if (!id) {
|
|
6001
6442
|
return ctx.badRequest("Order ID is required");
|
|
6002
6443
|
}
|
|
6003
|
-
const
|
|
6004
|
-
|
|
6005
|
-
|
|
6444
|
+
const orderId = typeof id === "string" ? isNaN(id) ? id : parseInt(id, 10) : id;
|
|
6445
|
+
strapi.log.info(`[cancelOrder] Attempting to cancel order ${orderId} (original: ${id}, type: ${typeof id}) for user ${user.id}`);
|
|
6446
|
+
let order;
|
|
6447
|
+
try {
|
|
6448
|
+
order = await strapi.db.query("plugin::webbycommerce.order").findOne({
|
|
6449
|
+
where: {
|
|
6450
|
+
id: orderId,
|
|
6451
|
+
user: user.id
|
|
6452
|
+
// Filter by user ID directly for security
|
|
6453
|
+
},
|
|
6454
|
+
populate: ["items", "user"]
|
|
6455
|
+
});
|
|
6456
|
+
if (!order && orderId !== id) {
|
|
6457
|
+
strapi.log.info(`[cancelOrder] Order not found with normalized ID ${orderId}, trying original ID ${id}`);
|
|
6458
|
+
order = await strapi.db.query("plugin::webbycommerce.order").findOne({
|
|
6459
|
+
where: {
|
|
6460
|
+
id,
|
|
6461
|
+
user: user.id
|
|
6462
|
+
},
|
|
6463
|
+
populate: ["items", "user"]
|
|
6464
|
+
});
|
|
6465
|
+
}
|
|
6466
|
+
} catch (queryError) {
|
|
6467
|
+
strapi.log.error(`[cancelOrder] Error querying order ${orderId}:`, queryError);
|
|
6468
|
+
strapi.log.error(`[cancelOrder] Query error message:`, queryError.message);
|
|
6469
|
+
return ctx.badRequest(`Failed to retrieve order: ${queryError.message || "Database error"}`);
|
|
6470
|
+
}
|
|
6006
6471
|
if (!order) {
|
|
6472
|
+
strapi.log.warn(`[cancelOrder] Order ${orderId} not found for user ${user.id}`);
|
|
6007
6473
|
return ctx.notFound("Order not found");
|
|
6008
6474
|
}
|
|
6009
|
-
|
|
6010
|
-
|
|
6475
|
+
strapi.log.info(`[cancelOrder] Found order ${order.id} (order_number: ${order.order_number}) with status: ${order.status || "null/undefined"}`);
|
|
6476
|
+
const orderStatus = order.status || "";
|
|
6477
|
+
const cancellableStatuses = ["pending", "processing"];
|
|
6478
|
+
if (!orderStatus) {
|
|
6479
|
+
strapi.log.warn(`[cancelOrder] Order ${order.id} has no status`);
|
|
6480
|
+
return ctx.badRequest("Order status is invalid");
|
|
6011
6481
|
}
|
|
6012
|
-
if (
|
|
6013
|
-
|
|
6482
|
+
if (!cancellableStatuses.includes(orderStatus)) {
|
|
6483
|
+
if (orderStatus === "cancelled") {
|
|
6484
|
+
return ctx.badRequest("Order is already cancelled");
|
|
6485
|
+
}
|
|
6486
|
+
if (orderStatus === "delivered") {
|
|
6487
|
+
return ctx.badRequest("Delivered orders cannot be cancelled");
|
|
6488
|
+
}
|
|
6489
|
+
if (orderStatus === "shipped") {
|
|
6490
|
+
return ctx.badRequest("Shipped orders cannot be cancelled. Please contact support for returns.");
|
|
6491
|
+
}
|
|
6492
|
+
return ctx.badRequest(`Order with status '${orderStatus}' cannot be cancelled`);
|
|
6014
6493
|
}
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
const product = await strapi.db.query("plugin::webbycommerce.product").findOne({
|
|
6021
|
-
where: { id: item.product_id }
|
|
6494
|
+
let updatedOrder;
|
|
6495
|
+
try {
|
|
6496
|
+
updatedOrder = await strapi.db.query("plugin::webbycommerce.order").update({
|
|
6497
|
+
where: { id: order.id },
|
|
6498
|
+
data: { status: "cancelled" }
|
|
6022
6499
|
});
|
|
6023
|
-
if (
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6500
|
+
if (!updatedOrder) {
|
|
6501
|
+
strapi.log.error(`[cancelOrder] Failed to update order ${order.id} status - update returned null`);
|
|
6502
|
+
return ctx.badRequest("Failed to update order status");
|
|
6503
|
+
}
|
|
6504
|
+
strapi.log.info(`[cancelOrder] Successfully updated order ${order.id} status to cancelled`);
|
|
6505
|
+
} catch (updateError) {
|
|
6506
|
+
strapi.log.error(`[cancelOrder] Error updating order ${order.id}:`, updateError);
|
|
6507
|
+
strapi.log.error(`[cancelOrder] Update error message:`, updateError.message);
|
|
6508
|
+
strapi.log.error(`[cancelOrder] Update error stack:`, updateError.stack);
|
|
6509
|
+
return ctx.badRequest(`Failed to update order status: ${updateError.message || "Unknown error"}`);
|
|
6510
|
+
}
|
|
6511
|
+
if (order.items && Array.isArray(order.items) && order.items.length > 0) {
|
|
6512
|
+
try {
|
|
6513
|
+
for (const item of order.items) {
|
|
6514
|
+
const productId = typeof item === "object" && item.id ? item.id : item;
|
|
6515
|
+
if (!productId) {
|
|
6516
|
+
strapi.log.warn(`[cancelOrder] Skipping item with invalid ID for order ${order.id}`);
|
|
6517
|
+
continue;
|
|
6031
6518
|
}
|
|
6032
|
-
|
|
6519
|
+
try {
|
|
6520
|
+
const product = await strapi.db.query("plugin::webbycommerce.product").findOne({
|
|
6521
|
+
where: { id: productId }
|
|
6522
|
+
});
|
|
6523
|
+
if (product) {
|
|
6524
|
+
const quantityToRestore = 1;
|
|
6525
|
+
const newStockQuantity = (product.stock_quantity || 0) + quantityToRestore;
|
|
6526
|
+
const newStockStatus = newStockQuantity > 0 ? "in_stock" : "out_of_stock";
|
|
6527
|
+
await strapi.db.query("plugin::webbycommerce.product").update({
|
|
6528
|
+
where: { id: productId },
|
|
6529
|
+
data: {
|
|
6530
|
+
stock_quantity: newStockQuantity,
|
|
6531
|
+
stock_status: newStockStatus
|
|
6532
|
+
}
|
|
6533
|
+
});
|
|
6534
|
+
strapi.log.info(`[cancelOrder] Restored ${quantityToRestore} unit(s) of product ${productId} for order ${order.id}`);
|
|
6535
|
+
} else {
|
|
6536
|
+
strapi.log.warn(`[cancelOrder] Product ${productId} not found for order ${order.id}`);
|
|
6537
|
+
}
|
|
6538
|
+
} catch (productError) {
|
|
6539
|
+
strapi.log.error(`[cancelOrder] Error processing product ${productId} for order ${order.id}:`, productError);
|
|
6540
|
+
}
|
|
6541
|
+
}
|
|
6542
|
+
} catch (stockError) {
|
|
6543
|
+
strapi.log.error(`[cancelOrder] Error restoring stock for order ${order.id}:`, stockError);
|
|
6033
6544
|
}
|
|
6034
6545
|
}
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6546
|
+
try {
|
|
6547
|
+
return ctx.send({
|
|
6548
|
+
data: {
|
|
6549
|
+
id: updatedOrder.id,
|
|
6550
|
+
order_number: updatedOrder.order_number,
|
|
6551
|
+
status: updatedOrder.status
|
|
6552
|
+
},
|
|
6553
|
+
message: "Order cancelled successfully"
|
|
6554
|
+
});
|
|
6555
|
+
} catch (sendError) {
|
|
6556
|
+
strapi.log.error(`[cancelOrder] Error sending response for order ${order.id}:`, sendError);
|
|
6557
|
+
return ctx.send({
|
|
6558
|
+
data: {
|
|
6559
|
+
id: updatedOrder.id,
|
|
6560
|
+
order_number: updatedOrder.order_number,
|
|
6561
|
+
status: updatedOrder.status
|
|
6562
|
+
},
|
|
6563
|
+
message: "Order cancelled successfully"
|
|
6564
|
+
});
|
|
6565
|
+
}
|
|
6043
6566
|
} catch (error) {
|
|
6044
|
-
strapi.log.error(
|
|
6045
|
-
|
|
6567
|
+
strapi.log.error(`[cancelOrder] Unexpected error cancelling order:`, error);
|
|
6568
|
+
strapi.log.error(`[cancelOrder] Error name:`, error.name);
|
|
6569
|
+
strapi.log.error(`[cancelOrder] Error message:`, error.message);
|
|
6570
|
+
strapi.log.error(`[cancelOrder] Error stack:`, error.stack);
|
|
6571
|
+
const errorMessage = error.message || "Unknown error occurred";
|
|
6572
|
+
const errorDetails = error.details ? JSON.stringify(error.details) : "";
|
|
6573
|
+
strapi.log.error(`[cancelOrder] Full error details:`, {
|
|
6574
|
+
name: error.name,
|
|
6575
|
+
message: errorMessage,
|
|
6576
|
+
details: errorDetails,
|
|
6577
|
+
stack: error.stack
|
|
6578
|
+
});
|
|
6579
|
+
return ctx.badRequest(`Failed to cancel order: ${errorMessage}${errorDetails ? ` - ${errorDetails}` : ""}`);
|
|
6046
6580
|
}
|
|
6047
6581
|
},
|
|
6048
6582
|
// Update order status (admin only)
|
|
@@ -6135,15 +6669,16 @@ var require_order2 = __commonJS({
|
|
|
6135
6669
|
return ctx.badRequest("Order ID is required");
|
|
6136
6670
|
}
|
|
6137
6671
|
const order = await strapi.db.query("plugin::webbycommerce.order").findOne({
|
|
6138
|
-
where: {
|
|
6139
|
-
|
|
6672
|
+
where: {
|
|
6673
|
+
id,
|
|
6674
|
+
user: user.id
|
|
6675
|
+
// Filter by user ID directly for security
|
|
6676
|
+
},
|
|
6677
|
+
populate: ["shipping_address", "user"]
|
|
6140
6678
|
});
|
|
6141
6679
|
if (!order) {
|
|
6142
6680
|
return ctx.notFound("Order not found");
|
|
6143
6681
|
}
|
|
6144
|
-
if (order.user !== user.id) {
|
|
6145
|
-
return ctx.forbidden("You can only view your own order tracking");
|
|
6146
|
-
}
|
|
6147
6682
|
const trackingTimeline = this.generateTrackingTimeline(order);
|
|
6148
6683
|
ctx.send({
|
|
6149
6684
|
data: {
|
|
@@ -6172,87 +6707,142 @@ var require_order2 = __commonJS({
|
|
|
6172
6707
|
},
|
|
6173
6708
|
// Send order confirmation email
|
|
6174
6709
|
async sendOrderConfirmationEmail(user, order) {
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6710
|
+
try {
|
|
6711
|
+
const settings = await strapi.store({ type: "plugin", name: "webbycommerce" }).get({ key: "settings" });
|
|
6712
|
+
const smtpSettings = settings?.smtp;
|
|
6713
|
+
if (!smtpSettings) {
|
|
6714
|
+
strapi.log.warn("SMTP settings not configured, skipping order confirmation email");
|
|
6715
|
+
return;
|
|
6716
|
+
}
|
|
6717
|
+
let orderWithItems = order;
|
|
6718
|
+
if (!order.items || !Array.isArray(order.items) || order.items.length === 0) {
|
|
6719
|
+
orderWithItems = await strapi.db.query("plugin::webbycommerce.order").findOne({
|
|
6720
|
+
where: { id: order.id },
|
|
6721
|
+
populate: ["items"]
|
|
6722
|
+
});
|
|
6723
|
+
}
|
|
6724
|
+
let itemsHtml = "<li>No items found</li>";
|
|
6725
|
+
if (orderWithItems && orderWithItems.items && Array.isArray(orderWithItems.items) && orderWithItems.items.length > 0) {
|
|
6726
|
+
itemsHtml = orderWithItems.items.map((item) => {
|
|
6727
|
+
if (!item) return "";
|
|
6728
|
+
const productName = item.name || item.product_name || "Unknown Product";
|
|
6729
|
+
const productPrice = item.price || item.product_price || 0;
|
|
6730
|
+
return `<li>${productName} - $${parseFloat(productPrice).toFixed(2)}</li>`;
|
|
6731
|
+
}).filter((item) => item !== "").join("");
|
|
6732
|
+
if (!itemsHtml) {
|
|
6733
|
+
itemsHtml = "<li>No items found</li>";
|
|
6734
|
+
}
|
|
6735
|
+
}
|
|
6736
|
+
const emailData = {
|
|
6737
|
+
to: user.email,
|
|
6738
|
+
subject: `Order Confirmation - ${order.order_number || orderWithItems?.order_number || "N/A"}`,
|
|
6739
|
+
html: `
|
|
6740
|
+
<h2>Order Confirmation</h2>
|
|
6741
|
+
<p>Dear ${user.username || "Customer"},</p>
|
|
6742
|
+
<p>Thank you for your order! Here are the details:</p>
|
|
6743
|
+
<h3>Order #${order.order_number || orderWithItems?.order_number || "N/A"}</h3>
|
|
6744
|
+
<p><strong>Total: $${order.total || orderWithItems?.total || 0} ${order.currency || orderWithItems?.currency || "USD"}</strong></p>
|
|
6745
|
+
<p><strong>Status:</strong> ${order.status || orderWithItems?.status || "pending"}</p>
|
|
6746
|
+
<p><strong>Items:</strong></p>
|
|
6747
|
+
<ul>
|
|
6748
|
+
${itemsHtml}
|
|
6749
|
+
</ul>
|
|
6750
|
+
<p>We will process your order shortly.</p>
|
|
6751
|
+
<p>Best regards,<br>Your Ecommerce Team</p>
|
|
6752
|
+
`
|
|
6753
|
+
};
|
|
6754
|
+
await sendEmail(emailData);
|
|
6755
|
+
strapi.log.info(`Order confirmation email sent successfully for order ${order.id || orderWithItems?.id}`);
|
|
6756
|
+
} catch (error) {
|
|
6757
|
+
strapi.log.error("Error sending order confirmation email:", error);
|
|
6758
|
+
strapi.log.error("Email error details:", {
|
|
6759
|
+
message: error.message,
|
|
6760
|
+
stack: error.stack,
|
|
6761
|
+
orderId: order?.id,
|
|
6762
|
+
orderNumber: order?.order_number
|
|
6763
|
+
});
|
|
6764
|
+
}
|
|
6200
6765
|
},
|
|
6201
6766
|
// Send order status update email
|
|
6202
6767
|
async sendOrderStatusUpdateEmail(user, order, newStatus) {
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6768
|
+
try {
|
|
6769
|
+
const settings = await strapi.store({ type: "plugin", name: "webbycommerce" }).get({ key: "settings" });
|
|
6770
|
+
const smtpSettings = settings?.smtp;
|
|
6771
|
+
if (!smtpSettings) {
|
|
6772
|
+
strapi.log.warn("SMTP settings not configured, skipping order status update email");
|
|
6773
|
+
return;
|
|
6774
|
+
}
|
|
6775
|
+
const statusMessages = {
|
|
6776
|
+
pending: "Your order is being prepared",
|
|
6777
|
+
processing: "Your order is now being processed",
|
|
6778
|
+
shipped: "Your order has been shipped",
|
|
6779
|
+
delivered: "Your order has been delivered successfully",
|
|
6780
|
+
cancelled: "Your order has been cancelled",
|
|
6781
|
+
refunded: "Your order has been refunded"
|
|
6782
|
+
};
|
|
6783
|
+
const emailData = {
|
|
6784
|
+
to: user.email,
|
|
6785
|
+
subject: `Order Status Update - ${order.order_number || "N/A"}`,
|
|
6786
|
+
html: `
|
|
6787
|
+
<h2>Order Status Update</h2>
|
|
6788
|
+
<p>Dear ${user.username || "Customer"},</p>
|
|
6789
|
+
<p>Your order status has been updated:</p>
|
|
6790
|
+
<h3>Order #${order.order_number || "N/A"}</h3>
|
|
6791
|
+
<p><strong>Status: ${newStatus ? newStatus.toUpperCase() : "UPDATED"}</strong></p>
|
|
6792
|
+
<p><strong>Message:</strong> ${statusMessages[newStatus] || "Status updated"}</p>
|
|
6793
|
+
${order.tracking_number ? `<p><strong>Tracking Number:</strong> ${order.tracking_number}</p>` : ""}
|
|
6794
|
+
${order.estimated_delivery ? `<p><strong>Estimated Delivery:</strong> ${new Date(order.estimated_delivery).toLocaleDateString()}</p>` : ""}
|
|
6795
|
+
<p>You can track your order at any time using our order tracking feature.</p>
|
|
6796
|
+
<p>Best regards,<br>Your Ecommerce Team</p>
|
|
6797
|
+
`
|
|
6798
|
+
};
|
|
6799
|
+
await sendEmail(emailData);
|
|
6800
|
+
strapi.log.info(`Order status update email sent successfully for order ${order.id}`);
|
|
6801
|
+
} catch (error) {
|
|
6802
|
+
strapi.log.error("Error sending order status update email:", error);
|
|
6803
|
+
strapi.log.error("Email error details:", {
|
|
6804
|
+
message: error.message,
|
|
6805
|
+
stack: error.stack,
|
|
6806
|
+
orderId: order?.id,
|
|
6807
|
+
orderNumber: order?.order_number,
|
|
6808
|
+
newStatus
|
|
6809
|
+
});
|
|
6208
6810
|
}
|
|
6209
|
-
const statusMessages = {
|
|
6210
|
-
pending: "Your order is being prepared",
|
|
6211
|
-
processing: "Your order is now being processed",
|
|
6212
|
-
shipped: "Your order has been shipped",
|
|
6213
|
-
delivered: "Your order has been delivered successfully",
|
|
6214
|
-
cancelled: "Your order has been cancelled",
|
|
6215
|
-
refunded: "Your order has been refunded"
|
|
6216
|
-
};
|
|
6217
|
-
const emailData = {
|
|
6218
|
-
to: user.email,
|
|
6219
|
-
subject: `Order Status Update - ${order.order_number}`,
|
|
6220
|
-
html: `
|
|
6221
|
-
<h2>Order Status Update</h2>
|
|
6222
|
-
<p>Dear ${user.username || "Customer"},</p>
|
|
6223
|
-
<p>Your order status has been updated:</p>
|
|
6224
|
-
<h3>Order #${order.order_number}</h3>
|
|
6225
|
-
<p><strong>Status: ${newStatus.toUpperCase()}</strong></p>
|
|
6226
|
-
<p><strong>Message:</strong> ${statusMessages[newStatus] || "Status updated"}</p>
|
|
6227
|
-
${order.tracking_number ? `<p><strong>Tracking Number:</strong> ${order.tracking_number}</p>` : ""}
|
|
6228
|
-
${order.estimated_delivery ? `<p><strong>Estimated Delivery:</strong> ${new Date(order.estimated_delivery).toLocaleDateString()}</p>` : ""}
|
|
6229
|
-
<p>You can track your order at any time using our order tracking feature.</p>
|
|
6230
|
-
<p>Best regards,<br>Your Ecommerce Team</p>
|
|
6231
|
-
`
|
|
6232
|
-
};
|
|
6233
|
-
await sendEmail(emailData);
|
|
6234
6811
|
},
|
|
6235
6812
|
// Restore stock when order is cancelled
|
|
6236
6813
|
async restoreOrderStock(order) {
|
|
6237
6814
|
try {
|
|
6815
|
+
if (!order.items || !Array.isArray(order.items) || order.items.length === 0) {
|
|
6816
|
+
strapi.log.warn(`[restoreOrderStock] No items found for order ${order.id}`);
|
|
6817
|
+
return;
|
|
6818
|
+
}
|
|
6238
6819
|
for (const item of order.items) {
|
|
6820
|
+
const productId = typeof item === "object" && item.id ? item.id : item;
|
|
6821
|
+
if (!productId) {
|
|
6822
|
+
strapi.log.warn(`[restoreOrderStock] Skipping item with invalid ID for order ${order.id}`);
|
|
6823
|
+
continue;
|
|
6824
|
+
}
|
|
6239
6825
|
const product = await strapi.db.query("plugin::webbycommerce.product").findOne({
|
|
6240
|
-
where: { id:
|
|
6826
|
+
where: { id: productId }
|
|
6241
6827
|
});
|
|
6242
6828
|
if (product) {
|
|
6243
|
-
const
|
|
6829
|
+
const quantityToRestore = 1;
|
|
6830
|
+
const newStockQuantity = (product.stock_quantity || 0) + quantityToRestore;
|
|
6244
6831
|
const newStockStatus = newStockQuantity > 0 ? "in_stock" : "out_of_stock";
|
|
6245
6832
|
await strapi.db.query("plugin::webbycommerce.product").update({
|
|
6246
|
-
where: { id:
|
|
6833
|
+
where: { id: productId },
|
|
6247
6834
|
data: {
|
|
6248
6835
|
stock_quantity: newStockQuantity,
|
|
6249
6836
|
stock_status: newStockStatus
|
|
6250
6837
|
}
|
|
6251
6838
|
});
|
|
6839
|
+
strapi.log.info(`[restoreOrderStock] Restored ${quantityToRestore} unit(s) of product ${productId} for order ${order.id}`);
|
|
6840
|
+
} else {
|
|
6841
|
+
strapi.log.warn(`[restoreOrderStock] Product ${productId} not found for order ${order.id}`);
|
|
6252
6842
|
}
|
|
6253
6843
|
}
|
|
6254
6844
|
} catch (error) {
|
|
6255
|
-
strapi.log.error(
|
|
6845
|
+
strapi.log.error(`[restoreOrderStock] Failed to restore order stock for order ${order.id}:`, error);
|
|
6256
6846
|
}
|
|
6257
6847
|
},
|
|
6258
6848
|
// Generate tracking timeline based on order status
|
|
@@ -7744,7 +8334,7 @@ var require_cart2 = __commonJS({
|
|
|
7744
8334
|
const guestId = user ? null : getGuestIdFromRequest(ctx) || randomUUID();
|
|
7745
8335
|
const cart = await cartService.getOrCreateCart({ userId: user?.id, guestId });
|
|
7746
8336
|
const items = await cartService.getCartItems({ cartId: cart.id });
|
|
7747
|
-
const totals = await cartService.getTotalsFromItems(items);
|
|
8337
|
+
const totals = await cartService.getTotalsFromItems(items, cart.coupon);
|
|
7748
8338
|
ctx.send({
|
|
7749
8339
|
data: {
|
|
7750
8340
|
cart: {
|
|
@@ -7779,7 +8369,11 @@ var require_cart2 = __commonJS({
|
|
|
7779
8369
|
const cart = await cartService.getOrCreateCart({ userId: user?.id, guestId });
|
|
7780
8370
|
await cartService.addOrUpdateItem({ cartId: cart.id, userId: user?.id, productId, quantity });
|
|
7781
8371
|
const items = await cartService.getCartItems({ cartId: cart.id });
|
|
7782
|
-
const
|
|
8372
|
+
const updatedCart = await strapi.db.query("plugin::webbycommerce.cart").findOne({
|
|
8373
|
+
where: { id: cart.id },
|
|
8374
|
+
populate: { coupon: true }
|
|
8375
|
+
});
|
|
8376
|
+
const totals = await cartService.getTotalsFromItems(items, updatedCart?.coupon);
|
|
7783
8377
|
ctx.send({
|
|
7784
8378
|
data: {
|
|
7785
8379
|
cart: {
|
|
@@ -7812,7 +8406,11 @@ var require_cart2 = __commonJS({
|
|
|
7812
8406
|
const cart = await cartService.getOrCreateCart({ userId: user?.id, guestId });
|
|
7813
8407
|
await cartService.updateItemQuantity({ cartId: cart.id, userId: user?.id, cartItemId: id, quantity });
|
|
7814
8408
|
const items = await cartService.getCartItems({ cartId: cart.id });
|
|
7815
|
-
const
|
|
8409
|
+
const updatedCart = await strapi.db.query("plugin::webbycommerce.cart").findOne({
|
|
8410
|
+
where: { id: cart.id },
|
|
8411
|
+
populate: { coupon: true }
|
|
8412
|
+
});
|
|
8413
|
+
const totals = await cartService.getTotalsFromItems(items, updatedCart?.coupon);
|
|
7816
8414
|
ctx.send({
|
|
7817
8415
|
data: {
|
|
7818
8416
|
cart: {
|
|
@@ -7844,7 +8442,11 @@ var require_cart2 = __commonJS({
|
|
|
7844
8442
|
const cart = await cartService.getOrCreateCart({ userId: user?.id, guestId });
|
|
7845
8443
|
await cartService.removeItem({ cartId: cart.id, cartItemId: id });
|
|
7846
8444
|
const items = await cartService.getCartItems({ cartId: cart.id });
|
|
7847
|
-
const
|
|
8445
|
+
const updatedCart = await strapi.db.query("plugin::webbycommerce.cart").findOne({
|
|
8446
|
+
where: { id: cart.id },
|
|
8447
|
+
populate: { coupon: true }
|
|
8448
|
+
});
|
|
8449
|
+
const totals = await cartService.getTotalsFromItems(items, updatedCart?.coupon);
|
|
7848
8450
|
ctx.send({
|
|
7849
8451
|
data: {
|
|
7850
8452
|
cart: {
|
|
@@ -7901,7 +8503,7 @@ var require_cart2 = __commonJS({
|
|
|
7901
8503
|
if (!user && !guestId) return ctx.badRequest("guest_id is required for guest cart");
|
|
7902
8504
|
const cart = await cartService.getOrCreateCart({ userId: user?.id, guestId });
|
|
7903
8505
|
const items = await cartService.getCartItems({ cartId: cart.id });
|
|
7904
|
-
const totals = await cartService.getTotalsFromItems(items);
|
|
8506
|
+
const totals = await cartService.getTotalsFromItems(items, cart.coupon);
|
|
7905
8507
|
ctx.send({
|
|
7906
8508
|
data: {
|
|
7907
8509
|
cart: {
|
|
@@ -7918,10 +8520,81 @@ var require_cart2 = __commonJS({
|
|
|
7918
8520
|
}
|
|
7919
8521
|
},
|
|
7920
8522
|
async applyCoupon(ctx) {
|
|
7921
|
-
|
|
8523
|
+
try {
|
|
8524
|
+
const user = ctx.state.user;
|
|
8525
|
+
const hasPermission = await ensureEcommercePermission(ctx);
|
|
8526
|
+
if (!hasPermission) return;
|
|
8527
|
+
const { coupon_code } = ctx.request.body || {};
|
|
8528
|
+
if (!coupon_code) {
|
|
8529
|
+
return ctx.badRequest("Coupon code is required");
|
|
8530
|
+
}
|
|
8531
|
+
const cartService = strapi.plugin("webbycommerce").service("cart");
|
|
8532
|
+
const guestId = user ? null : getGuestIdFromRequest(ctx);
|
|
8533
|
+
if (!user && !guestId) return ctx.badRequest("guest_id is required for guest cart");
|
|
8534
|
+
const cart = await cartService.getOrCreateCart({ userId: user?.id, guestId });
|
|
8535
|
+
const coupon = await cartService.validateAndApplyCoupon({
|
|
8536
|
+
cartId: cart.id,
|
|
8537
|
+
couponCode: coupon_code
|
|
8538
|
+
});
|
|
8539
|
+
const items = await cartService.getCartItems({ cartId: cart.id });
|
|
8540
|
+
const updatedCart = await strapi.db.query("plugin::webbycommerce.cart").findOne({
|
|
8541
|
+
where: { id: cart.id },
|
|
8542
|
+
populate: { coupon: true }
|
|
8543
|
+
});
|
|
8544
|
+
const totals = await cartService.getTotalsFromItems(items, updatedCart?.coupon);
|
|
8545
|
+
ctx.send({
|
|
8546
|
+
data: {
|
|
8547
|
+
cart: {
|
|
8548
|
+
id: cart.id,
|
|
8549
|
+
guest_id: cart.guest_id || guestId || null,
|
|
8550
|
+
currency: cart.currency || "USD"
|
|
8551
|
+
},
|
|
8552
|
+
coupon: {
|
|
8553
|
+
code: coupon.code,
|
|
8554
|
+
type: coupon.type,
|
|
8555
|
+
value: coupon.value,
|
|
8556
|
+
discount_amount: totals.discount
|
|
8557
|
+
},
|
|
8558
|
+
items,
|
|
8559
|
+
totals
|
|
8560
|
+
},
|
|
8561
|
+
message: "Coupon applied successfully"
|
|
8562
|
+
});
|
|
8563
|
+
} catch (error) {
|
|
8564
|
+
strapi.log.error("Error applying coupon:", error);
|
|
8565
|
+
const status = error?.status || 400;
|
|
8566
|
+
if (status === 404) return ctx.notFound(error.message);
|
|
8567
|
+
return ctx.badRequest(error.message || "Invalid coupon code");
|
|
8568
|
+
}
|
|
7922
8569
|
},
|
|
7923
8570
|
async removeCoupon(ctx) {
|
|
7924
|
-
|
|
8571
|
+
try {
|
|
8572
|
+
const user = ctx.state.user;
|
|
8573
|
+
const hasPermission = await ensureEcommercePermission(ctx);
|
|
8574
|
+
if (!hasPermission) return;
|
|
8575
|
+
const cartService = strapi.plugin("webbycommerce").service("cart");
|
|
8576
|
+
const guestId = user ? null : getGuestIdFromRequest(ctx);
|
|
8577
|
+
if (!user && !guestId) return ctx.badRequest("guest_id is required for guest cart");
|
|
8578
|
+
const cart = await cartService.getOrCreateCart({ userId: user?.id, guestId });
|
|
8579
|
+
await cartService.removeCoupon({ cartId: cart.id });
|
|
8580
|
+
const items = await cartService.getCartItems({ cartId: cart.id });
|
|
8581
|
+
const totals = await cartService.getTotalsFromItems(items, null);
|
|
8582
|
+
ctx.send({
|
|
8583
|
+
data: {
|
|
8584
|
+
cart: {
|
|
8585
|
+
id: cart.id,
|
|
8586
|
+
guest_id: cart.guest_id || guestId || null,
|
|
8587
|
+
currency: cart.currency || "USD"
|
|
8588
|
+
},
|
|
8589
|
+
items,
|
|
8590
|
+
totals
|
|
8591
|
+
},
|
|
8592
|
+
message: "Coupon removed successfully"
|
|
8593
|
+
});
|
|
8594
|
+
} catch (error) {
|
|
8595
|
+
strapi.log.error("Error removing coupon:", error);
|
|
8596
|
+
ctx.badRequest("Failed to remove coupon", { error: error.message });
|
|
8597
|
+
}
|
|
7925
8598
|
},
|
|
7926
8599
|
async checkout(ctx) {
|
|
7927
8600
|
const orderController = strapi.plugin("webbycommerce").controller("order");
|
|
@@ -9659,24 +10332,29 @@ var require_compare3 = __commonJS({
|
|
|
9659
10332
|
module2.exports = createCoreService("plugin::webbycommerce.compare", ({ strapi: strapi2 }) => ({
|
|
9660
10333
|
async findUserCompare(userId) {
|
|
9661
10334
|
try {
|
|
9662
|
-
const
|
|
9663
|
-
|
|
9664
|
-
userId
|
|
10335
|
+
const compares = await strapi2.db.query("plugin::webbycommerce.compare").findMany({
|
|
10336
|
+
where: {
|
|
10337
|
+
userId: String(userId)
|
|
9665
10338
|
},
|
|
10339
|
+
orderBy: { createdAt: "desc" },
|
|
9666
10340
|
populate: {
|
|
9667
10341
|
products: {
|
|
9668
10342
|
populate: {
|
|
9669
10343
|
images: true,
|
|
9670
10344
|
product_categories: true,
|
|
9671
10345
|
tags: true,
|
|
9672
|
-
variations:
|
|
10346
|
+
variations: {
|
|
10347
|
+
populate: {
|
|
10348
|
+
attributes: true,
|
|
10349
|
+
attributeValues: true
|
|
10350
|
+
}
|
|
10351
|
+
}
|
|
9673
10352
|
}
|
|
9674
10353
|
},
|
|
9675
10354
|
category: true
|
|
9676
|
-
}
|
|
9677
|
-
sort: { createdAt: "desc" }
|
|
10355
|
+
}
|
|
9678
10356
|
});
|
|
9679
|
-
return
|
|
10357
|
+
return compares.length > 0 ? compares[0] : null;
|
|
9680
10358
|
} catch (error) {
|
|
9681
10359
|
throw new Error(`Failed to find user compare: ${error.message}`);
|
|
9682
10360
|
}
|
|
@@ -9692,10 +10370,10 @@ var require_compare3 = __commonJS({
|
|
|
9692
10370
|
notes: data.notes || null,
|
|
9693
10371
|
category: data.categoryId || null
|
|
9694
10372
|
};
|
|
9695
|
-
|
|
10373
|
+
await strapi2.entityService.create("plugin::webbycommerce.compare", {
|
|
9696
10374
|
data: compareData
|
|
9697
10375
|
});
|
|
9698
|
-
return
|
|
10376
|
+
return await this.findUserCompare(userId);
|
|
9699
10377
|
} catch (error) {
|
|
9700
10378
|
throw new Error(`Failed to create user compare: ${error.message}`);
|
|
9701
10379
|
}
|
|
@@ -9712,7 +10390,10 @@ var require_compare3 = __commonJS({
|
|
|
9712
10390
|
if (compare.products.length >= 4) {
|
|
9713
10391
|
throw new Error("Compare list is full. Maximum 4 products allowed.");
|
|
9714
10392
|
}
|
|
9715
|
-
const productExists = compare.products.some((product2) =>
|
|
10393
|
+
const productExists = compare.products.some((product2) => {
|
|
10394
|
+
const productIdValue = typeof product2 === "object" && product2 !== null ? product2.id : product2;
|
|
10395
|
+
return productIdValue === parseInt(productId);
|
|
10396
|
+
});
|
|
9716
10397
|
if (productExists) {
|
|
9717
10398
|
throw new Error("Product already exists in compare list");
|
|
9718
10399
|
}
|
|
@@ -9725,13 +10406,16 @@ var require_compare3 = __commonJS({
|
|
|
9725
10406
|
if (compare.category && product.product_categories && product.product_categories.length > 0 && compare.category.id !== product.product_categories[0].id) {
|
|
9726
10407
|
strapi2.log.warn(`Adding product from different category to compare list. Compare category: ${compare.category.name}, Product category: ${product.product_categories[0].name}`);
|
|
9727
10408
|
}
|
|
9728
|
-
const
|
|
10409
|
+
const existingProductIds = compare.products.map((p) => {
|
|
10410
|
+
return typeof p === "object" && p !== null ? p.id : p;
|
|
10411
|
+
}).filter((id) => id != null);
|
|
10412
|
+
await strapi2.entityService.update("plugin::webbycommerce.compare", compare.id, {
|
|
9729
10413
|
data: {
|
|
9730
|
-
products: { set: [...
|
|
10414
|
+
products: { set: [...existingProductIds, parseInt(productId, 10)].map((id) => ({ id })) },
|
|
9731
10415
|
category: compare.category || product.product_categories?.[0]?.id || null
|
|
9732
10416
|
}
|
|
9733
10417
|
});
|
|
9734
|
-
return
|
|
10418
|
+
return await this.findUserCompare(userId);
|
|
9735
10419
|
} catch (error) {
|
|
9736
10420
|
throw new Error(`Failed to add product to compare: ${error.message}`);
|
|
9737
10421
|
}
|
|
@@ -9745,15 +10429,20 @@ var require_compare3 = __commonJS({
|
|
|
9745
10429
|
if (!compare.products) {
|
|
9746
10430
|
compare.products = [];
|
|
9747
10431
|
}
|
|
9748
|
-
const updatedProducts = compare.products.filter((product) =>
|
|
9749
|
-
|
|
10432
|
+
const updatedProducts = compare.products.filter((product) => {
|
|
10433
|
+
const productIdValue = typeof product === "object" && product !== null ? product.id : product;
|
|
10434
|
+
return productIdValue !== parseInt(productId);
|
|
10435
|
+
}).map((product) => {
|
|
10436
|
+
return typeof product === "object" && product !== null ? product.id : product;
|
|
10437
|
+
});
|
|
10438
|
+
await strapi2.entityService.update("plugin::webbycommerce.compare", compare.id, {
|
|
9750
10439
|
data: {
|
|
9751
10440
|
products: { set: updatedProducts.map((id) => ({ id })) },
|
|
9752
10441
|
// Reset category if no products left
|
|
9753
10442
|
category: updatedProducts.length === 0 ? null : compare.category
|
|
9754
10443
|
}
|
|
9755
10444
|
});
|
|
9756
|
-
return
|
|
10445
|
+
return await this.findUserCompare(userId);
|
|
9757
10446
|
} catch (error) {
|
|
9758
10447
|
throw new Error(`Failed to remove product from compare: ${error.message}`);
|
|
9759
10448
|
}
|
|
@@ -9764,13 +10453,13 @@ var require_compare3 = __commonJS({
|
|
|
9764
10453
|
if (!compare) {
|
|
9765
10454
|
throw new Error("Compare list not found");
|
|
9766
10455
|
}
|
|
9767
|
-
|
|
10456
|
+
await strapi2.entityService.update("plugin::webbycommerce.compare", compare.id, {
|
|
9768
10457
|
data: {
|
|
9769
10458
|
products: { set: [] },
|
|
9770
10459
|
category: null
|
|
9771
10460
|
}
|
|
9772
10461
|
});
|
|
9773
|
-
return
|
|
10462
|
+
return await this.findUserCompare(userId);
|
|
9774
10463
|
} catch (error) {
|
|
9775
10464
|
throw new Error(`Failed to clear compare list: ${error.message}`);
|
|
9776
10465
|
}
|
|
@@ -9781,14 +10470,14 @@ var require_compare3 = __commonJS({
|
|
|
9781
10470
|
if (!compare) {
|
|
9782
10471
|
throw new Error("Compare list not found");
|
|
9783
10472
|
}
|
|
9784
|
-
|
|
10473
|
+
await strapi2.entityService.update("plugin::webbycommerce.compare", compare.id, {
|
|
9785
10474
|
data: {
|
|
9786
10475
|
name: data.name !== void 0 ? data.name : compare.name,
|
|
9787
10476
|
notes: data.notes !== void 0 ? data.notes : compare.notes,
|
|
9788
10477
|
isPublic: data.isPublic !== void 0 ? data.isPublic : compare.isPublic
|
|
9789
10478
|
}
|
|
9790
10479
|
});
|
|
9791
|
-
return
|
|
10480
|
+
return await this.findUserCompare(userId);
|
|
9792
10481
|
} catch (error) {
|
|
9793
10482
|
throw new Error(`Failed to update compare list: ${error.message}`);
|
|
9794
10483
|
}
|
|
@@ -9872,6 +10561,7 @@ var require_cart3 = __commonJS({
|
|
|
9872
10561
|
var CART_UID = "plugin::webbycommerce.cart";
|
|
9873
10562
|
var CART_ITEM_UID = "plugin::webbycommerce.cart-item";
|
|
9874
10563
|
var PRODUCT_UID = "plugin::webbycommerce.product";
|
|
10564
|
+
var COUPON_UID = "plugin::webbycommerce.coupon";
|
|
9875
10565
|
var asInt = (value) => {
|
|
9876
10566
|
const n = Number.parseInt(String(value), 10);
|
|
9877
10567
|
return Number.isFinite(n) ? n : null;
|
|
@@ -9883,41 +10573,65 @@ var require_cart3 = __commonJS({
|
|
|
9883
10573
|
};
|
|
9884
10574
|
module2.exports = createCoreService(CART_ITEM_UID, ({ strapi: strapi2 }) => ({
|
|
9885
10575
|
async getOrCreateCart({ userId, guestId }) {
|
|
10576
|
+
let cart;
|
|
9886
10577
|
if (userId) {
|
|
9887
|
-
|
|
10578
|
+
cart = await strapi2.db.query(CART_UID).findOne({
|
|
9888
10579
|
where: { user: userId },
|
|
9889
10580
|
select: ["id", "guest_id", "currency"]
|
|
9890
10581
|
});
|
|
9891
|
-
if (
|
|
9892
|
-
|
|
10582
|
+
if (cart?.id) {
|
|
10583
|
+
const cartWithCoupon = await strapi2.db.query(CART_UID).findOne({
|
|
10584
|
+
where: { id: cart.id },
|
|
10585
|
+
populate: { coupon: true }
|
|
10586
|
+
});
|
|
10587
|
+
return cartWithCoupon || cart;
|
|
10588
|
+
}
|
|
10589
|
+
cart = await strapi2.db.query(CART_UID).create({
|
|
9893
10590
|
data: {
|
|
9894
10591
|
user: userId,
|
|
9895
10592
|
currency: "USD"
|
|
9896
10593
|
},
|
|
9897
10594
|
select: ["id", "guest_id", "currency"]
|
|
9898
10595
|
});
|
|
10596
|
+
return await strapi2.db.query(CART_UID).findOne({
|
|
10597
|
+
where: { id: cart.id },
|
|
10598
|
+
populate: { coupon: true }
|
|
10599
|
+
});
|
|
9899
10600
|
}
|
|
9900
10601
|
if (guestId) {
|
|
9901
|
-
|
|
10602
|
+
cart = await strapi2.db.query(CART_UID).findOne({
|
|
9902
10603
|
where: { guest_id: String(guestId) },
|
|
9903
10604
|
select: ["id", "guest_id", "currency"]
|
|
9904
10605
|
});
|
|
9905
|
-
if (
|
|
9906
|
-
|
|
10606
|
+
if (cart?.id) {
|
|
10607
|
+
const cartWithCoupon = await strapi2.db.query(CART_UID).findOne({
|
|
10608
|
+
where: { id: cart.id },
|
|
10609
|
+
populate: { coupon: true }
|
|
10610
|
+
});
|
|
10611
|
+
return cartWithCoupon || cart;
|
|
10612
|
+
}
|
|
10613
|
+
cart = await strapi2.db.query(CART_UID).create({
|
|
9907
10614
|
data: {
|
|
9908
10615
|
guest_id: String(guestId),
|
|
9909
10616
|
currency: "USD"
|
|
9910
10617
|
},
|
|
9911
10618
|
select: ["id", "guest_id", "currency"]
|
|
9912
10619
|
});
|
|
10620
|
+
return await strapi2.db.query(CART_UID).findOne({
|
|
10621
|
+
where: { id: cart.id },
|
|
10622
|
+
populate: { coupon: true }
|
|
10623
|
+
});
|
|
9913
10624
|
}
|
|
9914
|
-
|
|
10625
|
+
cart = await strapi2.db.query(CART_UID).create({
|
|
9915
10626
|
data: {
|
|
9916
10627
|
currency: "USD"
|
|
9917
10628
|
},
|
|
9918
10629
|
select: ["id", "guest_id", "currency"]
|
|
9919
10630
|
});
|
|
9920
|
-
return
|
|
10631
|
+
return await strapi2.db.query(CART_UID).findOne({
|
|
10632
|
+
where: { id: cart.id },
|
|
10633
|
+
populate: { coupon: true }
|
|
10634
|
+
});
|
|
9921
10635
|
},
|
|
9922
10636
|
async getCartItems({ cartId }) {
|
|
9923
10637
|
return await strapi2.db.query(CART_ITEM_UID).findMany({
|
|
@@ -9931,13 +10645,23 @@ var require_cart3 = __commonJS({
|
|
|
9931
10645
|
}
|
|
9932
10646
|
});
|
|
9933
10647
|
},
|
|
9934
|
-
async getTotalsFromItems(items) {
|
|
10648
|
+
async getTotalsFromItems(items, coupon = null) {
|
|
9935
10649
|
const safe = Array.isArray(items) ? items : [];
|
|
9936
10650
|
const totalItems = safe.reduce((sum, it) => sum + (Number(it.quantity) || 0), 0);
|
|
9937
10651
|
const subtotal = safe.reduce((sum, it) => sum + (Number(it.total_price) || 0), 0);
|
|
10652
|
+
let discount = 0;
|
|
10653
|
+
if (coupon) {
|
|
10654
|
+
if (coupon.type === "percentage") {
|
|
10655
|
+
discount = subtotal * Number(coupon.value || 0) / 100;
|
|
10656
|
+
} else if (coupon.type === "fixed") {
|
|
10657
|
+
discount = Number(coupon.value || 0);
|
|
10658
|
+
if (discount > subtotal) {
|
|
10659
|
+
discount = subtotal;
|
|
10660
|
+
}
|
|
10661
|
+
}
|
|
10662
|
+
}
|
|
9938
10663
|
const tax = 0;
|
|
9939
10664
|
const shipping = 0;
|
|
9940
|
-
const discount = 0;
|
|
9941
10665
|
const total = subtotal + tax + shipping - discount;
|
|
9942
10666
|
return {
|
|
9943
10667
|
totalItems,
|
|
@@ -10087,6 +10811,157 @@ var require_cart3 = __commonJS({
|
|
|
10087
10811
|
where: { cart: cartId }
|
|
10088
10812
|
});
|
|
10089
10813
|
return true;
|
|
10814
|
+
},
|
|
10815
|
+
async validateAndApplyCoupon({ cartId, couponCode }) {
|
|
10816
|
+
if (!couponCode || typeof couponCode !== "string" || !couponCode.trim()) {
|
|
10817
|
+
const err = new Error("Coupon code is required");
|
|
10818
|
+
err.status = 400;
|
|
10819
|
+
throw err;
|
|
10820
|
+
}
|
|
10821
|
+
const normalizedCode = couponCode.trim();
|
|
10822
|
+
strapi2.log.info(`[webbycommerce] Looking for coupon code: "${normalizedCode}"`);
|
|
10823
|
+
let coupon = null;
|
|
10824
|
+
try {
|
|
10825
|
+
const coupons = await strapi2.entityService.findMany(COUPON_UID, {
|
|
10826
|
+
filters: {
|
|
10827
|
+
code: normalizedCode
|
|
10828
|
+
}
|
|
10829
|
+
});
|
|
10830
|
+
strapi2.log.debug(`[webbycommerce] entityService found ${coupons?.length || 0} coupons with exact match`);
|
|
10831
|
+
if (coupons && Array.isArray(coupons) && coupons.length > 0) {
|
|
10832
|
+
coupon = coupons[0];
|
|
10833
|
+
strapi2.log.debug(`[webbycommerce] Found via entityService: "${coupon.code}"`);
|
|
10834
|
+
}
|
|
10835
|
+
} catch (entityServiceError) {
|
|
10836
|
+
strapi2.log.warn(`[webbycommerce] entityService query failed:`, entityServiceError.message);
|
|
10837
|
+
}
|
|
10838
|
+
if (!coupon) {
|
|
10839
|
+
try {
|
|
10840
|
+
coupon = await strapi2.db.query(COUPON_UID).findOne({
|
|
10841
|
+
where: { code: normalizedCode }
|
|
10842
|
+
});
|
|
10843
|
+
if (coupon) {
|
|
10844
|
+
strapi2.log.debug(`[webbycommerce] Found via db.query: "${coupon.code}"`);
|
|
10845
|
+
} else {
|
|
10846
|
+
strapi2.log.debug(`[webbycommerce] db.query exact match returned null`);
|
|
10847
|
+
}
|
|
10848
|
+
} catch (dbError) {
|
|
10849
|
+
strapi2.log.warn(`[webbycommerce] db.query exact match failed:`, dbError.message);
|
|
10850
|
+
}
|
|
10851
|
+
}
|
|
10852
|
+
if (!coupon) {
|
|
10853
|
+
try {
|
|
10854
|
+
coupon = await strapi2.db.query(COUPON_UID).findOne({
|
|
10855
|
+
where: { code: normalizedCode.toUpperCase() }
|
|
10856
|
+
});
|
|
10857
|
+
if (coupon) {
|
|
10858
|
+
strapi2.log.debug(`[webbycommerce] Found via db.query (uppercase): "${coupon.code}"`);
|
|
10859
|
+
}
|
|
10860
|
+
} catch (dbError) {
|
|
10861
|
+
}
|
|
10862
|
+
}
|
|
10863
|
+
if (!coupon) {
|
|
10864
|
+
try {
|
|
10865
|
+
coupon = await strapi2.db.query(COUPON_UID).findOne({
|
|
10866
|
+
where: { code: normalizedCode.toLowerCase() }
|
|
10867
|
+
});
|
|
10868
|
+
if (coupon) {
|
|
10869
|
+
strapi2.log.debug(`[webbycommerce] Found via db.query (lowercase): "${coupon.code}"`);
|
|
10870
|
+
}
|
|
10871
|
+
} catch (dbError) {
|
|
10872
|
+
}
|
|
10873
|
+
}
|
|
10874
|
+
if (!coupon) {
|
|
10875
|
+
try {
|
|
10876
|
+
strapi2.log.debug(`[webbycommerce] Trying fallback: fetching all coupons for case-insensitive match`);
|
|
10877
|
+
const allCoupons = await strapi2.entityService.findMany(COUPON_UID, {
|
|
10878
|
+
filters: {}
|
|
10879
|
+
});
|
|
10880
|
+
strapi2.log.debug(`[webbycommerce] Fetched ${allCoupons?.length || 0} total coupons`);
|
|
10881
|
+
if (allCoupons && Array.isArray(allCoupons)) {
|
|
10882
|
+
const allCodes = allCoupons.map((c) => `"${c.code || "N/A"}"`).join(", ");
|
|
10883
|
+
strapi2.log.debug(`[webbycommerce] All coupon codes: ${allCodes}`);
|
|
10884
|
+
coupon = allCoupons.find(
|
|
10885
|
+
(c) => {
|
|
10886
|
+
const couponCode2 = c.code ? String(c.code).trim() : "";
|
|
10887
|
+
const searchCode = normalizedCode.toLowerCase();
|
|
10888
|
+
const match = couponCode2.toLowerCase() === searchCode;
|
|
10889
|
+
if (match) {
|
|
10890
|
+
strapi2.log.debug(`[webbycommerce] Case-insensitive match found: "${couponCode2}" === "${normalizedCode}"`);
|
|
10891
|
+
}
|
|
10892
|
+
return match;
|
|
10893
|
+
}
|
|
10894
|
+
);
|
|
10895
|
+
}
|
|
10896
|
+
} catch (fallbackError) {
|
|
10897
|
+
strapi2.log.error(`[webbycommerce] Fallback query failed:`, fallbackError.message, fallbackError.stack);
|
|
10898
|
+
}
|
|
10899
|
+
}
|
|
10900
|
+
if (!coupon) {
|
|
10901
|
+
strapi2.log.error(`[webbycommerce] Coupon not found: "${normalizedCode}"`);
|
|
10902
|
+
try {
|
|
10903
|
+
const availableCoupons = await strapi2.entityService.findMany(COUPON_UID, {
|
|
10904
|
+
filters: {}
|
|
10905
|
+
});
|
|
10906
|
+
if (availableCoupons && Array.isArray(availableCoupons)) {
|
|
10907
|
+
const codes = availableCoupons.slice(0, 20).map((c) => `"${c.code || "N/A"}"`).join(", ");
|
|
10908
|
+
strapi2.log.error(`[webbycommerce] Available coupons (${availableCoupons.length}): ${codes}`);
|
|
10909
|
+
} else {
|
|
10910
|
+
strapi2.log.error(`[webbycommerce] No coupons found in database or query returned invalid format`);
|
|
10911
|
+
}
|
|
10912
|
+
} catch (debugError) {
|
|
10913
|
+
strapi2.log.error(`[webbycommerce] Error fetching coupons for debug:`, debugError.message, debugError.stack);
|
|
10914
|
+
}
|
|
10915
|
+
const err = new Error("Invalid coupon code");
|
|
10916
|
+
err.status = 400;
|
|
10917
|
+
throw err;
|
|
10918
|
+
}
|
|
10919
|
+
strapi2.log.info(`[webbycommerce] Found coupon: "${coupon.code}" (ID: ${coupon.id}, Active: ${coupon.is_active})`);
|
|
10920
|
+
if (coupon.is_active === false) {
|
|
10921
|
+
const err = new Error("This coupon is not active");
|
|
10922
|
+
err.status = 400;
|
|
10923
|
+
throw err;
|
|
10924
|
+
}
|
|
10925
|
+
if (coupon.expires_at) {
|
|
10926
|
+
const now = /* @__PURE__ */ new Date();
|
|
10927
|
+
const expiresAt = new Date(coupon.expires_at);
|
|
10928
|
+
if (expiresAt < now) {
|
|
10929
|
+
const err = new Error("This coupon has expired");
|
|
10930
|
+
err.status = 400;
|
|
10931
|
+
throw err;
|
|
10932
|
+
}
|
|
10933
|
+
}
|
|
10934
|
+
if (coupon.usage_limit !== null && coupon.usage_limit !== void 0) {
|
|
10935
|
+
const usedCount = coupon.used_count || 0;
|
|
10936
|
+
if (usedCount >= coupon.usage_limit) {
|
|
10937
|
+
const err = new Error("This coupon has reached its usage limit");
|
|
10938
|
+
err.status = 400;
|
|
10939
|
+
throw err;
|
|
10940
|
+
}
|
|
10941
|
+
}
|
|
10942
|
+
const items = await this.getCartItems({ cartId });
|
|
10943
|
+
const subtotal = items.reduce((sum, it) => sum + (Number(it.total_price) || 0), 0);
|
|
10944
|
+
if (coupon.minimum_order_amount !== null && coupon.minimum_order_amount !== void 0) {
|
|
10945
|
+
if (subtotal < Number(coupon.minimum_order_amount)) {
|
|
10946
|
+
const err = new Error(
|
|
10947
|
+
`Minimum order amount of ${coupon.minimum_order_amount} required for this coupon`
|
|
10948
|
+
);
|
|
10949
|
+
err.status = 400;
|
|
10950
|
+
throw err;
|
|
10951
|
+
}
|
|
10952
|
+
}
|
|
10953
|
+
await strapi2.db.query(CART_UID).update({
|
|
10954
|
+
where: { id: cartId },
|
|
10955
|
+
data: { coupon: coupon.id }
|
|
10956
|
+
});
|
|
10957
|
+
return coupon;
|
|
10958
|
+
},
|
|
10959
|
+
async removeCoupon({ cartId }) {
|
|
10960
|
+
await strapi2.db.query(CART_UID).update({
|
|
10961
|
+
where: { id: cartId },
|
|
10962
|
+
data: { coupon: null }
|
|
10963
|
+
});
|
|
10964
|
+
return true;
|
|
10090
10965
|
}
|
|
10091
10966
|
}));
|
|
10092
10967
|
}
|
|
@@ -10100,24 +10975,28 @@ var require_wishlist3 = __commonJS({
|
|
|
10100
10975
|
module2.exports = createCoreService("plugin::webbycommerce.wishlist", ({ strapi: strapi2 }) => ({
|
|
10101
10976
|
async findUserWishlist(userId) {
|
|
10102
10977
|
try {
|
|
10103
|
-
const
|
|
10104
|
-
|
|
10105
|
-
// userId is stored as a string in this content-type; normalize to string for reliable matching
|
|
10978
|
+
const wishlists = await strapi2.db.query("plugin::webbycommerce.wishlist").findMany({
|
|
10979
|
+
where: {
|
|
10106
10980
|
userId: String(userId)
|
|
10107
10981
|
},
|
|
10982
|
+
orderBy: { createdAt: "desc" },
|
|
10108
10983
|
populate: {
|
|
10109
10984
|
products: {
|
|
10110
10985
|
populate: {
|
|
10111
10986
|
images: true,
|
|
10112
10987
|
product_categories: true,
|
|
10113
10988
|
tags: true,
|
|
10114
|
-
variations:
|
|
10989
|
+
variations: {
|
|
10990
|
+
populate: {
|
|
10991
|
+
attributes: true,
|
|
10992
|
+
attributeValues: true
|
|
10993
|
+
}
|
|
10994
|
+
}
|
|
10115
10995
|
}
|
|
10116
10996
|
}
|
|
10117
|
-
}
|
|
10118
|
-
sort: { createdAt: "desc" }
|
|
10997
|
+
}
|
|
10119
10998
|
});
|
|
10120
|
-
return
|
|
10999
|
+
return wishlists.length > 0 ? wishlists[0] : null;
|
|
10121
11000
|
} catch (error) {
|
|
10122
11001
|
throw new Error(`Failed to find user wishlist: ${error.message}`);
|
|
10123
11002
|
}
|
|
@@ -10132,10 +11011,10 @@ var require_wishlist3 = __commonJS({
|
|
|
10132
11011
|
name: data.name || null,
|
|
10133
11012
|
description: data.description || null
|
|
10134
11013
|
};
|
|
10135
|
-
|
|
11014
|
+
await strapi2.entityService.create("plugin::webbycommerce.wishlist", {
|
|
10136
11015
|
data: wishlistData
|
|
10137
11016
|
});
|
|
10138
|
-
return
|
|
11017
|
+
return await this.findUserWishlist(userId);
|
|
10139
11018
|
} catch (error) {
|
|
10140
11019
|
throw new Error(`Failed to create user wishlist: ${error.message}`);
|
|
10141
11020
|
}
|
|
@@ -10149,7 +11028,10 @@ var require_wishlist3 = __commonJS({
|
|
|
10149
11028
|
if (!wishlist.products) {
|
|
10150
11029
|
wishlist.products = [];
|
|
10151
11030
|
}
|
|
10152
|
-
const productExists = wishlist.products.some((product2) =>
|
|
11031
|
+
const productExists = wishlist.products.some((product2) => {
|
|
11032
|
+
const productIdValue = typeof product2 === "object" && product2 !== null ? product2.id : product2;
|
|
11033
|
+
return productIdValue === parseInt(productId);
|
|
11034
|
+
});
|
|
10153
11035
|
if (productExists) {
|
|
10154
11036
|
throw new Error("Product already exists in wishlist");
|
|
10155
11037
|
}
|
|
@@ -10160,12 +11042,15 @@ var require_wishlist3 = __commonJS({
|
|
|
10160
11042
|
if (!product) {
|
|
10161
11043
|
throw new Error("Product not found");
|
|
10162
11044
|
}
|
|
10163
|
-
const
|
|
11045
|
+
const existingProductIds = wishlist.products.map((p) => {
|
|
11046
|
+
return typeof p === "object" && p !== null ? p.id : p;
|
|
11047
|
+
}).filter((id) => id != null);
|
|
11048
|
+
await strapi2.entityService.update("plugin::webbycommerce.wishlist", wishlist.id, {
|
|
10164
11049
|
data: {
|
|
10165
|
-
products: [...
|
|
11050
|
+
products: { set: [...existingProductIds, parseInt(productId, 10)].map((id) => ({ id })) }
|
|
10166
11051
|
}
|
|
10167
11052
|
});
|
|
10168
|
-
return
|
|
11053
|
+
return await this.findUserWishlist(userId);
|
|
10169
11054
|
} catch (error) {
|
|
10170
11055
|
throw new Error(`Failed to add product to wishlist: ${error.message}`);
|
|
10171
11056
|
}
|
|
@@ -10179,13 +11064,18 @@ var require_wishlist3 = __commonJS({
|
|
|
10179
11064
|
if (!wishlist.products) {
|
|
10180
11065
|
wishlist.products = [];
|
|
10181
11066
|
}
|
|
10182
|
-
const updatedProducts = wishlist.products.filter((product) =>
|
|
10183
|
-
|
|
11067
|
+
const updatedProducts = wishlist.products.filter((product) => {
|
|
11068
|
+
const productIdValue = typeof product === "object" && product !== null ? product.id : product;
|
|
11069
|
+
return productIdValue !== parseInt(productId);
|
|
11070
|
+
}).map((product) => {
|
|
11071
|
+
return typeof product === "object" && product !== null ? product.id : product;
|
|
11072
|
+
});
|
|
11073
|
+
await strapi2.entityService.update("plugin::webbycommerce.wishlist", wishlist.id, {
|
|
10184
11074
|
data: {
|
|
10185
|
-
products: updatedProducts
|
|
11075
|
+
products: { set: updatedProducts.map((id) => ({ id })) }
|
|
10186
11076
|
}
|
|
10187
11077
|
});
|
|
10188
|
-
return
|
|
11078
|
+
return await this.findUserWishlist(userId);
|
|
10189
11079
|
} catch (error) {
|
|
10190
11080
|
throw new Error(`Failed to remove product from wishlist: ${error.message}`);
|
|
10191
11081
|
}
|
|
@@ -10196,12 +11086,12 @@ var require_wishlist3 = __commonJS({
|
|
|
10196
11086
|
if (!wishlist) {
|
|
10197
11087
|
throw new Error("Wishlist not found");
|
|
10198
11088
|
}
|
|
10199
|
-
|
|
11089
|
+
await strapi2.entityService.update("plugin::webbycommerce.wishlist", wishlist.id, {
|
|
10200
11090
|
data: {
|
|
10201
|
-
products: []
|
|
11091
|
+
products: { set: [] }
|
|
10202
11092
|
}
|
|
10203
11093
|
});
|
|
10204
|
-
return
|
|
11094
|
+
return await this.findUserWishlist(userId);
|
|
10205
11095
|
} catch (error) {
|
|
10206
11096
|
throw new Error(`Failed to clear wishlist: ${error.message}`);
|
|
10207
11097
|
}
|
|
@@ -10212,14 +11102,14 @@ var require_wishlist3 = __commonJS({
|
|
|
10212
11102
|
if (!wishlist) {
|
|
10213
11103
|
throw new Error("Wishlist not found");
|
|
10214
11104
|
}
|
|
10215
|
-
|
|
11105
|
+
await strapi2.entityService.update("plugin::webbycommerce.wishlist", wishlist.id, {
|
|
10216
11106
|
data: {
|
|
10217
11107
|
name: data.name !== void 0 ? data.name : wishlist.name,
|
|
10218
11108
|
description: data.description !== void 0 ? data.description : wishlist.description,
|
|
10219
11109
|
isPublic: data.isPublic !== void 0 ? data.isPublic : wishlist.isPublic
|
|
10220
11110
|
}
|
|
10221
11111
|
});
|
|
10222
|
-
return
|
|
11112
|
+
return await this.findUserWishlist(userId);
|
|
10223
11113
|
} catch (error) {
|
|
10224
11114
|
throw new Error(`Failed to update wishlist: ${error.message}`);
|
|
10225
11115
|
}
|