download report and task show
This commit is contained in:
parent
26a924efbb
commit
6ab315c247
@ -16,6 +16,7 @@ import {
|
|||||||
updateunmapRD,
|
updateunmapRD,
|
||||||
uploadRetaildistributors,
|
uploadRetaildistributors,
|
||||||
updateretaildistributorwithKYC,
|
updateretaildistributorwithKYC,
|
||||||
|
generateRetailerReport,
|
||||||
} from "./RetailDistributorController.js";
|
} from "./RetailDistributorController.js";
|
||||||
import { isAuthenticatedRD } from "../../middlewares/rdAuth.js";
|
import { isAuthenticatedRD } from "../../middlewares/rdAuth.js";
|
||||||
import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js";
|
import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js";
|
||||||
@ -25,6 +26,9 @@ const router = express.Router();
|
|||||||
router
|
router
|
||||||
.route("/retaildistributor/upload")
|
.route("/retaildistributor/upload")
|
||||||
.post(isAuthenticatedUser, authorizeRoles("admin"), uploadRetaildistributors);
|
.post(isAuthenticatedUser, authorizeRoles("admin"), uploadRetaildistributors);
|
||||||
|
router
|
||||||
|
.route("/retaildistributor/download-report")
|
||||||
|
.get(isAuthenticatedUser, authorizeRoles("admin"), generateRetailerReport);
|
||||||
router.route("/rd-login").post(loginRD);
|
router.route("/rd-login").post(loginRD);
|
||||||
router.route("/rd-get-me").get(isAuthenticatedRD, getmyProfileRD);
|
router.route("/rd-get-me").get(isAuthenticatedRD, getmyProfileRD);
|
||||||
router.post("/forgot-password", forgotPasswordRD);
|
router.post("/forgot-password", forgotPasswordRD);
|
||||||
|
@ -1843,3 +1843,105 @@ export const saveFCMTokenForRD = async (req, res) => {
|
|||||||
res.status(500).send("Internal Server Error");
|
res.status(500).send("Internal Server Error");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const generateRetailerReport = async (req, res) => {
|
||||||
|
try {
|
||||||
|
// Fetch retailer data and populate required fields
|
||||||
|
const retailers = await RetailDistributor.find()
|
||||||
|
.populate("kyc", "trade_name pan_number aadhar_number gst_number state city district address pincode")
|
||||||
|
.populate("principal_distributer", "name")
|
||||||
|
.populate("mappedTM", "name")
|
||||||
|
.populate("mappedSC", "name")
|
||||||
|
.select("uniqueId name email mobile_number");
|
||||||
|
|
||||||
|
if (!retailers.length) {
|
||||||
|
return res.status(404).json({ message: "No retailers found." });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare data for the sheet
|
||||||
|
const retailerData = retailers.map((retailer) => ({
|
||||||
|
"Retailer ID": retailer.uniqueId,
|
||||||
|
"Retailer Name": retailer.name,
|
||||||
|
Email: retailer.email,
|
||||||
|
"Mobile Number": retailer.mobile_number,
|
||||||
|
"Trade Name": retailer.kyc?.trade_name || "",
|
||||||
|
"PAN Number": retailer.kyc?.pan_number || "",
|
||||||
|
"Aadhaar Number": retailer.kyc?.aadhar_number || "",
|
||||||
|
"GST Number": retailer.kyc?.gst_number || "",
|
||||||
|
State: retailer.kyc?.state || "",
|
||||||
|
City: retailer.kyc?.city || "",
|
||||||
|
District: retailer.kyc?.district || "",
|
||||||
|
Address: retailer.kyc?.address || "",
|
||||||
|
Pincode: retailer.kyc?.pincode || "",
|
||||||
|
PrincipalDistributor: retailer.principal_distributer?.name || "N/A",
|
||||||
|
TerritoryManager: retailer.mappedTM?.name || "N/A",
|
||||||
|
SalesCoordinator: retailer.mappedSC?.name || "N/A",
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Define headers for the worksheet
|
||||||
|
const headers = [
|
||||||
|
[
|
||||||
|
"Retailer ID",
|
||||||
|
"Retailer Name",
|
||||||
|
"Email",
|
||||||
|
"Mobile Number",
|
||||||
|
"Trade Name",
|
||||||
|
"PAN Number",
|
||||||
|
"Aadhaar Number",
|
||||||
|
"GST Number",
|
||||||
|
"State",
|
||||||
|
"City",
|
||||||
|
"District",
|
||||||
|
"Address",
|
||||||
|
"Pincode",
|
||||||
|
"Principal Distributor",
|
||||||
|
"Territory Manager",
|
||||||
|
"Sales Coordinator",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create worksheet with headers
|
||||||
|
const worksheet = XLSX.utils.aoa_to_sheet(headers);
|
||||||
|
|
||||||
|
// Append retailer data below headers
|
||||||
|
XLSX.utils.sheet_add_json(worksheet, retailerData, {
|
||||||
|
skipHeader: true,
|
||||||
|
origin: "A2",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set column widths based on content length
|
||||||
|
const columnWidths = headers[0].map((header, index) => {
|
||||||
|
let maxLength = header.length;
|
||||||
|
for (const row of retailerData) {
|
||||||
|
const cellContent = row[header]?.toString() || "";
|
||||||
|
maxLength = Math.max(maxLength, cellContent.length);
|
||||||
|
}
|
||||||
|
return { wch: maxLength + 2 };
|
||||||
|
});
|
||||||
|
worksheet["!cols"] = columnWidths;
|
||||||
|
|
||||||
|
// Create workbook and append worksheet
|
||||||
|
const workbook = XLSX.utils.book_new();
|
||||||
|
XLSX.utils.book_append_sheet(workbook, worksheet, "RetailerReport");
|
||||||
|
|
||||||
|
// Write workbook to a buffer
|
||||||
|
const excelBuffer = XLSX.write(workbook, {
|
||||||
|
bookType: "xlsx",
|
||||||
|
type: "buffer",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send Excel file as response
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Type",
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||||
|
);
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Disposition",
|
||||||
|
"attachment; filename=RetailerReport.xlsx"
|
||||||
|
);
|
||||||
|
res.send(excelBuffer);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error generating retailer report:", error);
|
||||||
|
res.status(500).json({ message: "Failed to generate report" });
|
||||||
|
}
|
||||||
|
};
|
@ -385,7 +385,7 @@ export const getTodaysTasks = async (req, res) => {
|
|||||||
|
|
||||||
// Find tasks that are due today, with pagination
|
// Find tasks that are due today, with pagination
|
||||||
const tasks = await Task.find({
|
const tasks = await Task.find({
|
||||||
taskDueDate: {
|
createdAt: {
|
||||||
$gte: startOfToday,
|
$gte: startOfToday,
|
||||||
$lte: endOfToday,
|
$lte: endOfToday,
|
||||||
},
|
},
|
||||||
@ -395,7 +395,7 @@ export const getTodaysTasks = async (req, res) => {
|
|||||||
.skip(skip) // Skip documents for pagination
|
.skip(skip) // Skip documents for pagination
|
||||||
.limit(itemsPerPage) // Limit the number of documents
|
.limit(itemsPerPage) // Limit the number of documents
|
||||||
.exec();
|
.exec();
|
||||||
|
// console.log(tasks);
|
||||||
// Populate addedForId conditionally
|
// Populate addedForId conditionally
|
||||||
const populatedTasks = await Promise.all(
|
const populatedTasks = await Promise.all(
|
||||||
tasks.map(async (task) => {
|
tasks.map(async (task) => {
|
||||||
@ -434,3 +434,127 @@ export const getTodaysTasks = async (req, res) => {
|
|||||||
res.status(500).json({ message: "Failed to retrieve tasks for today" });
|
res.status(500).json({ message: "Failed to retrieve tasks for today" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getTasks = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
page = 1,
|
||||||
|
show = 10,
|
||||||
|
startDate = "",
|
||||||
|
endDate = "",
|
||||||
|
TMname = "",
|
||||||
|
SCname = "",
|
||||||
|
status = "",
|
||||||
|
} = req.query;
|
||||||
|
|
||||||
|
const limit = parseInt(show);
|
||||||
|
const skip = (parseInt(page) - 1) * limit;
|
||||||
|
|
||||||
|
const matchStage = {};
|
||||||
|
|
||||||
|
// Filter by date range
|
||||||
|
if (startDate && endDate) {
|
||||||
|
const start = new Date(startDate);
|
||||||
|
const end = new Date(endDate);
|
||||||
|
if (start.toDateString() === end.toDateString()) {
|
||||||
|
matchStage.createdAt = {
|
||||||
|
$gte: start,
|
||||||
|
$lt: new Date(start).setDate(start.getDate() + 1),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
matchStage.createdAt = {
|
||||||
|
$gte: start,
|
||||||
|
$lte: new Date(end).setDate(end.getDate() + 1),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// matchStage.createdAt = {
|
||||||
|
// $gte: start,
|
||||||
|
// $lte: new Date(end.setDate(end.getDate() + 1)),
|
||||||
|
// };
|
||||||
|
} else if (startDate && endDate === "") {
|
||||||
|
matchStage.createdAt = {
|
||||||
|
$gte: new Date(startDate),
|
||||||
|
$lte: new Date(),
|
||||||
|
};
|
||||||
|
} else if (endDate && startDate === "") {
|
||||||
|
matchStage.createdAt = {
|
||||||
|
$lte: new Date(endDate),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter by task status
|
||||||
|
if (status) {
|
||||||
|
matchStage.taskStatus = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregation pipeline
|
||||||
|
const tasks = await Task.aggregate([
|
||||||
|
{ $match: matchStage },
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: "territorymanagers",
|
||||||
|
localField: "taskAssignedBy",
|
||||||
|
foreignField: "_id",
|
||||||
|
as: "taskAssignedBy",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: "salescoordinators",
|
||||||
|
localField: "taskAssignedTo",
|
||||||
|
foreignField: "_id",
|
||||||
|
as: "taskAssignedTo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$match: {
|
||||||
|
...(TMname && {
|
||||||
|
"taskAssignedBy.name": { $regex: TMname, $options: "i" },
|
||||||
|
}),
|
||||||
|
...(SCname && {
|
||||||
|
"taskAssignedTo.name": { $regex: SCname, $options: "i" },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ $unwind: "$taskAssignedBy" },
|
||||||
|
{ $unwind: "$taskAssignedTo" },
|
||||||
|
{ $sort: { createdAt: -1 } },
|
||||||
|
{ $skip: skip },
|
||||||
|
{ $limit: limit },
|
||||||
|
{
|
||||||
|
$project: {
|
||||||
|
taskId: 1,
|
||||||
|
task: 1,
|
||||||
|
taskStatus: 1,
|
||||||
|
taskPriority: 1,
|
||||||
|
taskDueDate: 1,
|
||||||
|
note: 1,
|
||||||
|
createdAt: 1,
|
||||||
|
"taskAssignedBy.name": 1,
|
||||||
|
"taskAssignedTo.name": 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Total count
|
||||||
|
const totalTasks = await Task.countDocuments(matchStage);
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: tasks,
|
||||||
|
pagination: {
|
||||||
|
total: totalTasks,
|
||||||
|
page: parseInt(page),
|
||||||
|
show: limit,
|
||||||
|
pages: Math.ceil(totalTasks / limit),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching tasks:", error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: "Server error while fetching tasks",
|
||||||
|
error: error.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -7,6 +7,7 @@ import {
|
|||||||
getAllTasksByStatus,
|
getAllTasksByStatus,
|
||||||
getTasksByDates,
|
getTasksByDates,
|
||||||
getTodaysTasks,
|
getTodaysTasks,
|
||||||
|
getTasks,
|
||||||
} from "./TaskController.js";
|
} from "./TaskController.js";
|
||||||
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
|
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
|
||||||
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
|
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
|
||||||
@ -38,4 +39,10 @@ router.get(
|
|||||||
authorizeRoles("admin"),
|
authorizeRoles("admin"),
|
||||||
getTodaysTasks
|
getTodaysTasks
|
||||||
);
|
);
|
||||||
|
router.get(
|
||||||
|
"/tasks",
|
||||||
|
isAuthenticatedUser,
|
||||||
|
authorizeRoles("admin"),
|
||||||
|
getTasks
|
||||||
|
);
|
||||||
export default router;
|
export default router;
|
||||||
|
@ -1149,3 +1149,132 @@ export const saveFCMTokenForUser = async (req, res) => {
|
|||||||
res.status(500).send("Internal Server Error");
|
res.status(500).send("Internal Server Error");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const generatePrincipalDistributorReport = async (req, res) => {
|
||||||
|
try {
|
||||||
|
// Fetch users with role 'principal-distributor'
|
||||||
|
const distributors = await User.find({ role: "principal-Distributor" })
|
||||||
|
.select("uniqueId SBU name email phone")
|
||||||
|
.populate("mappedby", "name") // Territory Manager
|
||||||
|
.populate("mappedbySC", "name") // Sales Coordinator
|
||||||
|
.lean();
|
||||||
|
if (!distributors.length) {
|
||||||
|
return res
|
||||||
|
.status(404)
|
||||||
|
.json({ message: "No principal distributors found." });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare data for the sheet
|
||||||
|
const distributorData = [];
|
||||||
|
|
||||||
|
for (const distributor of distributors) {
|
||||||
|
// Fetch shipping addresses associated with the distributor (both default and non-default)
|
||||||
|
const addresses = await ShippingAddress.find({
|
||||||
|
user: distributor._id,
|
||||||
|
}).lean();
|
||||||
|
|
||||||
|
// Determine the address to use (first default or first address if none default)
|
||||||
|
let selectedAddress = null;
|
||||||
|
|
||||||
|
// Find the first default address, otherwise use the first address
|
||||||
|
const defaultAddress = addresses.find(
|
||||||
|
(address) => address.isDefault === true
|
||||||
|
);
|
||||||
|
if (defaultAddress) {
|
||||||
|
selectedAddress = defaultAddress;
|
||||||
|
} else {
|
||||||
|
selectedAddress = addresses[0]; // If no default, take the first address
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a valid address, proceed with adding it to the report
|
||||||
|
if (selectedAddress) {
|
||||||
|
const addressDetails = {
|
||||||
|
"Unique ID": distributor.uniqueId,
|
||||||
|
SBU: distributor.SBU,
|
||||||
|
"Principal Distributor Name": distributor.name,
|
||||||
|
Email: distributor.email,
|
||||||
|
"Mobile Number": distributor.phone,
|
||||||
|
"Trade Name": selectedAddress.tradeName || "N/A",
|
||||||
|
"PAN Number": selectedAddress.panNumber || "N/A",
|
||||||
|
"GST Number": selectedAddress.gstNumber || "N/A",
|
||||||
|
State: selectedAddress.state || "N/A",
|
||||||
|
City: selectedAddress.city || "N/A",
|
||||||
|
Street: selectedAddress.street || "N/A",
|
||||||
|
Pincode: selectedAddress.postalCode || "N/A",
|
||||||
|
"Territory Manager": distributor.mappedby?.name || "N/A",
|
||||||
|
"Sales Coordinator": distributor.mappedbySC?.name || "N/A",
|
||||||
|
};
|
||||||
|
|
||||||
|
distributorData.push(addressDetails);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define headers for the worksheet
|
||||||
|
const headers = [
|
||||||
|
[
|
||||||
|
"Unique ID",
|
||||||
|
"SBU",
|
||||||
|
"Principal Distributor Name",
|
||||||
|
"Email",
|
||||||
|
"Mobile Number",
|
||||||
|
"Trade Name",
|
||||||
|
"PAN Number",
|
||||||
|
"GST Number",
|
||||||
|
"State",
|
||||||
|
"City",
|
||||||
|
"Street",
|
||||||
|
"Pincode",
|
||||||
|
"Territory Manager",
|
||||||
|
"Sales Coordinator",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create worksheet with headers
|
||||||
|
const worksheet = XLSX.utils.aoa_to_sheet(headers);
|
||||||
|
|
||||||
|
// Append distributor data below headers
|
||||||
|
XLSX.utils.sheet_add_json(worksheet, distributorData, {
|
||||||
|
skipHeader: true,
|
||||||
|
origin: "A2",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set column widths based on content length
|
||||||
|
const columnWidths = headers[0].map((header, index) => {
|
||||||
|
let maxLength = header.length;
|
||||||
|
for (const row of distributorData) {
|
||||||
|
const cellContent = row[header]?.toString() || "";
|
||||||
|
maxLength = Math.max(maxLength, cellContent.length);
|
||||||
|
}
|
||||||
|
return { wch: maxLength + 2 };
|
||||||
|
});
|
||||||
|
worksheet["!cols"] = columnWidths;
|
||||||
|
|
||||||
|
// Create workbook and append worksheet
|
||||||
|
const workbook = XLSX.utils.book_new();
|
||||||
|
XLSX.utils.book_append_sheet(
|
||||||
|
workbook,
|
||||||
|
worksheet,
|
||||||
|
"Principal_Distributor_Report"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Write workbook to a buffer
|
||||||
|
const excelBuffer = XLSX.write(workbook, {
|
||||||
|
bookType: "xlsx",
|
||||||
|
type: "buffer",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send Excel file as response
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Type",
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||||
|
);
|
||||||
|
res.setHeader(
|
||||||
|
"Content-Disposition",
|
||||||
|
"attachment; filename=Principal_Distributor_Report.xlsx"
|
||||||
|
);
|
||||||
|
res.send(excelBuffer);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error generating report:", error);
|
||||||
|
res.status(500).json({ message: "Failed to generate report" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -23,6 +23,7 @@ import {
|
|||||||
getAllPrincipalDistributorbyscId,
|
getAllPrincipalDistributorbyscId,
|
||||||
saveFCMTokenForUser,
|
saveFCMTokenForUser,
|
||||||
getAllPD,
|
getAllPD,
|
||||||
|
generatePrincipalDistributorReport,
|
||||||
} from "./userController.js";
|
} from "./userController.js";
|
||||||
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
|
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
|
||||||
|
|
||||||
@ -46,6 +47,13 @@ router
|
|||||||
authorizeRoles("admin"),
|
authorizeRoles("admin"),
|
||||||
uploadPrincipaldistributors
|
uploadPrincipaldistributors
|
||||||
);
|
);
|
||||||
|
router
|
||||||
|
.route("/principaldistributor/download-report")
|
||||||
|
.get(
|
||||||
|
isAuthenticatedUser,
|
||||||
|
authorizeRoles("admin"),
|
||||||
|
generatePrincipalDistributorReport
|
||||||
|
);
|
||||||
//mapping start
|
//mapping start
|
||||||
router
|
router
|
||||||
.route("/admin/users")
|
.route("/admin/users")
|
||||||
|
Loading…
Reference in New Issue
Block a user