order partial and fully processing with sending mail and fully cancel and partial cancel with mail was send successfully

This commit is contained in:
Sibunnayak 2024-09-19 16:06:31 +05:30
parent 839f942f08
commit a6707d5dea
2 changed files with 344 additions and 42 deletions

View File

@ -75,21 +75,29 @@ export const processOrder = async (req, res) => {
const { orderId, invoiceItems } = req.body;
if (!orderId || !invoiceItems || !Array.isArray(invoiceItems)) {
return res.status(400).json({ error: 'Missing required fields or invalid data' });
return res
.status(400)
.json({ error: "Missing required fields or invalid data" });
}
// Find the order by ID
const order = await PdOrder.findById(orderId).populate('addedBy');
const order = await PdOrder.findById(orderId).populate("addedBy");
if (!order) {
return res.status(404).json({ error: 'Order not found' });
return res.status(404).json({ error: "Order not found" });
}
// Validate quantities
for (const item of invoiceItems) {
const orderItem = order.orderItem.find(i => i.productId.toString() === item.productId.toString());
const orderItem = order.orderItem.find(
(i) => i.productId.toString() === item.productId.toString()
);
if (orderItem && item.processquantity > orderItem.remainingQuantity) {
return res.status(400).json({ error: `Product '${item.name}' has more quantity than remaining in the order.` });
return res
.status(400)
.json({
error: `Product '${item.name}' has more quantity than remaining in the order.`,
});
}
}
@ -103,9 +111,9 @@ export const processOrder = async (req, res) => {
let gstTotal = 0;
let invoiceAmount = 0;
invoiceItems.forEach(item => {
invoiceItems.forEach((item) => {
const itemSubtotal = item.price * item.processquantity;
const itemGST = (item.price * item.GST / 100) * item.processquantity;
const itemGST = ((item.price * item.GST) / 100) * item.processquantity;
subtotal += itemSubtotal;
gstTotal += itemGST;
@ -127,8 +135,10 @@ export const processOrder = async (req, res) => {
// Update the order's order items with the remaining quantity
let allItemsProcessed = true;
order.orderItem.forEach(item => {
const invoicedItem = invoiceItems.find(i => i.productId.toString() === item.productId.toString());
order.orderItem.forEach((item) => {
const invoicedItem = invoiceItems.find(
(i) => i.productId.toString() === item.productId.toString()
);
if (invoicedItem) {
item.remainingQuantity -= invoicedItem.processquantity;
if (item.remainingQuantity < 0) {
@ -142,55 +152,98 @@ export const processOrder = async (req, res) => {
// Calculate total amount for pending items
let pendingTotalAmount = 0;
order.orderItem.forEach(item => {
order.orderItem.forEach((item) => {
if (item.remainingQuantity > 0) {
const itemPendingSubtotal = item.price * item.remainingQuantity;
const itemPendingGST = (item.price * item.GST / 100) * item.remainingQuantity;
const itemPendingGST =
((item.price * item.GST) / 100) * item.remainingQuantity;
pendingTotalAmount += itemPendingSubtotal + itemPendingGST;
}
});
// Update the order status
order.status = allItemsProcessed ? 'processing' : 'pending';
order.status = allItemsProcessed ? "processing" : "pending";
order.invoices.push(savedInvoice._id);
// Save the updated order
await order.save();
// Prepare the email content
const processedItems = invoiceItems.map((item, index) => `
const processedItems = invoiceItems
.map(
(item, index) => `
<tr>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${index + 1}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${item.name}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
index + 1
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.name
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">
${item.image && item.image.length > 0 ? `<img src="${item.image[0]?.url}" alt="${item.name}" style="max-width: 40px; height: auto;">` : 'No Image'}
${
item.image && item.image.length > 0
? `<img src="${item.image[0]?.url}" alt="${item.name}" style="max-width: 40px; height: auto;">`
: "No Image"
}
</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${item.processquantity}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${item.price}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${(item.GST * item.price) / 100}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${(item.price + (item.GST * item.price) / 100) * item.processquantity}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.processquantity
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.price
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
(item.GST * item.price) / 100
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
(item.price + (item.GST * item.price) / 100) * item.processquantity
}</td>
</tr>
`).join("");
`
)
.join("");
const pendingItems = order.orderItem.filter(item => item.remainingQuantity > 0).map((item, index) => `
const pendingItems = order.orderItem
.filter((item) => item.remainingQuantity > 0)
.map(
(item, index) => `
<tr>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${index + 1}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${item.name}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
index + 1
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.name
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">
${item.image && item.image.length > 0 ? `<img src="${item.image[0]?.url}" alt="${item.name}" style="max-width: 40px; height: auto;">` : 'No Image'}
${
item.image && item.image.length > 0
? `<img src="${item.image[0]?.url}" alt="${item.name}" style="max-width: 40px; height: auto;">`
: "No Image"
}
</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${item.remainingQuantity}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${item.price}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${(item.GST * item.price) / 100}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${(item.price + (item.GST * item.price) / 100) * item.remainingQuantity}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.remainingQuantity
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.price
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
(item.GST * item.price) / 100
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
(item.price + (item.GST * item.price) / 100) * item.remainingQuantity
}</td>
</tr>
`).join("");
`
)
.join("");
// Dynamic email subject and message based on the order status
const emailSubject = allItemsProcessed
? `Your Order #${order.uniqueId} is in Processing!`
: `Your Order #${order.uniqueId} is Partially Processed!`;
const emailMessage = allItemsProcessed
const emailMessage = allItemsProcessed
? `
<h3>Exciting news! Your order #${order.uniqueId} has entered the processing phase. We're working hard to ensure everything is perfect for you.</h3>
<p>Your invoice ID is: <strong>${savedInvoice.invoiceId}</strong></p>
@ -207,8 +260,12 @@ export const processOrder = async (req, res) => {
html: `
<div style="font-family: Arial, sans-serif; color: #333;">
${emailMessage}
<strong style="color: #1b03a3; font-size: 16px;">Hi ${order.addedBy.name},</strong>
<h4 style="color: #333;">Order Status: ${order.status.charAt(0).toUpperCase() + order.status.slice(1)}</h4>
<strong style="color: #1b03a3; font-size: 16px;">Hi ${
order.addedBy.name
},</strong>
<h4 style="color: #333;">Order Status: ${
order.status.charAt(0).toUpperCase() + order.status.slice(1)
}</h4>
<h4 style="color: #333;">Processed Items:</h4>
<table style="border-collapse: collapse; width: 100%;">
@ -227,12 +284,16 @@ export const processOrder = async (req, res) => {
${processedItems}
<tr>
<th colspan="6" style="border: 1px solid #555; padding: 2px; text-align: right;">Total Amount:</th>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${savedInvoice.invoiceAmount.toFixed(2)}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${savedInvoice.invoiceAmount.toFixed(
2
)}</td>
</tr>
</tbody>
</table>
${pendingItems.length > 0 ? `
${
pendingItems.length > 0
? `
<h4 style="color: #333;">Pending Items:</h4>
<table style="border-collapse: collapse; width: 100%;">
<thead>
@ -250,20 +311,256 @@ export const processOrder = async (req, res) => {
${pendingItems}
<tr>
<th colspan="6" style="border: 1px solid #555; padding: 2px; text-align: right;">Pending Amount:</th>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${pendingTotalAmount.toFixed(2)}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${pendingTotalAmount.toFixed(
2
)}</td>
</tr>
</tbody>
</table>
` : ''}
`
: ""
}
</div>
`,
});
res.status(200).json({ message: 'Order processed and invoice created successfully', invoiceId: savedInvoice.invoiceId });
res
.status(200)
.json({
message: "Order processed and invoice created successfully",
invoiceId: savedInvoice.invoiceId,
});
} catch (error) {
console.error('Error processing order:', error);
res.status(500).json({ error: 'An error occurred while processing the order' });
console.error("Error processing order:", error);
res
.status(500)
.json({ error: "An error occurred while processing the order" });
}
};
export const cancelOrderController = async (req, res) => {
const { cancellationReason, id: _id } = req.body;
try {
// Find the order by ID
const order = await PdOrder.findById(_id)
.populate("invoices")
.populate("addedBy");
if (!order) {
return res.status(404).json({ message: "Order not found" });
}
// Update the order status to 'cancelled'
order.status = "cancelled";
order.iscancelled = true;
order.order_Cancelled_Reason =
cancellationReason || "No specific reason provided.";
await order.save();
if (order.invoices.length === 0) {
// If no invoices are associated with the order
await sendEmail({
to: `${order.addedBy.email}`, // Change to your recipient
from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender
subject: `Order #${order.uniqueId} Cancellation Confirmation`,
html: `
<strong style="color: #1b03a3; font-size: 16px">Hi ${order.addedBy.name},</strong>
<h3 style="color: #333; font-family: Arial, sans-serif;">We regret to inform you that your order #${order.uniqueId} has been fully cancelled.</h3>
<h4 style="color: #333; font-family: Arial, sans-serif;">Cancellation Reason: ${order.order_Cancelled_Reason}</h4>
<h5 style="color: #333; font-family: Arial, sans-serif;">If you have any concerns or further questions, please feel free to reply to this email.</h5>
<br/>
<span style="color: #555; font-size: 13px;">Best regards,</span><br/>
<span style="color: #555; font-size: 13px;">Team Cheminova</span>
`,
});
} else {
// If invoices are present
const invoices = await Invoice.find({ _id: { $in: order.invoices } });
// Collect all invoice data
const invoiceDetails = invoices.map((invoice) => {
let subtotal = 0;
let gstTotal = 0;
let totalAmount = 0;
const processedItems = invoice.items
.map((item) => {
const itemSubtotal = item.price * item.processquantity;
const itemGST =
((item.price * item.GST) / 100) * item.processquantity;
subtotal += itemSubtotal;
gstTotal += itemGST;
totalAmount += itemSubtotal + itemGST;
const itemImage =
item.image && Array.isArray(item.image) ? item.image[0]?.url : "";
return `
<tr>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.SKU
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.name
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;"><img src="${itemImage}" alt="${
item.name
}" style="max-width: 40px; height: auto;"></td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.processquantity
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.price
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
(item.price * item.GST)/100
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
itemSubtotal + itemGST
}</td>
</tr>
`;
})
.join("");
return {
invoiceId: invoice.invoiceId,
processedItems,
totalAmount,
};
});
// Collect all delivered and remaining items
let cancelItems = "";
let totalCancelAmount = 0;
if (Array.isArray(order.orderItem)) {
order.orderItem.forEach((item) => {
if (item.remainingQuantity > 0) {
const itemSubtotal = item.price * item.remainingQuantity;
const itemGST =
((item.price * item.GST) / 100) * item.remainingQuantity;
totalCancelAmount += itemSubtotal + itemGST;
const itemImage =
item.image && Array.isArray(item.image) ? item.image[0]?.url : "";
cancelItems += `
<tr>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.SKU
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.name
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;"><img src="${itemImage}" alt="${
item.name
}" style="max-width: 40px; height: auto;"></td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.remainingQuantity
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
item.price
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
(item.price * item.GST)/100
}</td>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
itemSubtotal + itemGST
}</td>
</tr>
`;
}
});
}
await sendEmail({
to: `${order.addedBy.email}`, // Change to your recipient
from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender
subject: `Order #${order.uniqueId} is Partially Cancelled!`,
html: `
<strong style="color: #1b03a3; font-size: 16px">Hi ${
order.addedBy.name
},</strong>
<h3 style="color: #333; font-family: Arial, sans-serif;">We would like to inform you that your order #${
order.uniqueId
} has been partially cancelled.</h3>
<h4 style="color: #333; font-family: Arial, sans-serif;">Cancellation Reason: ${
order.order_Cancelled_Reason
}</h4>
<h4 style="color: #333; font-family: Arial, sans-serif;">Delivered Items:</h4>
${invoiceDetails
.map(
(details) => `
<h5 style="color: #333; font-family: Arial, sans-serif;">Invoice ID: ${
details.invoiceId
}</h5>
<table style="border-collapse: collapse; width: 100%;">
<thead>
<tr>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">S No.</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Product Name</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Image</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Quantity</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Price</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">GST Amount</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">SubTotal</th>
</tr>
</thead>
<tbody>
${details.processedItems}
<tr>
<th colspan="6" style="border: 1px solid #555; padding: 2px; text-align: right;">Total Amount:</th>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${details.totalAmount.toFixed(
2
)}</td>
</tr>
</tbody>
</table>
`
)
.join("")}
<h4 style="color: #333; font-family: Arial, sans-serif;">Cancelled Items:</h4>
<table style="border-collapse: collapse; width: 100%;">
<thead>
<tr>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">S No.</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Product Name</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Image</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Quantity</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Price</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">GST Amount</th>
<th style="border: 1px solid #555; padding: 2px; text-align: center;">SubTotal</th>
</tr>
</thead>
<tbody>
${cancelItems}
<tr>
<th colspan="6" style="border: 1px solid #555; padding: 2px; text-align: right;">Total Refund Amount:</th>
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${totalCancelAmount.toFixed(
2
)}</td>
</tr>
</tbody>
</table>
<br/>
<h5 style="color: #333; font-family: Arial, sans-serif;">If you have any concerns or further questions, please feel free to reply to this email.</h5>
<br/>
<span style="color: #555; font-size: 13px;">Best regards,</span><br/>
<span style="color: #555; font-size: 13px;">Team Cheminova</span>
`,
});
}
res.status(200).json({ message: "Order cancelled successfully" });
} catch (error) {
console.error("Error cancelling order:", error);
res
.status(500)
.json({ message: "An error occurred while cancelling the order" });
}
};

View File

@ -12,6 +12,7 @@ import {
getProcessingOrdersAdmin,
updateOrderStatusById,
processOrder,
cancelOrderController,
} from "./pdOrderController.js";
const router = express.Router();
@ -27,6 +28,10 @@ router
router
.route("/processing-order")
.post(isAuthenticatedUser, authorizeRoles("admin"), processOrder);
// Define the route for cancel an order
router
.route("/cancel-order")
.post(isAuthenticatedUser, authorizeRoles("admin"), cancelOrderController);
router
.route("/get-placed-order-pd")
.get(