Spaces:
Running
Running
| 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; | |