Add rest candidate Esper projections
This commit is contained in:
parent
eb4e04f144
commit
3b2f893246
|
|
@ -386,7 +386,7 @@
|
||||||
],
|
],
|
||||||
"body": {
|
"body": {
|
||||||
"mode": "raw",
|
"mode": "raw",
|
||||||
"raw": "{\n \"occurredFrom\": \"{{occurredFrom}}\",\n \"occurredTo\": \"{{occurredTo}}\",\n \"significantDrivingMinutes\": 3\n}"
|
"raw": "{\n \"occurredFrom\": \"{{occurredFrom}}\",\n \"occurredTo\": \"{{occurredTo}}\",\n \"significantDrivingMinutes\": 3,\n \"minimumRestPeriodMinutes\": 720\n}"
|
||||||
},
|
},
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "{{baseUrl}}/api/eventhub/tachograph-file-sessions/{{sessionId}}/drivers/{{driverKey}}/processing/esper-events",
|
"raw": "{{baseUrl}}/api/eventhub/tachograph-file-sessions/{{sessionId}}/drivers/{{driverKey}}/processing/esper-events",
|
||||||
|
|
|
||||||
|
|
@ -358,6 +358,7 @@ public class EventHubProperties {
|
||||||
public static class Processing {
|
public static class Processing {
|
||||||
private int operatingSplitIdleHours = 7;
|
private int operatingSplitIdleHours = 7;
|
||||||
private int significantDrivingMinutes = 3;
|
private int significantDrivingMinutes = 3;
|
||||||
|
private int minimumRestPeriodMinutes = 720;
|
||||||
private int mergeGapSeconds = 0;
|
private int mergeGapSeconds = 0;
|
||||||
private int gapDetectionToleranceSeconds = 0;
|
private int gapDetectionToleranceSeconds = 0;
|
||||||
|
|
||||||
|
|
@ -377,6 +378,14 @@ public class EventHubProperties {
|
||||||
this.significantDrivingMinutes = Math.max(1, significantDrivingMinutes);
|
this.significantDrivingMinutes = Math.max(1, significantDrivingMinutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getMinimumRestPeriodMinutes() {
|
||||||
|
return minimumRestPeriodMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinimumRestPeriodMinutes(int minimumRestPeriodMinutes) {
|
||||||
|
this.minimumRestPeriodMinutes = Math.max(1, minimumRestPeriodMinutes);
|
||||||
|
}
|
||||||
|
|
||||||
public int getMergeGapSeconds() {
|
public int getMergeGapSeconds() {
|
||||||
return mergeGapSeconds;
|
return mergeGapSeconds;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package at.procon.eventhub.tachographfilesession.dto;
|
||||||
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
||||||
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
|
@ -19,11 +20,15 @@ public record TachographEsperDriverProcessingResultDto(
|
||||||
int activityIntervalCount,
|
int activityIntervalCount,
|
||||||
int drivingIntervalCount,
|
int drivingIntervalCount,
|
||||||
int drivingInterruptionIntervalCount,
|
int drivingInterruptionIntervalCount,
|
||||||
|
int drivingInterruptionVehicleChangeIntervalCount,
|
||||||
|
int potentialHomeOvernightStayIntervalCount,
|
||||||
int vehicleUsageIntervalCount,
|
int vehicleUsageIntervalCount,
|
||||||
int vuCardAbsentIntervalCount,
|
int vuCardAbsentIntervalCount,
|
||||||
List<TachographEsperActivityIntervalEvent> activityIntervals,
|
List<TachographEsperActivityIntervalEvent> activityIntervals,
|
||||||
List<TachographEsperActivityIntervalEvent> drivingIntervals,
|
List<TachographEsperActivityIntervalEvent> drivingIntervals,
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals,
|
||||||
|
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals,
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals,
|
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals,
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
||||||
List<String> notes
|
List<String> notes
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,13 @@ import java.time.OffsetDateTime;
|
||||||
public record TachographEsperEventsProcessingRequest(
|
public record TachographEsperEventsProcessingRequest(
|
||||||
OffsetDateTime occurredFrom,
|
OffsetDateTime occurredFrom,
|
||||||
OffsetDateTime occurredTo,
|
OffsetDateTime occurredTo,
|
||||||
Integer significantDrivingMinutes
|
Integer significantDrivingMinutes,
|
||||||
|
Integer minimumRestPeriodMinutes
|
||||||
) {
|
) {
|
||||||
public TachographEsperEventsProcessingRequest {
|
public TachographEsperEventsProcessingRequest {
|
||||||
significantDrivingMinutes = significantDrivingMinutes == null ? null : Math.max(1, significantDrivingMinutes);
|
significantDrivingMinutes = significantDrivingMinutes == null ? null : Math.max(1, significantDrivingMinutes);
|
||||||
|
minimumRestPeriodMinutes = minimumRestPeriodMinutes == null
|
||||||
|
? null
|
||||||
|
: Math.max(1, minimumRestPeriodMinutes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ public record TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
long durationSeconds,
|
long durationSeconds,
|
||||||
String previousDrivingSourceIntervalId,
|
String previousDrivingSourceIntervalId,
|
||||||
String nextDrivingSourceIntervalId,
|
String nextDrivingSourceIntervalId,
|
||||||
|
String previousRegistrationKey,
|
||||||
|
String nextRegistrationKey,
|
||||||
String previousVehicleKey,
|
String previousVehicleKey,
|
||||||
String nextVehicleKey
|
String nextVehicleKey
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package at.procon.eventhub.tachographfilesession.model;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record TachographEsperPotentialHomeOvernightStayIntervalEvent(
|
||||||
|
UUID sessionId,
|
||||||
|
String driverKey,
|
||||||
|
OffsetDateTime startedAt,
|
||||||
|
OffsetDateTime endedAt,
|
||||||
|
long durationSeconds,
|
||||||
|
long unknownDurationSeconds,
|
||||||
|
double unknownCoveragePercent,
|
||||||
|
String previousDrivingSourceIntervalId,
|
||||||
|
String nextDrivingSourceIntervalId,
|
||||||
|
String previousRegistrationKey,
|
||||||
|
String nextRegistrationKey,
|
||||||
|
String previousVehicleKey,
|
||||||
|
String nextVehicleKey
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
|
||||||
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
|
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
||||||
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||||
|
|
@ -52,6 +53,10 @@ public class DriverTimelineBuilder {
|
||||||
loadResource("esper/tachograph-driving-interval-events.epl");
|
loadResource("esper/tachograph-driving-interval-events.epl");
|
||||||
private static final String DRIVING_INTERRUPTION_INTERVAL_EVENTS_EPL_TEMPLATE =
|
private static final String DRIVING_INTERRUPTION_INTERVAL_EVENTS_EPL_TEMPLATE =
|
||||||
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 =
|
||||||
|
loadResource("esper/tachograph-driving-interruption-vehicle-change-interval-events.epl");
|
||||||
|
private static final String POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE =
|
||||||
|
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 =
|
||||||
loadResource("esper/tachograph-vehicle-usage-interval-events.epl");
|
loadResource("esper/tachograph-vehicle-usage-interval-events.epl");
|
||||||
private static final String VU_CARD_ABSENT_INTERVAL_EVENTS_EPL =
|
private static final String VU_CARD_ABSENT_INTERVAL_EVENTS_EPL =
|
||||||
|
|
@ -176,6 +181,77 @@ public class DriverTimelineBuilder {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<TachographEsperDrivingInterruptionIntervalEvent> buildEsperDrivingInterruptionVehicleChangeIntervalEvents(
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals
|
||||||
|
) {
|
||||||
|
if (drivingInterruptionIntervals == null || drivingInterruptionIntervals.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> result = new ArrayList<>();
|
||||||
|
executeWithRuntime(
|
||||||
|
configuration -> configuration.getCommon().addEventType(
|
||||||
|
"TachographDrivingInterruptionIntervalInputEvent",
|
||||||
|
drivingInterruptionIntervalInputDefinition()
|
||||||
|
),
|
||||||
|
DRIVING_INTERRUPTION_VEHICLE_CHANGE_INTERVAL_EVENTS_EPL,
|
||||||
|
"drivingInterruptionVehicleChangeIntervals",
|
||||||
|
newData -> collectDrivingInterruptionIntervalEventsFromTimestamps(newData, result),
|
||||||
|
runtime -> {
|
||||||
|
for (TachographEsperDrivingInterruptionIntervalEvent interval : drivingInterruptionIntervals) {
|
||||||
|
runtime.getEventService().sendEventMap(
|
||||||
|
toDrivingInterruptionIntervalInputMap(interval),
|
||||||
|
"TachographDrivingInterruptionIntervalInputEvent"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TachographEsperPotentialHomeOvernightStayIntervalEvent> buildEsperPotentialHomeOvernightStayIntervalEvents(
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
||||||
|
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
||||||
|
int minimumRestPeriodMinutes
|
||||||
|
) {
|
||||||
|
if (drivingInterruptionIntervals == null
|
||||||
|
|| drivingInterruptionIntervals.isEmpty()
|
||||||
|
|| vuCardAbsentIntervals == null
|
||||||
|
|| vuCardAbsentIntervals.isEmpty()) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> result = new ArrayList<>();
|
||||||
|
executeWithRuntime(
|
||||||
|
configuration -> {
|
||||||
|
configuration.getCommon().addEventType(
|
||||||
|
"TachographDrivingInterruptionIntervalInputEvent",
|
||||||
|
drivingInterruptionIntervalInputDefinition()
|
||||||
|
);
|
||||||
|
configuration.getCommon().addEventType(
|
||||||
|
"TachographVuCardAbsentIntervalInputEvent",
|
||||||
|
vuCardAbsentIntervalInputDefinition()
|
||||||
|
);
|
||||||
|
},
|
||||||
|
renderPotentialHomeOvernightStayIntervalEventsEpl(minimumRestPeriodMinutes),
|
||||||
|
"potentialHomeOvernightStayIntervals",
|
||||||
|
newData -> collectPotentialHomeOvernightStayIntervalEvents(newData, result),
|
||||||
|
runtime -> {
|
||||||
|
for (TachographEsperVuCardAbsentIntervalEvent interval : vuCardAbsentIntervals) {
|
||||||
|
runtime.getEventService().sendEventMap(
|
||||||
|
toVuCardAbsentIntervalInputMap(interval),
|
||||||
|
"TachographVuCardAbsentIntervalInputEvent"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (TachographEsperDrivingInterruptionIntervalEvent interval : drivingInterruptionIntervals) {
|
||||||
|
runtime.getEventService().sendEventMap(
|
||||||
|
toDrivingInterruptionIntervalInputMap(interval),
|
||||||
|
"TachographDrivingInterruptionIntervalInputEvent"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public List<TachographEsperVuCardAbsentIntervalEvent> buildEsperVuCardAbsentIntervalEvents(
|
public List<TachographEsperVuCardAbsentIntervalEvent> buildEsperVuCardAbsentIntervalEvents(
|
||||||
TachographFileSession session,
|
TachographFileSession session,
|
||||||
DriverExtractionSession driverSession
|
DriverExtractionSession driverSession
|
||||||
|
|
@ -602,6 +678,42 @@ public class DriverTimelineBuilder {
|
||||||
return definition;
|
return definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> drivingInterruptionIntervalInputDefinition() {
|
||||||
|
Map<String, Object> definition = new LinkedHashMap<>();
|
||||||
|
definition.put("sessionId", UUID.class);
|
||||||
|
definition.put("driverKey", String.class);
|
||||||
|
definition.put("startedAt", OffsetDateTime.class);
|
||||||
|
definition.put("endedAt", OffsetDateTime.class);
|
||||||
|
definition.put("startedAtEpochSecond", long.class);
|
||||||
|
definition.put("endedAtEpochSecond", long.class);
|
||||||
|
definition.put("durationSeconds", long.class);
|
||||||
|
definition.put("previousDrivingSourceIntervalId", String.class);
|
||||||
|
definition.put("nextDrivingSourceIntervalId", String.class);
|
||||||
|
definition.put("previousRegistrationKey", String.class);
|
||||||
|
definition.put("nextRegistrationKey", String.class);
|
||||||
|
definition.put("previousVehicleKey", String.class);
|
||||||
|
definition.put("nextVehicleKey", String.class);
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> vuCardAbsentIntervalInputDefinition() {
|
||||||
|
Map<String, Object> definition = new LinkedHashMap<>();
|
||||||
|
definition.put("sessionId", UUID.class);
|
||||||
|
definition.put("driverKey", String.class);
|
||||||
|
definition.put("startedAt", OffsetDateTime.class);
|
||||||
|
definition.put("endedAt", OffsetDateTime.class);
|
||||||
|
definition.put("startedAtEpochSecond", long.class);
|
||||||
|
definition.put("endedAtEpochSecond", long.class);
|
||||||
|
definition.put("durationSeconds", long.class);
|
||||||
|
definition.put("previousUsageIntervalId", String.class);
|
||||||
|
definition.put("nextUsageIntervalId", String.class);
|
||||||
|
definition.put("previousRegistrationKey", String.class);
|
||||||
|
definition.put("nextRegistrationKey", String.class);
|
||||||
|
definition.put("previousVehicleKey", String.class);
|
||||||
|
definition.put("nextVehicleKey", String.class);
|
||||||
|
return definition;
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, Object> toActivityIntervalInputMap(
|
private Map<String, Object> toActivityIntervalInputMap(
|
||||||
UUID sessionId,
|
UUID sessionId,
|
||||||
String driverKey,
|
String driverKey,
|
||||||
|
|
@ -663,6 +775,44 @@ public class DriverTimelineBuilder {
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> toDrivingInterruptionIntervalInputMap(
|
||||||
|
TachographEsperDrivingInterruptionIntervalEvent interval
|
||||||
|
) {
|
||||||
|
Map<String, Object> event = new LinkedHashMap<>();
|
||||||
|
event.put("sessionId", interval.sessionId());
|
||||||
|
event.put("driverKey", interval.driverKey());
|
||||||
|
event.put("startedAt", interval.startedAt());
|
||||||
|
event.put("endedAt", interval.endedAt());
|
||||||
|
event.put("startedAtEpochSecond", interval.startedAt().toEpochSecond());
|
||||||
|
event.put("endedAtEpochSecond", interval.endedAt().toEpochSecond());
|
||||||
|
event.put("durationSeconds", interval.durationSeconds());
|
||||||
|
event.put("previousDrivingSourceIntervalId", interval.previousDrivingSourceIntervalId());
|
||||||
|
event.put("nextDrivingSourceIntervalId", interval.nextDrivingSourceIntervalId());
|
||||||
|
event.put("previousRegistrationKey", interval.previousRegistrationKey());
|
||||||
|
event.put("nextRegistrationKey", interval.nextRegistrationKey());
|
||||||
|
event.put("previousVehicleKey", interval.previousVehicleKey());
|
||||||
|
event.put("nextVehicleKey", interval.nextVehicleKey());
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> toVuCardAbsentIntervalInputMap(TachographEsperVuCardAbsentIntervalEvent interval) {
|
||||||
|
Map<String, Object> event = new LinkedHashMap<>();
|
||||||
|
event.put("sessionId", interval.sessionId());
|
||||||
|
event.put("driverKey", interval.driverKey());
|
||||||
|
event.put("startedAt", interval.startedAt());
|
||||||
|
event.put("endedAt", interval.endedAt());
|
||||||
|
event.put("startedAtEpochSecond", interval.startedAt().toEpochSecond());
|
||||||
|
event.put("endedAtEpochSecond", interval.endedAt().toEpochSecond());
|
||||||
|
event.put("durationSeconds", interval.durationSeconds());
|
||||||
|
event.put("previousUsageIntervalId", interval.previousUsageIntervalId());
|
||||||
|
event.put("nextUsageIntervalId", interval.nextUsageIntervalId());
|
||||||
|
event.put("previousRegistrationKey", interval.previousRegistrationKey());
|
||||||
|
event.put("nextRegistrationKey", interval.nextRegistrationKey());
|
||||||
|
event.put("previousVehicleKey", interval.previousVehicleKey());
|
||||||
|
event.put("nextVehicleKey", interval.nextVehicleKey());
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
private String firstSourceIntervalId(ResolvedVehicleUsageInterval interval) {
|
private String firstSourceIntervalId(ResolvedVehicleUsageInterval interval) {
|
||||||
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().get(0);
|
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().get(0);
|
||||||
}
|
}
|
||||||
|
|
@ -746,6 +896,32 @@ public class DriverTimelineBuilder {
|
||||||
(Long) event.get("durationSeconds"),
|
(Long) event.get("durationSeconds"),
|
||||||
(String) event.get("previousDrivingSourceIntervalId"),
|
(String) event.get("previousDrivingSourceIntervalId"),
|
||||||
(String) event.get("nextDrivingSourceIntervalId"),
|
(String) event.get("nextDrivingSourceIntervalId"),
|
||||||
|
(String) event.get("previousRegistrationKey"),
|
||||||
|
(String) event.get("nextRegistrationKey"),
|
||||||
|
(String) event.get("previousVehicleKey"),
|
||||||
|
(String) event.get("nextVehicleKey")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void collectDrivingInterruptionIntervalEventsFromTimestamps(
|
||||||
|
EventBean[] newData,
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> target
|
||||||
|
) {
|
||||||
|
if (newData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (EventBean event : newData) {
|
||||||
|
target.add(new TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
|
(UUID) event.get("sessionId"),
|
||||||
|
(String) event.get("driverKey"),
|
||||||
|
(OffsetDateTime) event.get("startedAt"),
|
||||||
|
(OffsetDateTime) event.get("endedAt"),
|
||||||
|
(Long) event.get("durationSeconds"),
|
||||||
|
(String) event.get("previousDrivingSourceIntervalId"),
|
||||||
|
(String) event.get("nextDrivingSourceIntervalId"),
|
||||||
|
(String) event.get("previousRegistrationKey"),
|
||||||
|
(String) event.get("nextRegistrationKey"),
|
||||||
(String) event.get("previousVehicleKey"),
|
(String) event.get("previousVehicleKey"),
|
||||||
(String) event.get("nextVehicleKey")
|
(String) event.get("nextVehicleKey")
|
||||||
));
|
));
|
||||||
|
|
@ -778,6 +954,32 @@ public class DriverTimelineBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void collectPotentialHomeOvernightStayIntervalEvents(
|
||||||
|
EventBean[] newData,
|
||||||
|
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> target
|
||||||
|
) {
|
||||||
|
if (newData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (EventBean event : newData) {
|
||||||
|
target.add(new TachographEsperPotentialHomeOvernightStayIntervalEvent(
|
||||||
|
(UUID) event.get("sessionId"),
|
||||||
|
(String) event.get("driverKey"),
|
||||||
|
(OffsetDateTime) event.get("startedAt"),
|
||||||
|
(OffsetDateTime) event.get("endedAt"),
|
||||||
|
(Long) event.get("durationSeconds"),
|
||||||
|
(Long) event.get("unknownDurationSeconds"),
|
||||||
|
(Double) event.get("unknownCoveragePercent"),
|
||||||
|
(String) event.get("previousDrivingSourceIntervalId"),
|
||||||
|
(String) event.get("nextDrivingSourceIntervalId"),
|
||||||
|
(String) event.get("previousRegistrationKey"),
|
||||||
|
(String) event.get("nextRegistrationKey"),
|
||||||
|
(String) event.get("previousVehicleKey"),
|
||||||
|
(String) event.get("nextVehicleKey")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private List<String> castSourceIntervalIds(Object value) {
|
private List<String> castSourceIntervalIds(Object value) {
|
||||||
return value == null ? List.of() : List.copyOf((List<String>) value);
|
return value == null ? List.of() : List.copyOf((List<String>) value);
|
||||||
|
|
@ -799,4 +1001,12 @@ public class DriverTimelineBuilder {
|
||||||
Long.toString(thresholdSeconds)
|
Long.toString(thresholdSeconds)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String renderPotentialHomeOvernightStayIntervalEventsEpl(int minimumRestPeriodMinutes) {
|
||||||
|
long thresholdSeconds = Math.max(1, minimumRestPeriodMinutes) * 60L;
|
||||||
|
return POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE.replace(
|
||||||
|
"${POTENTIAL_HOME_OVERNIGHT_STAY_THRESHOLD_SECONDS}",
|
||||||
|
Long.toString(thresholdSeconds)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||||
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
@ -132,7 +133,7 @@ public class TachographFileSessionProcessingService {
|
||||||
TachographEsperEventsProcessingRequest request
|
TachographEsperEventsProcessingRequest request
|
||||||
) {
|
) {
|
||||||
TachographEsperEventsProcessingRequest effectiveRequest = request == null
|
TachographEsperEventsProcessingRequest effectiveRequest = request == null
|
||||||
? new TachographEsperEventsProcessingRequest(null, null, null)
|
? new TachographEsperEventsProcessingRequest(null, null, null, null)
|
||||||
: request;
|
: request;
|
||||||
TachographFileSession session = repository.find(sessionId)
|
TachographFileSession session = repository.find(sessionId)
|
||||||
.orElseThrow(() -> new TachographFileSessionNotFoundException(sessionId));
|
.orElseThrow(() -> new TachographFileSessionNotFoundException(sessionId));
|
||||||
|
|
@ -148,6 +149,7 @@ public class TachographFileSessionProcessingService {
|
||||||
throw new IllegalArgumentException("occurredTo must not be before occurredFrom.");
|
throw new IllegalArgumentException("occurredTo must not be before occurredFrom.");
|
||||||
}
|
}
|
||||||
int significantDrivingMinutes = resolveEsperSignificantDrivingMinutes(effectiveRequest);
|
int significantDrivingMinutes = resolveEsperSignificantDrivingMinutes(effectiveRequest);
|
||||||
|
int minimumRestPeriodMinutes = resolveMinimumRestPeriodMinutes(effectiveRequest);
|
||||||
|
|
||||||
List<TachographEsperActivityIntervalEvent> activityIntervals = clipEsperActivityIntervalEvents(
|
List<TachographEsperActivityIntervalEvent> activityIntervals = clipEsperActivityIntervalEvents(
|
||||||
driverTimelineBuilder.buildEsperActivityIntervalEvents(sessionId, driverKey, timeline),
|
driverTimelineBuilder.buildEsperActivityIntervalEvents(sessionId, driverKey, timeline),
|
||||||
|
|
@ -159,24 +161,47 @@ public class TachographFileSessionProcessingService {
|
||||||
requestedFrom,
|
requestedFrom,
|
||||||
requestedTo
|
requestedTo
|
||||||
);
|
);
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> rawDrivingInterruptionIntervals =
|
||||||
|
driverTimelineBuilder.buildEsperDrivingInterruptionIntervalEvents(
|
||||||
|
sessionId,
|
||||||
|
driverKey,
|
||||||
|
timeline,
|
||||||
|
significantDrivingMinutes
|
||||||
|
);
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals =
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals =
|
||||||
clipEsperDrivingInterruptionIntervalEvents(
|
clipEsperDrivingInterruptionIntervalEvents(
|
||||||
driverTimelineBuilder.buildEsperDrivingInterruptionIntervalEvents(
|
rawDrivingInterruptionIntervals,
|
||||||
sessionId,
|
requestedFrom,
|
||||||
driverKey,
|
requestedTo
|
||||||
timeline,
|
);
|
||||||
significantDrivingMinutes
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals =
|
||||||
|
clipEsperDrivingInterruptionIntervalEvents(
|
||||||
|
driverTimelineBuilder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents(
|
||||||
|
rawDrivingInterruptionIntervals
|
||||||
),
|
),
|
||||||
requestedFrom,
|
requestedFrom,
|
||||||
requestedTo
|
requestedTo
|
||||||
);
|
);
|
||||||
|
List<TachographEsperVuCardAbsentIntervalEvent> rawVuCardAbsentIntervals =
|
||||||
|
driverTimelineBuilder.buildEsperVuCardAbsentIntervalEvents(timeline);
|
||||||
|
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals =
|
||||||
|
clipEsperPotentialHomeOvernightStayIntervalEvents(
|
||||||
|
driverTimelineBuilder.buildEsperPotentialHomeOvernightStayIntervalEvents(
|
||||||
|
rawDrivingInterruptionIntervals,
|
||||||
|
rawVuCardAbsentIntervals,
|
||||||
|
minimumRestPeriodMinutes
|
||||||
|
),
|
||||||
|
rawVuCardAbsentIntervals,
|
||||||
|
requestedFrom,
|
||||||
|
requestedTo
|
||||||
|
);
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals = clipEsperVehicleUsageIntervalEvents(
|
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals = clipEsperVehicleUsageIntervalEvents(
|
||||||
driverTimelineBuilder.buildEsperVehicleUsageIntervalEvents(timeline),
|
driverTimelineBuilder.buildEsperVehicleUsageIntervalEvents(timeline),
|
||||||
requestedFrom,
|
requestedFrom,
|
||||||
requestedTo
|
requestedTo
|
||||||
);
|
);
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals = clipEsperVuCardAbsentIntervalEvents(
|
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals = clipEsperVuCardAbsentIntervalEvents(
|
||||||
driverTimelineBuilder.buildEsperVuCardAbsentIntervalEvents(timeline),
|
rawVuCardAbsentIntervals,
|
||||||
requestedFrom,
|
requestedFrom,
|
||||||
requestedTo
|
requestedTo
|
||||||
);
|
);
|
||||||
|
|
@ -192,11 +217,15 @@ public class TachographFileSessionProcessingService {
|
||||||
activityIntervals.size(),
|
activityIntervals.size(),
|
||||||
drivingIntervals.size(),
|
drivingIntervals.size(),
|
||||||
drivingInterruptionIntervals.size(),
|
drivingInterruptionIntervals.size(),
|
||||||
|
drivingInterruptionVehicleChangeIntervals.size(),
|
||||||
|
potentialHomeOvernightStayIntervals.size(),
|
||||||
vehicleUsageIntervals.size(),
|
vehicleUsageIntervals.size(),
|
||||||
vuCardAbsentIntervals.size(),
|
vuCardAbsentIntervals.size(),
|
||||||
activityIntervals,
|
activityIntervals,
|
||||||
drivingIntervals,
|
drivingIntervals,
|
||||||
drivingInterruptionIntervals,
|
drivingInterruptionIntervals,
|
||||||
|
drivingInterruptionVehicleChangeIntervals,
|
||||||
|
potentialHomeOvernightStayIntervals,
|
||||||
vehicleUsageIntervals,
|
vehicleUsageIntervals,
|
||||||
vuCardAbsentIntervals,
|
vuCardAbsentIntervals,
|
||||||
esperProjectionNotes()
|
esperProjectionNotes()
|
||||||
|
|
@ -310,6 +339,8 @@ public class TachographFileSessionProcessingService {
|
||||||
Duration.between(start, end).getSeconds(),
|
Duration.between(start, end).getSeconds(),
|
||||||
interval.previousDrivingSourceIntervalId(),
|
interval.previousDrivingSourceIntervalId(),
|
||||||
interval.nextDrivingSourceIntervalId(),
|
interval.nextDrivingSourceIntervalId(),
|
||||||
|
interval.previousRegistrationKey(),
|
||||||
|
interval.nextRegistrationKey(),
|
||||||
interval.previousVehicleKey(),
|
interval.previousVehicleKey(),
|
||||||
interval.nextVehicleKey()
|
interval.nextVehicleKey()
|
||||||
);
|
);
|
||||||
|
|
@ -355,6 +386,49 @@ public class TachographFileSessionProcessingService {
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<ResolvedActivityInterval> synthesizeUnknownGaps(
|
private List<ResolvedActivityInterval> synthesizeUnknownGaps(
|
||||||
List<ResolvedActivityInterval> knownIntervals,
|
List<ResolvedActivityInterval> knownIntervals,
|
||||||
Duration gapDetectionTolerance
|
Duration gapDetectionTolerance
|
||||||
|
|
@ -899,6 +973,12 @@ public class TachographFileSessionProcessingService {
|
||||||
: request.significantDrivingMinutes();
|
: request.significantDrivingMinutes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int resolveMinimumRestPeriodMinutes(TachographEsperEventsProcessingRequest request) {
|
||||||
|
return request.minimumRestPeriodMinutes() == null
|
||||||
|
? properties.getTachographFileSession().getProcessing().getMinimumRestPeriodMinutes()
|
||||||
|
: request.minimumRestPeriodMinutes();
|
||||||
|
}
|
||||||
|
|
||||||
private List<String> notes() {
|
private List<String> notes() {
|
||||||
return List.of(
|
return List.of(
|
||||||
"This endpoint evaluates operating periods from the in-memory tachograph file-session model.",
|
"This endpoint evaluates operating periods from the in-memory tachograph file-session model.",
|
||||||
|
|
@ -913,12 +993,37 @@ 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.",
|
||||||
|
"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.",
|
||||||
"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."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long overlapSeconds(
|
||||||
|
OffsetDateTime intervalStart,
|
||||||
|
OffsetDateTime intervalEnd,
|
||||||
|
List<TachographEsperVuCardAbsentIntervalEvent> unknownIntervals,
|
||||||
|
String driverKey
|
||||||
|
) {
|
||||||
|
if (unknownIntervals == null || unknownIntervals.isEmpty()) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
long total = 0L;
|
||||||
|
for (TachographEsperVuCardAbsentIntervalEvent unknown : unknownIntervals) {
|
||||||
|
if (!Objects.equals(driverKey, unknown.driverKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
OffsetDateTime overlapStart = max(intervalStart, unknown.startedAt());
|
||||||
|
OffsetDateTime overlapEnd = min(intervalEnd, unknown.endedAt());
|
||||||
|
if (overlapEnd.isAfter(overlapStart)) {
|
||||||
|
total += Duration.between(overlapStart, overlapEnd).getSeconds();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
private OffsetDateTime utc(OffsetDateTime value) {
|
private OffsetDateTime utc(OffsetDateTime value) {
|
||||||
return value == null ? null : value.withOffsetSameInstant(java.time.ZoneOffset.UTC);
|
return value == null ? null : value.withOffsetSameInstant(java.time.ZoneOffset.UTC);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ create schema SignificantDrivingInterval(
|
||||||
startedAtEpochSecond long,
|
startedAtEpochSecond long,
|
||||||
endedAtEpochSecond long,
|
endedAtEpochSecond long,
|
||||||
durationSeconds long,
|
durationSeconds long,
|
||||||
|
registrationKey string,
|
||||||
vehicleKey string
|
vehicleKey string
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -17,6 +18,8 @@ create schema DrivingInterruptionInterval(
|
||||||
durationSeconds long,
|
durationSeconds long,
|
||||||
previousDrivingSourceIntervalId string,
|
previousDrivingSourceIntervalId string,
|
||||||
nextDrivingSourceIntervalId string,
|
nextDrivingSourceIntervalId string,
|
||||||
|
previousRegistrationKey string,
|
||||||
|
nextRegistrationKey string,
|
||||||
previousVehicleKey string,
|
previousVehicleKey string,
|
||||||
nextVehicleKey string
|
nextVehicleKey string
|
||||||
);
|
);
|
||||||
|
|
@ -30,6 +33,7 @@ select
|
||||||
startedAtEpochSecond,
|
startedAtEpochSecond,
|
||||||
endedAtEpochSecond,
|
endedAtEpochSecond,
|
||||||
durationSeconds,
|
durationSeconds,
|
||||||
|
registrationKey,
|
||||||
vehicleKey
|
vehicleKey
|
||||||
from TachographActivityIntervalInputEvent(activityType = 'DRIVE', durationSeconds > ${SIGNIFICANT_DRIVING_THRESHOLD_SECONDS});
|
from TachographActivityIntervalInputEvent(activityType = 'DRIVE', durationSeconds > ${SIGNIFICANT_DRIVING_THRESHOLD_SECONDS});
|
||||||
|
|
||||||
|
|
@ -45,6 +49,8 @@ select
|
||||||
next.startedAtEpochSecond - priorInterval.endedAtEpochSecond as durationSeconds,
|
next.startedAtEpochSecond - priorInterval.endedAtEpochSecond as durationSeconds,
|
||||||
priorInterval.lastSourceIntervalId as previousDrivingSourceIntervalId,
|
priorInterval.lastSourceIntervalId as previousDrivingSourceIntervalId,
|
||||||
next.firstSourceIntervalId as nextDrivingSourceIntervalId,
|
next.firstSourceIntervalId as nextDrivingSourceIntervalId,
|
||||||
|
priorInterval.registrationKey as previousRegistrationKey,
|
||||||
|
next.registrationKey as nextRegistrationKey,
|
||||||
priorInterval.vehicleKey as previousVehicleKey,
|
priorInterval.vehicleKey as previousVehicleKey,
|
||||||
next.vehicleKey as nextVehicleKey
|
next.vehicleKey as nextVehicleKey
|
||||||
from PreviousSignificantDrivingInterval as priorInterval
|
from PreviousSignificantDrivingInterval as priorInterval
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
@name('drivingInterruptionVehicleChangeIntervals')
|
||||||
|
select
|
||||||
|
sessionId,
|
||||||
|
driverKey,
|
||||||
|
startedAt,
|
||||||
|
endedAt,
|
||||||
|
durationSeconds,
|
||||||
|
previousDrivingSourceIntervalId,
|
||||||
|
nextDrivingSourceIntervalId,
|
||||||
|
previousRegistrationKey,
|
||||||
|
nextRegistrationKey,
|
||||||
|
previousVehicleKey,
|
||||||
|
nextVehicleKey
|
||||||
|
from TachographDrivingInterruptionIntervalInputEvent(
|
||||||
|
previousRegistrationKey is not null,
|
||||||
|
nextRegistrationKey is not null,
|
||||||
|
previousRegistrationKey != nextRegistrationKey
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,65 @@
|
||||||
|
@name('potentialHomeOvernightStayIntervals')
|
||||||
|
select
|
||||||
|
d.sessionId as sessionId,
|
||||||
|
d.driverKey as driverKey,
|
||||||
|
d.startedAt as startedAt,
|
||||||
|
d.endedAt as endedAt,
|
||||||
|
d.durationSeconds as durationSeconds,
|
||||||
|
sum(
|
||||||
|
case
|
||||||
|
when u.startedAtEpochSecond <= d.startedAtEpochSecond and u.endedAtEpochSecond >= d.endedAtEpochSecond
|
||||||
|
then d.durationSeconds
|
||||||
|
when u.startedAtEpochSecond <= d.startedAtEpochSecond
|
||||||
|
then u.endedAtEpochSecond - d.startedAtEpochSecond
|
||||||
|
when u.endedAtEpochSecond >= d.endedAtEpochSecond
|
||||||
|
then d.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
|
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
|
end
|
||||||
|
) as unknownDurationSeconds,
|
||||||
|
(sum(
|
||||||
|
case
|
||||||
|
when u.startedAtEpochSecond <= d.startedAtEpochSecond and u.endedAtEpochSecond >= d.endedAtEpochSecond
|
||||||
|
then d.durationSeconds
|
||||||
|
when u.startedAtEpochSecond <= d.startedAtEpochSecond
|
||||||
|
then u.endedAtEpochSecond - d.startedAtEpochSecond
|
||||||
|
when u.endedAtEpochSecond >= d.endedAtEpochSecond
|
||||||
|
then d.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
|
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
|
end
|
||||||
|
) * 100.0d) / d.durationSeconds as unknownCoveragePercent,
|
||||||
|
d.previousDrivingSourceIntervalId as previousDrivingSourceIntervalId,
|
||||||
|
d.nextDrivingSourceIntervalId as nextDrivingSourceIntervalId,
|
||||||
|
d.previousRegistrationKey as previousRegistrationKey,
|
||||||
|
d.nextRegistrationKey as nextRegistrationKey,
|
||||||
|
d.previousVehicleKey as previousVehicleKey,
|
||||||
|
d.nextVehicleKey as nextVehicleKey
|
||||||
|
from TachographDrivingInterruptionIntervalInputEvent(durationSeconds > ${POTENTIAL_HOME_OVERNIGHT_STAY_THRESHOLD_SECONDS}) as d unidirectional,
|
||||||
|
TachographVuCardAbsentIntervalInputEvent#keepall as u
|
||||||
|
where u.driverKey = d.driverKey
|
||||||
|
and u.startedAtEpochSecond < d.endedAtEpochSecond
|
||||||
|
and u.endedAtEpochSecond > d.startedAtEpochSecond
|
||||||
|
group by
|
||||||
|
d.sessionId,
|
||||||
|
d.driverKey,
|
||||||
|
d.startedAt,
|
||||||
|
d.endedAt,
|
||||||
|
d.startedAtEpochSecond,
|
||||||
|
d.endedAtEpochSecond,
|
||||||
|
d.durationSeconds,
|
||||||
|
d.previousDrivingSourceIntervalId,
|
||||||
|
d.nextDrivingSourceIntervalId,
|
||||||
|
d.previousRegistrationKey,
|
||||||
|
d.nextRegistrationKey,
|
||||||
|
d.previousVehicleKey,
|
||||||
|
d.nextVehicleKey
|
||||||
|
having sum(
|
||||||
|
case
|
||||||
|
when u.startedAtEpochSecond <= d.startedAtEpochSecond and u.endedAtEpochSecond >= d.endedAtEpochSecond
|
||||||
|
then d.durationSeconds
|
||||||
|
when u.startedAtEpochSecond <= d.startedAtEpochSecond
|
||||||
|
then u.endedAtEpochSecond - d.startedAtEpochSecond
|
||||||
|
when u.endedAtEpochSecond >= d.endedAtEpochSecond
|
||||||
|
then d.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
|
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
||||||
|
end
|
||||||
|
) * 100L >= d.durationSeconds * 95L;
|
||||||
|
|
@ -21,6 +21,7 @@ import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionSummary
|
||||||
import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
|
import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
||||||
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionProcessingService;
|
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionProcessingService;
|
||||||
|
|
@ -81,6 +82,8 @@ class TachographFileSessionControllerTest {
|
||||||
2,
|
2,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
2,
|
2,
|
||||||
1,
|
1,
|
||||||
List.of(new TachographEsperActivityIntervalEvent(
|
List.of(new TachographEsperActivityIntervalEvent(
|
||||||
|
|
@ -129,6 +132,36 @@ class TachographFileSessionControllerTest {
|
||||||
1800L,
|
1800L,
|
||||||
"ACT-2",
|
"ACT-2",
|
||||||
"ACT-3",
|
"ACT-3",
|
||||||
|
"12:REG-1",
|
||||||
|
"12:REG-2",
|
||||||
|
"VIN-1",
|
||||||
|
"VIN-2"
|
||||||
|
)),
|
||||||
|
List.of(new TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
|
sessionId,
|
||||||
|
"12:123",
|
||||||
|
OffsetDateTime.parse("2026-05-12T10:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-12T10:30:00Z"),
|
||||||
|
1800L,
|
||||||
|
"ACT-2",
|
||||||
|
"ACT-3",
|
||||||
|
"12:REG-1",
|
||||||
|
"12:REG-2",
|
||||||
|
"VIN-1",
|
||||||
|
"VIN-2"
|
||||||
|
)),
|
||||||
|
List.of(new TachographEsperPotentialHomeOvernightStayIntervalEvent(
|
||||||
|
sessionId,
|
||||||
|
"12:123",
|
||||||
|
OffsetDateTime.parse("2026-05-12T10:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-12T22:00:00Z"),
|
||||||
|
43_200L,
|
||||||
|
43_200L,
|
||||||
|
100.0d,
|
||||||
|
"ACT-2",
|
||||||
|
"ACT-3",
|
||||||
|
"12:REG-1",
|
||||||
|
"12:REG-2",
|
||||||
"VIN-1",
|
"VIN-1",
|
||||||
"VIN-2"
|
"VIN-2"
|
||||||
)),
|
)),
|
||||||
|
|
@ -213,7 +246,8 @@ class TachographFileSessionControllerTest {
|
||||||
{
|
{
|
||||||
"occurredFrom": "2026-05-12T08:30:00Z",
|
"occurredFrom": "2026-05-12T08:30:00Z",
|
||||||
"occurredTo": "2026-05-12T11:30:00Z",
|
"occurredTo": "2026-05-12T11:30:00Z",
|
||||||
"significantDrivingMinutes": 3
|
"significantDrivingMinutes": 3,
|
||||||
|
"minimumRestPeriodMinutes": 720
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
|
|
@ -223,9 +257,17 @@ class TachographFileSessionControllerTest {
|
||||||
.andExpect(jsonPath("$.requestedTo").value("2026-05-12T11:30:00Z"))
|
.andExpect(jsonPath("$.requestedTo").value("2026-05-12T11:30:00Z"))
|
||||||
.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("$.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].nextRegistrationKey").value("12:REG-2"))
|
||||||
.andExpect(jsonPath("$.drivingInterruptionIntervals[0].previousVehicleKey").value("VIN-1"))
|
.andExpect(jsonPath("$.drivingInterruptionIntervals[0].previousVehicleKey").value("VIN-1"))
|
||||||
.andExpect(jsonPath("$.drivingInterruptionIntervals[0].nextVehicleKey").value("VIN-2"))
|
.andExpect(jsonPath("$.drivingInterruptionIntervals[0].nextVehicleKey").value("VIN-2"))
|
||||||
|
.andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervals[0].previousRegistrationKey").value("12:REG-1"))
|
||||||
|
.andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervals[0].nextRegistrationKey").value("12:REG-2"))
|
||||||
|
.andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervals[0].previousVehicleKey").value("VIN-1"))
|
||||||
|
.andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervals[0].nextVehicleKey").value("VIN-2"))
|
||||||
.andExpect(jsonPath("$.drivingIntervals[0].activityType").value("DRIVE"));
|
.andExpect(jsonPath("$.drivingIntervals[0].activityType").value("DRIVE"));
|
||||||
|
|
||||||
mockMvc.perform(post("/api/eventhub/tachograph-file-sessions/{sessionId}/drivers/{driverKey}/processing/operating-periods", sessionId, "12:123")
|
mockMvc.perform(post("/api/eventhub/tachograph-file-sessions/{sessionId}/drivers/{driverKey}/processing/operating-periods", sessionId, "12:123")
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
|
||||||
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
|
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperDrivingInterruptionIntervalEvent;
|
||||||
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||||
|
|
@ -448,7 +449,72 @@ class DriverTimelineBuilderTest {
|
||||||
assertThat(interruptions.get(0).durationSeconds()).isEqualTo(480L);
|
assertThat(interruptions.get(0).durationSeconds()).isEqualTo(480L);
|
||||||
assertThat(interruptions.get(0).previousDrivingSourceIntervalId()).isEqualTo("ACT-1");
|
assertThat(interruptions.get(0).previousDrivingSourceIntervalId()).isEqualTo("ACT-1");
|
||||||
assertThat(interruptions.get(0).nextDrivingSourceIntervalId()).isEqualTo("ACT-3");
|
assertThat(interruptions.get(0).nextDrivingSourceIntervalId()).isEqualTo("ACT-3");
|
||||||
|
assertThat(interruptions.get(0).previousRegistrationKey()).isEqualTo("12:REG-1");
|
||||||
|
assertThat(interruptions.get(0).nextRegistrationKey()).isEqualTo("12:REG-2");
|
||||||
assertThat(interruptions.get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
assertThat(interruptions.get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
||||||
assertThat(interruptions.get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
assertThat(interruptions.get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
||||||
|
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> vehicleChangeInterruptions =
|
||||||
|
builder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents(interruptions);
|
||||||
|
|
||||||
|
assertThat(vehicleChangeInterruptions).hasSize(1);
|
||||||
|
assertThat(vehicleChangeInterruptions.get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T08:02:00Z"));
|
||||||
|
assertThat(vehicleChangeInterruptions.get(0).previousRegistrationKey()).isEqualTo("12:REG-1");
|
||||||
|
assertThat(vehicleChangeInterruptions.get(0).nextRegistrationKey()).isEqualTo("12:REG-2");
|
||||||
|
assertThat(vehicleChangeInterruptions.get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
||||||
|
assertThat(vehicleChangeInterruptions.get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildsPotentialHomeOvernightStayIntervalsFromDtiAndVuCardAbsentOverlap() {
|
||||||
|
UUID sessionId = UUID.randomUUID();
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> interruptions = List.of(
|
||||||
|
new TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
|
sessionId,
|
||||||
|
"12:123",
|
||||||
|
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-02T00:00:00Z"),
|
||||||
|
50_400L,
|
||||||
|
"ACT-1",
|
||||||
|
"ACT-2",
|
||||||
|
"12:REG-1",
|
||||||
|
"12:REG-1",
|
||||||
|
"VIN-1",
|
||||||
|
"VIN-1"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals = List.of(
|
||||||
|
new TachographEsperVuCardAbsentIntervalEvent(
|
||||||
|
sessionId,
|
||||||
|
"12:123",
|
||||||
|
OffsetDateTime.parse("2026-05-01T10:00:01Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-02T00:00:00Z"),
|
||||||
|
50_399L,
|
||||||
|
"CVU-1",
|
||||||
|
"CVU-2",
|
||||||
|
"12:REG-1",
|
||||||
|
"12:REG-1",
|
||||||
|
"VIN-1",
|
||||||
|
"VIN-1"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> intervals =
|
||||||
|
builder.buildEsperPotentialHomeOvernightStayIntervalEvents(
|
||||||
|
interruptions,
|
||||||
|
vuCardAbsentIntervals,
|
||||||
|
720
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat(intervals).hasSize(1);
|
||||||
|
assertThat(intervals.get(0).sessionId()).isEqualTo(sessionId);
|
||||||
|
assertThat(intervals.get(0).driverKey()).isEqualTo("12:123");
|
||||||
|
assertThat(intervals.get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T10:00:00Z"));
|
||||||
|
assertThat(intervals.get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-02T00:00:00Z"));
|
||||||
|
assertThat(intervals.get(0).durationSeconds()).isEqualTo(50_400L);
|
||||||
|
assertThat(intervals.get(0).unknownDurationSeconds()).isEqualTo(50_399L);
|
||||||
|
assertThat(intervals.get(0).unknownCoveragePercent()).isGreaterThan(99.9d);
|
||||||
|
assertThat(intervals.get(0).previousDrivingSourceIntervalId()).isEqualTo("ACT-1");
|
||||||
|
assertThat(intervals.get(0).nextDrivingSourceIntervalId()).isEqualTo("ACT-2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,8 @@ class TachographFileSessionProcessingServiceTest {
|
||||||
assertThat(result.activityIntervalCount()).isEqualTo(2);
|
assertThat(result.activityIntervalCount()).isEqualTo(2);
|
||||||
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.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
||||||
assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2);
|
assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2);
|
||||||
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
||||||
assertThat(result.vuCardAbsentIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:01Z"));
|
assertThat(result.vuCardAbsentIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:01Z"));
|
||||||
|
|
@ -155,7 +157,8 @@ class TachographFileSessionProcessingServiceTest {
|
||||||
new TachographEsperEventsProcessingRequest(
|
new TachographEsperEventsProcessingRequest(
|
||||||
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
||||||
OffsetDateTime.parse("2026-05-01T12:30:00Z"),
|
OffsetDateTime.parse("2026-05-01T12:30:00Z"),
|
||||||
3
|
3,
|
||||||
|
720
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -166,10 +169,19 @@ 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.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"));
|
||||||
|
assertThat(result.drivingInterruptionIntervals().get(0).previousRegistrationKey()).isEqualTo("12:REG-1");
|
||||||
|
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();
|
||||||
|
|
@ -178,6 +190,80 @@ class TachographFileSessionProcessingServiceTest {
|
||||||
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void returnsPotentialHomeOvernightStayIntervalsWhenVuCardAbsentCoversLongDti() {
|
||||||
|
EventHubProperties properties = new EventHubProperties();
|
||||||
|
TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
|
||||||
|
TachographFileSessionProcessingService service = new TachographFileSessionProcessingService(
|
||||||
|
repository,
|
||||||
|
new DriverTimelineBuilder(),
|
||||||
|
properties
|
||||||
|
);
|
||||||
|
|
||||||
|
DriverExtractionSession driver = new DriverExtractionSession(
|
||||||
|
"12:123",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
List.of(),
|
||||||
|
List.of(),
|
||||||
|
List.of(
|
||||||
|
new ExtractedCardVehicleUsageInterval(
|
||||||
|
"CVU-1",
|
||||||
|
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||||
|
100L,
|
||||||
|
200L,
|
||||||
|
"12:REG-1",
|
||||||
|
"VIN-1",
|
||||||
|
"vu-1"
|
||||||
|
),
|
||||||
|
new ExtractedCardVehicleUsageInterval(
|
||||||
|
"CVU-2",
|
||||||
|
OffsetDateTime.parse("2026-05-02T00:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-02T02:00:00Z"),
|
||||||
|
201L,
|
||||||
|
260L,
|
||||||
|
"12:REG-1",
|
||||||
|
"VIN-1",
|
||||||
|
"vu-2"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
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-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")
|
||||||
|
),
|
||||||
|
List.of(),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
TachographFileSession session = new TachographFileSession(
|
||||||
|
UUID.randomUUID(),
|
||||||
|
new TachographFileSessionMetadata("default", "legalrequirements-drivercard", "sample", "sample.ddd", "a", 2, "42", "b", true, null),
|
||||||
|
Map.of(driver.driverKey(), driver),
|
||||||
|
new ExtractionStats(1, 2, 2, 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-01T11:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-01T23:00:00Z"),
|
||||||
|
3,
|
||||||
|
720
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(1);
|
||||||
|
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).unknownDurationSeconds()).isEqualTo(43_200L);
|
||||||
|
assertThat(result.potentialHomeOvernightStayIntervals().get(0).unknownCoveragePercent()).isEqualTo(100.0d);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void evaluatesOperatingPeriodsFromSessionTimeline() {
|
void evaluatesOperatingPeriodsFromSessionTimeline() {
|
||||||
EventHubProperties properties = new EventHubProperties();
|
EventHubProperties properties = new EventHubProperties();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue