39647-vm/backend/controllers/orderController.js
2026-04-08 14:28:58 +04:00

222 lines
5.9 KiB
JavaScript

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 });
}
};