other
This commit is contained in:
126
backend/models/Promotion.model.js
Normal file
126
backend/models/Promotion.model.js
Normal file
@@ -0,0 +1,126 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user