const Order = require('../models/orderModel'); const Cart = require('../models/cartModel'); const Product = require('../models/productModel'); // @desc Create new order from cart // @route POST /api/orders // @access Private exports.createOrder = async (req, res) => { try { const { deliveryAddress, paymentMethod, notes } = req.body; // Get user's cart const cart = await Cart.findOne({ user: req.user.id }); if (!cart || cart.items.length === 0) { return res.status(400).json({ message: 'Cart is empty' }); } // Validate cart items and calculate total let total = 0; const orderItems = []; for (const item of cart.items) { const product = await Product.findById(item.product); if (!product) { return res.status(404).json({ message: `Product ${item.product} not found` }); } if (product.stock < item.quantity) { return res.status(400).json({ message: `Insufficient stock for ${product.name}` }); } orderItems.push({ productId: product._id, name: product.name, price: product.price, quantity: item.quantity }); total += product.price * item.quantity; // Reduce stock product.stock -= item.quantity; await product.save(); } // Create order const order = await Order.create({ userId: req.user.id, items: orderItems, total, deliveryAddress, paymentMethod: paymentMethod || 'cash', notes: notes || '' }); // Clear cart cart.items = []; await cart.save(); res.status(201).json({ success: true, message: 'Order created successfully', order: order.getPublicData() }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } }; // @desc Get user's orders // @route GET /api/orders // @access Private exports.getUserOrders = async (req, res) => { try { const orders = await Order.find({ userId: req.user.id }); res.status(200).json({ success: true, count: orders.length, orders: orders.map(order => order.getPublicData()) }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } }; // @desc Get single order // @route GET /api/orders/:id // @access Private exports.getOrder = async (req, res) => { try { const { id } = req.params; const order = await Order.findById(id); if (!order) { return res.status(404).json({ message: 'Order not found' }); } // Check if user owns this order or is admin if (order.userId !== req.user.id && req.user.role !== 'admin') { return res.status(403).json({ message: 'Not authorized to view this order' }); } res.status(200).json({ success: true, order: order.getPublicData() }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } }; // @desc Update order status (Admin only) // @route PUT /api/orders/:id/status // @access Private/Admin exports.updateOrderStatus = async (req, res) => { try { const { id } = req.params; const { status } = req.body; if (!status) { return res.status(400).json({ message: 'Status is required' }); } const validStatuses = ['pending', 'confirmed', 'preparing', 'ready', 'delivered', 'cancelled']; if (!validStatuses.includes(status)) { return res.status(400).json({ message: 'Invalid status' }); } const order = await Order.findById(id); if (!order) { return res.status(404).json({ message: 'Order not found' }); } order.status = status; await order.save(); res.status(200).json({ success: true, message: 'Order status updated successfully', order: order.getPublicData() }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } }; // @desc Cancel order // @route PUT /api/orders/:id/cancel // @access Private exports.cancelOrder = async (req, res) => { try { const { id } = req.params; const order = await Order.findById(id); if (!order) { return res.status(404).json({ message: 'Order not found' }); } // Check if user owns this order if (order.userId !== req.user.id) { return res.status(403).json({ message: 'Not authorized to cancel this order' }); } // Only allow cancellation if order is pending or confirmed if (!['pending', 'confirmed'].includes(order.status)) { return res.status(400).json({ message: 'Order cannot be cancelled at this stage' }); } // Restore product stock for (const item of order.items) { const product = await Product.findById(item.productId); if (product) { product.stock += item.quantity; await product.save(); } } order.status = 'cancelled'; await order.save(); res.status(200).json({ success: true, message: 'Order cancelled successfully', order: order.getPublicData() }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } }; // @desc Get all orders (Admin only) // @route GET /api/orders/admin/all // @access Private/Admin exports.getAllOrders = async (req, res) => { try { const { status, page = 1, limit = 10 } = req.query; let query = {}; if (status) { query.status = status; } const orders = await Order.find(query); // Simple pagination const startIndex = (page - 1) * limit; const endIndex = page * limit; const paginatedOrders = orders.slice(startIndex, endIndex); res.status(200).json({ success: true, count: paginatedOrders.length, total: orders.length, page: parseInt(page), pages: Math.ceil(orders.length / limit), orders: paginatedOrders.map(order => order.getPublicData()) }); } catch (error) { res.status(500).json({ success: false, message: error.message }); } };