download report and task show
This commit is contained in:
parent
26a924efbb
commit
6ab315c247
@ -16,6 +16,7 @@ import {
|
||||
updateunmapRD,
|
||||
uploadRetaildistributors,
|
||||
updateretaildistributorwithKYC,
|
||||
generateRetailerReport,
|
||||
} from "./RetailDistributorController.js";
|
||||
import { isAuthenticatedRD } from "../../middlewares/rdAuth.js";
|
||||
import { authorizeRoles, isAuthenticatedUser } from "../../middlewares/auth.js";
|
||||
@ -25,6 +26,9 @@ const router = express.Router();
|
||||
router
|
||||
.route("/retaildistributor/upload")
|
||||
.post(isAuthenticatedUser, authorizeRoles("admin"), uploadRetaildistributors);
|
||||
router
|
||||
.route("/retaildistributor/download-report")
|
||||
.get(isAuthenticatedUser, authorizeRoles("admin"), generateRetailerReport);
|
||||
router.route("/rd-login").post(loginRD);
|
||||
router.route("/rd-get-me").get(isAuthenticatedRD, getmyProfileRD);
|
||||
router.post("/forgot-password", forgotPasswordRD);
|
||||
|
@ -1843,3 +1843,105 @@ export const saveFCMTokenForRD = async (req, res) => {
|
||||
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
|
||||
const tasks = await Task.find({
|
||||
taskDueDate: {
|
||||
createdAt: {
|
||||
$gte: startOfToday,
|
||||
$lte: endOfToday,
|
||||
},
|
||||
@ -395,7 +395,7 @@ export const getTodaysTasks = async (req, res) => {
|
||||
.skip(skip) // Skip documents for pagination
|
||||
.limit(itemsPerPage) // Limit the number of documents
|
||||
.exec();
|
||||
|
||||
// console.log(tasks);
|
||||
// Populate addedForId conditionally
|
||||
const populatedTasks = await Promise.all(
|
||||
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" });
|
||||
}
|
||||
};
|
||||
|
||||
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,
|
||||
getTasksByDates,
|
||||
getTodaysTasks,
|
||||
getTasks,
|
||||
} from "./TaskController.js";
|
||||
import { isAuthenticatedSalesCoOrdinator } from "../../middlewares/SalesCoOrdinatorAuth.js";
|
||||
import { isAuthenticatedTerritoryManager } from "../../middlewares/TerritoryManagerAuth.js";
|
||||
@ -38,4 +39,10 @@ router.get(
|
||||
authorizeRoles("admin"),
|
||||
getTodaysTasks
|
||||
);
|
||||
router.get(
|
||||
"/tasks",
|
||||
isAuthenticatedUser,
|
||||
authorizeRoles("admin"),
|
||||
getTasks
|
||||
);
|
||||
export default router;
|
||||
|
@ -1149,3 +1149,132 @@ export const saveFCMTokenForUser = async (req, res) => {
|
||||
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,
|
||||
saveFCMTokenForUser,
|
||||
getAllPD,
|
||||
generatePrincipalDistributorReport,
|
||||
} from "./userController.js";
|
||||
import { isAuthenticatedUser, authorizeRoles } from "../../middlewares/auth.js";
|
||||
|
||||
@ -46,6 +47,13 @@ router
|
||||
authorizeRoles("admin"),
|
||||
uploadPrincipaldistributors
|
||||
);
|
||||
router
|
||||
.route("/principaldistributor/download-report")
|
||||
.get(
|
||||
isAuthenticatedUser,
|
||||
authorizeRoles("admin"),
|
||||
generatePrincipalDistributorReport
|
||||
);
|
||||
//mapping start
|
||||
router
|
||||
.route("/admin/users")
|
||||
|
Loading…
Reference in New Issue
Block a user