Compare commits
No commits in common. "317983eba82e95e59a7165f81a21f4f2d1ba9a9b" and "9e6f8efb26aa6bb618ef3da570951c4faef12cba" have entirely different histories.
317983eba8
...
9e6f8efb26
|
|
@ -351,61 +351,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "Get tachograph file session driver Esper events",
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"header": [],
|
|
||||||
"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 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 \"minimumRestPeriodMinutes\": 720\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": {
|
||||||
|
|
|
||||||
|
|
@ -358,7 +358,6 @@ 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;
|
||||||
|
|
||||||
|
|
@ -378,14 +377,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
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.TachographFileDriverDetailDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverDetailDto;
|
||||||
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;
|
||||||
|
|
@ -68,23 +66,6 @@ public class TachographFileSessionController {
|
||||||
return ResponseEntity.ok(service.getDriver(sessionId, driverKey));
|
return ResponseEntity.ok(service.getDriver(sessionId, driverKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{sessionId}/drivers/{driverKey}/processing/esper-events")
|
|
||||||
public ResponseEntity<TachographEsperDriverProcessingResultDto> getEsperDriverProcessingResults(
|
|
||||||
@PathVariable UUID sessionId,
|
|
||||||
@PathVariable String 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,38 +0,0 @@
|
||||||
package at.procon.eventhub.tachographfilesession.dto;
|
|
||||||
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
|
||||||
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.TachographEsperVuCardAbsentIntervalEvent;
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public record TachographEsperDriverProcessingResultDto(
|
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
String sourceKind,
|
|
||||||
OffsetDateTime loadedFrom,
|
|
||||||
OffsetDateTime loadedTo,
|
|
||||||
OffsetDateTime requestedFrom,
|
|
||||||
OffsetDateTime requestedTo,
|
|
||||||
int activityIntervalCount,
|
|
||||||
int drivingIntervalCount,
|
|
||||||
int drivingInterruptionIntervalCount,
|
|
||||||
int drivingInterruptionVehicleChangeIntervalCount,
|
|
||||||
int dailyWeeklyRestCandidateIntervalCount,
|
|
||||||
int potentialHomeOvernightStayIntervalCount,
|
|
||||||
int vehicleUsageIntervalCount,
|
|
||||||
int vuCardAbsentIntervalCount,
|
|
||||||
List<TachographEsperActivityIntervalEvent> activityIntervals,
|
|
||||||
List<TachographEsperActivityIntervalEvent> drivingIntervals,
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals,
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> dailyWeeklyRestCandidateIntervals,
|
|
||||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals,
|
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals,
|
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals,
|
|
||||||
List<String> notes
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package at.procon.eventhub.tachographfilesession.dto;
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
|
|
||||||
public record TachographEsperEventsProcessingRequest(
|
|
||||||
OffsetDateTime occurredFrom,
|
|
||||||
OffsetDateTime occurredTo,
|
|
||||||
Integer significantDrivingMinutes,
|
|
||||||
Integer minimumRestPeriodMinutes
|
|
||||||
) {
|
|
||||||
public TachographEsperEventsProcessingRequest {
|
|
||||||
significantDrivingMinutes = significantDrivingMinutes == null ? null : Math.max(1, significantDrivingMinutes);
|
|
||||||
minimumRestPeriodMinutes = minimumRestPeriodMinutes == null
|
|
||||||
? null
|
|
||||||
: Math.max(1, minimumRestPeriodMinutes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,11 +3,8 @@ package at.procon.eventhub.tachographfilesession.model;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public record ResolvedVehicleUsageInterval(
|
public record ResolvedVehicleUsageInterval(
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
String intervalId,
|
String intervalId,
|
||||||
OffsetDateTime from,
|
OffsetDateTime from,
|
||||||
OffsetDateTime to,
|
OffsetDateTime to,
|
||||||
|
|
@ -20,8 +17,6 @@ public record ResolvedVehicleUsageInterval(
|
||||||
List<String> sourceIntervalIds
|
List<String> sourceIntervalIds
|
||||||
) {
|
) {
|
||||||
public static ResolvedVehicleUsageInterval resolved(
|
public static ResolvedVehicleUsageInterval resolved(
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
String intervalId,
|
String intervalId,
|
||||||
OffsetDateTime from,
|
OffsetDateTime from,
|
||||||
OffsetDateTime to,
|
OffsetDateTime to,
|
||||||
|
|
@ -33,8 +28,6 @@ public record ResolvedVehicleUsageInterval(
|
||||||
List<String> sourceIntervalIds
|
List<String> sourceIntervalIds
|
||||||
) {
|
) {
|
||||||
return new ResolvedVehicleUsageInterval(
|
return new ResolvedVehicleUsageInterval(
|
||||||
sessionId,
|
|
||||||
driverKey,
|
|
||||||
intervalId,
|
intervalId,
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package at.procon.eventhub.tachographfilesession.model;
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public record TachographEsperActivityIntervalEvent(
|
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
String intervalId,
|
|
||||||
String activityType,
|
|
||||||
String cardSlot,
|
|
||||||
String cardStatus,
|
|
||||||
String drivingStatus,
|
|
||||||
String registrationKey,
|
|
||||||
String vehicleKey,
|
|
||||||
String sourceKind,
|
|
||||||
OffsetDateTime startedAt,
|
|
||||||
OffsetDateTime endedAt,
|
|
||||||
long durationSeconds,
|
|
||||||
List<String> sourceIntervalIds,
|
|
||||||
boolean synthetic,
|
|
||||||
boolean clippedToRequestedPeriod,
|
|
||||||
String level
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
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 previousRegistrationKey,
|
|
||||||
String nextRegistrationKey,
|
|
||||||
String previousVehicleKey,
|
|
||||||
String nextVehicleKey
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
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
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package at.procon.eventhub.tachographfilesession.model;
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public record TachographEsperVehicleUsageIntervalEvent(
|
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
String intervalId,
|
|
||||||
OffsetDateTime startedAt,
|
|
||||||
OffsetDateTime endedAt,
|
|
||||||
long durationSeconds,
|
|
||||||
Long odometerBeginKm,
|
|
||||||
Long odometerEndKm,
|
|
||||||
String registrationKey,
|
|
||||||
String vehicleKey,
|
|
||||||
String sourceKind,
|
|
||||||
List<String> sourceIntervalIds
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package at.procon.eventhub.tachographfilesession.model;
|
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public record TachographEsperVuCardAbsentIntervalEvent(
|
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
OffsetDateTime startedAt,
|
|
||||||
OffsetDateTime endedAt,
|
|
||||||
long durationSeconds,
|
|
||||||
String previousUsageIntervalId,
|
|
||||||
String nextUsageIntervalId,
|
|
||||||
String previousRegistrationKey,
|
|
||||||
String nextRegistrationKey,
|
|
||||||
String previousVehicleKey,
|
|
||||||
String nextVehicleKey
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +1,5 @@
|
||||||
package at.procon.eventhub.tachographfilesession.service;
|
package at.procon.eventhub.tachographfilesession.service;
|
||||||
|
|
||||||
import com.espertech.esper.common.client.EPCompiled;
|
|
||||||
import com.espertech.esper.common.client.EventBean;
|
|
||||||
import com.espertech.esper.common.client.configuration.Configuration;
|
|
||||||
import com.espertech.esper.compiler.client.CompilerArguments;
|
|
||||||
import com.espertech.esper.compiler.client.EPCompileException;
|
|
||||||
import com.espertech.esper.compiler.client.EPCompilerProvider;
|
|
||||||
import com.espertech.esper.runtime.client.EPDeployException;
|
|
||||||
import com.espertech.esper.runtime.client.EPDeployment;
|
|
||||||
import com.espertech.esper.runtime.client.EPRuntime;
|
|
||||||
import com.espertech.esper.runtime.client.EPRuntimeProvider;
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
|
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
|
||||||
import at.procon.eventhub.tachographfilesession.model.ExtractedCardActivityInterval;
|
import at.procon.eventhub.tachographfilesession.model.ExtractedCardActivityInterval;
|
||||||
import at.procon.eventhub.tachographfilesession.model.ExtractedCardVehicleUsageInterval;
|
import at.procon.eventhub.tachographfilesession.model.ExtractedCardVehicleUsageInterval;
|
||||||
|
|
@ -18,60 +8,22 @@ import at.procon.eventhub.tachographfilesession.model.ExtractionWarning;
|
||||||
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.ResolvedVehicleUsageInterval;
|
import at.procon.eventhub.tachographfilesession.model.ResolvedVehicleUsageInterval;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperActivityIntervalEvent;
|
|
||||||
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.TachographEsperVehicleUsageIntervalEvent;
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||||
import java.io.IOException;
|
import java.time.Duration;
|
||||||
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.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.StreamUtils;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class DriverTimelineBuilder {
|
public class DriverTimelineBuilder {
|
||||||
|
|
||||||
private static final AtomicLong RUNTIME_COUNTER = new AtomicLong();
|
|
||||||
private static final String ACTIVITY_INTERVAL_EVENTS_EPL =
|
|
||||||
loadResource("esper/tachograph-activity-interval-events.epl");
|
|
||||||
private static final String 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 DRIVING_INTERRUPTION_VEHICLE_CHANGE_INTERVAL_EVENTS_EPL =
|
|
||||||
loadResource("esper/tachograph-driving-interruption-vehicle-change-interval-events.epl");
|
|
||||||
private static final String DAILY_WEEKLY_REST_CANDIDATE_INTERVAL_EVENTS_EPL_TEMPLATE =
|
|
||||||
loadResource("esper/tachograph-daily-weekly-rest-candidate-interval-events.epl");
|
|
||||||
private static final String POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE =
|
|
||||||
loadResource("esper/tachograph-potential-home-overnight-stay-interval-events.epl");
|
|
||||||
private static final String VEHICLE_USAGE_INTERVAL_EVENTS_EPL =
|
|
||||||
loadResource("esper/tachograph-vehicle-usage-interval-events.epl");
|
|
||||||
private static final String VU_CARD_ABSENT_INTERVAL_EVENTS_EPL =
|
|
||||||
loadResource("esper/tachograph-vu-card-absent-interval-events.epl");
|
|
||||||
|
|
||||||
public ResolvedDriverTimeline build(TachographFileSession session, DriverExtractionSession driverSession) {
|
public ResolvedDriverTimeline build(TachographFileSession session, DriverExtractionSession driverSession) {
|
||||||
String sourceKind = session.metadata().driverCardFile() ? "DRIVER_CARD" : "VEHICLE_UNIT";
|
String sourceKind = session.metadata().driverCardFile() ? "DRIVER_CARD" : "VEHICLE_UNIT";
|
||||||
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(
|
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(driverSession.cardVehicleUsageIntervals(), sourceKind);
|
||||||
session.sessionId(),
|
|
||||||
driverSession.driverKey(),
|
|
||||||
driverSession.cardVehicleUsageIntervals(),
|
|
||||||
sourceKind
|
|
||||||
);
|
|
||||||
List<ResolvedActivityInterval> activityIntervals = resolveActivities(driverSession.cardActivityIntervals(), sourceKind);
|
List<ResolvedActivityInterval> activityIntervals = resolveActivities(driverSession.cardActivityIntervals(), sourceKind);
|
||||||
List<ExtractedSupportEvent> supportEvents = driverSession.supportEvents().stream()
|
List<ExtractedSupportEvent> supportEvents = driverSession.supportEvents().stream()
|
||||||
.sorted(Comparator.comparing(ExtractedSupportEvent::occurredAt)
|
.sorted(Comparator.comparing(ExtractedSupportEvent::occurredAt)
|
||||||
|
|
@ -92,360 +44,7 @@ public class DriverTimelineBuilder {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<TachographEsperActivityIntervalEvent> buildEsperActivityIntervalEvents(
|
|
||||||
TachographFileSession session,
|
|
||||||
DriverExtractionSession driverSession
|
|
||||||
) {
|
|
||||||
String sourceKind = session.metadata().driverCardFile() ? "DRIVER_CARD" : "VEHICLE_UNIT";
|
|
||||||
List<ResolvedActivityInterval> activityIntervals = resolveActivities(driverSession.cardActivityIntervals(), sourceKind);
|
|
||||||
return buildEsperActivityIntervalEvents(session.sessionId(), driverSession.driverKey(), activityIntervals);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TachographEsperActivityIntervalEvent> buildEsperActivityIntervalEvents(
|
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
ResolvedDriverTimeline timeline
|
|
||||||
) {
|
|
||||||
return timeline == null
|
|
||||||
? List.of()
|
|
||||||
: buildEsperActivityIntervalEvents(sessionId, driverKey, timeline.activityIntervals());
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TachographEsperActivityIntervalEvent> buildEsperDrivingIntervalEvents(
|
|
||||||
TachographFileSession session,
|
|
||||||
DriverExtractionSession driverSession
|
|
||||||
) {
|
|
||||||
String sourceKind = session.metadata().driverCardFile() ? "DRIVER_CARD" : "VEHICLE_UNIT";
|
|
||||||
List<ResolvedActivityInterval> activityIntervals = resolveActivities(driverSession.cardActivityIntervals(), sourceKind);
|
|
||||||
return buildEsperDrivingIntervalEvents(session.sessionId(), driverSession.driverKey(), activityIntervals);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TachographEsperActivityIntervalEvent> buildEsperDrivingIntervalEvents(
|
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
ResolvedDriverTimeline timeline
|
|
||||||
) {
|
|
||||||
if (timeline == null) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
return buildEsperDrivingIntervalEvents(sessionId, driverKey, timeline.activityIntervals());
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TachographEsperVehicleUsageIntervalEvent> buildEsperVehicleUsageIntervalEvents(
|
|
||||||
TachographFileSession session,
|
|
||||||
DriverExtractionSession driverSession
|
|
||||||
) {
|
|
||||||
String sourceKind = session.metadata().driverCardFile() ? "DRIVER_CARD" : "VEHICLE_UNIT";
|
|
||||||
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(
|
|
||||||
session.sessionId(),
|
|
||||||
driverSession.driverKey(),
|
|
||||||
driverSession.cardVehicleUsageIntervals(),
|
|
||||||
sourceKind
|
|
||||||
);
|
|
||||||
return buildEsperVehicleUsageIntervalEvents(vehicleUsageIntervals);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TachographEsperVehicleUsageIntervalEvent> buildEsperVehicleUsageIntervalEvents(
|
|
||||||
ResolvedDriverTimeline timeline
|
|
||||||
) {
|
|
||||||
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<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> drivingInterruptionVehicleChangeIntervals,
|
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals
|
|
||||||
) {
|
|
||||||
if (drivingInterruptionVehicleChangeIntervals == null
|
|
||||||
|| drivingInterruptionVehicleChangeIntervals.isEmpty()
|
|
||||||
|| vuCardAbsentIntervals == null
|
|
||||||
|| vuCardAbsentIntervals.isEmpty()) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> result = new ArrayList<>();
|
|
||||||
executeWithRuntime(
|
|
||||||
configuration -> {
|
|
||||||
configuration.getCommon().addEventType(
|
|
||||||
"TachographDrivingInterruptionVehicleChangeIntervalInputEvent",
|
|
||||||
drivingInterruptionIntervalInputDefinition()
|
|
||||||
);
|
|
||||||
configuration.getCommon().addEventType(
|
|
||||||
"TachographVuCardAbsentIntervalInputEvent",
|
|
||||||
vuCardAbsentIntervalInputDefinition()
|
|
||||||
);
|
|
||||||
},
|
|
||||||
POTENTIAL_HOME_OVERNIGHT_STAY_INTERVAL_EVENTS_EPL_TEMPLATE,
|
|
||||||
"potentialHomeOvernightStayIntervals",
|
|
||||||
newData -> collectPotentialHomeOvernightStayIntervalEvents(newData, result),
|
|
||||||
runtime -> {
|
|
||||||
for (TachographEsperVuCardAbsentIntervalEvent interval : vuCardAbsentIntervals) {
|
|
||||||
runtime.getEventService().sendEventMap(
|
|
||||||
toVuCardAbsentIntervalInputMap(interval),
|
|
||||||
"TachographVuCardAbsentIntervalInputEvent"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for (TachographEsperDrivingInterruptionIntervalEvent interval : drivingInterruptionVehicleChangeIntervals) {
|
|
||||||
runtime.getEventService().sendEventMap(
|
|
||||||
toDrivingInterruptionIntervalInputMap(interval),
|
|
||||||
"TachographDrivingInterruptionVehicleChangeIntervalInputEvent"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TachographEsperDrivingInterruptionIntervalEvent> buildEsperDailyWeeklyRestCandidateIntervalEvents(
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals,
|
|
||||||
int minimumRestPeriodMinutes
|
|
||||||
) {
|
|
||||||
if (drivingInterruptionIntervals == null || drivingInterruptionIntervals.isEmpty()) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> result = new ArrayList<>();
|
|
||||||
executeWithRuntime(
|
|
||||||
configuration -> configuration.getCommon().addEventType(
|
|
||||||
"TachographDrivingInterruptionIntervalInputEvent",
|
|
||||||
drivingInterruptionIntervalInputDefinition()
|
|
||||||
),
|
|
||||||
renderDailyWeeklyRestCandidateIntervalEventsEpl(minimumRestPeriodMinutes),
|
|
||||||
"dailyWeeklyRestCandidateIntervals",
|
|
||||||
newData -> collectDrivingInterruptionIntervalEventsFromTimestamps(newData, result),
|
|
||||||
runtime -> {
|
|
||||||
for (TachographEsperDrivingInterruptionIntervalEvent interval : drivingInterruptionIntervals) {
|
|
||||||
runtime.getEventService().sendEventMap(
|
|
||||||
toDrivingInterruptionIntervalInputMap(interval),
|
|
||||||
"TachographDrivingInterruptionIntervalInputEvent"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TachographEsperVuCardAbsentIntervalEvent> buildEsperVuCardAbsentIntervalEvents(
|
|
||||||
TachographFileSession session,
|
|
||||||
DriverExtractionSession driverSession
|
|
||||||
) {
|
|
||||||
String sourceKind = session.metadata().driverCardFile() ? "DRIVER_CARD" : "VEHICLE_UNIT";
|
|
||||||
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals = mergeVehicleUsageIntervals(
|
|
||||||
session.sessionId(),
|
|
||||||
driverSession.driverKey(),
|
|
||||||
driverSession.cardVehicleUsageIntervals(),
|
|
||||||
sourceKind
|
|
||||||
);
|
|
||||||
return buildEsperVuCardAbsentIntervalEvents(vehicleUsageIntervals);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<TachographEsperVuCardAbsentIntervalEvent> buildEsperVuCardAbsentIntervalEvents(
|
|
||||||
ResolvedDriverTimeline timeline
|
|
||||||
) {
|
|
||||||
return timeline == null ? List.of() : buildEsperVuCardAbsentIntervalEvents(timeline.vehicleUsageIntervals());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<TachographEsperActivityIntervalEvent> buildEsperActivityIntervalEvents(
|
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
List<ResolvedActivityInterval> activityIntervals
|
|
||||||
) {
|
|
||||||
if (activityIntervals == null || activityIntervals.isEmpty()) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
List<TachographEsperActivityIntervalEvent> result = new ArrayList<>();
|
|
||||||
executeWithRuntime(
|
|
||||||
configuration -> configuration.getCommon().addEventType(
|
|
||||||
"TachographActivityIntervalInputEvent",
|
|
||||||
activityIntervalInputDefinition()
|
|
||||||
),
|
|
||||||
ACTIVITY_INTERVAL_EVENTS_EPL,
|
|
||||||
"activityIntervals",
|
|
||||||
newData -> collectActivityIntervalEvents(newData, result),
|
|
||||||
runtime -> {
|
|
||||||
for (ResolvedActivityInterval interval : activityIntervals) {
|
|
||||||
runtime.getEventService().sendEventMap(
|
|
||||||
toActivityIntervalInputMap(sessionId, driverKey, interval),
|
|
||||||
"TachographActivityIntervalInputEvent"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<TachographEsperActivityIntervalEvent> buildEsperDrivingIntervalEvents(
|
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
List<ResolvedActivityInterval> activityIntervals
|
|
||||||
) {
|
|
||||||
if (activityIntervals == null || activityIntervals.isEmpty()) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
List<TachographEsperActivityIntervalEvent> result = new ArrayList<>();
|
|
||||||
executeWithRuntime(
|
|
||||||
configuration -> configuration.getCommon().addEventType(
|
|
||||||
"TachographActivityIntervalInputEvent",
|
|
||||||
activityIntervalInputDefinition()
|
|
||||||
),
|
|
||||||
DRIVING_INTERVAL_EVENTS_EPL,
|
|
||||||
"drivingIntervals",
|
|
||||||
newData -> collectActivityIntervalEvents(newData, result),
|
|
||||||
runtime -> {
|
|
||||||
for (ResolvedActivityInterval interval : activityIntervals) {
|
|
||||||
runtime.getEventService().sendEventMap(
|
|
||||||
toActivityIntervalInputMap(sessionId, driverKey, interval),
|
|
||||||
"TachographActivityIntervalInputEvent"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<TachographEsperVehicleUsageIntervalEvent> buildEsperVehicleUsageIntervalEvents(
|
|
||||||
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals
|
|
||||||
) {
|
|
||||||
if (vehicleUsageIntervals == null || vehicleUsageIntervals.isEmpty()) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> result = new ArrayList<>();
|
|
||||||
executeWithRuntime(
|
|
||||||
configuration -> configuration.getCommon().addEventType(
|
|
||||||
"TachographVehicleUsageIntervalInputEvent",
|
|
||||||
vehicleUsageIntervalInputDefinition()
|
|
||||||
),
|
|
||||||
VEHICLE_USAGE_INTERVAL_EVENTS_EPL,
|
|
||||||
"vehicleUsageIntervals",
|
|
||||||
newData -> collectVehicleUsageIntervalEvents(newData, result),
|
|
||||||
runtime -> {
|
|
||||||
for (ResolvedVehicleUsageInterval interval : vehicleUsageIntervals) {
|
|
||||||
runtime.getEventService().sendEventMap(
|
|
||||||
toVehicleUsageIntervalInputMap(interval),
|
|
||||||
"TachographVehicleUsageIntervalInputEvent"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
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(
|
|
||||||
List<ResolvedVehicleUsageInterval> vehicleUsageIntervals
|
|
||||||
) {
|
|
||||||
if (vehicleUsageIntervals == null || vehicleUsageIntervals.size() < 2) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> result = new ArrayList<>();
|
|
||||||
executeWithRuntime(
|
|
||||||
configuration -> configuration.getCommon().addEventType(
|
|
||||||
"TachographVehicleUsageIntervalInputEvent",
|
|
||||||
vehicleUsageIntervalInputDefinition()
|
|
||||||
),
|
|
||||||
VU_CARD_ABSENT_INTERVAL_EVENTS_EPL,
|
|
||||||
"vuCardAbsentIntervals",
|
|
||||||
newData -> collectVuCardAbsentIntervalEvents(newData, result),
|
|
||||||
runtime -> {
|
|
||||||
for (ResolvedVehicleUsageInterval interval : vehicleUsageIntervals) {
|
|
||||||
runtime.getEventService().sendEventMap(
|
|
||||||
toVehicleUsageIntervalInputMap(interval),
|
|
||||||
"TachographVehicleUsageIntervalInputEvent"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ResolvedVehicleUsageInterval> mergeVehicleUsageIntervals(
|
private List<ResolvedVehicleUsageInterval> mergeVehicleUsageIntervals(
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
List<ExtractedCardVehicleUsageInterval> rawIntervals,
|
List<ExtractedCardVehicleUsageInterval> rawIntervals,
|
||||||
String sourceKind
|
String sourceKind
|
||||||
) {
|
) {
|
||||||
|
|
@ -455,8 +54,6 @@ public class DriverTimelineBuilder {
|
||||||
List<ResolvedVehicleUsageInterval> sorted = rawIntervals.stream()
|
List<ResolvedVehicleUsageInterval> sorted = rawIntervals.stream()
|
||||||
.filter(interval -> interval.from() != null && (interval.to() == null || interval.to().isAfter(interval.from())))
|
.filter(interval -> interval.from() != null && (interval.to() == null || interval.to().isAfter(interval.from())))
|
||||||
.map(interval -> ResolvedVehicleUsageInterval.resolved(
|
.map(interval -> ResolvedVehicleUsageInterval.resolved(
|
||||||
sessionId,
|
|
||||||
driverKey,
|
|
||||||
interval.intervalId(),
|
interval.intervalId(),
|
||||||
interval.from(),
|
interval.from(),
|
||||||
interval.to(),
|
interval.to(),
|
||||||
|
|
@ -482,8 +79,6 @@ public class DriverTimelineBuilder {
|
||||||
if (canMerge(current, next)) {
|
if (canMerge(current, next)) {
|
||||||
currentSources.addAll(next.sourceIntervalIds());
|
currentSources.addAll(next.sourceIntervalIds());
|
||||||
current = ResolvedVehicleUsageInterval.resolved(
|
current = ResolvedVehicleUsageInterval.resolved(
|
||||||
current.sessionId(),
|
|
||||||
current.driverKey(),
|
|
||||||
current.intervalId() + "+" + next.intervalId(),
|
current.intervalId() + "+" + next.intervalId(),
|
||||||
current.from(),
|
current.from(),
|
||||||
mergedTo(current.to(), next.to()),
|
mergedTo(current.to(), next.to()),
|
||||||
|
|
@ -625,417 +220,4 @@ public class DriverTimelineBuilder {
|
||||||
private OffsetDateTime mergeBoundary(OffsetDateTime endInclusive) {
|
private OffsetDateTime mergeBoundary(OffsetDateTime endInclusive) {
|
||||||
return endInclusive == null ? OffsetDateTime.MAX : endInclusive.plusSeconds(1);
|
return endInclusive == null ? OffsetDateTime.MAX : endInclusive.plusSeconds(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeWithRuntime(
|
|
||||||
Consumer<Configuration> configurationSetup,
|
|
||||||
String epl,
|
|
||||||
String statementName,
|
|
||||||
Consumer<EventBean[]> listener,
|
|
||||||
Consumer<EPRuntime> sender
|
|
||||||
) {
|
|
||||||
EPRuntime runtime = null;
|
|
||||||
try {
|
|
||||||
Configuration configuration = new Configuration();
|
|
||||||
configurationSetup.accept(configuration);
|
|
||||||
String runtimeUri = "eventhub-tachograph-projection-" + RUNTIME_COUNTER.incrementAndGet();
|
|
||||||
runtime = EPRuntimeProvider.getRuntime(runtimeUri, configuration);
|
|
||||||
|
|
||||||
CompilerArguments arguments = new CompilerArguments(configuration);
|
|
||||||
EPCompiled compiled = EPCompilerProvider.getCompiler().compile(epl, arguments);
|
|
||||||
EPDeployment deployment = runtime.getDeploymentService().deploy(compiled);
|
|
||||||
runtime.getDeploymentService()
|
|
||||||
.getStatement(deployment.getDeploymentId(), statementName)
|
|
||||||
.addListener((newData, oldData, statement, rt) -> listener.accept(newData));
|
|
||||||
|
|
||||||
sender.accept(runtime);
|
|
||||||
} catch (EPCompileException | EPDeployException e) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Cannot compile/deploy tachograph projection EPL for statement '" + statementName + "'",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
} finally {
|
|
||||||
if (runtime != null) {
|
|
||||||
runtime.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Object> activityIntervalInputDefinition() {
|
|
||||||
Map<String, Object> definition = new LinkedHashMap<>();
|
|
||||||
definition.put("sessionId", UUID.class);
|
|
||||||
definition.put("driverKey", String.class);
|
|
||||||
definition.put("intervalId", String.class);
|
|
||||||
definition.put("activityType", String.class);
|
|
||||||
definition.put("cardSlot", String.class);
|
|
||||||
definition.put("cardStatus", String.class);
|
|
||||||
definition.put("drivingStatus", String.class);
|
|
||||||
definition.put("registrationKey", String.class);
|
|
||||||
definition.put("vehicleKey", String.class);
|
|
||||||
definition.put("sourceKind", String.class);
|
|
||||||
definition.put("firstSourceIntervalId", String.class);
|
|
||||||
definition.put("lastSourceIntervalId", 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("sourceIntervalIds", java.util.List.class);
|
|
||||||
definition.put("synthetic", boolean.class);
|
|
||||||
definition.put("clippedToRequestedPeriod", boolean.class);
|
|
||||||
definition.put("level", String.class);
|
|
||||||
return definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Object> vehicleUsageIntervalInputDefinition() {
|
|
||||||
Map<String, Object> definition = new LinkedHashMap<>();
|
|
||||||
definition.put("sessionId", UUID.class);
|
|
||||||
definition.put("driverKey", String.class);
|
|
||||||
definition.put("intervalId", String.class);
|
|
||||||
definition.put("firstSourceIntervalId", String.class);
|
|
||||||
definition.put("lastSourceIntervalId", 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("odometerBeginKm", Long.class);
|
|
||||||
definition.put("odometerEndKm", Long.class);
|
|
||||||
definition.put("registrationKey", String.class);
|
|
||||||
definition.put("vehicleKey", String.class);
|
|
||||||
definition.put("sourceKind", String.class);
|
|
||||||
definition.put("sourceIntervalIds", java.util.List.class);
|
|
||||||
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(
|
|
||||||
UUID sessionId,
|
|
||||||
String driverKey,
|
|
||||||
ResolvedActivityInterval interval
|
|
||||||
) {
|
|
||||||
Map<String, Object> event = new LinkedHashMap<>();
|
|
||||||
event.put("sessionId", sessionId);
|
|
||||||
event.put("driverKey", driverKey);
|
|
||||||
event.put("intervalId", interval.intervalId());
|
|
||||||
event.put("activityType", interval.activityType());
|
|
||||||
event.put("cardSlot", interval.slot());
|
|
||||||
event.put("cardStatus", interval.cardStatus());
|
|
||||||
event.put("drivingStatus", interval.drivingStatus());
|
|
||||||
event.put("registrationKey", interval.registrationKey());
|
|
||||||
event.put("vehicleKey", interval.vehicleKey());
|
|
||||||
event.put("sourceKind", interval.sourceKind());
|
|
||||||
event.put("firstSourceIntervalId", firstSourceIntervalId(interval));
|
|
||||||
event.put("lastSourceIntervalId", lastSourceIntervalId(interval));
|
|
||||||
event.put("startedAt", interval.from());
|
|
||||||
event.put("endedAt", interval.to());
|
|
||||||
event.put("startedAtEpochSecond", interval.from().toEpochSecond());
|
|
||||||
event.put("endedAtEpochSecond", interval.to().toEpochSecond());
|
|
||||||
event.put("durationSeconds", interval.durationSeconds());
|
|
||||||
event.put("sourceIntervalIds", interval.sourceIntervalIds());
|
|
||||||
event.put("synthetic", interval.synthetic());
|
|
||||||
event.put("clippedToRequestedPeriod", interval.clippedToRequestedPeriod());
|
|
||||||
event.put("level", interval.level());
|
|
||||||
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) {
|
|
||||||
Map<String, Object> event = new LinkedHashMap<>();
|
|
||||||
event.put("sessionId", interval.sessionId());
|
|
||||||
event.put("driverKey", interval.driverKey());
|
|
||||||
event.put("intervalId", interval.intervalId());
|
|
||||||
event.put("firstSourceIntervalId", firstSourceIntervalId(interval));
|
|
||||||
event.put("lastSourceIntervalId", lastSourceIntervalId(interval));
|
|
||||||
event.put("startedAt", interval.from());
|
|
||||||
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("odometerBeginKm", interval.odometerBeginKm());
|
|
||||||
event.put("odometerEndKm", interval.odometerEndKm());
|
|
||||||
event.put("registrationKey", interval.registrationKey());
|
|
||||||
event.put("vehicleKey", interval.vehicleKey());
|
|
||||||
event.put("sourceKind", interval.sourceKind());
|
|
||||||
event.put("sourceIntervalIds", interval.sourceIntervalIds());
|
|
||||||
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) {
|
|
||||||
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(
|
|
||||||
EventBean[] newData,
|
|
||||||
List<TachographEsperActivityIntervalEvent> target
|
|
||||||
) {
|
|
||||||
if (newData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (EventBean event : newData) {
|
|
||||||
target.add(new TachographEsperActivityIntervalEvent(
|
|
||||||
(UUID) event.get("sessionId"),
|
|
||||||
(String) event.get("driverKey"),
|
|
||||||
(String) event.get("intervalId"),
|
|
||||||
(String) event.get("activityType"),
|
|
||||||
(String) event.get("cardSlot"),
|
|
||||||
(String) event.get("cardStatus"),
|
|
||||||
(String) event.get("drivingStatus"),
|
|
||||||
(String) event.get("registrationKey"),
|
|
||||||
(String) event.get("vehicleKey"),
|
|
||||||
(String) event.get("sourceKind"),
|
|
||||||
(OffsetDateTime) event.get("startedAt"),
|
|
||||||
(OffsetDateTime) event.get("endedAt"),
|
|
||||||
(Long) event.get("durationSeconds"),
|
|
||||||
castSourceIntervalIds(event.get("sourceIntervalIds")),
|
|
||||||
(Boolean) event.get("synthetic"),
|
|
||||||
(Boolean) event.get("clippedToRequestedPeriod"),
|
|
||||||
(String) event.get("level")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectVehicleUsageIntervalEvents(
|
|
||||||
EventBean[] newData,
|
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> target
|
|
||||||
) {
|
|
||||||
if (newData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (EventBean event : newData) {
|
|
||||||
target.add(new TachographEsperVehicleUsageIntervalEvent(
|
|
||||||
(UUID) event.get("sessionId"),
|
|
||||||
(String) event.get("driverKey"),
|
|
||||||
(String) event.get("intervalId"),
|
|
||||||
(OffsetDateTime) event.get("startedAt"),
|
|
||||||
(OffsetDateTime) event.get("endedAt"),
|
|
||||||
(Long) event.get("durationSeconds"),
|
|
||||||
(Long) event.get("odometerBeginKm"),
|
|
||||||
(Long) event.get("odometerEndKm"),
|
|
||||||
(String) event.get("registrationKey"),
|
|
||||||
(String) event.get("vehicleKey"),
|
|
||||||
(String) event.get("sourceKind"),
|
|
||||||
castSourceIntervalIds(event.get("sourceIntervalIds"))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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("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("nextVehicleKey")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectVuCardAbsentIntervalEvents(
|
|
||||||
EventBean[] newData,
|
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> target
|
|
||||||
) {
|
|
||||||
if (newData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (EventBean event : newData) {
|
|
||||||
long startedAtEpochSecond = (Long) event.get("startedAtEpochSecond");
|
|
||||||
long endedAtEpochSecond = (Long) event.get("endedAtEpochSecond");
|
|
||||||
target.add(new TachographEsperVuCardAbsentIntervalEvent(
|
|
||||||
(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("previousUsageIntervalId"),
|
|
||||||
(String) event.get("nextUsageIntervalId"),
|
|
||||||
(String) event.get("previousRegistrationKey"),
|
|
||||||
(String) event.get("nextRegistrationKey"),
|
|
||||||
(String) event.get("previousVehicleKey"),
|
|
||||||
(String) event.get("nextVehicleKey")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
private List<String> castSourceIntervalIds(Object value) {
|
|
||||||
return value == null ? List.of() : List.copyOf((List<String>) value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String loadResource(String path) {
|
|
||||||
try {
|
|
||||||
ClassPathResource resource = new ClassPathResource(path);
|
|
||||||
return StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException 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)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String renderDailyWeeklyRestCandidateIntervalEventsEpl(int minimumRestPeriodMinutes) {
|
|
||||||
long thresholdSeconds = Math.max(1, minimumRestPeriodMinutes) * 60L;
|
|
||||||
return DAILY_WEEKLY_REST_CANDIDATE_INTERVAL_EVENTS_EPL_TEMPLATE.replace(
|
|
||||||
"${MINIMUM_REST_PERIOD_THRESHOLD_SECONDS}",
|
|
||||||
Long.toString(thresholdSeconds)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
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.TachographOperatingPeriodsProcessingRequest;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
||||||
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
|
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
|
||||||
|
|
@ -12,12 +10,7 @@ import at.procon.eventhub.tachographfilesession.model.ProcessedOperatingPeriod;
|
||||||
import at.procon.eventhub.tachographfilesession.model.ProcessedShiftDrivingEvaluation;
|
import at.procon.eventhub.tachographfilesession.model.ProcessedShiftDrivingEvaluation;
|
||||||
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.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.TachographEsperVuCardAbsentIntervalEvent;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -120,334 +113,6 @@ public class TachographFileSessionProcessingService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TachographEsperDriverProcessingResultDto getEsperDriverProcessingResults(
|
|
||||||
UUID sessionId,
|
|
||||||
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, null)
|
|
||||||
: request;
|
|
||||||
TachographFileSession session = repository.find(sessionId)
|
|
||||||
.orElseThrow(() -> new TachographFileSessionNotFoundException(sessionId));
|
|
||||||
DriverExtractionSession driver = session.driversByKey().get(driverKey);
|
|
||||||
if (driver == null) {
|
|
||||||
throw new DriverNotFoundInSessionException(sessionId, driverKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolvedDriverTimeline timeline = driverTimelineBuilder.build(session, driver);
|
|
||||||
OffsetDateTime requestedFrom = effectiveRequest.occurredFrom() == null ? timeline.loadedFrom() : utc(effectiveRequest.occurredFrom());
|
|
||||||
OffsetDateTime requestedTo = effectiveRequest.occurredTo() == null ? timeline.loadedTo() : utc(effectiveRequest.occurredTo());
|
|
||||||
if (requestedFrom != null && requestedTo != null && requestedTo.isBefore(requestedFrom)) {
|
|
||||||
throw new IllegalArgumentException("occurredTo must not be before occurredFrom.");
|
|
||||||
}
|
|
||||||
int significantDrivingMinutes = resolveEsperSignificantDrivingMinutes(effectiveRequest);
|
|
||||||
int minimumRestPeriodMinutes = resolveMinimumRestPeriodMinutes(effectiveRequest);
|
|
||||||
|
|
||||||
List<TachographEsperActivityIntervalEvent> activityIntervals = clipEsperActivityIntervalEvents(
|
|
||||||
driverTimelineBuilder.buildEsperActivityIntervalEvents(sessionId, driverKey, timeline),
|
|
||||||
requestedFrom,
|
|
||||||
requestedTo
|
|
||||||
);
|
|
||||||
List<TachographEsperActivityIntervalEvent> drivingIntervals = clipEsperActivityIntervalEvents(
|
|
||||||
driverTimelineBuilder.buildEsperDrivingIntervalEvents(sessionId, driverKey, timeline),
|
|
||||||
requestedFrom,
|
|
||||||
requestedTo
|
|
||||||
);
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> rawDrivingInterruptionIntervals =
|
|
||||||
driverTimelineBuilder.buildEsperDrivingInterruptionIntervalEvents(
|
|
||||||
sessionId,
|
|
||||||
driverKey,
|
|
||||||
timeline,
|
|
||||||
significantDrivingMinutes
|
|
||||||
);
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals =
|
|
||||||
clipEsperDrivingInterruptionIntervalEvents(
|
|
||||||
rawDrivingInterruptionIntervals,
|
|
||||||
requestedFrom,
|
|
||||||
requestedTo
|
|
||||||
);
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> rawDailyWeeklyRestCandidateIntervals =
|
|
||||||
driverTimelineBuilder.buildEsperDailyWeeklyRestCandidateIntervalEvents(
|
|
||||||
rawDrivingInterruptionIntervals,
|
|
||||||
minimumRestPeriodMinutes
|
|
||||||
);
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> dailyWeeklyRestCandidateIntervals =
|
|
||||||
clipEsperDrivingInterruptionIntervalEvents(
|
|
||||||
rawDailyWeeklyRestCandidateIntervals,
|
|
||||||
requestedFrom,
|
|
||||||
requestedTo
|
|
||||||
);
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> rawDrivingInterruptionVehicleChangeIntervals =
|
|
||||||
driverTimelineBuilder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents(
|
|
||||||
rawDailyWeeklyRestCandidateIntervals
|
|
||||||
);
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals =
|
|
||||||
clipEsperDrivingInterruptionIntervalEvents(
|
|
||||||
rawDrivingInterruptionVehicleChangeIntervals,
|
|
||||||
requestedFrom,
|
|
||||||
requestedTo
|
|
||||||
);
|
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> rawVuCardAbsentIntervals =
|
|
||||||
driverTimelineBuilder.buildEsperVuCardAbsentIntervalEvents(timeline);
|
|
||||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> potentialHomeOvernightStayIntervals =
|
|
||||||
clipEsperPotentialHomeOvernightStayIntervalEvents(
|
|
||||||
driverTimelineBuilder.buildEsperPotentialHomeOvernightStayIntervalEvents(
|
|
||||||
rawDrivingInterruptionVehicleChangeIntervals,
|
|
||||||
rawVuCardAbsentIntervals
|
|
||||||
),
|
|
||||||
rawVuCardAbsentIntervals,
|
|
||||||
requestedFrom,
|
|
||||||
requestedTo
|
|
||||||
);
|
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageIntervals = clipEsperVehicleUsageIntervalEvents(
|
|
||||||
driverTimelineBuilder.buildEsperVehicleUsageIntervalEvents(timeline),
|
|
||||||
requestedFrom,
|
|
||||||
requestedTo
|
|
||||||
);
|
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> vuCardAbsentIntervals = clipEsperVuCardAbsentIntervalEvents(
|
|
||||||
rawVuCardAbsentIntervals,
|
|
||||||
requestedFrom,
|
|
||||||
requestedTo
|
|
||||||
);
|
|
||||||
|
|
||||||
return new TachographEsperDriverProcessingResultDto(
|
|
||||||
sessionId,
|
|
||||||
driverKey,
|
|
||||||
timeline.sourceKind(),
|
|
||||||
timeline.loadedFrom(),
|
|
||||||
timeline.loadedTo(),
|
|
||||||
requestedFrom,
|
|
||||||
requestedTo,
|
|
||||||
activityIntervals.size(),
|
|
||||||
drivingIntervals.size(),
|
|
||||||
drivingInterruptionIntervals.size(),
|
|
||||||
drivingInterruptionVehicleChangeIntervals.size(),
|
|
||||||
dailyWeeklyRestCandidateIntervals.size(),
|
|
||||||
potentialHomeOvernightStayIntervals.size(),
|
|
||||||
vehicleUsageIntervals.size(),
|
|
||||||
vuCardAbsentIntervals.size(),
|
|
||||||
activityIntervals,
|
|
||||||
drivingIntervals,
|
|
||||||
drivingInterruptionIntervals,
|
|
||||||
drivingInterruptionVehicleChangeIntervals,
|
|
||||||
dailyWeeklyRestCandidateIntervals,
|
|
||||||
potentialHomeOvernightStayIntervals,
|
|
||||||
vehicleUsageIntervals,
|
|
||||||
vuCardAbsentIntervals,
|
|
||||||
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.previousRegistrationKey(),
|
|
||||||
interval.nextRegistrationKey(),
|
|
||||||
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<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
|
||||||
|
|
@ -986,18 +651,6 @@ public class TachographFileSessionProcessingService {
|
||||||
: request.gapDetectionToleranceSeconds();
|
: request.gapDetectionToleranceSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int resolveEsperSignificantDrivingMinutes(TachographEsperEventsProcessingRequest request) {
|
|
||||||
return request.significantDrivingMinutes() == null
|
|
||||||
? properties.getTachographFileSession().getProcessing().getSignificantDrivingMinutes()
|
|
||||||
: 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.",
|
||||||
|
|
@ -1007,43 +660,6 @@ public class TachographFileSessionProcessingService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> esperProjectionNotes() {
|
|
||||||
return List.of(
|
|
||||||
"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 interruption intervals are gaps between consecutive driving intervals longer than the configured significant-driving threshold.",
|
|
||||||
"Driving interruption vehicle-change intervals are daily/weekly rest candidates where previousRegistrationKey differs from nextRegistrationKey.",
|
|
||||||
"Daily/weekly rest candidate intervals are driving interruption intervals longer than the configured minimum rest-period threshold.",
|
|
||||||
"Potential home overnight stay intervals are vehicle-change daily/weekly rest candidates where VU card-absent overlap covers at least 95% of the candidate interval.",
|
|
||||||
"VU card-absent intervals are gaps between consecutive normalized vehicle-usage intervals for the same driver.",
|
|
||||||
"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."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
@name('activityIntervals')
|
|
||||||
select
|
|
||||||
sessionId,
|
|
||||||
driverKey,
|
|
||||||
intervalId,
|
|
||||||
activityType,
|
|
||||||
cardSlot,
|
|
||||||
cardStatus,
|
|
||||||
drivingStatus,
|
|
||||||
registrationKey,
|
|
||||||
vehicleKey,
|
|
||||||
sourceKind,
|
|
||||||
startedAt,
|
|
||||||
endedAt,
|
|
||||||
durationSeconds,
|
|
||||||
sourceIntervalIds,
|
|
||||||
synthetic,
|
|
||||||
clippedToRequestedPeriod,
|
|
||||||
level
|
|
||||||
from TachographActivityIntervalInputEvent
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
@name('dailyWeeklyRestCandidateIntervals')
|
|
||||||
select *
|
|
||||||
from TachographDrivingInterruptionIntervalInputEvent(durationSeconds > ${MINIMUM_REST_PERIOD_THRESHOLD_SECONDS});
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
create schema SignificantDrivingInterval(
|
|
||||||
sessionId java.util.UUID,
|
|
||||||
driverKey string,
|
|
||||||
firstSourceIntervalId string,
|
|
||||||
lastSourceIntervalId string,
|
|
||||||
startedAtEpochSecond long,
|
|
||||||
endedAtEpochSecond long,
|
|
||||||
durationSeconds long,
|
|
||||||
registrationKey string,
|
|
||||||
vehicleKey string
|
|
||||||
);
|
|
||||||
|
|
||||||
create schema DrivingInterruptionInterval(
|
|
||||||
sessionId java.util.UUID,
|
|
||||||
driverKey string,
|
|
||||||
startedAtEpochSecond long,
|
|
||||||
endedAtEpochSecond long,
|
|
||||||
durationSeconds long,
|
|
||||||
previousDrivingSourceIntervalId string,
|
|
||||||
nextDrivingSourceIntervalId string,
|
|
||||||
previousRegistrationKey string,
|
|
||||||
nextRegistrationKey string,
|
|
||||||
previousVehicleKey string,
|
|
||||||
nextVehicleKey string
|
|
||||||
);
|
|
||||||
|
|
||||||
insert into SignificantDrivingInterval
|
|
||||||
select
|
|
||||||
sessionId,
|
|
||||||
driverKey,
|
|
||||||
firstSourceIntervalId,
|
|
||||||
lastSourceIntervalId,
|
|
||||||
startedAtEpochSecond,
|
|
||||||
endedAtEpochSecond,
|
|
||||||
durationSeconds,
|
|
||||||
registrationKey,
|
|
||||||
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.registrationKey as previousRegistrationKey,
|
|
||||||
next.registrationKey as nextRegistrationKey,
|
|
||||||
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;
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
@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
|
|
||||||
);
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
@name('drivingIntervals')
|
|
||||||
select
|
|
||||||
sessionId,
|
|
||||||
driverKey,
|
|
||||||
intervalId,
|
|
||||||
activityType,
|
|
||||||
cardSlot,
|
|
||||||
cardStatus,
|
|
||||||
drivingStatus,
|
|
||||||
registrationKey,
|
|
||||||
vehicleKey,
|
|
||||||
sourceKind,
|
|
||||||
startedAt,
|
|
||||||
endedAt,
|
|
||||||
durationSeconds,
|
|
||||||
sourceIntervalIds,
|
|
||||||
synthetic,
|
|
||||||
clippedToRequestedPeriod,
|
|
||||||
level
|
|
||||||
from TachographActivityIntervalInputEvent(activityType = 'DRIVE')
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
@name('potentialHomeOvernightStayIntervals')
|
|
||||||
select
|
|
||||||
c.sessionId as sessionId,
|
|
||||||
c.driverKey as driverKey,
|
|
||||||
c.startedAt as startedAt,
|
|
||||||
c.endedAt as endedAt,
|
|
||||||
c.durationSeconds as durationSeconds,
|
|
||||||
sum(
|
|
||||||
case
|
|
||||||
when u.startedAtEpochSecond <= c.startedAtEpochSecond and u.endedAtEpochSecond >= c.endedAtEpochSecond
|
|
||||||
then c.durationSeconds
|
|
||||||
when u.startedAtEpochSecond <= c.startedAtEpochSecond
|
|
||||||
then u.endedAtEpochSecond - c.startedAtEpochSecond
|
|
||||||
when u.endedAtEpochSecond >= c.endedAtEpochSecond
|
|
||||||
then c.endedAtEpochSecond - u.startedAtEpochSecond
|
|
||||||
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
|
||||||
end
|
|
||||||
) as unknownDurationSeconds,
|
|
||||||
(sum(
|
|
||||||
case
|
|
||||||
when u.startedAtEpochSecond <= c.startedAtEpochSecond and u.endedAtEpochSecond >= c.endedAtEpochSecond
|
|
||||||
then c.durationSeconds
|
|
||||||
when u.startedAtEpochSecond <= c.startedAtEpochSecond
|
|
||||||
then u.endedAtEpochSecond - c.startedAtEpochSecond
|
|
||||||
when u.endedAtEpochSecond >= c.endedAtEpochSecond
|
|
||||||
then c.endedAtEpochSecond - u.startedAtEpochSecond
|
|
||||||
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
|
||||||
end
|
|
||||||
) * 100.0d) / c.durationSeconds as unknownCoveragePercent,
|
|
||||||
c.previousDrivingSourceIntervalId as previousDrivingSourceIntervalId,
|
|
||||||
c.nextDrivingSourceIntervalId as nextDrivingSourceIntervalId,
|
|
||||||
c.previousRegistrationKey as previousRegistrationKey,
|
|
||||||
c.nextRegistrationKey as nextRegistrationKey,
|
|
||||||
c.previousVehicleKey as previousVehicleKey,
|
|
||||||
c.nextVehicleKey as nextVehicleKey
|
|
||||||
from TachographDrivingInterruptionVehicleChangeIntervalInputEvent as c unidirectional,
|
|
||||||
TachographVuCardAbsentIntervalInputEvent#keepall as u
|
|
||||||
where u.driverKey = c.driverKey
|
|
||||||
and u.startedAtEpochSecond < c.endedAtEpochSecond
|
|
||||||
and u.endedAtEpochSecond > c.startedAtEpochSecond
|
|
||||||
group by
|
|
||||||
c.sessionId,
|
|
||||||
c.driverKey,
|
|
||||||
c.startedAt,
|
|
||||||
c.endedAt,
|
|
||||||
c.startedAtEpochSecond,
|
|
||||||
c.endedAtEpochSecond,
|
|
||||||
c.durationSeconds,
|
|
||||||
c.previousDrivingSourceIntervalId,
|
|
||||||
c.nextDrivingSourceIntervalId,
|
|
||||||
c.previousRegistrationKey,
|
|
||||||
c.nextRegistrationKey,
|
|
||||||
c.previousVehicleKey,
|
|
||||||
c.nextVehicleKey
|
|
||||||
having sum(
|
|
||||||
case
|
|
||||||
when u.startedAtEpochSecond <= c.startedAtEpochSecond and u.endedAtEpochSecond >= c.endedAtEpochSecond
|
|
||||||
then c.durationSeconds
|
|
||||||
when u.startedAtEpochSecond <= c.startedAtEpochSecond
|
|
||||||
then u.endedAtEpochSecond - c.startedAtEpochSecond
|
|
||||||
when u.endedAtEpochSecond >= c.endedAtEpochSecond
|
|
||||||
then c.endedAtEpochSecond - u.startedAtEpochSecond
|
|
||||||
else u.endedAtEpochSecond - u.startedAtEpochSecond
|
|
||||||
end
|
|
||||||
) * 100L >= c.durationSeconds * 95L;
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
@name('vehicleUsageIntervals')
|
|
||||||
select
|
|
||||||
sessionId,
|
|
||||||
driverKey,
|
|
||||||
intervalId,
|
|
||||||
startedAt,
|
|
||||||
endedAt,
|
|
||||||
durationSeconds,
|
|
||||||
odometerBeginKm,
|
|
||||||
odometerEndKm,
|
|
||||||
registrationKey,
|
|
||||||
vehicleKey,
|
|
||||||
sourceKind,
|
|
||||||
sourceIntervalIds
|
|
||||||
from TachographVehicleUsageIntervalInputEvent
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
create context PerDriver partition by driverKey from TachographVehicleUsageIntervalInputEvent;
|
|
||||||
|
|
||||||
create schema VuCardAbsentInterval(
|
|
||||||
sessionId java.util.UUID,
|
|
||||||
driverKey string,
|
|
||||||
startedAtEpochSecond long,
|
|
||||||
endedAtEpochSecond long,
|
|
||||||
durationSeconds long,
|
|
||||||
previousUsageIntervalId string,
|
|
||||||
nextUsageIntervalId string,
|
|
||||||
previousRegistrationKey string,
|
|
||||||
nextRegistrationKey string,
|
|
||||||
previousVehicleKey string,
|
|
||||||
nextVehicleKey string
|
|
||||||
);
|
|
||||||
|
|
||||||
context PerDriver
|
|
||||||
create window PreviousVehicleUsageInterval#lastevent as TachographVehicleUsageIntervalInputEvent;
|
|
||||||
|
|
||||||
@Priority(30)
|
|
||||||
context PerDriver
|
|
||||||
on TachographVehicleUsageIntervalInputEvent as next
|
|
||||||
insert into VuCardAbsentInterval
|
|
||||||
select
|
|
||||||
priorInterval.sessionId as sessionId,
|
|
||||||
priorInterval.driverKey as driverKey,
|
|
||||||
priorInterval.endedAtEpochSecond + 1L as startedAtEpochSecond,
|
|
||||||
next.startedAtEpochSecond as endedAtEpochSecond,
|
|
||||||
next.startedAtEpochSecond - (priorInterval.endedAtEpochSecond + 1L) as durationSeconds,
|
|
||||||
priorInterval.lastSourceIntervalId as previousUsageIntervalId,
|
|
||||||
next.firstSourceIntervalId as nextUsageIntervalId,
|
|
||||||
priorInterval.registrationKey as previousRegistrationKey,
|
|
||||||
next.registrationKey as nextRegistrationKey,
|
|
||||||
priorInterval.vehicleKey as previousVehicleKey,
|
|
||||||
next.vehicleKey as nextVehicleKey
|
|
||||||
from PreviousVehicleUsageInterval as priorInterval
|
|
||||||
where priorInterval.endedAt is not null
|
|
||||||
and next.startedAt is not null
|
|
||||||
and next.startedAtEpochSecond > priorInterval.endedAtEpochSecond + 1L;
|
|
||||||
|
|
||||||
@Priority(20)
|
|
||||||
context PerDriver
|
|
||||||
on TachographVehicleUsageIntervalInputEvent
|
|
||||||
delete from PreviousVehicleUsageInterval;
|
|
||||||
|
|
||||||
@Priority(10)
|
|
||||||
context PerDriver
|
|
||||||
on TachographVehicleUsageIntervalInputEvent as current
|
|
||||||
insert into PreviousVehicleUsageInterval
|
|
||||||
select *;
|
|
||||||
|
|
||||||
@name('vuCardAbsentIntervals')
|
|
||||||
select * from VuCardAbsentInterval;
|
|
||||||
|
|
@ -9,8 +9,6 @@ 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.TachographFileDriverDetailDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographFileDriverDetailDto;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
||||||
|
|
@ -19,14 +17,8 @@ import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionDeleteR
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionListDriversResponse;
|
import at.procon.eventhub.tachographfilesession.dto.TachographFileSessionListDriversResponse;
|
||||||
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.TachographEsperDrivingInterruptionIntervalEvent;
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
|
||||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionProcessingService;
|
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionProcessingService;
|
||||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionService;
|
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionService;
|
||||||
import java.time.OffsetDateTime;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -66,148 +58,6 @@ 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(
|
|
||||||
eq(sessionId),
|
|
||||||
eq("12:123"),
|
|
||||||
org.mockito.ArgumentMatchers.any(TachographEsperEventsProcessingRequest.class)
|
|
||||||
))
|
|
||||||
.thenReturn(new TachographEsperDriverProcessingResultDto(
|
|
||||||
sessionId,
|
|
||||||
"12:123",
|
|
||||||
"DRIVER_CARD",
|
|
||||||
OffsetDateTime.parse("2026-05-12T08:00:00Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-12T12:00:00Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-12T08:30:00Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-12T11:30:00Z"),
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
List.of(new TachographEsperActivityIntervalEvent(
|
|
||||||
sessionId,
|
|
||||||
"12:123",
|
|
||||||
"ACT-1",
|
|
||||||
"WORK",
|
|
||||||
"DRIVER",
|
|
||||||
"INSERTED",
|
|
||||||
"SINGLE",
|
|
||||||
"12:REG-1",
|
|
||||||
"VIN-1",
|
|
||||||
"DRIVER_CARD",
|
|
||||||
OffsetDateTime.parse("2026-05-12T08:00:00Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-12T09:00:00Z"),
|
|
||||||
3600L,
|
|
||||||
List.of("ACT-1"),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
"RAW_INTERVAL"
|
|
||||||
)),
|
|
||||||
List.of(new TachographEsperActivityIntervalEvent(
|
|
||||||
sessionId,
|
|
||||||
"12:123",
|
|
||||||
"ACT-2",
|
|
||||||
"DRIVE",
|
|
||||||
"DRIVER",
|
|
||||||
"INSERTED",
|
|
||||||
"SINGLE",
|
|
||||||
"12:REG-1",
|
|
||||||
"VIN-1",
|
|
||||||
"DRIVER_CARD",
|
|
||||||
OffsetDateTime.parse("2026-05-12T09:00:00Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-12T10:00:00Z"),
|
|
||||||
3600L,
|
|
||||||
List.of("ACT-2"),
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
"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",
|
|
||||||
"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 TachographEsperDrivingInterruptionIntervalEvent(
|
|
||||||
sessionId,
|
|
||||||
"12:123",
|
|
||||||
OffsetDateTime.parse("2026-05-12T10:00:00Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-12T22:00:00Z"),
|
|
||||||
43_200L,
|
|
||||||
"ACT-2",
|
|
||||||
"ACT-3",
|
|
||||||
"12:REG-1",
|
|
||||||
"12:REG-2",
|
|
||||||
"VIN-1",
|
|
||||||
"VIN-2"
|
|
||||||
)),
|
|
||||||
List.of(new TachographEsperPotentialHomeOvernightStayIntervalEvent(
|
|
||||||
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-2"
|
|
||||||
)),
|
|
||||||
List.of(new TachographEsperVehicleUsageIntervalEvent(
|
|
||||||
sessionId,
|
|
||||||
"12:123",
|
|
||||||
"CVU-1",
|
|
||||||
OffsetDateTime.parse("2026-05-12T08:00:00Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-12T10:00:00Z"),
|
|
||||||
7200L,
|
|
||||||
100L,
|
|
||||||
200L,
|
|
||||||
"12:REG-1",
|
|
||||||
"VIN-1",
|
|
||||||
"DRIVER_CARD",
|
|
||||||
List.of("CVU-1")
|
|
||||||
)),
|
|
||||||
List.of(new TachographEsperVuCardAbsentIntervalEvent(
|
|
||||||
sessionId,
|
|
||||||
"12:123",
|
|
||||||
OffsetDateTime.parse("2026-05-12T10:00:01Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-12T11:00:00Z"),
|
|
||||||
3599L,
|
|
||||||
"CVU-1",
|
|
||||||
"CVU-2",
|
|
||||||
"12:REG-1",
|
|
||||||
"12:REG-2",
|
|
||||||
"VIN-1",
|
|
||||||
"VIN-2"
|
|
||||||
)),
|
|
||||||
List.of("note")
|
|
||||||
));
|
|
||||||
when(processingService.evaluateOperatingPeriods(eq(sessionId), eq("12:123"), org.mockito.ArgumentMatchers.any(TachographOperatingPeriodsProcessingRequest.class)))
|
when(processingService.evaluateOperatingPeriods(eq(sessionId), eq("12:123"), org.mockito.ArgumentMatchers.any(TachographOperatingPeriodsProcessingRequest.class)))
|
||||||
.thenReturn(new TachographOperatingPeriodsProcessingResultDto(
|
.thenReturn(new TachographOperatingPeriodsProcessingResultDto(
|
||||||
sessionId,
|
sessionId,
|
||||||
|
|
@ -254,37 +104,6 @@ class TachographFileSessionControllerTest {
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.driverKey").value("12:123"));
|
.andExpect(jsonPath("$.driverKey").value("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,
|
|
||||||
"minimumRestPeriodMinutes": 720
|
|
||||||
}
|
|
||||||
"""))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("$.driverKey").value("12:123"))
|
|
||||||
.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("$.drivingInterruptionIntervalCount").value(1))
|
|
||||||
.andExpect(jsonPath("$.drivingInterruptionVehicleChangeIntervalCount").value(1))
|
|
||||||
.andExpect(jsonPath("$.dailyWeeklyRestCandidateIntervalCount").value(1))
|
|
||||||
.andExpect(jsonPath("$.potentialHomeOvernightStayIntervalCount").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].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"));
|
|
||||||
|
|
||||||
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")
|
||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.content("""
|
.content("""
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,6 @@ import at.procon.eventhub.tachographfilesession.model.ExtractionWarning;
|
||||||
import at.procon.eventhub.tachographfilesession.model.ExtractedSupportEvent;
|
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.TachographEsperDrivingInterruptionIntervalEvent;
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperPotentialHomeOvernightStayIntervalEvent;
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVuCardAbsentIntervalEvent;
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographEsperVehicleUsageIntervalEvent;
|
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata;
|
import at.procon.eventhub.tachographfilesession.model.TachographFileSessionMetadata;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
@ -105,8 +100,6 @@ class DriverTimelineBuilderTest {
|
||||||
|
|
||||||
assertThat(timeline.sourceKind()).isEqualTo("DRIVER_CARD");
|
assertThat(timeline.sourceKind()).isEqualTo("DRIVER_CARD");
|
||||||
assertThat(timeline.vehicleUsageIntervals()).hasSize(1);
|
assertThat(timeline.vehicleUsageIntervals()).hasSize(1);
|
||||||
assertThat(timeline.vehicleUsageIntervals().get(0).sessionId()).isEqualTo(session.sessionId());
|
|
||||||
assertThat(timeline.vehicleUsageIntervals().get(0).driverKey()).isEqualTo("12:123");
|
|
||||||
assertThat(timeline.vehicleUsageIntervals().get(0).from()).isEqualTo(OffsetDateTime.parse("2026-05-01T00:00:00Z"));
|
assertThat(timeline.vehicleUsageIntervals().get(0).from()).isEqualTo(OffsetDateTime.parse("2026-05-01T00:00:00Z"));
|
||||||
assertThat(timeline.vehicleUsageIntervals().get(0).to()).isEqualTo(OffsetDateTime.parse("2026-05-02T08:00:00Z"));
|
assertThat(timeline.vehicleUsageIntervals().get(0).to()).isEqualTo(OffsetDateTime.parse("2026-05-02T08:00:00Z"));
|
||||||
assertThat(timeline.activityIntervals()).hasSize(1);
|
assertThat(timeline.activityIntervals()).hasSize(1);
|
||||||
|
|
@ -176,389 +169,9 @@ class DriverTimelineBuilderTest {
|
||||||
ResolvedDriverTimeline timeline = builder.build(session, driver);
|
ResolvedDriverTimeline timeline = builder.build(session, driver);
|
||||||
|
|
||||||
assertThat(timeline.vehicleUsageIntervals()).hasSize(1);
|
assertThat(timeline.vehicleUsageIntervals()).hasSize(1);
|
||||||
assertThat(timeline.vehicleUsageIntervals().get(0).sessionId()).isEqualTo(session.sessionId());
|
|
||||||
assertThat(timeline.vehicleUsageIntervals().get(0).driverKey()).isEqualTo("12:123");
|
|
||||||
assertThat(timeline.vehicleUsageIntervals().get(0).from()).isEqualTo(OffsetDateTime.parse("2026-05-01T00:00:00Z"));
|
assertThat(timeline.vehicleUsageIntervals().get(0).from()).isEqualTo(OffsetDateTime.parse("2026-05-01T00:00:00Z"));
|
||||||
assertThat(timeline.vehicleUsageIntervals().get(0).to()).isNull();
|
assertThat(timeline.vehicleUsageIntervals().get(0).to()).isNull();
|
||||||
assertThat(timeline.vehicleUsageIntervals().get(0).sourceIntervalIds()).containsExactly("CVU-1", "CVU-2");
|
assertThat(timeline.vehicleUsageIntervals().get(0).sourceIntervalIds()).containsExactly("CVU-1", "CVU-2");
|
||||||
assertThat(timeline.loadedTo()).isEqualTo(OffsetDateTime.parse("2026-05-02T09:00:00Z"));
|
assertThat(timeline.loadedTo()).isEqualTo(OffsetDateTime.parse("2026-05-02T09:00:00Z"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void buildsEsperActivityAndDrivingIntervalEventsFromResolvedTimeline() {
|
|
||||||
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-01T09:00:00Z"),
|
|
||||||
"WORK",
|
|
||||||
"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: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, 0, 0, 0, 0),
|
|
||||||
List.of(),
|
|
||||||
Instant.now(),
|
|
||||||
Instant.now().plus(4, ChronoUnit.HOURS)
|
|
||||||
);
|
|
||||||
|
|
||||||
List<TachographEsperActivityIntervalEvent> activityEvents =
|
|
||||||
builder.buildEsperActivityIntervalEvents(session, driver);
|
|
||||||
List<TachographEsperActivityIntervalEvent> drivingEvents =
|
|
||||||
builder.buildEsperDrivingIntervalEvents(session, driver);
|
|
||||||
|
|
||||||
assertThat(activityEvents).hasSize(2);
|
|
||||||
assertThat(activityEvents).extracting(TachographEsperActivityIntervalEvent::activityType)
|
|
||||||
.containsExactly("WORK", "DRIVE");
|
|
||||||
assertThat(activityEvents).extracting(TachographEsperActivityIntervalEvent::driverKey)
|
|
||||||
.containsOnly("12:123");
|
|
||||||
|
|
||||||
assertThat(drivingEvents).hasSize(1);
|
|
||||||
assertThat(drivingEvents.get(0).intervalId()).isEqualTo("ACT-2");
|
|
||||||
assertThat(drivingEvents.get(0).activityType()).isEqualTo("DRIVE");
|
|
||||||
assertThat(drivingEvents.get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T09:00:00Z"));
|
|
||||||
assertThat(drivingEvents.get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T10:30:00Z"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void buildsEsperVehicleUsageIntervalEventsFromResolvedTimeline() {
|
|
||||||
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",
|
|
||||||
"a"
|
|
||||||
),
|
|
||||||
new ExtractedCardVehicleUsageInterval(
|
|
||||||
"CVU-2",
|
|
||||||
OffsetDateTime.parse("2026-05-01T12:00:00Z"),
|
|
||||||
null,
|
|
||||||
201L,
|
|
||||||
null,
|
|
||||||
"12:REG-1",
|
|
||||||
"VIN-1",
|
|
||||||
"b"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
List.of(),
|
|
||||||
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, 0, 2, 0, 0, 0),
|
|
||||||
List.of(),
|
|
||||||
Instant.now(),
|
|
||||||
Instant.now().plus(4, ChronoUnit.HOURS)
|
|
||||||
);
|
|
||||||
|
|
||||||
List<TachographEsperVehicleUsageIntervalEvent> vehicleUsageEvents =
|
|
||||||
builder.buildEsperVehicleUsageIntervalEvents(session, driver);
|
|
||||||
|
|
||||||
assertThat(vehicleUsageEvents).hasSize(2);
|
|
||||||
assertThat(vehicleUsageEvents).extracting(TachographEsperVehicleUsageIntervalEvent::driverKey)
|
|
||||||
.containsOnly("12:123");
|
|
||||||
assertThat(vehicleUsageEvents).extracting(TachographEsperVehicleUsageIntervalEvent::sessionId)
|
|
||||||
.containsOnly(session.sessionId());
|
|
||||||
assertThat(vehicleUsageEvents.get(0).intervalId()).isEqualTo("CVU-1");
|
|
||||||
assertThat(vehicleUsageEvents.get(1).intervalId()).isEqualTo("CVU-2");
|
|
||||||
assertThat(vehicleUsageEvents.get(1).endedAt()).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void buildsEsperVuCardAbsentIntervalEventsFromVehicleUsageGaps() {
|
|
||||||
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",
|
|
||||||
"a"
|
|
||||||
),
|
|
||||||
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",
|
|
||||||
"b"
|
|
||||||
),
|
|
||||||
new ExtractedCardVehicleUsageInterval(
|
|
||||||
"CVU-3",
|
|
||||||
OffsetDateTime.parse("2026-05-01T13:00:01Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-01T14:00:00Z"),
|
|
||||||
261L,
|
|
||||||
320L,
|
|
||||||
"12:REG-2",
|
|
||||||
"VIN-2",
|
|
||||||
"c"
|
|
||||||
)
|
|
||||||
),
|
|
||||||
List.of(),
|
|
||||||
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, 0, 3, 0, 0, 0),
|
|
||||||
List.of(),
|
|
||||||
Instant.now(),
|
|
||||||
Instant.now().plus(4, ChronoUnit.HOURS)
|
|
||||||
);
|
|
||||||
|
|
||||||
List<TachographEsperVuCardAbsentIntervalEvent> absentIntervals =
|
|
||||||
builder.buildEsperVuCardAbsentIntervalEvents(session, driver);
|
|
||||||
|
|
||||||
assertThat(absentIntervals).hasSize(1);
|
|
||||||
assertThat(absentIntervals.get(0).sessionId()).isEqualTo(session.sessionId());
|
|
||||||
assertThat(absentIntervals.get(0).driverKey()).isEqualTo("12:123");
|
|
||||||
assertThat(absentIntervals.get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:01Z"));
|
|
||||||
assertThat(absentIntervals.get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T12:00:00Z"));
|
|
||||||
assertThat(absentIntervals.get(0).durationSeconds()).isEqualTo(3599L);
|
|
||||||
assertThat(absentIntervals.get(0).previousUsageIntervalId()).isEqualTo("CVU-1");
|
|
||||||
assertThat(absentIntervals.get(0).nextUsageIntervalId()).isEqualTo("CVU-2");
|
|
||||||
assertThat(absentIntervals.get(0).previousRegistrationKey()).isEqualTo("12:REG-1");
|
|
||||||
assertThat(absentIntervals.get(0).nextRegistrationKey()).isEqualTo("12:REG-2");
|
|
||||||
assertThat(absentIntervals.get(0).previousVehicleKey()).isEqualTo("VIN-1");
|
|
||||||
assertThat(absentIntervals.get(0).nextVehicleKey()).isEqualTo("VIN-2");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void buildsDailyWeeklyRestCandidateIntervalsFromDrivingInterruptionIntervals() {
|
|
||||||
UUID sessionId = UUID.randomUUID();
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionIntervals = List.of(
|
|
||||||
new TachographEsperDrivingInterruptionIntervalEvent(
|
|
||||||
sessionId,
|
|
||||||
"12:123",
|
|
||||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-01T20:00:00Z"),
|
|
||||||
36_000L,
|
|
||||||
"ACT-1",
|
|
||||||
"ACT-2",
|
|
||||||
"12:REG-1",
|
|
||||||
"12:REG-1",
|
|
||||||
"VIN-1",
|
|
||||||
"VIN-1"
|
|
||||||
),
|
|
||||||
new TachographEsperDrivingInterruptionIntervalEvent(
|
|
||||||
sessionId,
|
|
||||||
"12:123",
|
|
||||||
OffsetDateTime.parse("2026-05-02T10:00:00Z"),
|
|
||||||
OffsetDateTime.parse("2026-05-02T18:00:00Z"),
|
|
||||||
28_800L,
|
|
||||||
"ACT-3",
|
|
||||||
"ACT-4",
|
|
||||||
"12:REG-1",
|
|
||||||
"12:REG-1",
|
|
||||||
"VIN-1",
|
|
||||||
"VIN-1"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> candidates =
|
|
||||||
builder.buildEsperDailyWeeklyRestCandidateIntervalEvents(drivingInterruptionIntervals, 540);
|
|
||||||
|
|
||||||
assertThat(candidates).hasSize(1);
|
|
||||||
assertThat(candidates.get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T10:00:00Z"));
|
|
||||||
assertThat(candidates.get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T20:00:00Z"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
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).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).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-2",
|
|
||||||
"VIN-1",
|
|
||||||
"VIN-2"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
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<TachographEsperDrivingInterruptionIntervalEvent> dailyWeeklyRestCandidateIntervals =
|
|
||||||
builder.buildEsperDailyWeeklyRestCandidateIntervalEvents(interruptions, 720);
|
|
||||||
List<TachographEsperDrivingInterruptionIntervalEvent> drivingInterruptionVehicleChangeIntervals =
|
|
||||||
builder.buildEsperDrivingInterruptionVehicleChangeIntervalEvents(dailyWeeklyRestCandidateIntervals);
|
|
||||||
List<TachographEsperPotentialHomeOvernightStayIntervalEvent> intervals =
|
|
||||||
builder.buildEsperPotentialHomeOvernightStayIntervalEvents(
|
|
||||||
drivingInterruptionVehicleChangeIntervals,
|
|
||||||
vuCardAbsentIntervals
|
|
||||||
);
|
|
||||||
|
|
||||||
assertThat(drivingInterruptionVehicleChangeIntervals).hasSize(1);
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ 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.TachographOperatingPeriodsProcessingRequest;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingRequest;
|
||||||
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
import at.procon.eventhub.tachographfilesession.dto.TachographOperatingPeriodsProcessingResultDto;
|
||||||
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
|
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
|
||||||
|
|
@ -23,251 +21,6 @@ import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
class TachographFileSessionProcessingServiceTest {
|
class TachographFileSessionProcessingServiceTest {
|
||||||
|
|
||||||
@Test
|
|
||||||
void returnsEsperDriverProcessingResultsFromSessionTimeline() {
|
|
||||||
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"), "WORK", "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"), "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", 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());
|
|
||||||
|
|
||||||
assertThat(result.sourceKind()).isEqualTo("DRIVER_CARD");
|
|
||||||
assertThat(result.activityIntervalCount()).isEqualTo(2);
|
|
||||||
assertThat(result.drivingIntervalCount()).isEqualTo(1);
|
|
||||||
assertThat(result.drivingInterruptionIntervalCount()).isEqualTo(0);
|
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(0);
|
|
||||||
assertThat(result.dailyWeeklyRestCandidateIntervalCount()).isEqualTo(0);
|
|
||||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
|
||||||
assertThat(result.vehicleUsageIntervalCount()).isEqualTo(2);
|
|
||||||
assertThat(result.vuCardAbsentIntervalCount()).isEqualTo(1);
|
|
||||||
assertThat(result.vuCardAbsentIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:01Z"));
|
|
||||||
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,
|
|
||||||
720
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
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.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(0);
|
|
||||||
assertThat(result.dailyWeeklyRestCandidateIntervalCount()).isEqualTo(0);
|
|
||||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(0);
|
|
||||||
assertThat(result.drivingInterruptionIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T09:00:00Z"));
|
|
||||||
assertThat(result.drivingInterruptionIntervals().get(0).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).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
|
|
||||||
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-2", "VIN-2", "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.dailyWeeklyRestCandidateIntervalCount()).isEqualTo(1);
|
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervalCount()).isEqualTo(1);
|
|
||||||
assertThat(result.dailyWeeklyRestCandidateIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:00Z"));
|
|
||||||
assertThat(result.dailyWeeklyRestCandidateIntervals().get(0).endedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T23:00:00Z"));
|
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).startedAt()).isEqualTo(OffsetDateTime.parse("2026-05-01T11:00:00Z"));
|
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).previousRegistrationKey()).isEqualTo("12:REG-1");
|
|
||||||
assertThat(result.drivingInterruptionVehicleChangeIntervals().get(0).nextRegistrationKey()).isEqualTo("12:REG-2");
|
|
||||||
assertThat(result.potentialHomeOvernightStayIntervalCount()).isEqualTo(1);
|
|
||||||
assertThat(result.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