Untitled
unknown
typescript
5 months ago
16 kB
15
Indexable
import config from "@mercadoni/elementals/config"; import moment, { Moment } from "moment"; import jwt from "jsonwebtoken"; import { DynamicParameterValue } from "../../../entities/DynamicParameter"; import Job, { JobEventSource } from "../../../entities/Job"; import { getAbsoluteDifferenceInMinutes } from "../../../utils/Dates"; import InvariantViolation from "../../../utils/errors/InvariantViolation"; import { JobWithEvents } from "../../../interactors/InteractorResponseModel"; import Event, { EventType } from "../../../entities/Event"; import Task, { TaskType } from "../../../entities/Task"; import JobQuote from "../../../entities/JobQuote"; import { getEstimatedStepDurationInMinutes } from "../creation/CalculateEstimatedDurations"; import { OperationalModel, StartTimeByTask } from "../../../entities/Slot"; import { StepType } from "../../../entities/Step"; import { goBackToStorage } from "../tasks/GoBackToStorage"; import { setTaskOptimalsByJobAndStartOptimals } from "../creation/CalculateOptimals"; const MAXIMUM_SLOT_LENGTH_IN_MINUTES = 12 * 60; // add this validations in the interactor // const jwtScret = config.get("jwt_secret"); // const slotPayload = jwt.verify(slotId!, jwtScret) as SlotPayloadJwt; // if (!slotPayload) { // throw new InvariantViolation("INVALID_SLOT_ID_FOR_RESCHEDULE", { jobId: job.getId() }); // } // here you are going to receive all the information export const rescheduleJobV2 = async ( job: Job, newFrom: Date, newTo: Date, jobQuote: JobQuote, dynamicParameterValue: DynamicParameterValue, backToStorage: boolean, origin = JobEventSource.OPERATIONS, reusablePackages = false, reason?: string, metadata?: Record<string, any>, startTimeByTask?: StartTimeByTask, ): Promise<JobWithEvents> => { validateDates(newFrom, newTo, job.getId()); const slotLength = validateSlotLength(newFrom, newTo, job.getId()); updateSlot(job, newFrom, newTo); const event = buildRescheduleEvent(job, origin, reason, metadata); const { rescheduleOffsetPercentage } = dynamicParameterValue; const targetDate = moment(newFrom).add(Math.ceil((slotLength * rescheduleOffsetPercentage) / 100), "minutes"); if(startTimeByTask) { setTaskOptimalsByJobAndStartOptimals(job, startTimeByTask); // create this method in src/use_cases/jobs/creation/CalculateOptimals.ts // export const setTaskOptimalsByJobAndStartOptimals = (job: Job, startTimeByTask: StartTimeByTask): void => { // for (const task of job.getTasks()) { // const taskType = task.getType(); // const departments = task.getDepartments(); // let currentTime: Date; // const timeDetailsByTask: TimeDetailsByTask = // startTimeByTask[getCapabilitiesInfoKey(taskType, departments) as TaskType]!; // currentTime = moment.utc(timeDetailsByTask.startDate).toDate(); // task.getSteps().forEach((step, index) => { // step.setOptimalStartTime(currentTime); // const duration = timeDetailsByTask.stepsDuration[index]; // currentTime = moment.utc(currentTime).add(duration, "minutes").toDate(); // step.setOptimalEndTime(currentTime); // }); // } // } }else{ // you have to revert the changes made in this function await rescheduleJob(job, jobQuote, dynamicParameterValue, targetDate); } const resetDeliveryEvents: Event[] = []; if (backToStorage) { const { triggeredEvents } = goBackToStorage(job, reusablePackages); resetDeliveryEvents.push(...triggeredEvents); } return { associatedJob: job, triggeredEvents: [event, ...resetDeliveryEvents], }; }; const rescheduleJob = async ( job: Job, jobQuote: JobQuote, parameterValue: DynamicParameterValue, target: Moment ): Promise<void> => { switch (job.getSlot().getOpsModel()) { case OperationalModel.FULL_SERVICE: await rescheduleFullserviceJob(job, jobQuote, parameterValue, target, startTimeByTask); break; case OperationalModel.PICK_AND_DELIVERY: await reschedulePickAndDeliveryJob(job, jobQuote, parameterValue, target, startTimeByTask); break; case OperationalModel.PICK_AND_COLLECT: await reschedulePickAndCollectJob(job, jobQuote, parameterValue, target, startTimeByTask); break; case OperationalModel.PICK_AND_COLLECT_NO_TRANSFER: await reschedulePickAndCollectNoTransferJob(job, jobQuote, parameterValue, target, startTimeByTask); break; case OperationalModel.PICK_AND_DELIVERY_WITH_STORAGE: await reschedulePickAndDeliveryWithStorageJob(job, jobQuote, parameterValue, target, startTimeByTask); break; case OperationalModel.PICK_AND_DELIVERY_WITH_STORAGE_NO_TRANSFER: await reschedulePickAndDeliveryWithStorageNoTransferJob(job, jobQuote, parameterValue, target, startTimeByTask); break; case OperationalModel.ZONE_PICKING_AND_COLLECT: await rescheduleZonePickingAndCollectJob(job, jobQuote, parameterValue, target, startTimeByTask); break; case OperationalModel.ZONE_PICKING_AND_DELIVERY_WITH_STORAGE: await rescheduleZonePickingAndDeliveryWithStorageJob(job, jobQuote, parameterValue, target, startTimeByTask); break; default: throw new InvariantViolation("OPERATIONAL_MODEL_NOT_SUPPORTED_FOR_RESCHEDULE", { jobId: job.getId() }); } try { job.getDeliveryTask().setRoute(null); } catch (error) { return; } }; const rescheduleFullserviceJob = async ( job: Job, jobQuote: JobQuote, parameterValue: DynamicParameterValue, target: Moment, ): Promise<void> => { const fullServiceTask = job.getTaskByType(TaskType.FULL_SERVICE); await rescheduleTask(fullServiceTask, jobQuote, parameterValue, target); }; const reschedulePickAndDeliveryJob = async ( job: Job, jobQuote: JobQuote, parameterValue: DynamicParameterValue, target: Moment, startTimeByTask?: StartTimeByTask ): Promise<void> => { const deliveryTask = job.getTaskByType(TaskType.DELIVERY); const pickingTask = job.getTaskByType(TaskType.PICKING); if (startTimeByTask) { job.getTasks().forEach((task) => { rescheduleTaskWithSlotId(task, startTimeByTask); }) } else { await rescheduleTask(deliveryTask, jobQuote, parameterValue, target); const transferStep = deliveryTask.getStepOfType(deliveryTask.getTransferStepType()); await rescheduleTask(pickingTask, jobQuote, parameterValue, moment.utc(transferStep.getOptimalEndTime())); } }; const reschedulePickAndCollectJob = async ( job: Job, jobQuote: JobQuote, parameterValue: DynamicParameterValue, target: Moment | null, startTimeByTask?: StartTimeByTask ): Promise<void> => { const pickUpTask = job.getTaskByType(TaskType.PICK_UP); const storageTask = job.getTaskByType(TaskType.STORAGE); const pickingWithStorageTask = job.getTaskByType(TaskType.PICKING_WITH_STORAGE); if (startTimeByTask) { rescheduleTaskWithSlotId(pickUpTask, startTimeByTask); rescheduleTaskWithSlotId(storageTask, startTimeByTask); rescheduleTaskWithSlotId(pickingWithStorageTask, startTimeByTask); } else { await rescheduleTask(pickUpTask, jobQuote, parameterValue, target!); const deliveringStep = pickUpTask.getStepOfType(StepType.DELIVERING); await rescheduleTask(storageTask, jobQuote, parameterValue, moment.utc(deliveringStep.getOptimalStartTime())); const transferStep = storageTask.getStepOfType(storageTask.getTransferStepType()); await rescheduleTask( pickingWithStorageTask, jobQuote, parameterValue, moment.utc(transferStep.getOptimalEndTime()) ); } }; const reschedulePickAndCollectNoTransferJob = async ( job: Job, jobQuote: JobQuote, parameterValue: DynamicParameterValue, target: Moment | null, startTimeByTask?: StartTimeByTask ): Promise<void> => { const pickUpTask = job.getTaskByType(TaskType.PICK_UP); const pickAndStorageTask = job.getTaskByType(TaskType.PICKING_AND_STORAGE); if (startTimeByTask) { rescheduleTaskWithSlotId(pickUpTask, startTimeByTask); rescheduleTaskWithSlotId(pickAndStorageTask, startTimeByTask); } else { await rescheduleTask(pickUpTask, jobQuote, parameterValue, target!); const deliveringStep = pickUpTask.getStepOfType(StepType.DELIVERING); await rescheduleTask( pickAndStorageTask, jobQuote, parameterValue, moment.utc(deliveringStep.getOptimalStartTime()) ); } }; const reschedulePickAndDeliveryWithStorageJob = async ( job: Job, jobQuote: JobQuote, parameterValue: DynamicParameterValue, target: Moment | null, startTimeByTask?: StartTimeByTask ): Promise<void> => { const deliveryWithStorageTask = job.getTaskByType(TaskType.DELIVERY_WITH_STORAGE); const pickUpForDeliveryTask = job.getTaskByType(TaskType.PICK_UP_FOR_DELIVERY); const storageTask = job.getTaskByType(TaskType.STORAGE); const pickingWithStorageTask = job.getTaskByType(TaskType.PICKING_WITH_STORAGE); if (startTimeByTask) { rescheduleTaskWithSlotId(deliveryWithStorageTask, startTimeByTask); rescheduleTaskWithSlotId(pickUpForDeliveryTask, startTimeByTask); rescheduleTaskWithSlotId(storageTask, startTimeByTask); rescheduleTaskWithSlotId(pickingWithStorageTask, startTimeByTask); } else { await rescheduleTask(deliveryWithStorageTask, jobQuote, parameterValue, target!); const secondTransferStep = deliveryWithStorageTask.getStepOfType(deliveryWithStorageTask.getTransferStepType()); await rescheduleTask( pickUpForDeliveryTask, jobQuote, parameterValue, moment.utc(secondTransferStep.getOptimalEndTime()) ); await rescheduleTask(storageTask, jobQuote, parameterValue, moment.utc(secondTransferStep.getOptimalStartTime())); const firstTransferStep = storageTask.getStepOfType(storageTask.getTransferStepType()); await rescheduleTask( pickingWithStorageTask, jobQuote, parameterValue, moment.utc(firstTransferStep.getOptimalEndTime()) ); } }; const reschedulePickAndDeliveryWithStorageNoTransferJob = async ( job: Job, jobQuote: JobQuote, parameterValue: DynamicParameterValue, target: Moment | null, startTimeByTask?: StartTimeByTask ): Promise<void> => { const deliveryWithStorageTask = job.getTaskByType(TaskType.DELIVERY_WITH_STORAGE); const pickUpForDeliveryTask = job.getTaskByType(TaskType.PICK_UP_FOR_DELIVERY); const pickingAndStorageTask = job.getTaskByType(TaskType.PICKING_AND_STORAGE); if (startTimeByTask) { rescheduleTaskWithSlotId(deliveryWithStorageTask, startTimeByTask); rescheduleTaskWithSlotId(pickUpForDeliveryTask, startTimeByTask); rescheduleTaskWithSlotId(pickingAndStorageTask, startTimeByTask); } else { await rescheduleTask(deliveryWithStorageTask, jobQuote, parameterValue, target!); const transferStep = deliveryWithStorageTask.getStepOfType(deliveryWithStorageTask.getTransferStepType()); await rescheduleTask(pickUpForDeliveryTask, jobQuote, parameterValue, moment.utc(transferStep.getOptimalEndTime())); await rescheduleTask( pickingAndStorageTask, jobQuote, parameterValue, moment.utc(transferStep.getOptimalStartTime()) ); } }; const rescheduleZonePickingAndCollectJob = async ( job: Job, jobQuote: JobQuote, parameterValue: DynamicParameterValue, target: Moment | null, startTimeByTask?: StartTimeByTask ): Promise<void> => { const pickUpTask = job.getTaskByType(TaskType.PICK_UP); const consolidationTask = job.getTaskByType(TaskType.CONSOLIDATION); const zonePickingTasks = job.getTasksByType(TaskType.ZONE_PICKING); if (startTimeByTask) { rescheduleTaskWithSlotId(pickUpTask, startTimeByTask); rescheduleTaskWithSlotId(consolidationTask, startTimeByTask); zonePickingTasks.forEach((zonePickingTask) => { return rescheduleTaskWithSlotId(zonePickingTask, startTimeByTask); }); } else { await rescheduleTask(pickUpTask, jobQuote, parameterValue, target!); await rescheduleTask(consolidationTask, jobQuote, parameterValue, moment.utc(pickUpTask.getOptimalStartTime())); await Promise.all( zonePickingTasks.map(async (zonePickingTask: Task) => { return rescheduleTask( zonePickingTask, jobQuote, parameterValue, moment.utc(consolidationTask.getOptimalStartTime()) ); }) ); } }; const rescheduleZonePickingAndDeliveryWithStorageJob = async ( job: Job, jobQuote: JobQuote, parameterValue: DynamicParameterValue, target: Moment | null, startTimeByTask?: StartTimeByTask ): Promise<void> => { const deliveryWithStorageTask = job.getTaskByType(TaskType.DELIVERY_WITH_STORAGE); const pickUpForDeliveryTask = job.getTaskByType(TaskType.PICK_UP_FOR_DELIVERY); const consolidationTask = job.getTaskByType(TaskType.CONSOLIDATION); const zonePickingTasks = job.getTasksByType(TaskType.ZONE_PICKING); if (startTimeByTask) { setTaskOptimalsByJobAndStartOptimals(job, startTimeByTask); } else { await rescheduleTask(deliveryWithStorageTask, jobQuote, parameterValue, target!); const transferStep = deliveryWithStorageTask.getStepOfType(deliveryWithStorageTask.getTransferStepType()); await rescheduleTask(pickUpForDeliveryTask, jobQuote, parameterValue, moment.utc(transferStep.getOptimalEndTime())); await rescheduleTask( consolidationTask, jobQuote, parameterValue, moment.utc(pickUpForDeliveryTask.getOptimalStartTime()) ); await Promise.all( zonePickingTasks.map(async (zonePickingTask: Task) => { return rescheduleTask( zonePickingTask, jobQuote, parameterValue, moment.utc(consolidationTask.getOptimalStartTime()) ); }) ); } }; const rescheduleTask = async ( task: Task, jobQuote: JobQuote, parameterValue: DynamicParameterValue, endTime: Moment ): Promise<void> => { let optimalStartTime: Moment; let optimalEndTime = moment.utc(endTime); const steps = task.getSteps(); for (let i = steps.length - 1; i >= 0; i--) { const step = steps[i]; const stepDurationInMinutes = await getEstimatedStepDurationInMinutes( step.getType(), jobQuote, optimalEndTime, parameterValue ); optimalStartTime = moment.utc(optimalEndTime).subtract(stepDurationInMinutes, "minutes"); step.setOptimalStartTime(optimalStartTime.toDate()); step.setOptimalEndTime(optimalEndTime.toDate()); optimalEndTime = optimalStartTime; } }; const validateDates = (from: Date, to: Date, jobId: string): void => { if (moment(to).isBefore(moment(from))) { throw new InvariantViolation("INVALID_SLOT_FOR_RESCHEDULE", { jobId }); } }; const validateSlotLength = (from: Date, to: Date, jobId: string): number => { const slotLength = getAbsoluteDifferenceInMinutes(from, to); if (slotLength > MAXIMUM_SLOT_LENGTH_IN_MINUTES) { throw new InvariantViolation("INVALID_SLOT_LENGTH_FOR_RESCHEDULE", { jobId }); } return slotLength; }; const updateSlot = (job: Job, from: Date, to: Date): void => { job.getSlot().setFrom(from); job.getSlot().setTo(to); }; const buildRescheduleEvent = ( job: Job, origin: JobEventSource, reason?: string, metadata?: Record<string, any> ): Event => { return new Event(job.getId(), EventType.RESCHEDULED, job.getClientId(), { taskIds: job.getTasks().map((task) => { return task.getId(); }), origin, reason, metadata, }); };
Editor is loading...
Leave a Comment