126 lines
3.0 KiB
JavaScript
126 lines
3.0 KiB
JavaScript
import mongoose from "mongoose";
|
|
|
|
const PromotionSchema = new mongoose.Schema(
|
|
{
|
|
storeId: {
|
|
type: mongoose.Schema.Types.ObjectId,
|
|
ref: "Store",
|
|
required: [true, "Store ID is required"]
|
|
},
|
|
code: {
|
|
type: String,
|
|
required: [true, "Promotion code is required"],
|
|
trim: true,
|
|
uppercase: true,
|
|
minlength: [3, "Promotion code must be at least 3 characters"],
|
|
maxlength: [20, "Promotion code cannot exceed 20 characters"]
|
|
},
|
|
discountType: {
|
|
type: String,
|
|
required: [true, "Discount type is required"],
|
|
enum: {
|
|
values: ["percentage", "fixed"],
|
|
message: "Discount type must be either percentage or fixed"
|
|
}
|
|
},
|
|
discountValue: {
|
|
type: Number,
|
|
required: [true, "Discount value is required"],
|
|
validate: {
|
|
validator: function(value) {
|
|
if (this.discountType === "percentage") {
|
|
return value > 0 && value <= 100;
|
|
}
|
|
return value > 0;
|
|
},
|
|
message: props =>
|
|
props.value <= 0
|
|
? "Discount value must be greater than 0"
|
|
: "Percentage discount cannot exceed 100%"
|
|
}
|
|
},
|
|
minOrderAmount: {
|
|
type: Number,
|
|
default: 0,
|
|
min: [0, "Minimum order amount cannot be negative"]
|
|
},
|
|
maxUsage: {
|
|
type: Number,
|
|
default: null
|
|
},
|
|
usageCount: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
isActive: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
startDate: {
|
|
type: Date,
|
|
default: Date.now
|
|
},
|
|
endDate: {
|
|
type: Date,
|
|
default: null
|
|
},
|
|
description: {
|
|
type: String,
|
|
trim: true,
|
|
maxlength: [200, "Description cannot exceed 200 characters"]
|
|
}
|
|
},
|
|
{
|
|
timestamps: true
|
|
}
|
|
);
|
|
|
|
// Compound index to ensure unique promo codes per store
|
|
PromotionSchema.index({ storeId: 1, code: 1 }, { unique: true });
|
|
|
|
// Check if a promotion is valid and can be applied
|
|
PromotionSchema.methods.isValid = function() {
|
|
const now = new Date();
|
|
|
|
// Check if promotion is active
|
|
if (!this.isActive) return false;
|
|
|
|
// Check if promotion has expired
|
|
if (this.endDate && now > this.endDate) return false;
|
|
|
|
// Check if promotion has reached max usage (if set)
|
|
if (this.maxUsage !== null && this.usageCount >= this.maxUsage) return false;
|
|
|
|
return true;
|
|
};
|
|
|
|
// Calculate discount amount for a given order total
|
|
PromotionSchema.methods.calculateDiscount = function(orderTotal) {
|
|
if (!this.isValid()) {
|
|
return 0;
|
|
}
|
|
|
|
if (orderTotal < this.minOrderAmount) {
|
|
return 0;
|
|
}
|
|
|
|
let discountAmount = 0;
|
|
|
|
if (this.discountType === "percentage") {
|
|
discountAmount = (orderTotal * this.discountValue) / 100;
|
|
} else {
|
|
// Fixed amount discount
|
|
discountAmount = this.discountValue;
|
|
|
|
// Ensure discount doesn't exceed order total
|
|
if (discountAmount > orderTotal) {
|
|
discountAmount = orderTotal;
|
|
}
|
|
}
|
|
|
|
return parseFloat(discountAmount.toFixed(2));
|
|
};
|
|
|
|
const Promotion = mongoose.model("Promotion", PromotionSchema);
|
|
|
|
export default Promotion;
|