face / src /models /Order.js
aliroohan179's picture
feat: implement order model and comprehensive reporting controller for analytics, profit/loss, and CSV exports
385d733
Raw History Blame Contribute Delete
1.96 kB
const mongoose = require('mongoose');
const orderItemSchema = new mongoose.Schema(
{
menuItem: { type: mongoose.Schema.Types.ObjectId, ref: 'MenuItem', required: true },
menuItemName: { type: String, required: true }, // denormalised snapshot for reporting
variantId: { type: mongoose.Schema.Types.ObjectId, required: true },
variantLabel: { type: String, required: true }, // snapshot
qty: { type: Number, required: true, min: 1 },
priceAtSale: { type: Number, required: true, min: 0 }, // snapshot — never recalculate from live menu
},
{ _id: false }
);
const orderSchema = new mongoose.Schema(
{
// Client-generated UUID — used as idempotency key during offline sync
localId: { type: String, required: true, unique: true, index: true },
orderType: { type: String, enum: ['dine-in', 'takeaway', 'delivery'], required: true },
items: { type: [orderItemSchema], required: true },
subtotal: { type: Number, required: true },
discount: {
amount: { type: Number, default: 0 },
reason: { type: String, default: '' },
},
netTotal: { type: Number, required: true },
deliveryFee: { type: Number, default: 0 },
cashReceived: { type: Number, default: 0 },
change: { type: Number, default: 0 },
status: { type: String, enum: ['held', 'completed', 'voided'], default: 'completed' },
voidedBy: { type: mongoose.Schema.Types.ObjectId, ref: 'User', default: null },
voidedAt: { type: Date, default: null },
cashier: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
// synced is a client-side-only concept; all server records are considered synced
createdAt: { type: Date, default: Date.now },
},
{ timestamps: false } // we manage createdAt manually to preserve offline timestamps
);
orderSchema.index({ createdAt: -1 });
orderSchema.index({ status: 1, createdAt: -1 });
module.exports = mongoose.model('Order', orderSchema);