Refine rest candidate derivation chain
This commit is contained in:
parent
3b2f893246
commit
317983eba8
|
|
@ -21,6 +21,7 @@ public record TachographEsperDriverProcessingResultDto(
|
||||||
int drivingIntervalCount,
|
int drivingIntervalCount,
|
||||||
int drivingInterruptionIntervalCount,
|
int drivingInterruptionIntervalCount,
|
||||||
int drivingInterruptionVehicleChangeIntervalCount,
|
int drivingInterruptionVehicleChangeIntervalCount,
|
||||||
|
int dailyWeeklyRestCandidateIntervalCount,
|
||||||
int potentialHomeOvernightStayIntervalCount,
|
int potentialHomeOvernightStayIntervalCount,
|
||||||
int vehicleUsageIntervalCount,
|
int vehicleUsageIntervalCount,
|
||||||
int vuCardAbsentIntervalCount,
|
int vuCardAbsentIntervalCount,
|
||||||
|
|
@ -28,6 +29,7 @@ public record TachographEsperDriverProcessingResultDto(
|
||||||
List<TachographEsperActivityIntervalEvent> drivingIntervals,
|
List<TachographEsperActivityIntervalEvent> drivingIntervals,
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals,
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals,
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> dailyWeeklyRestCandidateIntervals,
|
||||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals,
|
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals,
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals,
|
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals,
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ public class DriverTimelineBuilder {
|
||||||
loadResource("esper/tachograph-driving-interruption-interval-events.epl");
|
loadResource("esper/tachograph-driving-interruption-interval-events.epl");
|
||||||
private static final String DRIVING_INTERRUPTION_VEHICLE_CHANGE_INTERVAL_EVENTS_EPL =
|
private static final String DRIVING_INTERRUPTION_VEHICLE_CHANGE_INTERVAL_EVENTS_EPL =
|
||||||
loadResource("esper/tachograph-driving-interruption-vehicle-change-interval-events.epl");
|
loadResource("esper/tachograph-driving-interruption-vehicle-change-interval-events.epl");
|
||||||
|
private static final String DAILY_WEEKLY_REST_CANDIDATE_INTERVAL_EVENTS_EPL_TEMPLATE =
|
||||||
|
loadResource("esper/tachograph-daily-weekly-rest-candidate-interval-events.epl");
|
||||||
private static final String POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE =
|
private static final String POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE =
|
||||||
loadResource("esper/tachograph-potential-home-overnight-stay-interval-events.epl");
|
loadResource("esper/tachograph-potential-home-overnight-stay-interval-events.epl");
|
||||||
private static final String VEHICLE_USAGE_INTERVAL_EVENTS_EPL =
|
private static final String VEHICLE_USAGE_INTERVAL_EVENTS_EPL =
|
||||||
|
|
@ -209,12 +211,11 @@ public class DriverTimelineBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TachographEsperPotentialHomeOvernightStayIntervalEvent> buildEsperPotentialHomeOvernightStayIntervalEvents(
|
public List<TachographEsperPotentialHomeOvernightStayIntervalEvent> buildEsperPotentialHomeOvernightStayIntervalEvents(
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals,
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals
|
||||||
int minimumRestPeriodMinutes
|
|
||||||
) {
|
) {
|
||||||
if (drivingInterruptionIntervals == null
|
if (drivingInterruptionVehicleChangeIntervals == null
|
||||||
|| drivingInterruptionIntervals.isEmpty()
|
|| drivingInterruptionVehicleChangeIntervals.isEmpty()
|
||||||
|| vuCardAbsentIntervals == null
|
|| vuCardAbsentIntervals == null
|
||||||
|| vuCardAbsentIntervals.isEmpty()) {
|
|| vuCardAbsentIntervals.isEmpty()) {
|
||||||
return List.of();
|
return List.of();
|
||||||
|
|
@ -223,7 +224,7 @@ public class DriverTimelineBuilder {
|
||||||
executeWithRuntime(
|
executeWithRuntime(
|
||||||
configuration -> {
|
configuration -> {
|
||||||
configuration.getCommon().addEventType(
|
configuration.getCommon().addEventType(
|
||||||
"TachographDrivingInterruptionIntervalInputEvent",
|
"TachographDrivingInterruptionVehicleChangeIntervalInputEvent",
|
||||||
drivingInterruptionIntervalInputDefinition()
|
drivingInterruptionIntervalInputDefinition()
|
||||||
);
|
);
|
||||||
configuration.getCommon().addEventType(
|
configuration.getCommon().addEventType(
|
||||||
|
|
@ -231,7 +232,7 @@ public class DriverTimelineBuilder {
|
||||||
vuCardAbsentIntervalInputDefinition()
|
vuCardAbsentIntervalInputDefinition()
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
renderPotentialHomeOvernightStayIntervalEventsEpl(minimumRestPeriodMinutes),
|
POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE,
|
||||||
"potentialHomeOvernightStayIntervals",
|
"potentialHomeOvernightStayIntervals",
|
||||||
newData -> collectPotentialHomeOvernightStayIntervalEvents(newData, result),
|
newData -> collectPotentialHomeOvernightStayIntervalEvents(newData, result),
|
||||||
runtime -> {
|
runtime -> {
|
||||||
|
|
@ -241,6 +242,34 @@ public class DriverTimelineBuilder {
|
||||||
"TachographVuCardAbsentIntervalInputEvent"
|
"TachographVuCardAbsentIntervalInputEvent"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
for (TachographEsperDrivingInterruptionIntervalEvent interval : drivingInterruptionVehicleChangeIntervals) {
|
||||||
|
runtime.getEventService().sendEventMap(
|
||||||
|
toDrivingInterruptionIntervalInputMap(interval),
|
||||||
|
"TachographDrivingInterruptionVehicleChangeIntervalInputEvent"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TachographEsperDrivingInterruptionIntervalEvent> buildEsperDailyWeeklyRestCandidateIntervalEvents(
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
||||||
|
int minimumRestPeriodMinutes
|
||||||
|
) {
|
||||||
|
if (drivingInterruptionIntervals == null || drivingInterruptionIntervals.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> result = new ArrayList<>();
|
||||||
|
executeWithRuntime(
|
||||||
|
configuration -> configuration.getCommon().addEventType(
|
||||||
|
"TachographDrivingInterruptionIntervalInputEvent",
|
||||||
|
drivingInterruptionIntervalInputDefinition()
|
||||||
|
),
|
||||||
|
renderDailyWeeklyRestCandidateIntervalEventsEpl(minimumRestPeriodMinutes),
|
||||||
|
"dailyWeeklyRestCandidateIntervals",
|
||||||
|
newData -> collectDrivingInterruptionIntervalEventsFromTimestamps(newData, result),
|
||||||
|
runtime -> {
|
||||||
for (TachographEsperDrivingInterruptionIntervalEvent interval : drivingInterruptionIntervals) {
|
for (TachographEsperDrivingInterruptionIntervalEvent interval : drivingInterruptionIntervals) {
|
||||||
runtime.getEventService().sendEventMap(
|
runtime.getEventService().sendEventMap(
|
||||||
toDrivingInterruptionIntervalInputMap(interval),
|
toDrivingInterruptionIntervalInputMap(interval),
|
||||||
|
|
@ -1002,10 +1031,10 @@ public class DriverTimelineBuilder {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String renderPotentialHomeOvernightStayIntervalEventsEpl(int minimumRestPeriodMinutes) {
|
private String renderDailyWeeklyRestCandidateIntervalEventsEpl(int minimumRestPeriodMinutes) {
|
||||||
long thresholdSeconds = Math.max(1, minimumRestPeriodMinutes) * 60L;
|
long thresholdSeconds = Math.max(1, minimumRestPeriodMinutes) * 60L;
|
||||||
return POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE.replace(
|
return DAILY_WEEKLY_REST_CANDIDATE_INTERVAL_EVENTS_EPL_TEMPLATE.replace(
|
||||||
"${POTENTIAL_HOME_OVERNIGHT_STAY_THRESHOLD_SECONDS}",
|
"${MINIMUM_REST_PERIOD_THRESHOLD_SECONDS}",
|
||||||
Long.toString(thresholdSeconds)
|
Long.toString(thresholdSeconds)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -174,11 +174,24 @@ public class TachographFileSessionProcessingService {
|
||||||
requestedFrom,
|
requestedFrom,
|
||||||
requestedTo
|
requestedTo
|
||||||
);
|
);
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> rawDailyWeeklyRestCandidateIntervals =
|
||||||
|
driverTimelineBuilder.buildEsperDailyWeeklyRestCandidateIntervalEvents(
|
||||||
|
rawDrivingInterruptionIntervals,
|
||||||
|
minimumRestPeriodMinutes
|
||||||
|
);
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> dailyWeeklyRestCandidateIntervals =
|
||||||
|
clipEsperDrivingInterruptionIntervalEvents(
|
||||||
|
rawDailyWeeklyRestCandidateIntervals,
|
||||||
|
requestedFrom,
|
||||||
|
requestedTo
|
||||||
|
);
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> rawDrivingInterruptionVehicleChangeIntervals =
|
||||||
|
driverTimelineBuilder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents(
|
||||||
|
rawDailyWeeklyRestCandidateIntervals
|
||||||
|
);
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals =
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals =
|
||||||
clipEsperDrivingInterruptionIntervalEvents(
|
clipEsperDrivingInterruptionIntervalEvents(
|
||||||
driverTimelineBuilder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents(
|
rawDrivingInterruptionVehicleChangeIntervals,
|
||||||
rawDrivingInterruptionIntervals
|
|
||||||
),
|
|
||||||
requestedFrom,
|
requestedFrom,
|
||||||
requestedTo
|
requestedTo
|
||||||
);
|
);
|
||||||
|
|
@ -187,9 +200,8 @@ public class TachographFileSessionProcessingService {
|
||||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals =
|
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals =
|
||||||
clipEsperPotentialHomeOvernightStayIntervalEvents(
|
clipEsperPotentialHomeOvernightStayIntervalEvents(
|
||||||
driverTimelineBuilder.buildEsperPotentialHomeOvernightStayIntervalEvents(
|
driverTimelineBuilder.buildEsperPotentialHomeOvernightStayIntervalEvents(
|
||||||
rawDrivingInterruptionIntervals,
|
rawDrivingInterruptionVehicleChangeIntervals,
|
||||||
rawVuCardAbsentIntervals,
|
rawVuCardAbsentIntervals
|
||||||
minimumRestPeriodMinutes
|
|
||||||
),
|
),
|
||||||
rawVuCardAbsentIntervals,
|
rawVuCardAbsentIntervals,
|
||||||
requestedFrom,
|
requestedFrom,
|
||||||
|
|
@ -218,6 +230,7 @@ public class TachographFileSessionProcessingService {
|
||||||
drivingIntervals.size(),
|
drivingIntervals.size(),
|
||||||
drivingInterruptionIntervals.size(),
|
drivingInterruptionIntervals.size(),
|
||||||
drivingInterruptionVehicleChangeIntervals.size(),
|
drivingInterruptionVehicleChangeIntervals.size(),
|
||||||
|
dailyWeeklyRestCandidateIntervals.size(),
|
||||||
potentialHomeOvernightStayIntervals.size(),
|
potentialHomeOvernightStayIntervals.size(),
|
||||||
vehicleUsageIntervals.size(),
|
vehicleUsageIntervals.size(),
|
||||||
vuCardAbsentIntervals.size(),
|
vuCardAbsentIntervals.size(),
|
||||||
|
|
@ -225,6 +238,7 @@ public class TachographFileSessionProcessingService {
|
||||||
drivingIntervals,
|
drivingIntervals,
|
||||||
drivingInterruptionIntervals,
|
drivingInterruptionIntervals,
|
||||||
drivingInterruptionVehicleChangeIntervals,
|
drivingInterruptionVehicleChangeIntervals,
|
||||||
|
dailyWeeklyRestCandidateIntervals,
|
||||||
potentialHomeOvernightStayIntervals,
|
potentialHomeOvernightStayIntervals,
|
||||||
vehicleUsageIntervals,
|
vehicleUsageIntervals,
|
||||||
vuCardAbsentIntervals,
|
vuCardAbsentIntervals,
|
||||||
|
|
@ -403,7 +417,12 @@ public class TachographFileSessionProcessingService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
long durationSeconds = Duration.between(start, end).getSeconds();
|
long durationSeconds = Duration.between(start, end).getSeconds();
|
||||||
long unknownDurationSeconds = overlapSeconds(start, end, rawVuCardAbsentIntervals, interval.driverKey());
|
long unknownDurationSeconds = overlapSeconds(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
rawVuCardAbsentIntervals,
|
||||||
|
interval.driverKey()
|
||||||
|
);
|
||||||
double unknownCoveragePercent = durationSeconds == 0L
|
double unknownCoveragePercent = durationSeconds == 0L
|
||||||
? 0.0d
|
? 0.0d
|
||||||
: (unknownDurationSeconds * 100.0d) / durationSeconds;
|
: (unknownDurationSeconds * 100.0d) / durationSeconds;
|
||||||
|
|
@ -993,8 +1012,9 @@ public class TachographFileSessionProcessingService {
|
||||||
"This endpoint returns Esper-backed per-driver interval projections from the in-memory tachograph file-session model.",
|
"This endpoint returns Esper-backed per-driver interval projections from the in-memory tachograph file-session model.",
|
||||||
"Driving intervals are a filtered projection of activity intervals where activityType = DRIVE.",
|
"Driving intervals are a filtered projection of activity intervals where activityType = DRIVE.",
|
||||||
"Driving interruption intervals are gaps between consecutive driving intervals longer than the configured significant-driving threshold.",
|
"Driving interruption intervals are gaps between consecutive driving intervals longer than the configured significant-driving threshold.",
|
||||||
"Driving interruption vehicle-change intervals are DTI intervals where previousRegistrationKey differs from nextRegistrationKey.",
|
"Driving interruption vehicle-change intervals are daily/weekly rest candidates where previousRegistrationKey differs from nextRegistrationKey.",
|
||||||
"Potential home overnight stay intervals are DTI intervals longer than the configured minimum rest-period threshold where VU card-absent overlap covers at least 95% of the DTI.",
|
"Daily/weekly rest candidate intervals are driving interruption intervals longer than the configured minimum rest-period threshold.",
|
||||||
|
"Potential home overnight stay intervals are vehicle-change daily/weekly rest candidates where VU card-absent overlap covers at least 95% of the candidate interval.",
|
||||||
"VU card-absent intervals are gaps between consecutive normalized vehicle-usage intervals for the same driver.",
|
"VU card-absent intervals are gaps between consecutive normalized vehicle-usage intervals for the same driver.",
|
||||||
"occurredFrom and occurredTo clip the returned interval projections to the requested UTC time window.",
|
"occurredFrom and occurredTo clip the returned interval projections to the requested UTC time window.",
|
||||||
"Vehicle-usage intervals clear clipped odometer endpoints because boundary odometer values cannot be recomputed safely from the source interval."
|
"Vehicle-usage intervals clear clipped odometer endpoints because boundary odometer values cannot be recomputed safely from the source interval."
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@name('dailyWeeklyRestCandidateIntervals')
|
||||||
|
select *
|
||||||
|
from TachographDrivingInterruptionIntervalInputEvent(durationSeconds > ${MINIMUM_REST_PERIOD_THRESHOLD_SECONDS});
|
||||||
|
|
@ -1,65 +1,65 @@
|
||||||
@name('potentialHomeOvernightStayIntervals')
|
@name('potentialHomeOvernightStayIntervals')
|
||||||
select
|
select
|
||||||
d.sessionId as sessionId,
|
c.sessionId as sessionId,
|
||||||
d.driverKey as driverKey,
|
c.driverKey as driverKey,
|
||||||
d.startedAt as startedAt,
|
c.startedAt as startedAt,
|
||||||
d.endedAt as endedAt,
|
c.endedAt as endedAt,
|
||||||
d.durationSeconds as durationSeconds,
|
c.durationSeconds as durationSeconds,
|
||||||
sum(
|
sum(
|
||||||
case
|
case
|
||||||
when u.startedAtEpochSecond <= d.startedAtEpochSecond and u.endedAtEpochSecond >= d.endedAtEpochSecond
|
when u.startedAtEpochSecond <= c.startedAtEpochSecond and u.endedAtEpochSecond >= c.endedAtEpochSecond
|
||||||
then d.durationSeconds
|
then c.durationSeconds
|
||||||
when u.startedAtEpochSecond <= d.startedAtEpochSecond
|
when u.startedAtEpochSecond <= c.startedAtEpochSecond
|
||||||
then u.endedAtEpochSecond - d.startedAtEpochSecond
|
then u.endedAtEpochSecond - c.startedAtEpochSecond
|
||||||
when u.endedAtEpochSecond >= d.endedAtEpochSecond
|
when u.endedAtEpochSecond >= c.endedAtEpochSecond
|
||||||
then d.endedAtEpochSecond - u.startedAtEpochSecond
|
then c.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
end
|
end
|
||||||
) as unknownDurationSeconds,
|
) as unknownDurationSeconds,
|
||||||
(sum(
|
(sum(
|
||||||
case
|
case
|
||||||
when u.startedAtEpochSecond <= d.startedAtEpochSecond and u.endedAtEpochSecond >= d.endedAtEpochSecond
|
when u.startedAtEpochSecond <= c.startedAtEpochSecond and u.endedAtEpochSecond >= c.endedAtEpochSecond
|
||||||
then d.durationSeconds
|
then c.durationSeconds
|
||||||
when u.startedAtEpochSecond <= d.startedAtEpochSecond
|
when u.startedAtEpochSecond <= c.startedAtEpochSecond
|
||||||
then u.endedAtEpochSecond - d.startedAtEpochSecond
|
then u.endedAtEpochSecond - c.startedAtEpochSecond
|
||||||
when u.endedAtEpochSecond >= d.endedAtEpochSecond
|
when u.endedAtEpochSecond >= c.endedAtEpochSecond
|
||||||
then d.endedAtEpochSecond - u.startedAtEpochSecond
|
then c.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
end
|
end
|
||||||
) * 100.0d) / d.durationSeconds as unknownCoveragePercent,
|
) * 100.0d) / c.durationSeconds as unknownCoveragePercent,
|
||||||
d.previousDrivingSourceIntervalId as previousDrivingSourceIntervalId,
|
c.previousDrivingSourceIntervalId as previousDrivingSourceIntervalId,
|
||||||
d.nextDrivingSourceIntervalId as nextDrivingSourceIntervalId,
|
c.nextDrivingSourceIntervalId as nextDrivingSourceIntervalId,
|
||||||
d.previousRegistrationKey as previousRegistrationKey,
|
c.previousRegistrationKey as previousRegistrationKey,
|
||||||
d.nextRegistrationKey as nextRegistrationKey,
|
c.nextRegistrationKey as nextRegistrationKey,
|
||||||
d.previousVehicleKey as previousVehicleKey,
|
c.previousVehicleKey as previousVehicleKey,
|
||||||
d.nextVehicleKey as nextVehicleKey
|
c.nextVehicleKey as nextVehicleKey
|
||||||
from TachographDrivingInterruptionIntervalInputEvent(durationSeconds > ${POTENTIAL_HOME_OVERNIGHT_STAY_THRESHOLD_SECONDS}) as d unidirectional,
|
from TachographDrivingInterruptionVehicleChangeIntervalInputEvent as c unidirectional,
|
||||||
TachographVuCardAbsentIntervalInputEvent#keepall as u
|
TachographVuCardAbsentIntervalInputEvent#keepall as u
|
||||||
where u.driverKey = d.driverKey
|
where u.driverKey = c.driverKey
|
||||||
and u.startedAtEpochSecond < d.endedAtEpochSecond
|
and u.startedAtEpochSecond < c.endedAtEpochSecond
|
||||||
and u.endedAtEpochSecond > d.startedAtEpochSecond
|
and u.endedAtEpochSecond > c.startedAtEpochSecond
|
||||||
group by
|
group by
|
||||||
d.sessionId,
|
c.sessionId,
|
||||||
d.driverKey,
|
c.driverKey,
|
||||||
d.startedAt,
|
c.startedAt,
|
||||||
d.endedAt,
|
c.endedAt,
|
||||||
d.startedAtEpochSecond,
|
c.startedAtEpochSecond,
|
||||||
d.endedAtEpochSecond,
|
c.endedAtEpochSecond,
|
||||||
d.durationSeconds,
|
c.durationSeconds,
|
||||||
d.previousDrivingSourceIntervalId,
|
c.previousDrivingSourceIntervalId,
|
||||||
d.nextDrivingSourceIntervalId,
|
c.nextDrivingSourceIntervalId,
|
||||||
d.previousRegistrationKey,
|
c.previousRegistrationKey,
|
||||||
d.nextRegistrationKey,
|
c.nextRegistrationKey,
|
||||||
d.previousVehicleKey,
|
c.previousVehicleKey,
|
||||||
d.nextVehicleKey
|
c.nextVehicleKey
|
||||||
having sum(
|
having sum(
|
||||||
case
|
case
|
||||||
when u.startedAtEpochSecond <= d.startedAtEpochSecond and u.endedAtEpochSecond >= d.endedAtEpochSecond
|
when u.startedAtEpochSecond <= c.startedAtEpochSecond and u.endedAtEpochSecond >= c.endedAtEpochSecond
|
||||||
then d.durationSeconds
|
then c.durationSeconds
|
||||||
when u.startedAtEpochSecond <= d.startedAtEpochSecond
|
when u.startedAtEpochSecond <= c.startedAtEpochSecond
|
||||||
then u.endedAtEpochSecond - d.startedAtEpochSecond
|
then u.endedAtEpochSecond - c.startedAtEpochSecond
|
||||||
when u.endedAtEpochSecond >= d.endedAtEpochSecond
|
when u.endedAtEpochSecond >= c.endedAtEpochSecond
|
||||||
then d.endedAtEpochSecond - u.startedAtEpochSecond
|
then c.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
end
|
end
|
||||||
) * 100L >= d.durationSeconds * 95L;
|
) * 100L >= c.durationSeconds * 95L;
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,7 @@ class TachographFileSessionControllerTest {
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
|
1,
|
||||||
2,
|
2,
|
||||||
1,
|
1,
|
||||||
List.of(new TachographEsperActivityIntervalEvent(
|
List.of(new TachographEsperActivityIntervalEvent(
|
||||||
|
|
@ -150,6 +151,19 @@ class TachographFileSessionControllerTest {
|
||||||
"VIN-1",
|
"VIN-1",
|
||||||
"VIN-2"
|
"VIN-2"
|
||||||
)),
|
)),
|
||||||
|
List.of(new TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
|
sessionId,
|
||||||
|
"12:123",
|
||||||
|
OffsetDateTime.parse("2026-05-12T10:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-12T22:00:00Z"),
|
||||||
|
43_200L,
|
||||||
|
"ACT-2",
|
||||||
|
"ACT-3",
|
||||||
|
"12:REG-1",
|
||||||
|
"12:REG-2",
|
||||||
|
"VIN-1",
|
||||||
|
"VIN-2"
|
||||||
|
)),
|
||||||
List.of(new TachographEsperPotentialHomeOvernightStayIntervalEvent(
|
List.of(new TachographEsperPotentialHomeOvernightStayIntervalEvent(
|
||||||
sessionId,
|
sessionId,
|
||||||
"12:123",
|
"12:123",
|
||||||
|
|
@ -258,6 +272,7 @@ class TachographFileSessionControllerTest {
|
||||||
.andExpect(jsonPath("$.activityIntervalCount").value(2))
|
.andExpect(jsonPath("$.activityIntervalCount").value(2))
|
||||||
.andExpect(jsonPath("$.drivingInterruptionIntervalCount").value(1))
|
.andExpect(jsonPath("$.drivingInterruptionIntervalCount").value(1))
|
||||||
.andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervalCount").value(1))
|
.andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervalCount").value(1))
|
||||||
|
.andExpect(jsonPath("$.dailyWeeklyRestCandidateIntervalCount").value(1))
|
||||||
.andExpect(jsonPath("$.potentialHomeOvernightStayIntervalCount").value(1))
|
.andExpect(jsonPath("$.potentialHomeOvernightStayIntervalCount").value(1))
|
||||||
.andExpect(jsonPath("$.vuCardAbsentIntervalCount").value(1))
|
.andExpect(jsonPath("$.vuCardAbsentIntervalCount").value(1))
|
||||||
.andExpect(jsonPath("$.drivingInterruptionIntervals[0].previousRegistrationKey").value("12:REG-1"))
|
.andExpect(jsonPath("$.drivingInterruptionIntervals[0].previousRegistrationKey").value("12:REG-1"))
|
||||||
|
|
|
||||||
|
|
@ -378,6 +378,46 @@ class DriverTimelineBuilderTest {
|
||||||
assertThat(absentIntervals.get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
assertThat(absentIntervals.get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildsDailyWeeklyRestCandidateIntervalsFromDrivingInterruptionIntervals() {
|
||||||
|
UUID sessionId = UUID.randomUUID();
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals = List.of(
|
||||||
|
new TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
|
sessionId,
|
||||||
|
"12:123",
|
||||||
|
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-01T20:00:00Z"),
|
||||||
|
36_000L,
|
||||||
|
"ACT-1",
|
||||||
|
"ACT-2",
|
||||||
|
"12:REG-1",
|
||||||
|
"12:REG-1",
|
||||||
|
"VIN-1",
|
||||||
|
"VIN-1"
|
||||||
|
),
|
||||||
|
new TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
|
sessionId,
|
||||||
|
"12:123",
|
||||||
|
OffsetDateTime.parse("2026-05-02T10:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-02T18:00:00Z"),
|
||||||
|
28_800L,
|
||||||
|
"ACT-3",
|
||||||
|
"ACT-4",
|
||||||
|
"12:REG-1",
|
||||||
|
"12:REG-1",
|
||||||
|
"VIN-1",
|
||||||
|
"VIN-1"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> candidates =
|
||||||
|
builder.buildEsperDailyWeeklyRestCandidateIntervalEvents(drivingInterruptionIntervals, 540);
|
||||||
|
|
||||||
|
assertThat(candidates).hasSize(1);
|
||||||
|
assertThat(candidates.get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T10:00:00Z"));
|
||||||
|
assertThat(candidates.get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T20:00:00Z"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void buildsEsperDrivingInterruptionIntervalEventsFromSignificantDrivingGaps() {
|
void buildsEsperDrivingInterruptionIntervalEventsFromSignificantDrivingGaps() {
|
||||||
DriverExtractionSession driver = new DriverExtractionSession(
|
DriverExtractionSession driver = new DriverExtractionSession(
|
||||||
|
|
@ -478,9 +518,9 @@ class DriverTimelineBuilderTest {
|
||||||
"ACT-1",
|
"ACT-1",
|
||||||
"ACT-2",
|
"ACT-2",
|
||||||
"12:REG-1",
|
"12:REG-1",
|
||||||
"12:REG-1",
|
"12:REG-2",
|
||||||
"VIN-1",
|
"VIN-1",
|
||||||
"VIN-1"
|
"VIN-2"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals = List.of(
|
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals = List.of(
|
||||||
|
|
@ -499,13 +539,17 @@ class DriverTimelineBuilderTest {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> dailyWeeklyRestCandidateIntervals =
|
||||||
|
builder.buildEsperDailyWeeklyRestCandidateIntervalEvents(interruptions, 720);
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals =
|
||||||
|
builder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents(dailyWeeklyRestCandidateIntervals);
|
||||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> intervals =
|
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> intervals =
|
||||||
builder.buildEsperPotentialHomeOvernightStayIntervalEvents(
|
builder.buildEsperPotentialHomeOvernightStayIntervalEvents(
|
||||||
interruptions,
|
drivingInterruptionVehicleChangeIntervals,
|
||||||
vuCardAbsentIntervals,
|
vuCardAbsentIntervals
|
||||||
720
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assertThat(drivingInterruptionVehicleChangeIntervals).hasSize(1);
|
||||||
assertThat(intervals).hasSize(1);
|
assertThat(intervals).hasSize(1);
|
||||||
assertThat(intervals.get(0).sessionId()).isEqualTo(sessionId);
|
assertThat(intervals.get(0).sessionId()).isEqualTo(sessionId);
|
||||||
assertThat(intervals.get(0).driverKey()).isEqualTo("12:123");
|
assertThat(intervals.get(0).driverKey()).isEqualTo("12:123");
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ class TachographFileSessionProcessingServiceTest {
|
||||||
assertThat(result.drivingIntervalCount()).isEqualTo(1);
|
assertThat(result.drivingIntervalCount()).isEqualTo(1);
|
||||||
assertThat(result.drivingInterruptionIntervalCount()).isEqualTo(0);
|
assertThat(result.drivingInterruptionIntervalCount()).isEqualTo(0);
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(0);
|
assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(0);
|
||||||
|
assertThat(result.dailyWeeklyRestCandidateIntervalCount()).isEqualTo(0);
|
||||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
||||||
assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2);
|
assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2);
|
||||||
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
||||||
|
|
@ -169,7 +170,8 @@ class TachographFileSessionProcessingServiceTest {
|
||||||
assertThat(result.activityIntervals().get(0).clippedToRequestedPeriod()).isTrue();
|
assertThat(result.activityIntervals().get(0).clippedToRequestedPeriod()).isTrue();
|
||||||
assertThat(result.drivingIntervalCount()).isEqualTo(2);
|
assertThat(result.drivingIntervalCount()).isEqualTo(2);
|
||||||
assertThat(result.drivingInterruptionIntervalCount()).isEqualTo(1);
|
assertThat(result.drivingInterruptionIntervalCount()).isEqualTo(1);
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(1);
|
assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(0);
|
||||||
|
assertThat(result.dailyWeeklyRestCandidateIntervalCount()).isEqualTo(0);
|
||||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
||||||
assertThat(result.drivingInterruptionIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T09:00:00Z"));
|
assertThat(result.drivingInterruptionIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T09:00:00Z"));
|
||||||
assertThat(result.drivingInterruptionIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T10:00:00Z"));
|
assertThat(result.drivingInterruptionIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T10:00:00Z"));
|
||||||
|
|
@ -177,11 +179,6 @@ class TachographFileSessionProcessingServiceTest {
|
||||||
assertThat(result.drivingInterruptionIntervals().get(0).nextRegistrationKey()).isEqualTo("12:REG-2");
|
assertThat(result.drivingInterruptionIntervals().get(0).nextRegistrationKey()).isEqualTo("12:REG-2");
|
||||||
assertThat(result.drivingInterruptionIntervals().get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
assertThat(result.drivingInterruptionIntervals().get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
||||||
assertThat(result.drivingInterruptionIntervals().get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
assertThat(result.drivingInterruptionIntervals().get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T09:00:00Z"));
|
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).previousRegistrationKey()).isEqualTo("12:REG-1");
|
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).nextRegistrationKey()).isEqualTo("12:REG-2");
|
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
|
||||||
assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2);
|
assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2);
|
||||||
assertThat(result.vehicleUsageIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T08:45:00Z"));
|
assertThat(result.vehicleUsageIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T08:45:00Z"));
|
||||||
assertThat(result.vehicleUsageIntervals().get(0).odometerBeginKm()).isNull();
|
assertThat(result.vehicleUsageIntervals().get(0).odometerBeginKm()).isNull();
|
||||||
|
|
@ -230,7 +227,7 @@ class TachographFileSessionProcessingServiceTest {
|
||||||
),
|
),
|
||||||
List.of(
|
List.of(
|
||||||
new ExtractedCardActivityInterval("ACT-1", OffsetDateTime.parse("2026-05-01T08:00:00Z"), OffsetDateTime.parse("2026-05-01T10:00:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "a"),
|
new ExtractedCardActivityInterval("ACT-1", OffsetDateTime.parse("2026-05-01T08:00:00Z"), OffsetDateTime.parse("2026-05-01T10:00:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "a"),
|
||||||
new ExtractedCardActivityInterval("ACT-2", OffsetDateTime.parse("2026-05-02T00:00:00Z"), OffsetDateTime.parse("2026-05-02T00:30:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "b")
|
new ExtractedCardActivityInterval("ACT-2", OffsetDateTime.parse("2026-05-02T00:00:00Z"), OffsetDateTime.parse("2026-05-02T00:30:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-2", "VIN-2", "b")
|
||||||
),
|
),
|
||||||
List.of(),
|
List.of(),
|
||||||
List.of()
|
List.of()
|
||||||
|
|
@ -257,6 +254,13 @@ class TachographFileSessionProcessingServiceTest {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assertThat(result.dailyWeeklyRestCandidateIntervalCount()).isEqualTo(1);
|
||||||
|
assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(1);
|
||||||
|
assertThat(result.dailyWeeklyRestCandidateIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:00Z"));
|
||||||
|
assertThat(result.dailyWeeklyRestCandidateIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T23:00:00Z"));
|
||||||
|
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:00Z"));
|
||||||
|
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).previousRegistrationKey()).isEqualTo("12:REG-1");
|
||||||
|
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).nextRegistrationKey()).isEqualTo("12:REG-2");
|
||||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(1);
|
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(1);
|
||||||
assertThat(result.potentialHomeOvernightStayIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:00Z"));
|
assertThat(result.potentialHomeOvernightStayIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:00Z"));
|
||||||
assertThat(result.potentialHomeOvernightStayIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T23:00:00Z"));
|
assertThat(result.potentialHomeOvernightStayIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T23:00:00Z"));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue