backend/src/services/trainService.services.js
Fred Boniface 0a25ae85f5 newStaffLDB-API (#48)
Merge newStaffLDB-API into main.

Ready to deploy

Reviewed-on: #48
2023-10-03 21:35:00 +01:00

211 lines
6.0 KiB
JavaScript

const db = require("./dbAccess.services");
const clean = require("../utils/sanitizer.utils");
const pis = require("../services/pis.services");
import { logger } from "../utils/logger.utils";
async function findByHeadcodeToday(headcode) {
const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase();
logger.debug(
`trainServiceServices.findByHeadcode: Searching for headcode ${sanitizedHeadcode}`
);
const now = new Date();
const dayMap = ["su", "m", "t", "w", "th", "f", "s"];
const shortDay = dayMap[now.getDay()]; // Fetch short day from map
const query = {
headcode: sanitizedHeadcode,
scheduleStartDate: { $lte: now },
scheduleEndDate: { $gte: now },
daysRun: { $in: [shortDay] },
};
const queryData = await db.query("timetable", query);
let trainData = await parseTrains(queryData);
let preparedData = [];
for (let trainService in trainData) {
if (pis.supported.includes(trainService?.operator)) {
// Search for PIS Code for each service
const tiplocList = await getPublicStops(trainService?.stops);
//console.log(tiplocList.length); console.log(tiplocList);
if (tiplocList.length) {
const pisDetail = await pis.findByTiplocArray(tiplocList);
trainService["pis"] = pisDetail?.[0]?.["code"] ?? "None";
} else if (trainService?.operator === "GW") {
trainService["pis"] = "0015"; // Not in Service code
// '0015' is a string becuase 0015 is not a valid number..
}
}
preparedData.push(trainService);
}
return preparedData;
}
async function findByHeadcode(date, headcode) {
const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase();
logger.debug(
`trainServiceServices.findByHeadcode: Searching for headcode ${sanitizedHeadcode}`
);
let searchDate;
if (date === "now") {
searchDate = new Date();
} else {
searchDate = new Date(date);
}
searchDate.setHours(12, 0, 0); // Set to midday to avoid any timezone issues
const dayMap = ["su", "m", "t", "w", "th", "f", "s"];
const shortDay = dayMap[searchDate.getDay()]; // Fetch short day from map
const query = {
headcode: sanitizedHeadcode,
scheduleStartDate: { $lte: searchDate },
scheduleEndDate: { $gte: searchDate },
daysRun: { $in: [shortDay] },
};
const pipeline = [
{
$match: query,
},
{
$project: {
operator: 1,
stops: {
$concatArrays: [
[{ $first: "$stops" }],
[{ $arrayElemAt: ["$stops", -1] }],
],
},
trainUid: 1,
stpIndicator: 1,
},
},
];
const queryData = await db.queryAggregate("timetable", pipeline);
let filteredData = filterServices(queryData);
return await filteredData;
}
async function findByTrainUid(uid, date = new Date()) {
let queryDate;
if (date === "now") {
queryDate = new Date();
} else {
queryDate = date;
}
const query = {
trainUid: uid,
scheduleStartDate: { $lte: queryDate },
scheduleEndDate: { $gte: queryDate },
};
const queryData = await db.query("timetable", query);
if (queryData.length === 0) {
return [];
}
let services;
services = await filterServices(queryData);
console.log(services);
let publicStops;
if (pis.supported.includes(services[0]?.operator)) {
publicStops = await getPublicStops(services[0]?.stops);
if (publicStops.length) {
const pisCode = await pis.findByTiplocArray(publicStops);
services[0].pis = pisCode[0]?.code;
} else if (services[0]?.operator === "GW" && !publicStops.length) {
services[0].pis = "0015";
}
}
return services[0];
}
module.exports = {
findByHeadcodeToday,
findByHeadcode,
findByTrainUid,
};
/* Internal Functions, not to be exported */
/* Accepts the 'stops' array from a db query and produces an
array of only public stops as TIPLOCs. */
async function getPublicStops(data) {
let tiplocList = [];
for (const publicStop in data) {
if (data[publicStop]["isPublic"]) {
tiplocList.push(data[publicStop]["tiploc"]);
}
}
return tiplocList;
}
/* Takes a single days data from a headcode query and requeries
using the trainUid, required to ensure any cancellations are
accounted for */
async function parseTrains(data) {
let trainUids = [];
for (const i of data) {
const trainUid = i["trainUid"];
if (!trainUids.includes(trainUid)) {
trainUids.push(trainUid);
}
}
let parsedData = [];
for (const i in trainUids) {
const result = await findByTrainUid(trainUids[i]);
parsedData.push(result);
}
return parsedData;
}
async function filterServices(data) {
let stpIndicators = {},
filteredServices = [];
for (const serviceDetail of data) {
const trainUid = serviceDetail["trainUid"];
const stpIndicator = serviceDetail["stpIndicator"];
if (!stpIndicators[trainUid]) {
stpIndicators[trainUid] = {
hasC: false,
hasN: false,
hasO: false,
hasP: false,
};
}
if (stpIndicator === "C") {
stpIndicators[trainUid].hasC = true;
}
if (stpIndicator === "N") {
stpIndicators[trainUid].hasN = true;
}
if (stpIndicator === "O") {
stpIndicators[trainUid].hasO = true;
}
if (stpIndicator === "P") {
stpIndicators[trainUid].hasP = true;
}
}
let preparedData;
for (const serviceDetail of data) {
const trainUid = serviceDetail["trainUid"];
const thisStpIndicators = stpIndicators[trainUid];
const stpIndicator = serviceDetail["stpIndicator"];
if (stpIndicator === "C") {
break;
}
if (stpIndicator === "N" && !thisStpIndicators.hasC) {
filteredServices.push(serviceDetail);
} else if (
stpIndicator === "O" &&
!thisStpIndicators.hasC &&
!thisStpIndicators.hasN
) {
filteredServices.push(serviceDetail);
} else if (
stpIndicator === "P" &&
!thisStpIndicators.hasC &&
!thisStpIndicators.hasN &&
!thisStpIndicators.hasO
) {
filteredServices.push(serviceDetail);
}
}
return filteredServices;
}