Added stops departure and arrival datetime

This commit is contained in:
Roba Boru
2026-07-18 21:51:54 +03:00
parent d7a66cfac5
commit c1858e76d4
16 changed files with 1026 additions and 94 deletions

View File

@@ -133,26 +133,62 @@ export class SchedulesService {
let plannedTimes = dto.plannedTimes;
if (!plannedTimes || plannedTimes.length === 0) {
const totalDuration = arr.getTime() - dep.getTime();
const totalDistance = route.stops[route.stops.length - 1].distanceKm || 0;
const hasRouteTimes = route.stops.some(
s => (s as any).plannedArrivalTime != null || (s as any).plannedDepartureTime != null,
);
plannedTimes = route.stops.map((stop, index) => {
let stopTime: Date;
if (index === 0) {
stopTime = dep;
} else if (index === route.stops.length - 1) {
stopTime = arr;
} else {
const stopDistance = stop.distanceKm || 0;
const progress = totalDistance > 0 ? stopDistance / totalDistance : index / (route.stops.length - 1);
stopTime = new Date(dep.getTime() + totalDuration * progress);
}
return {
sequence: stop.sequence,
plannedArrivalAt: index === 0 ? undefined : stopTime.toISOString(),
plannedDepartureAt: index === route.stops.length - 1 ? undefined : stopTime.toISOString(),
if (hasRouteTimes) {
// Extract EAT time-of-day from a template DateTime and anchor to the schedule's EAT date.
const EAT_MS = 3 * 60 * 60 * 1000;
const depEATMs = dep.getTime() + EAT_MS;
const depMsIntoDay = depEATMs % (24 * 60 * 60 * 1000);
const eatMidnightUTC = dep.getTime() - depMsIntoDay;
const templateToScheduleUTC = (templateDt: Date): Date => {
// Pull the time-of-day in EAT from the template DateTime
const templateEATMs = templateDt.getTime() + EAT_MS;
const timeOfDayMs = templateEATMs % (24 * 60 * 60 * 1000);
const candidate = new Date(eatMidnightUTC + timeOfDayMs);
// Overnight: if the stop time lands before departure, move to next day
if (candidate < dep) return new Date(candidate.getTime() + 24 * 60 * 60 * 1000);
return candidate;
};
});
plannedTimes = route.stops.map((stop, index) => {
const arrDt: Date | null = (stop as any).plannedArrivalTime ?? null;
const depDt: Date | null = (stop as any).plannedDepartureTime ?? null;
return {
sequence: stop.sequence,
plannedArrivalAt: index > 0 && arrDt != null
? templateToScheduleUTC(arrDt).toISOString()
: undefined,
plannedDepartureAt: index < route.stops.length - 1 && depDt != null
? templateToScheduleUTC(depDt).toISOString()
: undefined,
};
});
} else {
const totalDuration = arr.getTime() - dep.getTime();
const totalDistance = route.stops[route.stops.length - 1].distanceKm || 0;
plannedTimes = route.stops.map((stop, index) => {
let stopTime: Date;
if (index === 0) {
stopTime = dep;
} else if (index === route.stops.length - 1) {
stopTime = arr;
} else {
const stopDistance = stop.distanceKm || 0;
const progress = totalDistance > 0 ? stopDistance / totalDistance : index / (route.stops.length - 1);
stopTime = new Date(dep.getTime() + totalDuration * progress);
}
return {
sequence: stop.sequence,
plannedArrivalAt: index === 0 ? undefined : stopTime.toISOString(),
plannedDepartureAt: index === route.stops.length - 1 ? undefined : stopTime.toISOString(),
};
});
}
}
const providedSeqs = new Set((plannedTimes ?? []).map(t => t.sequence));
@@ -304,26 +340,59 @@ export class SchedulesService {
let plannedTimes = dto.plannedTimes;
if (!plannedTimes || plannedTimes.length === 0) {
const totalDuration = arr.getTime() - dep.getTime();
const totalDistance = route.stops[route.stops.length - 1].distanceKm || 0;
const hasRouteTimes = route.stops.some(
s => (s as any).plannedArrivalTime != null || (s as any).plannedDepartureTime != null,
);
plannedTimes = route.stops.map((stop, index) => {
let stopTime: Date;
if (index === 0) {
stopTime = dep;
} else if (index === route.stops.length - 1) {
stopTime = arr;
} else {
const stopDistance = stop.distanceKm || 0;
const progress = totalDistance > 0 ? stopDistance / totalDistance : index / (route.stops.length - 1);
stopTime = new Date(dep.getTime() + totalDuration * progress);
}
return {
sequence: stop.sequence,
plannedArrivalAt: index === 0 ? undefined : stopTime.toISOString(),
plannedDepartureAt: index === route.stops.length - 1 ? undefined : stopTime.toISOString(),
if (hasRouteTimes) {
const EAT_MS = 3 * 60 * 60 * 1000;
const depEATMs = dep.getTime() + EAT_MS;
const depMsIntoDay = depEATMs % (24 * 60 * 60 * 1000);
const eatMidnightUTC = dep.getTime() - depMsIntoDay;
const templateToScheduleUTC = (templateDt: Date): Date => {
const templateEATMs = templateDt.getTime() + EAT_MS;
const timeOfDayMs = templateEATMs % (24 * 60 * 60 * 1000);
const candidate = new Date(eatMidnightUTC + timeOfDayMs);
if (candidate < dep) return new Date(candidate.getTime() + 24 * 60 * 60 * 1000);
return candidate;
};
});
plannedTimes = route.stops.map((stop, index) => {
const arrDt: Date | null = (stop as any).plannedArrivalTime ?? null;
const depDt: Date | null = (stop as any).plannedDepartureTime ?? null;
return {
sequence: stop.sequence,
plannedArrivalAt: index > 0 && arrDt != null
? templateToScheduleUTC(arrDt).toISOString()
: undefined,
plannedDepartureAt: index < route.stops.length - 1 && depDt != null
? templateToScheduleUTC(depDt).toISOString()
: undefined,
};
});
} else {
const totalDuration = arr.getTime() - dep.getTime();
const totalDistance = route.stops[route.stops.length - 1].distanceKm || 0;
plannedTimes = route.stops.map((stop, index) => {
let stopTime: Date;
if (index === 0) {
stopTime = dep;
} else if (index === route.stops.length - 1) {
stopTime = arr;
} else {
const stopDistance = stop.distanceKm || 0;
const progress = totalDistance > 0 ? stopDistance / totalDistance : index / (route.stops.length - 1);
stopTime = new Date(dep.getTime() + totalDuration * progress);
}
return {
sequence: stop.sequence,
plannedArrivalAt: index === 0 ? undefined : stopTime.toISOString(),
plannedDepartureAt: index === route.stops.length - 1 ? undefined : stopTime.toISOString(),
};
});
}
}
const plannedTimesMap = Object.fromEntries(plannedTimes.map(t => [t.sequence, t]));
@@ -678,6 +747,12 @@ export class SchedulesService {
}
}
if (dto.plannedTimes && dto.plannedTimes.length > 0 && schedule.routeId) {
await this.prisma.tripStopTime.deleteMany({ where: { scheduleId: id } });
const plannedTimesMap = Object.fromEntries(dto.plannedTimes.map(t => [t.sequence, t]));
await this.routesService.applyRouteToSchedule(schedule.routeId, id, plannedTimesMap);
}
return this.getSchedule(id);
}