Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor target generate and validate for generic type #1296

Merged
merged 13 commits into from
Dec 30, 2024
12 changes: 0 additions & 12 deletions health-services/project-factory/src/server/api/campaignApis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1848,21 +1848,9 @@ async function projectCreate(projectCreateBody: any, request: any) {
logger.info(
`for boundary type ${projectCreateResponse?.Project[0]?.address?.boundaryType} and code ${projectCreateResponse?.Project[0]?.address?.boundary}`
);
// if (
// !request.body.newlyCreatedBoundaryProjectMap[
// projectCreateBody?.Projects?.[0]?.address?.boundary
// ]
// ) {
// request.body.newlyCreatedBoundaryProjectMap[
// projectCreateBody?.Projects?.[0]?.address?.boundary
// ] = {};
// }
request.body.boundaryProjectMapping[
projectCreateBody?.Projects?.[0]?.address?.boundary
].projectId = projectCreateResponse?.Project[0]?.id;
// request.body.newlyCreatedBoundaryProjectMap[
// projectCreateBody?.Projects?.[0]?.address?.boundary
// ].projectId = projectCreateResponse?.Project[0]?.id;
} else {
throwError(
"PROJECT",
Expand Down
43 changes: 3 additions & 40 deletions health-services/project-factory/src/server/api/genericApis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@ import FormData from "form-data"; // Import FormData for handling multipart/form
import { defaultheader, httpRequest } from "../utils/request"; // Import httpRequest function for making HTTP requests
import { getFormattedStringForDebug, logger } from "../utils/logger"; // Import logger for logging
import { correctParentValues, findMapValue, generateActivityMessage, getBoundaryRelationshipData, getDataSheetReady, getLocalizedHeaders, sortCampaignDetails, throwError } from "../utils/genericUtils"; // Import utility functions
import { extractCodesFromBoundaryRelationshipResponse, generateFilteredBoundaryData, getConfigurableColumnHeadersBasedOnCampaignType, getFiltersFromCampaignSearchResponse, getLocalizedName } from '../utils/campaignUtils'; // Import utility functions
import { extractCodesFromBoundaryRelationshipResponse, generateFilteredBoundaryData, getConfigurableColumnHeadersBasedOnCampaignType, getFiltersFromCampaignSearchResponse, getLocalizedName, processDataForTargetCalculation } from '../utils/campaignUtils'; // Import utility functions
import { getCampaignSearchResponse, getHierarchy } from './campaignApis';
const _ = require('lodash'); // Import lodash library
import { getExcelWorkbookFromFileURL } from "../utils/excelUtils";
import { processMapping } from "../utils/campaignMappingUtils";


//Function to get Workbook with different tabs (for type target)
const getTargetWorkbook = async (fileUrl: string, localizationMap?: any) => {
// Define headers for HTTP request
Expand Down Expand Up @@ -209,6 +208,7 @@ const getTargetSheetDataAfterCode = async (
for (const sheetName of localizedSheetNames) {
const worksheet = workbook.getWorksheet(sheetName);
const sheetData = getSheetDataFromWorksheet(worksheet);
const jsonData = getJsonData(sheetData,true,true, sheetName);

// Find the target column index where the first row value matches codeColumnName
const firstRow = sheetData[0];
Expand All @@ -224,44 +224,7 @@ const getTargetSheetDataAfterCode = async (
console.warn(`Column "${codeColumnName}" not found in sheet "${sheetName}".`);
continue;
}

// Process data from sheet
const processedData = sheetData.map((row: any, rowIndex: any) => {
if (rowIndex <= 0) return null; // Skip header row

let rowData: any = { [codeColumnName]: row[boundaryCodeColumnIndex] };

// Add integer values in the target column for the current row
let sumOfCurrentTargets = 0;
let sumOfParentTargets = 0;
const remainingColumns = row.length - boundaryCodeColumnIndex - 1;
const halfPoint = Math.floor(remainingColumns / 2);
let startColIndex = boundaryCodeColumnIndex + 1;

if (request?.body?.parentCampaign) {
for (let colIndex = startColIndex; colIndex < startColIndex + halfPoint; colIndex++) {
const value = row[colIndex];
if (typeof value === 'number' && Number.isInteger(value)) {
sumOfParentTargets += value;
}
}
// Add the sum to the row data
rowData['Parent Target at the Selected Boundary level'] = sumOfParentTargets;

// Calculate middle point of remaining columns
startColIndex = boundaryCodeColumnIndex + 1 + halfPoint;
}
for (let colIndex = startColIndex; colIndex < row.length; colIndex++) {
const value = row[colIndex];
if (typeof value === 'number' && Number.isInteger(value)) {
sumOfCurrentTargets += value;
}
}

// Add the sum to the row data
rowData['Target at the Selected Boundary level'] = sumOfCurrentTargets;
return rowData;
}).filter(Boolean); // Remove null entries
const processedData = await processDataForTargetCalculation(request, jsonData, codeColumnName, localizationMap);

workbookData[sheetName] = processedData;
}
Expand Down
198 changes: 135 additions & 63 deletions health-services/project-factory/src/server/utils/campaignUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
createAndUploadJsonFile,
createBoundaryRelationship,
getSheetData,
searchMDMS
} from "../api/genericApis";
import { getFormattedStringForDebug, logger } from "./logger";
import createAndSearch from "../config/createAndSearch";
Expand Down Expand Up @@ -1695,21 +1696,37 @@ function mapBoundariesParent(boundaryResponse: any, request: any, parent: any) {
function mapTargets(boundaryResponses: any, codesTargetMapping: any) {
if (!boundaryResponses || !codesTargetMapping) return;

for (const boundaryResponse of boundaryResponses) {
const mapBoundary = (boundary: any) => {
if (!boundary.children || boundary.children.length === 0) {
const targetValue = codesTargetMapping[boundary.code];
return targetValue ? targetValue : 0;
}
// Helper function to map individual boundaries
const mapBoundary = (boundary: any) => {
if (!boundary.children || boundary.children.length === 0) {
// If no children, simply return the target value object or default to empty object
const targetValue = codesTargetMapping[boundary.code];
return targetValue || {};
}

let totalTargetValue = 0;
for (const child of boundary.children) {
const childTargetValue = mapBoundary(child);
totalTargetValue += childTargetValue;
// Initialize a new object to accumulate total target values from children
let totalTargetValue: any = {};

// Iterate through each child and accumulate their target values
for (const child of boundary.children) {
const childTargetValue = mapBoundary(child);

// Accumulate the child target values into the total target value
for (const key in childTargetValue) {
if (childTargetValue.hasOwnProperty(key)) {
// Initialize key in totalTargetValue if it doesn't exist
totalTargetValue[key] = (totalTargetValue[key] || 0) + childTargetValue[key];
}
}
codesTargetMapping[boundary.code] = totalTargetValue;
return totalTargetValue;
};
}

// Store the accumulated total target value for the current boundary
codesTargetMapping[boundary.code] = totalTargetValue;
return totalTargetValue;
};

// Map each boundary response
for (const boundaryResponse of boundaryResponses) {
mapBoundary(boundaryResponse);
}
}
Expand Down Expand Up @@ -2169,13 +2186,14 @@ async function getCodesTarget(request: any, localizationMap?: any) {
fileResponse?.fileStoreIds?.[0]?.url,
true,
true,
codeColumnName
codeColumnName,
localizationMap
);
const boundaryTargetMapping: any = {};
// Iterate through each key in targetData
for (const key in targetData) {
// Iterate through each entry in the array under the current key
targetData[key].forEach((entry) => {
targetData[key].forEach((entry : any) => {
// Check if the entry has both "Boundary Code" and "Target at the Selected Boundary level"
if (
entry[codeColumnName] !== undefined &&
Expand All @@ -2185,7 +2203,7 @@ async function getCodesTarget(request: any, localizationMap?: any) {
boundaryTargetMapping[entry[codeColumnName]] =
entry["Target at the Selected Boundary level"];
if (
entry["Parent Target at the Selected Boundary level"] !== 0 &&
Object.keys(entry["Parent Target at the Selected Boundary level"]).length > 0 &&
entry["Parent Target at the Selected Boundary level"] !==
entry["Target at the Selected Boundary level"]
) {
Expand Down Expand Up @@ -2236,6 +2254,7 @@ async function createProject(
Projects,
};
boundaries = await reorderBoundaries(request, localizationMap);
const codesTargetMapping = request?.body?.CampaignDetails?.codesTargetMapping;
let boundariesAlreadyWithProjects: any;
if (request?.body?.parentCampaign) {
// make search to project with parent campaign root project id
Expand Down Expand Up @@ -2267,38 +2286,7 @@ async function createProject(
);
const projectToUpdate = projectSearchResponse?.Project?.[0];
if (projectToUpdate) {
const filteredTargets = projectToUpdate.targets.filter(
(e: any) =>
e.beneficiaryType ==
request?.body?.CampaignDetails?.additionalDetails
?.beneficiaryType
);
if (filteredTargets.length == 0) {
projectToUpdate.targets = [
{
beneficiaryType:
request?.body?.CampaignDetails?.additionalDetails
?.beneficiaryType,
totalNo:
request?.body?.CampaignDetails?.codesTargetMapping[
boundary
],
targetNo:
request?.body?.CampaignDetails?.codesTargetMapping[
boundary
],
},
];
} else {
const targetobj = filteredTargets[0];
(targetobj.totalNo =
request?.body?.CampaignDetails?.codesTargetMapping[boundary]),
(targetobj.targetNo =
request?.body?.CampaignDetails?.codesTargetMapping[
boundary
]);
projectToUpdate.targets = [targetobj];
}
enrichTargetForProject(projectToUpdate, codesTargetMapping, boundary);
const projectUpdateBody = {
RequestInfo: request?.body?.RequestInfo,
Projects: [projectToUpdate],
Expand Down Expand Up @@ -2344,21 +2332,7 @@ async function createProject(

// Set the reference ID and project targets
Projects[0].referenceID = request?.body?.CampaignDetails?.campaignNumber;
(Projects[0].targets = [
{
beneficiaryType:
request?.body?.CampaignDetails?.additionalDetails
?.beneficiaryType,
totalNo:
request?.body?.CampaignDetails?.codesTargetMapping[
boundaryCode
],
targetNo:
request?.body?.CampaignDetails?.codesTargetMapping[
boundaryCode
],
},
]);
enrichTargetForProject(Projects[0], codesTargetMapping, boundaryCode);
await projectCreate(projectCreateBody, request);
}
}
Expand All @@ -2385,6 +2359,26 @@ async function createProject(
);
}

const enrichTargetForProject = (project: any, codesTargetMapping: any, boundaryCode: any) => {
if (codesTargetMapping?.[boundaryCode] && Object.keys(codesTargetMapping[boundaryCode]).length > 0) {
let targets = [];
for (const key in codesTargetMapping?.[boundaryCode]) {
let targetNo = parseInt(codesTargetMapping?.[boundaryCode][key]);
let beneficiaryType = key;
targets.push({
beneficiaryType: beneficiaryType,
targetNo: targetNo,
});
}
if(targets.length > 0){
project.targets = targets;
}
}
else{
logger.info(`No targets found for boundary code ${boundaryCode}`);
}
}

async function processAfterPersist(request: any, actionInUrl: any) {
try {
const localizationMap = await getLocalizedMessagesHandler(
Expand Down Expand Up @@ -3030,6 +3024,84 @@ async function updateAndPersistResourceDetails(
);
}

export async function processDataForTargetCalculation(request: any, jsonData: any, codeColumnName: string, localizationMap?: any) {
// Retrieve targetConfigs from MDMS
const targetConfigs = await searchMDMS([request?.body?.CampaignDetails?.projectType], "HCM-ADMIN-CONSOLE.targetConfigs", request?.body?.RequestInfo);

// Process each row of the sheet data
const resultantData = jsonData.map((row: any) => {

// Initialize an object to hold row-specific data
let rowData: any = { [codeColumnName]: row[codeColumnName] };

// Add placeholder fields for Parent Target and Current Target data
rowData['Parent Target at the Selected Boundary level'] = {};
rowData['Target at the Selected Boundary level'] = {};
const beneficiaries = targetConfigs?.mdms?.[0]?.data?.beneficiaries;
// Calculate the parent target values
calculateTargetsAtParentLevel(request, row, rowData, beneficiaries, localizationMap);
// Calculate the current target values
calculateTargetsAtCurrentLevel(row, rowData, beneficiaries, localizationMap);

// Return the processed row data
return rowData;
}).filter(Boolean); // Remove any null entries from the map (i.e., skip the header row)

return resultantData;
}

export function calculateTargetsAtParentLevel(request: any, row: any, rowData: any, beneficiaries: any, localizationMap?: any) {
// Check if a parent campaign exists in the request body
if (request?.body?.parentCampaign) {
// Loop through the beneficiaries for the specified campaign type
if (Array.isArray(beneficiaries) && beneficiaries?.length > 0) {
for (const beneficiary of beneficiaries) {
const beneficiaryType = beneficiary?.beneficiaryType;
const columns = beneficiary?.columns;
let totalParentValue = 0;

// Loop through each column to calculate the total parent value
for (const col of columns) {
// Get the parent value from the column and add it if it's an integer
const parentValue = row[`${getLocalizedName(col, localizationMap)}(OLD)`];
if (typeof parentValue === 'number' && Number.isInteger(parentValue)) {
totalParentValue += parentValue;
}
}
// Assign the total parent value to the corresponding beneficiary type
rowData['Parent Target at the Selected Boundary level'][beneficiaryType] = totalParentValue;
}
}
else {
logger.warn("No beneficiaries config found for the specified campaign type");
}
}
}

export function calculateTargetsAtCurrentLevel(row: any, rowData: any, beneficiaries: any, localizationMap?: any) {
// Loop through the beneficiaries again to calculate the current target values
if (Array.isArray(beneficiaries) && beneficiaries?.length > 0) {
for (const beneficiary of beneficiaries) {
const beneficiaryType = beneficiary?.beneficiaryType;
const columns = beneficiary?.columns;
let totalCurrentValue = 0;

// Loop through each column to calculate the total current value
for (const col of columns) {
const currentValue = row[getLocalizedName(col, localizationMap)];
if (typeof currentValue === 'number' && Number.isInteger(currentValue)) {
totalCurrentValue += currentValue;
}
}
// Assign the total current value to the corresponding beneficiary type
rowData['Target at the Selected Boundary level'][beneficiaryType] = totalCurrentValue;
}
}
else {
logger.warn("No beneficiaries config found for the specified campaign type");
}
}

async function getResourceDetails(request: any) {
const { tenantId, type, hierarchyType } =
request?.body?.ResourceDetails || request?.query;
Expand Down
Loading
Loading