diff --git a/controllers/customDiscount.controller.js b/controllers/customDiscount.controller.js index a8c4da868c060573f0897086cda3a53095078a2d..4ba25de7af11b90ab4b2534ffdef4f1c1891b6f3 100644 --- a/controllers/customDiscount.controller.js +++ b/controllers/customDiscount.controller.js @@ -104,6 +104,7 @@ const processDiscountData = (data) => { const createCustomDiscount = async (req, res) => { try { const discountData = req.body; + const { user } = req.body; // Check if coupon name already exists const existingCouponName = await getSingleCustomDiscountService({ @@ -130,7 +131,10 @@ const createCustomDiscount = async (req, res) => { } // Process data to convert arrays to objects where needed - const processedDiscountData = processDiscountData(discountData); + const processedDiscountData = processDiscountData({ + ...discountData, + createdBy: user.id, + }); const discount = await createCustomDiscountService(processedDiscountData); @@ -172,22 +176,18 @@ const getAllCustomDiscounts = async (req, res) => { if (search) { const searchLower = search.toLowerCase(); whereClause[Op.or] = [ - Sequelize.where( - Sequelize.fn('LOWER', Sequelize.col('couponName')), - { [Op.like]: `%${searchLower}%` } - ), - Sequelize.where( - Sequelize.fn('LOWER', Sequelize.col('couponCode')), - { [Op.like]: `%${searchLower}%` } - ), - Sequelize.where( - Sequelize.fn('LOWER', Sequelize.col('description')), - { [Op.like]: `%${searchLower}%` } - ), - Sequelize.where( - Sequelize.fn('LOWER', Sequelize.col('discountType')), - { [Op.like]: `%${searchLower}%` } - ), + Sequelize.where(Sequelize.fn("LOWER", Sequelize.col("couponName")), { + [Op.like]: `%${searchLower}%`, + }), + Sequelize.where(Sequelize.fn("LOWER", Sequelize.col("couponCode")), { + [Op.like]: `%${searchLower}%`, + }), + Sequelize.where(Sequelize.fn("LOWER", Sequelize.col("description")), { + [Op.like]: `%${searchLower}%`, + }), + Sequelize.where(Sequelize.fn("LOWER", Sequelize.col("discountType")), { + [Op.like]: `%${searchLower}%`, + }), ]; } @@ -256,6 +256,7 @@ const updateCustomDiscount = async (req, res) => { try { const { id } = req.params; const updateData = req.body; + const { user } = req.body; // Check if coupon name already exists (if being updated) if (updateData.couponName) { @@ -287,7 +288,10 @@ const updateCustomDiscount = async (req, res) => { } // Process data to convert arrays to objects where needed - const processedUpdateData = processDiscountData(updateData); + const processedUpdateData = processDiscountData({ + ...updateData, + updatedBy: user.id, + }); const updatedDiscount = await updateCustomDiscountService( id, diff --git a/models/customDiscount.model.js b/models/customDiscount.model.js index 7a8d8c5226d079bb7bc7233fbbe45d9fe056679f..d76a8c09b4fd53b62aeba37d84ee9e98044e65af 100644 --- a/models/customDiscount.model.js +++ b/models/customDiscount.model.js @@ -114,14 +114,19 @@ const CUSTOM_DISCOUNT_MODEL = sequelize.define( allowNull: false, defaultValue: false, }, - couponLife: { + couponLife: { type: DataTypes.JSON, allowNull: true, }, - custom_meta: { // This is for Buyx getx / buyxgety + custom_meta: { + // This is for Buyx getx / buyxgety type: DataTypes.JSON, allowNull: true, }, + store_filter: { + type: DataTypes.JSON, + allowNull: false, + }, discount_lable: { // For ecom discount label type: DataTypes.STRING(191), @@ -157,6 +162,15 @@ const CUSTOM_DISCOUNT_MODEL = sequelize.define( allowNull: true, comment: "Maximum discount amount for cart adjustment and free shipping", }, + createdBy: { + type: DataTypes.BIGINT.UNSIGNED, + allowNull: false, + }, + updatedBy: { + type: DataTypes.BIGINT.UNSIGNED, + allowNull: true, + defaultValue: null, + }, }, { tableName: "custom_discounts", diff --git a/validators/customDiscount.validator.js b/validators/customDiscount.validator.js index c5d256fd8229bb8a3efb5488f5c9376e60ce688e..8ff0f16ce9365b545a3ccbef0ca0336304425e77 100644 --- a/validators/customDiscount.validator.js +++ b/validators/customDiscount.validator.js @@ -22,6 +22,36 @@ const filterSchema = Joi.object({ product_variants: Joi.array().items(Joi.string()).default([]), }); +// Schema for store filter +const storeFilterSchema = Joi.object({ + type: Joi.string().valid("all", "specific").required().messages({ + "any.only": "Store filter type must be either 'all' or 'specific'", + "any.required": "Store filter type is required", + }), + method: Joi.string() + .valid("in_list", "not_in_list") + .when("type", { + is: "specific", + then: Joi.required(), + otherwise: Joi.allow(null), + }) + .messages({ + "any.only": "Store filter method must be either 'in_list' or 'not_in_list'", + "any.required": "Store filter method is required when type is 'specific'", + }), + value: Joi.array() + .items(Joi.string()) + .when("type", { + is: "specific", + then: Joi.array().items(Joi.string()).min(1).required(), + otherwise: Joi.array().length(0).default([]), + }) + .messages({ + "array.min": "At least one store ID is required when type is 'specific'", + "any.required": "Store filter value is required when type is 'specific'", + }), +}); + // Schema for rulesOnCustomer const rulesOnCustomerSchema = Joi.object({ applyOn: Joi.string().valid("all", "specific").required(), @@ -278,6 +308,15 @@ const customDiscountValidator = Joi.object({ "number.integer": "Per customer limit must be an integer", "number.min": "Per customer limit cannot be negative", }), + + // Store filter - required field with default structure + store_filter: storeFilterSchema.default({ + type: "all", + method: null, + value: [] + }).messages({ + "any.required": "Store filter is required", + }), }); // Separate update validator - only validates fields that are provided with conditional logic @@ -439,6 +478,11 @@ const updateCustomDiscountValidator = Joi.object({ "number.integer": "Per customer limit must be an integer", "number.min": "Per customer limit cannot be negative", }), + + // Store filter - optional for updates + store_filter: storeFilterSchema.messages({ + "object.base": "Store filter must be a valid object", + }), }) .min(1) .messages({