Skip to content

Commit

Permalink
Merge pull request #1469 from bcgov/feature/schoolDups
Browse files Browse the repository at this point in the history
Added dups page
  • Loading branch information
SodhiA1 authored Apr 10, 2024
2 parents a3894ec + eaeb4e2 commit 05d69bf
Show file tree
Hide file tree
Showing 12 changed files with 631 additions and 89 deletions.
72 changes: 65 additions & 7 deletions backend/src/components/cache-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ let activeDistricts = [];
let activeAuthorities = [];
let authorities = [];
let authoritiesMap = new Map();
let bandCodesMap = new Map();
let enrolledProgramCodesMap = new Map();
let careerProgramCodesMap = new Map();
let schoolFundingCodesMap = new Map();
let specialEducationCodesMap = new Map();
let rolePermissionsMap = new Map();
let documentTypeCodesMap = new Map();
let documentTypeCodes = [];
Expand Down Expand Up @@ -192,9 +197,6 @@ const cacheService = {
retries: 50
});
},
getAllDocumentTypeCodesJSON() {
return documentTypeCodes;
},
getDocumentTypeCodeLabelByCode(code) {
return documentTypeCodesMap.get(code);
},
Expand Down Expand Up @@ -232,19 +234,75 @@ const cacheService = {
getCachedData(){
return cachedData;
},
getAllActiveBandCodesMap() {
let bandCodesRaw = cachedData[constants.CACHE_KEYS.SDC_BAND_CODES].activeRecords;
let bandCodes = bandCodesRaw.map(item => {
return {...item, dropdownText: `${item.description} (${item.bandCode})`};
});

bandCodes.unshift({'bandCode': '', 'dropdownText': 'No Band Code'});
bandCodes.forEach(bandCode => {
bandCodesMap.set(bandCode.bandCode, bandCode);
});
return bandCodesMap;
},
getActiveCareerProgramCodesMap() {
let careerProgramCodesRaw = cachedData[constants.CACHE_KEYS.SDC_CAREER_PROGRAM_CODES].activeRecords;
let careerProgramCodes = careerProgramCodesRaw.map(item => {
return {...item, dropdownText: `${item.description} (${item.careerProgramCode})`};
});
careerProgramCodes.unshift({'careerProgramCode': '', 'dropdownText': 'No Career Code'});
careerProgramCodes.forEach(careerProgramCode => {
careerProgramCodesMap.set(careerProgramCode.careerProgramCode, careerProgramCode);
});
return careerProgramCodesMap;
},
getEnrolledProgramCodesMap() {
let enrolledProgramCodesRaw = cachedData[constants.CACHE_KEYS.SDC_ENROLLED_GRADE_CODES].activeRecords;
let enrolledProgramCodes = enrolledProgramCodesRaw.map(item => {
return {...item, dropdownText: `${item.description} (${item.enrolledProgramCode})`};
});
enrolledProgramCodes.forEach(enrolledProgramCode => {
enrolledProgramCodesMap.set(enrolledProgramCode.enrolledProgramCode, enrolledProgramCode);
});
return enrolledProgramCodesMap;
},
getActiveSchoolFundingCodesMap() {
let schoolFundingCodesRaw = cachedData[constants.CACHE_KEYS.SDC_SCHOOL_FUNDING_CODES].activeRecords;
let schoolFundingCodes = schoolFundingCodesRaw.map(item => {
return {...item, dropdownText: `${item.description} (${item.schoolFundingCode})`};
});
schoolFundingCodes.unshift({'schoolFundingCode': '', 'dropdownText': 'No Funding Code'});
schoolFundingCodes.forEach(schoolFundingCode => {
schoolFundingCodesMap.set(schoolFundingCode.schoolFundingCode, schoolFundingCode);
});
return schoolFundingCodesMap;
},
getActiveSpecialEducationCodesMap() {
let specialEducationCodesRaw = cachedData[constants.CACHE_KEYS.SDC_SPECIAL_ED_CODES].activeRecords;
let specialEducationCodes = specialEducationCodesRaw.map(item => {
return {...item, dropdownText: `${item.description} (${item.specialEducationCategoryCode})`};
});
specialEducationCodesMap = new Map();
specialEducationCodes.unshift({'specialEducationCategoryCode': '', 'dropdownText': 'No Special Ed Category Code'});
specialEducationCodes.forEach(specialEducationCategoryCode => {
specialEducationCodesMap.set(specialEducationCategoryCode.specialEducationCategoryCode, specialEducationCategoryCode);
});
return specialEducationCodesMap;
},
getActiveEnrolledGradeCodes() {
return cachedData[constants.CACHE_KEYS.SDC_ENROLLED_GRADE_CODES].activeRecords;
},
getActiveFundingCodes() {
getActiveSchoolFundingCodes() {
return cachedData[constants.CACHE_KEYS.SDC_SCHOOL_FUNDING_CODES].activeRecords;
},
getActiveCareerCodes() {
getActiveCareerProgramCodes() {
return cachedData[constants.CACHE_KEYS.SDC_CAREER_PROGRAM_CODES].activeRecords;
},
getActiveEnrolledPrograms() {
getActiveEnrolledProgramCodes() {
return cachedData[constants.CACHE_KEYS.SDC_ENROLLED_PROGRAM_CODES].activeRecords;
},
getActiveSpedCodes() {
getActiveSpecialEducationCodes() {
return cachedData[constants.CACHE_KEYS.SDC_SPECIAL_ED_CODES].activeRecords;
}
};
Expand Down
95 changes: 94 additions & 1 deletion backend/src/components/sdc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ const { getAccessToken, handleExceptionResponse, getData, postData, putData, get
const HttpStatus = require('http-status-codes');
const log = require('./logger');
const config = require('../config');
const { FILTER_OPERATION, VALUE_TYPE, CONDITION } = require('../util/constants');
const { FILTER_OPERATION, VALUE_TYPE, CONDITION, ENROLLED_PROGRAM_TYPE_CODE_MAP} = require('../util/constants');
const {createMoreFiltersSearchCriteria} = require('./studentFilters');
const {REPORT_TYPE_CODE_MAP} = require('../util/constants');
const cacheService = require('./cache-service');

async function getCollectionBySchoolId(req, res) {
try {
Expand Down Expand Up @@ -160,6 +161,10 @@ async function getSDCSchoolCollectionStudentPaginated(req, res) {
return res.status(HttpStatus.OK).json(result);
}

if(req?.query?.tableFormat){
data.content = data?.content.map(toTableRow);
}

return res.status(HttpStatus.OK).json(data);
} catch (e) {
if (e?.status === 404) {
Expand Down Expand Up @@ -201,6 +206,20 @@ async function getSDCSchoolCollectionStudentDetail(req, res) {
}
}

async function markSdcSchoolCollectionStudentAsDifferent(req, res) {
try {
const payload = req.body;
payload.assignedPen = null;
payload.assignedStudentId = null;
payload.penMatchResult = 'MRKED_DIFF';

return updateAndValidateSdcSchoolCollectionStudent(req, res);
} catch (e) {
log.error('Error updating sdc school collection student detail', e.stack);
return handleExceptionResponse(e, res);
}
}

async function updateAndValidateSdcSchoolCollectionStudent(req, res) {
try {
const payload = req.body;
Expand Down Expand Up @@ -253,6 +272,78 @@ async function removeSDCSchoolCollectionStudents(req, res) {
}
}

async function getSchoolStudentDuplicates(req, res) {
try {
const token = getAccessToken(req);
let studentDuplicates = await getData(token, `${config.get('sdc:schoolCollectionURL')}/${req.params.sdcSchoolCollectionID}/duplicates`, req.session?.correlationID);

let dupsMap = new Map();
studentDuplicates.forEach((dup) => {
if(dupsMap.has(dup.assignedPen)){
dupsMap.get(dup.assignedPen).push(toTableRow(dup));
}else{
dupsMap.set(dup.assignedPen, [toTableRow(dup)]);
}
});

let resultArray = [];

dupsMap.forEach(function(items,key){
resultArray.push({assignedPen: key, items});
});

return res.status(HttpStatus.OK).json(resultArray);
} catch (e) {
log.error('Error getting Student duplicates.', e.stack);
return handleExceptionResponse(e, res);
}
}

function toTableRow(student) {
let bandCodesMap = cacheService.getAllActiveBandCodesMap();
let careerProgramCodesMap = cacheService.getActiveCareerProgramCodesMap();
let schoolFundingCodesMap = cacheService.getActiveSchoolFundingCodesMap();
let specialEducationCodesMap = cacheService.getActiveSpecialEducationCodesMap();

student.mappedSpedCode = specialEducationCodesMap.get(student.specialEducationCategoryCode) !== undefined ? `${specialEducationCodesMap.get(student.specialEducationCategoryCode)?.description} (${specialEducationCodesMap.get(student.specialEducationCategoryCode)?.specialEducationCategoryCode})` : null;
student.mappedAncestryIndicator = student.nativeAncestryInd === null ? null : nativeAncestryInd(student);
student.mappedFrenchEnrolledProgram = enrolledProgramMapping(student, ENROLLED_PROGRAM_TYPE_CODE_MAP.FRENCH_ENROLLED_PROGRAM_CODES);
student.mappedEllEnrolledProgram = enrolledProgramMapping(student, ENROLLED_PROGRAM_TYPE_CODE_MAP.ENGLISH_ENROLLED_PROGRAM_CODES);
student.mappedLanguageEnrolledProgram = enrolledProgramMapping(student, [...ENROLLED_PROGRAM_TYPE_CODE_MAP.ENGLISH_ENROLLED_PROGRAM_CODES, ...ENROLLED_PROGRAM_TYPE_CODE_MAP.FRENCH_ENROLLED_PROGRAM_CODES]);
student.careerProgram = enrolledProgramMapping(student, ENROLLED_PROGRAM_TYPE_CODE_MAP.CAREER_ENROLLED_PROGRAM_CODES);
student.mappedIndigenousEnrolledProgram = enrolledProgramMapping(student, ENROLLED_PROGRAM_TYPE_CODE_MAP.INDIGENOUS_ENROLLED_PROGRAM_CODES);
student.mappedBandCode = bandCodesMap.get(student.bandCode) !== undefined ? `${bandCodesMap.get(student.bandCode)?.description} (${bandCodesMap.get(student.bandCode)?.bandCode})` : null;
student.careerProgramCode = careerProgramCodesMap.get(student.careerProgramCode) !== undefined ? `${careerProgramCodesMap.get(student.careerProgramCode)?.description} (${careerProgramCodesMap.get(student.careerProgramCode)?.careerProgramCode})` : null;
student.mappedSchoolFunding = schoolFundingCodesMap.get(student.schoolFundingCode) !== undefined ? `${schoolFundingCodesMap.get(student.schoolFundingCode)?.description} (${schoolFundingCodesMap.get(student.schoolFundingCode)?.schoolFundingCode})` : null;
student.indProgramEligible = student.indigenousSupportProgramNonEligReasonCode !== null ? 'No' : 'Yes';
student.frenchProgramEligible = student.frenchProgramNonEligReasonCode !== null ? 'No' : 'Yes';
student.ellProgramEligible = student.ellNonEligReasonCode !== null ? 'No' : 'Yes';
student.careerProgramEligible = student.careerProgramNonEligReasonCode !== null ? 'No' : 'Yes';
student.spedProgramEligible = student.specialEducationNonEligReasonCode !== null ? 'No' : 'Yes';
student.yearsInEll = student.sdcStudentEll ? student.sdcStudentEll.yearsInEll : '';
student.mappedNoOfCourses = student.numberOfCoursesDec !== null ? student.numberOfCoursesDec.toFixed(2) : '0';
return student;
}

function enrolledProgramMapping(student, enrolledProgramFilter) {
let enrolledProgramCodesMap = cacheService.getActiveSpecialEducationCodesMap();
if(!student.enrolledProgramCodes) {
return '';
}
return student.enrolledProgramCodes
.match(/.{1,2}/g)
.filter(programCode => enrolledProgramFilter.includes(programCode))
.map(programCode => {
const enrolledProgram = enrolledProgramCodesMap.get(programCode);
return enrolledProgram ? `${enrolledProgram.description} (${programCode})` : programCode;
})
.join(',');
}

function nativeAncestryInd(student) {
return student.nativeAncestryInd === 'Y' ? 'Yes' : 'No';
}

async function getStudentHeadcounts(req, res) {
try {
const params = {
Expand Down Expand Up @@ -454,6 +545,7 @@ module.exports = {
getCollectionBySchoolId,
uploadFile,
getSdcFileProgress,
getSchoolStudentDuplicates,
removeSDCSchoolCollectionStudents,
updateSchoolCollection,
getDistrictCollectionById,
Expand All @@ -465,5 +557,6 @@ module.exports = {
getSDCSchoolCollectionStudentDetail,
updateAndValidateSdcSchoolCollectionStudent,
deleteSDCSchoolCollectionStudent,
markSdcSchoolCollectionStudentAsDifferent,
getStudentHeadcounts
};
12 changes: 6 additions & 6 deletions backend/src/components/studentFilters.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ function validateGradeFilter(filterGrades = []) {
}

function validateFundingTypeFilter(filterFunding = []) {
const activeFundingCodes = cacheService.getActiveFundingCodes();
const activeFundingCodes = cacheService.getActiveSchoolFundingCodes();
if (filterFunding.length > 0) {
if (filterFunding.every(value => activeFundingCodes.includes(code => code !== 'No Funding' && value === code.schoolFundingCode))) {
log.error('Invalid funding code filter.');
Expand All @@ -278,7 +278,7 @@ function validateFundingTypeFilter(filterFunding = []) {
}

function validateCareerCodeFilter(filterCareerCodes = []) {
const activeFundingCodes = cacheService.getActiveCareerCodes();
const activeFundingCodes = cacheService.getActiveCareerProgramCodes();
if (filterCareerCodes.length > 0) {
if (filterCareerCodes.every(value => activeFundingCodes.includes(code => value === code.careerProgramCode))) {
log.error('Invalid career code filter.');
Expand All @@ -288,7 +288,7 @@ function validateCareerCodeFilter(filterCareerCodes = []) {
}

function validateEnrolledProgramFilter(filterGrades = []) {
const activeFundingCodes = cacheService.getActiveEnrolledPrograms();
const activeFundingCodes = cacheService.getActiveEnrolledProgramCodes();
if (filterGrades.length > 0) {
if (filterGrades.every(value => activeFundingCodes.includes(code => value === code.enrolledProgramCode))) {
log.error('Invalid enrolled program filter.');
Expand All @@ -311,7 +311,7 @@ function validateWarningFilter(filters = []) {
}

function validateSpedCodes(filters = []) {
const activeSpedCodes = cacheService.getActiveSpedCodes();
const activeSpedCodes = cacheService.getActiveSpecialEducationCodes();
if (filters.length > 0) {
if (filters.every(value => activeSpedCodes.includes(code => value === code.specialEducationCategoryCode))) {
log.error('Invalid special education filter.');
Expand Down Expand Up @@ -391,7 +391,7 @@ function createSpedFilter(pValue) {
let spedCodeList = [];
validateSpedCodes(pValue);
if (pValue.includes('noSpedCode')) {
const notInValues = cacheService.getActiveSpedCodes().map(x=>x.specialEducationCategoryCode).filter(value => !pValue.includes(value) && pValue!=='noSpedCode');
const notInValues = cacheService.getActiveSpecialEducationCodes().map(x=>x.specialEducationCategoryCode).filter(value => !pValue.includes(value) && pValue!=='noSpedCode');
if(notInValues?.length > 0) { //if all filters are selected then it is equivalent to no filters being selected
spedCodeList.push({ key: 'specialEducationCategoryCode', value: notInValues.toString(), operation: FILTER_OPERATION.NOT_IN, valueType: VALUE_TYPE.STRING, condition: CONDITION.OR });
}
Expand Down Expand Up @@ -511,7 +511,7 @@ function careerCodeFilter(pValue) {

validateCareerCodeFilter(pValue);
if (pValue.includes('noCareerCodes')) {
const notInValues = cacheService.getActiveCareerCodes().map(x=>x.careerProgramCode).filter(value => !pValue.includes(value) && pValue!=='noCareerCodes');
const notInValues = cacheService.getActiveCareerProgramCodes().map(x=>x.careerProgramCode).filter(value => !pValue.includes(value) && pValue!=='noCareerCodes');
if(notInValues?.length > 0) { //if all filters are selected then it is equivalent to no filters being selected
careerCodeList.push({ key: 'careerProgramCode', value: notInValues.toString(), operation: FILTER_OPERATION.NOT_IN, valueType: VALUE_TYPE.STRING, condition: CONDITION.OR });
}
Expand Down
7 changes: 6 additions & 1 deletion backend/src/routes/sdc.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 05d69bf

Please sign in to comment.