diff --git a/resources/RD_Ordes/rdOrderController.js b/resources/RD_Ordes/rdOrderController.js index 30b9bd7..f1e2498 100644 --- a/resources/RD_Ordes/rdOrderController.js +++ b/resources/RD_Ordes/rdOrderController.js @@ -600,7 +600,525 @@ export const processOrder = async (req, res) => { .json({ error: "An error occurred while processing the order" }); } }; +// get invoice by id +export const getProcessingInvoicesForPd = async (req, res) => { + console.log("req , cames"); + try { + // Ensure this is passed in your route, or retrieve it from the logged-in user + const page = parseInt(req.query.page, 10) || 1; // Default page is 1 + const limit = parseInt(req.query.limit, 10) || 5; // Default limit is 5 + const skip = (page - 1) * limit; + const { invoiceId, orderId } = req.query; // Search parameters + const pdId = req.user._id; + if (!pdId) { + return res.status(400).json({ message: "PD ID is required" }); + } + console.log(pdId); + // Build the base query for fetching processing invoices + let query = { courierStatus: "processing" }; + + // If invoiceId is provided, add regex search for invoiceId + if (invoiceId) { + query.invoiceId = { $regex: invoiceId, $options: "i" }; // Case-insensitive search + } + + // Fetch the invoices matching the query, along with pagination and population + const invoices = await InvoiceRd.find(query) + .skip(skip) + .limit(limit) + .populate({ + path: "orderId", + match: { pd: pdId }, // Match the associated PD in the RdOrder model + select: "uniqueId", // Only select uniqueId from the order + }) + .sort({ "courierstatus_timeline.processing": -1 }); // Sort by processing date, newest first + console.log(invoices); + // Filter invoices where the orderId exists and matches the search (if orderId is provided) + let filteredInvoices = invoices.filter( + (invoice) => invoice.orderId !== null + ); + + if (orderId) { + filteredInvoices = filteredInvoices.filter( + (invoice) => + invoice.orderId && + invoice.orderId.uniqueId && + invoice.orderId.uniqueId.toLowerCase().includes(orderId.toLowerCase()) + ); + } + + // Pagination metadata + const totalCount = filteredInvoices.length; + const totalPages = Math.ceil(totalCount / limit); + + // Send the filtered invoices with pagination details + res.status(200).json({ + totalCount, + currentPage: page, + totalPages, + invoices: filteredInvoices, + }); + } catch (error) { + console.error(error); + res.status(500).json({ error: error.message }); + } +}; + +export const getInvoiceDetailsByIdForPD = async (req, res) => { + const { invoiceId } = req.params; + + try { + // Find the invoice by ID and populate the orderId and addedBy fields + const invoice = await InvoiceRd.findById(invoiceId).populate({ + path: "orderId", + model: "PdOrder", + populate: { + path: "addedBy", + model: "RetailDistributor", + select: "name email phone ", // Select only specific fields + }, + }); + + if (!invoice) { + return res.status(404).json({ error: "Invoice not found" }); + } + + res.status(200).json(invoice); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; +export const updateCourierStatusToDispatchedForPD = async (req, res) => { + const { invoiceId } = req.params; + const { courierName, couriertrackingId } = req.body; + try { + // Find the invoice by ID + const invoice = await InvoiceRd.findById(invoiceId).populate({ + path: "orderId", + populate: { + path: "addedBy", + select: "email", + }, + }); + + if (!invoice) { + return res.status(404).json({ error: "Invoice not found" }); + } + + invoice.courierStatus = "dispatched"; + invoice.courierstatus_timeline.dispatched = new Date(); + invoice.courier_name = courierName; + invoice.courier_tracking_id = couriertrackingId; + + // Save the updated invoice + await invoice.save(); + + const order = invoice.orderId; + const allItemsDispatched = order.orderItem.every( + (item) => item.remainingQuantity === 0 + ); + + if (allItemsDispatched) { + order.status = "dispatched"; + await order.save(); + } + + // Send email to the user + await sendEmail({ + to: `${order?.addedBy?.email}`, // Assuming 'addedBy' references the user who placed the order + from: `${process.env.SEND_EMAIL_FROM}`, // Change to your verified sender + subject: `Your Order #${order?.uniqueId} is On Its Way!`, + html: ` + Hi, +

Exciting news! Your order #${ + order?.uniqueId + } has been dispatched and is en route to you. 🚚 Here are the details:

+ +

Courier Name: ${ + invoice?.courier_name || "N/A" + }

+

Courier Tracking ID: ${ + invoice?.courier_tracking_id || "N/A" + }

+ +

Items:

+ + + + + + + + + + + + + + + ${invoice?.items + ?.map( + (product, index) => ` + + + + + + + + + + + ` + ) + .join("")} + + + + + +
S No.Product NameSKUImageQuantityPriceGST AmountSubTotal
${ + index + 1 + }${ + product.name + }${ + product.SKU + } + ${ + product.image && product.image.length > 0 + ? `${product.name}` + : "No Image" + } + ${ + product.processquantity + }₹${ + product.price + }₹${( + (product.GST * product.price) / + 100 + ).toFixed(2)}₹${( + (product.price + (product.GST * product.price) / 100) * + product.processquantity + ).toFixed(2)}
Total Amount:₹${ + invoice.invoiceAmount + }
+ +

Order Status: Dispatched

+

If you have any questions or need assistance, feel free to reply to this email.

+
Thanks for choosing Cheminova! We hope you enjoy your purchase.
+
+ Best regards,
+ Team Cheminova + `, + }); + + res.status(200).json({ + message: "Courier status updated to dispatched", + orderStatus: order.status, + }); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; +export const updateCourierStatusToDeliveredForPD = async (req, res) => { + const { invoiceId } = req.params; + + try { + // Find the invoice by ID + const invoice = await InvoiceRd.findById(invoiceId).populate({ + path: "orderId", + populate: { + path: "addedBy", + select: "email", + }, + }); + if (!invoice) { + return res.status(404).json({ error: "Invoice not found" }); + } + + // Update courier status and timeline + invoice.courierStatus = "delivered"; + invoice.courierstatus_timeline.delivered = new Date(); + + // Save the updated invoice + await invoice.save(); + + const order = invoice.orderId; + const allItemsDelivered = order.orderItem.every( + (item) => item.remainingQuantity === 0 + ); + + if (allItemsDelivered) { + order.status = "delivered"; + await order.save(); + } + // Get the userId from the order's addedBy + const userId = order?.addedBy?._id; + + if (!userId) { + return res.status(400).json({ error: "User not found for the order" }); + } + // Check if PDStock exists for the user + // let pdStock = await PDStock.findOne({ userId }); + + // if (!pdStock) { + // // If no stock record exists, create a new one + // pdStock = new PDStock({ + // userId, + // products: [], // Initialize with empty products array + // }); + // } + // // Iterate over each item in the invoice + // for (let item of invoice.items) { + // const { productId, processquantity } = item; + + // // Check if the product already exists in the PDStock for the user + // const existingProduct = pdStock.products.find( + // (p) => p.productid.toString() === productId.toString() + // ); + + // if (existingProduct) { + // // If the product exists, update the stock by adding the processquantity + // existingProduct.Stock += processquantity; + // } else { + // // If the product doesn't exist, add a new entry for the product + // pdStock.products.push({ + // productid: productId, + // Stock: processquantity, + // }); + // } + // } + // Save the updated PDStock + // await pdStock.save(); + // Format the current date for display + const formattedDate = formatDate(new Date()); + + // Send email to the user + await sendEmail({ + to: `${order?.addedBy?.email}`, // Using 'addedBy' to reference the user's email + from: `${process.env.SEND_EMAIL_FROM}`, // Your verified sender + subject: `Your Order #${order?.uniqueId} Has Been Delivered!`, + html: ` + Hi, +

+ Great news! Your order #${ + order?.uniqueId + } has been successfully delivered to your doorstep. We hope everything is just as you expected! +

+ +

Items:

+ + + + + + + + + + + + + + + ${invoice?.items + ?.map( + (product, index) => ` + + + + + + + + + + + ` + ) + .join("")} + + + + + +
S No.Product NameSKUImageQuantityPriceGST AmountSubTotal
${ + index + 1 + }${ + product.name + }${ + product.SKU + } + ${ + product.image && product.image.length > 0 + ? `${product.name}` + : "No Image" + } + ${ + product.processquantity + }₹${ + product.price + }₹${( + (product.GST * product.price) / + 100 + ).toFixed(2)}₹${( + (product.price + (product.GST * product.price) / 100) * + product.processquantity + ).toFixed(2)}
Total Amount:₹${invoice.invoiceAmount.toFixed( + 2 + )}
+ +

Delivery Date: ${formattedDate}

+ +

+ Your satisfaction is our priority, and we'd love to hear about your experience. Please take a moment to share your thoughts by leaving a review. Your feedback is invaluable to us! +

+ +
+ If you have any questions or concerns about your order, feel free to reply to this email. +
+ +
+ Thank you for choosing Cheminova! We hope to serve you again soon. +
+ +
+ Best regards,
+ Team Cheminova + `, + }); + + res.status(200).json({ + message: "Courier status updated to delivered", + orderStatus: order.status, + }); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}; +export const getDispatchedInvoicesForPd = async (req, res) => { + try { + const pdId = req.params.pdId; // Ensure this is passed in your route, or retrieve it from the logged-in user + const page = parseInt(req.query.page, 10) || 1; // Default page is 1 + const limit = parseInt(req.query.limit, 10) || 5; // Default limit is 5 + const skip = (page - 1) * limit; + const { invoiceId, orderId } = req.query; // Search parameters + + if (!pdId) { + return res.status(400).json({ message: "PD ID is required" }); + } + + // Build the base query for fetching processing invoices + let query = { courierStatus: "dispatched" }; + + // If invoiceId is provided, add regex search for invoiceId + if (invoiceId) { + query.invoiceId = { $regex: invoiceId, $options: "i" }; // Case-insensitive search + } + + // Fetch the invoices matching the query, along with pagination and population + const invoices = await InvoiceRd.find(query) + .skip(skip) + .limit(limit) + .populate({ + path: "orderId", + match: { pd: pdId }, // Match the associated PD in the RdOrder model + select: "uniqueId", // Only select uniqueId from the order + }) + .sort({ "courierstatus_timeline.processing": -1 }); // Sort by processing date, newest first + + // Filter invoices where the orderId exists and matches the search (if orderId is provided) + let filteredInvoices = invoices.filter( + (invoice) => invoice.orderId !== null + ); + + if (orderId) { + filteredInvoices = filteredInvoices.filter( + (invoice) => + invoice.orderId && + invoice.orderId.uniqueId && + invoice.orderId.uniqueId.toLowerCase().includes(orderId.toLowerCase()) + ); + } + + // Pagination metadata + const totalCount = filteredInvoices.length; + const totalPages = Math.ceil(totalCount / limit); + + // Send the filtered invoices with pagination details + res.status(200).json({ + totalCount, + currentPage: page, + totalPages, + invoices: filteredInvoices, + }); + } catch (error) { + console.error(error); + res.status(500).json({ error: error.message }); + } +}; +export const getDeliveredInvoicesForPd = async (req, res) => { + try { + const pdId = req.params.pdId; // Ensure this is passed in your route, or retrieve it from the logged-in user + const page = parseInt(req.query.page, 10) || 1; // Default page is 1 + const limit = parseInt(req.query.limit, 10) || 5; // Default limit is 5 + const skip = (page - 1) * limit; + const { invoiceId, orderId } = req.query; // Search parameters + + if (!pdId) { + return res.status(400).json({ message: "PD ID is required" }); + } + + // Build the base query for fetching processing invoices + let query = { courierStatus: "delivered" }; + + // If invoiceId is provided, add regex search for invoiceId + if (invoiceId) { + query.invoiceId = { $regex: invoiceId, $options: "i" }; // Case-insensitive search + } + + // Fetch the invoices matching the query, along with pagination and population + const invoices = await InvoiceRd.find(query) + .skip(skip) + .limit(limit) + .populate({ + path: "orderId", + match: { pd: pdId }, // Match the associated PD in the RdOrder model + select: "uniqueId", // Only select uniqueId from the order + }) + .sort({ "courierstatus_timeline.processing": -1 }); // Sort by processing date, newest first + + // Filter invoices where the orderId exists and matches the search (if orderId is provided) + let filteredInvoices = invoices.filter( + (invoice) => invoice.orderId !== null + ); + + if (orderId) { + filteredInvoices = filteredInvoices.filter( + (invoice) => + invoice.orderId && + invoice.orderId.uniqueId && + invoice.orderId.uniqueId.toLowerCase().includes(orderId.toLowerCase()) + ); + } + + // Pagination metadata + const totalCount = filteredInvoices.length; + const totalPages = Math.ceil(totalCount / limit); + + // Send the filtered invoices with pagination details + res.status(200).json({ + totalCount, + currentPage: page, + totalPages, + invoices: filteredInvoices, + }); + } catch (error) { + console.error(error); + res.status(500).json({ error: error.message }); + } +}; // cancell order export const cancelOrderController = async (req, res) => { @@ -832,3 +1350,15 @@ export const cancelOrderController = async (req, res) => { .json({ message: "An error occurred while cancelling the order" }); } }; +const formatDate = (date) => { + const options = { + weekday: "short", + year: "numeric", + month: "short", + day: "2-digit", + // hour: "2-digit", + // minute: "2-digit", + // hour12: true, + }; + return new Intl.DateTimeFormat("en-US", options).format(new Date(date)); +}; diff --git a/resources/RD_Ordes/rdOrderRoutes.js b/resources/RD_Ordes/rdOrderRoutes.js index 5432ea0..239eef4 100644 --- a/resources/RD_Ordes/rdOrderRoutes.js +++ b/resources/RD_Ordes/rdOrderRoutes.js @@ -3,16 +3,26 @@ import { cancelOrderController, createOrderRD, getCancelledOrders, + getDeliveredInvoicesForPd, + getDispatchedInvoicesForPd, + getInvoiceDetailsByIdForPD, getNewOrders, getPendignOrders, getPlacedOrdersForPD, getPlacedOrdersForRD, + getProcessingInvoicesForPd, getSinglePlacedOrderForPD, getSinglePlacedOrderForRD, processOrder, + updateCourierStatusToDeliveredForPD, + updateCourierStatusToDispatchedForPD, } from "./rdOrderController.js"; import { isAuthenticatedRD } from "../../middlewares/rdAuth.js"; import { isAuthenticatedUser } from "../../middlewares/auth.js"; +import { + getDispatchedInvoices, + getProcessingInvoices, +} from "../PD_Orders/pdOrderController.js"; const router = express.Router(); router.route("/rd-place-order").post(isAuthenticatedRD, createOrderRD); @@ -38,8 +48,32 @@ router router .route("/pd-get-cancelled-orders") .get(isAuthenticatedUser, getCancelledOrders); + +router + .route("/pd-get-processing-invoices") + .get(isAuthenticatedUser, getProcessingInvoicesForPd); +router + .route("/pd-get-dispatched-invoices") + .get(isAuthenticatedUser, getDispatchedInvoicesForPd); +router + .route("/pd-get-delivered-invoices") + .get(isAuthenticatedUser, getDeliveredInvoicesForPd); +router + .route("/pd-get-invoices/:invoiceId") + .get(isAuthenticatedUser, getInvoiceDetailsByIdForPD); router .route("/pd-cancel-order/:id") .put(isAuthenticatedUser, cancelOrderController); +router.route("/invoice/dispatched/:invoiceId").put( + isAuthenticatedUser, + + updateCourierStatusToDispatchedForPD +); + +router.route("/invoice/delivered/:invoiceId").put( + isAuthenticatedUser, + + updateCourierStatusToDeliveredForPD +); export default router;