NMDSdevopsServiceAdm/SopraSteria-SFC

View on GitHub
backend/server/models/BulkImport/csv/workplaceCSVValidator.js

Summary

Maintainability
F
2 mos
Test Coverage
File `workplaceCSVValidator.js` has 2808 lines of code (exceeds 250 allowed). Consider refactoring.
const BUDI = require('../BUDI').BUDI;
const models = require('../../index');
const clonedeep = require('lodash.clonedeep');
const moment = require('moment');
const { sanitisePostcode } = require('../../../utils/postcodeSanitizer');
const STOP_VALIDATING_ON = ['UNCHECKED', 'DELETE', 'NOCHANGE'];
const Establishment = require('../../classes/establishment').Establishment;
 
const employedContractStatusIds = [1, 2];
const cqcRegulatedServiceCodes = [24, 25, 20, 22, 21, 23, 19, 27, 28, 26, 29, 30, 32, 31, 33, 34];
const registeredManagerJobID = 4;
const regManager = 4;
 
const csvQuote = (toCsv) => {
if (toCsv && toCsv.replace(/ /g, '').match(/[\s,"]/)) {
return '"' + toCsv.replace(/"/g, '""') + '"';
} else {
return toCsv;
}
};
 
function isRegManager(worker) {
if (worker.mainJobRoleId === registeredManagerJobID) {
// 4 is reg manager in csv
return true;
}
return false;
}
function isPerm(worker) {
return employedContractStatusIds.includes(worker.contractTypeId);
}
 
const _headers_v1 =
'LOCALESTID,STATUS,ESTNAME,ADDRESS1,ADDRESS2,ADDRESS3,POSTTOWN,POSTCODE,ESTTYPE,OTHERTYPE,' +
'PERMCQC,PERMLA,REGTYPE,PROVNUM,LOCATIONID,MAINSERVICE,ALLSERVICES,CAPACITY,UTILISATION,SERVICEDESC,' +
'SERVICEUSERS,OTHERUSERDESC,TOTALPERMTEMP,ALLJOBROLES,STARTERS,LEAVERS,VACANCIES,REASONS,REASONNOS,' +
'ADVERTISING,INTERVIEWS,REPEATTRAINING,ACCEPTCARECERT,BENEFITS,SICKPAY,PENSION,HOLIDAY';
 
`WorkplaceCSVValidator` has 161 functions (exceeds 20 allowed). Consider refactoring.
class WorkplaceCSVValidator {
Function `constructor` has 43 lines of code (exceeds 25 allowed). Consider refactoring.
constructor(currentLine, lineNumber, allCurrentEstablishments) {
this._currentLine = currentLine;
this._lineNumber = lineNumber;
this._allCurrentEstablishments = allCurrentEstablishments;
 
this._validationErrors = [];
 
// CSV properties
this._localId = null;
this._status = null;
this._key = null;
this._name = null;
this._address1 = null;
this._address2 = null;
this._address3 = null;
this._town = null;
this._postcode = null;
 
this._establishmentType = null;
this._establishmentTypeOther = null;
 
this._shareWithCqc = null;
this._shareWithLA = null;
 
this._regType = null;
this._provID = null;
this._locationID = null;
 
this._mainService = null;
this._allServices = null;
this._allServicesOther = null;
this._allServiceUsers = null;
this._allServiceUsersOther = null;
this._capacities = null;
this._utilisations = null;
 
this._totalPermTemp = null;
 
this._alljobs = null;
this._vacancies = null;
this._starters = null;
this._leavers = null;
this._reasonsForLeaving = null;
this._doNewStartersRepeatMandatoryTrainingFromPreviousEmployment = null;
this._wouldYouAcceptCareCertificatesFromPreviousEmployment = null;
this._moneySpentOnAdvertisingInTheLastFourWeeks = null;
this._peopleInterviewedInTheLastFourWeeks = null;
this._careWorkersCashLoyaltyForFirstTwoYears = null;
this._sickPay = null;
this._pensionContribution = null;
this._careWorkersLeaveDaysPerYear = null;
 
this._id = null;
this._ignore = false;
}
 
static get EXPECT_JUST_ONE_ERROR() {
return 950;
}
static get MISSING_PRIMARY_ERROR() {
return 955;
}
static get CANNOT_DELETE_PRIMARY_ERROR() {
return 956;
}
 
static get NOT_OWNER_ERROR() {
return 997;
}
static get DUPLICATE_ERROR() {
return 998;
}
static get HEADERS_ERROR() {
return 999;
}
static get MAIN_SERVICE_ERROR() {
return 1000;
}
static get LOCAL_ID_ERROR() {
return 1010;
}
static get STATUS_ERROR() {
return 1020;
}
static get STATUS_WARNING() {
return 1025;
}
static get NAME_ERROR() {
return 1030;
}
static get ADDRESS_ERROR() {
return 1040;
}
static get ESTABLISHMENT_TYPE_ERROR() {
return 1070;
}
static get SHARE_WITH_CQC_ERROR() {
return 1080;
}
static get SHARE_WITH_LA_ERROR() {
return 1090;
}
static get REGTYPE_ERROR() {
return 1100;
}
static get PROV_ID_ERROR() {
return 1105;
}
static get LOCATION_ID_ERROR() {
return 1110;
}
static get ALL_SERVICES_ERROR() {
return 1120;
}
static get ALL_SERVICES_ERROR_NONE() {
return 1121;
}
static get SERVICE_USERS_ERROR() {
return 1130;
}
static get CAPACITY_UTILISATION_ERROR() {
return 1140;
}
 
static get TOTAL_PERM_TEMP_ERROR() {
return 1200;
}
static get ALL_JOBS_ERROR() {
return 1280;
}
static get VACANCIES_ERROR() {
return 1300;
}
static get STARTERS_ERROR() {
return 1310;
}
static get LEAVERS_ERROR() {
return 1320;
}
 
static get REASONS_FOR_LEAVING_ERROR() {
return 1360;
}
 
static get MAIN_SERVICE_WARNING() {
return 2000;
}
static get NAME_WARNING() {
return 2030;
}
static get ADDRESS_WARNING() {
return 2040;
}
static get ESTABLISHMENT_TYPE_WARNING() {
return 2070;
}
static get TOTAL_PERM_TEMP_WARNING() {
return 2200;
}
static get REGTYPE_WARNING() {
return 2100;
}
static get PROV_ID_WARNING() {
return 2105;
}
static get LOCATION_ID_WARNING() {
return 2110;
}
static get ALL_SERVICES_WARNING() {
return 2120;
}
static get SERVICE_USERS_WARNING() {
return 2130;
}
static get CAPACITY_UTILISATION_WARNING() {
return 2140;
}
static get ALL_JOBS_WARNING() {
return 2180;
}
 
static get VACANCIES_WARNING() {
return 2300;
}
static get STARTERS_WARNING() {
return 2310;
}
static get LEAVERS_WARNING() {
return 2320;
}
static get REASONS_FOR_LEAVING_WARNING() {
return 2360;
}
static get ADVERTISING_WARNING() {
return 2400;
}
static get INTERVIEWS_WARNING() {
return 2410;
}
static get REPEAT_TRAINING_WARNING() {
return 2420;
}
static get ACCEPT_CARE_CERT_WARNING() {
return 2430;
}
static get BENEFITS_WARNING() {
return 2440;
}
static get SICKPAY_WARNING() {
return 2450;
}
static get PENSION_WARNING() {
return 2460;
}
static get HOLIDAY_WARNING() {
return 2470;
}
 
get id() {
if (this._id === null) {
const est = this._allCurrentEstablishments.find((currentEstablishment) => currentEstablishment.key === this._key);
 
if (typeof est !== 'undefined') {
this._id = est._id;
}
}
 
return this._id;
}
 
static headers() {
return _headers_v1;
}
 
get headers() {
return _headers_v1;
}
 
get lineNumber() {
return this._lineNumber;
}
 
get currentLine() {
return this._currentLine;
}
 
get localId() {
return this._localId;
}
 
get key() {
return this._key;
}
 
get status() {
return this._status;
}
 
get name() {
return this._name;
}
 
get address() {
return this._address;
}
 
get postcode() {
return this._postcode;
}
 
get establishmentType() {
return BUDI.establishmentType(BUDI.TO_ASC, this._establishmentType) || this._establishmentType;
}
 
get establishmentTypeId() {
return this._establishmentType;
}
 
get establishmentTypeOther() {
return this._establishmentTypeOther;
}
 
get mainService() {
return this._mainService;
}
 
get allServices() {
// return a clone of the services array to prevent outside modifications
return Array.isArray(this._allServices) ? this._allServices.map((x) => x) : [];
}
 
get allServicesOther() {
return this._allServicesOther;
}
 
get allServiceUsers() {
return this._allServiceUsers;
}
 
get allServiceUsersOther() {
return this._allServiceUsersOther;
}
 
get capacities() {
return this._capacities;
}
 
get utilisations() {
return this._utilisations;
}
 
get shareWithCqc() {
return this._shareWithCqc;
}
 
get shareWithLa() {
return this._shareWithLA;
}
 
get regType() {
return this._regType;
}
 
get provId() {
return this._provID;
}
 
get locationId() {
return this._locationID;
}
 
get totalPermTemp() {
return this._totalPermTemp;
}
 
get allJobs() {
return this._alljobs;
}
 
get vacancies() {
return this._vacancies;
}
 
get starters() {
return this._starters;
}
 
get leavers() {
return this._leavers;
}
 
get reasonsForLeaving() {
return this._reasonsForLeaving;
}
 
get doNewStartersRepeatMandatoryTrainingFromPreviousEmployment() {
return this._doNewStartersRepeatMandatoryTrainingFromPreviousEmployment;
}
 
get moneySpentOnAdvertisingInTheLastFourWeeks() {
return this._moneySpentOnAdvertisingInTheLastFourWeeks;
}
 
get peopleInterviewedInTheLastFourWeeks() {
return this._peopleInterviewedInTheLastFourWeeks;
}
 
get wouldYouAcceptCareCertificatesFromPreviousEmployment() {
return this._wouldYouAcceptCareCertificatesFromPreviousEmployment;
}
 
get careWorkersLeaveDaysPerYear() {
return this._careWorkersLeaveDaysPerYear;
}
 
get careWorkersCashLoyaltyForFirstTwoYears() {
return this._careWorkersCashLoyaltyForFirstTwoYears;
}
 
get pensionContribution() {
return this._pensionContribution;
}
 
get sickPay() {
return this._sickPay;
}
 
Function `_validateLocalisedId` has 27 lines of code (exceeds 25 allowed). Consider refactoring.
Similar blocks of code found in 2 locations. Consider refactoring.
_validateLocalisedId() {
const myLocalId = this._currentLine.LOCALESTID;
 
// must be present and n more than 50 characters
const MAX_LENGTH = 50;
let status = true;
 
if (myLocalId === null || myLocalId.length === 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.LOCAL_ID_ERROR,
errType: 'LOCAL_ID_ERROR',
error: 'LOCALESTID has not been supplied',
source: myLocalId,
column: 'LOCALESTID',
});
status = false;
} else if (myLocalId.length >= MAX_LENGTH) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.LOCAL_ID_ERROR,
errType: 'LOCAL_ID_ERROR',
error: `LOCALESTID is longer than ${MAX_LENGTH} characters`,
source: myLocalId,
column: 'LOCALESTID',
});
status = false;
}
 
// need the LOCALSTID regardless of whether it has failed validation or not
this._localId = myLocalId === null || myLocalId.length === 0 ? `SFCROW$${this._lineNumber}` : myLocalId;
this._key = this._localId.replace(/\s/g, '');
 
return status;
}
 
Function `_validateStatus` has 99 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateStatus` has a Cognitive Complexity of 21 (exceeds 5 allowed). Consider refactoring.
_validateStatus() {
const statusValues = ['DELETE', 'UPDATE', 'UNCHECKED', 'NOCHANGE', 'NEW'];
const myStatus = this._currentLine.STATUS
? String(this._currentLine.STATUS).toUpperCase()
: this._currentLine.STATUS;
 
// must be present and must be one of the preset values (case insensitive)
if (!this._currentLine.STATUS || this._currentLine.STATUS.length === 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.STATUS_ERROR,
errType: 'STATUS_ERROR',
error: 'STATUS is blank',
source: this._currentLine.STATUS,
column: 'STATUS',
name: this._currentLine.LOCALESTID,
});
return false;
}
if (!statusValues.includes(myStatus)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.STATUS_ERROR,
errType: 'STATUS_ERROR',
error: 'The code you have entered for STATUS is incorrect',
source: this._currentLine.STATUS,
column: 'STATUS',
name: this._currentLine.LOCALESTID,
});
return false;
} else {
// helper which returns true if the given LOCALESTID exists
const thisEstablishmentId = this.id;
 
// we have a known status - now validate the status against the known set of all current establishments
switch (myStatus) {
Similar blocks of code found in 5 locations. Consider refactoring.
case 'NEW':
if (thisEstablishmentId !== null) {
this._validationErrors.push({
name: this._currentLine.LOCALESTID,
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.STATUS_ERROR,
errType: 'STATUS_ERROR',
error: 'Workplace has a STATUS of NEW but already exists, please use one of the other statuses',
source: myStatus,
column: 'STATUS',
});
}
break;
 
Similar blocks of code found in 5 locations. Consider refactoring.
case 'DELETE':
if (thisEstablishmentId === null) {
this._validationErrors.push({
name: this._currentLine.LOCALESTID,
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.STATUS_ERROR,
errType: 'STATUS_ERROR',
error: 'Workplace has a STATUS of DELETE but does not exist',
source: myStatus,
column: 'STATUS',
});
}
break;
 
Similar blocks of code found in 5 locations. Consider refactoring.
case 'UNCHECKED':
if (thisEstablishmentId === null) {
this._validationErrors.push({
name: this._currentLine.LOCALESTID,
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.STATUS_ERROR,
errType: 'STATUS_ERROR',
error: 'Workplace has a STATUS of UNCHECKED but does not exist, please change to NEW to add it',
source: myStatus,
column: 'STATUS',
});
}
break;
 
Similar blocks of code found in 5 locations. Consider refactoring.
case 'NOCHANGE':
if (thisEstablishmentId === null) {
this._validationErrors.push({
name: this._currentLine.LOCALESTID,
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.STATUS_ERROR,
errType: 'STATUS_ERROR',
error: 'Workplace has a STATUS of NOCHANGE but does not exist, please change to NEW to add it',
source: myStatus,
column: 'STATUS',
});
}
break;
 
Similar blocks of code found in 5 locations. Consider refactoring.
case 'UPDATE':
if (thisEstablishmentId === null) {
this._validationErrors.push({
name: this._currentLine.LOCALESTID,
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.STATUS_ERROR,
errType: 'STATUS_ERROR',
error: 'Workplace has a STATUS of UPDATE but does not exist, please change to NEW to add it',
source: myStatus,
column: 'STATUS',
});
}
break;
}
 
this._status = myStatus;
return true;
}
}
 
Function `_validateEstablishmentName` has 28 lines of code (exceeds 25 allowed). Consider refactoring.
_validateEstablishmentName() {
const myName = this._currentLine.ESTNAME;
 
// must be present and no more than 120 characters
const MAX_LENGTH = 120;
 
if (!myName || myName.length === 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.NAME_ERROR,
errType: 'NAME_ERROR',
error: 'ESTNAME has not been supplied',
source: myName,
column: 'ESTNAME',
name: this._currentLine.LOCALESTID,
});
 
return false;
Similar blocks of code found in 2 locations. Consider refactoring.
} else if (myName.length > MAX_LENGTH) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.NAME_ERROR,
errType: 'NAME_ERROR',
error: `ESTNAME is longer than ${MAX_LENGTH} characters`,
source: myName,
column: 'ESTNAME',
name: this._currentLine.LOCALESTID,
});
 
return false;
} else {
this._name = myName;
return true;
}
}
 
Function `_validateAddress` has 136 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateAddress` has a Cognitive Complexity of 17 (exceeds 5 allowed). Consider refactoring.
async _validateAddress() {
const myAddress1 = this._currentLine.ADDRESS1;
const myAddress2 = this._currentLine.ADDRESS2;
const myAddress3 = this._currentLine.ADDRESS3;
const myTown = this._currentLine.POSTTOWN;
const myPostcode = this._currentLine.POSTCODE;
let ignorePostcode = false;
 
// TODO - if town is empty, match against PAF
 
// adddress 1 is mandatory and no more than 40 characters
const MAX_LENGTH = 40;
let postcodeExists = [];
 
if (myPostcode && myPostcode.length) {
postcodeExists = await models.pcodedata.findAll({
where: {
postcode: myPostcode,
},
order: [['uprn', 'ASC']],
});
}
 
const localValidationErrors = [];
if (!myAddress1 || myAddress1.length === 0) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ADDRESS_ERROR,
errType: 'ADDRESS_ERROR',
error: 'ADDRESS1 is blank',
column: 'ADDRESS1',
name: this._currentLine.LOCALESTID,
});
} else if (myAddress1.length > MAX_LENGTH) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ADDRESS_ERROR,
errType: 'ADDRESS_ERROR',
error: `ADDRESS1 is longer than ${MAX_LENGTH} characters`,
source: myAddress1,
column: 'ADDRESS1',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
if (myAddress2 && myAddress2.length > MAX_LENGTH) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ADDRESS_ERROR,
errType: 'ADDRESS_ERROR',
error: `ADDRESS2 is longer than ${MAX_LENGTH} characters`,
source: myAddress2,
column: 'ADDRESS2',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
if (myAddress3 && myAddress3.length > MAX_LENGTH) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ADDRESS_ERROR,
errType: 'ADDRESS_ERROR',
error: `ADDRESS3 is longer than ${MAX_LENGTH} characters`,
source: myAddress3,
column: 'ADDRESS3',
name: this._currentLine.LOCALESTID,
});
}
 
if (myTown && myTown.length > MAX_LENGTH) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ADDRESS_ERROR,
errType: 'ADDRESS_ERROR',
error: `POSTTOWN is longer than ${MAX_LENGTH} characters`,
source: myTown,
column: 'POSTTOWN',
name: this._currentLine.LOCALESTID,
});
}
// TODO - registration/establishment APIs do not validate postcode (relies on the frontend - this must be fixed)
const POSTCODE_MAX_LENGTH = 10;
Similar blocks of code found in 4 locations. Consider refactoring.
if (!myPostcode || myPostcode.length === 0) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ADDRESS_ERROR,
errType: 'ADDRESS_ERROR',
error: 'POSTCODE has not been supplied',
source: myPostcode,
column: 'POSTCODE',
name: this._currentLine.LOCALESTID,
});
} else if (myPostcode.length > POSTCODE_MAX_LENGTH) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ADDRESS_ERROR,
errType: 'ADDRESS_ERROR',
error: `POSTCODE is longer than ${POSTCODE_MAX_LENGTH} characters`,
source: myPostcode,
column: 'POSTCODE',
name: this._currentLine.LOCALESTID,
});
Similar blocks of code found in 4 locations. Consider refactoring.
} else if (sanitisePostcode(myPostcode) === null) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ADDRESS_ERROR,
errType: 'ADDRESS_ERROR',
error: 'POSTCODE is incorrectly formatted',
source: myPostcode,
column: 'POSTCODE',
name: this._currentLine.LOCALESTID,
});
} else if (this._status === 'NEW' && !postcodeExists.length) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ADDRESS_ERROR,
errType: 'ADDRESS_ERROR',
error: 'The POSTCODE for this workplace cannot be found in our database and must be registered manually.',
source: myPostcode,
column: 'POSTCODE',
name: this._currentLine.LOCALESTID,
});
this._ignore = true;
} else if (this._status === 'UPDATE' && !postcodeExists.length) {
localValidationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.ADDRESS_ERROR,
warnType: 'ADDRESS_ERROR',
warning: 'The POSTCODE cannot be found in our database and will be ignored.',
source: myPostcode,
column: 'POSTCODE',
name: this._currentLine.LOCALESTID,
});
ignorePostcode = true;
}
 
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
 
// concatenate the address
this._address1 = myAddress1;
this._address2 = myAddress2;
this._address3 = myAddress3;
this._town = myTown;
if (!ignorePostcode) {
this._postcode = myPostcode;
}
 
return true;
}
 
Function `_validateEstablishmentType` has 74 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateEstablishmentType` has a Cognitive Complexity of 10 (exceeds 5 allowed). Consider refactoring.
_validateEstablishmentType() {
const myEstablishmentType = parseInt(this._currentLine.ESTTYPE, 10);
const myOtherEstablishmentType = this._currentLine.OTHERTYPE;
 
const localValidationErrors = [];
Similar blocks of code found in 12 locations. Consider refactoring.
if (!this._currentLine.ESTTYPE || this._currentLine.ESTTYPE.length === 0) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ESTABLISHMENT_TYPE_ERROR,
errType: 'ESTABLISHMENT_TYPE_ERROR',
error: 'ESTTYPE has not been supplied',
source: this._currentLine.ESTTYPE,
column: 'ESTTYPE',
name: this._currentLine.LOCALESTID,
});
Similar blocks of code found in 12 locations. Consider refactoring.
} else if (Number.isNaN(myEstablishmentType)) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ESTABLISHMENT_TYPE_ERROR,
errType: 'ESTABLISHMENT_TYPE_ERROR',
error: 'The code you have entered for ESTTYPE is incorrect',
source: this._currentLine.ESTTYPE,
column: 'ESTTYPE',
name: this._currentLine.LOCALESTID,
});
Similar blocks of code found in 12 locations. Consider refactoring.
} else if (myEstablishmentType < 1 || myEstablishmentType > 8) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ESTABLISHMENT_TYPE_ERROR,
errType: 'ESTABLISHMENT_TYPE_ERROR',
error: 'The code you have entered for ESTTYPE is incorrect',
source: this._currentLine.ESTTYPE,
column: 'ESTTYPE',
name: this._currentLine.LOCALESTID,
});
}
 
// if the establishment type is "other" (8), then OTHERTYPE must be defined
const MAX_LENGTH = 240;
 
Similar blocks of code found in 4 locations. Consider refactoring.
if (myEstablishmentType === 8 && (!myOtherEstablishmentType || myOtherEstablishmentType.length === 0)) {
localValidationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.ESTABLISHMENT_TYPE_WARNING,
warnType: 'ESTABLISHMENT_TYPE_WARNING',
warning: 'OTHERTYPE has not been supplied',
source: myOtherEstablishmentType,
column: 'OTHERTYPE',
name: this._currentLine.LOCALESTID,
});
} else if (myEstablishmentType === 8 && myOtherEstablishmentType.length > MAX_LENGTH) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ESTABLISHMENT_TYPE_ERROR,
errType: 'ESTABLISHMENT_TYPE_ERROR',
error: `OTHERTYPE is longer than ${MAX_LENGTH} characters`,
source: myOtherEstablishmentType,
column: 'OTHERTYPE',
name: this._currentLine.LOCALESTID,
});
} else if (myEstablishmentType === 8) {
this._establishmentTypeOther = myOtherEstablishmentType;
Similar blocks of code found in 4 locations. Consider refactoring.
} else if (myEstablishmentType !== 8 && myOtherEstablishmentType && myOtherEstablishmentType.length > 0) {
localValidationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.ESTABLISHMENT_TYPE_WARNING,
warnType: 'ESTABLISHMENT_TYPE_WARNING',
warning: 'OTHERTYPE will be ignored as not required',
source: myOtherEstablishmentType,
column: 'OTHERTYPE',
name: this._currentLine.LOCALESTID,
});
}
 
Identical blocks of code found in 8 locations. Consider refactoring.
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
 
this._establishmentType = myEstablishmentType;
return true;
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
_validateShareWithCQC() {
const ALLOWED_VALUES = ['0', '1', ''];
 
if (!ALLOWED_VALUES.includes(this._currentLine.PERMCQC)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.SHARE_WITH_CQC_ERROR,
errType: 'SHARE_WITH_CQC_ERROR',
error: 'The code you have entered for PERMCQC is incorrect',
source: this._currentLine.PERMCQC,
column: 'PERMCQC',
name: this._currentLine.LOCALESTID,
});
 
return false;
} else {
const shareWithCqcAsInt = parseInt(this._currentLine.PERMCQC, 10);
this._shareWithCqc = Number.isNaN(shareWithCqcAsInt) ? this._currentLine.PERMCQC : shareWithCqcAsInt;
 
return true;
}
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
_validateShareWithLA() {
const ALLOWED_VALUES = ['0', '1', ''];
 
if (!ALLOWED_VALUES.includes(this._currentLine.PERMLA)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.SHARE_WITH_LA_ERROR,
errType: 'SHARE_WITH_LA_ERROR',
error: 'The code you have entered for PERMLA is incorrect',
source: this._currentLine.PERMLA,
column: 'PERMLA',
name: this._currentLine.LOCALESTID,
});
 
return false;
} else {
const shareWithLaAsInt = parseInt(this._currentLine.PERMLA, 10);
this._shareWithLA = Number.isNaN(shareWithLaAsInt) ? this._currentLine.PERMLA : shareWithLaAsInt;
return true;
}
}
 
Function `_validateRegType` has 61 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateRegType` has a Cognitive Complexity of 9 (exceeds 5 allowed). Consider refactoring.
_validateRegType() {
const myRegType = parseInt(this._currentLine.REGTYPE, 10);
const dbServiceCode = BUDI.services(BUDI.TO_ASC, this._mainService);
const dbMainServiceCode = 16;
 
if (!this._currentLine.REGTYPE || this._currentLine.REGTYPE.length === 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REGTYPE_ERROR,
errType: 'REGTYPE_ERROR',
error: 'REGTYPE has not been supplied',
source: this._currentLine.REGTYPE,
column: 'REGTYPE',
name: this._currentLine.LOCALESTID,
});
 
return false;
} else if (Number.isNaN(myRegType) || (myRegType !== 0 && myRegType !== 2)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REGTYPE_ERROR,
errType: 'REGTYPE_ERROR',
error: 'The code you have entered for REGTYPE is incorrect',
source: this._currentLine.REGTYPE,
column: 'REGTYPE',
name: this._currentLine.LOCALESTID,
});
 
return false;
} else if (
myRegType === 2 &&
!cqcRegulatedServiceCodes.includes(dbServiceCode) &&
dbServiceCode !== dbMainServiceCode
) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REGTYPE_ERROR,
errType: 'REGTYPE_ERROR',
error:
'REGTYPE is 2 (CQC) but no CQC regulated services have been specified. Please change either REGTYPE or MAINSERVICE',
source: this._currentLine.REGTYPE,
column: 'REGTYPE/MAINSERVICE',
name: this._currentLine.LOCALESTID,
});
 
return false;
} else if (
myRegType === 0 &&
cqcRegulatedServiceCodes.includes(dbServiceCode) &&
dbServiceCode !== dbMainServiceCode
) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REGTYPE_ERROR,
errType: 'REGTYPE_ERROR',
error:
'REGTYPE is 0 (Non-CQC) but CQC regulated services have been specified. Please change either REGTYPE or MAINSERVICE',
source: this._currentLine.REGTYPE,
column: 'REGTYPE/MAINSERVICE',
name: this._currentLine.LOCALESTID,
});
 
return false;
} else {
this._regType = myRegType;
Avoid too many `return` statements within this function.
return true;
}
}
 
