Adjust runtime interval loading and result projections
This commit is contained in:
parent
7457872d51
commit
6bef8becf9
|
|
@ -55,6 +55,7 @@ public class EventHubEventReadRepository {
|
|||
request.tenantKey(),
|
||||
request.occurredFrom(),
|
||||
request.occurredTo(),
|
||||
request.includeIntersectingIntervals() && "TACHOGRAPH".equalsIgnoreCase(providerKey),
|
||||
request.driverSourceEntityId(),
|
||||
request.driverCardNation(),
|
||||
request.driverCardNumber(),
|
||||
|
|
@ -76,6 +77,7 @@ public class EventHubEventReadRepository {
|
|||
request.tenantKey(),
|
||||
request.occurredFrom(),
|
||||
request.occurredTo(),
|
||||
request.includeIntersectingIntervals() && "TACHOGRAPH".equalsIgnoreCase(providerKey),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
|
|
@ -92,6 +94,7 @@ public class EventHubEventReadRepository {
|
|||
String tenantKey,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals,
|
||||
String driverSourceEntityId,
|
||||
String driverCardNation,
|
||||
String driverCardNumber,
|
||||
|
|
@ -104,6 +107,7 @@ public class EventHubEventReadRepository {
|
|||
) {
|
||||
StringBuilder sql = new StringBuilder(
|
||||
"""
|
||||
with candidate_events as (
|
||||
select
|
||||
event.id,
|
||||
event.external_source_event_id,
|
||||
|
|
@ -223,14 +227,6 @@ public class EventHubEventReadRepository {
|
|||
}
|
||||
sql.append(")");
|
||||
}
|
||||
if (occurredFrom != null) {
|
||||
sql.append(" and event.occurred_at >= ?");
|
||||
params.add(occurredFrom);
|
||||
}
|
||||
if (occurredTo != null) {
|
||||
sql.append(" and event.occurred_at <= ?");
|
||||
params.add(occurredTo);
|
||||
}
|
||||
if (driverSourceEntityId != null) {
|
||||
sql.append(
|
||||
"""
|
||||
|
|
@ -307,7 +303,9 @@ public class EventHubEventReadRepository {
|
|||
}
|
||||
}
|
||||
|
||||
sql.append(" order by event.occurred_at, event.event_domain, event.event_type, event.lifecycle, event.id");
|
||||
sql.append("\n)");
|
||||
appendTemporalFilter(sql, params, occurredFrom, occurredTo, includeIntersectingIntervals);
|
||||
sql.append(" order by occurred_at, event_domain, event_type, lifecycle, id");
|
||||
|
||||
return jdbcTemplate.query(
|
||||
sql.toString(),
|
||||
|
|
@ -316,6 +314,109 @@ public class EventHubEventReadRepository {
|
|||
);
|
||||
}
|
||||
|
||||
private void appendTemporalFilter(
|
||||
StringBuilder sql,
|
||||
List<Object> params,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
if (!includeIntersectingIntervals) {
|
||||
sql.append("\nselect * from candidate_events");
|
||||
appendPointWindowFilter(sql, params, occurredFrom, occurredTo);
|
||||
return;
|
||||
}
|
||||
if (occurredFrom == null && occurredTo == null) {
|
||||
sql.append("\nselect * from candidate_events");
|
||||
return;
|
||||
}
|
||||
|
||||
sql.append(
|
||||
"""
|
||||
|
||||
, interval_events as (
|
||||
select
|
||||
'DRIVER_ACTIVITY' as interval_scope,
|
||||
coalesce(payload #>> '{raw,intervalId}', payload #>> '{raw,sourceRowId}', external_source_event_id) as interval_key,
|
||||
min(case when lifecycle = 'START' then occurred_at end) as started_at,
|
||||
max(case when lifecycle = 'END' then occurred_at end) as ended_at
|
||||
from candidate_events
|
||||
where event_domain = 'DRIVER_ACTIVITY'
|
||||
group by 1, 2
|
||||
union all
|
||||
select
|
||||
'DRIVER_CARD' as interval_scope,
|
||||
coalesce(payload #>> '{raw,intervalId}', payload #>> '{raw,sourceRowId}', external_source_event_id) as interval_key,
|
||||
min(case when event_type = 'CARD_INSERTED' then occurred_at end) as started_at,
|
||||
max(case when event_type = 'CARD_WITHDRAWN' then occurred_at end) as ended_at
|
||||
from candidate_events
|
||||
where event_domain = 'DRIVER_CARD'
|
||||
and event_type in ('CARD_INSERTED', 'CARD_WITHDRAWN')
|
||||
group by 1, 2
|
||||
)
|
||||
select ce.*
|
||||
from candidate_events ce
|
||||
left join interval_events ie
|
||||
on ie.interval_key = coalesce(ce.payload #>> '{raw,intervalId}', ce.payload #>> '{raw,sourceRowId}', ce.external_source_event_id)
|
||||
and (
|
||||
(ie.interval_scope = 'DRIVER_ACTIVITY' and ce.event_domain = 'DRIVER_ACTIVITY')
|
||||
or (ie.interval_scope = 'DRIVER_CARD'
|
||||
and ce.event_domain = 'DRIVER_CARD'
|
||||
and ce.event_type in ('CARD_INSERTED', 'CARD_WITHDRAWN'))
|
||||
)
|
||||
"""
|
||||
);
|
||||
|
||||
StringBuilder where = new StringBuilder();
|
||||
appendPointWindowPredicate(where, params, "ce.occurred_at", occurredFrom, occurredTo);
|
||||
if (where.length() == 0) {
|
||||
where.append("\nwhere 1 = 0");
|
||||
}
|
||||
where.append("\n or (ie.interval_key is not null");
|
||||
if (occurredTo != null) {
|
||||
where.append("\n and ie.started_at <= ?");
|
||||
params.add(occurredTo);
|
||||
}
|
||||
if (occurredFrom != null) {
|
||||
where.append("\n and coalesce(ie.ended_at, 'infinity'::timestamptz) >= ?");
|
||||
params.add(occurredFrom);
|
||||
}
|
||||
where.append("\n )");
|
||||
sql.append(where);
|
||||
}
|
||||
|
||||
private void appendPointWindowFilter(
|
||||
StringBuilder sql,
|
||||
List<Object> params,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
) {
|
||||
StringBuilder where = new StringBuilder();
|
||||
appendPointWindowPredicate(where, params, "occurred_at", occurredFrom, occurredTo);
|
||||
sql.append(where);
|
||||
}
|
||||
|
||||
private void appendPointWindowPredicate(
|
||||
StringBuilder sql,
|
||||
List<Object> params,
|
||||
String occurredAtColumn,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
) {
|
||||
boolean hasCondition = false;
|
||||
if (occurredFrom != null) {
|
||||
sql.append(hasCondition ? " and " : "\nwhere ");
|
||||
sql.append(occurredAtColumn).append(" >= ?");
|
||||
params.add(occurredFrom);
|
||||
hasCondition = true;
|
||||
}
|
||||
if (occurredTo != null) {
|
||||
sql.append(hasCondition ? " and " : "\nwhere ");
|
||||
sql.append(occurredAtColumn).append(" <= ?");
|
||||
params.add(occurredTo);
|
||||
}
|
||||
}
|
||||
|
||||
private EventHubEventDto mapEvent(ResultSet rs) throws SQLException {
|
||||
DriverRefDto driverRef = driverRef(rs);
|
||||
VehicleRefDto vehicleRef = vehicleRef(rs);
|
||||
|
|
|
|||
|
|
@ -47,4 +47,48 @@ public record DriverWorkingTimeProcessingResultDto(
|
|||
List<DriverWorkingTimeSupportGeoEvent> supportGeoEvents,
|
||||
List<String> notes
|
||||
) {
|
||||
public DriverWorkingTimeProcessingResultDto withIncludedIntervals(
|
||||
boolean includeActivityIntervals,
|
||||
boolean includeDrivingIntervals
|
||||
) {
|
||||
if (includeActivityIntervals && includeDrivingIntervals) {
|
||||
return this;
|
||||
}
|
||||
return new DriverWorkingTimeProcessingResultDto(
|
||||
sessionId,
|
||||
driverKey,
|
||||
sourceKind,
|
||||
loadedFrom,
|
||||
loadedTo,
|
||||
requestedFrom,
|
||||
requestedTo,
|
||||
activityIntervalCount,
|
||||
drivingIntervalCount,
|
||||
drivingInterruptionIntervalCount,
|
||||
drivingInterruptionVehicleChangeIntervalCount,
|
||||
dailyWeeklyRestCandidateIntervalCount,
|
||||
dailyWeeklyRestCandidateCoverageIntervalCount,
|
||||
unclassifiedDailyWeeklyRestCandidateCoverageIntervalCount,
|
||||
potentialHomeOvernightStayIntervalCount,
|
||||
potentialInVehicleOvernightStayIntervalCount,
|
||||
potentialInVehicleTripIntervalCount,
|
||||
vehicleUsageIntervalCount,
|
||||
vuCardAbsentIntervalCount,
|
||||
supportGeoEventCount,
|
||||
includeActivityIntervals ? activityIntervals : List.of(),
|
||||
includeDrivingIntervals ? drivingIntervals : List.of(),
|
||||
drivingInterruptionIntervals,
|
||||
drivingInterruptionVehicleChangeIntervals,
|
||||
dailyWeeklyRestCandidateIntervals,
|
||||
dailyWeeklyRestCandidateCoverageIntervals,
|
||||
unclassifiedDailyWeeklyRestCandidateCoverageIntervals,
|
||||
potentialHomeOvernightStayIntervals,
|
||||
potentialInVehicleOvernightStayIntervals,
|
||||
potentialInVehicleTripIntervals,
|
||||
vehicleUsageIntervals,
|
||||
vuCardAbsentIntervals,
|
||||
supportGeoEvents,
|
||||
notes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,11 @@ public record UnifiedRuntimeProcessingApiRequest(
|
|||
OffsetDateTime occurredTo,
|
||||
Boolean expandVehicleEvents,
|
||||
Integer vehicleExpansionPaddingMinutes,
|
||||
Boolean includeIntersectingIntervals,
|
||||
Integer significantDrivingMinutes,
|
||||
Integer minimumRestPeriodMinutes
|
||||
Integer minimumRestPeriodMinutes,
|
||||
Boolean includeActivityIntervals,
|
||||
Boolean includeDrivingIntervals
|
||||
) {
|
||||
public UnifiedRuntimeProcessingRequest toRuntimeRequest() {
|
||||
return new UnifiedRuntimeProcessingRequest(
|
||||
|
|
@ -52,7 +55,16 @@ public record UnifiedRuntimeProcessingApiRequest(
|
|||
occurredFrom,
|
||||
occurredTo,
|
||||
expandVehicleEvents == null || expandVehicleEvents,
|
||||
vehicleExpansionPaddingMinutes == null ? 0 : Math.max(0, vehicleExpansionPaddingMinutes)
|
||||
vehicleExpansionPaddingMinutes == null ? 0 : Math.max(0, vehicleExpansionPaddingMinutes),
|
||||
includeIntersectingIntervals == null || includeIntersectingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
public boolean includeActivityIntervalsOrDefault() {
|
||||
return includeActivityIntervals != null && includeActivityIntervals;
|
||||
}
|
||||
|
||||
public boolean includeDrivingIntervalsOrDefault() {
|
||||
return includeDrivingIntervals != null && includeDrivingIntervals;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,11 @@ public class DriverWorkingTimeDerivedProjectionsModule implements RuntimeProcess
|
|||
for (Map.Entry<String, DriverWorkingTimePreparedInput> entry : preparedInputs.entrySet()) {
|
||||
DriverWorkingTimePreparedInput preparedInput = entry.getValue();
|
||||
DriverWorkingTimeProcessingResultDto projection =
|
||||
workingTimeProcessingCore.process(preparedInput.processingInput());
|
||||
workingTimeProcessingCore.process(preparedInput.processingInput())
|
||||
.withIncludedIntervals(
|
||||
scopeRequest.includeActivityIntervalsOrDefault(),
|
||||
scopeRequest.includeDrivingIntervalsOrDefault()
|
||||
);
|
||||
warnings.addAll(preparedInput.partition().warnings());
|
||||
UnifiedRuntimeProcessingRequest driverRequest = broadBundle.request().withDriverKey(preparedInput.driverKey());
|
||||
driverResults.put(preparedInput.driverKey(), new UnifiedRuntimeDerivedProjectionResultDto(
|
||||
|
|
|
|||
|
|
@ -168,6 +168,8 @@ public class DriverWorkingTimeRuntimeProcessingPlan implements RuntimeProcessing
|
|||
"minimumRestPeriodMinutes",
|
||||
"attachVehicleOnlyEvents",
|
||||
"vehicleEvidencePaddingMinutes",
|
||||
"includeActivityIntervals",
|
||||
"includeDrivingIntervals",
|
||||
"includePartitionDebug"
|
||||
);
|
||||
}
|
||||
|
|
@ -368,6 +370,10 @@ public class DriverWorkingTimeRuntimeProcessingPlan implements RuntimeProcessing
|
|||
|
||||
Integer significantDrivingMinutes = integerParameter(parameters, "significantDrivingMinutes", sourceSelection.significantDrivingMinutes());
|
||||
Integer minimumRestPeriodMinutes = integerParameter(parameters, "minimumRestPeriodMinutes", sourceSelection.minimumRestPeriodMinutes());
|
||||
boolean includeActivityIntervals = booleanParameter(parameters, "includeActivityIntervals",
|
||||
sourceSelection.includeActivityIntervalsOrDefault());
|
||||
boolean includeDrivingIntervals = booleanParameter(parameters, "includeDrivingIntervals",
|
||||
sourceSelection.includeDrivingIntervalsOrDefault());
|
||||
boolean attachVehicleOnlyEvents = booleanParameter(parameters, "attachVehicleOnlyEvents",
|
||||
partitioning == null ? sourceSelection.expandVehicleEvents() == null || sourceSelection.expandVehicleEvents() : partitioning.attachVehicleEvidenceOrDefault());
|
||||
Integer vehicleEvidencePaddingMinutes = nonNegativeIntegerParameter(parameters, "vehicleEvidencePaddingMinutes",
|
||||
|
|
@ -395,8 +401,11 @@ public class DriverWorkingTimeRuntimeProcessingPlan implements RuntimeProcessing
|
|||
sourceSelection.occurredTo(),
|
||||
attachVehicleOnlyEvents,
|
||||
vehicleEvidencePaddingMinutes,
|
||||
sourceSelection.includeIntersectingIntervals(),
|
||||
significantDrivingMinutes,
|
||||
minimumRestPeriodMinutes
|
||||
minimumRestPeriodMinutes,
|
||||
includeActivityIntervals,
|
||||
includeDrivingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -178,8 +178,11 @@ public class RuntimeTachographParityValidationService {
|
|||
request.occurredTo(),
|
||||
request.expandVehicleEventsOrDefault(),
|
||||
request.vehicleExpansionPaddingMinutesOrDefault(),
|
||||
null,
|
||||
request.significantDrivingMinutes(),
|
||||
request.minimumRestPeriodMinutes()
|
||||
request.minimumRestPeriodMinutes(),
|
||||
false,
|
||||
false
|
||||
);
|
||||
RuntimeEventPartitioningApiRequest partitioning = new RuntimeEventPartitioningApiRequest(
|
||||
RuntimeEventPartitioningStrategy.DRIVER,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ public record UnifiedDriverEventsRequest(
|
|||
String registrationNation,
|
||||
String registrationNumber,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
public UnifiedDriverEventsRequest {
|
||||
Objects.requireNonNull(sourceFamily, "sourceFamily must not be null");
|
||||
|
|
@ -59,6 +60,16 @@ public record UnifiedDriverEventsRequest(
|
|||
String driverKey,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
) {
|
||||
return forTachographFileSession(sessionId, driverKey, occurredFrom, occurredTo, false);
|
||||
}
|
||||
|
||||
public static UnifiedDriverEventsRequest forTachographFileSession(
|
||||
UUID sessionId,
|
||||
String driverKey,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
return new UnifiedDriverEventsRequest(
|
||||
UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION,
|
||||
|
|
@ -74,7 +85,8 @@ public record UnifiedDriverEventsRequest(
|
|||
null,
|
||||
null,
|
||||
occurredFrom,
|
||||
occurredTo
|
||||
occurredTo,
|
||||
includeIntersectingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +105,29 @@ public record UnifiedDriverEventsRequest(
|
|||
driverCardNumber,
|
||||
occurredFrom,
|
||||
occurredTo,
|
||||
List.of()
|
||||
List.of(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static UnifiedDriverEventsRequest forTachographDbDriver(
|
||||
String tenantKey,
|
||||
String driverSourceEntityId,
|
||||
String driverCardNation,
|
||||
String driverCardNumber,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
return forTachographDbDriver(
|
||||
tenantKey,
|
||||
driverSourceEntityId,
|
||||
driverCardNation,
|
||||
driverCardNumber,
|
||||
occurredFrom,
|
||||
occurredTo,
|
||||
List.of(),
|
||||
includeIntersectingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +139,28 @@ public record UnifiedDriverEventsRequest(
|
|||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
List<String> sourceKinds
|
||||
) {
|
||||
return forTachographDbDriver(
|
||||
tenantKey,
|
||||
driverSourceEntityId,
|
||||
driverCardNation,
|
||||
driverCardNumber,
|
||||
occurredFrom,
|
||||
occurredTo,
|
||||
sourceKinds,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static UnifiedDriverEventsRequest forTachographDbDriver(
|
||||
String tenantKey,
|
||||
String driverSourceEntityId,
|
||||
String driverCardNation,
|
||||
String driverCardNumber,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
List<String> sourceKinds,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
return new UnifiedDriverEventsRequest(
|
||||
UnifiedEventSourceFamily.TACHOGRAPH_DB,
|
||||
|
|
@ -120,7 +176,8 @@ public record UnifiedDriverEventsRequest(
|
|||
null,
|
||||
null,
|
||||
occurredFrom,
|
||||
occurredTo
|
||||
occurredTo,
|
||||
includeIntersectingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +204,8 @@ public record UnifiedDriverEventsRequest(
|
|||
registrationNation,
|
||||
registrationNumber,
|
||||
occurredFrom,
|
||||
occurredTo
|
||||
occurredTo,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +231,8 @@ public record UnifiedDriverEventsRequest(
|
|||
null,
|
||||
null,
|
||||
occurredFrom,
|
||||
occurredTo
|
||||
occurredTo,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
boolean expandVehicleEvents,
|
||||
int vehicleExpansionPaddingMinutes
|
||||
int vehicleExpansionPaddingMinutes,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
public UnifiedRuntimeProcessingRequest {
|
||||
if (sourceFamilies == null || sourceFamilies.isEmpty()) {
|
||||
|
|
@ -118,7 +119,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
occurredTo,
|
||||
UnifiedRuntimeEventBackend.SOURCE_DB,
|
||||
true,
|
||||
0
|
||||
0,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +145,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
occurredTo,
|
||||
UnifiedRuntimeEventBackend.SOURCE_DB,
|
||||
expandVehicleEvents,
|
||||
vehicleExpansionPaddingMinutes
|
||||
vehicleExpansionPaddingMinutes,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -158,6 +161,34 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
UnifiedRuntimeEventBackend eventBackend,
|
||||
boolean expandVehicleEvents,
|
||||
int vehicleExpansionPaddingMinutes
|
||||
) {
|
||||
return forDriver(
|
||||
tenantKey,
|
||||
sourceFamilies,
|
||||
driverSourceEntityId,
|
||||
driverCardNation,
|
||||
driverCardNumber,
|
||||
occurredFrom,
|
||||
occurredTo,
|
||||
eventBackend,
|
||||
expandVehicleEvents,
|
||||
vehicleExpansionPaddingMinutes,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
public static UnifiedRuntimeProcessingRequest forDriver(
|
||||
String tenantKey,
|
||||
Set<UnifiedEventSourceFamily> sourceFamilies,
|
||||
String driverSourceEntityId,
|
||||
String driverCardNation,
|
||||
String driverCardNumber,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
UnifiedRuntimeEventBackend eventBackend,
|
||||
boolean expandVehicleEvents,
|
||||
int vehicleExpansionPaddingMinutes,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
return new UnifiedRuntimeProcessingRequest(
|
||||
null,
|
||||
|
|
@ -178,7 +209,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
occurredFrom,
|
||||
occurredTo,
|
||||
expandVehicleEvents,
|
||||
vehicleExpansionPaddingMinutes
|
||||
vehicleExpansionPaddingMinutes,
|
||||
includeIntersectingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +244,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
occurredFrom,
|
||||
occurredTo,
|
||||
expandVehicleEvents,
|
||||
vehicleExpansionPaddingMinutes
|
||||
vehicleExpansionPaddingMinutes,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -243,7 +276,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
occurredFrom,
|
||||
occurredTo,
|
||||
expandVehicleEvents,
|
||||
vehicleExpansionPaddingMinutes
|
||||
vehicleExpansionPaddingMinutes,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +308,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
occurredFrom,
|
||||
occurredTo,
|
||||
expandVehicleEvents,
|
||||
vehicleExpansionPaddingMinutes
|
||||
vehicleExpansionPaddingMinutes,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -305,7 +340,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
occurredFrom,
|
||||
occurredTo,
|
||||
expandVehicleEvents,
|
||||
vehicleExpansionPaddingMinutes
|
||||
vehicleExpansionPaddingMinutes,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -348,7 +384,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
occurredFrom,
|
||||
occurredTo,
|
||||
expandVehicleEvents,
|
||||
vehicleExpansionPaddingMinutes
|
||||
vehicleExpansionPaddingMinutes,
|
||||
includeIntersectingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ public record UnifiedVehicleEventsRequest(
|
|||
String registrationNation,
|
||||
String registrationNumber,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
public UnifiedVehicleEventsRequest {
|
||||
Objects.requireNonNull(sourceFamily, "sourceFamily must not be null");
|
||||
|
|
@ -46,6 +47,28 @@ public record UnifiedVehicleEventsRequest(
|
|||
String registrationNumber,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
) {
|
||||
return forTachographFileSession(
|
||||
sessionId,
|
||||
vehicleSourceEntityId,
|
||||
vin,
|
||||
registrationNation,
|
||||
registrationNumber,
|
||||
occurredFrom,
|
||||
occurredTo,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static UnifiedVehicleEventsRequest forTachographFileSession(
|
||||
UUID sessionId,
|
||||
String vehicleSourceEntityId,
|
||||
String vin,
|
||||
String registrationNation,
|
||||
String registrationNumber,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
return new UnifiedVehicleEventsRequest(
|
||||
UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION,
|
||||
|
|
@ -57,7 +80,8 @@ public record UnifiedVehicleEventsRequest(
|
|||
registrationNation,
|
||||
registrationNumber,
|
||||
occurredFrom,
|
||||
occurredTo
|
||||
occurredTo,
|
||||
includeIntersectingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +102,31 @@ public record UnifiedVehicleEventsRequest(
|
|||
registrationNumber,
|
||||
occurredFrom,
|
||||
occurredTo,
|
||||
List.of()
|
||||
List.of(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static UnifiedVehicleEventsRequest forTachographDb(
|
||||
String tenantKey,
|
||||
String vehicleSourceEntityId,
|
||||
String vin,
|
||||
String registrationNation,
|
||||
String registrationNumber,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
return forTachographDb(
|
||||
tenantKey,
|
||||
vehicleSourceEntityId,
|
||||
vin,
|
||||
registrationNation,
|
||||
registrationNumber,
|
||||
occurredFrom,
|
||||
occurredTo,
|
||||
List.of(),
|
||||
includeIntersectingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -91,6 +139,30 @@ public record UnifiedVehicleEventsRequest(
|
|||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
List<String> sourceKinds
|
||||
) {
|
||||
return forTachographDb(
|
||||
tenantKey,
|
||||
vehicleSourceEntityId,
|
||||
vin,
|
||||
registrationNation,
|
||||
registrationNumber,
|
||||
occurredFrom,
|
||||
occurredTo,
|
||||
sourceKinds,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static UnifiedVehicleEventsRequest forTachographDb(
|
||||
String tenantKey,
|
||||
String vehicleSourceEntityId,
|
||||
String vin,
|
||||
String registrationNation,
|
||||
String registrationNumber,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
List<String> sourceKinds,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
return new UnifiedVehicleEventsRequest(
|
||||
UnifiedEventSourceFamily.TACHOGRAPH_DB,
|
||||
|
|
@ -102,7 +174,8 @@ public record UnifiedVehicleEventsRequest(
|
|||
registrationNation,
|
||||
registrationNumber,
|
||||
occurredFrom,
|
||||
occurredTo
|
||||
occurredTo,
|
||||
includeIntersectingIntervals
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +198,8 @@ public record UnifiedVehicleEventsRequest(
|
|||
registrationNation,
|
||||
registrationNumber,
|
||||
occurredFrom,
|
||||
occurredTo
|
||||
occurredTo,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,8 @@ public class EventHubRuntimeEventLoader implements RuntimeDriverEventLoader, Run
|
|||
request.driverCardNumber(),
|
||||
request.occurredFrom(),
|
||||
request.occurredTo(),
|
||||
request.tachographSourceKindNames()
|
||||
request.tachographSourceKindNames(),
|
||||
request.includeIntersectingIntervals()
|
||||
);
|
||||
case YELLOWFOX_DB -> UnifiedDriverEventsRequest.forYellowFoxDbDriver(
|
||||
request.tenantKey(),
|
||||
|
|
@ -99,7 +100,8 @@ public class EventHubRuntimeEventLoader implements RuntimeDriverEventLoader, Run
|
|||
vehicleRef.registrationNumber(),
|
||||
request.vehicleOccurredFrom(),
|
||||
request.vehicleOccurredTo(),
|
||||
request.tachographSourceKindNames()
|
||||
request.tachographSourceKindNames(),
|
||||
request.includeIntersectingIntervals()
|
||||
);
|
||||
case YELLOWFOX_DB -> UnifiedVehicleEventsRequest.forYellowFoxDb(
|
||||
request.tenantKey(),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
package at.procon.eventhub.processing.service;
|
||||
|
||||
import at.procon.eventhub.dto.EventHubEventDto;
|
||||
import at.procon.eventhub.dto.EventLifecycle;
|
||||
import at.procon.eventhub.dto.EventType;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographTimelineEventBundle;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
final class RuntimeIntervalEventWindowSelector {
|
||||
|
||||
private RuntimeIntervalEventWindowSelector() {
|
||||
}
|
||||
|
||||
static TachographTimelineEventBundle filterBundle(
|
||||
TachographTimelineEventBundle bundle,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
if (bundle == null) {
|
||||
return new TachographTimelineEventBundle(List.of(), List.of(), List.of());
|
||||
}
|
||||
return new TachographTimelineEventBundle(
|
||||
filterIntervalEvents(bundle.activityEvents(), occurredFrom, occurredTo, includeIntersectingIntervals),
|
||||
filterIntervalEvents(bundle.vehicleUsageEvents(), occurredFrom, occurredTo, includeIntersectingIntervals),
|
||||
filterPointEvents(bundle.supportEvents(), occurredFrom, occurredTo)
|
||||
);
|
||||
}
|
||||
|
||||
private static List<EventHubEventDto> filterIntervalEvents(
|
||||
List<EventHubEventDto> events,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo,
|
||||
boolean includeIntersectingIntervals
|
||||
) {
|
||||
if (events == null || events.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
if (!includeIntersectingIntervals) {
|
||||
return filterPointEvents(events, occurredFrom, occurredTo);
|
||||
}
|
||||
|
||||
LinkedHashMap<String, IntervalGroup> byInterval = new LinkedHashMap<>();
|
||||
for (EventHubEventDto event : events) {
|
||||
byInterval.computeIfAbsent(intervalKey(event), ignored -> new IntervalGroup()).add(event);
|
||||
}
|
||||
|
||||
List<EventHubEventDto> result = new ArrayList<>();
|
||||
for (IntervalGroup group : byInterval.values()) {
|
||||
if (group.overlaps(occurredFrom, occurredTo)) {
|
||||
result.addAll(group.events);
|
||||
}
|
||||
}
|
||||
return List.copyOf(result);
|
||||
}
|
||||
|
||||
private static List<EventHubEventDto> filterPointEvents(
|
||||
List<EventHubEventDto> events,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
) {
|
||||
return events.stream()
|
||||
.filter(event -> withinWindow(event.occurredAt(), occurredFrom, occurredTo))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static boolean withinWindow(
|
||||
OffsetDateTime occurredAt,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
) {
|
||||
if (occurredAt == null) {
|
||||
return false;
|
||||
}
|
||||
if (occurredFrom != null && occurredAt.isBefore(occurredFrom)) {
|
||||
return false;
|
||||
}
|
||||
return occurredTo == null || !occurredAt.isAfter(occurredTo);
|
||||
}
|
||||
|
||||
private static String intervalKey(EventHubEventDto event) {
|
||||
JsonNode raw = raw(event);
|
||||
String intervalId = text(raw, "intervalId");
|
||||
if (intervalId != null) {
|
||||
return intervalId;
|
||||
}
|
||||
String sourceRowId = text(raw, "sourceRowId");
|
||||
return sourceRowId != null ? sourceRowId : event.externalSourceEventId();
|
||||
}
|
||||
|
||||
private static JsonNode raw(EventHubEventDto event) {
|
||||
JsonNode payload = event == null ? null : event.payload();
|
||||
if (payload == null || payload.isNull() || payload.isMissingNode()) {
|
||||
return null;
|
||||
}
|
||||
JsonNode raw = payload.get("raw");
|
||||
return raw == null || raw.isNull() ? payload : raw;
|
||||
}
|
||||
|
||||
private static String text(JsonNode node, String field) {
|
||||
if (node == null || field == null) {
|
||||
return null;
|
||||
}
|
||||
JsonNode value = node.get(field);
|
||||
if (value == null || value.isNull()) {
|
||||
return null;
|
||||
}
|
||||
String text = value.asText(null);
|
||||
return text == null || text.isBlank() ? null : text.trim();
|
||||
}
|
||||
|
||||
private static final class IntervalGroup {
|
||||
private final List<EventHubEventDto> events = new ArrayList<>();
|
||||
private OffsetDateTime startedAt;
|
||||
private OffsetDateTime endedAt;
|
||||
|
||||
private void add(EventHubEventDto event) {
|
||||
events.add(event);
|
||||
if (event == null || event.occurredAt() == null) {
|
||||
return;
|
||||
}
|
||||
if (isStartEvent(event)) {
|
||||
startedAt = min(startedAt, event.occurredAt());
|
||||
return;
|
||||
}
|
||||
if (isEndEvent(event)) {
|
||||
endedAt = max(endedAt, event.occurredAt());
|
||||
return;
|
||||
}
|
||||
startedAt = min(startedAt, event.occurredAt());
|
||||
endedAt = max(endedAt, event.occurredAt());
|
||||
}
|
||||
|
||||
private boolean overlaps(OffsetDateTime occurredFrom, OffsetDateTime occurredTo) {
|
||||
if (startedAt == null && endedAt == null) {
|
||||
return false;
|
||||
}
|
||||
OffsetDateTime effectiveStart = startedAt == null ? endedAt : startedAt;
|
||||
OffsetDateTime effectiveEnd = endedAt;
|
||||
if (occurredTo != null && effectiveStart != null && effectiveStart.isAfter(occurredTo)) {
|
||||
return false;
|
||||
}
|
||||
return occurredFrom == null || effectiveEnd == null || !effectiveEnd.isBefore(occurredFrom);
|
||||
}
|
||||
|
||||
private boolean isStartEvent(EventHubEventDto event) {
|
||||
return event.lifecycle() == EventLifecycle.START
|
||||
|| event.eventType() == EventType.CARD_INSERTED;
|
||||
}
|
||||
|
||||
private boolean isEndEvent(EventHubEventDto event) {
|
||||
return event.lifecycle() == EventLifecycle.END
|
||||
|| event.eventType() == EventType.CARD_WITHDRAWN;
|
||||
}
|
||||
|
||||
private OffsetDateTime min(OffsetDateTime left, OffsetDateTime right) {
|
||||
if (left == null) {
|
||||
return right;
|
||||
}
|
||||
if (right == null) {
|
||||
return left;
|
||||
}
|
||||
return left.isBefore(right) ? left : right;
|
||||
}
|
||||
|
||||
private OffsetDateTime max(OffsetDateTime left, OffsetDateTime right) {
|
||||
if (left == null) {
|
||||
return right;
|
||||
}
|
||||
if (right == null) {
|
||||
return left;
|
||||
}
|
||||
return left.isAfter(right) ? left : right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,8 @@ public class TachographFileSessionRuntimeEventLoader implements RuntimeDriverEve
|
|||
sessionId,
|
||||
request.driverKey(),
|
||||
request.occurredFrom(),
|
||||
request.occurredTo()
|
||||
request.occurredTo(),
|
||||
request.includeIntersectingIntervals()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
|
@ -77,7 +78,8 @@ public class TachographFileSessionRuntimeEventLoader implements RuntimeDriverEve
|
|||
vehicleRef.registrationNation(),
|
||||
vehicleRef.registrationNumber(),
|
||||
request.vehicleOccurredFrom(),
|
||||
request.vehicleOccurredTo()
|
||||
request.vehicleOccurredTo(),
|
||||
request.includeIntersectingIntervals()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ import at.procon.eventhub.processing.model.UnifiedDriverEventsRequest;
|
|||
import at.procon.eventhub.processing.model.UnifiedEventSourceFamily;
|
||||
import at.procon.eventhub.tachographfilesession.model.DriverExtractionSession;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographTimelineEventBundle;
|
||||
import at.procon.eventhub.tachographfilesession.service.DriverNotFoundInSessionException;
|
||||
import at.procon.eventhub.tachographfilesession.service.DriverTimelineEventBuilder;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionNotFoundException;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionRepository;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
|
@ -38,30 +38,27 @@ public class TachographFileSessionUnifiedDriverEventSource implements UnifiedDri
|
|||
.orElseThrow(() -> new TachographFileSessionNotFoundException(request.sessionId()));
|
||||
if (request.driverKey() == null) {
|
||||
return session.driversByKey().values().stream()
|
||||
.flatMap(driver -> eventBuilder.buildEvents(session, driver).stream())
|
||||
.filter(event -> withinWindow(event.occurredAt(), request.occurredFrom(), request.occurredTo()))
|
||||
.map(driver -> filterBundle(session, driver, request).allEvents())
|
||||
.flatMap(List::stream)
|
||||
.toList();
|
||||
}
|
||||
DriverExtractionSession driver = session.driversByKey().get(request.driverKey());
|
||||
if (driver == null) {
|
||||
throw new DriverNotFoundInSessionException(request.sessionId(), request.driverKey());
|
||||
}
|
||||
return eventBuilder.buildEvents(session, driver).stream()
|
||||
.filter(event -> withinWindow(event.occurredAt(), request.occurredFrom(), request.occurredTo()))
|
||||
.toList();
|
||||
return filterBundle(session, driver, request).allEvents();
|
||||
}
|
||||
|
||||
private boolean withinWindow(
|
||||
OffsetDateTime occurredAt,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
private TachographTimelineEventBundle filterBundle(
|
||||
TachographFileSession session,
|
||||
DriverExtractionSession driver,
|
||||
UnifiedDriverEventsRequest request
|
||||
) {
|
||||
if (occurredAt == null) {
|
||||
return false;
|
||||
}
|
||||
if (occurredFrom != null && occurredAt.isBefore(occurredFrom)) {
|
||||
return false;
|
||||
}
|
||||
return occurredTo == null || !occurredAt.isAfter(occurredTo);
|
||||
return RuntimeIntervalEventWindowSelector.filterBundle(
|
||||
eventBuilder.buildEventBundle(session, driver),
|
||||
request.occurredFrom(),
|
||||
request.occurredTo(),
|
||||
request.includeIntersectingIntervals()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import at.procon.eventhub.processing.model.UnifiedEventSourceFamily;
|
|||
import at.procon.eventhub.processing.model.UnifiedVehicleEventsRequest;
|
||||
import at.procon.eventhub.reference.TachographNationRegistry;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographFileSession;
|
||||
import at.procon.eventhub.tachographfilesession.model.TachographTimelineEventBundle;
|
||||
import at.procon.eventhub.tachographfilesession.service.DriverTimelineEventBuilder;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionNotFoundException;
|
||||
import at.procon.eventhub.tachographfilesession.service.TachographFileSessionRepository;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
|
@ -37,9 +37,14 @@ public class TachographFileSessionUnifiedVehicleEventSource implements UnifiedVe
|
|||
TachographFileSession session = repository.find(request.sessionId())
|
||||
.orElseThrow(() -> new TachographFileSessionNotFoundException(request.sessionId()));
|
||||
return session.driversByKey().values().stream()
|
||||
.flatMap(driver -> eventBuilder.buildEvents(session, driver).stream())
|
||||
.map(driver -> RuntimeIntervalEventWindowSelector.filterBundle(
|
||||
eventBuilder.buildEventBundle(session, driver),
|
||||
request.occurredFrom(),
|
||||
request.occurredTo(),
|
||||
request.includeIntersectingIntervals()
|
||||
).allEvents())
|
||||
.flatMap(List::stream)
|
||||
.filter(event -> matchesVehicle(event.vehicleRef(), request))
|
||||
.filter(event -> withinWindow(event.occurredAt(), request.occurredFrom(), request.occurredTo()))
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
|
@ -61,20 +66,6 @@ public class TachographFileSessionUnifiedVehicleEventSource implements UnifiedVe
|
|||
&& matchesNation(request.registrationNation(), vehicleRef.vehicleRegistration().nation(), vehicleRef.vehicleRegistration().nationNumericCode());
|
||||
}
|
||||
|
||||
private boolean withinWindow(
|
||||
OffsetDateTime occurredAt,
|
||||
OffsetDateTime occurredFrom,
|
||||
OffsetDateTime occurredTo
|
||||
) {
|
||||
if (occurredAt == null) {
|
||||
return false;
|
||||
}
|
||||
if (occurredFrom != null && occurredAt.isBefore(occurredFrom)) {
|
||||
return false;
|
||||
}
|
||||
return occurredTo == null || !occurredAt.isAfter(occurredTo);
|
||||
}
|
||||
|
||||
private boolean matchesNation(String requestedNation, String actualNation, Integer actualNationNumericCode) {
|
||||
if (requestedNation == null) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -68,11 +68,10 @@ public class UnifiedEventTimelineReconstructor {
|
|||
continue;
|
||||
}
|
||||
JsonNode raw = raw(event);
|
||||
String intervalId = firstNonBlank(
|
||||
text(raw, "intervalId"),
|
||||
text(raw, "sourceRowId"),
|
||||
event.externalSourceEventId()
|
||||
);
|
||||
String intervalId = firstNonBlank(text(raw, "intervalId"), text(raw, "sourceRowId"), event.externalSourceEventId());
|
||||
if (intervalId == null) {
|
||||
continue;
|
||||
}
|
||||
ActivityAccumulator accumulator = byIntervalId.computeIfAbsent(
|
||||
intervalId,
|
||||
ignored -> new ActivityAccumulator(intervalId)
|
||||
|
|
@ -102,11 +101,10 @@ public class UnifiedEventTimelineReconstructor {
|
|||
continue;
|
||||
}
|
||||
JsonNode raw = raw(event);
|
||||
String intervalId = firstNonBlank(
|
||||
text(raw, "intervalId"),
|
||||
text(raw, "sourceRowId"),
|
||||
event.externalSourceEventId()
|
||||
);
|
||||
String intervalId = firstNonBlank(text(raw, "intervalId"), text(raw, "sourceRowId"), event.externalSourceEventId());
|
||||
if (intervalId == null) {
|
||||
continue;
|
||||
}
|
||||
VehicleUsageAccumulator accumulator = byIntervalId.computeIfAbsent(
|
||||
intervalId,
|
||||
ignored -> new VehicleUsageAccumulator(sessionId, driverKey, intervalId)
|
||||
|
|
|
|||
|
|
@ -167,7 +167,11 @@ public class UnifiedRuntimeDerivedProjectionService {
|
|||
.toList(),
|
||||
notes
|
||||
);
|
||||
DriverWorkingTimeProcessingResultDto projection = workingTimeProcessingCore.process(processingInput);
|
||||
DriverWorkingTimeProcessingResultDto projection = workingTimeProcessingCore.process(processingInput)
|
||||
.withIncludedIntervals(
|
||||
apiRequest.includeActivityIntervalsOrDefault(),
|
||||
apiRequest.includeDrivingIntervalsOrDefault()
|
||||
);
|
||||
notes = projection.notes();
|
||||
|
||||
RuntimeSupportEvidenceNormalizationDebugDto normalizationDebug = new RuntimeSupportEvidenceNormalizationDebugDto(
|
||||
|
|
|
|||
|
|
@ -145,4 +145,5 @@ final class TachographRawPayloadSupport {
|
|||
|| message.toLowerCase(java.util.Locale.ROOT).contains("not valid")
|
||||
|| message.toLowerCase(java.util.Locale.ROOT).contains("invalid")));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ public class IntervalBackedDriverTimelineEventBuilder implements DriverTimelineE
|
|||
Map<String, Object> raw = new LinkedHashMap<>();
|
||||
raw.put("intervalId", interval.intervalId());
|
||||
raw.put("sourceRowId", interval.intervalId());
|
||||
raw.put("sessionId", session.sessionId().toString());
|
||||
raw.put("driverKey", driverKey);
|
||||
raw.put("activityType", interval.activityType());
|
||||
raw.put("sourceRowIds", interval.sourceIntervalIds());
|
||||
|
|
@ -232,6 +233,7 @@ public class IntervalBackedDriverTimelineEventBuilder implements DriverTimelineE
|
|||
Map<String, Object> raw = new LinkedHashMap<>();
|
||||
raw.put("intervalId", interval.intervalId());
|
||||
raw.put("sourceRowId", interval.intervalId());
|
||||
raw.put("sessionId", session.sessionId().toString());
|
||||
raw.put("driverKey", driverKey);
|
||||
raw.put("sourceRowIds", interval.sourceIntervalIds());
|
||||
raw.put("startedAt", timeText(interval.from()));
|
||||
|
|
@ -312,6 +314,7 @@ public class IntervalBackedDriverTimelineEventBuilder implements DriverTimelineE
|
|||
EventDetailsDto details = supportDetails(eventDomain, supportEvent);
|
||||
Map<String, Object> raw = new LinkedHashMap<>();
|
||||
raw.put("sourceRowId", supportEvent.eventId());
|
||||
raw.put("sessionId", session.sessionId().toString());
|
||||
raw.put("supportEventId", supportEvent.eventId());
|
||||
raw.put("driverKey", supportEvent.driverKey());
|
||||
raw.put("supportEventType", supportEvent.eventType());
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ create schema DriverActivityIntervalEvent(
|
|||
);
|
||||
|
||||
create window OpenDriverActivityPoint#unique(driverKey, intervalId) as DriverActivityPointEvent;
|
||||
|
||||
insert into OpenDriverActivityPoint
|
||||
select *
|
||||
from DriverActivityPointEvent(lifecycle = 'START');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
package at.procon.eventhub.processing.driverworkingtime.dto;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class DriverWorkingTimeProcessingResultDtoTest {
|
||||
|
||||
@Test
|
||||
void canExcludeActivityAndDrivingIntervalsWhileKeepingCounts() {
|
||||
DriverWorkingTimeActivityInterval activityInterval = new DriverWorkingTimeActivityInterval(
|
||||
null,
|
||||
"12:123",
|
||||
"ACT-1",
|
||||
"WORK",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"DRIVER_CARD",
|
||||
null,
|
||||
null,
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T09:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z").toEpochSecond(),
|
||||
OffsetDateTime.parse("2026-05-01T09:00:00Z").toEpochSecond(),
|
||||
3600L,
|
||||
List.of("ACT-1"),
|
||||
false,
|
||||
false,
|
||||
"RAW_INTERVAL"
|
||||
);
|
||||
DriverWorkingTimeActivityInterval drivingInterval = new DriverWorkingTimeActivityInterval(
|
||||
null,
|
||||
"12:123",
|
||||
"DRV-1",
|
||||
"DRIVE",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"DRIVER_CARD",
|
||||
null,
|
||||
null,
|
||||
OffsetDateTime.parse("2026-05-01T09:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T09:00:00Z").toEpochSecond(),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z").toEpochSecond(),
|
||||
3600L,
|
||||
List.of("DRV-1"),
|
||||
false,
|
||||
false,
|
||||
"RAW_INTERVAL"
|
||||
);
|
||||
DriverWorkingTimeProcessingResultDto result = new DriverWorkingTimeProcessingResultDto(
|
||||
UUID.randomUUID(),
|
||||
"12:123",
|
||||
"UNIFIED_EVENT_STREAM",
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
List.of(activityInterval),
|
||||
List.of(drivingInterval),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of("note")
|
||||
);
|
||||
|
||||
DriverWorkingTimeProcessingResultDto compact = result.withIncludedIntervals(false, false);
|
||||
|
||||
assertThat(compact.activityIntervalCount()).isEqualTo(1);
|
||||
assertThat(compact.drivingIntervalCount()).isEqualTo(1);
|
||||
assertThat(compact.activityIntervals()).isEmpty();
|
||||
assertThat(compact.drivingIntervals()).isEmpty();
|
||||
assertThat(compact.notes()).containsExactly("note");
|
||||
}
|
||||
}
|
||||
|
|
@ -49,6 +49,9 @@ class RuntimeEventProcessingServiceTest {
|
|||
true,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
),
|
||||
new RuntimeEventPartitioningApiRequest(RuntimeEventPartitioningStrategy.DRIVER, null, false, null, false, null, false, null, null, null),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,219 @@
|
|||
package at.procon.eventhub.processing.eventprocessing.module;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import at.procon.eventhub.processing.driverworkingtime.dto.DriverWorkingTimeProcessingResultDto;
|
||||
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeActivityInterval;
|
||||
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeDriverPartition;
|
||||
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimePreparedInput;
|
||||
import at.procon.eventhub.processing.driverworkingtime.model.DriverWorkingTimeProcessingInput;
|
||||
import at.procon.eventhub.processing.driverworkingtime.service.DriverWorkingTimeProcessingCore;
|
||||
import at.procon.eventhub.processing.dto.UnifiedRuntimeDerivedProjectionResultDto;
|
||||
import at.procon.eventhub.processing.dto.UnifiedRuntimeProcessingApiRequest;
|
||||
import at.procon.eventhub.processing.dto.UnifiedRuntimeDriverWorkingTimeScopeResultDto;
|
||||
import at.procon.eventhub.processing.eventprocessing.plan.RuntimeProcessingExecutionApiRequest;
|
||||
import at.procon.eventhub.processing.model.UnifiedEventSourceFamily;
|
||||
import at.procon.eventhub.processing.model.UnifiedRuntimeEventBundle;
|
||||
import at.procon.eventhub.processing.model.UnifiedRuntimeProcessingRequest;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class DriverWorkingTimeDerivedProjectionsModuleTest {
|
||||
|
||||
@Test
|
||||
void appliesIncludeFlagsOnModulePath() {
|
||||
DriverWorkingTimeProcessingCore core = org.mockito.Mockito.mock(DriverWorkingTimeProcessingCore.class);
|
||||
DriverWorkingTimeDerivedProjectionsModule module = new DriverWorkingTimeDerivedProjectionsModule(core);
|
||||
|
||||
DriverWorkingTimeActivityInterval activityInterval = new DriverWorkingTimeActivityInterval(
|
||||
null,
|
||||
"12:123",
|
||||
"ACT-1",
|
||||
"WORK",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"DRIVER_CARD",
|
||||
null,
|
||||
null,
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T09:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z").toEpochSecond(),
|
||||
OffsetDateTime.parse("2026-05-01T09:00:00Z").toEpochSecond(),
|
||||
3600L,
|
||||
List.of("ACT-1"),
|
||||
false,
|
||||
false,
|
||||
"RAW_INTERVAL"
|
||||
);
|
||||
DriverWorkingTimeActivityInterval drivingInterval = new DriverWorkingTimeActivityInterval(
|
||||
null,
|
||||
"12:123",
|
||||
"DRV-1",
|
||||
"DRIVE",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
"DRIVER_CARD",
|
||||
null,
|
||||
null,
|
||||
OffsetDateTime.parse("2026-05-01T09:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T09:00:00Z").toEpochSecond(),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z").toEpochSecond(),
|
||||
3600L,
|
||||
List.of("DRV-1"),
|
||||
false,
|
||||
false,
|
||||
"RAW_INTERVAL"
|
||||
);
|
||||
DriverWorkingTimeProcessingResultDto rawProjection = new DriverWorkingTimeProcessingResultDto(
|
||||
UUID.randomUUID(),
|
||||
"12:123",
|
||||
"UNIFIED_EVENT_STREAM",
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
1,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
List.of(activityInterval),
|
||||
List.of(drivingInterval),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of("note")
|
||||
);
|
||||
when(core.process(any())).thenReturn(rawProjection);
|
||||
|
||||
UnifiedRuntimeProcessingApiRequest scope = new UnifiedRuntimeProcessingApiRequest(
|
||||
UUID.randomUUID(),
|
||||
List.of(),
|
||||
null,
|
||||
null,
|
||||
Set.of(UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION),
|
||||
null,
|
||||
null,
|
||||
"12:123",
|
||||
Set.of(),
|
||||
false,
|
||||
Set.of(),
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
true,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
false
|
||||
);
|
||||
UnifiedRuntimeProcessingRequest runtimeRequest = scope.toRuntimeRequest();
|
||||
DriverWorkingTimeProcessingInput processingInput = new DriverWorkingTimeProcessingInput(
|
||||
null,
|
||||
"12:123",
|
||||
"UNIFIED_EVENT_STREAM",
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z"),
|
||||
3,
|
||||
720,
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of()
|
||||
);
|
||||
DriverWorkingTimePreparedInput preparedInput = new DriverWorkingTimePreparedInput(
|
||||
"12:123",
|
||||
new DriverWorkingTimeDriverPartition(
|
||||
"12:123",
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
null,
|
||||
List.of(),
|
||||
null,
|
||||
List.of(),
|
||||
List.of()
|
||||
),
|
||||
processingInput
|
||||
);
|
||||
UnifiedRuntimeEventBundle bundle = new UnifiedRuntimeEventBundle(
|
||||
runtimeRequest,
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of(),
|
||||
List.of()
|
||||
);
|
||||
RuntimeProcessingModuleContext context = new RuntimeProcessingModuleContext(
|
||||
new RuntimeProcessingExecutionApiRequest("driver-working-time-v1", scope, null, List.of(), Map.of()),
|
||||
List.of(),
|
||||
Map.of("runtimeScopeApiRequest", scope),
|
||||
Map.of(
|
||||
DriverWorkingTimeModuleKeys.RUNTIME_EVENT_ASSEMBLY,
|
||||
new RuntimeProcessingModuleResult(
|
||||
DriverWorkingTimeModuleKeys.RUNTIME_EVENT_ASSEMBLY,
|
||||
RuntimeProcessingModuleStatus.SUCCESS,
|
||||
bundle,
|
||||
Map.of(),
|
||||
List.of()
|
||||
),
|
||||
DriverWorkingTimeModuleKeys.SUPPORT_EVIDENCE_NORMALIZATION,
|
||||
new RuntimeProcessingModuleResult(
|
||||
DriverWorkingTimeModuleKeys.SUPPORT_EVIDENCE_NORMALIZATION,
|
||||
RuntimeProcessingModuleStatus.SUCCESS,
|
||||
Map.of("12:123", preparedInput),
|
||||
Map.of(),
|
||||
List.of()
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
RuntimeProcessingModuleResult result = module.execute(context);
|
||||
UnifiedRuntimeDriverWorkingTimeScopeResultDto scopeResult =
|
||||
(UnifiedRuntimeDriverWorkingTimeScopeResultDto) result.output();
|
||||
UnifiedRuntimeDerivedProjectionResultDto driverResult = scopeResult.driverResults().get("12:123");
|
||||
|
||||
assertThat(driverResult.projection().activityIntervalCount()).isEqualTo(1);
|
||||
assertThat(driverResult.projection().drivingIntervalCount()).isEqualTo(1);
|
||||
assertThat(driverResult.projection().activityIntervals()).isEmpty();
|
||||
assertThat(driverResult.projection().drivingIntervals()).isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,8 @@ class TachographDriverEsperRuntimeEventProcessingProfileTest {
|
|||
"minimumRestPeriodMinutes",
|
||||
"attachVehicleOnlyEvents",
|
||||
"vehicleEvidencePaddingMinutes",
|
||||
"includeActivityIntervals",
|
||||
"includeDrivingIntervals",
|
||||
"includePartitionDebug"
|
||||
);
|
||||
}
|
||||
|
|
@ -71,6 +73,9 @@ class TachographDriverEsperRuntimeEventProcessingProfileTest {
|
|||
true,
|
||||
15,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
RuntimeEventProcessingApiRequest request = new RuntimeEventProcessingApiRequest(
|
||||
|
|
@ -93,6 +98,8 @@ class TachographDriverEsperRuntimeEventProcessingProfileTest {
|
|||
"minimumRestPeriodMinutes", "600",
|
||||
"vehicleEvidencePaddingMinutes", 20,
|
||||
"attachVehicleOnlyEvents", true,
|
||||
"includeActivityIntervals", true,
|
||||
"includeDrivingIntervals", true,
|
||||
"includePartitionDebug", true
|
||||
)
|
||||
);
|
||||
|
|
@ -116,7 +123,8 @@ class TachographDriverEsperRuntimeEventProcessingProfileTest {
|
|||
OffsetDateTime.parse("2026-05-01T00:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-31T23:59:59Z"),
|
||||
true,
|
||||
15
|
||||
15,
|
||||
true
|
||||
);
|
||||
UnifiedRuntimeDerivedProjectionResultDto driverResult = new UnifiedRuntimeDerivedProjectionResultDto(
|
||||
processedRequest,
|
||||
|
|
@ -158,6 +166,8 @@ class TachographDriverEsperRuntimeEventProcessingProfileTest {
|
|||
assertThat(delegated.minimumRestPeriodMinutes()).isEqualTo(600);
|
||||
assertThat(delegated.vehicleExpansionPaddingMinutes()).isEqualTo(20);
|
||||
assertThat(delegated.expandVehicleEvents()).isTrue();
|
||||
assertThat(delegated.includeActivityIntervals()).isTrue();
|
||||
assertThat(delegated.includeDrivingIntervals()).isTrue();
|
||||
assertThat(debugCaptor.getValue()).isTrue();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,8 +99,11 @@ class RuntimeMixedSourceEvidenceValidationServiceTest {
|
|||
OffsetDateTime.parse("2026-05-02T00:00:00Z"),
|
||||
true,
|
||||
15,
|
||||
null,
|
||||
3,
|
||||
720
|
||||
720,
|
||||
null,
|
||||
null
|
||||
),
|
||||
new RuntimeEventPartitioningApiRequest(
|
||||
RuntimeEventPartitioningStrategy.DRIVER,
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ class UnifiedDriverEventsRequestTest {
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
null,
|
||||
false
|
||||
)).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("At least one driver or vehicle selector");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class UnifiedRuntimeProcessingRequestTest {
|
|||
assertThat(request.eventBackend()).isEqualTo(UnifiedRuntimeEventBackend.SOURCE_DB);
|
||||
assertThat(request.expandVehicleEvents()).isTrue();
|
||||
assertThat(request.vehicleOccurredFrom()).isEqualTo(OffsetDateTime.parse("2026-05-01T00:00:00Z"));
|
||||
assertThat(request.includeIntersectingIntervals()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -92,7 +93,8 @@ class UnifiedRuntimeProcessingRequestTest {
|
|||
OffsetDateTime.parse("2026-05-01T00:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-02T00:00:00Z"),
|
||||
true,
|
||||
0
|
||||
0,
|
||||
true
|
||||
);
|
||||
|
||||
assertThat(driverCardOnlyRequest.tachographSourceKinds()).containsExactly(UnifiedTachographSourceKind.DRIVER_CARD);
|
||||
|
|
@ -195,7 +197,8 @@ class UnifiedRuntimeProcessingRequestTest {
|
|||
OffsetDateTime.parse("2026-05-01T00:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-02T00:00:00Z"),
|
||||
true,
|
||||
10
|
||||
10,
|
||||
true
|
||||
);
|
||||
|
||||
assertThat(request.driverKey()).isNull();
|
||||
|
|
@ -224,7 +227,8 @@ class UnifiedRuntimeProcessingRequestTest {
|
|||
OffsetDateTime.parse("2026-05-01T00:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-02T00:00:00Z"),
|
||||
true,
|
||||
10
|
||||
10,
|
||||
true
|
||||
);
|
||||
|
||||
assertThat(request.includeAllDrivers()).isTrue();
|
||||
|
|
@ -254,7 +258,8 @@ class UnifiedRuntimeProcessingRequestTest {
|
|||
null,
|
||||
null,
|
||||
true,
|
||||
0
|
||||
0,
|
||||
true
|
||||
)).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("Use either compositeSessionId");
|
||||
}
|
||||
|
|
@ -281,7 +286,8 @@ class UnifiedRuntimeProcessingRequestTest {
|
|||
null,
|
||||
null,
|
||||
true,
|
||||
0
|
||||
0,
|
||||
true
|
||||
)).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("At least one driver selector");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ class UnifiedVehicleEventsRequestTest {
|
|||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
null,
|
||||
false
|
||||
)).isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessageContaining("At least one vehicle selector");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@ class EventHubRuntimeEventLoaderTest {
|
|||
assertThat(driverRequest.occurredFrom()).isEqualTo(OffsetDateTime.parse("2026-05-01T00:00:00Z"));
|
||||
assertThat(driverRequest.occurredTo()).isEqualTo(OffsetDateTime.parse("2026-05-02T00:00:00Z"));
|
||||
});
|
||||
assertThat(driverSource.requests).extracting(UnifiedDriverEventsRequest::includeIntersectingIntervals)
|
||||
.containsExactly(true, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -121,6 +123,8 @@ class EventHubRuntimeEventLoaderTest {
|
|||
assertThat(vehicleRequest.occurredFrom()).isEqualTo(OffsetDateTime.parse("2026-04-30T23:45:00Z"));
|
||||
assertThat(vehicleRequest.occurredTo()).isEqualTo(OffsetDateTime.parse("2026-05-02T00:15:00Z"));
|
||||
});
|
||||
assertThat(vehicleSource.requests).extracting(UnifiedVehicleEventsRequest::includeIntersectingIntervals)
|
||||
.containsExactly(true, false);
|
||||
}
|
||||
|
||||
private static final class CapturingDriverSource implements UnifiedDriverEventSource {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,49 @@ class TachographFileSessionRuntimeEventLoaderTest {
|
|||
assertThat(loader.loadVehicleEvents(request, new UnifiedDiscoveredVehicleRef("VIN-1", "VIN-1", "12", "REG-1"))).hasSize(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void keepsCompleteIntersectingIntervalsWhenRequestStartsInsideInterval() {
|
||||
EventHubProperties properties = new EventHubProperties();
|
||||
TachographFileSessionRepository repository = new InMemoryTachographFileSessionRepository(properties);
|
||||
InMemoryTachographCompositeSessionRepository compositeRepository = new InMemoryTachographCompositeSessionRepository();
|
||||
IntervalBackedDriverTimelineEventBuilder eventBuilder = new IntervalBackedDriverTimelineEventBuilder(
|
||||
new DriverTimelineBuilder(),
|
||||
new DriverKeyFactory(),
|
||||
new VehicleKeyFactory(),
|
||||
new EventDetailsFactory(new ObjectMapper())
|
||||
);
|
||||
TachographFileSessionRuntimeEventLoader loader = new TachographFileSessionRuntimeEventLoader(
|
||||
new UnifiedDriverEventSourceService(List.of(new TachographFileSessionUnifiedDriverEventSource(repository, eventBuilder))),
|
||||
new UnifiedVehicleEventSourceService(List.of(new TachographFileSessionUnifiedVehicleEventSource(repository, eventBuilder))),
|
||||
compositeRepository,
|
||||
new EventAcquisitionRecordKeyService(),
|
||||
new EventHubEventSorter()
|
||||
);
|
||||
|
||||
DriverExtractionSession driver = driver();
|
||||
TachographFileSession session = session(driver);
|
||||
repository.save(session);
|
||||
|
||||
UnifiedRuntimeProcessingRequest request = UnifiedRuntimeProcessingRequest.forTachographFileSession(
|
||||
session.sessionId(),
|
||||
driver.driverKey(),
|
||||
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T09:15:00Z"),
|
||||
true,
|
||||
0
|
||||
);
|
||||
|
||||
assertThat(loader.loadDriverEvents(request))
|
||||
.extracting(event -> event.occurredAt())
|
||||
.containsExactly(
|
||||
OffsetDateTime.parse("2026-05-01T08:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T08:30:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T09:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-01T10:00:00Z")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ class UnifiedRuntimeDriverTimelineServiceTest {
|
|||
OffsetDateTime.parse("2026-05-01T00:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-02T00:00:00Z"),
|
||||
false,
|
||||
0
|
||||
0,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ class UnifiedRuntimeEventAssemblyServiceTest {
|
|||
OffsetDateTime.parse("2026-05-01T00:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-02T00:00:00Z"),
|
||||
true,
|
||||
15
|
||||
15,
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue