Skip to content

Commit

Permalink
Merge pull request #6429 from NMDSdevopsServiceAdm/fix/allow-change-i…
Browse files Browse the repository at this point in the history
…d-and-staff-transfer

Fix: Allow change id and staff transfer
  • Loading branch information
duncanc19 authored Nov 26, 2024
2 parents e700124 + 433f4e9 commit 3d556ce
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 30 deletions.
76 changes: 60 additions & 16 deletions backend/server/models/BulkImport/csv/crossValidate.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,26 @@ const crossValidateTransferStaffRecord = async (
const relatedEstablishmentIds = myEstablishments.map((establishment) => establishment.id);

const allMovingWorkers = myJSONWorkers.filter(isMovingToNewWorkplace);
const allNewWorkers = myJSONWorkers.filter((JSONWorker) => JSONWorker.status === 'NEW');
const allNewWorkers = myJSONWorkers.filter((worker) => worker.status === 'NEW');
const allOtherWorkers = myJSONWorkers.filter((worker) => !isMovingToNewWorkplace(worker) && worker.status !== 'NEW');

const newWorkerWithDuplicateIdErrorAdded = _crossValidateWorkersWithDuplicateRefsMovingToWorkplace(
csvWorkerSchemaErrors,
allMovingWorkers,
allNewWorkers,
TRANSFER_STAFF_RECORD_ERRORS.SameRefsMovingToWorkplace,
);

if (newWorkerWithDuplicateIdErrorAdded) return;

_crossValidateWorkersWithSameRefMovingToSameWorkplace(csvWorkerSchemaErrors, allMovingWorkers, allNewWorkers);
const existingWorkerWithDuplicateIdErrorAdded = _crossValidateWorkersWithDuplicateRefsMovingToWorkplace(
csvWorkerSchemaErrors,
allMovingWorkers,
allOtherWorkers,
TRANSFER_STAFF_RECORD_ERRORS.SameLocalIdExistInNewWorkplace,
);

if (existingWorkerWithDuplicateIdErrorAdded) return;

for (const JSONWorker of allMovingWorkers) {
const newWorkplaceId = await _validateTransferIsPossible(
Expand Down Expand Up @@ -92,12 +109,21 @@ const _validateTransferIsPossible = async (csvWorkerSchemaErrors, relatedEstabli
return;
}

const sameLocalIdExistInNewWorkplace = await models.worker.findOneWithConflictingLocalRef(
const workerReferenceToLookup = JSONWorker.changeUniqueWorker
? JSONWorker.changeUniqueWorker
: JSONWorker.uniqueWorkerId;

// if worker with duplicated reference found in database but not in csv file,
// changes to unique worker ID are applied before deleting workers not in file,
// which would cause bulk upload to break
// the code below prevents this issue

const uniqueWorkerIdFoundInWorkplaceInDatabase = await models.worker.findOneWithConflictingLocalRef(
newWorkplaceId,
JSONWorker.uniqueWorkerId,
workerReferenceToLookup,
);

if (sameLocalIdExistInNewWorkplace) {
if (uniqueWorkerIdFoundInWorkplaceInDatabase) {
addCrossValidateError(
csvWorkerSchemaErrors,
TRANSFER_STAFF_RECORD_ERRORS.SameLocalIdExistInNewWorkplace,
Expand Down Expand Up @@ -139,19 +165,27 @@ const _addNewWorkplaceIdToWorkerEntity = (myAPIEstablishments, JSONWorker, newWo

const workerEntity = myAPIEstablishments[oldWorkplaceKey].theWorker(workerEntityKey);

workerEntity._newWorkplaceId = newWorkplaceId;
if (workerEntity) {
workerEntity._newWorkplaceId = newWorkplaceId;
}
};

const _crossValidateWorkersWithSameRefMovingToSameWorkplace = (
const _crossValidateWorkersWithDuplicateRefsMovingToWorkplace = (
csvWorkerSchemaErrors,
allMovingWorkers,
allNewWorkers,
otherWorkers,
errorType,
) => {
const workplacesDict = _buildWorkplaceDictWithNewWorkers(allNewWorkers);
const workplacesDict = _buildWorkplaceDictWithOtherWorkers(otherWorkers);

let errorAdded = false;

for (const JSONWorker of allMovingWorkers) {
const newWorkplaceRef = JSONWorker.transferStaffRecord;
const workerRef = JSONWorker.uniqueWorkerId.replace(/\s/g, '');

const workerRef = JSONWorker.changeUniqueWorker
? JSONWorker.changeUniqueWorker.replace(/\s/g, '')
: JSONWorker.uniqueWorkerId.replace(/\s/g, '');

if (!workplacesDict[newWorkplaceRef]) {
workplacesDict[newWorkplaceRef] = new Set([workerRef]);
Expand All @@ -162,17 +196,27 @@ const _crossValidateWorkersWithSameRefMovingToSameWorkplace = (
workplacesDict[newWorkplaceRef].add(workerRef);
continue;
}
// worker's ID exists in workplace in file
addCrossValidateError(csvWorkerSchemaErrors, errorType, JSONWorker);

// if arrive at here, there is already another new or moving worker with that workerRef coming to the same new workplace
addCrossValidateError(csvWorkerSchemaErrors, TRANSFER_STAFF_RECORD_ERRORS.SameRefsMovingToWorkplace, JSONWorker);
errorAdded = true;
}

return errorAdded;
};

const _buildWorkplaceDictWithNewWorkers = (allNewWorkers) => {
return chain(allNewWorkers)
const _buildWorkplaceDictWithOtherWorkers = (otherWorkers) => {
return chain(otherWorkers)
.groupBy('localId') // workplace ref
.mapValues((JSONWorkers) => JSONWorkers.map((JSONWorker) => JSONWorker.uniqueWorkerId.replace(/\s/g, '')))
.mapValues((workerRefs) => new Set(workerRefs))
.mapValues((JSONWorkers) =>
JSONWorkers.map((JSONWorker) => {
if (JSONWorker.changeUniqueWorker) {
return [JSONWorker.changeUniqueWorker.replace(/\s/g, ''), JSONWorker.uniqueWorkerId.replace(/\s/g, '')];
}
return [JSONWorker.uniqueWorkerId.replace(/\s/g, '')];
}),
)
.mapValues((workerRefs) => new Set(workerRefs.flat()))
.value();
};

Expand Down
3 changes: 2 additions & 1 deletion backend/server/models/BulkImport/csv/crossValidateErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ const TRANSFER_STAFF_RECORD_ERRORS = {
errType: 'TRANSFERSTAFFRECORD_ERROR',
column: 'UNIQUEWORKERID',
_sourceFieldName: 'uniqueWorkerId',
error: 'The UNIQUEWORKERID already exists in the LOCALESTID given in TRANSFERSTAFFRECORD',
error:
"The UNIQUEWORKERID already exists in the LOCALESTID given in TRANSFERSTAFFRECORD. Use CHGUNIQUEWRKID to change this worker's UNIQUEWORKERID.",
}),
SameRefsMovingToWorkplace: Object.freeze({
errCode: TRANSFER_STAFF_RECORD_BASE_ERROR_CODE + 3,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,16 @@ const workerHeadersWithTransferStaffRecordAsArray = [
...workerHeaders.slice(2),
];

const workerHeadersWithChangeUniqueWorkerIdAndTransferStaffRecordAsArray = [
...workerHeaders.slice(0, 2),
'CHGUNIQUEWRKID',
'TRANSFERSTAFFRECORD',
...workerHeaders.slice(2),
];

exports.workerHeadersWithCHGUNIQUEWRKID = workerHeadersWithChangeUniqueWorkerIdAsArray.join(',');
exports.workerHeadersWithTRANSFERSTAFFRECORD = workerHeadersWithTransferStaffRecordAsArray.join(',');
exports.workerHeadersWithoutCHGUNIQUEWRKID = workerHeaders.join(',');
exports.workerHeadersWithCHGUNIQUEWRKIDAndTRANSFERSTAFFRECORD =
workerHeadersWithChangeUniqueWorkerIdAndTransferStaffRecordAsArray.join(',');
exports.getWorkerColumnIndex = (columnName) => workerHeaders.findIndex((header) => header === columnName);
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ const {
workerHeadersWithCHGUNIQUEWRKID,
workerHeadersWithoutCHGUNIQUEWRKID,
workerHeadersWithTRANSFERSTAFFRECORD,
workerHeadersWithCHGUNIQUEWRKIDAndTRANSFERSTAFFRECORD,
} = require('../../data/workerHeaders');

const validateWorkerHeaders = (headers) => {
const allowedWorkerHeaders = [
workerHeadersWithoutCHGUNIQUEWRKID,
workerHeadersWithCHGUNIQUEWRKID,
workerHeadersWithTRANSFERSTAFFRECORD,
workerHeadersWithCHGUNIQUEWRKIDAndTRANSFERSTAFFRECORD,
];

for (const workerHeadersBeforeExtraQuals of allowedWorkerHeaders) {
Expand Down
10 changes: 9 additions & 1 deletion backend/server/routes/establishments/bulkUpload/whichFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ const isWorkerFile = (fileAsString) => {
const headersRegexBaseCase = /LOCALESTID,UNIQUEWORKERID,STATUS,DISPLAYID,/;
const headersRegexChangeUniqueWorkerId = /LOCALESTID,UNIQUEWORKERID,CHGUNIQUEWRKID,STATUS,DISPLAYID,/;
const headersRegexTransferStaffRecord = /LOCALESTID,UNIQUEWORKERID,TRANSFERSTAFFRECORD,STATUS,DISPLAYID,/;
const regexToCheckHeaders = [headersRegexBaseCase, headersRegexChangeUniqueWorkerId, headersRegexTransferStaffRecord];
const headersRegexChangeUniqueWorkerIdTransferStaffRecord =
/LOCALESTID,UNIQUEWORKERID,CHGUNIQUEWRKID,TRANSFERSTAFFRECORD,STATUS,DISPLAYID,/;

const regexToCheckHeaders = [
headersRegexBaseCase,
headersRegexChangeUniqueWorkerId,
headersRegexTransferStaffRecord,
headersRegexChangeUniqueWorkerIdTransferStaffRecord,
];

const headerRow = fileAsString.split('\n')[0];

Expand Down
Loading

0 comments on commit 3d556ce

Please sign in to comment.