Function `_validateProvID` has 39 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateProvID` has a Cognitive Complexity of 6 (exceeds 5 allowed). Consider refactoring.
_validateProvID() {
// must be given if "REGTYPE" is 2 - but if given must be in the format "n-nnnnnnnnn"
const provIDRegex = /^[0-9]{1}-[0-9]{8,12}$/;
const myprovID = this._currentLine.PROVNUM;
 
if (this._regType === 2 && (!myprovID || myprovID.length === 0)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.PROV_ID_ERROR,
errType: 'PROV_ID_ERROR',
error: 'PROVNUM has not been supplied',
source: myprovID,
column: 'PROVNUM',
name: this._currentLine.LOCALESTID,
});
 
return false;
} else if (this._regType === 2 && !provIDRegex.test(myprovID)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.PROV_ID_ERROR,
errType: 'PROV_ID_ERROR',
error: 'PROVNUM is incorrectly formatted',
source: myprovID,
column: 'PROVNUM',
name: this._currentLine.LOCALESTID,
});
 
return false;
Similar blocks of code found in 2 locations. Consider refactoring.
} else if (this._regType === 2) {
this._provID = myprovID;
return true;
} else if (this._regType === 0 && myprovID && myprovID.length > 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.PROV_ID_WARNING,
warnType: 'PROV_ID_WARNING',
warning: 'PROVNUM will be ignored as not required for this REGTYPE',
source: myprovID,
column: 'PROVNUM',
name: this._currentLine.LOCALESTID,
});
 
return false;
}
}
 
Function `_validateLocationID` has 69 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateLocationID` has a Cognitive Complexity of 14 (exceeds 5 allowed). Consider refactoring.
async _validateLocationID() {
try {
// must be given if "share with CQC" - but if given must be in the format "n-nnnnnnnnn"
const locationIDRegex = /^[0-9]{1}-[0-9]{8,12}$/;
const myLocationID = this._currentLine.LOCATIONID;
 
// do not use
const mainServiceIsHeadOffice = parseInt(this._currentLine.MAINSERVICE, 10) === 72;
const locationExists = await models.establishment.findAll({
where: {
locationId: myLocationID,
},
attributes: ['id', 'locationId'],
});
let existingEstablishment = false;
await locationExists.map(async (establishment) => {
if (establishment.id === this._id) existingEstablishment = true;
});
Similar blocks of code found in 2 locations. Consider refactoring.
if (this._regType === 2) {
// ignore location i
if (!mainServiceIsHeadOffice) {
if (!myLocationID || myLocationID.length === 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.LOCATION_ID_ERROR,
errType: 'LOCATION_ID_ERROR',
error: 'LOCATIONID has not been supplied',
source: myLocationID,
column: 'LOCATIONID',
name: this._currentLine.LOCALESTID,
});
return false;
} else if (!locationIDRegex.test(myLocationID)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.LOCATION_ID_ERROR,
errType: 'LOCATION_ID_ERROR',
error: 'LOCATIONID is incorrectly formatted',
source: myLocationID,
column: 'LOCATIONID',
name: this._currentLine.LOCALESTID,
});
return false;
}
}
if (locationExists.length > 0 && !existingEstablishment) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.LOCATION_ID_ERROR,
errType: 'LOCATION_ID_ERROR',
error: 'LOCATIONID already exists in ASC-WDS please contact Support on 0113 241 0969',
source: myLocationID,
column: 'LOCATIONID',
name: this._currentLine.LOCALESTID,
});
return false;
}
 
this._locationID = myLocationID;
return true;
} else if (this._regType === 0 && myLocationID && myLocationID.length > 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.LOCATION_ID_WARNING,
warnType: 'LOCATION_ID_WARNING',
warning: 'LOCATIONID will be ignored as not required for this REGTYPE',
source: myLocationID,
column: 'LOCATIONID',
name: this._currentLine.LOCALESTID,
});
Avoid too many `return` statements within this function.
return false;
}
} catch (error) {
throw new Error(error);
}
}
 
Function `_validateMainService` has 27 lines of code (exceeds 25 allowed). Consider refactoring.
_validateMainService() {
const myMainService = parseInt(this._currentLine.MAINSERVICE, 10);
 
if (!this._currentLine.MAINSERVICE || this._currentLine.MAINSERVICE.length === 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.MAIN_SERVICE_ERROR,
errType: 'MAIN_SERVICE_ERROR',
error: 'MAINSERVICE has not been supplied',
source: this._currentLine.MAINSERVICE,
column: 'MAINSERVICE',
name: this._currentLine.LOCALESTID,
});
return false;
} else if (Number.isNaN(myMainService)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.MAIN_SERVICE_ERROR,
errType: 'MAIN_SERVICE_ERROR',
error: 'MAINSERVICE has not been supplied',
source: this._currentLine.MAINSERVICE,
column: 'MAINSERVICE',
name: this._currentLine.LOCALESTID,
});
return false;
} else {
this._mainService = myMainService;
return true;
}
}
 
Function `_validateAllServices` has 82 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateAllServices` has a Cognitive Complexity of 16 (exceeds 5 allowed). Consider refactoring.
_validateAllServices() {
// all services must have main service in it
 
const listOfServices = this._currentLine.ALLSERVICES.split(';');
const listOfServicesWithoutNo = listOfServices.filter((item) => item !== '0');
Similar blocks of code found in 2 locations. Consider refactoring.
if (!listOfServices || !listOfServices.includes(this._currentLine.MAINSERVICE)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_SERVICES_ERROR,
errType: 'ALL_SERVICES_ERROR',
error: 'MAINSERVICE is not included in ALLSERVICES',
source: this._currentLine.ALLSERVICES,
column: 'ALLSERVICES',
name: this._currentLine.LOCALESTID,
});
}
Similar blocks of code found in 2 locations. Consider refactoring.
if (listOfServices.includes('0') && listOfServicesWithoutNo.length !== 1) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_SERVICES_ERROR_NONE,
errType: 'ALL_SERVICES_ERROR_NONE',
error: 'ALLSERVICES is 0 (none) but contains services other than the MAINSERVICE',
source: this._currentLine.ALLSERVICES,
column: 'ALLSERVICES',
name: this._currentLine.LOCALESTID,
});
}
const localValidationErrors = [];
 
// all services and their service descriptions are semi-colon delimited
//remove 0 aka NO other services
const listOfServiceDescriptions = this._currentLine.SERVICEDESC.split(';');
const listOfServiceDescriptionsWithoutNo = this._prepArray(listOfServiceDescriptions);
const isValid = listOfServicesWithoutNo.every((thisService) => !Number.isNaN(parseInt(thisService, 10)));
Similar blocks of code found in 12 locations. Consider refactoring.
if (!isValid) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_SERVICES_ERROR,
errType: 'ALL_SERVICES_ERROR',
error: 'There is an empty element in ALLSERVICES',
source: this._currentLine.ALLSERVICES,
column: 'ALLSERVICES',
name: this._currentLine.LOCALESTID,
});
Similar blocks of code found in 12 locations. Consider refactoring.
} else if (listOfServicesWithoutNo.length !== listOfServiceDescriptionsWithoutNo.length) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_SERVICES_ERROR,
errType: 'ALL_SERVICES_ERROR',
error:
'ALLSERVICES/CAPACITY/UTILISATION/SERVICEDESC do not have the same number of items (i.e. numbers and/or semi colons)',
source: this._currentLine.SERVICEDESC,
column: 'ALLSERVICES/CAPACITY/UTILISATION/SERVICEDESC',
name: this._currentLine.LOCALESTID,
});
} else {
const myServiceDescriptions = [];
this._allServices = listOfServices.map((thisService, index) => {
const thisServiceIndex = parseInt(thisService, 10);
 
// if the service is one of the many "other" type of services, then need to validate the "other description"
const otherServices = [5, 7, 12, 21, 52, 71, 72, 75]; // these are the original budi codes
const MAX_LENGTH = 120;
if (otherServices.includes(thisServiceIndex)) {
const myServiceOther = listOfServiceDescriptions[index];
if (myServiceOther.length > MAX_LENGTH) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_SERVICES_ERROR,
errType: 'ALL_SERVICES_ERROR',
error: `SERVICEDESC(${index + 1}) is longer than ${MAX_LENGTH} characters`,
source: `${this._currentLine.SERVICEDESC} - ${listOfServiceDescriptions[index]}`,
column: 'SERVICEDESC',
name: this._currentLine.LOCALESTID,
});
} else {
myServiceDescriptions.push(listOfServiceDescriptions[index]);
}
} else {
myServiceDescriptions.push(null);
}
 
return thisServiceIndex;
});
 
this._allServicesOther = myServiceDescriptions;
}
 
Identical blocks of code found in 8 locations. Consider refactoring.
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
 
return true;
}
 
Function `_validateServiceUsers` has 74 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateServiceUsers` has a Cognitive Complexity of 21 (exceeds 5 allowed). Consider refactoring.
_validateServiceUsers() {
// service user (optional) is a semi colon delimited list of integers
 
const listOfServiceUsers = this._currentLine.SERVICEUSERS.split(';');
const listOfServiceUsersDescriptions = this._currentLine.OTHERUSERDESC.split(';');
 
const localValidationErrors = [];
if (this._currentLine.SERVICEUSERS && this._currentLine.SERVICEUSERS.length > 0) {
// which is not valid
const isValid = this._currentLine.SERVICEUSERS.length
? listOfServiceUsers.every((thisService) => !Number.isNaN(parseInt(thisService, 10)))
: true;
Similar blocks of code found in 12 locations. Consider refactoring.
if (!isValid) {
localValidationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.SERVICE_USERS_WARNING,
warnType: 'SERVICE_USERS_WARNING',
warning: 'Entry for code in SERVICEUSERS you have supplied will be ignored as this is invalid',
source: this._currentLine.SERVICEUSERS,
column: 'SERVICEUSERS',
name: this._currentLine.LOCALESTID,
});
Similar blocks of code found in 6 locations. Consider refactoring.
} else if (listOfServiceUsers.length !== listOfServiceUsersDescriptions.length) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.SERVICE_USERS_ERROR,
errType: 'SERVICE_USERS_ERROR',
error: 'SERVICEUSERS/OTHERUSERDESC do not have the same number of items (i.e. numbers and/or semi colons)',
source: `${this._currentLine.SERVICEUSERS} - ${this._currentLine.OTHERUSERDESC}`,
column: 'SERVICEUSERS/OTHERUSERDESC',
name: this._currentLine.LOCALESTID,
});
} else if (isValid) {
const myServiceUsersDescriptions = [];
Function `_allServiceUsers` has 35 lines of code (exceeds 25 allowed). Consider refactoring.
this._allServiceUsers = listOfServiceUsers.map((thisService, index) => {
const thisServiceIndex = parseInt(thisService, 10);
 
// if the service user is one of the many "other" type of services, then need to validate the "other description"
const otherServiceUsers = [3, 9, 21]; // these are the original budi codes
if (otherServiceUsers.includes(thisServiceIndex)) {
const myServiceUserOther = listOfServiceUsersDescriptions[index];
const MAX_LENGTH = 120;
if (!myServiceUserOther || myServiceUserOther.length === 0) {
localValidationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.SERVICE_USERS_WARNING,
warnType: 'SERVICE_USERS_WARNING',
warning: `OTHERUSERDESC(${index + 1}) has not been supplied`,
source: `${this._currentLine.SERVICEDESC} - ${listOfServiceUsersDescriptions[index]}`,
column: 'OTHERUSERDESC',
name: this._currentLine.LOCALESTID,
});
myServiceUsersDescriptions.push(null);
} else if (myServiceUserOther.length > MAX_LENGTH) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.SERVICE_USERS_ERROR,
errType: 'SERVICE_USERS_ERROR',
error: `Service Users (SERVICEUSERS:${index + 1}) is an 'other' service and (OTHERUSERDESC:${
index + 1
}) must not be greater than ${MAX_LENGTH} characters`,
source: `${this._currentLine.SERVICEDESC} - ${listOfServiceUsersDescriptions[index]}`,
column: 'OTHERUSERDESC',
name: this._currentLine.LOCALESTID,
});
} else {
myServiceUsersDescriptions.push(listOfServiceUsersDescriptions[index]);
}
} else {
myServiceUsersDescriptions.push(null);
}
 
return thisServiceIndex;
});
 
this._allServiceUsersOther = myServiceUsersDescriptions;
}
}
 
Identical blocks of code found in 8 locations. Consider refactoring.
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
 
return true;
}
Function `_ignoreZerosIfNo` has a Cognitive Complexity of 7 (exceeds 5 allowed). Consider refactoring.
_ignoreZerosIfNo(listOfEntities, zeroInService, allServices) {
if (zeroInService.length > 0 && listOfEntities.length === 2 && allServices.length === 2) {
const indexOfZero = allServices.indexOf('0');
if (indexOfZero > -1) {
listOfEntities[indexOfZero] = listOfEntities[indexOfZero] === '0' ? '' : listOfEntities[indexOfZero];
}
}
return listOfEntities;
}
_prepArray(listOfEntities) {
const allServices = this._currentLine.ALLSERVICES.split(';');
const zeroInService = allServices.filter((service) => {
return service === '0';
});
listOfEntities = this._ignoreZerosIfNo(listOfEntities, zeroInService, allServices);
listOfEntities = this._checkForTrailingSemiColon(listOfEntities, zeroInService);
return listOfEntities;
}
 
