From 01ebac7e748ea661b17226fb0c913f8089528f0a Mon Sep 17 00:00:00 2001 From: Romain Thouvenin Date: Fri, 12 Apr 2024 11:33:17 +0200 Subject: [PATCH] DRY the pax/driver schedule adjustment logic --- .../ad/core/domain/candidate.entity.ts | 169 +++++++----------- 1 file changed, 69 insertions(+), 100 deletions(-) diff --git a/src/modules/ad/core/domain/candidate.entity.ts b/src/modules/ad/core/domain/candidate.entity.ts index 3da8964..26bd990 100644 --- a/src/modules/ad/core/domain/candidate.entity.ts +++ b/src/modules/ad/core/domain/candidate.entity.ts @@ -2,12 +2,14 @@ import { AggregateID, AggregateRoot, ArgumentInvalidException, + ValueObject, } from '@mobicoop/ddd-library'; import { Role } from './ad.types'; import { CalendarTools } from './calendar-tools.service'; import { CandidateProps, CreateCandidateProps, + DateInterval, Target, } from './candidate.types'; import { ActorTime } from './value-objects/actor-time.value-object'; @@ -101,57 +103,13 @@ export class CandidateEntity extends AggregateRoot { * Create the driver schedule based on the passenger schedule */ private _createDriverSchedule = (): void => { - let driverSchedule: Array = - this.props.passengerSchedule!.map( - (scheduleItemProps: ScheduleItemProps) => ({ - day: scheduleItemProps.day, - time: scheduleItemProps.time, - margin: scheduleItemProps.margin, - }), - ); - // adjust the driver theoretical schedule : - // we guess the ideal driver departure time based on the duration to - // reach the passenger starting point from the driver starting point - driverSchedule = driverSchedule - .map((scheduleItemProps: ScheduleItemProps) => { - try { - const driverDate: Date = CalendarTools.firstDate( - scheduleItemProps.day, - this.props.dateInterval, - ); - const driverStartDatetime: Date = CalendarTools.datetimeWithSeconds( - driverDate, - scheduleItemProps.time, - -this._passengerStartDuration(), - ); - return { - day: driverDate.getUTCDay(), - margin: scheduleItemProps.margin, - time: `${driverStartDatetime - .getUTCHours() - .toString() - .padStart(2, '0')}:${driverStartDatetime - .getUTCMinutes() - .toString() - .padStart(2, '0')}`, - }; - } catch (e) { - // no possible driver date or time - // TODO : find a test case ! - return undefined; - } - }) - .filter( - (scheduleItemProps: ScheduleItemProps | undefined) => - scheduleItemProps !== undefined, - ); - this.props.driverSchedule = driverSchedule.map( - (scheduleItemProps: ScheduleItemProps) => ({ - day: scheduleItemProps.day, - time: scheduleItemProps.time, - margin: scheduleItemProps.margin, - }), + const passengerSchedule = new Schedule( + this.props.passengerSchedule!, + this.props.dateInterval, ); + this.props.driverSchedule = passengerSchedule + .adjust(-this._passengerStartDuration()) + .unpack().items; }; /** @@ -174,57 +132,14 @@ export class CandidateEntity extends AggregateRoot { * Create the passenger schedule based on the driver schedule */ private _createPassengerSchedule = (): void => { - let passengerSchedule: Array = - this.props.driverSchedule!.map( - (scheduleItemProps: ScheduleItemProps) => ({ - day: scheduleItemProps.day, - time: scheduleItemProps.time, - margin: scheduleItemProps.margin, - }), - ); - // adjust the passenger theoretical schedule : - // we guess the ideal passenger departure time based on the duration to - // reach the passenger starting point from the driver starting point - passengerSchedule = passengerSchedule - .map((scheduleItemProps: ScheduleItemProps) => { - try { - const passengerDate: Date = CalendarTools.firstDate( - scheduleItemProps.day, - this.props.dateInterval, - ); - const passengeStartDatetime: Date = CalendarTools.datetimeWithSeconds( - passengerDate, - scheduleItemProps.time, - this._passengerStartDuration(), - ); - return { - day: passengerDate.getUTCDay(), - margin: scheduleItemProps.margin, - time: `${passengeStartDatetime - .getUTCHours() - .toString() - .padStart(2, '0')}:${passengeStartDatetime - .getUTCMinutes() - .toString() - .padStart(2, '0')}`, - }; - } catch (e) { - // no possible passenger date or time - // TODO : find a test case ! - return undefined; - } - }) - .filter( - (scheduleItemProps: ScheduleItemProps | undefined) => - scheduleItemProps !== undefined, - ); - this.props.passengerSchedule = passengerSchedule.map( - (scheduleItemProps: ScheduleItemProps) => ({ - day: scheduleItemProps.day, - time: scheduleItemProps.time, - margin: scheduleItemProps.margin, - }), + const driverSchedule = new Schedule( + this.props.driverSchedule!, + this.props.dateInterval, ); + + this.props.passengerSchedule = driverSchedule + .adjust(this._passengerStartDuration()) + .unpack().items; }; private _createJourney = (driverScheduleItem: ScheduleItem): Journey => @@ -407,6 +322,60 @@ export class CandidateEntity extends AggregateRoot { } } +//TODO Use this class as part of the CandidateEntity aggregate +class Schedule extends ValueObject<{ + items: ScheduleItemProps[]; + dateInterval: DateInterval; +}> { + constructor(items: ScheduleItemProps[], dateInterval: DateInterval) { + super({ items, dateInterval }); + } + + protected validate(): void {} + + /** + * Add the given duration to each schedule item + * unless the expected new datetime is not possible, + * in which case the item is removed from the adjusted schedule + * @param duration time increment in seconds (can be negative) + * @returns the new adjusted schedule + */ + adjust(duration: number): Schedule { + const newItems = this.props.items.reduce((acc, scheduleItemProps) => { + try { + const itemDate: Date = CalendarTools.firstDate( + scheduleItemProps.day, + this.props.dateInterval, + ); + const driverStartDatetime: Date = CalendarTools.datetimeWithSeconds( + itemDate, + scheduleItemProps.time, + duration, + ); + acc.push({ + day: itemDate.getUTCDay(), + margin: scheduleItemProps.margin, + time: this._formatTime(driverStartDatetime), + }); + } catch (e) { + // no possible driver date or time + // TODO : find a test case ! + } + return acc; + }, new Array()); + + return new Schedule(newItems, this.props.dateInterval); + } + + private _formatTime(dateTime: Date) { + return ( + dateTime.getUTCHours().toString().padStart(2, '0') + + ':' + + dateTime.getUTCMinutes().toString().padStart(2, '0') + ); + } +} + type ScheduleItemRange = { scheduleItem: ScheduleItem; range: Date[];