journey and journey item value objects
This commit is contained in:
parent
c9c682c1fc
commit
dfc8dbcc51
|
@ -5,5 +5,7 @@ export class JourneyCompleter extends Completer {
|
|||
complete = async (
|
||||
candidates: CandidateEntity[],
|
||||
): Promise<CandidateEntity[]> =>
|
||||
candidates.map((candidate: CandidateEntity) => candidate.createJourney());
|
||||
candidates.map((candidate: CandidateEntity) =>
|
||||
candidate.createJourneys(this.query.fromDate, this.query.toDate),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
RouteCompleter,
|
||||
RouteCompleterType,
|
||||
} from './completer/route.completer';
|
||||
import { JourneyCompleter } from './completer/journey.completer';
|
||||
|
||||
export class PassengerOrientedAlgorithm extends Algorithm {
|
||||
constructor(
|
||||
|
@ -21,6 +22,7 @@ export class PassengerOrientedAlgorithm extends Algorithm {
|
|||
new RouteCompleter(query, RouteCompleterType.BASIC),
|
||||
new PassengerOrientedGeoFilter(query),
|
||||
new RouteCompleter(query, RouteCompleterType.DETAILED),
|
||||
new JourneyCompleter(query),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import { ExceptionBase } from '@mobicoop/ddd-library';
|
||||
|
||||
export class CalendarTools {
|
||||
/**
|
||||
* Returns the first date corresponding to a week day (0 based monday)
|
||||
* within a date range
|
||||
*/
|
||||
static firstDate = (
|
||||
weekDay: number,
|
||||
lowerDate: string,
|
||||
higherDate: string,
|
||||
): Date => {
|
||||
if (weekDay < 0 || weekDay > 6)
|
||||
throw new CalendarToolsException(
|
||||
new Error('weekDay must be between 0 and 6'),
|
||||
);
|
||||
const lowerDateAsDate: Date = new Date(lowerDate);
|
||||
const higherDateAsDate: Date = new Date(higherDate);
|
||||
if (lowerDateAsDate.getDay() == weekDay) return lowerDateAsDate;
|
||||
const nextDate: Date = new Date(lowerDateAsDate);
|
||||
nextDate.setDate(
|
||||
lowerDateAsDate.getDate() + (7 - (lowerDateAsDate.getDay() - weekDay)),
|
||||
);
|
||||
if (lowerDateAsDate.getDay() < weekDay) {
|
||||
nextDate.setMonth(lowerDateAsDate.getMonth());
|
||||
nextDate.setFullYear(lowerDateAsDate.getFullYear());
|
||||
nextDate.setDate(
|
||||
lowerDateAsDate.getDate() + (weekDay - lowerDateAsDate.getDay()),
|
||||
);
|
||||
}
|
||||
if (nextDate <= higherDateAsDate) return nextDate;
|
||||
throw new CalendarToolsException(
|
||||
new Error('no available day for the given date range'),
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the last date corresponding to a week day (0 based monday)
|
||||
* within a date range
|
||||
*/
|
||||
static lastDate = (
|
||||
weekDay: number,
|
||||
lowerDate: string,
|
||||
higherDate: string,
|
||||
): Date => {
|
||||
if (weekDay < 0 || weekDay > 6)
|
||||
throw new CalendarToolsException(
|
||||
new Error('weekDay must be between 0 and 6'),
|
||||
);
|
||||
const lowerDateAsDate: Date = new Date(lowerDate);
|
||||
const higherDateAsDate: Date = new Date(higherDate);
|
||||
if (higherDateAsDate.getDay() == weekDay) return higherDateAsDate;
|
||||
const previousDate: Date = new Date(higherDateAsDate);
|
||||
previousDate.setDate(
|
||||
higherDateAsDate.getDate() - (higherDateAsDate.getDay() - weekDay),
|
||||
);
|
||||
if (higherDateAsDate.getDay() < weekDay) {
|
||||
previousDate.setMonth(higherDateAsDate.getMonth());
|
||||
previousDate.setFullYear(higherDateAsDate.getFullYear());
|
||||
previousDate.setDate(
|
||||
higherDateAsDate.getDate() -
|
||||
(7 + (higherDateAsDate.getDay() - weekDay)),
|
||||
);
|
||||
}
|
||||
if (previousDate >= lowerDateAsDate) return previousDate;
|
||||
throw new CalendarToolsException(
|
||||
new Error('no available day for the given date range'),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export class CalendarToolsException extends ExceptionBase {
|
||||
static readonly message = 'Calendar tools error';
|
||||
|
||||
public readonly code = 'CALENDAR.TOOLS';
|
||||
|
||||
constructor(cause?: Error, metadata?: unknown) {
|
||||
super(CalendarToolsException.message, cause, metadata);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,10 @@ import { AggregateRoot, AggregateID } from '@mobicoop/ddd-library';
|
|||
import { CandidateProps, CreateCandidateProps } from './candidate.types';
|
||||
import { CarpoolStepProps } from './value-objects/carpool-step.value-object';
|
||||
import { StepProps } from './value-objects/step.value-object';
|
||||
import { ScheduleItem } from './value-objects/schedule-item.value-object';
|
||||
import { Journey } from './value-objects/journey.value-object';
|
||||
import { CalendarTools } from './calendar-tools.service';
|
||||
import { JourneyItem } from './value-objects/journey-item.value-object';
|
||||
|
||||
export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
||||
protected readonly _id: AggregateID;
|
||||
|
@ -30,7 +34,23 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
|||
isDetourValid = (): boolean =>
|
||||
this._validateDistanceDetour() && this._validateDurationDetour();
|
||||
|
||||
createJourney = (): CandidateEntity => this;
|
||||
createJourneys = (fromDate: string, toDate: string): CandidateEntity => {
|
||||
this.props.driverJourneys = this.props.driverSchedule
|
||||
.map((driverScheduleItem: ScheduleItem) =>
|
||||
this._createJourney(fromDate, toDate, driverScheduleItem),
|
||||
)
|
||||
.filter(
|
||||
(journey: Journey | undefined) => journey !== undefined,
|
||||
) as Journey[];
|
||||
this.props.passengerJourneys = this.props.passengerSchedule
|
||||
.map((passengerScheduleItem: ScheduleItem) =>
|
||||
this._createJourney(fromDate, toDate, passengerScheduleItem),
|
||||
)
|
||||
.filter(
|
||||
(journey: Journey | undefined) => journey !== undefined,
|
||||
) as Journey[];
|
||||
return this;
|
||||
};
|
||||
|
||||
private _validateDurationDetour = (): boolean =>
|
||||
this.props.duration
|
||||
|
@ -46,6 +66,22 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
|||
(1 + this.props.spacetimeDetourRatio.maxDistanceDetourRatio)
|
||||
: false;
|
||||
|
||||
private _createJourney = (
|
||||
fromDate: string,
|
||||
toDate: string,
|
||||
scheduleItem: ScheduleItem,
|
||||
): Journey | undefined =>
|
||||
new Journey({
|
||||
day: scheduleItem.day,
|
||||
firstDate: CalendarTools.firstDate(scheduleItem.day, fromDate, toDate),
|
||||
lastDate: CalendarTools.lastDate(scheduleItem.day, fromDate, toDate),
|
||||
journeyItems: this._createJourneyItems(scheduleItem),
|
||||
});
|
||||
|
||||
private _createJourneyItems = (
|
||||
scheduleItem: ScheduleItem,
|
||||
): JourneyItem[] => [];
|
||||
|
||||
validate(): void {
|
||||
// entity business rules validation to protect it's invariant before saving entity to a database
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ export interface CandidateProps {
|
|||
steps?: StepProps[];
|
||||
driverSchedule: ScheduleItemProps[];
|
||||
passengerSchedule: ScheduleItemProps[];
|
||||
journeys?: JourneyProps[];
|
||||
driverJourneys?: JourneyProps[];
|
||||
passengerJourneys?: JourneyProps[];
|
||||
spacetimeDetourRatio: SpacetimeDetourRatio;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ export class CarpoolPathCreator {
|
|||
});
|
||||
if (
|
||||
this.driverWaypoints.filter((driverWaypoint: Point) =>
|
||||
passengerWaypoint.isSame(driverWaypoint),
|
||||
passengerWaypoint.equals(driverWaypoint),
|
||||
).length == 0
|
||||
) {
|
||||
carpoolStep.actors.push(
|
||||
|
@ -233,7 +233,7 @@ export class CarpoolPathCreator {
|
|||
const uniquePoints: Point[] = [];
|
||||
carpoolSteps.forEach((carpoolStep: CarpoolStep) => {
|
||||
if (
|
||||
uniquePoints.find((point: Point) => point.isSame(carpoolStep.point)) ===
|
||||
uniquePoints.find((point: Point) => point.equals(carpoolStep.point)) ===
|
||||
undefined
|
||||
)
|
||||
uniquePoints.push(
|
||||
|
@ -249,7 +249,7 @@ export class CarpoolPathCreator {
|
|||
point,
|
||||
actors: carpoolSteps
|
||||
.filter((carpoolStep: CarpoolStep) =>
|
||||
carpoolStep.point.isSame(point),
|
||||
carpoolStep.point.equals(point),
|
||||
)
|
||||
.map((carpoolStep: CarpoolStep) => carpoolStep.actors)
|
||||
.flat(),
|
||||
|
|
|
@ -9,24 +9,15 @@ import { Actor, ActorProps } from './actor.value-object';
|
|||
* */
|
||||
|
||||
export interface ActorTimeProps extends ActorProps {
|
||||
time: string;
|
||||
minTime: string;
|
||||
maxTime: string;
|
||||
firstDatetime: Date;
|
||||
firstMinDatetime: Date;
|
||||
firstMaxDatetime: Date;
|
||||
lastDatetime: Date;
|
||||
lastMinDatetime: Date;
|
||||
lastMaxDatetime: Date;
|
||||
}
|
||||
|
||||
export class ActorTime extends ValueObject<ActorTimeProps> {
|
||||
get time(): string {
|
||||
return this.props.time;
|
||||
}
|
||||
|
||||
get minTime(): string {
|
||||
return this.props.minTime;
|
||||
}
|
||||
|
||||
get maxTime(): string {
|
||||
return this.props.maxTime;
|
||||
}
|
||||
|
||||
get role(): Role {
|
||||
return this.props.role;
|
||||
}
|
||||
|
@ -35,23 +26,59 @@ export class ActorTime extends ValueObject<ActorTimeProps> {
|
|||
return this.props.target;
|
||||
}
|
||||
|
||||
get firstDatetime(): Date {
|
||||
return this.props.firstDatetime;
|
||||
}
|
||||
|
||||
get firstMinDatetime(): Date {
|
||||
return this.props.firstMinDatetime;
|
||||
}
|
||||
|
||||
get firstMaxDatetime(): Date {
|
||||
return this.props.firstMaxDatetime;
|
||||
}
|
||||
|
||||
get lastDatetime(): Date {
|
||||
return this.props.lastDatetime;
|
||||
}
|
||||
|
||||
get lastMinDatetime(): Date {
|
||||
return this.props.lastMinDatetime;
|
||||
}
|
||||
|
||||
get lastMaxDatetime(): Date {
|
||||
return this.props.lastMaxDatetime;
|
||||
}
|
||||
|
||||
protected validate(props: ActorTimeProps): void {
|
||||
// validate actor props
|
||||
new Actor({
|
||||
role: props.role,
|
||||
target: props.target,
|
||||
});
|
||||
this._validateTime(props.time, 'time');
|
||||
this._validateTime(props.minTime, 'minTime');
|
||||
this._validateTime(props.maxTime, 'maxTime');
|
||||
}
|
||||
|
||||
private _validateTime(time: string, property: string): void {
|
||||
if (time.split(':').length != 2)
|
||||
throw new ArgumentInvalidException(`${property} is invalid`);
|
||||
if (parseInt(time.split(':')[0]) < 0 || parseInt(time.split(':')[0]) > 23)
|
||||
throw new ArgumentInvalidException(`${property} is invalid`);
|
||||
if (parseInt(time.split(':')[1]) < 0 || parseInt(time.split(':')[1]) > 59)
|
||||
throw new ArgumentInvalidException(`${property} is invalid`);
|
||||
if (props.firstDatetime.getDay() != props.lastDatetime.getDay())
|
||||
throw new ArgumentInvalidException(
|
||||
'firstDatetime week day must be equal to lastDatetime week day',
|
||||
);
|
||||
if (props.firstDatetime > props.lastDatetime)
|
||||
throw new ArgumentInvalidException(
|
||||
'firstDatetime must be before or equal to lastDatetime',
|
||||
);
|
||||
if (props.firstMinDatetime > props.firstDatetime)
|
||||
throw new ArgumentInvalidException(
|
||||
'firstMinDatetime must be before or equal to firstDatetime',
|
||||
);
|
||||
if (props.firstDatetime > props.firstMaxDatetime)
|
||||
throw new ArgumentInvalidException(
|
||||
'firstDatetime must be before or equal to firstMaxDatetime',
|
||||
);
|
||||
if (props.lastMinDatetime > props.lastDatetime)
|
||||
throw new ArgumentInvalidException(
|
||||
'lastMinDatetime must be before or equal to lastDatetime',
|
||||
);
|
||||
if (props.lastDatetime > props.lastMaxDatetime)
|
||||
throw new ArgumentInvalidException(
|
||||
'lastDatetime must be before or equal to lastMaxDatetime',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import {
|
||||
ArgumentOutOfRangeException,
|
||||
ValueObject,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import { ActorTime } from './actor-time.value-object';
|
||||
import { Step, StepProps } from './step.value-object';
|
||||
|
||||
/** Note:
|
||||
* Value Objects with multiple properties can contain
|
||||
* other Value Objects inside if needed.
|
||||
* */
|
||||
|
||||
export interface JourneyItemProps extends StepProps {
|
||||
actorTimes: ActorTime[];
|
||||
}
|
||||
|
||||
export class JourneyItem extends ValueObject<JourneyItemProps> {
|
||||
get duration(): number {
|
||||
return this.props.duration;
|
||||
}
|
||||
|
||||
get distance(): number | undefined {
|
||||
return this.props.distance;
|
||||
}
|
||||
|
||||
get lon(): number {
|
||||
return this.props.lon;
|
||||
}
|
||||
|
||||
get lat(): number {
|
||||
return this.props.lat;
|
||||
}
|
||||
|
||||
get actorTimes(): ActorTime[] {
|
||||
return this.props.actorTimes;
|
||||
}
|
||||
|
||||
protected validate(props: JourneyItemProps): void {
|
||||
// validate step props
|
||||
new Step({
|
||||
lon: props.lon,
|
||||
lat: props.lat,
|
||||
distance: props.distance,
|
||||
duration: props.duration,
|
||||
});
|
||||
if (props.actorTimes.length == 0)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
'at least one actorTime is required',
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,19 +3,18 @@ import {
|
|||
ArgumentOutOfRangeException,
|
||||
ValueObject,
|
||||
} from '@mobicoop/ddd-library';
|
||||
import { ScheduleItem, ScheduleItemProps } from './schedule-item.value-object';
|
||||
import { ActorTime } from './actor-time.value-object';
|
||||
import { Actor } from './actor.value-object';
|
||||
import { JourneyItem } from './journey-item.value-object';
|
||||
|
||||
/** Note:
|
||||
* Value Objects with multiple properties can contain
|
||||
* other Value Objects inside if needed.
|
||||
* */
|
||||
|
||||
export interface JourneyProps extends ScheduleItemProps {
|
||||
export interface JourneyProps {
|
||||
firstDate: Date;
|
||||
lastDate: Date;
|
||||
actorTimes: ActorTime[];
|
||||
day: number;
|
||||
journeyItems: JourneyItem[];
|
||||
}
|
||||
|
||||
export class Journey extends ValueObject<JourneyProps> {
|
||||
|
@ -27,41 +26,26 @@ export class Journey extends ValueObject<JourneyProps> {
|
|||
return this.props.lastDate;
|
||||
}
|
||||
|
||||
get actorTimes(): ActorTime[] {
|
||||
return this.props.actorTimes;
|
||||
}
|
||||
|
||||
get day(): number {
|
||||
return this.props.day;
|
||||
}
|
||||
|
||||
get time(): string {
|
||||
return this.props.time;
|
||||
}
|
||||
|
||||
get margin(): number {
|
||||
return this.props.margin;
|
||||
get journeyItems(): JourneyItem[] {
|
||||
return this.props.journeyItems;
|
||||
}
|
||||
|
||||
protected validate(props: JourneyProps): void {
|
||||
// validate scheduleItem props
|
||||
new ScheduleItem({
|
||||
day: props.day,
|
||||
time: props.time,
|
||||
margin: props.margin,
|
||||
});
|
||||
// validate actor times
|
||||
props.actorTimes.forEach((actorTime: ActorTime) => {
|
||||
new Actor({
|
||||
role: actorTime.role,
|
||||
target: actorTime.target,
|
||||
});
|
||||
});
|
||||
if (props.day < 0 || props.day > 6)
|
||||
throw new ArgumentOutOfRangeException('day must be between 0 and 6');
|
||||
if (props.firstDate.getDay() != props.lastDate.getDay())
|
||||
throw new ArgumentInvalidException(
|
||||
'firstDate week day must be equal to lastDate week day',
|
||||
);
|
||||
if (props.firstDate > props.lastDate)
|
||||
throw new ArgumentInvalidException('firstDate must be before lastDate');
|
||||
if (props.actorTimes.length < 4)
|
||||
throw new ArgumentOutOfRangeException(
|
||||
'at least 4 actorTimes are required',
|
||||
if (props.journeyItems.length < 2)
|
||||
throw new ArgumentInvalidException(
|
||||
'at least 2 journey items are required',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,6 @@ export class Point extends ValueObject<PointProps> {
|
|||
return this.props.lat;
|
||||
}
|
||||
|
||||
isSame = (point: this): boolean =>
|
||||
point.lon == this.lon && point.lat == this.lat;
|
||||
|
||||
protected validate(props: PointProps): void {
|
||||
if (props.lon > 180 || props.lon < -180)
|
||||
throw new ArgumentOutOfRangeException('lon must be between -180 and 180');
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { ArgumentInvalidException } from '@mobicoop/ddd-library';
|
||||
import { Role } from '@modules/ad/core/domain/ad.types';
|
||||
import { Target } from '@modules/ad/core/domain/candidate.types';
|
||||
import { ActorTime } from '@modules/ad/core/domain/value-objects/actor-time.value-object';
|
||||
|
@ -7,43 +8,100 @@ describe('Actor time value object', () => {
|
|||
const actorTimeVO = new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
time: '07:00',
|
||||
minTime: '06:45',
|
||||
maxTime: '07:15',
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
});
|
||||
expect(actorTimeVO.role).toBe(Role.DRIVER);
|
||||
expect(actorTimeVO.target).toBe(Target.START);
|
||||
expect(actorTimeVO.time).toBe('07:00');
|
||||
expect(actorTimeVO.minTime).toBe('06:45');
|
||||
expect(actorTimeVO.maxTime).toBe('07:15');
|
||||
expect(actorTimeVO.firstDatetime.getHours()).toBe(7);
|
||||
expect(actorTimeVO.firstMinDatetime.getMinutes()).toBe(45);
|
||||
expect(actorTimeVO.firstMaxDatetime.getMinutes()).toBe(15);
|
||||
expect(actorTimeVO.lastDatetime.getHours()).toBe(7);
|
||||
expect(actorTimeVO.lastMinDatetime.getMinutes()).toBe(45);
|
||||
expect(actorTimeVO.lastMaxDatetime.getMinutes()).toBe(15);
|
||||
});
|
||||
it('should throw an error if a time is invalid', () => {
|
||||
expect(() => {
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
time: '27:00',
|
||||
minTime: '06:45',
|
||||
maxTime: '07:15',
|
||||
});
|
||||
}).toThrow();
|
||||
expect(() => {
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
time: '07:00',
|
||||
minTime: '06:95',
|
||||
maxTime: '07:15',
|
||||
});
|
||||
}).toThrow();
|
||||
expect(() => {
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
time: '07:00',
|
||||
minTime: '06:45',
|
||||
maxTime: '07',
|
||||
});
|
||||
}).toThrow();
|
||||
it('should throw an error if dates are inconsistent', () => {
|
||||
expect(
|
||||
() =>
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:05'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
}),
|
||||
).toThrow(ArgumentInvalidException);
|
||||
expect(
|
||||
() =>
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 06:55'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
}),
|
||||
).toThrow(ArgumentInvalidException);
|
||||
expect(
|
||||
() =>
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:05'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
}),
|
||||
).toThrow(ArgumentInvalidException);
|
||||
expect(
|
||||
() =>
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 06:35'),
|
||||
}),
|
||||
).toThrow(ArgumentInvalidException);
|
||||
expect(
|
||||
() =>
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2024-08-30 07:00'),
|
||||
firstMinDatetime: new Date('2024-08-30 06:45'),
|
||||
firstMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
lastDatetime: new Date('2023-09-01 07:00'),
|
||||
lastMinDatetime: new Date('2023-09-01 06:45'),
|
||||
lastMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
}),
|
||||
).toThrow(ArgumentInvalidException);
|
||||
expect(
|
||||
() =>
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-31 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-31 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-31 06:35'),
|
||||
}),
|
||||
).toThrow(ArgumentInvalidException);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import {
|
||||
CalendarTools,
|
||||
CalendarToolsException,
|
||||
} from '@modules/ad/core/domain/calendar-tools.service';
|
||||
|
||||
describe('Calendar tools service', () => {
|
||||
describe('First date', () => {
|
||||
it('should return the first date for a given week day within a date range', () => {
|
||||
const firstDate: Date = CalendarTools.firstDate(
|
||||
1,
|
||||
'2023-08-31',
|
||||
'2023-09-07',
|
||||
);
|
||||
expect(firstDate.getDay()).toBe(1);
|
||||
expect(firstDate.getDate()).toBe(4);
|
||||
expect(firstDate.getMonth()).toBe(8);
|
||||
const secondDate: Date = CalendarTools.firstDate(
|
||||
5,
|
||||
'2023-08-31',
|
||||
'2023-09-07',
|
||||
);
|
||||
expect(secondDate.getDay()).toBe(5);
|
||||
expect(secondDate.getDate()).toBe(1);
|
||||
expect(secondDate.getMonth()).toBe(8);
|
||||
const thirdDate: Date = CalendarTools.firstDate(
|
||||
4,
|
||||
'2023-08-31',
|
||||
'2023-09-07',
|
||||
);
|
||||
expect(thirdDate.getDay()).toBe(4);
|
||||
expect(thirdDate.getDate()).toBe(31);
|
||||
expect(thirdDate.getMonth()).toBe(7);
|
||||
});
|
||||
it('should throw an exception if a given week day is not within a date range', () => {
|
||||
expect(() => {
|
||||
CalendarTools.firstDate(1, '2023-09-05', '2023-09-07');
|
||||
}).toThrow(CalendarToolsException);
|
||||
});
|
||||
it('should throw an exception if a given week day is invalid', () => {
|
||||
expect(() => {
|
||||
CalendarTools.firstDate(8, '2023-09-05', '2023-09-07');
|
||||
}).toThrow(CalendarToolsException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Second date', () => {
|
||||
it('should return the last date for a given week day within a date range', () => {
|
||||
const firstDate: Date = CalendarTools.lastDate(
|
||||
0,
|
||||
'2023-09-30',
|
||||
'2024-09-30',
|
||||
);
|
||||
expect(firstDate.getDay()).toBe(0);
|
||||
expect(firstDate.getDate()).toBe(29);
|
||||
expect(firstDate.getMonth()).toBe(8);
|
||||
const secondDate: Date = CalendarTools.lastDate(
|
||||
5,
|
||||
'2023-09-30',
|
||||
'2024-09-30',
|
||||
);
|
||||
expect(secondDate.getDay()).toBe(5);
|
||||
expect(secondDate.getDate()).toBe(27);
|
||||
expect(secondDate.getMonth()).toBe(8);
|
||||
const thirdDate: Date = CalendarTools.lastDate(
|
||||
1,
|
||||
'2023-09-30',
|
||||
'2024-09-30',
|
||||
);
|
||||
expect(thirdDate.getDay()).toBe(1);
|
||||
expect(thirdDate.getDate()).toBe(30);
|
||||
expect(thirdDate.getMonth()).toBe(8);
|
||||
});
|
||||
it('should throw an exception if a given week day is not within a date range', () => {
|
||||
expect(() => {
|
||||
CalendarTools.lastDate(2, '2024-09-27', '2024-09-30');
|
||||
}).toThrow(CalendarToolsException);
|
||||
});
|
||||
it('should throw an exception if a given week day is invalid', () => {
|
||||
expect(() => {
|
||||
CalendarTools.lastDate(8, '2023-09-30', '2024-09-30');
|
||||
}).toThrow(CalendarToolsException);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,45 @@
|
|||
import { ArgumentOutOfRangeException } from '@mobicoop/ddd-library';
|
||||
import { Role } from '@modules/ad/core/domain/ad.types';
|
||||
import { Target } from '@modules/ad/core/domain/candidate.types';
|
||||
import { ActorTime } from '@modules/ad/core/domain/value-objects/actor-time.value-object';
|
||||
import { JourneyItem } from '@modules/ad/core/domain/value-objects/journey-item.value-object';
|
||||
|
||||
describe('Journey item value object', () => {
|
||||
it('should create a journey item value object', () => {
|
||||
const journeyItemVO: JourneyItem = new JourneyItem({
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
duration: 1545,
|
||||
distance: 48754,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
}),
|
||||
],
|
||||
});
|
||||
expect(journeyItemVO.duration).toBe(1545);
|
||||
expect(journeyItemVO.distance).toBe(48754);
|
||||
expect(journeyItemVO.lon).toBe(6.17651);
|
||||
expect(journeyItemVO.lat).toBe(48.689445);
|
||||
expect(journeyItemVO.actorTimes[0].firstMaxDatetime.getMinutes()).toBe(15);
|
||||
});
|
||||
it('should throw an error if actorTimes is too short', () => {
|
||||
expect(
|
||||
() =>
|
||||
new JourneyItem({
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
duration: 1545,
|
||||
distance: 48754,
|
||||
actorTimes: [],
|
||||
}),
|
||||
).toThrow(ArgumentOutOfRangeException);
|
||||
});
|
||||
});
|
|
@ -90,14 +90,14 @@ const candidate: CandidateEntity = CandidateEntity.create({
|
|||
driverDuration: 13548,
|
||||
driverSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
day: 1,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
passengerSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
day: 1,
|
||||
time: '07:10',
|
||||
margin: 900,
|
||||
},
|
||||
|
@ -140,6 +140,7 @@ const candidate: CandidateEntity = CandidateEntity.create({
|
|||
],
|
||||
},
|
||||
]);
|
||||
candidate.createJourneys = jest.fn().mockImplementation(() => candidate);
|
||||
|
||||
describe('Journey completer', () => {
|
||||
it('should complete candidates with their journey', async () => {
|
||||
|
|
|
@ -5,161 +5,453 @@ import {
|
|||
import { Role } from '@modules/ad/core/domain/ad.types';
|
||||
import { Target } from '@modules/ad/core/domain/candidate.types';
|
||||
import { ActorTime } from '@modules/ad/core/domain/value-objects/actor-time.value-object';
|
||||
import { JourneyItem } from '@modules/ad/core/domain/value-objects/journey-item.value-object';
|
||||
import { Journey } from '@modules/ad/core/domain/value-objects/journey.value-object';
|
||||
|
||||
describe('Journey value object', () => {
|
||||
it('should create a journey value object', () => {
|
||||
const journeyVO = new Journey({
|
||||
firstDate: new Date('2023-09-20'),
|
||||
lastDate: new Date('2024-09-20'),
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
time: '07:00',
|
||||
minTime: '06:45',
|
||||
maxTime: '07:15',
|
||||
firstDate: new Date('2023-09-01'),
|
||||
lastDate: new Date('2024-08-30'),
|
||||
day: 5,
|
||||
journeyItems: [
|
||||
new JourneyItem({
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
duration: 0,
|
||||
distance: 0,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
time: '07:10',
|
||||
minTime: '06:55',
|
||||
maxTime: '07:25',
|
||||
new JourneyItem({
|
||||
lat: 48.369445,
|
||||
lon: 6.67487,
|
||||
duration: 2100,
|
||||
distance: 56878,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
firstDatetime: new Date('2023-09-01 07:35'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:20'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:50'),
|
||||
lastDatetime: new Date('2024-08-30 07:35'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:20'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:50'),
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:32'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:17'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:47'),
|
||||
lastDatetime: new Date('2024-08-30 07:32'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:17'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:47'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
time: '08:30',
|
||||
minTime: '08:15',
|
||||
maxTime: '08:45',
|
||||
new JourneyItem({
|
||||
lat: 47.98487,
|
||||
lon: 6.9427,
|
||||
duration: 3840,
|
||||
distance: 76491,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
firstDatetime: new Date('2023-09-01 08:04'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:51'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:19'),
|
||||
lastDatetime: new Date('2024-08-30 08:04'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:51'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:19'),
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
firstDatetime: new Date('2023-09-01 08:01'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:46'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:16'),
|
||||
lastDatetime: new Date('2024-08-30 08:01'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:46'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:16'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
time: '08:40',
|
||||
minTime: '08:25',
|
||||
maxTime: '08:55',
|
||||
new JourneyItem({
|
||||
lat: 47.365987,
|
||||
lon: 7.02154,
|
||||
duration: 4980,
|
||||
distance: 96475,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
firstDatetime: new Date('2023-09-01 08:23'),
|
||||
firstMinDatetime: new Date('2023-09-01 08:08'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:38'),
|
||||
lastDatetime: new Date('2024-08-30 08:23'),
|
||||
lastMinDatetime: new Date('2024-08-30 08:08'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:38'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
day: 0,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
});
|
||||
expect(journeyVO.day).toBe(0);
|
||||
expect(journeyVO.time).toBe('07:00');
|
||||
expect(journeyVO.margin).toBe(900);
|
||||
expect(journeyVO.actorTimes).toHaveLength(4);
|
||||
expect(journeyVO.firstDate.getDate()).toBe(20);
|
||||
expect(journeyVO.lastDate.getMonth()).toBe(8);
|
||||
expect(journeyVO.day).toBe(5);
|
||||
expect(journeyVO.journeyItems).toHaveLength(4);
|
||||
expect(journeyVO.firstDate.getDate()).toBe(1);
|
||||
expect(journeyVO.lastDate.getMonth()).toBe(7);
|
||||
});
|
||||
it('should throw an exception if day is invalid', () => {
|
||||
expect(() => {
|
||||
new Journey({
|
||||
firstDate: new Date('2023-09-20'),
|
||||
lastDate: new Date('2024-09-20'),
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
time: '07:00',
|
||||
minTime: '06:45',
|
||||
maxTime: '07:15',
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
time: '07:10',
|
||||
minTime: '06:55',
|
||||
maxTime: '07:25',
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
time: '08:30',
|
||||
minTime: '08:15',
|
||||
maxTime: '08:45',
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
time: '08:40',
|
||||
minTime: '08:25',
|
||||
maxTime: '08:55',
|
||||
}),
|
||||
],
|
||||
day: 7,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
});
|
||||
}).toThrow(ArgumentOutOfRangeException);
|
||||
it('should throw an error if day is wrong', () => {
|
||||
expect(
|
||||
() =>
|
||||
new Journey({
|
||||
firstDate: new Date('2023-09-01'),
|
||||
lastDate: new Date('2024-08-30'),
|
||||
day: 7,
|
||||
journeyItems: [
|
||||
new JourneyItem({
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
duration: 0,
|
||||
distance: 0,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new JourneyItem({
|
||||
lat: 48.369445,
|
||||
lon: 6.67487,
|
||||
duration: 2100,
|
||||
distance: 56878,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
firstDatetime: new Date('2023-09-01 07:35'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:20'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:50'),
|
||||
lastDatetime: new Date('2024-08-30 07:35'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:20'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:50'),
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:32'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:17'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:47'),
|
||||
lastDatetime: new Date('2024-08-30 07:32'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:17'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:47'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new JourneyItem({
|
||||
lat: 47.98487,
|
||||
lon: 6.9427,
|
||||
duration: 3840,
|
||||
distance: 76491,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
firstDatetime: new Date('2023-09-01 08:04'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:51'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:19'),
|
||||
lastDatetime: new Date('2024-08-30 08:04'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:51'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:19'),
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
firstDatetime: new Date('2023-09-01 08:01'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:46'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:16'),
|
||||
lastDatetime: new Date('2024-08-30 08:01'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:46'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:16'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new JourneyItem({
|
||||
lat: 47.365987,
|
||||
lon: 7.02154,
|
||||
duration: 4980,
|
||||
distance: 96475,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
firstDatetime: new Date('2023-09-01 08:23'),
|
||||
firstMinDatetime: new Date('2023-09-01 08:08'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:38'),
|
||||
lastDatetime: new Date('2024-08-30 08:23'),
|
||||
lastMinDatetime: new Date('2024-08-30 08:08'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:38'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
).toThrow(ArgumentOutOfRangeException);
|
||||
});
|
||||
it('should throw an exception if actor times is too short', () => {
|
||||
expect(() => {
|
||||
new Journey({
|
||||
firstDate: new Date('2023-09-20'),
|
||||
lastDate: new Date('2024-09-20'),
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
time: '07:00',
|
||||
minTime: '06:45',
|
||||
maxTime: '07:15',
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
time: '08:30',
|
||||
minTime: '08:15',
|
||||
maxTime: '08:45',
|
||||
}),
|
||||
],
|
||||
day: 0,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
});
|
||||
}).toThrow(ArgumentOutOfRangeException);
|
||||
it('should throw an error if dates are inconsistent', () => {
|
||||
expect(
|
||||
() =>
|
||||
new Journey({
|
||||
firstDate: new Date('2023-09-01'),
|
||||
lastDate: new Date('2024-08-31'),
|
||||
day: 5,
|
||||
journeyItems: [
|
||||
new JourneyItem({
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
duration: 0,
|
||||
distance: 0,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new JourneyItem({
|
||||
lat: 48.369445,
|
||||
lon: 6.67487,
|
||||
duration: 2100,
|
||||
distance: 56878,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
firstDatetime: new Date('2023-09-01 07:35'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:20'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:50'),
|
||||
lastDatetime: new Date('2024-08-30 07:35'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:20'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:50'),
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:32'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:17'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:47'),
|
||||
lastDatetime: new Date('2024-08-30 07:32'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:17'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:47'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new JourneyItem({
|
||||
lat: 47.98487,
|
||||
lon: 6.9427,
|
||||
duration: 3840,
|
||||
distance: 76491,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
firstDatetime: new Date('2023-09-01 08:04'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:51'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:19'),
|
||||
lastDatetime: new Date('2024-08-30 08:04'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:51'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:19'),
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
firstDatetime: new Date('2023-09-01 08:01'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:46'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:16'),
|
||||
lastDatetime: new Date('2024-08-30 08:01'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:46'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:16'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new JourneyItem({
|
||||
lat: 47.365987,
|
||||
lon: 7.02154,
|
||||
duration: 4980,
|
||||
distance: 96475,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
firstDatetime: new Date('2023-09-01 08:23'),
|
||||
firstMinDatetime: new Date('2023-09-01 08:08'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:38'),
|
||||
lastDatetime: new Date('2024-08-30 08:23'),
|
||||
lastMinDatetime: new Date('2024-08-30 08:08'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:38'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
).toThrow(ArgumentInvalidException);
|
||||
expect(
|
||||
() =>
|
||||
new Journey({
|
||||
firstDate: new Date('2024-08-30'),
|
||||
lastDate: new Date('2023-09-01'),
|
||||
day: 5,
|
||||
journeyItems: [
|
||||
new JourneyItem({
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
duration: 0,
|
||||
distance: 0,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new JourneyItem({
|
||||
lat: 48.369445,
|
||||
lon: 6.67487,
|
||||
duration: 2100,
|
||||
distance: 56878,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
firstDatetime: new Date('2023-09-01 07:35'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:20'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:50'),
|
||||
lastDatetime: new Date('2024-08-30 07:35'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:20'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:50'),
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:32'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:17'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:47'),
|
||||
lastDatetime: new Date('2024-08-30 07:32'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:17'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:47'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new JourneyItem({
|
||||
lat: 47.98487,
|
||||
lon: 6.9427,
|
||||
duration: 3840,
|
||||
distance: 76491,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
firstDatetime: new Date('2023-09-01 08:04'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:51'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:19'),
|
||||
lastDatetime: new Date('2024-08-30 08:04'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:51'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:19'),
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
firstDatetime: new Date('2023-09-01 08:01'),
|
||||
firstMinDatetime: new Date('2023-09-01 07:46'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:16'),
|
||||
lastDatetime: new Date('2024-08-30 08:01'),
|
||||
lastMinDatetime: new Date('2024-08-30 07:46'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:16'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
new JourneyItem({
|
||||
lat: 47.365987,
|
||||
lon: 7.02154,
|
||||
duration: 4980,
|
||||
distance: 96475,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
firstDatetime: new Date('2023-09-01 08:23'),
|
||||
firstMinDatetime: new Date('2023-09-01 08:08'),
|
||||
firstMaxDatetime: new Date('2023-09-01 08:38'),
|
||||
lastDatetime: new Date('2024-08-30 08:23'),
|
||||
lastMinDatetime: new Date('2024-08-30 08:08'),
|
||||
lastMaxDatetime: new Date('2024-08-30 08:38'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
).toThrow(ArgumentInvalidException);
|
||||
});
|
||||
it('should throw an exception if dates are invalid', () => {
|
||||
expect(() => {
|
||||
new Journey({
|
||||
firstDate: new Date('2023-09-20'),
|
||||
lastDate: new Date('2023-09-19'),
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
time: '07:00',
|
||||
minTime: '06:45',
|
||||
maxTime: '07:15',
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
time: '07:10',
|
||||
minTime: '06:55',
|
||||
maxTime: '07:25',
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
time: '08:30',
|
||||
minTime: '08:15',
|
||||
maxTime: '08:45',
|
||||
}),
|
||||
new ActorTime({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
time: '08:40',
|
||||
minTime: '08:25',
|
||||
maxTime: '08:55',
|
||||
}),
|
||||
],
|
||||
day: 0,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
});
|
||||
}).toThrow(ArgumentInvalidException);
|
||||
it('should throw an error if journeyItems is too short', () => {
|
||||
expect(
|
||||
() =>
|
||||
new Journey({
|
||||
firstDate: new Date('2023-09-01'),
|
||||
lastDate: new Date('2024-08-30'),
|
||||
day: 5,
|
||||
journeyItems: [
|
||||
new JourneyItem({
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
duration: 0,
|
||||
distance: 0,
|
||||
actorTimes: [
|
||||
new ActorTime({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
firstDatetime: new Date('2023-09-01 07:00'),
|
||||
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||
lastDatetime: new Date('2024-08-30 07:00'),
|
||||
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}),
|
||||
).toThrow(ArgumentInvalidException);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -23,8 +23,8 @@ describe('Point value object', () => {
|
|||
lat: 48.689446,
|
||||
lon: 6.17651,
|
||||
});
|
||||
expect(pointVO.isSame(identicalPointVO)).toBeTruthy();
|
||||
expect(pointVO.isSame(differentPointVO)).toBeFalsy();
|
||||
expect(pointVO.equals(identicalPointVO)).toBeTruthy();
|
||||
expect(pointVO.equals(differentPointVO)).toBeFalsy();
|
||||
});
|
||||
it('should throw an exception if longitude is invalid', () => {
|
||||
expect(() => {
|
||||
|
|
Loading…
Reference in New Issue