_checkForTrailingSemiColon(listOfEntities, zeroInService) {
if (
(zeroInService.length !== 0 && listOfEntities.length === 2) ||
this._currentLine.ALLSERVICES.split(';').length === 1
) {
listOfEntities = listOfEntities.filter((thisItem) => !Number.isNaN(parseInt(thisItem, 10)));
//make sure listOfEntities always has at least one null for MainService
return listOfEntities.length === 0 ? [''] : listOfEntities;
}
return listOfEntities;
}
Function `_validateCapacitiesAndUtilisations` has 107 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateCapacitiesAndUtilisations` has a Cognitive Complexity of 19 (exceeds 5 allowed). Consider refactoring.
_validateCapacitiesAndUtilisations() {
// capacities/utilisations are a semi colon delimited list of integers
let listOfCapacities = this._currentLine.CAPACITY.split(';');
let listOfUtilisations = this._currentLine.UTILISATION.split(';');
 
//remove excess semicolon when no other services = 0
listOfCapacities = this._prepArray(listOfCapacities);
listOfUtilisations = this._prepArray(listOfUtilisations);
 
const localValidationErrors = [];
 
// first - the number of capacities/utilisations must be non-zero and must be equal
Similar blocks of code found in 12 locations. Consider refactoring.
if (listOfCapacities.length === 0) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.CAPACITY_UTILISATION_ERROR,
errType: 'CAPACITY_UTILISATION_ERROR',
error: 'Capacities (CAPACITY) must be a semi-colon delimited list of whole numbers',
source: this._currentLine.CAPACITY,
column: 'CAPACITY',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 12 locations. Consider refactoring.
if (listOfUtilisations.length === 0) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.CAPACITY_UTILISATION_ERROR,
errType: 'CAPACITY_UTILISATION_ERROR',
error: 'Utilisations (UTILISATION) must be a semi-colon delimited list of whole numbers',
source: this._currentLine.UTILISATION,
column: 'UTILISATION',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 6 locations. Consider refactoring.
if (listOfCapacities.length !== listOfUtilisations.length) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.CAPACITY_UTILISATION_ERROR,
errType: 'CAPACITY_UTILISATION_ERROR',
error: 'Number of Capacities (CAPACITY) and Utilisations (UTILISATION) must be equal',
source: `${this._currentLine.CAPACITY} - ${this._currentLine.UTILISATION}`,
column: 'CAPACITY/UTILISATION',
name: this._currentLine.LOCALESTID,
});
}
 
// and the number of utilisations/capacities must equal the number of all services
const lengthOfServicesWithoutNo = this._allServices ? this._allServices.filter((item) => item !== 0).length : 0;
 
if (this._allServices && listOfCapacities.length !== lengthOfServicesWithoutNo) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.CAPACITY_UTILISATION_ERROR,
errType: 'CAPACITY_UTILISATION_ERROR',
error:
'Number of Capacities/Utilisations (CAPACITY/UTILISATION) must equal the number of all services (ALLSERVICES)',
source: `${this._currentLine.CAPACITY} - ${this._currentLine.UTILISATION} - ${this._currentLine.ALLSERVICES}`,
column: 'CAPACITY/UTILISATION',
name: this._currentLine.LOCALESTID,
});
}
 
// all capacities and all utilisations are integers (if given)
// capacities and utilisations must be less than 999999999
const MAX_CAP_UTIL = 9999;
 
Similar blocks of code found in 2 locations. Consider refactoring.
const areCapacitiesValid = listOfCapacities.every(
(thisCapacity) =>
thisCapacity === null ||
thisCapacity.length === 0 ||
(!Number.isNaN(parseInt(thisCapacity, 10)) && parseInt(thisCapacity, 10) < MAX_CAP_UTIL),
);
Similar blocks of code found in 2 locations. Consider refactoring.
if (!areCapacitiesValid) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.CAPACITY_UTILISATION_ERROR,
errType: 'CAPACITY_UTILISATION_ERROR',
error: `All capacities (CAPACITY) must be whole numbers and less than ${MAX_CAP_UTIL}`,
source: this._currentLine.CAPACITY,
column: 'CAPACITY',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
const areUtilisationsValid = listOfUtilisations.every(
(thisUtilisation) =>
thisUtilisation === null ||
thisUtilisation.length === 0 ||
(!Number.isNaN(parseInt(thisUtilisation, 10)) && parseInt(thisUtilisation, 10) < MAX_CAP_UTIL),
);
 
Similar blocks of code found in 2 locations. Consider refactoring.
if (!areUtilisationsValid) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.CAPACITY_UTILISATION_ERROR,
errType: 'CAPACITY_UTILISATION_ERROR',
error: `All utilisations (UTILISATION) must be whole numbers and less than ${MAX_CAP_UTIL}`,
source: this._currentLine.UTILISATION,
column: 'UTILISATION',
name: this._currentLine.LOCALESTID,
});
}
 
Identical blocks of code found in 8 locations. Consider refactoring.
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
Similar blocks of code found in 2 locations. Consider refactoring.
this._capacities = listOfCapacities.map((thisCapacity) => {
const intCapacity = parseInt(thisCapacity, 10);
if (isNaN(intCapacity)) {
return null;
} else {
return intCapacity;
}
});
Similar blocks of code found in 2 locations. Consider refactoring.
this._utilisations = listOfUtilisations.map((thisUtilisation) => {
const intUtilisation = parseInt(thisUtilisation, 10);
if (isNaN(intUtilisation)) {
return null;
} else {
return intUtilisation;
}
});
 
return true;
}
 
Function `_validateTotalPermTemp` has 40 lines of code (exceeds 25 allowed). Consider refactoring.
_validateTotalPermTemp() {
// mandatory
const MAX_TOTAL = 999;
const myTotalPermTemp = parseInt(this._currentLine.TOTALPERMTEMP, 10);
const HEAD_OFFICE_MAIN_SERVICE = 72;
 
if (myTotalPermTemp.length === 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.TOTAL_PERM_TEMP_ERROR,
errType: 'TOTAL_PERM_TEMP_ERROR',
error: 'TOTALPERMTEMP is missing',
source: this._currentLine.PERMCQC,
column: 'TOTALPERMTEMP',
name: this._currentLine.LOCALESTID,
});
return false;
Similar blocks of code found in 2 locations. Consider refactoring.
} else if (myTotalPermTemp < 0 || myTotalPermTemp > MAX_TOTAL || Number.isNaN(myTotalPermTemp)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.TOTAL_PERM_TEMP_ERROR,
errType: 'TOTAL_PERM_TEMP_ERROR',
error: `TOTALPERMTEMP must be a number from 0 to ${MAX_TOTAL} if this is correct call support on 0113 241 0969`,
source: myTotalPermTemp,
column: 'TOTALPERMTEMP',
name: this._currentLine.LOCALESTID,
});
return false;
} else if (this._mainService && this.mainService !== HEAD_OFFICE_MAIN_SERVICE && myTotalPermTemp === 0) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.TOTAL_PERM_TEMP_ERROR,
errType: 'TOTAL_PERM_TEMP_ERROR',
error: 'Total Permanent and Temporary (TOTALPERMTEMP) cannot be 0 except when MAINSERVICE is head office',
source: myTotalPermTemp,
column: 'TOTALPERMTEMP',
name: this._currentLine.LOCALESTID,
});
return false;
} else {
this._totalPermTemp = myTotalPermTemp;
return true;
}
}
 
Similar blocks of code found in 3 locations. Consider refactoring.
getDuplicateLocationError() {
return {
origin: 'Establishments',
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.DUPLICATE_ERROR,
errType: 'DUPLICATE_ERROR',
error: 'LOCATIONID is not unique',
source: this._currentLine.LOCATIONID,
column: 'LOCATIONID',
name: this._currentLine.LOCALESTID,
};
}
 
getTotal(allWorkers) {
let total = 0;
for (let totalInRole of allWorkers.split(';')) {
if (totalInRole !== '999') {
total += parseInt(totalInRole);
}
}
return total;
}
 
Function `_crossValidateTotalPermTemp` has 54 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_crossValidateTotalPermTemp` has a Cognitive Complexity of 8 (exceeds 5 allowed). Consider refactoring.
_crossValidateTotalPermTemp(csvEstablishmentSchemaErrors, { employedWorkers = 0, nonEmployedWorkers = 0 }) {
const vacancies = this.getTotal(this._currentLine.VACANCIES);
const starters = this.getTotal(this._currentLine.STARTERS);
const leavers = this.getTotal(this._currentLine.LEAVERS);
 
const template = {
origin: 'Establishments',
lineNumber: this._lineNumber,
source: this._currentLine.TOTALPERMTEMP,
name: this._currentLine.LOCALESTID,
};
 
const totalStaff = employedWorkers + nonEmployedWorkers;
 
if (this._totalPermTemp !== totalStaff) {
csvEstablishmentSchemaErrors.unshift(
Object.assign(clonedeep(template), {
warnCode: WorkplaceCSVValidator.TOTAL_PERM_TEMP_WARNING,
warnType: 'TOTAL_PERM_TEMP_WARNING',
warning: 'TOTALPERMTEMP (Total staff and the number of worker records) does not match',
column: 'TOTALPERMTEMP',
}),
);
} else if (this._totalPermTemp === totalStaff) {
Similar blocks of code found in 3 locations. Consider refactoring.
if (starters > totalStaff) {
csvEstablishmentSchemaErrors.unshift(
Object.assign(clonedeep(template), {
warnCode: WorkplaceCSVValidator.STARTERS_WARNING,
warnType: 'STARTERS_WARNING',
warning:
'STARTERS data you have entered does not fall within the expected range please ensure this is correct',
column: 'STARTERS',
}),
);
}
Similar blocks of code found in 3 locations. Consider refactoring.
if (leavers >= totalStaff) {
csvEstablishmentSchemaErrors.unshift(
Object.assign(clonedeep(template), {
warnCode: WorkplaceCSVValidator.LEAVERS_WARNING,
warnType: 'LEAVERS_WARNING',
warning:
'LEAVERS data you have entered does not fall within the expected range please ensure this is correct',
column: 'LEAVERS',
}),
);
}
Similar blocks of code found in 3 locations. Consider refactoring.
if (vacancies >= totalStaff) {
csvEstablishmentSchemaErrors.unshift(
Object.assign(clonedeep(template), {
warnCode: WorkplaceCSVValidator.VACANCIES_WARNING,
warnType: 'VACANCIES_WARNING',
warning:
'VACANCIES data you have entered does not fall within the expected range please ensure this is correct',
column: 'VACANCIES',
}),
);
}
}
}
 
Function `_validateAllJobs` has 66 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateAllJobs` has a Cognitive Complexity of 12 (exceeds 5 allowed). Consider refactoring.
_validateAllJobs() {
// optional
const allJobs = this._currentLine.ALLJOBROLES ? this._currentLine.ALLJOBROLES.split(';') : [];
const localValidationErrors = [];
const vacancies = this._currentLine.VACANCIES.split(';');
const starters = this._currentLine.STARTERS.split(';');
const leavers = this._currentLine.LEAVERS.split(';');
const myRegType = parseInt(this._currentLine.REGTYPE, 10);
 
const isCQCRegulated = myRegType === 2;
 
Identical blocks of code found in 2 locations. Consider refactoring.
const hasRegisteredManagerVacancy = () => {
let regManagerVacancies = 0;
allJobs.map((job, index) => {
if (parseInt(job, 10) === regManager && parseInt(vacancies[index], 10) > 0) regManagerVacancies++;
});
return regManagerVacancies > 0;
};
 
// allJobs can only be empty, if TOTALPERMTEMP is 0
if (!this._currentLine.ALLJOBROLES || this._currentLine.ALLJOBROLES.length === 0) {
Similar blocks of code found in 12 locations. Consider refactoring.
if (
[]
.concat(vacancies)
.concat(starters)
.concat(leavers)
.findIndex((item) => {
item = parseInt(item, 10);
 
return Number.isInteger(item) && item > 0 && item !== 999;
}) !== -1
) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_JOBS_ERROR,
errType: 'ALL_JOBS_ERROR',
error: 'ALLJOBROLES cannot be blank as you have STARTERS, LEAVERS, VACANCIES greater than zero',
source: this._currentLine.ALLJOBROLES,
column: 'ALLJOBROLES',
name: this._currentLine.LOCALESTID,
});
}
} else if (this._currentLine.ALLJOBROLES && this._currentLine.ALLJOBROLES.length > 0) {
// all jobs are integers
const isValid = allJobs.every((thisJob) => !Number.isNaN(parseInt(thisJob, 10)));
Similar blocks of code found in 12 locations. Consider refactoring.
if (!isValid) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_JOBS_ERROR,
errType: 'ALL_JOBS_ERROR',
error: 'All Job Roles (ALLJOBROLES) must be whole numbers',
source: this._currentLine.ALLJOBROLES,
column: 'ALLJOBROLES',
name: this._currentLine.LOCALESTID,
});
}
Similar blocks of code found in 12 locations. Consider refactoring.
if (!isCQCRegulated && hasRegisteredManagerVacancy()) {
localValidationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.ALL_JOBS_WARNING,
warnType: 'ALL_JOBS_WARNING',
warning: 'Vacancy for Registered Manager should not be included for this service and will be ignored',
source: this._currentLine.ALLJOBROLES,
column: 'VACANCY',
name: this._currentLine.LOCALESTID,
});
}
}
 
// Need to add if they currently have a registered manager
// if (this._currentLine.ALLJOBROLES && this._currentLine.ALLJOBROLES.length > 0 && isCQCRegulated && !hasRegisteredManagerVacancy()) {
// localValidationErrors.push({
// lineNumber: this._lineNumber,
// errCode: WorkplaceCSVValidator.ALL_JOBS_ERROR,
// errType: 'ALL_JOBS_ERROR',
// error: 'You do not have a staff record for a Registered Manager therefore must record a vacancy for one',
// source: this._currentLine.ALLJOBROLES,
// name: this._currentLine.LOCALESTID
// });
// }
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
 
this._alljobs = allJobs.map((thisJob) => parseInt(thisJob, 10));
 
return true;
}
 
Function `_crossValidateAllJobRoles` has 28 lines of code (exceeds 25 allowed). Consider refactoring.
_crossValidateAllJobRoles(csvEstablishmentSchemaErrors, registeredManager) {
const template = {
origin: 'Establishments',
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_JOBS_ERROR,
errType: 'ALL_JOBS_ERROR',
source: this._currentLine.ALLJOBROLES,
name: this._currentLine.LOCALESTID,
};
const allJobs = this._currentLine.ALLJOBROLES.split(';');
const vacancies = this._currentLine.VACANCIES.split(';');
const myRegType = parseInt(this._currentLine.REGTYPE, 10);
 
const isCQCRegulated = myRegType === 2;
const notHeadOffice = this._currentLine.MAINSERVICE !== '72'; // Head Office ID
 
Identical blocks of code found in 2 locations. Consider refactoring.
const hasRegisteredManagerVacancy = () => {
let regManagerVacancies = 0;
allJobs.map((job, index) => {
if (parseInt(job, 10) === regManager && parseInt(vacancies[index], 10) > 0) regManagerVacancies++;
});
return regManagerVacancies > 0;
};
 
if (isCQCRegulated && !hasRegisteredManagerVacancy() && registeredManager === 0 && notHeadOffice) {
csvEstablishmentSchemaErrors.unshift(
Object.assign(template, {
error: 'You do not have a staff record for a Registered Manager therefore must record a vacancy for one',
column: 'VACANCY',
}),
);
}
}
 
// includes perm, temp, pool, agency, student, voluntary and other counts
// includes vacancies, starters and leavers, total vacancies, total starters and total leavers
Function `_validateJobRoleTotals` has 131 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateJobRoleTotals` has a Cognitive Complexity of 26 (exceeds 5 allowed). Consider refactoring.
_validateJobRoleTotals() {
// mandatory
const vacancies = this._currentLine.VACANCIES.split(';');
const starters = this._currentLine.STARTERS.split(';');
const leavers = this._currentLine.LEAVERS.split(';');
const localValidationErrors = [];
const allJobsCount = this._alljobs ? this._alljobs.length : 0;
const DONT_KNOW = '999'; // MUST BE A STRING VALUE!!!!!
const NONE = '0';
 
if (allJobsCount === 0) {
// no jobs defined, so ignore starters, leavers and vacancies
if (vacancies[0] === DONT_KNOW) {
this._vacancies = [parseInt(DONT_KNOW)];
} else if (vacancies[0] === NONE) {
this._vacancies = [parseInt(NONE)];
}
Similar blocks of code found in 2 locations. Consider refactoring.
if (starters[0] === DONT_KNOW) {
this._starters = [parseInt(DONT_KNOW)];
} else if (starters[0] === NONE) {
this._starters = [parseInt(NONE)];
}
Similar blocks of code found in 2 locations. Consider refactoring.
if (leavers[0] === DONT_KNOW) {
this._leavers = [parseInt(DONT_KNOW)];
} else if (leavers[0] === NONE) {
this._leavers = [parseInt(NONE)];
}
return true;
}
 
// all counts must have the same number of entries as all job roles
// - except starters, leavers and vacancies can be a single value of 999
 
Similar blocks of code found in 6 locations. Consider refactoring.
if (!((vacancies.length === 1 && vacancies[0] === DONT_KNOW) || vacancies.length === allJobsCount)) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.VACANCIES_ERROR,
errType: 'VACANCIES_ERROR',
error: 'ALLJOBROLES and VACANCIES do not have the same number of items (i.e. numbers and/or semi colons).',
source: `${this._currentLine.VACANCIES} - ${this._currentLine.ALLJOBROLES}`,
column: 'ALLJOBROLES/VACANCIES',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 6 locations. Consider refactoring.
if (!((starters.length === 1 && starters[0] === DONT_KNOW) || starters.length === allJobsCount)) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.STARTERS_ERROR,
errType: 'STARTERS_ERROR',
error: 'ALLJOBROLES and STARTERS do not have the same number of items (i.e. numbers and/or semi colons).',
source: `${this._currentLine.STARTERS} - ${this._currentLine.ALLJOBROLES}`,
column: 'ALLJOBROLES/STARTERS',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 6 locations. Consider refactoring.
if (!((leavers.length === 1 && leavers[0] === DONT_KNOW) || leavers.length === allJobsCount)) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.LEAVERS_ERROR,
errType: 'LEAVERS_ERROR',
error: 'ALLJOBROLES and LEAVERS do not have the same number of items (i.e. numbers and/or semi colons).',
source: `${this._currentLine.LEAVERS} - ${this._currentLine.ALLJOBROLES}`,
column: 'ALLJOBROLES/LEAVERS',
name: this._currentLine.LOCALESTID,
});
}
 
// all counts must be integers and greater than/equal to zero
const MIN_COUNT = 0;
const MAX_COUNT = 999;
 
Similar blocks of code found in 3 locations. Consider refactoring.
if (
!vacancies.every(
(thisCount) =>
!Number.isNaN(parseInt(thisCount, 10)) &&
parseInt(thisCount, 10) >= MIN_COUNT &&
parseInt(thisCount, 10) <= MAX_COUNT,
)
) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.VACANCIES_ERROR,
errType: 'VACANCIES_ERROR',
error: `Vacancies (VACANCIES) values must be whole numbers and ${MIN_COUNT} or more but less than ${MAX_COUNT}`,
source: `${this._currentLine.VACANCIES}`,
column: 'VACANCIES',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 3 locations. Consider refactoring.
if (
!starters.every(
(thisCount) =>
!Number.isNaN(parseInt(thisCount, 10)) &&
parseInt(thisCount, 10) >= MIN_COUNT &&
parseInt(thisCount, 10) <= MAX_COUNT,
)
) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.STARTERS_ERROR,
errType: 'STARTERS_ERROR',
error: `Starters (STARTERS) values must be whole numbers and ${MIN_COUNT} or more but less than ${MAX_COUNT}`,
source: `${this._currentLine.STARTERS}`,
column: 'STARTERS',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 3 locations. Consider refactoring.
if (
!leavers.every(
(thisCount) =>
!Number.isNaN(parseInt(thisCount, 10)) &&
parseInt(thisCount, 10) >= MIN_COUNT &&
parseInt(thisCount, 10) <= MAX_COUNT,
)
) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.LEAVERS_ERROR,
errType: 'LEAVERS_ERROR',
error: `Leavers (LEAVERS) values must be whole numbers and ${MIN_COUNT} or more but less than ${MAX_COUNT}`,
source: `${this._currentLine.LEAVERS}`,
column: 'LEAVERS',
name: this._currentLine.LOCALESTID,
});
}
 
Identical blocks of code found in 8 locations. Consider refactoring.
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
 
this._vacancies = vacancies.map((thisCount) => parseInt(thisCount, 10));
this._starters = starters.map((thisCount) => parseInt(thisCount, 10));
this._leavers = leavers.map((thisCount) => parseInt(thisCount, 10));
 
// remove RM vacancy
if (this._allJobs && this._allJobs.length) {
this._allJobs.map((job, index) => {
if (job === regManager && this._vacancies[index] > 0) this._vacancies[index] = 0;
});
}
 
Identical blocks of code found in 8 locations. Consider refactoring.
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
 
return true;
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
_validateRepeatTraining() {
const ALLOWED_VALUES = ['1', '2', '3', '4', ''];
 
if (!ALLOWED_VALUES.includes(this._currentLine.REPEATTRAINING)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.REPEAT_TRAINING_WARNING,
warnType: 'REPEAT_TRAINING_WARNING',
warning: 'The code you have entered for REPEATTRAINING is incorrect and will be ignored',
source: this._currentLine.REPEATTRAINING,
column: 'REPEATTRAINING',
name: this._currentLine.LOCALESTID,
});
return false;
} else {
const repeatTrainingAsInt = parseInt(this._currentLine.REPEATTRAINING, 10);
 
this._doNewStartersRepeatMandatoryTrainingFromPreviousEmployment = Number.isNaN(repeatTrainingAsInt)
? this._currentLine.REPEATTRAINING
: repeatTrainingAsInt;
return true;
}
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
_validateAcceptCareCertificate() {
const ALLOWED_VALUES = ['1', '2', '3', '4', ''];
 
if (!ALLOWED_VALUES.includes(this._currentLine.ACCEPTCARECERT)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.ACCEPT_CARE_CERT_WARNING,
warnType: 'ACCEPT_CARE_CERT_WARNING',
warning: 'The code you have entered for ACCEPTCARECERT is incorrect and will be ignored',
source: this._currentLine.ACCEPTCARECERT,
column: 'ACCEPTCARECERT',
name: this._currentLine.LOCALESTID,
});
return false;
} else {
const acceptCareCertAsInt = parseInt(this._currentLine.ACCEPTCARECERT, 10);
 
this._wouldYouAcceptCareCertificatesFromPreviousEmployment = Number.isNaN(acceptCareCertAsInt)
? this._currentLine.ACCEPTCARECERT
: acceptCareCertAsInt;
return true;
}
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
_validateInterviews() {
const interviewsRegex = /^[0-9]*$/;
const interviews = this._currentLine.INTERVIEWS;
 
if (!interviewsRegex.test(interviews) && interviews.toLowerCase() !== 'unknown') {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.INTERVIEWS_WARNING,
warnType: 'INTERVIEWS_WARNING',
warning:
"The value you entered for INTERVIEWS should be a whole number or the value 'unknown' and will be ignored",
source: interviews,
column: 'INTERVIEWS',
name: this.currentLine.LOCALESTID,
});
return false;
} else {
this._peopleInterviewedInTheLastFourWeeks = interviews;
return true;
}
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
_validateAdvertising() {
const advertisingRegex = /^\d*(\.\d{1,2})?$/;
const advertising = this._currentLine.ADVERTISING;
 
if (!advertisingRegex.test(advertising) && advertising.toLowerCase() !== 'unknown') {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.ADVERTISING_WARNING,
warnType: 'ADVERTISING_WARNING',
warning:
"The value you entered for ADVERTISING should be a number in pounds and pence or the value 'unknown' and will be ignored",
source: advertising,
column: 'ADVERTISING',
name: this.currentLine.LOCALESTID,
});
return false;
} else {
this._moneySpentOnAdvertisingInTheLastFourWeeks = advertising;
return true;
}
}
 
_validateBenefits() {
const benefitsRegex = /^\d*(\.\d{1,2})?$/;
const benefits = this._currentLine.BENEFITS.split(';').join('');
 
if (!benefitsRegex.test(benefits) && benefits.toLowerCase() !== 'unknown') {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.BENEFITS_WARNING,
warnType: 'BENEFITS_WARNING',
warning: 'The code you have entered for BENEFITS is incorrect and will be ignored',
source: benefits,
column: 'BENEFITS',
name: this.currentLine.LOCALESTID,
});
return false;
} else {
this._careWorkersCashLoyaltyForFirstTwoYears = this._currentLine.BENEFITS;
 
return true;
}
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
_validateSickPay() {
const ALLOWED_VALUES = ['0', '1', ''];
const sickpay = this._currentLine.SICKPAY;
 
if (!ALLOWED_VALUES.includes(this._currentLine.SICKPAY) && sickpay.toLowerCase() !== 'unknown') {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.SICKPAY_WARNING,
warnType: 'SICKPAY_WARNING',
warning: 'The code you have entered for SICKPAY is incorrect and will be ignored',
source: this._currentLine.SICKPAY,
column: 'SICKPAY',
name: this._currentLine.LOCALESTID,
});
return false;
} else {
const sickPayAsInt = parseInt(this._currentLine.SICKPAY, 10);
 
this._sickPay = Number.isNaN(sickPayAsInt) ? this._currentLine.SICKPAY : sickPayAsInt;
return true;
}
}
 
_validateHoliday() {
const holidayRegex = /^[0-9]*$/;
const holiday = this._currentLine.HOLIDAY;
 
if (!holidayRegex.test(holiday)) {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.HOLIDAY_WARNING,
warnType: 'HOLIDAY_WARNING',
warning: 'The code you have entered for HOLIDAY is incorrect and will be ignored',
source: this._currentLine.HOLIDAY,
column: 'HOLIDAY',
name: this._currentLine.LOCALESTID,
});
return false;
} else {
this._careWorkersLeaveDaysPerYear = holiday;
return true;
}
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
_validatePensionContribution() {
const ALLOWED_VALUES = ['0', '1', ''];
const pension = this._currentLine.PENSION;
 
if (!ALLOWED_VALUES.includes(this._currentLine.PENSION) && pension.toLowerCase() !== 'unknown') {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.PENSION_WARNING,
warnType: 'PENSION_WARNING',
warning: 'The code you have entered for PENSION is incorrect and will be ignored',
source: this._currentLine.PENSION,
column: 'PENSION',
name: this._currentLine.LOCALESTID,
});
return false;
} else {
const pensionAsInt = parseInt(this._currentLine.PENSION, 10);
 
this._pensionContribution = Number.isNaN(pensionAsInt) ? this._currentLine.PENSION : pensionAsInt;
return true;
}
}
 
Function `_validateNoChange` has 37 lines of code (exceeds 25 allowed). Consider refactoring.
_validateNoChange() {
let localValidationErrors = [];
var thisEstablishment = this._allCurrentEstablishments.find(
(establishment) =>
establishment.localIdentifier.replace(/\s/g, '') === this._currentLine.LOCALESTID.replace(/\s/g, ''),
);
const startersSavedAt = moment(thisEstablishment._properties.get('Starters').savedAt);
 
const starterWarning = this._getStartersNoChangeWarning();
localValidationErrors = this._startersLeaverVacanciesWarnings(
thisEstablishment.starters,
this.starters,
startersSavedAt,
localValidationErrors,
starterWarning,
);
 
const leaversSavedAt = moment(thisEstablishment._properties.get('Leavers').savedAt);
const leaverWarning = this._getLeaversNoChangeWarning();
localValidationErrors = this._startersLeaverVacanciesWarnings(
thisEstablishment.leavers,
this.leavers,
leaversSavedAt,
localValidationErrors,
leaverWarning,
);
 
const vacanciesSavedAt = moment(thisEstablishment._properties.get('Vacancies').savedAt);
const vacanciesWarning = this._getVacanciesNoChangeWarning();
localValidationErrors = this._startersLeaverVacanciesWarnings(
thisEstablishment.vacancies,
this.vacancies,
vacanciesSavedAt,
localValidationErrors,
vacanciesWarning,
);
 
Identical blocks of code found in 8 locations. Consider refactoring.
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
return true;
}
 
