Added basic bucketed smart scheduling BOD-4
This commit is contained in:
@@ -111,8 +111,8 @@ query QUERY_INVOICES_FOR_PAYABLES_EXPORT($invoices: [uuid!]!) {
|
||||
|
||||
exports.QUERY_UPCOMING_APPOINTMENTS = `
|
||||
query QUERY_UPCOMING_APPOINTMENTS($now: timestamptz!, $jobId: uuid!) {
|
||||
jobs_by_pk(id: $jobId){
|
||||
bodyshop{
|
||||
jobs_by_pk(id: $jobId) {
|
||||
bodyshop {
|
||||
ssbuckets
|
||||
}
|
||||
jobhrs: joblines_aggregate {
|
||||
@@ -122,23 +122,27 @@ query QUERY_UPCOMING_APPOINTMENTS($now: timestamptz!, $jobId: uuid!) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
appointments(where: {start: {_gt: $now}}) {
|
||||
start
|
||||
isintake
|
||||
id
|
||||
job {
|
||||
joblines_aggregate {
|
||||
aggregate {
|
||||
sum {
|
||||
mod_lb_hrs
|
||||
}
|
||||
appointments(where: {_and: {canceled: {_eq: false}, start: {_gte: $now}}}) {
|
||||
start
|
||||
isintake
|
||||
id
|
||||
job {
|
||||
joblines_aggregate {
|
||||
aggregate {
|
||||
sum {
|
||||
mod_lb_hrs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
productionview {
|
||||
id
|
||||
labhrs
|
||||
larhrs
|
||||
scheduled_completion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
`;
|
||||
|
||||
@@ -29,48 +29,103 @@ exports.job = async (req, res) => {
|
||||
jobId: jobId,
|
||||
});
|
||||
|
||||
const { appointments } = result;
|
||||
const { appointments, productionview } = result;
|
||||
const { ssbuckets } = result.jobs_by_pk.bodyshop;
|
||||
const jobhrs = result.jobs_by_pk.jobhrs.aggregate.sum.mod_lb_hrs;
|
||||
const jobHrs = result.jobs_by_pk.jobhrs.aggregate.sum.mod_lb_hrs;
|
||||
|
||||
const JobClassification = ssbuckets.filter(
|
||||
(b) => b.gte <= jobhrs && b.lt > jobhrs
|
||||
);
|
||||
//Create a matrix of load bucket
|
||||
const JobBucket = ssbuckets.filter(
|
||||
(bucket) =>
|
||||
bucket.gte <= jobHrs && (!!bucket.lt ? bucket.lt > jobHrs : true)
|
||||
)[0];
|
||||
|
||||
const bucketMatrix = {};
|
||||
|
||||
//Get latest date + add 5 days.
|
||||
|
||||
//Get latest date + add 5 days to allow for back end adding..
|
||||
const totalMatrixDays = moment
|
||||
.max(appointments.map((a) => moment(a.start)))
|
||||
.max([
|
||||
...appointments.map((a) => moment(a.start)),
|
||||
...productionview
|
||||
.map((p) => moment(p.scheduled_completion))
|
||||
.filter((p) => p.isValid()),
|
||||
])
|
||||
.add("5", "days")
|
||||
.diff(moment(), "days");
|
||||
|
||||
for (var i = 0; i++; i < totalMatrixDays) {
|
||||
//Initialize the bucket matrix
|
||||
for (i = 0; i < totalMatrixDays; i++) {
|
||||
const theDate = moment().add(i, "days").toISOString().substr(0, 10);
|
||||
console.log("theDate", theDate);
|
||||
ssbuckets.forEach((bucket) => {
|
||||
bucketMatrix[theDate][bucket.id] = { in: 0, out: 0 };
|
||||
});
|
||||
//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) => {
|
||||
//Get the day of the appointment.
|
||||
const appDate = moment(appointment.start).toISOString().substr(0, 10);
|
||||
!!bucketMatrix[appDate] ? {} : {};
|
||||
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).toISOString().substr(0, 10);
|
||||
bucketMatrix[appDate] = {
|
||||
...bucketMatrix[appDate],
|
||||
in: bucketMatrix[appDate].in + 1,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
//Calculate the load for the shop looking forward.
|
||||
//Populate the jobs that are leaving today.
|
||||
const todayIsoString = moment().toISOString().substr(0, 10);
|
||||
productionview.forEach((pjob) => {
|
||||
const jobHrs = pjob.larhrs + pjob.labhrs;
|
||||
//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.toISOString().substr(0, 10)
|
||||
: todayIsoString
|
||||
: todayIsoString;
|
||||
|
||||
bucketMatrix[dateToUse] = {
|
||||
...bucketMatrix[dateToUse],
|
||||
out: bucketMatrix[dateToUse].out + 1,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
//Propose the first 5 dates where we are below target.
|
||||
|
||||
const possibleDates = [];
|
||||
const bucketMatrixKeys = Object.keys(bucketMatrix);
|
||||
bucketMatrixKeys.forEach((bmkey) => {
|
||||
if (JobBucket.target > bucketMatrix[bmkey].in - bucketMatrix[bmkey].out)
|
||||
possibleDates.push(new Date(bmkey).toISOString().substr(0, 10));
|
||||
});
|
||||
|
||||
//Temp
|
||||
possibleDates.push(new Date());
|
||||
possibleDates.push(new Date());
|
||||
possibleDates.push(new Date());
|
||||
possibleDates.push(new Date());
|
||||
possibleDates.push(new Date());
|
||||
// possibleDates.push(new Date());
|
||||
// possibleDates.push(new Date());
|
||||
// possibleDates.push(new Date());
|
||||
// possibleDates.push(new Date());
|
||||
// possibleDates.push(new Date());
|
||||
//Get a list of upcoming appointments
|
||||
//Get the config for each day
|
||||
|
||||
|
||||
Reference in New Issue
Block a user