samoulla-backend / models /orderModel.js
Samoulla Sync Bot
Auto-deploy Samoulla Backend: 8574a71f0fc617aeb1ce9b5e35dac24c5319a12a
59c49c1
const mongoose = require('mongoose');
const Counter = require('./counterModel');
const orderSchema = new mongoose.Schema(
{
orderNumber: {
type: Number,
unique: true,
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: false,
},
name: {
type: String,
required: [true, 'Customer name is required'],
trim: true,
},
mobile: {
type: String,
required: [true, 'Mobile number is required'],
trim: true,
},
address: {
governorate: {
type: String,
required: [true, 'Governorate is required'],
trim: true,
},
city: {
type: String,
required: [true, 'City is required'],
trim: true,
},
district: {
type: String,
required: [true, 'District is required'],
trim: true,
},
street: {
type: String,
required: [true, 'Street is required'],
trim: true,
},
},
items: [
{
product: { type: mongoose.Schema.ObjectId, ref: 'Product' },
name: String,
quantity: { type: Number, min: 1, default: 1 },
unitPrice: Number,
fulfillmentStatus: {
type: String,
enum: ['pending', 'preparing', 'ready', 'cancelled'],
default: 'pending',
},
},
],
payment: {
method: {
type: String,
enum: ['cash', 'visa'],
required: [true, 'Payment method is required'],
},
status: {
type: String,
enum: ['pending', 'paid', 'failed'],
default: 'pending',
},
paidAt: {
type: Date,
required: false,
},
paymobTransactionId: {
type: String,
required: false,
},
paymobOrderId: {
type: String,
required: false,
},
paymentKey: {
type: String,
required: false,
},
frontendUrl: {
type: String,
required: false,
},
refundedAt: {
type: Date,
required: false,
},
refundAmount: {
type: Number,
required: false,
},
},
promoCode: {
type: String,
trim: true,
},
promo: {
type: mongoose.Schema.ObjectId,
ref: 'PromoCode',
required: false,
},
discountAmount: {
type: Number,
default: 0,
},
discountType: {
type: String,
enum: ['percentage', 'fixed'],
required: false,
},
images: [
{
filename: String,
url: String,
contentType: String,
},
],
totalPrice: {
type: Number,
required: [true, 'Total price is required'],
min: [0, 'Total price must be positive'],
},
orderStatus: {
type: String,
enum: ['created', 'processing', 'shipped', 'cancelled', 'completed'],
default: 'created',
},
canceledAt: {
type: Date,
required: false,
},
notes: {
type: String,
trim: true,
},
estimatedDeliveryDate: {
type: Date,
},
shippingPrice: {
type: Number,
default: 0,
},
source: {
type: String,
trim: true,
default: 'direct',
},
},
{
timestamps: true,
},
);
orderSchema.pre('save', async function (next) {
if (!this.isNew) return next();
try {
const counter = await Counter.findOneAndUpdate(
{ id: 'orderNumber' },
{ $inc: { seq: 1 } },
{ new: true, upsert: true },
);
this.orderNumber = counter.seq;
next();
} catch (error) {
next(error);
}
});
orderSchema.index({ user: 1, createdAt: -1 });
orderSchema.index({ orderStatus: 1 });
orderSchema.index({ createdAt: -1 });
orderSchema.index({ orderNumber: 1 });
const Order = mongoose.model('Order', orderSchema);
module.exports = Order;