Function `_startersLeaverVacanciesWarnings` has a Cognitive Complexity of 26 (exceeds 5 allowed). Consider refactoring.
Function `_startersLeaverVacanciesWarnings` has 26 lines of code (exceeds 25 allowed). Consider refactoring.
_startersLeaverVacanciesWarnings(dbValues, buValues, savedAt, localValidationErrors, warning) {
if (!savedAt.isSame(Date.now(), 'day')) {
if (!Array.isArray(this.allJobs)) return localValidationErrors;
let isSame = true;
for (var i = 0; i < this.allJobs.length; i++) {
const mappedRole = BUDI.jobRoles(BUDI.TO_ASC, parseInt(this.allJobs[i]));
const buValue = buValues && buValues[i] ? buValues[i] : null;
if (dbValues && Array.isArray(dbValues) && dbValues.length > 0) {
const starterJob = dbValues.find((job) => job.jobId === mappedRole);
 
if ((starterJob && starterJob.total !== buValue) || (!starterJob && buValue > 0)) {
isSame = false;
break;
}
} else {
if (buValue > 0) {
isSame = false;
break;
}
}
}
if (this.allJobs && this.allJobs.length === 0 && dbValues && Array.isArray(dbValues) && dbValues.length > 0)
isSame = false;
if (isSame) {
localValidationErrors.push(warning);
}
}
return localValidationErrors;
}
 
Similar blocks of code found in 3 locations. Consider refactoring.
_getStartersNoChangeWarning() {
return {
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.STARTERS_WARNING,
warnType: 'STARTERS_WARNING',
warning: 'STARTERS in the last 12 months has not changed please check this is correct',
source: this.starters,
column: 'STARTERS',
name: this._currentLine.LOCALESTID,
};
}
Similar blocks of code found in 3 locations. Consider refactoring.
_getVacanciesNoChangeWarning() {
return {
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.VACANCIES_WARNING,
warnType: 'VACANCIES_WARNING',
warning: 'VACANCIES value has not changed please check this is correct',
source: this.vacancies,
column: 'VACANCIES',
name: this._currentLine.LOCALESTID,
};
}
Similar blocks of code found in 3 locations. Consider refactoring.
_getLeaversNoChangeWarning() {
return {
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.LEAVERS_WARNING,
warnType: 'LEAVERS_WARNING',
warning: 'LEAVERS in the last 12 months has not changed please check this is correct',
source: this.leavers,
column: 'LEAVERS',
name: this._currentLine.LOCALESTID,
};
}
 
