Merge branch 'main' of https://git.cnapp.co.in/gitadmin/api
This commit is contained in:
commit
f405476976
5
app.js
5
app.js
@ -202,6 +202,8 @@ import RDOrderRoute from "./resources/RD_Ordes/rdOrderRoutes.js"
|
|||||||
import TaskRoute from "./resources/Task/TaskRoute.js";
|
import TaskRoute from "./resources/Task/TaskRoute.js";
|
||||||
// visit RD and PD
|
// visit RD and PD
|
||||||
import VisitRDandPDRoute from "./resources/VisitRD&PD/VisitRD&PDRoute.js";
|
import VisitRDandPDRoute from "./resources/VisitRD&PD/VisitRD&PDRoute.js";
|
||||||
|
//Stock
|
||||||
|
import Stock from "./resources/Stock/PdStockRoute.js";
|
||||||
app.use("/api/v1", user);
|
app.use("/api/v1", user);
|
||||||
|
|
||||||
//Product
|
//Product
|
||||||
@ -293,7 +295,8 @@ app.use("/api", VisitRDandPDRoute);
|
|||||||
//short urls
|
//short urls
|
||||||
// app.use("/api/shorturl", ShortUrlRouter);
|
// app.use("/api/shorturl", ShortUrlRouter);
|
||||||
//Support
|
//Support
|
||||||
|
//Stock
|
||||||
|
app.use("/api", Stock);
|
||||||
// Email CMS
|
// Email CMS
|
||||||
// app.use("/api", RegisterEmail);
|
// app.use("/api", RegisterEmail);
|
||||||
export default app;
|
export default app;
|
||||||
|
@ -2,7 +2,7 @@ import mongoose from "mongoose";
|
|||||||
import { PdOrder } from "./pdOrderModal.js";
|
import { PdOrder } from "./pdOrderModal.js";
|
||||||
import sendEmail from "../../Utils/sendEmail.js";
|
import sendEmail from "../../Utils/sendEmail.js";
|
||||||
import { Invoice } from "./invoiceModel.js";
|
import { Invoice } from "./invoiceModel.js";
|
||||||
|
import { PDStock } from "../Stock/PdStockModel.js";
|
||||||
// Controller for placing an order
|
// Controller for placing an order
|
||||||
export const createOrder = async (req, res) => {
|
export const createOrder = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
@ -731,7 +731,8 @@ export const getCancelledOrdersAdmin = async (req, res) => {
|
|||||||
.limit(limit)
|
.limit(limit)
|
||||||
.populate({ path: "orderItem.productId" })
|
.populate({ path: "orderItem.productId" })
|
||||||
.populate({ path: "invoices" })
|
.populate({ path: "invoices" })
|
||||||
.populate({ path: "addedBy" });
|
.populate({ path: "addedBy" })
|
||||||
|
.sort({ createdAt: -1 });
|
||||||
|
|
||||||
if (cancelledOrders.length > 0) {
|
if (cancelledOrders.length > 0) {
|
||||||
return res.status(200).json({ cancelledOrders, totalOrders });
|
return res.status(200).json({ cancelledOrders, totalOrders });
|
||||||
@ -815,13 +816,13 @@ export const getProcessingInvoices = async (req, res) => {
|
|||||||
query.invoiceId = { $regex: invoiceId, $options: "i" };
|
query.invoiceId = { $regex: invoiceId, $options: "i" };
|
||||||
}
|
}
|
||||||
const invoices = await Invoice.find(query)
|
const invoices = await Invoice.find(query)
|
||||||
.sort({ createdAt: -1 })
|
|
||||||
.skip(skip)
|
.skip(skip)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.populate({
|
.populate({
|
||||||
path: "orderId",
|
path: "orderId",
|
||||||
select: "uniqueId",
|
select: "uniqueId",
|
||||||
});
|
})
|
||||||
|
.sort({ "courierstatus_timeline.processing": -1 });
|
||||||
|
|
||||||
if (orderId) {
|
if (orderId) {
|
||||||
const filteredInvoices = invoices.filter(
|
const filteredInvoices = invoices.filter(
|
||||||
@ -1025,7 +1026,8 @@ export const getDispatchedInvoices = async (req, res) => {
|
|||||||
.populate({
|
.populate({
|
||||||
path: "orderId",
|
path: "orderId",
|
||||||
select: "uniqueId",
|
select: "uniqueId",
|
||||||
});
|
})
|
||||||
|
.sort({ "courierstatus_timeline.dispatched": -1 });
|
||||||
|
|
||||||
if (orderId) {
|
if (orderId) {
|
||||||
const filteredInvoices = invoices.filter(
|
const filteredInvoices = invoices.filter(
|
||||||
@ -1065,7 +1067,6 @@ export const updateCourierStatusToDelivered = async (req, res) => {
|
|||||||
select: "email",
|
select: "email",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!invoice) {
|
if (!invoice) {
|
||||||
return res.status(404).json({ error: "Invoice not found" });
|
return res.status(404).json({ error: "Invoice not found" });
|
||||||
}
|
}
|
||||||
@ -1086,7 +1087,44 @@ export const updateCourierStatusToDelivered = async (req, res) => {
|
|||||||
order.status = "delivered";
|
order.status = "delivered";
|
||||||
await order.save();
|
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
|
// Format the current date for display
|
||||||
const formattedDate = formatDate(new Date());
|
const formattedDate = formatDate(new Date());
|
||||||
|
|
||||||
@ -1212,7 +1250,8 @@ export const getDeliveredInvoices = async (req, res) => {
|
|||||||
.populate({
|
.populate({
|
||||||
path: "orderId",
|
path: "orderId",
|
||||||
select: "uniqueId",
|
select: "uniqueId",
|
||||||
});
|
})
|
||||||
|
.sort({ "courierstatus_timeline.delivered": -1 });
|
||||||
|
|
||||||
if (orderId) {
|
if (orderId) {
|
||||||
const filteredInvoices = invoices.filter(
|
const filteredInvoices = invoices.filter(
|
||||||
@ -1323,418 +1362,128 @@ export const getOrderCounts = async (req, res) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// no need
|
export const getAllOrdersByDistributor = async (req, res) => {
|
||||||
export const updateOrderStatusById = async (req, res) => {
|
const { distributorId } = req.params;
|
||||||
|
const { orderId, status } = req.query; // Added status to query parameters
|
||||||
|
// console.log(distributorId, orderId, status);
|
||||||
|
|
||||||
|
// Handle pagination parameters
|
||||||
|
const page = parseInt(req.query.page, 10) || 1;
|
||||||
|
const limit = parseInt(req.query.limit, 10) || 5;
|
||||||
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let body = { status: req.body.status };
|
let orders;
|
||||||
|
|
||||||
const currentDate = new Date();
|
// Search by orderId
|
||||||
body["status_timeline." + req.body.status] = currentDate;
|
if (orderId) {
|
||||||
|
const id = new RegExp(orderId, "i");
|
||||||
|
orders = await PdOrder.find({
|
||||||
|
addedBy: distributorId,
|
||||||
|
uniqueId: { $regex: id },
|
||||||
|
})
|
||||||
|
.sort({ createdAt: -1 })
|
||||||
|
.skip(skip)
|
||||||
|
.limit(limit);
|
||||||
|
|
||||||
const order = await PdOrder.findById(req.params.id).populate({
|
// console.log(orders);
|
||||||
path: "addedBy",
|
|
||||||
select: "name email _id",
|
// Return empty array if no orders are found
|
||||||
});
|
if (!orders || orders.length === 0) {
|
||||||
|
return res.status(200).json([]);
|
||||||
if (req.body.status === "cancelled") {
|
}
|
||||||
console.log("req came here ");
|
|
||||||
body["order_Cancelled_Reason"] = req.body?.ReasonforCancellation;
|
// Get total count for pagination
|
||||||
body["iscancelled"] = true;
|
const totalOrders = await PdOrder.countDocuments({
|
||||||
|
addedBy: distributorId,
|
||||||
const updatedCan = await PdOrder.findByIdAndUpdate(order._id, body);
|
status: { $regex: id },
|
||||||
|
|
||||||
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} Update: Cancellation and Refund Process`,
|
|
||||||
html: `
|
|
||||||
<strong style="color: #1b03a3; font-size: 16px"> Hi ${
|
|
||||||
order?.addedBy.name
|
|
||||||
},</strong>
|
|
||||||
<h3 style="color: #333; font-family: Arial, sans-serif;">We hope this message finds you well. We're writing to inform you that your order ${
|
|
||||||
order?.uniqueId
|
|
||||||
} has been canceled. We understand that circumstances may change, and we're here to assist you throughout the process.</h3>
|
|
||||||
|
|
||||||
<h4 style="color: #333; font-family: Arial, sans-serif;">Cancellation Reason: ${
|
|
||||||
order?.order_Cancelled_Reason || "No specific reason provided."
|
|
||||||
}</h4>
|
|
||||||
|
|
||||||
<h4 style="color: #333; font-family: Arial, sans-serif;">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;">Category</th>
|
|
||||||
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Brand</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>
|
|
||||||
${order?.orderItem
|
|
||||||
?.map(
|
|
||||||
(product, 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;">${
|
|
||||||
product.name
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
|
|
||||||
product.categoryName
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
|
|
||||||
product.brandName
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;"><img src="${
|
|
||||||
product?.image[0]?.url
|
|
||||||
}" alt="${
|
|
||||||
product.name
|
|
||||||
}" style="max-width: 40px; height: auto;"></td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
|
|
||||||
product.quantity
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
product.price
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
(product.GST * product.price) / 100
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
(product.price + (product.GST * product.price) / 100) *
|
|
||||||
product.quantity
|
|
||||||
}</td>
|
|
||||||
</tr>
|
|
||||||
`
|
|
||||||
)
|
|
||||||
.join("")}
|
|
||||||
<tr>
|
|
||||||
<th colspan="8" style="border: 1px solid #555; padding: 2px; text-align: right;">Total Amount :</th>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
order?.grandTotal
|
|
||||||
}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h4 style="color: #333; font-family: Arial, sans-serif;">Refund Information: The amount from your canceled order will be processed for a refund. Please allow up to 7 working days for the amount to be transferred back to your original payment method.</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. We appreciate your understanding and hope to serve you better in the future.</h5>
|
|
||||||
<br/>
|
|
||||||
<span style="color: #555; font-size: 13px;">Best regards,</span><br/>
|
|
||||||
<span style="color: #555; font-size: 13px;">Team Cheminova</span>
|
|
||||||
`,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Send response with pagination info
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
status: "ok",
|
totalOrders,
|
||||||
message: "Order status updated successfully!",
|
totalPages: Math.ceil(totalOrders / limit),
|
||||||
updatedCan,
|
currentPage: page,
|
||||||
|
orders,
|
||||||
});
|
});
|
||||||
} else if (req.body.status === "processing") {
|
}
|
||||||
const updatedPro = await PdOrder.findByIdAndUpdate(order._id, body);
|
|
||||||
await sendEmail({
|
|
||||||
to: `${order?.addedBy?.email}`, // Recipient's email address from order model
|
|
||||||
from: `${process.env.SEND_EMAIL_FROM}`, // Sender's email address
|
|
||||||
subject: `Your Order #${order?.uniqueId} is in Processing!`,
|
|
||||||
html: `
|
|
||||||
<div style="font-family: Arial, sans-serif; color: #333;">
|
|
||||||
<h3 style="color: #333;">Exciting news! Your order #${
|
|
||||||
order?.uniqueId
|
|
||||||
} has entered the processing phase. Our team is diligently preparing your items for dispatch. Rest assured, we're working hard to ensure everything is perfect for you.</h3>
|
|
||||||
<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>
|
|
||||||
|
|
||||||
|
// Search by status
|
||||||
|
else if (status) {
|
||||||
|
// Create a regex for case-insensitive search
|
||||||
|
const regex = new RegExp(status, "i");
|
||||||
|
|
||||||
|
orders = await PdOrder.find({
|
||||||
|
addedBy: distributorId,
|
||||||
|
status: { $regex: regex },
|
||||||
|
})
|
||||||
|
.sort({ createdAt: -1 })
|
||||||
|
.skip(skip)
|
||||||
|
.limit(limit);
|
||||||
|
|
||||||
<h4 style="color: #333;">Order Items:</h4>
|
// console.log(orders);
|
||||||
<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>
|
// Return empty array if no orders are found
|
||||||
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Quantity</th>
|
if (!orders || orders.length === 0) {
|
||||||
<th style="border: 1px solid #555; padding: 2px; text-align: center;">Price</th>
|
return res.status(200).json([]);
|
||||||
<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>
|
|
||||||
${order?.orderItem
|
|
||||||
?.map(
|
|
||||||
(product, 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;">${
|
|
||||||
product.name
|
|
||||||
}</td>
|
|
||||||
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">
|
// Get total count for pagination
|
||||||
<img src="${product.image[0]?.url}" alt="${
|
const totalOrders = await PdOrder.countDocuments({
|
||||||
product.name
|
addedBy: distributorId,
|
||||||
}" style="max-width: 40px; height: auto;">
|
status: { $regex: regex },
|
||||||
</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
|
|
||||||
product.quantity
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
product.price
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
(product.GST * product.price) / 100
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
(product.price + (product.GST * product.price) / 100) *
|
|
||||||
product.quantity
|
|
||||||
}</td>
|
|
||||||
</tr>
|
|
||||||
`
|
|
||||||
)
|
|
||||||
.join("")}
|
|
||||||
<tr>
|
|
||||||
<th colspan="7" style="border: 1px solid #555; padding: 2px; text-align: right;">Total Amount:</th>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
order?.grandTotal
|
|
||||||
}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h5 style="color: #333;">We'll send you another email with the tracking details as soon as your order is dispatched. If you have any questions or need assistance, feel free to reply to this email.</h5>
|
|
||||||
<h5 style="color: #333;">Thank you for choosing Cheminova!</h5>
|
|
||||||
<br/>
|
|
||||||
<span style="color: #555; font-size: 13px;">Best regards,</span><br/>
|
|
||||||
<span style="color: #555; font-size: 13px;">Team Cheminova</span>
|
|
||||||
</div>
|
|
||||||
`,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Send response with pagination info
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
status: "ok",
|
totalOrders,
|
||||||
message: "Order status updated successfully!",
|
totalPages: Math.ceil(totalOrders / limit),
|
||||||
updatedPro,
|
currentPage: page,
|
||||||
|
orders,
|
||||||
});
|
});
|
||||||
} else if (req.body.status === "dispatched") {
|
}
|
||||||
body["courier_name"] = req.body.courierName;
|
|
||||||
body["courier_tracking_id"] = req.body.TrackingID;
|
|
||||||
const disRes = await PdOrder.findByIdAndUpdate(order._id, body);
|
|
||||||
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: `
|
|
||||||
<strong style="color: #1b03a3; font-size: 16px">Hi,</strong>
|
|
||||||
<h3 style="color: #333; font-family: Arial, sans-serif;">Exciting news! Your order #${
|
|
||||||
order?.uniqueId
|
|
||||||
} has been dispatched and is en route to you. 🚚 Here are the details:</h3>
|
|
||||||
|
|
||||||
<h4 style="color: #333; font-family: Arial, sans-serif;">Courier Name: ${
|
// Default behavior to return all orders
|
||||||
order?.courier_name || "N/A"
|
else {
|
||||||
}</h4>
|
orders = await PdOrder.find({ addedBy: distributorId })
|
||||||
<h4 style="color: #333; font-family: Arial, sans-serif;">Courier Tracking ID: ${
|
.sort({ createdAt: -1 })
|
||||||
order?.courier_tracking_id || "N/A"
|
.skip(skip)
|
||||||
}</h4>
|
.limit(limit);
|
||||||
|
|
||||||
|
// Return empty array if no orders are found
|
||||||
|
if (!orders || orders.length === 0) {
|
||||||
|
return res.status(200).json([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get total count for pagination
|
||||||
<h4 style="color: #333; font-family: Arial, sans-serif;">Items:</h4>
|
const totalOrders = await PdOrder.countDocuments({
|
||||||
<table style="border-collapse: collapse; width: 100%;">
|
addedBy: distributorId,
|
||||||
<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;">SKU</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>
|
|
||||||
${order?.orderItem
|
|
||||||
?.map(
|
|
||||||
(product, 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;">${
|
|
||||||
product.name
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
|
|
||||||
product.SKU
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">
|
|
||||||
<img src="${product?.image[0]?.url}" alt="${
|
|
||||||
product.name
|
|
||||||
}" style="max-width: 40px; height: auto;">
|
|
||||||
</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
|
|
||||||
product.quantity
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
product.price
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
(product.GST * product.price) / 100
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
(product.price + (product.GST * product.price) / 100) *
|
|
||||||
product.quantity
|
|
||||||
}</td>
|
|
||||||
</tr>
|
|
||||||
`
|
|
||||||
)
|
|
||||||
.join("")}
|
|
||||||
<tr>
|
|
||||||
<th colspan="7" style="border: 1px solid #555; padding: 2px; text-align: right;">Total Amount:</th>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
order?.grandTotal
|
|
||||||
}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3 style="color: #333; font-family: Arial, sans-serif;">Order Status: Dispatched</h3>
|
|
||||||
<h4 style="color: #333; font-family: Arial, sans-serif;">If you have any questions or need assistance, feel free to reply to this email.</h4>
|
|
||||||
<h5 style="color: #333; font-family: Arial, sans-serif;">Thanks for choosing Cheminova! We hope you enjoy your purchase.</h5>
|
|
||||||
<br/>
|
|
||||||
<span style="color: #555; font-size: 13px;">Best regards,</span><br/>
|
|
||||||
<span style="color: #555; font-size: 13px;">Team Cheminova</span>
|
|
||||||
`,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Send response with pagination info
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
status: "ok",
|
totalOrders,
|
||||||
message: "Order status updated successfully!",
|
totalPages: Math.ceil(totalOrders / limit),
|
||||||
disRes,
|
currentPage: page,
|
||||||
|
orders,
|
||||||
});
|
});
|
||||||
} else if (req.body.status === "delivered") {
|
|
||||||
body["isDelivered"] = true;
|
|
||||||
body["DeliveredDate"] = req.body.DDate;
|
|
||||||
const formattedDate = formatDate(req.body.DDate);
|
|
||||||
console.log(formattedDate);
|
|
||||||
const updatedDeli = await PdOrder.findByIdAndUpdate(order._id, body);
|
|
||||||
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: `
|
|
||||||
<strong style="color: #1b03a3; font-size: 16px">Hi,</strong>
|
|
||||||
<h3 style="color: #333; font-family: Arial, sans-serif;">
|
|
||||||
Great news! Your order #${
|
|
||||||
order?.uniqueId
|
|
||||||
} has been successfully delivered to your doorstep. We hope everything is just as you expected!
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h4 style="color: #333; font-family: Arial, sans-serif;">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;">SKU</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>
|
|
||||||
${order?.orderItem
|
|
||||||
?.map(
|
|
||||||
(product, 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;">${
|
|
||||||
product.name
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
|
|
||||||
product.SKU
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">
|
|
||||||
<img src="${product?.image[0]?.url}" alt="${
|
|
||||||
product.name
|
|
||||||
}" style="max-width: 40px; height: auto;">
|
|
||||||
</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">${
|
|
||||||
product.quantity
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
product.price
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
(product.GST * product.price) / 100
|
|
||||||
}</td>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
(product.price + (product.GST * product.price) / 100) *
|
|
||||||
product.quantity
|
|
||||||
}</td>
|
|
||||||
</tr>
|
|
||||||
`
|
|
||||||
)
|
|
||||||
.join("")}
|
|
||||||
<tr>
|
|
||||||
<th colspan="7" style="border: 1px solid #555; padding: 2px; text-align: right;">Total Amount:</th>
|
|
||||||
<td style="border: 1px solid #555; padding: 2px; text-align: center;">₹${
|
|
||||||
order?.grandTotal
|
|
||||||
}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3 style="color: #333; font-family: Arial, sans-serif;">Delivery Date: ${formattedDate}</h3>
|
|
||||||
|
|
||||||
<h4 style="color: #333; font-family: Arial, sans-serif;">
|
|
||||||
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!
|
|
||||||
</h4>
|
|
||||||
|
|
||||||
<h5 style="color: #333; font-family: Arial, sans-serif;">
|
|
||||||
If you have any questions or concerns about your order, feel free to reply to this email.
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
<h5 style="color: #333; font-family: Arial, sans-serif;">
|
|
||||||
Thank you for choosing Cheminova! We hope to serve you again soon.
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
<span style="color: #555; font-size: 13px;">Best regards,</span><br/>
|
|
||||||
<span style="color: #555; font-size: 13px;">Team Cheminova</span>
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
return res.status(200).json({
|
|
||||||
status: "ok",
|
|
||||||
message: "Order status updated successfully!",
|
|
||||||
updatedDeli,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// await Order.findByIdAndUpdate(order._id, body);
|
|
||||||
// console.log(order);
|
|
||||||
res
|
|
||||||
.status(200)
|
|
||||||
.json({ status: "ok", message: "Order status updated successfully!" });
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.error("Error fetching orders:", error);
|
||||||
res
|
res.status(500).json({ message: "Server error", error });
|
||||||
.status(500)
|
}
|
||||||
.json({ message: error?.message || "Something went wrong!" });
|
};
|
||||||
|
|
||||||
|
export const gettotalorderandvalueofpd = async (req, res) => {
|
||||||
|
const { distributorId } = req.params;
|
||||||
|
try {
|
||||||
|
const orders = await PdOrder.find({ addedBy: distributorId });
|
||||||
|
const totalOrders = orders.length;
|
||||||
|
const totalValue = orders.reduce((acc, order) => acc + order.grandTotal, 0);
|
||||||
|
|
||||||
|
res.status(200).json({ totalOrders, totalValue });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching orders:", error);
|
||||||
|
res.status(500).json({ message: "Server error", error });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,6 @@ import {
|
|||||||
getPlacedOrder,
|
getPlacedOrder,
|
||||||
getPlacedOrderById,
|
getPlacedOrderById,
|
||||||
getProcessingOrdersAdmin,
|
getProcessingOrdersAdmin,
|
||||||
updateOrderStatusById,
|
|
||||||
processOrder,
|
processOrder,
|
||||||
cancelOrderController,
|
cancelOrderController,
|
||||||
getPlacedPendingOrderAdmin,
|
getPlacedPendingOrderAdmin,
|
||||||
@ -20,6 +19,8 @@ import {
|
|||||||
getDeliveredInvoices,
|
getDeliveredInvoices,
|
||||||
getDispatchedInvoices,
|
getDispatchedInvoices,
|
||||||
updateCourierStatusToDelivered,
|
updateCourierStatusToDelivered,
|
||||||
|
getAllOrdersByDistributor,
|
||||||
|
gettotalorderandvalueofpd,
|
||||||
} from "./pdOrderController.js";
|
} from "./pdOrderController.js";
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
@ -98,9 +99,11 @@ router
|
|||||||
updateCourierStatusToDelivered
|
updateCourierStatusToDelivered
|
||||||
);
|
);
|
||||||
router
|
router
|
||||||
.route("/change/status/:id")
|
.route("/single-pd-order/:distributorId")
|
||||||
.patch(isAuthenticatedUser, authorizeRoles("admin"), updateOrderStatusById);
|
.get(isAuthenticatedUser, authorizeRoles("admin"), getAllOrdersByDistributor);
|
||||||
|
router
|
||||||
|
.route("/single-pd-ordercount/:distributorId")
|
||||||
|
.get(isAuthenticatedUser, authorizeRoles("admin"), gettotalorderandvalueofpd);
|
||||||
router.route("/get-counts-pdOrders").get(isAuthenticatedUser, getOrderCounts);
|
router.route("/get-counts-pdOrders").get(isAuthenticatedUser, getOrderCounts);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
103
resources/Stock/PdStockController.js
Normal file
103
resources/Stock/PdStockController.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import mongoose from "mongoose";
|
||||||
|
import { PDStock } from "./PdStockModel.js";
|
||||||
|
import { Product } from "../Products/ProductModel.js";
|
||||||
|
|
||||||
|
export const getProductsAndStockByUser = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { userId } = req.params;
|
||||||
|
|
||||||
|
// Pagination parameters
|
||||||
|
const PAGE_SIZE = parseInt(req.query.show) || 10;
|
||||||
|
const page = parseInt(req.query.page) || 1;
|
||||||
|
const skip = (page - 1) * PAGE_SIZE;
|
||||||
|
|
||||||
|
// Filtering criteria
|
||||||
|
const filter = {};
|
||||||
|
if (req.query.name) {
|
||||||
|
filter.name = {
|
||||||
|
$regex: new RegExp(req.query.name, "i"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (req.query.category) {
|
||||||
|
filter.category = mongoose.Types.ObjectId(req.query.category);
|
||||||
|
}
|
||||||
|
if (req.query.brand) {
|
||||||
|
filter.brand = mongoose.Types.ObjectId(req.query.brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch user's PDStock data and products concurrently
|
||||||
|
const [userStock, products] = await Promise.all([
|
||||||
|
PDStock.findOne({ userId: mongoose.Types.ObjectId(userId) }),
|
||||||
|
Product.aggregate([
|
||||||
|
{ $match: filter },
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: "categorymodels",
|
||||||
|
localField: "category",
|
||||||
|
foreignField: "_id",
|
||||||
|
as: "categoryDetails",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: "brandmodels",
|
||||||
|
localField: "brand",
|
||||||
|
foreignField: "_id",
|
||||||
|
as: "brandDetails",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$project: {
|
||||||
|
category: { $arrayElemAt: ["$categoryDetails.categoryName", 0] },
|
||||||
|
brand: { $arrayElemAt: ["$brandDetails.brandName", 0] },
|
||||||
|
GST: 1,
|
||||||
|
HSN_Code: 1,
|
||||||
|
SKU: 1,
|
||||||
|
addedBy: 1,
|
||||||
|
createdAt: 1,
|
||||||
|
description: 1,
|
||||||
|
image: 1,
|
||||||
|
name: 1,
|
||||||
|
price: 1,
|
||||||
|
product_Status: 1,
|
||||||
|
updatedAt: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ $skip: skip },
|
||||||
|
{ $limit: PAGE_SIZE },
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create a stock map for easy lookup
|
||||||
|
const stockMap = {};
|
||||||
|
if (userStock && userStock.products) {
|
||||||
|
userStock.products.forEach((product) => {
|
||||||
|
stockMap[product.productid.toString()] = product.Stock;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine products with their respective stock
|
||||||
|
const productsWithStock = products.map((product) => ({
|
||||||
|
...product,
|
||||||
|
stock: stockMap[product._id.toString()] || 0,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Get total count for pagination purposes
|
||||||
|
const total = await Product.countDocuments(filter);
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
totalProducts: total,
|
||||||
|
totalPages: Math.ceil(total / PAGE_SIZE),
|
||||||
|
currentPage: page,
|
||||||
|
products: productsWithStock,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching products with stock:", error);
|
||||||
|
return res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: "Error fetching products and stock",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
26
resources/Stock/PdStockModel.js
Normal file
26
resources/Stock/PdStockModel.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
|
// Define Product record schema
|
||||||
|
const ProductRecordSchema = new mongoose.Schema({
|
||||||
|
productid: {
|
||||||
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
|
ref: 'Product',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
Stock: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define main Stock schema
|
||||||
|
const StockSchema = new mongoose.Schema({
|
||||||
|
userId: {
|
||||||
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
|
refPath: 'User',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
products: [ProductRecordSchema],
|
||||||
|
}, { timestamps: true, versionKey: false });
|
||||||
|
|
||||||
|
export const PDStock = mongoose.model('PDStock', StockSchema);
|
12
resources/Stock/PdStockRoute.js
Normal file
12
resources/Stock/PdStockRoute.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import express from "express";
|
||||||
|
import { getProductsAndStockByUser } from "./PdStockController.js";
|
||||||
|
import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
"/pd/stock/:userId",
|
||||||
|
isAuthenticatedUser,
|
||||||
|
authorizeRoles("admin"),
|
||||||
|
getProductsAndStockByUser
|
||||||
|
);
|
||||||
|
export default router;
|
@ -15,6 +15,7 @@ import path from "path";
|
|||||||
import validator from "validator";
|
import validator from "validator";
|
||||||
import ShippingAddress from "../ShippingAddresses/ShippingAddressModel.js";
|
import ShippingAddress from "../ShippingAddresses/ShippingAddressModel.js";
|
||||||
import { generatePassword } from "../../Utils/generatepassword.js";
|
import { generatePassword } from "../../Utils/generatepassword.js";
|
||||||
|
import { PdOrder } from "../PD_Orders/pdOrderModal.js";
|
||||||
// const generatePassword = (name, email) => {
|
// const generatePassword = (name, email) => {
|
||||||
// // Combine name and email, and convert to lowercase
|
// // Combine name and email, and convert to lowercase
|
||||||
// const combinedStr = (name + email).toLowerCase();
|
// const combinedStr = (name + email).toLowerCase();
|
||||||
@ -997,43 +998,33 @@ export const updateProfile = catchAsyncErrors(async (req, res, next) => {
|
|||||||
// 9.Get all users(admin)
|
// 9.Get all users(admin)
|
||||||
export const getAllUser = catchAsyncErrors(async (req, res, next) => {
|
export const getAllUser = catchAsyncErrors(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
// Extract query parameters
|
|
||||||
const { page = 1, show = 10, name, mobileNumber, SBU } = req.query;
|
const { page = 1, show = 10, name, mobileNumber, SBU } = req.query;
|
||||||
|
|
||||||
// Create a filter object
|
|
||||||
const filter = { role: "principal-Distributor" };
|
const filter = { role: "principal-Distributor" };
|
||||||
|
|
||||||
// Add case-insensitive name search
|
|
||||||
if (name) {
|
if (name) {
|
||||||
filter.name = { $regex: name, $options: "i" }; // Case-insensitive regex search
|
filter.name = { $regex: name, $options: "i" };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add mobileNumber search
|
|
||||||
if (mobileNumber) {
|
if (mobileNumber) {
|
||||||
filter.phone = mobileNumber;
|
filter.phone = mobileNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add SBU filter if provided
|
|
||||||
if (SBU) {
|
if (SBU) {
|
||||||
filter.SBU = { $regex: SBU, $options: "i" }; // Case-insensitive regex search for SBU
|
filter.SBU = { $regex: SBU, $options: "i" };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate pagination values
|
|
||||||
const limit = parseInt(show, 10);
|
const limit = parseInt(show, 10);
|
||||||
const skip = (parseInt(page, 10) - 1) * limit;
|
const skip = (parseInt(page, 10) - 1) * limit;
|
||||||
|
|
||||||
// Find users with the filter, pagination, and sorting
|
|
||||||
const users = await User.find(filter)
|
const users = await User.find(filter)
|
||||||
.populate("mappedby", "name")
|
.populate("mappedby", "name")
|
||||||
.populate("mappedbySC", "name")
|
.populate("mappedbySC", "name")
|
||||||
.sort({ createdAt: -1 })
|
.sort({ createdAt: -1 })
|
||||||
.skip(skip)
|
.skip(skip)
|
||||||
.limit(limit);
|
.limit(limit);
|
||||||
|
|
||||||
// Count total users matching the filter
|
|
||||||
const totalUsers = await User.countDocuments(filter);
|
const totalUsers = await User.countDocuments(filter);
|
||||||
|
|
||||||
// Respond with users and pagination info
|
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
success: true,
|
success: true,
|
||||||
users,
|
users,
|
||||||
@ -1041,12 +1032,75 @@ export const getAllUser = catchAsyncErrors(async (req, res, next) => {
|
|||||||
total_pages: Math.ceil(totalUsers / limit),
|
total_pages: Math.ceil(totalUsers / limit),
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Handle errors
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
res.status(500).json({ message: "Server Error", error });
|
res.status(500).json({ message: "Server Error", error });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
export const getAllPD = catchAsyncErrors(async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const { page = 1, show = 10, name, mobileNumber, SBU } = req.query;
|
||||||
|
|
||||||
|
const filter = { role: "principal-Distributor" };
|
||||||
|
|
||||||
|
if (name) {
|
||||||
|
filter.name = { $regex: name, $options: "i" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mobileNumber) {
|
||||||
|
filter.phone = mobileNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SBU) {
|
||||||
|
filter.SBU = { $regex: SBU, $options: "i" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const limit = parseInt(show, 10);
|
||||||
|
const skip = (parseInt(page, 10) - 1) * limit;
|
||||||
|
|
||||||
|
// Fetch users with the given filter and pagination
|
||||||
|
const users = await User.find(filter)
|
||||||
|
.populate("mappedby", "name")
|
||||||
|
.populate("mappedbySC", "name")
|
||||||
|
.sort({ createdAt: -1 })
|
||||||
|
.skip(skip)
|
||||||
|
.limit(limit);
|
||||||
|
|
||||||
|
// Fetch total count of users matching the filter
|
||||||
|
const totalUsers = await User.countDocuments(filter);
|
||||||
|
|
||||||
|
// Aggregate orders data for each user
|
||||||
|
const orderStats = await PdOrder.aggregate([
|
||||||
|
{ $match: { addedBy: { $in: users.map(user => user._id) } } }, // Match orders for the listed distributors
|
||||||
|
{
|
||||||
|
$group: {
|
||||||
|
_id: "$addedBy", // Group by addedBy (distributor ID)
|
||||||
|
totalOrders: { $sum: 1 }, // Calculate total number of orders
|
||||||
|
lastOrderDate: { $max: "$createdAt" }, // Get the date of the last order
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Map orders data to corresponding users
|
||||||
|
const usersWithOrderStats = users.map(user => {
|
||||||
|
const orderData = orderStats.find(order => order._id.toString() === user._id.toString());
|
||||||
|
return {
|
||||||
|
...user.toObject(),
|
||||||
|
totalOrders: orderData ? orderData.totalOrders : 0,
|
||||||
|
lastOrderDate: orderData ? orderData.lastOrderDate : null,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
users: usersWithOrderStats,
|
||||||
|
total_data: totalUsers,
|
||||||
|
total_pages: Math.ceil(totalUsers / limit),
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching Principal Distributors:', error);
|
||||||
|
res.status(500).json({ message: "Server Error", error });
|
||||||
|
}
|
||||||
|
});
|
||||||
export const getAllPrincipalDistributorbytmId = catchAsyncErrors(
|
export const getAllPrincipalDistributorbytmId = catchAsyncErrors(
|
||||||
async (req, res, next) => {
|
async (req, res, next) => {
|
||||||
const { page = 1, show = 10, name, mobileNumber } = req.query;
|
const { page = 1, show = 10, name, mobileNumber } = req.query;
|
||||||
|
@ -22,6 +22,7 @@ import {
|
|||||||
mappedbySC,
|
mappedbySC,
|
||||||
getAllPrincipalDistributorbyscId,
|
getAllPrincipalDistributorbyscId,
|
||||||
saveFCMTokenForUser,
|
saveFCMTokenForUser,
|
||||||
|
getAllPD,
|
||||||
} from "./userController.js";
|
} from "./userController.js";
|
||||||
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
|
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
|
||||||
|
|
||||||
@ -48,7 +49,10 @@ router
|
|||||||
//mapping start
|
//mapping start
|
||||||
router
|
router
|
||||||
.route("/admin/users")
|
.route("/admin/users")
|
||||||
.get(isAuthenticatedUser, authorizeRoles("admin", "Employee"), getAllUser);
|
.get(isAuthenticatedUser, authorizeRoles("admin"), getAllUser);
|
||||||
|
router
|
||||||
|
.route("/admin/pd")
|
||||||
|
.get(isAuthenticatedUser, authorizeRoles("admin"), getAllPD);
|
||||||
router
|
router
|
||||||
.route("/getbyTmId/:id")
|
.route("/getbyTmId/:id")
|
||||||
.get(
|
.get(
|
||||||
|
Loading…
Reference in New Issue
Block a user