Files
Guitar-Ecommerce/server/controllers/orderController.js
2026-09-16 17:36:46 +05:30

213 lines
6.0 KiB
JavaScript

const Order = require('../models/Order');
const Product = require('../models/Product');
const InventoryHistory = require('../models/InventoryHistory');
const Cart = require('../models/Cart');
const { sendEmail } = require('../utils/emailSender');
const { successResponse, errorResponse } = require('../utils/apiResponse');
// @desc Create new order
// @route POST /api/orders
// @access Private
const createOrder = async (req, res, next) => {
try {
const {
orderItems,
shippingAddress,
paymentMethod,
itemsPrice,
taxPrice,
shippingPrice,
discountAmount,
totalAmount
} = req.body;
if (!orderItems || orderItems.length === 0) {
return errorResponse(res, 'No order items provided', [], 400);
}
// 1. Check stock and reduce inventory
for (const item of orderItems) {
const product = await Product.findById(item.product);
if (!product) {
return errorResponse(res, `Product ${item.name} not found`, [], 400);
}
if (product.stock < item.quantity) {
return errorResponse(res, `Insufficient stock for product ${product.name}`, [], 400);
}
// Record stock deduction
const oldStock = product.stock;
product.stock -= item.quantity;
product.salesCount += item.quantity;
await product.save();
await InventoryHistory.create({
product: product._id,
sku: product.sku,
changeType: 'Order Placed',
quantityChanged: -item.quantity,
previousStock: oldStock,
newStock: product.stock,
reason: `Order placed by user ${req.user.name}`,
performedBy: req.user._id
});
}
// 2. Generate unique order number
const orderNumber = `GTR-${Math.floor(100000 + Math.random() * 900000)}`;
// 3. Save Order
const order = new Order({
orderNumber,
user: req.user._id,
orderItems,
shippingAddress,
paymentMethod,
itemsPrice,
taxPrice,
shippingPrice,
discountAmount,
totalAmount,
isPaid: paymentMethod === 'Stripe', // Auto mark paid for simulated stripe
paidAt: paymentMethod === 'Stripe' ? Date.now() : null,
orderStatus: paymentMethod === 'Stripe' ? 'Payment Confirmed' : 'Pending',
statusHistory: [
{
status: paymentMethod === 'Stripe' ? 'Payment Confirmed' : 'Pending',
note: `Order created via ${paymentMethod}`
}
]
});
const createdOrder = await order.save();
// 4. Clear user cart
await Cart.findOneAndDelete({ user: req.user._id });
// 5. Send order confirmation email
sendEmail({
templateName: 'Order Confirmation',
to: req.user.email,
variables: {
customerName: req.user.name,
orderId: createdOrder.orderNumber,
orderTotal: `$${createdOrder.totalAmount.toFixed(2)}`
}
});
return successResponse(res, 'Order created successfully', createdOrder, 201);
} catch (error) {
next(error);
}
};
// @desc Get logged in user orders
// @route GET /api/orders/my-orders
// @access Private
const getMyOrders = async (req, res, next) => {
try {
const orders = await Order.find({ user: req.user._id }).sort({ createdAt: -1 });
return successResponse(res, 'User orders retrieved', orders);
} catch (error) {
next(error);
}
};
// @desc Get order by ID
// @route GET /api/orders/:id
// @access Private
const getOrderById = async (req, res, next) => {
try {
const order = await Order.findById(req.params.id).populate('user', 'name email phone');
if (!order) {
return errorResponse(res, 'Order not found', [], 404);
}
// Check authorization: customer can only view own order unless Admin
if (order.user._id.toString() !== req.user._id.toString() && req.user.role !== 'Admin') {
return errorResponse(res, 'Not authorized to view this order', [], 403);
}
return successResponse(res, 'Order retrieved', order);
} catch (error) {
next(error);
}
};
// @desc Get all orders (Admin)
// @route GET /api/orders
// @access Private/Admin
const getAllOrders = async (req, res, next) => {
try {
const { status } = req.query;
const filter = {};
if (status) filter.orderStatus = status;
const orders = await Order.find(filter)
.populate('user', 'name email')
.sort({ createdAt: -1 });
return successResponse(res, 'All orders retrieved', orders);
} catch (error) {
next(error);
}
};
// @desc Update order status & shipping info (Admin)
// @route PUT /api/orders/:id/status
// @access Private/Admin
const updateOrderStatus = async (req, res, next) => {
try {
const { orderStatus, trackingNumber, shippingProvider, note } = req.body;
const order = await Order.findById(req.params.id).populate('user', 'name email');
if (!order) {
return errorResponse(res, 'Order not found', [], 404);
}
if (orderStatus) {
order.orderStatus = orderStatus;
order.statusHistory.push({
status: orderStatus,
note: note || `Status updated to ${orderStatus}`
});
}
if (trackingNumber) order.trackingNumber = trackingNumber;
if (shippingProvider) order.shippingProvider = shippingProvider;
if (orderStatus === 'Delivered') {
order.isDelivered = true;
order.deliveredAt = Date.now();
}
const updatedOrder = await order.save();
// Trigger status change email
if (['Shipped', 'Delivered', 'Cancelled'].includes(orderStatus)) {
sendEmail({
templateName: orderStatus === 'Shipped' ? 'Order Shipped' : 'Order Confirmation',
to: order.user.email,
variables: {
customerName: order.user.name,
orderId: order.orderNumber,
trackingNumber: order.trackingNumber || 'N/A'
}
});
}
return successResponse(res, 'Order status updated', updatedOrder);
} catch (error) {
next(error);
}
};
module.exports = {
createOrder,
getMyOrders,
getOrderById,
getAllOrders,
updateOrderStatus
};