exports.
getPrDataPoDataInvoiceDataGrnDataByGraph = async (req, res) => {
try {
const {
pr_id,
company_id,
prCategory,
type,
priority,
emp_id,
poInvoice_id
} = req.body;
const resultArray = [];
// -------- Fetch PR Data (Service PR or Item PR) -------- //
if (pr_id && prCategory) {
const prIncludeOptions = [
{ model: db.tbl_prWorkFlowApprove },
{ model: db.employee },
{ model: db.tbl_prFileUpload }
];
if (prCategory === 'Service PR') {
prIncludeOptions.push({ model: db.tbl_prServiceMapping });
} else if (prCategory === 'Item PR') {
prIncludeOptions.push(
{
model: db.tbl_prItemMapping,
where: { isDeleted: false },
required: false
},
{
model: db.tbl_prBOMMapping,
required: false
}
);
}
const prData = await db.tbl_pr.findAll({
where: { pr_id, company_id },
include: prIncludeOptions
});
if (prData.length) {
await Promise.all(prData.map(async (pr) => {
const department = await db.tbl_department.findOne({
where: { department_id: pr.department_id }
});
pr.dataValues.department_name = department?.department_name ||
null;
}));
resultArray.push({
prData: prData
});
}
}
// -------- Fetch PO + Invoice Data -------- //
if (type === "PO_INVOICE") {
const poList = await db.tbl_po.findAll();
for (const po of poList) {
const invoices = await db.tbl_poInvoice.findAll({
where: {
po_id: po.po_id,
...(poInvoice_id && { poInvoice_id }),
isDeleted: false
}
});
const [data] = await db.sequelize.query(`
SELECT * FROM tbl_poInvoices poi
WHERE poi.po_id = :po_id
`, {
replacements: { po_id: po.po_id }
});
const poItems = await db.tbl_PoItemMapping.findAll({
where: { po_id: po.po_id }
});
const totalAmount = poItems.reduce((sum, item) => sum +
(item.priceIncludingCharges || 0), 0);
const itemsArray = [];
for (const invoice of invoices) {
const items = await db.tbl_poInvoiceMapping.findAll({
where: {
poInvoice_id: invoice.poInvoice_id,
status: "ACTIVE"
}
});
itemsArray.push(...items);
}
resultArray.push({
poData: po,
poitemData: poItems,
itemsArray,
invoiceData: invoices,
totalAmount,
data
});
}
}
// -------- Fetch GRN Data -------- //
if (type === "GRN") {
const [poResults] = await db.sequelize.query(`
SELECT po.*, rf.rfpCategory
FROM tbl_pos po
LEFT JOIN tbl_rfps rf ON po.rfp_id = rf.rfp_id
WHERE
(rf.rfpCategory IN ('ItemRFP', 'BomRFP') OR rf.rfpCategory IS
NULL)
AND (po.createdBy = :emp_id OR po.grnCreator = :emp_id)
AND po.poStatus = 'ACCEPTED'
ORDER BY po.po_id DESC;
`, {
replacements: { emp_id }
});
const enrichedPoList = await Promise.all(poResults.map(async (po) => {
const poItems = await db.tbl_PoItemMapping.findAll({
where: { po_id: po.po_id }
});
const enrichedItems = await Promise.all(poItems.map(async (item) =>
{
const vendor = await db.tbl_vendor.findOne({
where: { vendor_id: item.vendor_id },
attributes: ['supplierName']
});
const itemDetails = await db.tbl_item.findOne({
where: { item_id: item.item_id },
attributes: ['itemDescription', 'brand', 'model']
});
return {
...item.dataValues,
supplierName: vendor?.supplierName || null,
description: itemDetails?.itemDescription || null,
brand: itemDetails?.brand || null,
model: itemDetails?.model || null
};
}));
return {
...po,
poItemMappings: enrichedItems
};
}));
resultArray.push({
grnData: enrichedPoList
});
}
// -------- Final Response -------- //
return res.status(200).send({
code: 200,
message: "Data fetched successfully",
result: resultArray
});
} catch (error) {
console.error("Error in getPrDataPoDataInvoiceDataGrnDataByGraph:", error);
return res.status(500).json({
code: 500,
message: error.message || "Internal server error"
});
}
};
getAllPrDataPoDataInvoiceDataGrnDataByGraph() {
const body: any = {
company_id: this.companyId,
type: "PO_INVOICE",
emp_id: this.employeeLoginId,
poInvoice_id: 456,
prCategory: "Item PR",
pr_id: 370
};
this.dashboard_service.getAllPrDataPoDataInvoiceDataGrnDataByGraph(body).subscribe(
(res: any) => {
if (res && res.code === 200 && res.result && res.result.length > 0) {
// Extract data correctly from the response structure
const result = res.result;
// PR data is in the first element of result array under prData key
const prData = result[0]?.prData || [];
// PO and invoice data are in subsequent elements of the result array
const poInvoiceData = result.slice(1) || [];
// --- PR Amount calculations ---
const totalPrAmount = prData.reduce((sum: number, pr: any) =>
sum + (parseFloat(pr.totalAmount) || 0), 0);
const approvedPrAmount = prData
.filter((pr: any) => pr.prCategoryStatus === "Approved")
.reduce((sum: number, pr: any) => sum + (parseFloat(pr.totalAmount) ||
0), 0);
// --- PO Amount calculations ---
const totalPoAmount = poInvoiceData.reduce((sum: number, po: any) => {
const amount = po.totalAmount || 0;
return sum + parseFloat(amount);
}, 0);
const approvedPoAmount = poInvoiceData
.filter((po: any) => po.poData && po.poData.poStatus === "ACCEPTED")
.reduce((sum: number, po: any) => {
const amount = po.totalAmount || 0;
return sum + parseFloat(amount);
}, 0);
// --- Invoice Amount calculations ---
const totalInvoiceAmount = poInvoiceData.reduce((sum: number, po: any) =>
{
if (!po.data || !Array.isArray(po.data)) return sum;
return sum + po.data.reduce((innerSum: number, invoice: any) => {
// Use totalAmount from PO for each active invoice since
invoiceAmount isn't in the response
return innerSum + (invoice.isDeleted === 0 ? po.totalAmount : 0);
}, 0);
}, 0);
const approvedInvoiceAmount = poInvoiceData.reduce((sum: number, po: any)
=> {
if (!po.data || !Array.isArray(po.data)) return sum;
return sum + po.data.reduce((innerSum: number, invoice: any) => {
return innerSum + (invoice.isDeleted === 0 && invoice.paymentStatus
=== "PAID" ?
po.totalAmount : 0);
}, 0);
}, 0);
// --- GRN Amount calculations ---
const totalGrnAmount = poInvoiceData
.filter((po: any) => po.poData && po.poData.grnStatus !== null)
.reduce((sum: number, po: any) => {
// Since grnAmount isn't in the response, use totalAmount as a
fallback
return sum + parseFloat(po.totalAmount || 0);
}, 0);
const approvedGrnAmount = poInvoiceData
.filter((po: any) => po.poData && po.poData.grnStatus === "Created")
.reduce((sum: number, po: any) => {
return sum + parseFloat(po.totalAmount || 0);
}, 0);
// Log calculated values for debugging
console.log("Calculated Values:", {
totalPrAmount,
approvedPrAmount,
totalPoAmount,
approvedPoAmount,
totalInvoiceAmount,
approvedInvoiceAmount,
totalGrnAmount,
approvedGrnAmount
});
// Create chart options with proper values
this.chartOptions1 = {
animationEnabled: true,
theme: "light2",
exportEnabled: true,
title: {
text: "Current Year Spent Analysis",
fontSize: 20
},
axisX: {
labelFontSize: 12,
labelAngle: 0
},
axisY: {
title: "Amount in Rupees (₹)",
titleFontSize: 14,
interlacedColor: "#EBF2FA",
tickColor: "azure",
titleFontColor: "#4f81bc",
prefix: "₹",
includeZero: true
},
toolTip: {
shared: true,
contentFormatter: function(e: any) {
let content = "<strong>" + e.entries[0].dataPoint.label +
"</strong><br/>";
for (let i = 0; i < e.entries.length; i++) {
content += "<span style='color: " + e.entries[i].dataSeries.color
+ ";'>" +
e.entries[i].dataSeries.name + "</span>: <strong>₹" +
e.entries[i].dataPoint.y.toLocaleString() + "</strong><br/>";
}
return content;
}
},
legend: {
cursor: "pointer",
fontSize: 14,
itemclick: function(e: any) {
if (typeof e.dataSeries.visible === "undefined" ||
e.dataSeries.visible) {
e.dataSeries.visible = false;
} else {
e.dataSeries.visible = true;
}
e.chart.render();
}
},
dataPointWidth: 50,
data: [
{
type: "column",
name: "Created",
legendText: "Created",
showInLegend: true,
color: "#4472c4",
dataPoints: [
{ label: "Purchase Request", y: totalPrAmount || 0 },
{ label: "Purchase Order", y: totalPoAmount || 0 },
{ label: "Invoice", y: totalInvoiceAmount || 0 },
{ label: "GRN", y: totalGrnAmount || 0 }
]
},
{
type: "column",
name: "Approved",
legendText: "Approved",
showInLegend: true,
color: "#5cb85c",
dataPoints: [
{ label: "Purchase Request", y: approvedPrAmount || 0 },
{ label: "Purchase Order", y: approvedPoAmount || 0 },
{ label: "Invoice", y: approvedInvoiceAmount || 0 },
{ label: "GRN", y: approvedGrnAmount || 0 }
]
}
]
};
// Make sure the chart renders after data is available
setTimeout(() => {
if (this.cdr) {
this.cdr.detectChanges();
console.log("Chart options updated and change detection triggered");
}
}, 100);
}
else {
console.error("Error fetching data:", res);
}
},
(error) => {
console.error("API call failed:", error);
}
);
}