Add in-vehicle trip Esper projection
This commit is contained in:
parent
9b86d13001
commit
33e9cb62c3
|
|
@ -5,6 +5,7 @@ import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeekly
|
|||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleOvernightStayIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||
import java.time.OffsetDateTime;
|
||||
|
|
@ -28,6 +29,7 @@ public record TachographEsperDriverProcessingResultDto(
|
|||
int unclassifiedDailyWeeklyRestCandidateCoverageIntervalCount,
|
||||
int potentialHomeOvernightStayIntervalCount,
|
||||
int potentialInVehicleOvernightStayIntervalCount,
|
||||
int potentialInVehicleTripIntervalCount,
|
||||
int vehicleUsageIntervalCount,
|
||||
int vuCardAbsentIntervalCount,
|
||||
List<TachographEsperActivityIntervalEvent> activityIntervals,
|
||||
|
|
@ -39,6 +41,7 @@ public record TachographEsperDriverProcessingResultDto(
|
|||
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> unclassifiedDailyWeeklyRestCandidateCoverageIntervals,
|
||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals,
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals,
|
||||
List<TachographEsperPotentialInVehicleTripIntervalEvent> potentialInVehicleTripIntervals,
|
||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals,
|
||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
||||
List<String> notes
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ public record TachographEsperDrivingDerivedProjectionBundle(
|
|||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals,
|
||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals,
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals,
|
||||
List<TachographEsperPotentialInVehicleTripIntervalEvent> potentialInVehicleTripIntervals
|
||||
) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ public record TachographEsperPotentialHomeOvernightStayIntervalEvent(
|
|||
OffsetDateTime startedAt,
|
||||
OffsetDateTime endedAt,
|
||||
long durationSeconds,
|
||||
long cardPresentDurationSeconds,
|
||||
double cardPresentCoveragePercent,
|
||||
long unknownDurationSeconds,
|
||||
double unknownCoveragePercent,
|
||||
String previousDrivingSourceIntervalId,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ public record TachographEsperPotentialInVehicleOvernightStayIntervalEvent(
|
|||
long durationSeconds,
|
||||
long cardPresentDurationSeconds,
|
||||
double cardPresentCoveragePercent,
|
||||
long unknownDurationSeconds,
|
||||
double unknownCoveragePercent,
|
||||
String previousDrivingSourceIntervalId,
|
||||
String nextDrivingSourceIntervalId,
|
||||
String previousRegistrationKey,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package at.procon.eventhub.tachographfilesession.model;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public record TachographEsperPotentialInVehicleTripIntervalEvent(
|
||||
UUID sessionId,
|
||||
String driverKey,
|
||||
OffsetDateTime startedAt,
|
||||
OffsetDateTime endedAt,
|
||||
long durationSeconds,
|
||||
String registrationKey,
|
||||
String vehicleKey,
|
||||
int containedPotentialInVehicleOvernightStayIntervalCount,
|
||||
long containedPotentialInVehicleOvernightStayDurationSeconds,
|
||||
long containedCardPresentDurationSeconds,
|
||||
long containedUnknownDurationSeconds,
|
||||
OffsetDateTime firstPotentialInVehicleOvernightStayStartedAt,
|
||||
OffsetDateTime lastPotentialInVehicleOvernightStayEndedAt,
|
||||
String firstPreviousDrivingSourceIntervalId,
|
||||
String lastNextDrivingSourceIntervalId,
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals
|
||||
) {
|
||||
}
|
||||
|
|
@ -997,6 +997,8 @@ public class DriverTimelineBuilder {
|
|||
(OffsetDateTime) event.get("startedAt"),
|
||||
(OffsetDateTime) event.get("endedAt"),
|
||||
(Long) event.get("durationSeconds"),
|
||||
0L,
|
||||
0.0d,
|
||||
(Long) event.get("unknownDurationSeconds"),
|
||||
(Double) event.get("unknownCoveragePercent"),
|
||||
(String) event.get("previousDrivingSourceIntervalId"),
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingDeri
|
|||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleOvernightStayIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||
import java.io.IOException;
|
||||
|
|
@ -108,6 +109,7 @@ public class DriverTimelineReusableProjectionBuilder {
|
|||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals = new ArrayList<>();
|
||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals = new ArrayList<>();
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals = new ArrayList<>();
|
||||
List<TachographEsperPotentialInVehicleTripIntervalEvent> potentialInVehicleTripIntervals = new ArrayList<>();
|
||||
|
||||
executeWithRuntime(
|
||||
configuration -> {
|
||||
|
|
@ -129,7 +131,8 @@ public class DriverTimelineReusableProjectionBuilder {
|
|||
"drivingInterruptionVehicleChangeIntervals", newData -> collectDrivingInterruptionIntervalEvents(newData, drivingInterruptionVehicleChangeIntervals),
|
||||
"vuCardAbsentIntervals", newData -> collectVuCardAbsentIntervalEvents(newData, vuCardAbsentIntervals),
|
||||
"potentialHomeOvernightStayIntervals", newData -> collectPotentialHomeOvernightStayIntervalEvents(newData, potentialHomeOvernightStayIntervals),
|
||||
"potentialInVehicleOvernightStayIntervals", newData -> collectPotentialInVehicleOvernightStayIntervalEvents(newData, potentialInVehicleOvernightStayIntervals)
|
||||
"potentialInVehicleOvernightStayIntervals", newData -> collectPotentialInVehicleOvernightStayIntervalEvents(newData, potentialInVehicleOvernightStayIntervals),
|
||||
"potentialInVehicleTripIntervals", newData -> collectPotentialInVehicleTripIntervalEvents(newData, potentialInVehicleTripIntervals)
|
||||
),
|
||||
runtime -> {
|
||||
if (vehicleUsageIntervals != null) {
|
||||
|
|
@ -159,7 +162,8 @@ public class DriverTimelineReusableProjectionBuilder {
|
|||
sortDrivingInterruptionIntervals(drivingInterruptionVehicleChangeIntervals),
|
||||
sortVuCardAbsentIntervals(vuCardAbsentIntervals),
|
||||
sortPotentialHomeOvernightStayIntervals(potentialHomeOvernightStayIntervals),
|
||||
sortPotentialInVehicleOvernightStayIntervals(potentialInVehicleOvernightStayIntervals)
|
||||
sortPotentialInVehicleOvernightStayIntervals(potentialInVehicleOvernightStayIntervals),
|
||||
sortPotentialInVehicleTripIntervals(potentialInVehicleTripIntervals)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -172,6 +176,7 @@ public class DriverTimelineReusableProjectionBuilder {
|
|||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of()
|
||||
);
|
||||
}
|
||||
|
|
@ -424,6 +429,8 @@ public class DriverTimelineReusableProjectionBuilder {
|
|||
OffsetDateTime.ofInstant(Instant.ofEpochSecond(startedAtEpochSecond), ZoneOffset.UTC),
|
||||
OffsetDateTime.ofInstant(Instant.ofEpochSecond(endedAtEpochSecond), ZoneOffset.UTC),
|
||||
(Long) event.get("durationSeconds"),
|
||||
(Long) event.get("cardPresentDurationSeconds"),
|
||||
(Double) event.get("cardPresentCoveragePercent"),
|
||||
(Long) event.get("unknownDurationSeconds"),
|
||||
(Double) event.get("unknownCoveragePercent"),
|
||||
(String) event.get("previousDrivingSourceIntervalId"),
|
||||
|
|
@ -454,6 +461,8 @@ public class DriverTimelineReusableProjectionBuilder {
|
|||
(Long) event.get("durationSeconds"),
|
||||
(Long) event.get("cardPresentDurationSeconds"),
|
||||
(Double) event.get("cardPresentCoveragePercent"),
|
||||
(Long) event.get("unknownDurationSeconds"),
|
||||
(Double) event.get("unknownCoveragePercent"),
|
||||
(String) event.get("previousDrivingSourceIntervalId"),
|
||||
(String) event.get("nextDrivingSourceIntervalId"),
|
||||
(String) event.get("previousRegistrationKey"),
|
||||
|
|
@ -464,6 +473,37 @@ public class DriverTimelineReusableProjectionBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
private void collectPotentialInVehicleTripIntervalEvents(
|
||||
EventBean[] newData,
|
||||
List<TachographEsperPotentialInVehicleTripIntervalEvent> target
|
||||
) {
|
||||
if (newData == null) {
|
||||
return;
|
||||
}
|
||||
for (EventBean event : newData) {
|
||||
long startedAtEpochSecond = (Long) event.get("startedAtEpochSecond");
|
||||
long endedAtEpochSecond = (Long) event.get("endedAtEpochSecond");
|
||||
target.add(new TachographEsperPotentialInVehicleTripIntervalEvent(
|
||||
(UUID) event.get("sessionId"),
|
||||
(String) event.get("driverKey"),
|
||||
OffsetDateTime.ofInstant(Instant.ofEpochSecond(startedAtEpochSecond), ZoneOffset.UTC),
|
||||
OffsetDateTime.ofInstant(Instant.ofEpochSecond(endedAtEpochSecond), ZoneOffset.UTC),
|
||||
(Long) event.get("durationSeconds"),
|
||||
(String) event.get("registrationKey"),
|
||||
(String) event.get("vehicleKey"),
|
||||
(Integer) event.get("containedPotentialInVehicleOvernightStayIntervalCount"),
|
||||
(Long) event.get("containedPotentialInVehicleOvernightStayDurationSeconds"),
|
||||
(Long) event.get("containedCardPresentDurationSeconds"),
|
||||
(Long) event.get("containedUnknownDurationSeconds"),
|
||||
OffsetDateTime.ofInstant(Instant.ofEpochSecond((Long) event.get("firstPotentialInVehicleOvernightStayStartedAtEpochSecond")), ZoneOffset.UTC),
|
||||
OffsetDateTime.ofInstant(Instant.ofEpochSecond((Long) event.get("lastPotentialInVehicleOvernightStayEndedAtEpochSecond")), ZoneOffset.UTC),
|
||||
(String) event.get("firstPreviousDrivingSourceIntervalId"),
|
||||
(String) event.get("lastNextDrivingSourceIntervalId"),
|
||||
List.of()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private List<TachographEsperDrivingInterruptionIntervalEvent> sortDrivingInterruptionIntervals(
|
||||
List<TachographEsperDrivingInterruptionIntervalEvent> intervals
|
||||
) {
|
||||
|
|
@ -509,6 +549,15 @@ public class DriverTimelineReusableProjectionBuilder {
|
|||
.toList();
|
||||
}
|
||||
|
||||
private List<TachographEsperPotentialInVehicleTripIntervalEvent> sortPotentialInVehicleTripIntervals(
|
||||
List<TachographEsperPotentialInVehicleTripIntervalEvent> intervals
|
||||
) {
|
||||
return intervals.stream()
|
||||
.sorted(Comparator.comparing(TachographEsperPotentialInVehicleTripIntervalEvent::startedAt)
|
||||
.thenComparing(TachographEsperPotentialInVehicleTripIntervalEvent::endedAt))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private String renderDrivingDerivedProjectionBundleEpl(int significantDrivingMinutes, int minimumRestPeriodMinutes) {
|
||||
return DRIVING_DERIVED_PROJECTION_BUNDLE_EPL_TEMPLATE
|
||||
.replace(
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInte
|
|||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleOvernightStayIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||
import java.time.Duration;
|
||||
|
|
@ -202,17 +203,18 @@ public class TachographFileSessionProcessingService {
|
|||
requestedFrom,
|
||||
requestedTo
|
||||
);
|
||||
List<TachographEsperVehicleUsageIntervalEvent> rawVehicleUsageIntervals =
|
||||
driverTimelineBuilder.buildEsperVehicleUsageIntervalEvents(timeline);
|
||||
List<TachographEsperVuCardAbsentIntervalEvent> rawVuCardAbsentIntervals =
|
||||
derivedProjectionBundle.vuCardAbsentIntervals();
|
||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals =
|
||||
clipEsperPotentialHomeOvernightStayIntervalEvents(
|
||||
derivedProjectionBundle.potentialHomeOvernightStayIntervals(),
|
||||
rawVuCardAbsentIntervals,
|
||||
rawVehicleUsageIntervals,
|
||||
requestedFrom,
|
||||
requestedTo
|
||||
);
|
||||
List<TachographEsperVehicleUsageIntervalEvent> rawVehicleUsageIntervals =
|
||||
driverTimelineBuilder.buildEsperVehicleUsageIntervalEvents(timeline);
|
||||
List<TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent> dailyWeeklyRestCandidateCoverageIntervals =
|
||||
clipEsperDailyWeeklyRestCandidateCoverageIntervalEvents(
|
||||
derivedProjectionBundle.dailyWeeklyRestCandidateCoverageIntervals(),
|
||||
|
|
@ -232,10 +234,18 @@ public class TachographFileSessionProcessingService {
|
|||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals =
|
||||
clipEsperPotentialInVehicleOvernightStayIntervalEvents(
|
||||
derivedProjectionBundle.potentialInVehicleOvernightStayIntervals(),
|
||||
rawVuCardAbsentIntervals,
|
||||
rawVehicleUsageIntervals,
|
||||
requestedFrom,
|
||||
requestedTo
|
||||
);
|
||||
List<TachographEsperPotentialInVehicleTripIntervalEvent> potentialInVehicleTripIntervals =
|
||||
clipEsperPotentialInVehicleTripIntervalEvents(
|
||||
derivedProjectionBundle.potentialInVehicleTripIntervals(),
|
||||
potentialInVehicleOvernightStayIntervals,
|
||||
requestedFrom,
|
||||
requestedTo
|
||||
);
|
||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals = clipEsperVehicleUsageIntervalEvents(
|
||||
rawVehicleUsageIntervals,
|
||||
requestedFrom,
|
||||
|
|
@ -264,10 +274,11 @@ public class TachographFileSessionProcessingService {
|
|||
unclassifiedDailyWeeklyRestCandidateCoverageIntervals.size(),
|
||||
potentialHomeOvernightStayIntervals.size(),
|
||||
potentialInVehicleOvernightStayIntervals.size(),
|
||||
potentialInVehicleTripIntervals.size(),
|
||||
vehicleUsageIntervals.size(),
|
||||
vuCardAbsentIntervals.size(),
|
||||
activityIntervals,
|
||||
drivingIntervals,
|
||||
List.of()/*activityIntervals*/,
|
||||
List.of()/*drivingIntervals*/,
|
||||
drivingInterruptionIntervals,
|
||||
drivingInterruptionVehicleChangeIntervals,
|
||||
dailyWeeklyRestCandidateIntervals,
|
||||
|
|
@ -275,6 +286,7 @@ public class TachographFileSessionProcessingService {
|
|||
unclassifiedDailyWeeklyRestCandidateCoverageIntervals,
|
||||
potentialHomeOvernightStayIntervals,
|
||||
potentialInVehicleOvernightStayIntervals,
|
||||
potentialInVehicleTripIntervals,
|
||||
vehicleUsageIntervals,
|
||||
vuCardAbsentIntervals,
|
||||
esperProjectionNotes()
|
||||
|
|
@ -510,53 +522,6 @@ public class TachographFileSessionProcessingService {
|
|||
private List<TachographEsperPotentialHomeOvernightStayIntervalEvent> clipEsperPotentialHomeOvernightStayIntervalEvents(
|
||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> intervals,
|
||||
List<TachographEsperVuCardAbsentIntervalEvent> rawVuCardAbsentIntervals,
|
||||
OffsetDateTime requestedFrom,
|
||||
OffsetDateTime requestedTo
|
||||
) {
|
||||
if (requestedFrom == null || requestedTo == null) {
|
||||
return List.of();
|
||||
}
|
||||
return intervals.stream()
|
||||
.map(interval -> {
|
||||
OffsetDateTime start = max(interval.startedAt(), requestedFrom);
|
||||
OffsetDateTime end = min(interval.endedAt(), requestedTo);
|
||||
if (!end.isAfter(start)) {
|
||||
return null;
|
||||
}
|
||||
long durationSeconds = Duration.between(start, end).getSeconds();
|
||||
long unknownDurationSeconds = overlapSeconds(
|
||||
start,
|
||||
end,
|
||||
rawVuCardAbsentIntervals,
|
||||
interval.driverKey()
|
||||
);
|
||||
double unknownCoveragePercent = durationSeconds == 0L
|
||||
? 0.0d
|
||||
: (unknownDurationSeconds * 100.0d) / durationSeconds;
|
||||
return new TachographEsperPotentialHomeOvernightStayIntervalEvent(
|
||||
interval.sessionId(),
|
||||
interval.driverKey(),
|
||||
start,
|
||||
end,
|
||||
durationSeconds,
|
||||
unknownDurationSeconds,
|
||||
unknownCoveragePercent,
|
||||
interval.previousDrivingSourceIntervalId(),
|
||||
interval.nextDrivingSourceIntervalId(),
|
||||
interval.previousRegistrationKey(),
|
||||
interval.nextRegistrationKey(),
|
||||
interval.previousVehicleKey(),
|
||||
interval.nextVehicleKey()
|
||||
);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.sorted(Comparator.comparing(TachographEsperPotentialHomeOvernightStayIntervalEvent::startedAt)
|
||||
.thenComparing(TachographEsperPotentialHomeOvernightStayIntervalEvent::endedAt))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> clipEsperPotentialInVehicleOvernightStayIntervalEvents(
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> intervals,
|
||||
List<TachographEsperVehicleUsageIntervalEvent> rawVehicleUsageIntervals,
|
||||
OffsetDateTime requestedFrom,
|
||||
OffsetDateTime requestedTo
|
||||
|
|
@ -577,11 +542,81 @@ public class TachographFileSessionProcessingService {
|
|||
end,
|
||||
rawVehicleUsageIntervals,
|
||||
interval.driverKey(),
|
||||
interval.previousRegistrationKey()
|
||||
null
|
||||
);
|
||||
double cardPresentCoveragePercent = durationSeconds == 0L
|
||||
? 0.0d
|
||||
: (cardPresentDurationSeconds * 100.0d) / durationSeconds;
|
||||
long unknownDurationSeconds = overlapSeconds(
|
||||
start,
|
||||
end,
|
||||
rawVuCardAbsentIntervals,
|
||||
interval.driverKey()
|
||||
);
|
||||
double unknownCoveragePercent = durationSeconds == 0L
|
||||
? 0.0d
|
||||
: (unknownDurationSeconds * 100.0d) / durationSeconds;
|
||||
return new TachographEsperPotentialHomeOvernightStayIntervalEvent(
|
||||
interval.sessionId(),
|
||||
interval.driverKey(),
|
||||
start,
|
||||
end,
|
||||
durationSeconds,
|
||||
cardPresentDurationSeconds,
|
||||
cardPresentCoveragePercent,
|
||||
unknownDurationSeconds,
|
||||
unknownCoveragePercent,
|
||||
interval.previousDrivingSourceIntervalId(),
|
||||
interval.nextDrivingSourceIntervalId(),
|
||||
interval.previousRegistrationKey(),
|
||||
interval.nextRegistrationKey(),
|
||||
interval.previousVehicleKey(),
|
||||
interval.nextVehicleKey()
|
||||
);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.sorted(Comparator.comparing(TachographEsperPotentialHomeOvernightStayIntervalEvent::startedAt)
|
||||
.thenComparing(TachographEsperPotentialHomeOvernightStayIntervalEvent::endedAt))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> clipEsperPotentialInVehicleOvernightStayIntervalEvents(
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> intervals,
|
||||
List<TachographEsperVuCardAbsentIntervalEvent> rawVuCardAbsentIntervals,
|
||||
List<TachographEsperVehicleUsageIntervalEvent> rawVehicleUsageIntervals,
|
||||
OffsetDateTime requestedFrom,
|
||||
OffsetDateTime requestedTo
|
||||
) {
|
||||
if (requestedFrom == null || requestedTo == null) {
|
||||
return List.of();
|
||||
}
|
||||
return intervals.stream()
|
||||
.map(interval -> {
|
||||
OffsetDateTime start = max(interval.startedAt(), requestedFrom);
|
||||
OffsetDateTime end = min(interval.endedAt(), requestedTo);
|
||||
if (!end.isAfter(start)) {
|
||||
return null;
|
||||
}
|
||||
long durationSeconds = Duration.between(start, end).getSeconds();
|
||||
long cardPresentDurationSeconds = overlapVehicleUsageSeconds(
|
||||
start,
|
||||
end,
|
||||
rawVehicleUsageIntervals,
|
||||
interval.driverKey(),
|
||||
null
|
||||
);
|
||||
double cardPresentCoveragePercent = durationSeconds == 0L
|
||||
? 0.0d
|
||||
: (cardPresentDurationSeconds * 100.0d) / durationSeconds;
|
||||
long unknownDurationSeconds = overlapSeconds(
|
||||
start,
|
||||
end,
|
||||
rawVuCardAbsentIntervals,
|
||||
interval.driverKey()
|
||||
);
|
||||
double unknownCoveragePercent = durationSeconds == 0L
|
||||
? 0.0d
|
||||
: (unknownDurationSeconds * 100.0d) / durationSeconds;
|
||||
return new TachographEsperPotentialInVehicleOvernightStayIntervalEvent(
|
||||
interval.sessionId(),
|
||||
interval.driverKey(),
|
||||
|
|
@ -590,6 +625,8 @@ public class TachographFileSessionProcessingService {
|
|||
durationSeconds,
|
||||
cardPresentDurationSeconds,
|
||||
cardPresentCoveragePercent,
|
||||
unknownDurationSeconds,
|
||||
unknownCoveragePercent,
|
||||
interval.previousDrivingSourceIntervalId(),
|
||||
interval.nextDrivingSourceIntervalId(),
|
||||
interval.previousRegistrationKey(),
|
||||
|
|
@ -604,6 +641,98 @@ public class TachographFileSessionProcessingService {
|
|||
.toList();
|
||||
}
|
||||
|
||||
private List<TachographEsperPotentialInVehicleTripIntervalEvent> clipEsperPotentialInVehicleTripIntervalEvents(
|
||||
List<TachographEsperPotentialInVehicleTripIntervalEvent> intervals,
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> potentialInVehicleOvernightStayIntervals,
|
||||
OffsetDateTime requestedFrom,
|
||||
OffsetDateTime requestedTo
|
||||
) {
|
||||
if (requestedFrom == null || requestedTo == null) {
|
||||
return List.of();
|
||||
}
|
||||
if (intervals == null || intervals.isEmpty()
|
||||
|| potentialInVehicleOvernightStayIntervals == null || potentialInVehicleOvernightStayIntervals.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
return intervals.stream()
|
||||
.map(interval -> {
|
||||
OffsetDateTime start = max(interval.startedAt(), requestedFrom);
|
||||
OffsetDateTime end = min(interval.endedAt(), requestedTo);
|
||||
if (!end.isAfter(start)) {
|
||||
return null;
|
||||
}
|
||||
List<TachographEsperPotentialInVehicleOvernightStayIntervalEvent> containedIntervals =
|
||||
potentialInVehicleOvernightStayIntervals.stream()
|
||||
.filter(candidate -> tripContainsPotentialInterval(
|
||||
interval.driverKey(),
|
||||
interval.registrationKey(),
|
||||
interval.vehicleKey(),
|
||||
start,
|
||||
end,
|
||||
candidate
|
||||
))
|
||||
.sorted(Comparator.comparing(TachographEsperPotentialInVehicleOvernightStayIntervalEvent::startedAt)
|
||||
.thenComparing(TachographEsperPotentialInVehicleOvernightStayIntervalEvent::endedAt))
|
||||
.toList();
|
||||
if (containedIntervals.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
TachographEsperPotentialInVehicleOvernightStayIntervalEvent first = containedIntervals.get(0);
|
||||
TachographEsperPotentialInVehicleOvernightStayIntervalEvent last =
|
||||
containedIntervals.get(containedIntervals.size() - 1);
|
||||
return new TachographEsperPotentialInVehicleTripIntervalEvent(
|
||||
interval.sessionId(),
|
||||
interval.driverKey(),
|
||||
start,
|
||||
end,
|
||||
Duration.between(start, end).getSeconds(),
|
||||
interval.registrationKey(),
|
||||
interval.vehicleKey(),
|
||||
containedIntervals.size(),
|
||||
containedIntervals.stream()
|
||||
.mapToLong(TachographEsperPotentialInVehicleOvernightStayIntervalEvent::durationSeconds)
|
||||
.sum(),
|
||||
containedIntervals.stream()
|
||||
.mapToLong(TachographEsperPotentialInVehicleOvernightStayIntervalEvent::cardPresentDurationSeconds)
|
||||
.sum(),
|
||||
containedIntervals.stream()
|
||||
.mapToLong(TachographEsperPotentialInVehicleOvernightStayIntervalEvent::unknownDurationSeconds)
|
||||
.sum(),
|
||||
first.startedAt(),
|
||||
last.endedAt(),
|
||||
first.previousDrivingSourceIntervalId(),
|
||||
last.nextDrivingSourceIntervalId(),
|
||||
containedIntervals
|
||||
);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.sorted(Comparator.comparing(TachographEsperPotentialInVehicleTripIntervalEvent::startedAt)
|
||||
.thenComparing(TachographEsperPotentialInVehicleTripIntervalEvent::endedAt))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private boolean tripContainsPotentialInterval(
|
||||
String driverKey,
|
||||
String registrationKey,
|
||||
String vehicleKey,
|
||||
OffsetDateTime tripStartedAt,
|
||||
OffsetDateTime tripEndedAt,
|
||||
TachographEsperPotentialInVehicleOvernightStayIntervalEvent candidate
|
||||
) {
|
||||
if (!Objects.equals(driverKey, candidate.driverKey())) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(registrationKey, candidate.previousRegistrationKey())) {
|
||||
return false;
|
||||
}
|
||||
if (vehicleKey != null && candidate.previousVehicleKey() != null
|
||||
&& !Objects.equals(vehicleKey, candidate.previousVehicleKey())) {
|
||||
return false;
|
||||
}
|
||||
return !candidate.startedAt().isBefore(tripStartedAt)
|
||||
&& !candidate.endedAt().isAfter(tripEndedAt);
|
||||
}
|
||||
|
||||
private List<ResolvedActivityInterval> synthesizeUnknownGaps(
|
||||
List<ResolvedActivityInterval> knownIntervals,
|
||||
Duration gapDetectionTolerance
|
||||
|
|
@ -1174,6 +1303,7 @@ public class TachographFileSessionProcessingService {
|
|||
"Unclassified daily/weekly rest candidate coverage intervals are the rest candidates that are neither potential home overnight stays nor potential in-vehicle overnight stays.",
|
||||
"Potential home overnight stay intervals are vehicle-change daily/weekly rest candidate coverage intervals where VU card-absent overlap covers at least 95% of the candidate interval.",
|
||||
"Potential in-vehicle overnight stay intervals are no-change daily/weekly rest candidate coverage intervals where card-present overlap covers the candidate rest period.",
|
||||
"Potential in-vehicle trip intervals span from the end of the coverage interval before a same-vehicle in-vehicle-overnight sequence to the start of the first coverage interval after that sequence.",
|
||||
"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.",
|
||||
"Vehicle-usage intervals clear clipped odometer endpoints because boundary odometer values cannot be recomputed safely from the source interval."
|
||||
|
|
|
|||
|
|
@ -137,6 +137,8 @@ create schema PotentialHomeOvernightStayInterval(
|
|||
startedAtEpochSecond long,
|
||||
endedAtEpochSecond long,
|
||||
durationSeconds long,
|
||||
cardPresentDurationSeconds long,
|
||||
cardPresentCoveragePercent double,
|
||||
unknownDurationSeconds long,
|
||||
unknownCoveragePercent double,
|
||||
previousDrivingSourceIntervalId string,
|
||||
|
|
@ -155,6 +157,8 @@ create schema PotentialInVehicleOvernightStayInterval(
|
|||
durationSeconds long,
|
||||
cardPresentDurationSeconds long,
|
||||
cardPresentCoveragePercent double,
|
||||
unknownDurationSeconds long,
|
||||
unknownCoveragePercent double,
|
||||
previousDrivingSourceIntervalId string,
|
||||
nextDrivingSourceIntervalId string,
|
||||
previousRegistrationKey string,
|
||||
|
|
@ -181,6 +185,44 @@ create schema UnclassifiedDailyWeeklyRestCandidateCoverageInterval(
|
|||
nextVehicleKey string
|
||||
);
|
||||
|
||||
create schema PotentialInVehicleTripState(
|
||||
sessionId java.util.UUID,
|
||||
driverKey string,
|
||||
tripStartedAtEpochSecond long,
|
||||
registrationKey string,
|
||||
vehicleKey string,
|
||||
containedPotentialInVehicleOvernightStayIntervalCount int,
|
||||
containedPotentialInVehicleOvernightStayDurationSeconds long,
|
||||
containedCardPresentDurationSeconds long,
|
||||
containedUnknownDurationSeconds long,
|
||||
firstPotentialInVehicleOvernightStayStartedAtEpochSecond long,
|
||||
lastPotentialInVehicleOvernightStayEndedAtEpochSecond long,
|
||||
firstPreviousDrivingSourceIntervalId string,
|
||||
lastNextDrivingSourceIntervalId string
|
||||
);
|
||||
|
||||
create schema PotentialInVehicleTripInterval(
|
||||
sessionId java.util.UUID,
|
||||
driverKey string,
|
||||
startedAtEpochSecond long,
|
||||
endedAtEpochSecond long,
|
||||
durationSeconds long,
|
||||
registrationKey string,
|
||||
vehicleKey string,
|
||||
containedPotentialInVehicleOvernightStayIntervalCount int,
|
||||
containedPotentialInVehicleOvernightStayDurationSeconds long,
|
||||
containedCardPresentDurationSeconds long,
|
||||
containedUnknownDurationSeconds long,
|
||||
firstPotentialInVehicleOvernightStayStartedAtEpochSecond long,
|
||||
lastPotentialInVehicleOvernightStayEndedAtEpochSecond long,
|
||||
firstPreviousDrivingSourceIntervalId string,
|
||||
lastNextDrivingSourceIntervalId string
|
||||
);
|
||||
|
||||
create window PreviousRestCandidateCoverageInterval#unique(driverKey) as DailyWeeklyRestCandidateCoverageInterval;
|
||||
|
||||
create window OpenPotentialInVehicleTripState#unique(driverKey) as PotentialInVehicleTripState;
|
||||
|
||||
insert into SignificantDrivingInterval
|
||||
select
|
||||
sessionId,
|
||||
|
|
@ -435,6 +477,8 @@ select
|
|||
c.startedAtEpochSecond as startedAtEpochSecond,
|
||||
c.endedAtEpochSecond as endedAtEpochSecond,
|
||||
c.durationSeconds as durationSeconds,
|
||||
c.cardPresentDurationSeconds as cardPresentDurationSeconds,
|
||||
c.cardPresentCoveragePercent as cardPresentCoveragePercent,
|
||||
c.unknownDurationSeconds as unknownDurationSeconds,
|
||||
c.unknownCoveragePercent as unknownCoveragePercent,
|
||||
c.previousDrivingSourceIntervalId as previousDrivingSourceIntervalId,
|
||||
|
|
@ -458,6 +502,8 @@ select
|
|||
c.durationSeconds as durationSeconds,
|
||||
c.cardPresentDurationSeconds as cardPresentDurationSeconds,
|
||||
c.cardPresentCoveragePercent as cardPresentCoveragePercent,
|
||||
c.unknownDurationSeconds as unknownDurationSeconds,
|
||||
c.unknownCoveragePercent as unknownCoveragePercent,
|
||||
c.previousDrivingSourceIntervalId as previousDrivingSourceIntervalId,
|
||||
c.nextDrivingSourceIntervalId as nextDrivingSourceIntervalId,
|
||||
c.previousRegistrationKey as previousRegistrationKey,
|
||||
|
|
@ -501,6 +547,130 @@ where not (
|
|||
and c.cardPresentDurationSeconds >= c.durationSeconds
|
||||
);
|
||||
|
||||
@Priority(40)
|
||||
on DailyWeeklyRestCandidateCoverageInterval as c
|
||||
insert into PotentialInVehicleTripInterval
|
||||
select
|
||||
s.sessionId as sessionId,
|
||||
s.driverKey as driverKey,
|
||||
s.tripStartedAtEpochSecond as startedAtEpochSecond,
|
||||
c.startedAtEpochSecond as endedAtEpochSecond,
|
||||
c.startedAtEpochSecond - s.tripStartedAtEpochSecond as durationSeconds,
|
||||
s.registrationKey as registrationKey,
|
||||
s.vehicleKey as vehicleKey,
|
||||
s.containedPotentialInVehicleOvernightStayIntervalCount as containedPotentialInVehicleOvernightStayIntervalCount,
|
||||
s.containedPotentialInVehicleOvernightStayDurationSeconds as containedPotentialInVehicleOvernightStayDurationSeconds,
|
||||
s.containedCardPresentDurationSeconds as containedCardPresentDurationSeconds,
|
||||
s.containedUnknownDurationSeconds as containedUnknownDurationSeconds,
|
||||
s.firstPotentialInVehicleOvernightStayStartedAtEpochSecond as firstPotentialInVehicleOvernightStayStartedAtEpochSecond,
|
||||
s.lastPotentialInVehicleOvernightStayEndedAtEpochSecond as lastPotentialInVehicleOvernightStayEndedAtEpochSecond,
|
||||
s.firstPreviousDrivingSourceIntervalId as firstPreviousDrivingSourceIntervalId,
|
||||
s.lastNextDrivingSourceIntervalId as lastNextDrivingSourceIntervalId
|
||||
from OpenPotentialInVehicleTripState as s
|
||||
where s.driverKey = c.driverKey
|
||||
and c.startedAtEpochSecond > s.tripStartedAtEpochSecond
|
||||
and (
|
||||
not (
|
||||
c.previousRegistrationKey is not null
|
||||
and c.nextRegistrationKey is not null
|
||||
and c.previousRegistrationKey = c.nextRegistrationKey
|
||||
and c.cardPresentDurationSeconds >= c.durationSeconds
|
||||
)
|
||||
or s.registrationKey != c.previousRegistrationKey
|
||||
or (
|
||||
s.vehicleKey is not null
|
||||
and c.previousVehicleKey is not null
|
||||
and s.vehicleKey != c.previousVehicleKey
|
||||
)
|
||||
);
|
||||
|
||||
@Priority(35)
|
||||
on DailyWeeklyRestCandidateCoverageInterval as c
|
||||
delete from OpenPotentialInVehicleTripState as s
|
||||
where s.driverKey = c.driverKey
|
||||
and not (
|
||||
c.previousRegistrationKey is not null
|
||||
and c.nextRegistrationKey is not null
|
||||
and c.previousRegistrationKey = c.nextRegistrationKey
|
||||
and c.cardPresentDurationSeconds >= c.durationSeconds
|
||||
);
|
||||
|
||||
@Priority(30)
|
||||
on DailyWeeklyRestCandidateCoverageInterval as c
|
||||
insert into OpenPotentialInVehicleTripState
|
||||
select
|
||||
s.sessionId as sessionId,
|
||||
s.driverKey as driverKey,
|
||||
s.tripStartedAtEpochSecond as tripStartedAtEpochSecond,
|
||||
s.registrationKey as registrationKey,
|
||||
s.vehicleKey as vehicleKey,
|
||||
s.containedPotentialInVehicleOvernightStayIntervalCount + 1 as containedPotentialInVehicleOvernightStayIntervalCount,
|
||||
s.containedPotentialInVehicleOvernightStayDurationSeconds + c.durationSeconds as containedPotentialInVehicleOvernightStayDurationSeconds,
|
||||
s.containedCardPresentDurationSeconds + c.cardPresentDurationSeconds as containedCardPresentDurationSeconds,
|
||||
s.containedUnknownDurationSeconds + c.unknownDurationSeconds as containedUnknownDurationSeconds,
|
||||
s.firstPotentialInVehicleOvernightStayStartedAtEpochSecond as firstPotentialInVehicleOvernightStayStartedAtEpochSecond,
|
||||
c.endedAtEpochSecond as lastPotentialInVehicleOvernightStayEndedAtEpochSecond,
|
||||
s.firstPreviousDrivingSourceIntervalId as firstPreviousDrivingSourceIntervalId,
|
||||
c.nextDrivingSourceIntervalId as lastNextDrivingSourceIntervalId
|
||||
from OpenPotentialInVehicleTripState as s
|
||||
where s.driverKey = c.driverKey
|
||||
and c.previousRegistrationKey is not null
|
||||
and c.nextRegistrationKey is not null
|
||||
and c.previousRegistrationKey = c.nextRegistrationKey
|
||||
and c.cardPresentDurationSeconds >= c.durationSeconds
|
||||
and s.registrationKey = c.previousRegistrationKey
|
||||
and (
|
||||
s.vehicleKey is null
|
||||
or c.previousVehicleKey is null
|
||||
or s.vehicleKey = c.previousVehicleKey
|
||||
);
|
||||
|
||||
@Priority(20)
|
||||
on DailyWeeklyRestCandidateCoverageInterval as c
|
||||
insert into OpenPotentialInVehicleTripState
|
||||
select
|
||||
c.sessionId as sessionId,
|
||||
c.driverKey as driverKey,
|
||||
priorCoverage.endedAtEpochSecond as tripStartedAtEpochSecond,
|
||||
c.previousRegistrationKey as registrationKey,
|
||||
case
|
||||
when c.previousVehicleKey is not null then c.previousVehicleKey
|
||||
else c.nextVehicleKey
|
||||
end as vehicleKey,
|
||||
1 as containedPotentialInVehicleOvernightStayIntervalCount,
|
||||
c.durationSeconds as containedPotentialInVehicleOvernightStayDurationSeconds,
|
||||
c.cardPresentDurationSeconds as containedCardPresentDurationSeconds,
|
||||
c.unknownDurationSeconds as containedUnknownDurationSeconds,
|
||||
c.startedAtEpochSecond as firstPotentialInVehicleOvernightStayStartedAtEpochSecond,
|
||||
c.endedAtEpochSecond as lastPotentialInVehicleOvernightStayEndedAtEpochSecond,
|
||||
c.previousDrivingSourceIntervalId as firstPreviousDrivingSourceIntervalId,
|
||||
c.nextDrivingSourceIntervalId as lastNextDrivingSourceIntervalId
|
||||
from PreviousRestCandidateCoverageInterval as priorCoverage
|
||||
where priorCoverage.driverKey = c.driverKey
|
||||
and c.previousRegistrationKey is not null
|
||||
and c.nextRegistrationKey is not null
|
||||
and c.previousRegistrationKey = c.nextRegistrationKey
|
||||
and c.cardPresentDurationSeconds >= c.durationSeconds
|
||||
and not exists (
|
||||
select * from OpenPotentialInVehicleTripState as s
|
||||
where s.driverKey = c.driverKey
|
||||
and s.registrationKey = c.previousRegistrationKey
|
||||
and (
|
||||
s.vehicleKey is null
|
||||
or c.previousVehicleKey is null
|
||||
or s.vehicleKey = c.previousVehicleKey
|
||||
)
|
||||
);
|
||||
|
||||
@Priority(10)
|
||||
on DailyWeeklyRestCandidateCoverageInterval
|
||||
delete from PreviousRestCandidateCoverageInterval;
|
||||
|
||||
@Priority(5)
|
||||
on DailyWeeklyRestCandidateCoverageInterval as current
|
||||
insert into PreviousRestCandidateCoverageInterval
|
||||
select *;
|
||||
|
||||
@name('drivingInterruptionIntervals')
|
||||
select * from DrivingInterruptionInterval;
|
||||
|
||||
|
|
@ -522,5 +692,8 @@ select * from PotentialHomeOvernightStayInterval;
|
|||
@name('potentialInVehicleOvernightStayIntervals')
|
||||
select * from PotentialInVehicleOvernightStayInterval;
|
||||
|
||||
@name('potentialInVehicleTripIntervals')
|
||||
select * from PotentialInVehicleTripInterval;
|
||||
|
||||
@name('unclassifiedDailyWeeklyRestCandidateCoverageIntervals')
|
||||
select * from UnclassifiedDailyWeeklyRestCandidateCoverageInterval;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityInt
|
|||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDailyWeeklyRestCandidateCoverageIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialInVehicleTripIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionProcessingService;
|
||||
|
|
@ -89,6 +90,7 @@ class TachographFileSessionControllerTest {
|
|||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
2,
|
||||
1,
|
||||
List.of(new TachographEsperActivityIntervalEvent(
|
||||
|
|
@ -192,6 +194,8 @@ class TachographFileSessionControllerTest {
|
|||
OffsetDateTime.parse("2026-05-12T10:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-12T22:00:00Z"),
|
||||
43_200L,
|
||||
0L,
|
||||
0.0d,
|
||||
43_200L,
|
||||
100.0d,
|
||||
"ACT-2",
|
||||
|
|
@ -202,6 +206,7 @@ class TachographFileSessionControllerTest {
|
|||
"VIN-2"
|
||||
)),
|
||||
List.of(),
|
||||
List.<TachographEsperPotentialInVehicleTripIntervalEvent>of(),
|
||||
List.of(new TachographEsperVehicleUsageIntervalEvent(
|
||||
sessionId,
|
||||
"12:123",
|
||||
|
|
@ -300,6 +305,7 @@ class TachographFileSessionControllerTest {
|
|||
.andExpect(jsonPath("$.unclassifiedDailyWeeklyRestCandidateCoverageIntervalCount").value(0))
|
||||
.andExpect(jsonPath("$.potentialHomeOvernightStayIntervalCount").value(1))
|
||||
.andExpect(jsonPath("$.potentialInVehicleOvernightStayIntervalCount").value(0))
|
||||
.andExpect(jsonPath("$.potentialInVehicleTripIntervalCount").value(0))
|
||||
.andExpect(jsonPath("$.vuCardAbsentIntervalCount").value(1))
|
||||
.andExpect(jsonPath("$.drivingInterruptionIntervals[0].previousRegistrationKey").value("12:REG-1"))
|
||||
.andExpect(jsonPath("$.drivingInterruptionIntervals[0].nextRegistrationKey").value("12:REG-2"))
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
assertThat(result.unclassifiedDailyWeeklyRestCandidateCoverageIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleTripIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2);
|
||||
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
||||
assertThat(result.vuCardAbsentIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:01Z"));
|
||||
|
|
@ -201,6 +202,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
assertThat(result.unclassifiedDailyWeeklyRestCandidateCoverageIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleTripIntervalCount()).isEqualTo(0);
|
||||
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).previousRegistrationKey()).isEqualTo("12:REG-1");
|
||||
|
|
@ -300,6 +302,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
assertThat(result.dailyWeeklyRestCandidateCoverageIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.unclassifiedDailyWeeklyRestCandidateCoverageIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleTripIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2);
|
||||
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
||||
}
|
||||
|
|
@ -397,8 +400,11 @@ class TachographFileSessionProcessingServiceTest {
|
|||
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).nextRegistrationKey()).isEqualTo("12:REG-2");
|
||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(1);
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleTripIntervalCount()).isEqualTo(0);
|
||||
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).cardPresentDurationSeconds()).isEqualTo(0L);
|
||||
assertThat(result.potentialHomeOvernightStayIntervals().get(0).cardPresentCoveragePercent()).isEqualTo(0.0d);
|
||||
assertThat(result.potentialHomeOvernightStayIntervals().get(0).unknownDurationSeconds()).isEqualTo(43_200L);
|
||||
assertThat(result.potentialHomeOvernightStayIntervals().get(0).unknownCoveragePercent()).isEqualTo(100.0d);
|
||||
}
|
||||
|
|
@ -476,6 +482,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervalCount()).isEqualTo(1);
|
||||
assertThat(result.potentialInVehicleTripIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.dailyWeeklyRestCandidateCoverageIntervals().get(0).cardPresentDurationSeconds()).isEqualTo(50_400L);
|
||||
assertThat(result.dailyWeeklyRestCandidateCoverageIntervals().get(0).cardPresentCoveragePercent()).isEqualTo(100.0d);
|
||||
assertThat(result.dailyWeeklyRestCandidateCoverageIntervals().get(0).unknownDurationSeconds()).isEqualTo(0L);
|
||||
|
|
@ -483,6 +490,8 @@ class TachographFileSessionProcessingServiceTest {
|
|||
assertThat(result.potentialInVehicleOvernightStayIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-02T00:00:00Z"));
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervals().get(0).cardPresentDurationSeconds()).isEqualTo(50_400L);
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervals().get(0).cardPresentCoveragePercent()).isEqualTo(100.0d);
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervals().get(0).unknownDurationSeconds()).isEqualTo(0L);
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervals().get(0).unknownCoveragePercent()).isEqualTo(0.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -565,6 +574,7 @@ class TachographFileSessionProcessingServiceTest {
|
|||
assertThat(result.dailyWeeklyRestCandidateCoverageIntervalCount()).isEqualTo(1);
|
||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.potentialInVehicleTripIntervalCount()).isEqualTo(0);
|
||||
assertThat(result.unclassifiedDailyWeeklyRestCandidateCoverageIntervalCount()).isEqualTo(1);
|
||||
assertThat(result.unclassifiedDailyWeeklyRestCandidateCoverageIntervals().get(0).startedAt())
|
||||
.isEqualTo(OffsetDateTime.parse("2026-05-01T10:00:00Z"));
|
||||
|
|
@ -576,6 +586,80 @@ class TachographFileSessionProcessingServiceTest {
|
|||
.isLessThan(95.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsPotentialInVehicleTripIntervalsForSameVehicleOvernightSequenceBoundedByCoverageIntervals() {
|
||||
EventHubProperties properties = new EventHubProperties();
|
||||
TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
|
||||
DriverTimelineBuilder driverTimelineBuilder = new DriverTimelineBuilder();
|
||||
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||
repository,
|
||||
driverTimelineBuilder,
|
||||
new DriverTimelineReusableProjectionBuilder(driverTimelineBuilder),
|
||||
new EventBackedDriverTimelineBuilder(
|
||||
new IntervalBackedDriverTimelineEventBuilder(
|
||||
driverTimelineBuilder,
|
||||
new DriverKeyFactory(),
|
||||
new VehicleKeyFactory(),
|
||||
new EventDetailsFactory(new ObjectMapper())
|
||||
)
|
||||
),
|
||||
properties
|
||||
);
|
||||
|
||||
DriverExtractionSession driver = new DriverExtractionSession(
|
||||
"12:123",
|
||||
null,
|
||||
null,
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(
|
||||
new ExtractedCardVehicleUsageInterval("CVU-0", OffsetDateTime.parse("2026-05-01T08:00:00Z"), OffsetDateTime.parse("2026-05-01T09:00:00Z"), 100L, 150L, "12:REG-0", "VIN-0", "vu-0"),
|
||||
new ExtractedCardVehicleUsageInterval("CVU-1", OffsetDateTime.parse("2026-05-01T22:00:00Z"), OffsetDateTime.parse("2026-05-04T02:00:00Z"), 200L, 400L, "12:REG-1", "VIN-1", "vu-1"),
|
||||
new ExtractedCardVehicleUsageInterval("CVU-2", OffsetDateTime.parse("2026-05-05T00:00:00Z"), OffsetDateTime.parse("2026-05-05T02:00:00Z"), 401L, 430L, "12:REG-2", "VIN-2", "vu-2")
|
||||
),
|
||||
List.of(
|
||||
new ExtractedCardActivityInterval("ACT-0", OffsetDateTime.parse("2026-05-01T08:00:00Z"), OffsetDateTime.parse("2026-05-01T09:00:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-0", "VIN-0", "a"),
|
||||
new ExtractedCardActivityInterval("ACT-1", OffsetDateTime.parse("2026-05-01T22:00:00Z"), OffsetDateTime.parse("2026-05-02T00:00:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "b"),
|
||||
new ExtractedCardActivityInterval("ACT-2", OffsetDateTime.parse("2026-05-02T20:00:00Z"), OffsetDateTime.parse("2026-05-02T22:00:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "c"),
|
||||
new ExtractedCardActivityInterval("ACT-3", OffsetDateTime.parse("2026-05-03T20:00:00Z"), OffsetDateTime.parse("2026-05-03T22:00:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "d"),
|
||||
new ExtractedCardActivityInterval("ACT-4", OffsetDateTime.parse("2026-05-05T00:00:00Z"), OffsetDateTime.parse("2026-05-05T02:00:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-2", "VIN-2", "e")
|
||||
),
|
||||
List.of(),
|
||||
List.of()
|
||||
);
|
||||
TachographFileSession session = new TachographFileSession(
|
||||
UUID.randomUUID(),
|
||||
new TachographFileSessionMetadata("default", "legalrequirements-drivercard", "sample", "sample.ddd", "a", 5, "42", "b", true, null),
|
||||
Map.of(driver.driverKey(), driver),
|
||||
new ExtractionStats(1, 5, 3, 1, 1, 0),
|
||||
List.of(),
|
||||
Instant.now(),
|
||||
Instant.now().plus(4, ChronoUnit.HOURS)
|
||||
);
|
||||
repository.save(session);
|
||||
|
||||
TachographEsperDriverProcessingResultDto result = service.getEsperDriverProcessingResults(
|
||||
session.sessionId(),
|
||||
driver.driverKey(),
|
||||
new TachographEsperEventsProcessingRequest(
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-05T00:00:00Z"),
|
||||
3,
|
||||
720
|
||||
)
|
||||
);
|
||||
|
||||
assertThat(result.potentialInVehicleOvernightStayIntervalCount()).isEqualTo(2);
|
||||
assertThat(result.potentialInVehicleTripIntervalCount()).isEqualTo(1);
|
||||
assertThat(result.potentialInVehicleTripIntervals().get(0).startedAt())
|
||||
.isEqualTo(OffsetDateTime.parse("2026-05-01T22:00:00Z"));
|
||||
assertThat(result.potentialInVehicleTripIntervals().get(0).endedAt())
|
||||
.isEqualTo(OffsetDateTime.parse("2026-05-03T22:00:00Z"));
|
||||
assertThat(result.potentialInVehicleTripIntervals().get(0).containedPotentialInVehicleOvernightStayIntervalCount()).isEqualTo(2);
|
||||
assertThat(result.potentialInVehicleTripIntervals().get(0).potentialInVehicleOvernightStayIntervals()).hasSize(2);
|
||||
assertThat(result.potentialInVehicleTripIntervals().get(0).registrationKey()).isEqualTo("12:REG-1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void evaluatesOperatingPeriodsFromSessionTimeline() {
|
||||
EventHubProperties properties = new EventHubProperties();
|
||||
|
|
|
|||
Loading…
Reference in New Issue