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 (
|
complete = async (
|
||||||
candidates: CandidateEntity[],
|
candidates: CandidateEntity[],
|
||||||
): Promise<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,
|
RouteCompleter,
|
||||||
RouteCompleterType,
|
RouteCompleterType,
|
||||||
} from './completer/route.completer';
|
} from './completer/route.completer';
|
||||||
|
import { JourneyCompleter } from './completer/journey.completer';
|
||||||
|
|
||||||
export class PassengerOrientedAlgorithm extends Algorithm {
|
export class PassengerOrientedAlgorithm extends Algorithm {
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -21,6 +22,7 @@ export class PassengerOrientedAlgorithm extends Algorithm {
|
||||||
new RouteCompleter(query, RouteCompleterType.BASIC),
|
new RouteCompleter(query, RouteCompleterType.BASIC),
|
||||||
new PassengerOrientedGeoFilter(query),
|
new PassengerOrientedGeoFilter(query),
|
||||||
new RouteCompleter(query, RouteCompleterType.DETAILED),
|
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 { CandidateProps, CreateCandidateProps } from './candidate.types';
|
||||||
import { CarpoolStepProps } from './value-objects/carpool-step.value-object';
|
import { CarpoolStepProps } from './value-objects/carpool-step.value-object';
|
||||||
import { StepProps } from './value-objects/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> {
|
export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
||||||
protected readonly _id: AggregateID;
|
protected readonly _id: AggregateID;
|
||||||
|
@ -30,7 +34,23 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
||||||
isDetourValid = (): boolean =>
|
isDetourValid = (): boolean =>
|
||||||
this._validateDistanceDetour() && this._validateDurationDetour();
|
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 =>
|
private _validateDurationDetour = (): boolean =>
|
||||||
this.props.duration
|
this.props.duration
|
||||||
|
@ -46,6 +66,22 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
||||||
(1 + this.props.spacetimeDetourRatio.maxDistanceDetourRatio)
|
(1 + this.props.spacetimeDetourRatio.maxDistanceDetourRatio)
|
||||||
: false;
|
: 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 {
|
validate(): void {
|
||||||
// entity business rules validation to protect it's invariant before saving entity to a database
|
// entity business rules validation to protect it's invariant before saving entity to a database
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ export interface CandidateProps {
|
||||||
steps?: StepProps[];
|
steps?: StepProps[];
|
||||||
driverSchedule: ScheduleItemProps[];
|
driverSchedule: ScheduleItemProps[];
|
||||||
passengerSchedule: ScheduleItemProps[];
|
passengerSchedule: ScheduleItemProps[];
|
||||||
journeys?: JourneyProps[];
|
driverJourneys?: JourneyProps[];
|
||||||
|
passengerJourneys?: JourneyProps[];
|
||||||
spacetimeDetourRatio: SpacetimeDetourRatio;
|
spacetimeDetourRatio: SpacetimeDetourRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ export class CarpoolPathCreator {
|
||||||
});
|
});
|
||||||
if (
|
if (
|
||||||
this.driverWaypoints.filter((driverWaypoint: Point) =>
|
this.driverWaypoints.filter((driverWaypoint: Point) =>
|
||||||
passengerWaypoint.isSame(driverWaypoint),
|
passengerWaypoint.equals(driverWaypoint),
|
||||||
).length == 0
|
).length == 0
|
||||||
) {
|
) {
|
||||||
carpoolStep.actors.push(
|
carpoolStep.actors.push(
|
||||||
|
@ -233,7 +233,7 @@ export class CarpoolPathCreator {
|
||||||
const uniquePoints: Point[] = [];
|
const uniquePoints: Point[] = [];
|
||||||
carpoolSteps.forEach((carpoolStep: CarpoolStep) => {
|
carpoolSteps.forEach((carpoolStep: CarpoolStep) => {
|
||||||
if (
|
if (
|
||||||
uniquePoints.find((point: Point) => point.isSame(carpoolStep.point)) ===
|
uniquePoints.find((point: Point) => point.equals(carpoolStep.point)) ===
|
||||||
undefined
|
undefined
|
||||||
)
|
)
|
||||||
uniquePoints.push(
|
uniquePoints.push(
|
||||||
|
@ -249,7 +249,7 @@ export class CarpoolPathCreator {
|
||||||
point,
|
point,
|
||||||
actors: carpoolSteps
|
actors: carpoolSteps
|
||||||
.filter((carpoolStep: CarpoolStep) =>
|
.filter((carpoolStep: CarpoolStep) =>
|
||||||
carpoolStep.point.isSame(point),
|
carpoolStep.point.equals(point),
|
||||||
)
|
)
|
||||||
.map((carpoolStep: CarpoolStep) => carpoolStep.actors)
|
.map((carpoolStep: CarpoolStep) => carpoolStep.actors)
|
||||||
.flat(),
|
.flat(),
|
||||||
|
|
|
@ -9,24 +9,15 @@ import { Actor, ActorProps } from './actor.value-object';
|
||||||
* */
|
* */
|
||||||
|
|
||||||
export interface ActorTimeProps extends ActorProps {
|
export interface ActorTimeProps extends ActorProps {
|
||||||
time: string;
|
firstDatetime: Date;
|
||||||
minTime: string;
|
firstMinDatetime: Date;
|
||||||
maxTime: string;
|
firstMaxDatetime: Date;
|
||||||
|
lastDatetime: Date;
|
||||||
|
lastMinDatetime: Date;
|
||||||
|
lastMaxDatetime: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ActorTime extends ValueObject<ActorTimeProps> {
|
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 {
|
get role(): Role {
|
||||||
return this.props.role;
|
return this.props.role;
|
||||||
}
|
}
|
||||||
|
@ -35,23 +26,59 @@ export class ActorTime extends ValueObject<ActorTimeProps> {
|
||||||
return this.props.target;
|
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 {
|
protected validate(props: ActorTimeProps): void {
|
||||||
// validate actor props
|
// validate actor props
|
||||||
new Actor({
|
new Actor({
|
||||||
role: props.role,
|
role: props.role,
|
||||||
target: props.target,
|
target: props.target,
|
||||||
});
|
});
|
||||||
this._validateTime(props.time, 'time');
|
if (props.firstDatetime.getDay() != props.lastDatetime.getDay())
|
||||||
this._validateTime(props.minTime, 'minTime');
|
throw new ArgumentInvalidException(
|
||||||
this._validateTime(props.maxTime, 'maxTime');
|
'firstDatetime week day must be equal to lastDatetime week day',
|
||||||
}
|
);
|
||||||
|
if (props.firstDatetime > props.lastDatetime)
|
||||||
private _validateTime(time: string, property: string): void {
|
throw new ArgumentInvalidException(
|
||||||
if (time.split(':').length != 2)
|
'firstDatetime must be before or equal to lastDatetime',
|
||||||
throw new ArgumentInvalidException(`${property} is invalid`);
|
);
|
||||||
if (parseInt(time.split(':')[0]) < 0 || parseInt(time.split(':')[0]) > 23)
|
if (props.firstMinDatetime > props.firstDatetime)
|
||||||
throw new ArgumentInvalidException(`${property} is invalid`);
|
throw new ArgumentInvalidException(
|
||||||
if (parseInt(time.split(':')[1]) < 0 || parseInt(time.split(':')[1]) > 59)
|
'firstMinDatetime must be before or equal to firstDatetime',
|
||||||
throw new ArgumentInvalidException(`${property} is invalid`);
|
);
|
||||||
|
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,
|
ArgumentOutOfRangeException,
|
||||||
ValueObject,
|
ValueObject,
|
||||||
} from '@mobicoop/ddd-library';
|
} from '@mobicoop/ddd-library';
|
||||||
import { ScheduleItem, ScheduleItemProps } from './schedule-item.value-object';
|
import { JourneyItem } from './journey-item.value-object';
|
||||||
import { ActorTime } from './actor-time.value-object';
|
|
||||||
import { Actor } from './actor.value-object';
|
|
||||||
|
|
||||||
/** Note:
|
/** Note:
|
||||||
* Value Objects with multiple properties can contain
|
* Value Objects with multiple properties can contain
|
||||||
* other Value Objects inside if needed.
|
* other Value Objects inside if needed.
|
||||||
* */
|
* */
|
||||||
|
|
||||||
export interface JourneyProps extends ScheduleItemProps {
|
export interface JourneyProps {
|
||||||
firstDate: Date;
|
firstDate: Date;
|
||||||
lastDate: Date;
|
lastDate: Date;
|
||||||
actorTimes: ActorTime[];
|
day: number;
|
||||||
|
journeyItems: JourneyItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Journey extends ValueObject<JourneyProps> {
|
export class Journey extends ValueObject<JourneyProps> {
|
||||||
|
@ -27,41 +26,26 @@ export class Journey extends ValueObject<JourneyProps> {
|
||||||
return this.props.lastDate;
|
return this.props.lastDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
get actorTimes(): ActorTime[] {
|
|
||||||
return this.props.actorTimes;
|
|
||||||
}
|
|
||||||
|
|
||||||
get day(): number {
|
get day(): number {
|
||||||
return this.props.day;
|
return this.props.day;
|
||||||
}
|
}
|
||||||
|
|
||||||
get time(): string {
|
get journeyItems(): JourneyItem[] {
|
||||||
return this.props.time;
|
return this.props.journeyItems;
|
||||||
}
|
|
||||||
|
|
||||||
get margin(): number {
|
|
||||||
return this.props.margin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected validate(props: JourneyProps): void {
|
protected validate(props: JourneyProps): void {
|
||||||
// validate scheduleItem props
|
if (props.day < 0 || props.day > 6)
|
||||||
new ScheduleItem({
|
throw new ArgumentOutOfRangeException('day must be between 0 and 6');
|
||||||
day: props.day,
|
if (props.firstDate.getDay() != props.lastDate.getDay())
|
||||||
time: props.time,
|
throw new ArgumentInvalidException(
|
||||||
margin: props.margin,
|
'firstDate week day must be equal to lastDate week day',
|
||||||
});
|
);
|
||||||
// validate actor times
|
|
||||||
props.actorTimes.forEach((actorTime: ActorTime) => {
|
|
||||||
new Actor({
|
|
||||||
role: actorTime.role,
|
|
||||||
target: actorTime.target,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (props.firstDate > props.lastDate)
|
if (props.firstDate > props.lastDate)
|
||||||
throw new ArgumentInvalidException('firstDate must be before lastDate');
|
throw new ArgumentInvalidException('firstDate must be before lastDate');
|
||||||
if (props.actorTimes.length < 4)
|
if (props.journeyItems.length < 2)
|
||||||
throw new ArgumentOutOfRangeException(
|
throw new ArgumentInvalidException(
|
||||||
'at least 4 actorTimes are required',
|
'at least 2 journey items are required',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,6 @@ export class Point extends ValueObject<PointProps> {
|
||||||
return this.props.lat;
|
return this.props.lat;
|
||||||
}
|
}
|
||||||
|
|
||||||
isSame = (point: this): boolean =>
|
|
||||||
point.lon == this.lon && point.lat == this.lat;
|
|
||||||
|
|
||||||
protected validate(props: PointProps): void {
|
protected validate(props: PointProps): void {
|
||||||
if (props.lon > 180 || props.lon < -180)
|
if (props.lon > 180 || props.lon < -180)
|
||||||
throw new ArgumentOutOfRangeException('lon must be between -180 and 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 { Role } from '@modules/ad/core/domain/ad.types';
|
||||||
import { Target } from '@modules/ad/core/domain/candidate.types';
|
import { Target } from '@modules/ad/core/domain/candidate.types';
|
||||||
import { ActorTime } from '@modules/ad/core/domain/value-objects/actor-time.value-object';
|
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({
|
const actorTimeVO = new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.START,
|
target: Target.START,
|
||||||
time: '07:00',
|
firstDatetime: new Date('2023-09-01 07:00'),
|
||||||
minTime: '06:45',
|
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||||
maxTime: '07:15',
|
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.role).toBe(Role.DRIVER);
|
||||||
expect(actorTimeVO.target).toBe(Target.START);
|
expect(actorTimeVO.target).toBe(Target.START);
|
||||||
expect(actorTimeVO.time).toBe('07:00');
|
expect(actorTimeVO.firstDatetime.getHours()).toBe(7);
|
||||||
expect(actorTimeVO.minTime).toBe('06:45');
|
expect(actorTimeVO.firstMinDatetime.getMinutes()).toBe(45);
|
||||||
expect(actorTimeVO.maxTime).toBe('07:15');
|
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', () => {
|
it('should throw an error if dates are inconsistent', () => {
|
||||||
expect(() => {
|
expect(
|
||||||
|
() =>
|
||||||
new ActorTime({
|
new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.START,
|
target: Target.START,
|
||||||
time: '27:00',
|
firstDatetime: new Date('2023-09-01 07:00'),
|
||||||
minTime: '06:45',
|
firstMinDatetime: new Date('2023-09-01 07:05'),
|
||||||
maxTime: '07:15',
|
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||||
});
|
lastDatetime: new Date('2024-08-30 07:00'),
|
||||||
}).toThrow();
|
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||||
expect(() => {
|
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||||
|
}),
|
||||||
|
).toThrow(ArgumentInvalidException);
|
||||||
|
expect(
|
||||||
|
() =>
|
||||||
new ActorTime({
|
new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.START,
|
target: Target.START,
|
||||||
time: '07:00',
|
firstDatetime: new Date('2023-09-01 07:00'),
|
||||||
minTime: '06:95',
|
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||||
maxTime: '07:15',
|
firstMaxDatetime: new Date('2023-09-01 06:55'),
|
||||||
});
|
lastDatetime: new Date('2024-08-30 07:00'),
|
||||||
}).toThrow();
|
lastMinDatetime: new Date('2024-08-30 06:45'),
|
||||||
expect(() => {
|
lastMaxDatetime: new Date('2024-08-30 07:15'),
|
||||||
|
}),
|
||||||
|
).toThrow(ArgumentInvalidException);
|
||||||
|
expect(
|
||||||
|
() =>
|
||||||
new ActorTime({
|
new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.START,
|
target: Target.START,
|
||||||
time: '07:00',
|
firstDatetime: new Date('2023-09-01 07:00'),
|
||||||
minTime: '06:45',
|
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||||
maxTime: '07',
|
firstMaxDatetime: new Date('2023-09-01 07:15'),
|
||||||
});
|
lastDatetime: new Date('2024-08-30 07:00'),
|
||||||
}).toThrow();
|
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,
|
driverDuration: 13548,
|
||||||
driverSchedule: [
|
driverSchedule: [
|
||||||
{
|
{
|
||||||
day: 0,
|
day: 1,
|
||||||
time: '07:00',
|
time: '07:00',
|
||||||
margin: 900,
|
margin: 900,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
passengerSchedule: [
|
passengerSchedule: [
|
||||||
{
|
{
|
||||||
day: 0,
|
day: 1,
|
||||||
time: '07:10',
|
time: '07:10',
|
||||||
margin: 900,
|
margin: 900,
|
||||||
},
|
},
|
||||||
|
@ -140,6 +140,7 @@ const candidate: CandidateEntity = CandidateEntity.create({
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
candidate.createJourneys = jest.fn().mockImplementation(() => candidate);
|
||||||
|
|
||||||
describe('Journey completer', () => {
|
describe('Journey completer', () => {
|
||||||
it('should complete candidates with their journey', async () => {
|
it('should complete candidates with their journey', async () => {
|
||||||
|
|
|
@ -5,161 +5,453 @@ import {
|
||||||
import { Role } from '@modules/ad/core/domain/ad.types';
|
import { Role } from '@modules/ad/core/domain/ad.types';
|
||||||
import { Target } from '@modules/ad/core/domain/candidate.types';
|
import { Target } from '@modules/ad/core/domain/candidate.types';
|
||||||
import { ActorTime } from '@modules/ad/core/domain/value-objects/actor-time.value-object';
|
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';
|
import { Journey } from '@modules/ad/core/domain/value-objects/journey.value-object';
|
||||||
|
|
||||||
describe('Journey value object', () => {
|
describe('Journey value object', () => {
|
||||||
it('should create a journey value object', () => {
|
it('should create a journey value object', () => {
|
||||||
const journeyVO = new Journey({
|
const journeyVO = new Journey({
|
||||||
firstDate: new Date('2023-09-20'),
|
firstDate: new Date('2023-09-01'),
|
||||||
lastDate: new Date('2024-09-20'),
|
lastDate: new Date('2024-08-30'),
|
||||||
|
day: 5,
|
||||||
|
journeyItems: [
|
||||||
|
new JourneyItem({
|
||||||
|
lat: 48.689445,
|
||||||
|
lon: 6.17651,
|
||||||
|
duration: 0,
|
||||||
|
distance: 0,
|
||||||
actorTimes: [
|
actorTimes: [
|
||||||
new ActorTime({
|
new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.START,
|
target: Target.START,
|
||||||
time: '07:00',
|
firstDatetime: new Date('2023-09-01 07:00'),
|
||||||
minTime: '06:45',
|
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||||
maxTime: '07:15',
|
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({
|
new ActorTime({
|
||||||
role: Role.PASSENGER,
|
role: Role.PASSENGER,
|
||||||
target: Target.START,
|
target: Target.START,
|
||||||
time: '07:10',
|
firstDatetime: new Date('2023-09-01 07:32'),
|
||||||
minTime: '06:55',
|
firstMinDatetime: new Date('2023-09-01 07:17'),
|
||||||
maxTime: '07:25',
|
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({
|
new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.FINISH,
|
target: Target.NEUTRAL,
|
||||||
time: '08:30',
|
firstDatetime: new Date('2023-09-01 08:04'),
|
||||||
minTime: '08:15',
|
firstMinDatetime: new Date('2023-09-01 07:51'),
|
||||||
maxTime: '08:45',
|
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({
|
new ActorTime({
|
||||||
role: Role.PASSENGER,
|
role: Role.PASSENGER,
|
||||||
target: Target.FINISH,
|
target: Target.FINISH,
|
||||||
time: '08:40',
|
firstDatetime: new Date('2023-09-01 08:01'),
|
||||||
minTime: '08:25',
|
firstMinDatetime: new Date('2023-09-01 07:46'),
|
||||||
maxTime: '08:55',
|
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'),
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
day: 0,
|
|
||||||
time: '07:00',
|
|
||||||
margin: 900,
|
|
||||||
});
|
});
|
||||||
expect(journeyVO.day).toBe(0);
|
expect(journeyVO.day).toBe(5);
|
||||||
expect(journeyVO.time).toBe('07:00');
|
expect(journeyVO.journeyItems).toHaveLength(4);
|
||||||
expect(journeyVO.margin).toBe(900);
|
expect(journeyVO.firstDate.getDate()).toBe(1);
|
||||||
expect(journeyVO.actorTimes).toHaveLength(4);
|
expect(journeyVO.lastDate.getMonth()).toBe(7);
|
||||||
expect(journeyVO.firstDate.getDate()).toBe(20);
|
|
||||||
expect(journeyVO.lastDate.getMonth()).toBe(8);
|
|
||||||
});
|
});
|
||||||
it('should throw an exception if day is invalid', () => {
|
it('should throw an error if day is wrong', () => {
|
||||||
expect(() => {
|
expect(
|
||||||
|
() =>
|
||||||
new Journey({
|
new Journey({
|
||||||
firstDate: new Date('2023-09-20'),
|
firstDate: new Date('2023-09-01'),
|
||||||
lastDate: new Date('2024-09-20'),
|
lastDate: new Date('2024-08-30'),
|
||||||
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,
|
day: 7,
|
||||||
time: '07:00',
|
journeyItems: [
|
||||||
margin: 900,
|
new JourneyItem({
|
||||||
});
|
lat: 48.689445,
|
||||||
}).toThrow(ArgumentOutOfRangeException);
|
lon: 6.17651,
|
||||||
});
|
duration: 0,
|
||||||
it('should throw an exception if actor times is too short', () => {
|
distance: 0,
|
||||||
expect(() => {
|
|
||||||
new Journey({
|
|
||||||
firstDate: new Date('2023-09-20'),
|
|
||||||
lastDate: new Date('2024-09-20'),
|
|
||||||
actorTimes: [
|
actorTimes: [
|
||||||
new ActorTime({
|
new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.START,
|
target: Target.START,
|
||||||
time: '07:00',
|
firstDatetime: new Date('2023-09-01 07:00'),
|
||||||
minTime: '06:45',
|
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||||
maxTime: '07:15',
|
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({
|
new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.FINISH,
|
target: Target.FINISH,
|
||||||
time: '08:30',
|
firstDatetime: new Date('2023-09-01 08:23'),
|
||||||
minTime: '08:15',
|
firstMinDatetime: new Date('2023-09-01 08:08'),
|
||||||
maxTime: '08:45',
|
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,
|
}),
|
||||||
|
).toThrow(ArgumentOutOfRangeException);
|
||||||
});
|
});
|
||||||
}).toThrow(ArgumentOutOfRangeException);
|
it('should throw an error if dates are inconsistent', () => {
|
||||||
});
|
expect(
|
||||||
it('should throw an exception if dates are invalid', () => {
|
() =>
|
||||||
expect(() => {
|
|
||||||
new Journey({
|
new Journey({
|
||||||
firstDate: new Date('2023-09-20'),
|
firstDate: new Date('2023-09-01'),
|
||||||
lastDate: new Date('2023-09-19'),
|
lastDate: new Date('2024-08-31'),
|
||||||
|
day: 5,
|
||||||
|
journeyItems: [
|
||||||
|
new JourneyItem({
|
||||||
|
lat: 48.689445,
|
||||||
|
lon: 6.17651,
|
||||||
|
duration: 0,
|
||||||
|
distance: 0,
|
||||||
actorTimes: [
|
actorTimes: [
|
||||||
new ActorTime({
|
new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.START,
|
target: Target.START,
|
||||||
time: '07:00',
|
firstDatetime: new Date('2023-09-01 07:00'),
|
||||||
minTime: '06:45',
|
firstMinDatetime: new Date('2023-09-01 06:45'),
|
||||||
maxTime: '07:15',
|
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({
|
new ActorTime({
|
||||||
role: Role.PASSENGER,
|
role: Role.PASSENGER,
|
||||||
target: Target.START,
|
target: Target.START,
|
||||||
time: '07:10',
|
firstDatetime: new Date('2023-09-01 07:32'),
|
||||||
minTime: '06:55',
|
firstMinDatetime: new Date('2023-09-01 07:17'),
|
||||||
maxTime: '07:25',
|
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({
|
new ActorTime({
|
||||||
role: Role.DRIVER,
|
role: Role.DRIVER,
|
||||||
target: Target.FINISH,
|
target: Target.NEUTRAL,
|
||||||
time: '08:30',
|
firstDatetime: new Date('2023-09-01 08:04'),
|
||||||
minTime: '08:15',
|
firstMinDatetime: new Date('2023-09-01 07:51'),
|
||||||
maxTime: '08:45',
|
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({
|
new ActorTime({
|
||||||
role: Role.PASSENGER,
|
role: Role.PASSENGER,
|
||||||
target: Target.FINISH,
|
target: Target.FINISH,
|
||||||
time: '08:40',
|
firstDatetime: new Date('2023-09-01 08:01'),
|
||||||
minTime: '08:25',
|
firstMinDatetime: new Date('2023-09-01 07:46'),
|
||||||
maxTime: '08:55',
|
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'),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
day: 0,
|
}),
|
||||||
time: '07:00',
|
new JourneyItem({
|
||||||
margin: 900,
|
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);
|
||||||
});
|
});
|
||||||
}).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,
|
lat: 48.689446,
|
||||||
lon: 6.17651,
|
lon: 6.17651,
|
||||||
});
|
});
|
||||||
expect(pointVO.isSame(identicalPointVO)).toBeTruthy();
|
expect(pointVO.equals(identicalPointVO)).toBeTruthy();
|
||||||
expect(pointVO.isSame(differentPointVO)).toBeFalsy();
|
expect(pointVO.equals(differentPointVO)).toBeFalsy();
|
||||||
});
|
});
|
||||||
it('should throw an exception if longitude is invalid', () => {
|
it('should throw an exception if longitude is invalid', () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
|
|
Loading…
Reference in New Issue