176 lines
6.4 KiB
JavaScript
176 lines
6.4 KiB
JavaScript
const GraphQLClient = require("graphql-request").GraphQLClient;
|
|
const path = require("path");
|
|
const queries = require("../graphql-client/queries");
|
|
const Dinero = require("dinero.js");
|
|
const moment = require("moment");
|
|
const logger = require("../utils/logger");
|
|
require("dotenv").config({
|
|
path: path.resolve(
|
|
process.cwd(),
|
|
`.env.${process.env.NODE_ENV || "development"}`
|
|
),
|
|
});
|
|
|
|
exports.job = async (req, res) => {
|
|
const BearerToken = req.headers.authorization;
|
|
const { jobId } = req.body;
|
|
try {
|
|
logger.log("smart-scheduling-start", "DEBUG", req.user.email, jobId, null);
|
|
|
|
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
|
headers: {
|
|
Authorization:`Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjhmYmRmMjQxZTdjM2E2NTEzNTYwNmRkYzFmZWQyYzU1MjI2MzBhODciLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUGF0cmljayAoUFJPRCBBRE0pIiwiaHR0cHM6Ly9oYXN1cmEuaW8vand0L2NsYWltcyI6eyJ4LWhhc3VyYS1kZWZhdWx0LXJvbGUiOiJ1c2VyIiwieC1oYXN1cmEtYWxsb3dlZC1yb2xlcyI6WyJ1c2VyIl0sIngtaGFzdXJhLXVzZXItaWQiOiJRc3UzOUZnaTJyZzlYdUtQZFRDZXgwZk5abzQzIn0sImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9pbWV4LXByb2QiLCJhdWQiOiJpbWV4LXByb2QiLCJhdXRoX3RpbWUiOjE2MzQ4MzUyMDQsInVzZXJfaWQiOiJRc3UzOUZnaTJyZzlYdUtQZFRDZXgwZk5abzQzIiwic3ViIjoiUXN1MzlGZ2kycmc5WHVLUGRUQ2V4MGZOWm80MyIsImlhdCI6MTYzNDgzNTIwNCwiZXhwIjoxNjM0ODM4ODA0LCJlbWFpbCI6InBhdHJpY2tAaW1leC5wcm9kIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJmaXJlYmFzZSI6eyJpZGVudGl0aWVzIjp7ImVtYWlsIjpbInBhdHJpY2tAaW1leC5wcm9kIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.hILLhQoHqvO_jlc5GyrIX8UEoUDgOrbUduUZZapZivIqucVUt0zN_Fks30I4y3A8Lx7QCwwIW0WXcM8kSpCtyBJPCsfiaAT2IU0vbSGQtvm9zedTwIINYYv4wKNTtnUuev8VRDYlowHhhTO1kW7VzlKz6zOeyQYFMAvxdGinMS49kyF7DwVNxh_7uI87NIpCmwSL2CWTjTrUcZjAj24Th3TiJWgnxp7kqIqHKBXtYe5w-Nt4IWixUbeu4IJ4_klNcPl3qVODA6YRY0t0y6fRWXseFAKD_pnGTyhv_ZcVl-qVasxi1t8QFkhYW0GVJCNCuTBZcl5KsOS4dLMSFKrCMg`
|
|
/// BearerToken,
|
|
},
|
|
});
|
|
|
|
const result = await client
|
|
.setHeaders({ Authorization: BearerToken })
|
|
.request(queries.QUERY_UPCOMING_APPOINTMENTS, {
|
|
now: new Date(),
|
|
jobId:`6b92e1af-3161-45a3-91a4-06a5f85a12b1`// jobId,
|
|
});
|
|
|
|
const { appointments, jobs } = result;
|
|
const { ssbuckets, workingdays } = result.jobs_by_pk.bodyshop;
|
|
const jobHrs = result.jobs_by_pk.jobhrs.aggregate.sum.mod_lb_hrs;
|
|
|
|
const JobBucket = ssbuckets.filter(
|
|
(bucket) =>
|
|
bucket.gte <= jobHrs && (!!bucket.lt ? bucket.lt > jobHrs : true)
|
|
)[0];
|
|
|
|
const bucketMatrix = {};
|
|
const yesterday = moment().subtract(1, "day");
|
|
//Get latest date + add 5 days to allow for back end adding..
|
|
|
|
|
|
const totalMatrixDays = moment
|
|
.max([
|
|
...appointments.map((a) => moment(a.start)),
|
|
...jobs
|
|
.map((p) => moment(p.scheduled_completion))
|
|
.filter((p) => p.isValid() && p.isAfter(yesterday)),
|
|
])
|
|
.add("5", "days")
|
|
.diff(moment(), "days");
|
|
|
|
//Initialize the bucket matrix
|
|
for (var i = 0; i < totalMatrixDays; i++) {
|
|
const theDate = moment().add(i, "days").format("yyyy-MM-DD");
|
|
//Only need to create a matrix for jobs of the same bucket.
|
|
bucketMatrix[theDate] = { in: 0, out: 0 };
|
|
|
|
// ssbuckets.forEach((bucket) => {
|
|
// bucketMatrix[theDate] = {
|
|
// ...bucketMatrix[theDate],
|
|
// [bucket.id]: { in: 0, out: 0 },
|
|
// };
|
|
// });
|
|
}
|
|
|
|
//Populate the jobs scheduled to come in.
|
|
appointments.forEach((appointment) => {
|
|
if (!appointment.block) {
|
|
const jobHrs =
|
|
appointment.job.joblines_aggregate.aggregate.sum.mod_lb_hrs;
|
|
//Is the job in the same bucket?
|
|
const appointmentBucket = ssbuckets.filter(
|
|
(bucket) =>
|
|
bucket.gte <= jobHrs && (!!bucket.lt ? bucket.lt > jobHrs : true)
|
|
)[0];
|
|
if (appointmentBucket.id === JobBucket.id) {
|
|
//Theyre the same classification. Add it to the matrix.
|
|
const appDate = moment(appointment.start).format("yyyy-MM-DD");
|
|
bucketMatrix[appDate] = {
|
|
...bucketMatrix[appDate],
|
|
in: bucketMatrix[appDate].in + 1,
|
|
};
|
|
}
|
|
} else {
|
|
//remove the date from the possible list.
|
|
const appDate = moment(appointment.start).format("yyyy-MM-DD");
|
|
bucketMatrix[appDate] = {
|
|
...bucketMatrix[appDate],
|
|
blocked: true,
|
|
};
|
|
}
|
|
});
|
|
|
|
//Populate the jobs that are leaving today.
|
|
const todayIsoString = moment().format("yyyy-MM-DD");
|
|
jobs.forEach((pjob) => {
|
|
const jobHrs =
|
|
pjob.larhrs.aggregate.sum.mod_lb_hrs +
|
|
pjob.labhrs.aggregate.sum.mod_lb_hrs;
|
|
//Is the job in the same bucket?
|
|
const pjobBucket = ssbuckets.filter(
|
|
(bucket) =>
|
|
bucket.gte <= jobHrs && (!!bucket.lt ? bucket.lt > jobHrs : true)
|
|
)[0];
|
|
if (pjobBucket.id === JobBucket.id) {
|
|
//Theyre the same classification. Add it to the matrix.
|
|
const compDate = moment(pjob.scheduled_completion);
|
|
//Is the schedule completion behind today? If so, use today as it.
|
|
let dateToUse;
|
|
dateToUse = compDate.isValid()
|
|
? moment().diff(compDate, "days") < 0
|
|
? compDate.format("yyyy-MM-DD")
|
|
: todayIsoString
|
|
: todayIsoString;
|
|
|
|
bucketMatrix[dateToUse] = {
|
|
...bucketMatrix[dateToUse],
|
|
out: (bucketMatrix[dateToUse].out || 0) + 1,
|
|
};
|
|
}
|
|
});
|
|
|
|
//Propose the first 5 dates where we are below target.
|
|
|
|
const possibleDates = [];
|
|
const bucketMatrixKeys = Object.keys(bucketMatrix);
|
|
bucketMatrixKeys.forEach((bmkey) => {
|
|
const isShopOpen =
|
|
workingdays[dayOfWeekMapper(moment(bmkey).day())] &&
|
|
!bucketMatrix[bmkey].blocked;
|
|
|
|
if (
|
|
JobBucket.target > bucketMatrix[bmkey].in - bucketMatrix[bmkey].out &&
|
|
isShopOpen
|
|
)
|
|
possibleDates.push(new Date(bmkey).toISOString().substr(0, 10));
|
|
});
|
|
|
|
if (possibleDates.length < 6) {
|
|
res.json(possibleDates);
|
|
} else {
|
|
res.json(possibleDates.slice(0, 5));
|
|
}
|
|
} catch (error) {
|
|
logger.log("smart-scheduling-error", "ERROR", req.user.email, jobId, {
|
|
error: JSON.stringify(error),
|
|
});
|
|
res.status(400).send(error);
|
|
}
|
|
};
|
|
|
|
const dayOfWeekMapper = (numberOfDay) => {
|
|
switch (numberOfDay) {
|
|
case 0:
|
|
return "sunday";
|
|
case 1:
|
|
return "monday";
|
|
case 2:
|
|
return "tuesday";
|
|
case 3:
|
|
return "wednesday";
|
|
case 4:
|
|
return "thursday";
|
|
case 5:
|
|
return "friday";
|
|
case 6:
|
|
return "saturday";
|
|
}
|
|
};
|