Function `_validateReasonsForLeaving` has 85 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_validateReasonsForLeaving` has a Cognitive Complexity of 16 (exceeds 5 allowed). Consider refactoring.
_validateReasonsForLeaving() {
// only if the sum of "LEAVERS" is greater than 0
const sumOfLeavers =
this._leavers && Array.isArray(this._leavers) && this._leavers[0] !== 999
? this._leavers.reduce((total, thisCount) => total + thisCount)
: 0;
 
if (sumOfLeavers > 0 && this._currentLine.REASONS && this._currentLine.REASONS.length > 0) {
const allReasons = this._currentLine.REASONS.split(';');
const allReasonsCounts = this._currentLine.REASONNOS.split(';');
 
const localValidationErrors = [];
 
if (!allReasons.every((thisCount) => !Number.isNaN(parseInt(thisCount, 10)))) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REASONS_FOR_LEAVING_ERROR,
errType: 'REASONS_FOR_LEAVING_ERROR',
error: 'The REASONS you have supplied has an incorrect code',
source: `${this._currentLine.REASONS}`,
column: 'REASONS',
name: this._currentLine.LOCALESTID,
});
}
 
Similar blocks of code found in 12 locations. Consider refactoring.
if (!allReasonsCounts || allReasonsCounts.length === 0) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REASONS_FOR_LEAVING_ERROR,
errType: 'REASONS_FOR_LEAVING_ERROR',
error: 'REASONS/REASONNOS do not have the same number of items (i.e. numbers and/or semi colons)',
source: this._currentLine.REASONNOS,
column: 'REASONS/REASONNOS',
name: this._currentLine.LOCALESTID,
});
}
 
const MIN_COUNT = 0;
 
if (
!allReasonsCounts.every(
(thisCount) => !Number.isNaN(parseInt(thisCount, 10)) || parseInt(thisCount, 10) < MIN_COUNT,
)
) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REASONS_FOR_LEAVING_ERROR,
errType: 'REASONS_FOR_LEAVING_ERROR',
error: `Reasons for Leaving Counts (REASONNOS) values must be whole numbers and ${MIN_COUNT} or more`,
source: `${this._currentLine.REASONNOS}`,
column: 'REASONNOS',
name: this._currentLine.LOCALESTID,
});
}
 
// all reasons and all reasons counts must be equal in number
Similar blocks of code found in 6 locations. Consider refactoring.
if (allReasons.length !== allReasonsCounts.length) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REASONS_FOR_LEAVING_ERROR,
errType: 'REASONS_FOR_LEAVING_ERROR',
error: 'REASONS/REASONNOS do not have the same number of items (i.e. numbers and/or semi colons)',
source: `${this._currentLine.REASON} - ${this._currentLine.REASONNOS}`,
column: 'REASONS/REASONNOS',
name: this._currentLine.LOCALESTID,
});
}
 
// sum of all reasons counts must equal the sum of leavers
const sumOfReasonsCounts = allReasonsCounts.reduce(
(total, thisCount) => parseInt(total, 10) + parseInt(thisCount, 10),
);
 
if (parseInt(sumOfReasonsCounts) !== parseInt(sumOfLeavers)) {
localValidationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REASONS_FOR_LEAVING_ERROR,
errType: 'REASONS_FOR_LEAVING_ERROR',
error: 'The total number of REASONNOS you have entered does not equal the total number of LEAVERS',
source: `${this._currentLine.REASONNOS} (${sumOfReasonsCounts}) - ${this._currentLine.LEAVERS} (${sumOfLeavers})`,
column: 'REASONNOS/LEAVERS',
name: this._currentLine.LOCALESTID,
});
}
 
Identical blocks of code found in 8 locations. Consider refactoring.
if (localValidationErrors.length > 0) {
localValidationErrors.forEach((thisValidation) => this._validationErrors.push(thisValidation));
return false;
}
 
this._reasonsForLeaving = allReasons.map((thisReason, index) => {
return {
id: parseInt(thisReason, 10),
count: parseInt(allReasonsCounts[index], 10),
};
});
 
return true;
} else {
return true;
}
}
 
Function `_transformMainService` has a Cognitive Complexity of 10 (exceeds 5 allowed). Consider refactoring.
_transformMainService() {
if (this._mainService) {
const mappedService = BUDI.services(BUDI.TO_ASC, this._mainService);
 
Similar blocks of code found in 2 locations. Consider refactoring.
if (mappedService) {
// main service can have an "other" description. That "other" description is
// given by _allServiceUsersOther, based on the position index of this main service
// within _allServices
const positionOfMainService = this._allServices ? this._allServices.indexOf(this._mainService) : -1;
 
let mainServiceOther = null;
if (positionOfMainService > -1) {
mainServiceOther = this._allServicesOther[positionOfMainService];
}
this._mainService = {
id: mappedService,
other: mainServiceOther || undefined,
};
} else {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.MAIN_SERVICE_ERROR,
errType: 'MAIN_SERVICE_ERROR',
error: 'The code you have entered for MAINSERVICE is incorrect',
source: this._currentLine.MAINSERVICE,
column: 'MAINSERVICE',
name: this._currentLine.LOCALESTID,
});
}
}
}
 
_transformAllServices() {
if (this._allServices && Array.isArray(this._allServices)) {
const mappedServices = [];
 
this._allServices.forEach((thisService) => {
let thisMappedService = null;
if (thisService !== 0) {
thisMappedService = BUDI.services(BUDI.TO_ASC, thisService);
}
if (thisMappedService) {
mappedServices.push(thisMappedService);
Similar blocks of code found in 3 locations. Consider refactoring.
} else if (thisService == 0) {
mappedServices.push(0);
} else {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_SERVICES_ERROR,
errType: 'ALL_SERVICES_ERROR',
error: `All Services (ALLSERVICES): ${thisService} is unknown`,
source: this._currentLine.ALLSERVICES,
column: 'ALLSERVICES',
name: this._currentLine.LOCALESTID,
});
}
});
 
this._allServices = mappedServices;
}
}
 
_transformServiceUsers() {
if (this._allServiceUsers && Array.isArray(this._allServiceUsers)) {
const mappedServices = [];
 
this._allServiceUsers.forEach((thisService) => {
const thisMappedService = BUDI.serviceUsers(BUDI.TO_ASC, thisService);
 
Similar blocks of code found in 3 locations. Consider refactoring.
if (thisMappedService) {
mappedServices.push(thisMappedService);
} else {
this._validationErrors.push({
lineNumber: this._lineNumber,
warnCode: WorkplaceCSVValidator.SERVICE_USERS_ERROR,
warnType: 'SERVICE_USERS_ERROR',
warning: `Entry for code ${thisService} in SERVICEUSERS will be ignored as this is invalid`,
source: this._currentLine.SERVICEUSERS,
column: 'SERVICEUSERS',
name: this._currentLine.LOCALESTID,
});
}
});
 
this._allServiceUsers = mappedServices;
}
}
 
_transformEstablishmentType() {
// integer in source; enum in target
if (this._establishmentType) {
if (BUDI.establishmentType(BUDI.TO_ASC, this._establishmentType) === null) {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ESTABLISHMENT_TYPE_ERROR,
errType: 'ESTABLISHMENT_TYPE_ERROR',
error: `WorkplaceCSVValidator Type (ESTTYPE): ${this._establishmentType} is unknown`,
source: this._currentLine.ESTTYPE,
column: 'ESTTYPE',
name: this._currentLine.LOCALESTID,
});
}
}
}
 
Function `_transformAllCapacities` has 28 lines of code (exceeds 25 allowed). Consider refactoring.
_transformAllCapacities() {
if (this._capacities && Array.isArray(this._capacities) && this._allServices) {
const mappedCapacities = [];
 
// capacities start out as a positional array including nulls
// where the position of the capacity correlates to the service (id) in the same
// position in _allServices
this._capacities.forEach((thisCapacity, index) => {
// we're only interested in non null capacities to map
if (thisCapacity !== null) {
//if the allservices is 0 then there can only be 2 allservices
const allServiceIndex = this._allServices[index] === 0 ? 1 : index;
 
// we need to map from service id to service capacity id
const thisMappedCapacity = BUDI.capacity(BUDI.TO_ASC, this._allServices[allServiceIndex]);
 
if (thisMappedCapacity) {
mappedCapacities.push({
questionId: thisMappedCapacity,
answer: thisCapacity,
});
} else {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.CAPACITY_UTILISATION_ERROR,
errType: 'CAPACITY_UTILISATION_ERROR',
error: `Capacities (CAPACITY): position ${
index + 1
} is unexpected capacity (no expected capacity for given service: ${thisMappedCapacity})`,
source: this._currentLine.CAPACITY,
column: 'CAPACITY',
name: this._currentLine.LOCALESTID,
});
}
}
});
 
this._capacities = mappedCapacities;
}
}
 
Function `_transformAllUtilisation` has 26 lines of code (exceeds 25 allowed). Consider refactoring.
_transformAllUtilisation() {
if (this._utilisations && Array.isArray(this._utilisations) && this._allServices) {
const mappedUtilisations = [];
 
// utilsiations start out as a positional array including nulls
// where the position of the capacity correlates to the service (id) in the same
// position in _allServices
this._utilisations.forEach((thisUtilisation, index) => {
// we're only interested in non null utilisations to map
if (thisUtilisation !== null) {
// we need to map from service id to service capacity id
const serviceType = this._allServices[index];
const thisMappedUtilisation = BUDI.utilisation(BUDI.TO_ASC, serviceType);
 
Similar blocks of code found in 3 locations. Consider refactoring.
if (thisMappedUtilisation) {
mappedUtilisations.push({
questionId: thisMappedUtilisation,
answer: thisUtilisation,
});
} else {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.CAPACITY_UTILISATION_ERROR,
errType: 'CAPACITY_UTILISATION_ERROR',
error: `UTILISATION for SERVICETYPE ${serviceType} will be ignored as it is not required for this service`,
source: this._currentLine.UTILISATION,
column: 'UTILISATION',
name: this._currentLine.LOCALESTID,
});
}
}
});
 
this._utilisations = mappedUtilisations;
}
}
 
_transformAllJobs() {
if (this._alljobs && Array.isArray(this._alljobs)) {
const mappedJobs = [];
 
this._alljobs.forEach((thisJob) => {
const thisMappedJob = BUDI.jobRoles(BUDI.TO_ASC, thisJob);
 
Similar blocks of code found in 2 locations. Consider refactoring.
if (thisMappedJob) {
mappedJobs.push(thisMappedJob);
} else {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.ALL_JOBS_ERROR,
errType: 'ALL_JOBS_ERROR',
error: 'The code you have entered for ALLJOBROLES is incorrect',
source: this._currentLine.ALLJOBROLES,
column: 'ALLJOBROLES',
name: this._currentLine.LOCALESTID,
});
}
});
 
this._alljobs = mappedJobs;
}
}
 
// returns true if all given job counts are 0; otherwise returns false
_jobsAllZeros(jobs) {
if (jobs && Array.isArray(jobs)) {
return jobs.every((thisJob) => thisJob === 0);
} else {
return false;
}
}
 
Function `_transformAllVacanciesStartersLeavers` has 43 lines of code (exceeds 25 allowed). Consider refactoring.
Function `_transformAllVacanciesStartersLeavers` has a Cognitive Complexity of 9 (exceeds 5 allowed). Consider refactoring.
_transformAllVacanciesStartersLeavers() {
// vacancies, starters and leavers is either an array of counts against positional indexes to _allJobs
// or a single value of 999
 
// if a single value of 999, then map to "Don't know"
// if a full set of 0 (e.g. 0, or 0;0 or 0;0;0, ...), then map to "None"
const DONT_KNOW = 999;
 
Similar blocks of code found in 3 locations. Consider refactoring.
if (this._jobsAllZeros(this._vacancies)) {
this._vacancies = 'None';
} else if (this._vacancies && this._vacancies.length === 1 && this._vacancies[0] === DONT_KNOW) {
this._vacancies = "Don't know";
} else if (this._vacancies && Array.isArray(this._vacancies)) {
this._vacancies = this._vacancies
.map((thisJob, index) => {
return {
jobId: this._alljobs[index],
total: thisJob,
};
})
.filter((thisJob) => thisJob.total !== 0);
}
 
Similar blocks of code found in 3 locations. Consider refactoring.
if (this._jobsAllZeros(this._starters)) {
this._starters = 'None';
} else if (this._starters && this._starters.length === 1 && this._starters[0] === DONT_KNOW) {
this._starters = "Don't know";
} else if (this._starters && Array.isArray(this._starters)) {
this._starters = this._starters
.map((thisJob, index) => {
return {
jobId: this._alljobs[index],
total: thisJob,
};
})
.filter((thisJob) => thisJob.total !== 0);
}
 
Similar blocks of code found in 3 locations. Consider refactoring.
if (this._jobsAllZeros(this._leavers)) {
this._leavers = 'None';
} else if (this._leavers && this._leavers.length === 1 && this._leavers[0] === DONT_KNOW) {
this._leavers = "Don't know";
} else if (this._leavers && Array.isArray(this._leavers)) {
this._leavers = this._leavers
.map((thisJob, index) => {
return {
jobId: this._alljobs[index],
total: thisJob,
};
})
.filter((thisJob) => thisJob.total !== 0);
}
}
 
_transformReasonsForLeaving() {
if (this._reasonsForLeaving && Array.isArray(this._reasonsForLeaving)) {
const mappedReasons = [];
 
this._reasonsForLeaving.forEach((thisReason) => {
const thisMappedReason = {
id: BUDI.reasonsForLeaving(BUDI.TO_ASC, thisReason.id),
count: thisReason.count,
};
 
if (thisMappedReason.id) {
mappedReasons.push(thisMappedReason);
} else {
this._validationErrors.push({
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.REASONS_FOR_LEAVING_ERROR,
errType: 'REASONS_FOR_LEAVING_ERROR',
error: `Reason for Leaving (REASONS): ${thisReason.id} is unknown`,
source: this._currentLine.REASONS,
column: 'REASONS',
name: this._currentLine.LOCALESTID,
});
}
});
 
this._reasonsForLeaving = mappedReasons;
}
}
 
_transformRepeatTrainingAndAcceptCareCert() {
const mapping = {
1: 'Yes, always',
2: 'Yes, very often',
3: 'Yes, but not very often',
4: 'No, never',
'': null,
};
const repeatTraining = this._doNewStartersRepeatMandatoryTrainingFromPreviousEmployment;
this._doNewStartersRepeatMandatoryTrainingFromPreviousEmployment = mapping[repeatTraining];
const acceptCareCert = this._wouldYouAcceptCareCertificatesFromPreviousEmployment;
this._wouldYouAcceptCareCertificatesFromPreviousEmployment = mapping[acceptCareCert];
}
 
_transformAdvertisingAndInterviews() {
const DONT_KNOW = 'unknown';
const NONE = '0';
 
const interview = this._peopleInterviewedInTheLastFourWeeks;
const advertising = this._moneySpentOnAdvertisingInTheLastFourWeeks;
const interviewAndAdvertisingArr = [
{ name: '_peopleInterviewedInTheLastFourWeeks', value: interview },
{ name: '_moneySpentOnAdvertisingInTheLastFourWeeks', value: advertising },
];
 
interviewAndAdvertisingArr.forEach((property) => {
if (!property.value) {
this[property.name] = null;
} else if (property.value.toLowerCase() === DONT_KNOW) {
this[property.name] = "Don't know";
} else if (property.value === NONE) {
this[property.name] = 'None';
}
});
}
 
Function `_transformCashLoyaltyForFirstTwoYears` has a Cognitive Complexity of 7 (exceeds 5 allowed). Consider refactoring.
_transformCashLoyaltyForFirstTwoYears() {
const YES = '1';
const YES_COMMA = '1;';
const NO = '0';
const DONT_KNOW = 'unknown';
 
const benefit = this._careWorkersCashLoyaltyForFirstTwoYears;
 
if (benefit !== null) {
if (benefit === YES) {
this._careWorkersCashLoyaltyForFirstTwoYears = 'Yes';
} else if (benefit === YES_COMMA) {
this._careWorkersCashLoyaltyForFirstTwoYears = 'Yes';
} else if (benefit === NO) {
this._careWorkersCashLoyaltyForFirstTwoYears = 'No';
} else if (benefit.toLowerCase() === DONT_KNOW) {
this._careWorkersCashLoyaltyForFirstTwoYears = "Don't know";
} else if (benefit.includes(';')) {
this._careWorkersCashLoyaltyForFirstTwoYears = benefit.split(';')[1];
}
}
}
 
_transformPensionAndSickPay() {
const mapping = {
0: 'No',
1: 'Yes',
unknown: "Don't know",
'': null,
};
 
const sickPay = this._sickPay && this._sickPay.toString().toLowerCase();
this._sickPay = mapping[sickPay];
const pension = this._pensionContribution && this._pensionContribution.toString().toLowerCase();
this._pensionContribution = mapping[pension];
}
 
preValidate(headers) {
return this._validateHeaders(headers);
}
 
static isContent(data) {
const contentRegex = /LOCALESTID,STATUS,ESTNAME,ADDRESS1,ADDRESS2,ADDRES/;
return contentRegex.test(data.substring(0, 50));
}
 
_validateHeaders(headers) {
// only run once for first line, so check _lineNumber
if (_headers_v1 !== headers) {
this._validationErrors.push({
lineNumber: 1,
errCode: WorkplaceCSVValidator.HEADERS_ERROR,
errType: 'HEADERS_ERROR',
error: `WorkplaceCSVValidator headers (HEADERS) can contain, ${_headers_v1.split(',')}`,
source: headers,
column: '',
name: this._currentLine.LOCALESTID,
});
return false;
}
return true;
}
 
// add a duplicate validation error to the current set
Similar blocks of code found in 3 locations. Consider refactoring.
addDuplicate() {
return {
origin: 'Establishments',
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.DUPLICATE_ERROR,
errType: 'DUPLICATE_ERROR',
error: 'LOCALESTID is not unique',
source: this._currentLine.LOCALESTID,
column: 'LOCALESTID',
name: this._currentLine.LOCALESTID,
};
}
 
// add a duplicate validation error to the current set
Similar blocks of code found in 3 locations. Consider refactoring.
addNotOwner() {
return {
origin: 'Establishments',
lineNumber: this._lineNumber,
errCode: WorkplaceCSVValidator.NOT_OWNER_ERROR,
errType: 'NOT_OWNER_ERROR',
error: 'Not the owner',
source: this._currentLine.LOCALESTID,
column: '',
name: this._currentLine.LOCALESTID,
};
}
 
static justOneEstablishmentError() {
return {
origin: 'Establishments',
lineNumber: 1,
errCode: WorkplaceCSVValidator.EXPECT_JUST_ONE_ERROR,
errType: 'EXPECT_JUST_ONE_ERROR',
error: 'Expect just one establishment',
source: '',
column: 'LOCALESTID',
};
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
static missingPrimaryEstablishmentError(name) {
return {
origin: 'Establishments',
lineNumber: 1,
errCode: WorkplaceCSVValidator.MISSING_PRIMARY_ERROR,
errType: 'MISSING_PRIMARY_ERROR',
error: `Missing the primary establishment: ${name}`,
source: '',
column: 'LOCALESTID',
name,
};
}
 
Similar blocks of code found in 2 locations. Consider refactoring.
static cannotDeletePrimaryEstablishmentError(name) {
return {
origin: 'Establishments',
lineNumber: 1,
errCode: WorkplaceCSVValidator.CANNOT_DELETE_PRIMARY_ERROR,
errType: 'CANNOT_DELETE_PRIMARY_ERROR',
error: `STATUS cannot be DELETE for primary establishment: ${name}`,
source: '',
column: 'STATUS',
name,
};
}
 
// returns true on success, false is any attribute of WorkplaceCSVValidator fails
Function `validate` has 29 lines of code (exceeds 25 allowed). Consider refactoring.
async validate() {
this._validateLocalisedId();
this._validateEstablishmentName();
this._validateStatus();
 
// if the status is unchecked or deleted, then don't continue validation
if (!STOP_VALIDATING_ON.includes(this._status)) {
await this._validateAddress();
this._validateEstablishmentType();
 
this._validateShareWithCQC();
this._validateShareWithLA();
 
this._validateMainService();
this._validateRegType();
this._validateProvID();
await this._validateLocationID();
 
this._validateAllServices();
this._validateServiceUsers();
this._validateCapacitiesAndUtilisations();
 
this._validateTotalPermTemp();
this._validateAllJobs();
this._validateJobRoleTotals();
 
this._validateReasonsForLeaving();
this._validateAdvertising();
this._validateInterviews();
this._validateRepeatTraining();
this._validateAcceptCareCertificate();
this._validateSickPay();
this._validateHoliday();
this._validatePensionContribution();
this._validateBenefits();
 
// this._validateNoChange(); // Not working, disabled for LA Window
}
 
return this.validationErrors.length === 0;
}
 
// Adds items to csvEstablishmentSchemaErrors if validations that depend on
// worker totals give errors or warnings
Function `crossValidate` has 42 lines of code (exceeds 25 allowed). Consider refactoring.
async crossValidate(csvEstablishmentSchemaErrors, myJSONWorkers) {
// if establishment isn't being added or updated then exit early
if (!['NEW', 'UPDATE', 'NOCHANGE'].includes(this._status)) {
return;
}
 
const totals = {
directCareWorkers: 0,
managerialProfessionalWorkers: 0,
employedWorkers: 0,
nonEmployedWorkers: 0,
};
 
let registeredManagers = 0;
 
const dataInCSV = ['NEW', 'UPDATE', 'CHGSUB']; //For theses statuses trust the data in the CSV
 
myJSONWorkers.forEach((worker) => {
if (this.key === worker.establishmentKey && dataInCSV.includes(worker.status)) {
/* update totals */
if (isPerm(worker)) {
totals.employedWorkers++;
} else {
totals.nonEmployedWorkers++;
}
/* update registeredManagers */
registeredManagers += isRegManager(worker) ? 1 : 0;
}
});
 
// get all the other records that may already exist in the db but aren't being updated or deleted
// and check how many registered managers there is
const dataInDB = ['UNCHECKED', 'NOCHANGE']; // for theses statuses trust the data in the DB
 
const establishmentWorkers = await Establishment.fetchMyEstablishmentsWorkers(this.id, this._key);
 
establishmentWorkers.forEach((worker) => {
let workerFromCSV = myJSONWorkers.find((w) => {
return w.uniqueWorkerId === worker.uniqueWorker;
});
if (workerFromCSV && dataInDB.includes(workerFromCSV._status)) {
worker.contractTypeId = BUDI.contractType(BUDI.FROM_ASC, worker.contractTypeId);
worker.otherJobIds = worker.otherJobIds.length ? worker.otherJobIds.split(';') : [];
worker.otherJobIds.map((otherJobId) => BUDI.jobRoles(BUDI.FROM_ASC, otherJobId));
worker.mainJobRoleId = BUDI.jobRoles(BUDI.FROM_ASC, worker.mainJobRoleId);
if (isPerm(worker)) {
totals.employedWorkers++;
} else {
totals.nonEmployedWorkers++;
}
registeredManagers += isRegManager(worker) ? 1 : 0;
}
});
 
this._crossValidateTotalPermTemp(csvEstablishmentSchemaErrors, totals);
this._crossValidateAllJobRoles(csvEstablishmentSchemaErrors, registeredManagers);
}
 
// returns true on success, false is any attribute of WorkplaceCSVValidator fails
Function `transform` has a Cognitive Complexity of 26 (exceeds 5 allowed). Consider refactoring.
transform() {
// if the status is unchecked or deleted, then don't transform
if (!STOP_VALIDATING_ON.includes(this._status)) {
let status = true;
 
status = !this._transformMainService() ? false : status;
status = !this._transformEstablishmentType() ? false : status;
status = !this._transformAllServices() ? false : status;
status = !this._transformServiceUsers() ? false : status;
status = !this._transformAllJobs() ? false : status;
// status = !this._transformReasonsForLeaving() ? false : status; // interim solution - not transforming reasons for leaving
status = !this._transformAllCapacities() ? false : status;
status = !this._transformAllUtilisation() ? false : status;
status = !this._transformAllVacanciesStartersLeavers() ? false : status;
status = !this._transformAdvertisingAndInterviews() ? false : status;
status = !this._transformRepeatTrainingAndAcceptCareCert() ? false : status;
status = !this._transformCashLoyaltyForFirstTwoYears() ? false : status;
status = !this._transformPensionAndSickPay() ? false : status;
return status;
} else {
return true;
}
}
 
Function `toJSON` has 49 lines of code (exceeds 25 allowed). Consider refactoring.
Function `toJSON` has a Cognitive Complexity of 12 (exceeds 5 allowed). Consider refactoring.
toJSON() {
return {
status: this._status,
name: this._name,
address1: this._address1,
address2: this._address2,
address3: this._address3,
town: this._town,
postcode: this._postcode,
employerType: this.establishmentType,
employerTypeOther: this._establishmentTypeOther ? this._establishmentTypeOther : undefined,
shareWithCQC: this._shareWithCqc,
shareWithLA: this._shareWithLA,
regType: this._regType,
locationId: this._regType ? this._locationID : undefined,
provId: this._regType ? this._provID : undefined,
mainService: this._mainService,
Similar blocks of code found in 2 locations. Consider refactoring.
allServices: this._allServices
? this._allServices.map((thisService, index) => {
const returnThis = {
id: thisService,
};
 
if (this._allServicesOther[index]) {
returnThis.other = this._allServicesOther[index];
}
 
return returnThis;
})
: undefined,
Similar blocks of code found in 2 locations. Consider refactoring.
serviceUsers: this._allServiceUsers
? this._allServiceUsers.map((thisService, index) => {
const returnThis = {
id: thisService,
};
 
if (this._allServiceUsersOther[index]) {
returnThis.other = this._allServiceUsersOther[index];
}
 
return returnThis;
})
: undefined,
capacities: this._capacities,
utilisations: this._utilisations,
totalPermTemp: this._totalPermTemp,
 
allJobs: this._alljobs,
counts: {
vacancies: this._vacancies,
starters: this._starters,
leavers: this._leavers,
reasonsForLeaving: this._reasonsForLeaving ? this._reasonsForLeaving : undefined,
},
};
}
 
get validationErrors() {
// include the "origin" of validation error
return this._validationErrors.map((thisValidation) => {
return {
origin: 'Establishments',
...thisValidation,
};
});
}
 
// returns an API representation of this WorkplaceCSVValidator
Function `toAPI` has a Cognitive Complexity of 31 (exceeds 5 allowed). Consider refactoring.
Function `toAPI` has 107 lines of code (exceeds 25 allowed). Consider refactoring.
toAPI() {
const fixedProperties = {
address1: this._address1 ? this._address1 : '',
address2: this._address2 ? this._address2 : '',
address3: this._address3 ? this._address3 : '',
town: this._town ? this._town : '',
postcode: this._postcode ? this._postcode : '',
locationId: this._regType ? this._locationID : undefined,
provId: this._regType ? this._provID : undefined,
isCQCRegulated: this._regType === 2,
};
 
// interim solution for reasons for leaving
if (this._reasonsForLeaving && Array.isArray(this._reasonsForLeaving)) {
fixedProperties.reasonsForLeaving = this._reasonsForLeaving
.map((thisReason) => `${thisReason.id}:${thisReason.count}`)
.join('|');
} else {
fixedProperties.reasonsForLeaving = ''; // reset
}
 
const changeProperties = {
status: this._status,
name: this._name,
localIdentifier: this._localId,
isRegulated: this._regType === 2,
employerType: {
value: this.establishmentType,
other: this._establishmentTypeOther ? this._establishmentTypeOther : undefined,
},
mainService: this._mainService,
services: {
value: null,
},
serviceUsers: this._allServiceUsers
? this._allServiceUsers.map((thisService, index) => {
const returnThis = {
id: thisService,
};
 
if (this._allServiceUsersOther[index]) {
returnThis.other = this._allServiceUsersOther[index];
}
 
return returnThis;
})
: [],
numberOfStaff: this._totalPermTemp,
vacancies: this._vacancies,
starters: this._starters,
leavers: this._leavers,
doNewStartersRepeatMandatoryTrainingFromPreviousEmployment:
this._doNewStartersRepeatMandatoryTrainingFromPreviousEmployment,
moneySpentOnAdvertisingInTheLastFourWeeks: this._moneySpentOnAdvertisingInTheLastFourWeeks,
peopleInterviewedInTheLastFourWeeks: this._peopleInterviewedInTheLastFourWeeks,
wouldYouAcceptCareCertificatesFromPreviousEmployment: this._wouldYouAcceptCareCertificatesFromPreviousEmployment,
careWorkersCashLoyaltyForFirstTwoYears: this._careWorkersCashLoyaltyForFirstTwoYears,
sickPay: this._sickPay,
pensionContribution: this._pensionContribution,
careWorkersLeaveDaysPerYear: this._careWorkersLeaveDaysPerYear,
};
if (this._allServices) {
if (this._allServices.length === 1) {
changeProperties.services.value = null;
} else if (this._allServices.includes(0)) {
changeProperties.services.value = 'No';
} else if (this._allServices.length > 1) {
changeProperties.services = {
value: 'Yes',
services: this._allServices
.filter((thisService) => (this._mainService ? this._mainService.id !== thisService : true)) // main service cannot appear in otherServices
.map((thisService, index) => {
const returnThis = {
id: thisService,
};
if (this._allServicesOther[index]) {
returnThis.other = this._allServicesOther[index];
}
return returnThis;
}),
};
}
}
 
if (this._regType === 2) {
changeProperties.locationId = this._locationID;
}
 
// shareWith options
const shareWithMapping = {
0: false,
1: true,
'': null,
};
 
changeProperties.shareWith = {
cqc: shareWithMapping[this._shareWithCqc],
localAuthorities: shareWithMapping[this._shareWithLA],
};
 
// capacities - we combine both capacities and utilisations
changeProperties.capacities = [];
if (Array.isArray(this._capacities)) {
this._capacities.forEach((thisCapacity) => {
changeProperties.capacities.push(thisCapacity);
});
}
 
if (Array.isArray(this._utilisations)) {
this._utilisations.forEach((thisUtilisation) => {
changeProperties.capacities.push(thisUtilisation);
});
}
 
// clean up empty properties
if (changeProperties.capacities.length === 0) {
changeProperties.capacities = [];
}
 
return {
...fixedProperties,
...changeProperties,
};
}
 
// takes the given establishment entity and writes it out to CSV string (one line)
Function `toCSV` has 175 lines of code (exceeds 25 allowed). Consider refactoring.
Function `toCSV` has a Cognitive Complexity of 43 (exceeds 5 allowed). Consider refactoring.
static toCSV(entity) {
// ["LOCALESTID","STATUS","ESTNAME","ADDRESS1","ADDRESS2","ADDRESS3","POSTTOWN","POSTCODE","ESTTYPE","OTHERTYPE","PERMCQC","PERMLA","REGTYPE","PROVNUM","LOCATIONID","MAINSERVICE","ALLSERVICES","CAPACITY","UTILISATION","SERVICEDESC","SERVICEUSERS","OTHERUSERDESC","TOTALPERMTEMP","ALLJOBROLES","STARTERS","LEAVERS","VACANCIES","REASONS","REASONNOS"]
const columns = [];
columns.push(csvQuote(entity.LocalIdentifierValue));
columns.push('UNCHECKED');
columns.push(csvQuote(entity.NameValue));
columns.push(csvQuote(entity.address1));
columns.push(csvQuote(entity.address2));
columns.push(csvQuote(entity.address3));
columns.push(csvQuote(entity.town));
columns.push(csvQuote(entity.postcode));
columns.push(entity.EmployerTypeValue ? BUDI.establishmentType(BUDI.FROM_ASC, entity.EmployerTypeValue) : '');
columns.push(csvQuote(entity.EmployerTypeOther ? entity.EmployerTypeOther : ''));
 
const shareWithMapping = {
true: '1',
false: '0',
null: '',
};
 
columns.push(shareWithMapping[entity.shareWithCQC]);
columns.push(shareWithMapping[entity.shareWithLA]);
 
// CQC regulated, Prov IDand Location ID
columns.push(entity.isRegulated ? 2 : 0);
columns.push(entity.isRegulated ? entity.provId : '');
columns.push(entity.isRegulated ? entity.locationId : '');
 
const services = entity.otherServices;
services.unshift(entity.mainService);
// main service - this is mandatory in ASC WDS so no need to check for it being available or not
columns.push(entity.mainService.reportingID);
 
if (entity.otherServices.value === 'No') {
columns.push('0');
} else {
columns.push(services.map((service) => service.reportingID).join(';'));
}
 
const capacities = [];
const utilisations = [];
 
const findUtilCap = (type, service, capacities) =>
capacities.find((capacity) => capacity.reference.service.id === service.id && capacity.reference.type === type);
 
services.map((service) => {
const capacity = findUtilCap('Capacity', service, entity.capacity);
const utilisation = findUtilCap('Utilisation', service, entity.capacity);
capacities.push(capacity && capacity.answer ? capacity.answer : '');
utilisations.push(utilisation && utilisation.answer ? utilisation.answer : '');
});
 
columns.push(capacities.join(';'));
columns.push(utilisations.join(';'));
 
// all service "other" descriptions
 
Similar blocks of code found in 2 locations. Consider refactoring.
columns.push(
services
.map((thisService) =>
thisService.establishmentServices && thisService.establishmentServices.other
? thisService.establishmentServices.other
: '',
)
.join(';'),
);
 
// service users and their 'other' descriptions
const serviceUsers = Array.isArray(entity.serviceUsers) ? entity.serviceUsers : [];
columns.push(serviceUsers.map((thisUser) => BUDI.serviceUsers(BUDI.FROM_ASC, thisUser.id)).join(';'));
Similar blocks of code found in 2 locations. Consider refactoring.
columns.push(
serviceUsers
.map((thisServiceUser) =>
thisServiceUser.establishmentServiceUsers && thisServiceUser.establishmentServiceUsers.other
? thisServiceUser.establishmentServiceUsers.other
: '',
)
.join(';'),
);
 
// total perm/temp staff
columns.push(entity.NumberOfStaffValue ? entity.NumberOfStaffValue : 0);
 
// all job roles, starters, leavers and vacancies
// all jobs needs to be a set of unique ids (which across starters, leavers and vacancies may be repeated)
const uniqueJobs = entity.jobs
.map((job) => job.jobId)
.filter((value, index, self) => self.indexOf(value) === index);
 
columns.push(uniqueJobs.map((thisJob) => BUDI.jobRoles(BUDI.FROM_ASC, thisJob)).join(';'));
 
const starters = entity.jobs.filter((value) => value.type === 'Starters');
const leavers = entity.jobs.filter((value) => value.type === 'Leavers');
const vacancies = entity.jobs.filter((value) => value.type === 'Vacancies');
 
const starterCounts = [];
const leaverCounts = [];
const vacancyCounts = [];
 
uniqueJobs.map((job) => {
const starterCount = starters.find((starter) => starter.jobId === job);
const leaverCount = leavers.find((leaver) => leaver.jobId === job);
const vacancyCount = vacancies.find((vacancy) => vacancy.jobId === job);
starterCounts.push(starterCount && starterCount.total ? starterCount.total : 0);
leaverCounts.push(leaverCount && leaverCount.total ? leaverCount.total : 0);
vacancyCounts.push(vacancyCount && vacancyCount.total ? vacancyCount.total : 0);
});
 
const slv = (value, counts) => {
if (value === "Don't know") {
return 999;
} else if (value === null) {
return '';
} else if (value === 'None') {
return uniqueJobs.length > 0 ? uniqueJobs.map(() => 0).join(';') : 0;
} else {
return counts.join(';');
}
};
 
columns.push(slv(entity.StartersValue, starterCounts));
columns.push(slv(entity.LeaversValue, leaverCounts));
columns.push(slv(entity.VacanciesValue, vacancyCounts));
 
// reasons for leaving - currently can't be mapped - interim solution is a string of "reasonID:count|reasonId:count" (without BUDI mapping)
if (entity.reasonsForLeaving && entity.reasonsForLeaving.length > 0) {
const reasons = [];
const reasonsCount = [];
const myReasons = entity.reasonsForLeaving.split('|');
 
myReasons.forEach((currentReason) => {
const [reasonId, reasonCount] = currentReason.split(':');
reasons.push(reasonId);
reasonsCount.push(reasonCount);
});
 
columns.push(reasons.join(';'));
columns.push(reasonsCount.join(';'));
} else {
columns.push('');
columns.push('');
}
 
// Advertising, interviews,
const advertisingAndInterviewsMapping = (value) => {
if (value === "Don't know") {
return 'unknown';
} else if (value === 'None') {
return 0;
} else if (!value) {
return '';
} else {
return value;
}
};
 
columns.push(advertisingAndInterviewsMapping(entity.moneySpentOnAdvertisingInTheLastFourWeeks));
columns.push(advertisingAndInterviewsMapping(entity.peopleInterviewedInTheLastFourWeeks));
 
// RepeatTraining and AcceptCareCertifiicate
const repeatTrainingAndCareCertMapping = (value) => {
if (value === 'Yes, always') {
return 1;
} else if (value === 'Yes, very often') {
return 2;
} else if (value === 'Yes, but not very often') {
return 3;
} else if (value === 'No, never') {
return 4;
} else if (!value) {
Avoid too many `return` statements within this function.
return '';
}
};
 
columns.push(repeatTrainingAndCareCertMapping(entity.doNewStartersRepeatMandatoryTrainingFromPreviousEmployment));
columns.push(repeatTrainingAndCareCertMapping(entity.wouldYouAcceptCareCertificatesFromPreviousEmployment));
 
// cash Loyalty
const cashLoyaltyMapping = (value) => {
if (value === "Don't know") {
return 'unknown';
} else if (value === 'No') {
return 0;
} else if (value === 'Yes') {
return '1;';
} else if (!value) {
return '';
} else {
Avoid too many `return` statements within this function.
return value;
}
};
const whenValue = '1;';
columns.push(
cashLoyaltyMapping(
Number(entity.careWorkersCashLoyaltyForFirstTwoYears)
? whenValue.concat(entity.careWorkersCashLoyaltyForFirstTwoYears)
: entity.careWorkersCashLoyaltyForFirstTwoYears,
),
);
 
// Sick Pay, Pension Contribution,Holiday
const sickPayHolidayAndPensionMapping = (value) => {
if (value === "Don't know") {
return 'unknown';
} else if (value === 'No') {
return 0;
} else if (value === 'Yes') {
return 1;
} else if (!value) {
return '';
} else {
Avoid too many `return` statements within this function.
return value;
}
};
 
columns.push(sickPayHolidayAndPensionMapping(entity.sickPay));
columns.push(sickPayHolidayAndPensionMapping(entity.pensionContribution));
columns.push(sickPayHolidayAndPensionMapping(entity.careWorkersLeaveDaysPerYear));
 
return columns.join(',');
}
 
toCSV(entity) {
return WorkplaceCSVValidator.toCSV(entity);
}
}
 
module.exports.WorkplaceCSVValidator = WorkplaceCSVValidator;
module.exports.EstablishmentFileHeaders = _headers_v1;