Add esper driving interruption projections
This commit is contained in:
parent
0e2b83270c
commit
eb4e04f144
|
|
@ -374,6 +374,38 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Process tachograph file session Esper events",
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [
|
||||||
|
{
|
||||||
|
"key": "Content-Type",
|
||||||
|
"value": "application/json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"occurredFrom\": \"{{occurredFrom}}\",\n \"occurredTo\": \"{{occurredTo}}\",\n \"significantDrivingMinutes\": 3\n}"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "{{baseUrl}}/api/eventhub/tachograph-file-sessions/{{sessionId}}/drivers/{{driverKey}}/processing/esper-events",
|
||||||
|
"host": [
|
||||||
|
"{{baseUrl}}"
|
||||||
|
],
|
||||||
|
"path": [
|
||||||
|
"api",
|
||||||
|
"eventhub",
|
||||||
|
"tachograph-file-sessions",
|
||||||
|
"{{sessionId}}",
|
||||||
|
"drivers",
|
||||||
|
"{{driverKey}}",
|
||||||
|
"processing",
|
||||||
|
"esper-events"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Process tachograph file session operating periods",
|
"name": "Process tachograph file session operating periods",
|
||||||
"request": {
|
"request": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package at.procon.eventhub.tachographfilesession.api;
|
package at.procon.eventhub.tachographfilesession.api;
|
||||||
|
|
||||||
import at.procon.eventhub.tachographfilesession.dto.CreateTachographFileSessionResponse;
|
import at.procon.eventhub.tachographfilesession.dto.CreateTachographFileSessionResponse;
|
||||||
|
import at.procon.eventhub.tachographfilesession.dto.TachographEsperEventsProcessingRequest;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverDetailDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverDetailDto;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
||||||
|
|
@ -75,6 +76,15 @@ public class TachographFileSessionController {
|
||||||
return ResponseEntity.ok(processingService.getEsperDriverProcessingResults(sessionId, driverKey));
|
return ResponseEntity.ok(processingService.getEsperDriverProcessingResults(sessionId, driverKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/{sessionId}/drivers/{driverKey}/processing/esper-events")
|
||||||
|
public ResponseEntity<TachographEsperDriverProcessingResultDto> evaluateEsperDriverProcessingResults(
|
||||||
|
@PathVariable UUID sessionId,
|
||||||
|
@PathVariable String driverKey,
|
||||||
|
@RequestBody(required = false) TachographEsperEventsProcessingRequest request
|
||||||
|
) {
|
||||||
|
return ResponseEntity.ok(processingService.getEsperDriverProcessingResults(sessionId, driverKey, request));
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/{sessionId}/drivers/{driverKey}/processing/operating-periods")
|
@PostMapping("/{sessionId}/drivers/{driverKey}/processing/operating-periods")
|
||||||
public ResponseEntity<TachographOperatingPeriodsProcessingResultDto> evaluateOperatingPeriods(
|
public ResponseEntity<TachographOperatingPeriodsProcessingResultDto> evaluateOperatingPeriods(
|
||||||
@PathVariable UUID sessionId,
|
@PathVariable UUID sessionId,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package at.procon.eventhub.tachographfilesession.dto;
|
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.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;
|
||||||
|
|
@ -13,12 +14,16 @@ public record TachographEsperDriverProcessingResultDto(
|
||||||
String sourceKind,
|
String sourceKind,
|
||||||
OffsetDateTime loadedFrom,
|
OffsetDateTime loadedFrom,
|
||||||
OffsetDateTime loadedTo,
|
OffsetDateTime loadedTo,
|
||||||
|
OffsetDateTime requestedFrom,
|
||||||
|
OffsetDateTime requestedTo,
|
||||||
int activityIntervalCount,
|
int activityIntervalCount,
|
||||||
int drivingIntervalCount,
|
int drivingIntervalCount,
|
||||||
|
int drivingInterruptionIntervalCount,
|
||||||
int vehicleUsageIntervalCount,
|
int vehicleUsageIntervalCount,
|
||||||
int vuCardAbsentIntervalCount,
|
int vuCardAbsentIntervalCount,
|
||||||
List<TachographEsperActivityIntervalEvent> activityIntervals,
|
List<TachographEsperActivityIntervalEvent> activityIntervals,
|
||||||
List<TachographEsperActivityIntervalEvent> drivingIntervals,
|
List<TachographEsperActivityIntervalEvent> drivingIntervals,
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals,
|
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals,
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
||||||
List<String> notes
|
List<String> notes
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package at.procon.eventhub.tachographfilesession.dto;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
|
public record TachographEsperEventsProcessingRequest(
|
||||||
|
OffsetDateTime occurredFrom,
|
||||||
|
OffsetDateTime occurredTo,
|
||||||
|
Integer significantDrivingMinutes
|
||||||
|
) {
|
||||||
|
public TachographEsperEventsProcessingRequest {
|
||||||
|
significantDrivingMinutes = significantDrivingMinutes == null ? null : Math.max(1, significantDrivingMinutes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package at.procon.eventhub.tachographfilesession.model;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
|
UUID sessionId,
|
||||||
|
String driverKey,
|
||||||
|
OffsetDateTime startedAt,
|
||||||
|
OffsetDateTime endedAt,
|
||||||
|
long durationSeconds,
|
||||||
|
String previousDrivingSourceIntervalId,
|
||||||
|
String nextDrivingSourceIntervalId,
|
||||||
|
String previousVehicleKey,
|
||||||
|
String nextVehicleKey
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
@ -19,12 +19,15 @@ import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
|
||||||
import at.procon.eventhub.tachographfilesession.model.ResolvedDriverTimeline;
|
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.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;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
|
@ -47,6 +50,8 @@ public class DriverTimelineBuilder {
|
||||||
loadResource("esper/tachograph-activity-interval-events.epl");
|
loadResource("esper/tachograph-activity-interval-events.epl");
|
||||||
private static final String DRIVING_INTERVAL_EVENTS_EPL =
|
private static final String DRIVING_INTERVAL_EVENTS_EPL =
|
||||||
loadResource("esper/tachograph-driving-interval-events.epl");
|
loadResource("esper/tachograph-driving-interval-events.epl");
|
||||||
|
private static final String DRIVING_INTERRUPTION_INTERVAL_EVENTS_EPL_TEMPLATE =
|
||||||
|
loadResource("esper/tachograph-driving-interruption-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 =
|
||||||
|
|
@ -139,6 +144,38 @@ public class DriverTimelineBuilder {
|
||||||
return timeline == null ? List.of() : buildEsperVehicleUsageIntervalEvents(timeline.vehicleUsageIntervals());
|
return timeline == null ? List.of() : buildEsperVehicleUsageIntervalEvents(timeline.vehicleUsageIntervals());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<TachographEsperDrivingInterruptionIntervalEvent> buildEsperDrivingInterruptionIntervalEvents(
|
||||||
|
TachographFileSession session,
|
||||||
|
DriverExtractionSession driverSession,
|
||||||
|
int significantDrivingMinutes
|
||||||
|
) {
|
||||||
|
String sourceKind = session.metadata().driverCardFile() ? "DRIVER_CARD" : "VEHICLE_UNIT";
|
||||||
|
List<ResolvedActivityInterval> activityIntervals = resolveActivities(driverSession.cardActivityIntervals(), sourceKind);
|
||||||
|
return buildEsperDrivingInterruptionIntervalEvents(
|
||||||
|
session.sessionId(),
|
||||||
|
driverSession.driverKey(),
|
||||||
|
activityIntervals,
|
||||||
|
significantDrivingMinutes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TachographEsperDrivingInterruptionIntervalEvent> buildEsperDrivingInterruptionIntervalEvents(
|
||||||
|
UUID sessionId,
|
||||||
|
String driverKey,
|
||||||
|
ResolvedDriverTimeline timeline,
|
||||||
|
int significantDrivingMinutes
|
||||||
|
) {
|
||||||
|
if (timeline == null) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return buildEsperDrivingInterruptionIntervalEvents(
|
||||||
|
sessionId,
|
||||||
|
driverKey,
|
||||||
|
timeline.activityIntervals(),
|
||||||
|
significantDrivingMinutes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public List<TachographEsperVuCardAbsentIntervalEvent> buildEsperVuCardAbsentIntervalEvents(
|
public List<TachographEsperVuCardAbsentIntervalEvent> buildEsperVuCardAbsentIntervalEvents(
|
||||||
TachographFileSession session,
|
TachographFileSession session,
|
||||||
DriverExtractionSession driverSession
|
DriverExtractionSession driverSession
|
||||||
|
|
@ -244,6 +281,36 @@ public class DriverTimelineBuilder {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<TachographEsperDrivingInterruptionIntervalEvent> buildEsperDrivingInterruptionIntervalEvents(
|
||||||
|
UUID sessionId,
|
||||||
|
String driverKey,
|
||||||
|
List<ResolvedActivityInterval> activityIntervals,
|
||||||
|
int significantDrivingMinutes
|
||||||
|
) {
|
||||||
|
if (activityIntervals == null || activityIntervals.size() < 2) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> result = new ArrayList<>();
|
||||||
|
executeWithRuntime(
|
||||||
|
configuration -> configuration.getCommon().addEventType(
|
||||||
|
"TachographActivityIntervalInputEvent",
|
||||||
|
activityIntervalInputDefinition()
|
||||||
|
),
|
||||||
|
renderDrivingInterruptionIntervalEventsEpl(significantDrivingMinutes),
|
||||||
|
"drivingInterruptionIntervals",
|
||||||
|
newData -> collectDrivingInterruptionIntervalEvents(newData, result),
|
||||||
|
runtime -> {
|
||||||
|
for (ResolvedActivityInterval interval : activityIntervals) {
|
||||||
|
runtime.getEventService().sendEventMap(
|
||||||
|
toActivityIntervalInputMap(sessionId, driverKey, interval),
|
||||||
|
"TachographActivityIntervalInputEvent"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private List<TachographEsperVuCardAbsentIntervalEvent> buildEsperVuCardAbsentIntervalEvents(
|
private List<TachographEsperVuCardAbsentIntervalEvent> buildEsperVuCardAbsentIntervalEvents(
|
||||||
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals
|
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals
|
||||||
) {
|
) {
|
||||||
|
|
@ -477,7 +544,10 @@ public class DriverTimelineBuilder {
|
||||||
|
|
||||||
sender.accept(runtime);
|
sender.accept(runtime);
|
||||||
} catch (EPCompileException | EPDeployException e) {
|
} catch (EPCompileException | EPDeployException e) {
|
||||||
throw new IllegalStateException("Cannot compile/deploy tachograph projection EPL", e);
|
throw new IllegalStateException(
|
||||||
|
"Cannot compile/deploy tachograph projection EPL for statement '" + statementName + "'",
|
||||||
|
e
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
if (runtime != null) {
|
if (runtime != null) {
|
||||||
runtime.destroy();
|
runtime.destroy();
|
||||||
|
|
@ -497,8 +567,12 @@ public class DriverTimelineBuilder {
|
||||||
definition.put("registrationKey", String.class);
|
definition.put("registrationKey", String.class);
|
||||||
definition.put("vehicleKey", String.class);
|
definition.put("vehicleKey", String.class);
|
||||||
definition.put("sourceKind", String.class);
|
definition.put("sourceKind", String.class);
|
||||||
|
definition.put("firstSourceIntervalId", String.class);
|
||||||
|
definition.put("lastSourceIntervalId", String.class);
|
||||||
definition.put("startedAt", OffsetDateTime.class);
|
definition.put("startedAt", OffsetDateTime.class);
|
||||||
definition.put("endedAt", OffsetDateTime.class);
|
definition.put("endedAt", OffsetDateTime.class);
|
||||||
|
definition.put("startedAtEpochSecond", long.class);
|
||||||
|
definition.put("endedAtEpochSecond", long.class);
|
||||||
definition.put("durationSeconds", long.class);
|
definition.put("durationSeconds", long.class);
|
||||||
definition.put("sourceIntervalIds", java.util.List.class);
|
definition.put("sourceIntervalIds", java.util.List.class);
|
||||||
definition.put("synthetic", boolean.class);
|
definition.put("synthetic", boolean.class);
|
||||||
|
|
@ -512,8 +586,12 @@ public class DriverTimelineBuilder {
|
||||||
definition.put("sessionId", UUID.class);
|
definition.put("sessionId", UUID.class);
|
||||||
definition.put("driverKey", String.class);
|
definition.put("driverKey", String.class);
|
||||||
definition.put("intervalId", String.class);
|
definition.put("intervalId", String.class);
|
||||||
|
definition.put("firstSourceIntervalId", String.class);
|
||||||
|
definition.put("lastSourceIntervalId", String.class);
|
||||||
definition.put("startedAt", OffsetDateTime.class);
|
definition.put("startedAt", OffsetDateTime.class);
|
||||||
definition.put("endedAt", OffsetDateTime.class);
|
definition.put("endedAt", OffsetDateTime.class);
|
||||||
|
definition.put("startedAtEpochSecond", long.class);
|
||||||
|
definition.put("endedAtEpochSecond", Long.class);
|
||||||
definition.put("durationSeconds", long.class);
|
definition.put("durationSeconds", long.class);
|
||||||
definition.put("odometerBeginKm", Long.class);
|
definition.put("odometerBeginKm", Long.class);
|
||||||
definition.put("odometerEndKm", Long.class);
|
definition.put("odometerEndKm", Long.class);
|
||||||
|
|
@ -540,8 +618,12 @@ public class DriverTimelineBuilder {
|
||||||
event.put("registrationKey", interval.registrationKey());
|
event.put("registrationKey", interval.registrationKey());
|
||||||
event.put("vehicleKey", interval.vehicleKey());
|
event.put("vehicleKey", interval.vehicleKey());
|
||||||
event.put("sourceKind", interval.sourceKind());
|
event.put("sourceKind", interval.sourceKind());
|
||||||
|
event.put("firstSourceIntervalId", firstSourceIntervalId(interval));
|
||||||
|
event.put("lastSourceIntervalId", lastSourceIntervalId(interval));
|
||||||
event.put("startedAt", interval.from());
|
event.put("startedAt", interval.from());
|
||||||
event.put("endedAt", interval.to());
|
event.put("endedAt", interval.to());
|
||||||
|
event.put("startedAtEpochSecond", interval.from().toEpochSecond());
|
||||||
|
event.put("endedAtEpochSecond", interval.to().toEpochSecond());
|
||||||
event.put("durationSeconds", interval.durationSeconds());
|
event.put("durationSeconds", interval.durationSeconds());
|
||||||
event.put("sourceIntervalIds", interval.sourceIntervalIds());
|
event.put("sourceIntervalIds", interval.sourceIntervalIds());
|
||||||
event.put("synthetic", interval.synthetic());
|
event.put("synthetic", interval.synthetic());
|
||||||
|
|
@ -550,13 +632,27 @@ public class DriverTimelineBuilder {
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String firstSourceIntervalId(ResolvedActivityInterval interval) {
|
||||||
|
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String lastSourceIntervalId(ResolvedActivityInterval interval) {
|
||||||
|
return interval.sourceIntervalIds().isEmpty()
|
||||||
|
? interval.intervalId()
|
||||||
|
: interval.sourceIntervalIds().get(interval.sourceIntervalIds().size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, Object> toVehicleUsageIntervalInputMap(ResolvedVehicleUsageInterval interval) {
|
private Map<String, Object> toVehicleUsageIntervalInputMap(ResolvedVehicleUsageInterval interval) {
|
||||||
Map<String, Object> event = new LinkedHashMap<>();
|
Map<String, Object> event = new LinkedHashMap<>();
|
||||||
event.put("sessionId", interval.sessionId());
|
event.put("sessionId", interval.sessionId());
|
||||||
event.put("driverKey", interval.driverKey());
|
event.put("driverKey", interval.driverKey());
|
||||||
event.put("intervalId", interval.intervalId());
|
event.put("intervalId", interval.intervalId());
|
||||||
|
event.put("firstSourceIntervalId", firstSourceIntervalId(interval));
|
||||||
|
event.put("lastSourceIntervalId", lastSourceIntervalId(interval));
|
||||||
event.put("startedAt", interval.from());
|
event.put("startedAt", interval.from());
|
||||||
event.put("endedAt", interval.to());
|
event.put("endedAt", interval.to());
|
||||||
|
event.put("startedAtEpochSecond", interval.from().toEpochSecond());
|
||||||
|
event.put("endedAtEpochSecond", interval.to() == null ? null : interval.to().toEpochSecond());
|
||||||
event.put("durationSeconds", interval.durationSeconds());
|
event.put("durationSeconds", interval.durationSeconds());
|
||||||
event.put("odometerBeginKm", interval.odometerBeginKm());
|
event.put("odometerBeginKm", interval.odometerBeginKm());
|
||||||
event.put("odometerEndKm", interval.odometerEndKm());
|
event.put("odometerEndKm", interval.odometerEndKm());
|
||||||
|
|
@ -567,6 +663,16 @@ public class DriverTimelineBuilder {
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String firstSourceIntervalId(ResolvedVehicleUsageInterval interval) {
|
||||||
|
return interval.sourceIntervalIds().isEmpty() ? interval.intervalId() : interval.sourceIntervalIds().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String lastSourceIntervalId(ResolvedVehicleUsageInterval interval) {
|
||||||
|
return interval.sourceIntervalIds().isEmpty()
|
||||||
|
? interval.intervalId()
|
||||||
|
: interval.sourceIntervalIds().get(interval.sourceIntervalIds().size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
private void collectActivityIntervalEvents(
|
private void collectActivityIntervalEvents(
|
||||||
EventBean[] newData,
|
EventBean[] newData,
|
||||||
List<TachographEsperActivityIntervalEvent> target
|
List<TachographEsperActivityIntervalEvent> target
|
||||||
|
|
@ -622,6 +728,30 @@ public class DriverTimelineBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void collectDrivingInterruptionIntervalEvents(
|
||||||
|
EventBean[] newData,
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> target
|
||||||
|
) {
|
||||||
|
if (newData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (EventBean event : newData) {
|
||||||
|
long startedAtEpochSecond = (Long) event.get("startedAtEpochSecond");
|
||||||
|
long endedAtEpochSecond = (Long) event.get("endedAtEpochSecond");
|
||||||
|
target.add(new TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
|
(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("previousDrivingSourceIntervalId"),
|
||||||
|
(String) event.get("nextDrivingSourceIntervalId"),
|
||||||
|
(String) event.get("previousVehicleKey"),
|
||||||
|
(String) event.get("nextVehicleKey")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void collectVuCardAbsentIntervalEvents(
|
private void collectVuCardAbsentIntervalEvents(
|
||||||
EventBean[] newData,
|
EventBean[] newData,
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> target
|
List<TachographEsperVuCardAbsentIntervalEvent> target
|
||||||
|
|
@ -630,11 +760,13 @@ public class DriverTimelineBuilder {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (EventBean event : newData) {
|
for (EventBean event : newData) {
|
||||||
|
long startedAtEpochSecond = (Long) event.get("startedAtEpochSecond");
|
||||||
|
long endedAtEpochSecond = (Long) event.get("endedAtEpochSecond");
|
||||||
target.add(new TachographEsperVuCardAbsentIntervalEvent(
|
target.add(new TachographEsperVuCardAbsentIntervalEvent(
|
||||||
(UUID) event.get("sessionId"),
|
(UUID) event.get("sessionId"),
|
||||||
(String) event.get("driverKey"),
|
(String) event.get("driverKey"),
|
||||||
(OffsetDateTime) event.get("startedAt"),
|
OffsetDateTime.ofInstant(Instant.ofEpochSecond(startedAtEpochSecond), ZoneOffset.UTC),
|
||||||
(OffsetDateTime) event.get("endedAt"),
|
OffsetDateTime.ofInstant(Instant.ofEpochSecond(endedAtEpochSecond), ZoneOffset.UTC),
|
||||||
(Long) event.get("durationSeconds"),
|
(Long) event.get("durationSeconds"),
|
||||||
(String) event.get("previousUsageIntervalId"),
|
(String) event.get("previousUsageIntervalId"),
|
||||||
(String) event.get("nextUsageIntervalId"),
|
(String) event.get("nextUsageIntervalId"),
|
||||||
|
|
@ -659,4 +791,12 @@ public class DriverTimelineBuilder {
|
||||||
throw new IllegalStateException("Cannot load EPL resource: " + path, e);
|
throw new IllegalStateException("Cannot load EPL resource: " + path, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String renderDrivingInterruptionIntervalEventsEpl(int significantDrivingMinutes) {
|
||||||
|
long thresholdSeconds = Math.max(1, significantDrivingMinutes) * 60L;
|
||||||
|
return DRIVING_INTERRUPTION_INTERVAL_EVENTS_EPL_TEMPLATE.replace(
|
||||||
|
"${SIGNIFICANT_DRIVING_THRESHOLD_SECONDS}",
|
||||||
|
Long.toString(thresholdSeconds)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package at.procon.eventhub.tachographfilesession.service;
|
package at.procon.eventhub.tachographfilesession.service;
|
||||||
|
|
||||||
import at.procon.eventhub.config.EventHubProperties;
|
import at.procon.eventhub.config.EventHubProperties;
|
||||||
|
import at.procon.eventhub.tachographfilesession.dto.TachographEsperEventsProcessingRequest;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
||||||
|
|
@ -12,6 +13,7 @@ import at.procon.eventhub.tachographfilesession.model.ProcessedShiftDrivingEvalu
|
||||||
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
|
import at.procon.eventhub.tachographfilesession.model.ResolvedActivityInterval;
|
||||||
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.TachographFileSession;
|
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||||
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;
|
||||||
|
|
@ -121,6 +123,17 @@ public class TachographFileSessionProcessingService {
|
||||||
UUID sessionId,
|
UUID sessionId,
|
||||||
String driverKey
|
String driverKey
|
||||||
) {
|
) {
|
||||||
|
return getEsperDriverProcessingResults(sessionId, driverKey, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TachographEsperDriverProcessingResultDto getEsperDriverProcessingResults(
|
||||||
|
UUID sessionId,
|
||||||
|
String driverKey,
|
||||||
|
TachographEsperEventsProcessingRequest request
|
||||||
|
) {
|
||||||
|
TachographEsperEventsProcessingRequest effectiveRequest = request == null
|
||||||
|
? new TachographEsperEventsProcessingRequest(null, null, null)
|
||||||
|
: request;
|
||||||
TachographFileSession session = repository.find(sessionId)
|
TachographFileSession session = repository.find(sessionId)
|
||||||
.orElseThrow(() -> new TachographFileSessionNotFoundException(sessionId));
|
.orElseThrow(() -> new TachographFileSessionNotFoundException(sessionId));
|
||||||
DriverExtractionSession driver = session.driversByKey().get(driverKey);
|
DriverExtractionSession driver = session.driversByKey().get(driverKey);
|
||||||
|
|
@ -129,14 +142,44 @@ public class TachographFileSessionProcessingService {
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedDriverTimeline timeline = driverTimelineBuilder.build(session, driver);
|
ResolvedDriverTimeline timeline = driverTimelineBuilder.build(session, driver);
|
||||||
List<TachographEsperActivityIntervalEvent> activityIntervals =
|
OffsetDateTime requestedFrom = effectiveRequest.occurredFrom() == null ? timeline.loadedFrom() : utc(effectiveRequest.occurredFrom());
|
||||||
driverTimelineBuilder.buildEsperActivityIntervalEvents(sessionId, driverKey, timeline);
|
OffsetDateTime requestedTo = effectiveRequest.occurredTo() == null ? timeline.loadedTo() : utc(effectiveRequest.occurredTo());
|
||||||
List<TachographEsperActivityIntervalEvent> drivingIntervals =
|
if (requestedFrom != null && requestedTo != null && requestedTo.isBefore(requestedFrom)) {
|
||||||
driverTimelineBuilder.buildEsperDrivingIntervalEvents(sessionId, driverKey, timeline);
|
throw new IllegalArgumentException("occurredTo must not be before occurredFrom.");
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals =
|
}
|
||||||
driverTimelineBuilder.buildEsperVehicleUsageIntervalEvents(timeline);
|
int significantDrivingMinutes = resolveEsperSignificantDrivingMinutes(effectiveRequest);
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals =
|
|
||||||
driverTimelineBuilder.buildEsperVuCardAbsentIntervalEvents(timeline);
|
List<TachographEsperActivityIntervalEvent> activityIntervals = clipEsperActivityIntervalEvents(
|
||||||
|
driverTimelineBuilder.buildEsperActivityIntervalEvents(sessionId, driverKey, timeline),
|
||||||
|
requestedFrom,
|
||||||
|
requestedTo
|
||||||
|
);
|
||||||
|
List<TachographEsperActivityIntervalEvent> drivingIntervals = clipEsperActivityIntervalEvents(
|
||||||
|
driverTimelineBuilder.buildEsperDrivingIntervalEvents(sessionId, driverKey, timeline),
|
||||||
|
requestedFrom,
|
||||||
|
requestedTo
|
||||||
|
);
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals =
|
||||||
|
clipEsperDrivingInterruptionIntervalEvents(
|
||||||
|
driverTimelineBuilder.buildEsperDrivingInterruptionIntervalEvents(
|
||||||
|
sessionId,
|
||||||
|
driverKey,
|
||||||
|
timeline,
|
||||||
|
significantDrivingMinutes
|
||||||
|
),
|
||||||
|
requestedFrom,
|
||||||
|
requestedTo
|
||||||
|
);
|
||||||
|
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals = clipEsperVehicleUsageIntervalEvents(
|
||||||
|
driverTimelineBuilder.buildEsperVehicleUsageIntervalEvents(timeline),
|
||||||
|
requestedFrom,
|
||||||
|
requestedTo
|
||||||
|
);
|
||||||
|
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals = clipEsperVuCardAbsentIntervalEvents(
|
||||||
|
driverTimelineBuilder.buildEsperVuCardAbsentIntervalEvents(timeline),
|
||||||
|
requestedFrom,
|
||||||
|
requestedTo
|
||||||
|
);
|
||||||
|
|
||||||
return new TachographEsperDriverProcessingResultDto(
|
return new TachographEsperDriverProcessingResultDto(
|
||||||
sessionId,
|
sessionId,
|
||||||
|
|
@ -144,18 +187,174 @@ public class TachographFileSessionProcessingService {
|
||||||
timeline.sourceKind(),
|
timeline.sourceKind(),
|
||||||
timeline.loadedFrom(),
|
timeline.loadedFrom(),
|
||||||
timeline.loadedTo(),
|
timeline.loadedTo(),
|
||||||
|
requestedFrom,
|
||||||
|
requestedTo,
|
||||||
activityIntervals.size(),
|
activityIntervals.size(),
|
||||||
drivingIntervals.size(),
|
drivingIntervals.size(),
|
||||||
|
drivingInterruptionIntervals.size(),
|
||||||
vehicleUsageIntervals.size(),
|
vehicleUsageIntervals.size(),
|
||||||
vuCardAbsentIntervals.size(),
|
vuCardAbsentIntervals.size(),
|
||||||
activityIntervals,
|
activityIntervals,
|
||||||
drivingIntervals,
|
drivingIntervals,
|
||||||
|
drivingInterruptionIntervals,
|
||||||
vehicleUsageIntervals,
|
vehicleUsageIntervals,
|
||||||
vuCardAbsentIntervals,
|
vuCardAbsentIntervals,
|
||||||
esperProjectionNotes()
|
esperProjectionNotes()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<TachographEsperActivityIntervalEvent> clipEsperActivityIntervalEvents(
|
||||||
|
List<TachographEsperActivityIntervalEvent> intervals,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
boolean clipped = interval.clippedToRequestedPeriod()
|
||||||
|
|| !start.equals(interval.startedAt())
|
||||||
|
|| !end.equals(interval.endedAt());
|
||||||
|
return new TachographEsperActivityIntervalEvent(
|
||||||
|
interval.sessionId(),
|
||||||
|
interval.driverKey(),
|
||||||
|
interval.intervalId(),
|
||||||
|
interval.activityType(),
|
||||||
|
interval.cardSlot(),
|
||||||
|
interval.cardStatus(),
|
||||||
|
interval.drivingStatus(),
|
||||||
|
interval.registrationKey(),
|
||||||
|
interval.vehicleKey(),
|
||||||
|
interval.sourceKind(),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Duration.between(start, end).getSeconds(),
|
||||||
|
interval.sourceIntervalIds(),
|
||||||
|
interval.synthetic(),
|
||||||
|
clipped,
|
||||||
|
interval.level()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.sorted(Comparator.comparing(TachographEsperActivityIntervalEvent::startedAt)
|
||||||
|
.thenComparing(TachographEsperActivityIntervalEvent::endedAt)
|
||||||
|
.thenComparing(TachographEsperActivityIntervalEvent::activityType, Comparator.nullsLast(String::compareTo)))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TachographEsperVehicleUsageIntervalEvent> clipEsperVehicleUsageIntervalEvents(
|
||||||
|
List<TachographEsperVehicleUsageIntervalEvent> intervals,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
boolean startClipped = !start.equals(interval.startedAt());
|
||||||
|
boolean endClipped = !end.equals(interval.endedAt());
|
||||||
|
return new TachographEsperVehicleUsageIntervalEvent(
|
||||||
|
interval.sessionId(),
|
||||||
|
interval.driverKey(),
|
||||||
|
interval.intervalId(),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Duration.between(start, end).getSeconds(),
|
||||||
|
startClipped ? null : interval.odometerBeginKm(),
|
||||||
|
endClipped ? null : interval.odometerEndKm(),
|
||||||
|
interval.registrationKey(),
|
||||||
|
interval.vehicleKey(),
|
||||||
|
interval.sourceKind(),
|
||||||
|
interval.sourceIntervalIds()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.sorted(Comparator.comparing(TachographEsperVehicleUsageIntervalEvent::startedAt)
|
||||||
|
.thenComparing(TachographEsperVehicleUsageIntervalEvent::endedAt)
|
||||||
|
.thenComparing(TachographEsperVehicleUsageIntervalEvent::intervalId, Comparator.nullsLast(String::compareTo)))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TachographEsperDrivingInterruptionIntervalEvent> clipEsperDrivingInterruptionIntervalEvents(
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> intervals,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return new TachographEsperDrivingInterruptionIntervalEvent(
|
||||||
|
interval.sessionId(),
|
||||||
|
interval.driverKey(),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Duration.between(start, end).getSeconds(),
|
||||||
|
interval.previousDrivingSourceIntervalId(),
|
||||||
|
interval.nextDrivingSourceIntervalId(),
|
||||||
|
interval.previousVehicleKey(),
|
||||||
|
interval.nextVehicleKey()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.sorted(Comparator.comparing(TachographEsperDrivingInterruptionIntervalEvent::startedAt)
|
||||||
|
.thenComparing(TachographEsperDrivingInterruptionIntervalEvent::endedAt))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TachographEsperVuCardAbsentIntervalEvent> clipEsperVuCardAbsentIntervalEvents(
|
||||||
|
List<TachographEsperVuCardAbsentIntervalEvent> intervals,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return new TachographEsperVuCardAbsentIntervalEvent(
|
||||||
|
interval.sessionId(),
|
||||||
|
interval.driverKey(),
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
Duration.between(start, end).getSeconds(),
|
||||||
|
interval.previousUsageIntervalId(),
|
||||||
|
interval.nextUsageIntervalId(),
|
||||||
|
interval.previousRegistrationKey(),
|
||||||
|
interval.nextRegistrationKey(),
|
||||||
|
interval.previousVehicleKey(),
|
||||||
|
interval.nextVehicleKey()
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.sorted(Comparator.comparing(TachographEsperVuCardAbsentIntervalEvent::startedAt)
|
||||||
|
.thenComparing(TachographEsperVuCardAbsentIntervalEvent::endedAt))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
private List<ResolvedActivityInterval> synthesizeUnknownGaps(
|
private List<ResolvedActivityInterval> synthesizeUnknownGaps(
|
||||||
List<ResolvedActivityInterval> knownIntervals,
|
List<ResolvedActivityInterval> knownIntervals,
|
||||||
Duration gapDetectionTolerance
|
Duration gapDetectionTolerance
|
||||||
|
|
@ -694,6 +893,12 @@ public class TachographFileSessionProcessingService {
|
||||||
: request.gapDetectionToleranceSeconds();
|
: request.gapDetectionToleranceSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int resolveEsperSignificantDrivingMinutes(TachographEsperEventsProcessingRequest request) {
|
||||||
|
return request.significantDrivingMinutes() == null
|
||||||
|
? properties.getTachographFileSession().getProcessing().getSignificantDrivingMinutes()
|
||||||
|
: request.significantDrivingMinutes();
|
||||||
|
}
|
||||||
|
|
||||||
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.",
|
||||||
|
|
@ -707,7 +912,10 @@ public class TachographFileSessionProcessingService {
|
||||||
return List.of(
|
return List.of(
|
||||||
"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.",
|
||||||
"VU card-absent intervals are gaps between consecutive normalized vehicle-usage intervals for the same driver."
|
"Driving interruption intervals are gaps between consecutive driving intervals longer than the configured significant-driving threshold.",
|
||||||
|
"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."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
create schema SignificantDrivingInterval(
|
||||||
|
sessionId java.util.UUID,
|
||||||
|
driverKey string,
|
||||||
|
firstSourceIntervalId string,
|
||||||
|
lastSourceIntervalId string,
|
||||||
|
startedAtEpochSecond long,
|
||||||
|
endedAtEpochSecond long,
|
||||||
|
durationSeconds long,
|
||||||
|
vehicleKey string
|
||||||
|
);
|
||||||
|
|
||||||
|
create schema DrivingInterruptionInterval(
|
||||||
|
sessionId java.util.UUID,
|
||||||
|
driverKey string,
|
||||||
|
startedAtEpochSecond long,
|
||||||
|
endedAtEpochSecond long,
|
||||||
|
durationSeconds long,
|
||||||
|
previousDrivingSourceIntervalId string,
|
||||||
|
nextDrivingSourceIntervalId string,
|
||||||
|
previousVehicleKey string,
|
||||||
|
nextVehicleKey string
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into SignificantDrivingInterval
|
||||||
|
select
|
||||||
|
sessionId,
|
||||||
|
driverKey,
|
||||||
|
firstSourceIntervalId,
|
||||||
|
lastSourceIntervalId,
|
||||||
|
startedAtEpochSecond,
|
||||||
|
endedAtEpochSecond,
|
||||||
|
durationSeconds,
|
||||||
|
vehicleKey
|
||||||
|
from TachographActivityIntervalInputEvent(activityType = 'DRIVE', durationSeconds > ${SIGNIFICANT_DRIVING_THRESHOLD_SECONDS});
|
||||||
|
|
||||||
|
create window PreviousSignificantDrivingInterval#unique(driverKey) as SignificantDrivingInterval;
|
||||||
|
|
||||||
|
on SignificantDrivingInterval as next
|
||||||
|
insert into DrivingInterruptionInterval
|
||||||
|
select
|
||||||
|
priorInterval.sessionId as sessionId,
|
||||||
|
priorInterval.driverKey as driverKey,
|
||||||
|
priorInterval.endedAtEpochSecond as startedAtEpochSecond,
|
||||||
|
next.startedAtEpochSecond as endedAtEpochSecond,
|
||||||
|
next.startedAtEpochSecond - priorInterval.endedAtEpochSecond as durationSeconds,
|
||||||
|
priorInterval.lastSourceIntervalId as previousDrivingSourceIntervalId,
|
||||||
|
next.firstSourceIntervalId as nextDrivingSourceIntervalId,
|
||||||
|
priorInterval.vehicleKey as previousVehicleKey,
|
||||||
|
next.vehicleKey as nextVehicleKey
|
||||||
|
from PreviousSignificantDrivingInterval as priorInterval
|
||||||
|
where priorInterval.driverKey = next.driverKey
|
||||||
|
and next.startedAtEpochSecond > priorInterval.endedAtEpochSecond;
|
||||||
|
|
||||||
|
@Priority(20)
|
||||||
|
on SignificantDrivingInterval
|
||||||
|
delete from PreviousSignificantDrivingInterval;
|
||||||
|
|
||||||
|
@Priority(10)
|
||||||
|
on SignificantDrivingInterval as current
|
||||||
|
insert into PreviousSignificantDrivingInterval
|
||||||
|
select *;
|
||||||
|
|
||||||
|
@name('drivingInterruptionIntervals')
|
||||||
|
select * from DrivingInterruptionInterval;
|
||||||
|
|
@ -3,8 +3,8 @@ create context PerDriver partition by driverKey from TachographVehicleUsageInter
|
||||||
create schema VuCardAbsentInterval(
|
create schema VuCardAbsentInterval(
|
||||||
sessionId java.util.UUID,
|
sessionId java.util.UUID,
|
||||||
driverKey string,
|
driverKey string,
|
||||||
startedAt java.time.OffsetDateTime,
|
startedAtEpochSecond long,
|
||||||
endedAt java.time.OffsetDateTime,
|
endedAtEpochSecond long,
|
||||||
durationSeconds long,
|
durationSeconds long,
|
||||||
previousUsageIntervalId string,
|
previousUsageIntervalId string,
|
||||||
nextUsageIntervalId string,
|
nextUsageIntervalId string,
|
||||||
|
|
@ -17,38 +17,37 @@ create schema VuCardAbsentInterval(
|
||||||
context PerDriver
|
context PerDriver
|
||||||
create window PreviousVehicleUsageInterval#lastevent as TachographVehicleUsageIntervalInputEvent;
|
create window PreviousVehicleUsageInterval#lastevent as TachographVehicleUsageIntervalInputEvent;
|
||||||
|
|
||||||
context PerDriver
|
|
||||||
@Priority(30)
|
@Priority(30)
|
||||||
|
context PerDriver
|
||||||
on TachographVehicleUsageIntervalInputEvent as next
|
on TachographVehicleUsageIntervalInputEvent as next
|
||||||
insert into VuCardAbsentInterval
|
insert into VuCardAbsentInterval
|
||||||
select
|
select
|
||||||
prev.sessionId as sessionId,
|
priorInterval.sessionId as sessionId,
|
||||||
prev.driverKey as driverKey,
|
priorInterval.driverKey as driverKey,
|
||||||
prev.endedAt.plusSeconds(1) as startedAt,
|
priorInterval.endedAtEpochSecond + 1L as startedAtEpochSecond,
|
||||||
next.startedAt as endedAt,
|
next.startedAtEpochSecond as endedAtEpochSecond,
|
||||||
java.time.Duration.between(prev.endedAt.plusSeconds(1), next.startedAt).getSeconds() as durationSeconds,
|
next.startedAtEpochSecond - (priorInterval.endedAtEpochSecond + 1L) as durationSeconds,
|
||||||
prev.intervalId as previousUsageIntervalId,
|
priorInterval.lastSourceIntervalId as previousUsageIntervalId,
|
||||||
next.intervalId as nextUsageIntervalId,
|
next.firstSourceIntervalId as nextUsageIntervalId,
|
||||||
prev.registrationKey as previousRegistrationKey,
|
priorInterval.registrationKey as previousRegistrationKey,
|
||||||
next.registrationKey as nextRegistrationKey,
|
next.registrationKey as nextRegistrationKey,
|
||||||
prev.vehicleKey as previousVehicleKey,
|
priorInterval.vehicleKey as previousVehicleKey,
|
||||||
next.vehicleKey as nextVehicleKey
|
next.vehicleKey as nextVehicleKey
|
||||||
from PreviousVehicleUsageInterval as prev
|
from PreviousVehicleUsageInterval as priorInterval
|
||||||
where prev.endedAt is not null
|
where priorInterval.endedAt is not null
|
||||||
and next.startedAt is not null
|
and next.startedAt is not null
|
||||||
and next.startedAt.isAfter(prev.endedAt.plusSeconds(1));
|
and next.startedAtEpochSecond > priorInterval.endedAtEpochSecond + 1L;
|
||||||
|
|
||||||
context PerDriver
|
|
||||||
@Priority(20)
|
@Priority(20)
|
||||||
|
context PerDriver
|
||||||
on TachographVehicleUsageIntervalInputEvent
|
on TachographVehicleUsageIntervalInputEvent
|
||||||
delete from PreviousVehicleUsageInterval;
|
delete from PreviousVehicleUsageInterval;
|
||||||
|
|
||||||
context PerDriver
|
|
||||||
@Priority(10)
|
@Priority(10)
|
||||||
|
context PerDriver
|
||||||
on TachographVehicleUsageIntervalInputEvent as current
|
on TachographVehicleUsageIntervalInputEvent as current
|
||||||
insert into PreviousVehicleUsageInterval
|
insert into PreviousVehicleUsageInterval
|
||||||
select *;
|
select *;
|
||||||
|
|
||||||
@name('vuCardAbsentIntervals')
|
@name('vuCardAbsentIntervals')
|
||||||
context PerDriver
|
|
||||||
select * from VuCardAbsentInterval;
|
select * from VuCardAbsentInterval;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
import at.procon.eventhub.tachographfilesession.dto.CreateTachographFileSessionResponse;
|
import at.procon.eventhub.tachographfilesession.dto.CreateTachographFileSessionResponse;
|
||||||
|
import at.procon.eventhub.tachographfilesession.dto.TachographEsperEventsProcessingRequest;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverDetailDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverDetailDto;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
||||||
|
|
@ -19,6 +20,7 @@ import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionListDri
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionSummaryDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionSummaryDto;
|
||||||
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.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;
|
||||||
|
|
@ -63,15 +65,22 @@ class TachographFileSessionControllerTest {
|
||||||
when(service.getSession(sessionId)).thenReturn(summary);
|
when(service.getSession(sessionId)).thenReturn(summary);
|
||||||
when(service.listDrivers(sessionId)).thenReturn(new TachographFileSessionListDriversResponse(sessionId, List.of(driver)));
|
when(service.listDrivers(sessionId)).thenReturn(new TachographFileSessionListDriversResponse(sessionId, List.of(driver)));
|
||||||
when(service.getDriver(sessionId, "12:123")).thenReturn(new TachographFileDriverDetailDto(sessionId, "12:123", null, null, List.of(), List.of(), List.of(), List.of(), List.of(), List.of()));
|
when(service.getDriver(sessionId, "12:123")).thenReturn(new TachographFileDriverDetailDto(sessionId, "12:123", null, null, List.of(), List.of(), List.of(), List.of(), List.of(), List.of()));
|
||||||
when(processingService.getEsperDriverProcessingResults(sessionId, "12:123"))
|
when(processingService.getEsperDriverProcessingResults(
|
||||||
|
eq(sessionId),
|
||||||
|
eq("12:123"),
|
||||||
|
org.mockito.ArgumentMatchers.any(TachographEsperEventsProcessingRequest.class)
|
||||||
|
))
|
||||||
.thenReturn(new TachographEsperDriverProcessingResultDto(
|
.thenReturn(new TachographEsperDriverProcessingResultDto(
|
||||||
sessionId,
|
sessionId,
|
||||||
"12:123",
|
"12:123",
|
||||||
"DRIVER_CARD",
|
"DRIVER_CARD",
|
||||||
OffsetDateTime.parse("2026-05-12T08:00:00Z"),
|
OffsetDateTime.parse("2026-05-12T08:00:00Z"),
|
||||||
OffsetDateTime.parse("2026-05-12T12:00:00Z"),
|
OffsetDateTime.parse("2026-05-12T12:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-12T08:30:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-12T11:30:00Z"),
|
||||||
2,
|
2,
|
||||||
1,
|
1,
|
||||||
|
1,
|
||||||
2,
|
2,
|
||||||
1,
|
1,
|
||||||
List.of(new TachographEsperActivityIntervalEvent(
|
List.of(new TachographEsperActivityIntervalEvent(
|
||||||
|
|
@ -112,6 +121,17 @@ class TachographFileSessionControllerTest {
|
||||||
false,
|
false,
|
||||||
"RAW_INTERVAL"
|
"RAW_INTERVAL"
|
||||||
)),
|
)),
|
||||||
|
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",
|
||||||
|
"VIN-1",
|
||||||
|
"VIN-2"
|
||||||
|
)),
|
||||||
List.of(new TachographEsperVehicleUsageIntervalEvent(
|
List.of(new TachographEsperVehicleUsageIntervalEvent(
|
||||||
sessionId,
|
sessionId,
|
||||||
"12:123",
|
"12:123",
|
||||||
|
|
@ -187,12 +207,25 @@ class TachographFileSessionControllerTest {
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.driverKey").value("12:123"));
|
.andExpect(jsonPath("$.driverKey").value("12:123"));
|
||||||
|
|
||||||
mockMvc.perform(get("/api/eventhub/tachograph-file-sessions/{sessionId}/drivers/{driverKey}/processing/esper-events", sessionId, "12:123"))
|
mockMvc.perform(post("/api/eventhub/tachograph-file-sessions/{sessionId}/drivers/{driverKey}/processing/esper-events", sessionId, "12:123")
|
||||||
|
.contentType("application/json")
|
||||||
|
.content("""
|
||||||
|
{
|
||||||
|
"occurredFrom": "2026-05-12T08:30:00Z",
|
||||||
|
"occurredTo": "2026-05-12T11:30:00Z",
|
||||||
|
"significantDrivingMinutes": 3
|
||||||
|
}
|
||||||
|
"""))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.driverKey").value("12:123"))
|
.andExpect(jsonPath("$.driverKey").value("12:123"))
|
||||||
.andExpect(jsonPath("$.sourceKind").value("DRIVER_CARD"))
|
.andExpect(jsonPath("$.sourceKind").value("DRIVER_CARD"))
|
||||||
|
.andExpect(jsonPath("$.requestedFrom").value("2026-05-12T08: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("$.vuCardAbsentIntervalCount").value(1))
|
.andExpect(jsonPath("$.vuCardAbsentIntervalCount").value(1))
|
||||||
|
.andExpect(jsonPath("$.drivingInterruptionIntervals[0].previousVehicleKey").value("VIN-1"))
|
||||||
|
.andExpect(jsonPath("$.drivingInterruptionIntervals[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")
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
|
||||||
import at.procon.eventhub.tachographfilesession.model.ExtractionStats;
|
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.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;
|
||||||
|
|
@ -375,4 +376,79 @@ class DriverTimelineBuilderTest {
|
||||||
assertThat(absentIntervals.get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
assertThat(absentIntervals.get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
||||||
assertThat(absentIntervals.get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
assertThat(absentIntervals.get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildsEsperDrivingInterruptionIntervalEventsFromSignificantDrivingGaps() {
|
||||||
|
DriverExtractionSession driver = new DriverExtractionSession(
|
||||||
|
"12:123",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
List.of(),
|
||||||
|
List.of(),
|
||||||
|
List.of(),
|
||||||
|
List.of(
|
||||||
|
new ExtractedCardActivityInterval(
|
||||||
|
"ACT-1",
|
||||||
|
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-01T08:02:00Z"),
|
||||||
|
"DRIVE",
|
||||||
|
"DRIVER",
|
||||||
|
"INSERTED",
|
||||||
|
"SINGLE",
|
||||||
|
"12:REG-1",
|
||||||
|
"VIN-1",
|
||||||
|
"a"
|
||||||
|
),
|
||||||
|
new ExtractedCardActivityInterval(
|
||||||
|
"ACT-2",
|
||||||
|
OffsetDateTime.parse("2026-05-01T08:02:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-01T08:10:00Z"),
|
||||||
|
"WORK",
|
||||||
|
"DRIVER",
|
||||||
|
"INSERTED",
|
||||||
|
"SINGLE",
|
||||||
|
"12:REG-1",
|
||||||
|
"VIN-1",
|
||||||
|
"b"
|
||||||
|
),
|
||||||
|
new ExtractedCardActivityInterval(
|
||||||
|
"ACT-3",
|
||||||
|
OffsetDateTime.parse("2026-05-01T08:10:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-01T08:15:00Z"),
|
||||||
|
"DRIVE",
|
||||||
|
"DRIVER",
|
||||||
|
"INSERTED",
|
||||||
|
"SINGLE",
|
||||||
|
"12:REG-2",
|
||||||
|
"VIN-2",
|
||||||
|
"c"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
List.of(),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
TachographFileSession session = new TachographFileSession(
|
||||||
|
UUID.randomUUID(),
|
||||||
|
new TachographFileSessionMetadata("default", "legalrequirements-drivercard", "sample", "sample.ddd", "a", 3, "42", "b", true, null),
|
||||||
|
Map.of(driver.driverKey(), driver),
|
||||||
|
new ExtractionStats(1, 3, 0, 0, 0, 0),
|
||||||
|
List.of(),
|
||||||
|
Instant.now(),
|
||||||
|
Instant.now().plus(4, ChronoUnit.HOURS)
|
||||||
|
);
|
||||||
|
|
||||||
|
List<TachographEsperDrivingInterruptionIntervalEvent> interruptions =
|
||||||
|
builder.buildEsperDrivingInterruptionIntervalEvents(session, driver, 1);
|
||||||
|
|
||||||
|
assertThat(interruptions).hasSize(1);
|
||||||
|
assertThat(interruptions.get(0).sessionId()).isEqualTo(session.sessionId());
|
||||||
|
assertThat(interruptions.get(0).driverKey()).isEqualTo("12:123");
|
||||||
|
assertThat(interruptions.get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T08:02:00Z"));
|
||||||
|
assertThat(interruptions.get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T08:10:00Z"));
|
||||||
|
assertThat(interruptions.get(0).durationSeconds()).isEqualTo(480L);
|
||||||
|
assertThat(interruptions.get(0).previousDrivingSourceIntervalId()).isEqualTo("ACT-1");
|
||||||
|
assertThat(interruptions.get(0).nextDrivingSourceIntervalId()).isEqualTo("ACT-3");
|
||||||
|
assertThat(interruptions.get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
||||||
|
assertThat(interruptions.get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package at.procon.eventhub.tachographfilesession.service;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import at.procon.eventhub.config.EventHubProperties;
|
import at.procon.eventhub.config.EventHubProperties;
|
||||||
|
import at.procon.eventhub.tachographfilesession.dto.TachographEsperEventsProcessingRequest;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographEsperDriverProcessingResultDto;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
||||||
|
|
@ -84,12 +85,99 @@ class TachographFileSessionProcessingServiceTest {
|
||||||
assertThat(result.sourceKind()).isEqualTo("DRIVER_CARD");
|
assertThat(result.sourceKind()).isEqualTo("DRIVER_CARD");
|
||||||
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.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"));
|
||||||
assertThat(result.vuCardAbsentIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T12:00:00Z"));
|
assertThat(result.vuCardAbsentIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T12:00:00Z"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void appliesOccurredWindowToEsperDriverProcessingResults() {
|
||||||
|
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-01T11:00:00Z"),
|
||||||
|
100L,
|
||||||
|
200L,
|
||||||
|
"12:REG-1",
|
||||||
|
"VIN-1",
|
||||||
|
"vu-1"
|
||||||
|
),
|
||||||
|
new ExtractedCardVehicleUsageInterval(
|
||||||
|
"CVU-2",
|
||||||
|
OffsetDateTime.parse("2026-05-01T12:00:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-01T13:00:00Z"),
|
||||||
|
201L,
|
||||||
|
260L,
|
||||||
|
"12:REG-2",
|
||||||
|
"VIN-2",
|
||||||
|
"vu-2"
|
||||||
|
)
|
||||||
|
),
|
||||||
|
List.of(
|
||||||
|
new ExtractedCardActivityInterval("ACT-1", OffsetDateTime.parse("2026-05-01T08:30:00Z"), OffsetDateTime.parse("2026-05-01T09:00:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "a"),
|
||||||
|
new ExtractedCardActivityInterval("ACT-2", OffsetDateTime.parse("2026-05-01T09:00:00Z"), OffsetDateTime.parse("2026-05-01T10:00:00Z"), "WORK", "DRIVER", "INSERTED", "SINGLE", "12:REG-1", "VIN-1", "b"),
|
||||||
|
new ExtractedCardActivityInterval("ACT-3", OffsetDateTime.parse("2026-05-01T10:00:00Z"), OffsetDateTime.parse("2026-05-01T10:05:00Z"), "DRIVE", "DRIVER", "INSERTED", "SINGLE", "12:REG-2", "VIN-2", "c")
|
||||||
|
),
|
||||||
|
List.of(),
|
||||||
|
List.of()
|
||||||
|
);
|
||||||
|
TachographFileSession session = new TachographFileSession(
|
||||||
|
UUID.randomUUID(),
|
||||||
|
new TachographFileSessionMetadata("default", "legalrequirements-drivercard", "sample", "sample.ddd", "a", 3, "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-01T08:45:00Z"),
|
||||||
|
OffsetDateTime.parse("2026-05-01T12:30:00Z"),
|
||||||
|
3
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat(result.requestedFrom()).isEqualTo(OffsetDateTime.parse("2026-05-01T08:45:00Z"));
|
||||||
|
assertThat(result.requestedTo()).isEqualTo(OffsetDateTime.parse("2026-05-01T12:30:00Z"));
|
||||||
|
assertThat(result.activityIntervalCount()).isEqualTo(3);
|
||||||
|
assertThat(result.activityIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T08:45:00Z"));
|
||||||
|
assertThat(result.activityIntervals().get(0).clippedToRequestedPeriod()).isTrue();
|
||||||
|
assertThat(result.drivingIntervalCount()).isEqualTo(2);
|
||||||
|
assertThat(result.drivingInterruptionIntervalCount()).isEqualTo(1);
|
||||||
|
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).previousVehicleKey()).isEqualTo("VIN-1");
|
||||||
|
assertThat(result.drivingInterruptionIntervals().get(0).nextVehicleKey()).isEqualTo("VIN-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).odometerBeginKm()).isNull();
|
||||||
|
assertThat(result.vehicleUsageIntervals().get(1).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T12:30:00Z"));
|
||||||
|
assertThat(result.vehicleUsageIntervals().get(1).odometerEndKm()).isNull();
|
||||||
|
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void evaluatesOperatingPeriodsFromSessionTimeline() {
|
void evaluatesOperatingPeriodsFromSessionTimeline() {
|
||||||
EventHubProperties properties = new EventHubProperties();
|
EventHubProperties properties = new EventHubProperties();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue