Align driver card identity normalization
This commit is contained in:
parent
33e9cb62c3
commit
4535f620fc
|
|
@ -1,5 +1,6 @@
|
|||
package at.procon.eventhub.dto;
|
||||
|
||||
import at.procon.eventhub.reference.DriverCardNumberNormalizer;
|
||||
import at.procon.eventhub.reference.TachographNationRegistry;
|
||||
|
||||
/**
|
||||
|
|
@ -43,6 +44,6 @@ public record DriverCardRefDto(
|
|||
}
|
||||
|
||||
private static String normalizeNullable(String value) {
|
||||
return value == null || value.isBlank() ? null : value.trim();
|
||||
return DriverCardNumberNormalizer.canonical(value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package at.procon.eventhub.persistence;
|
|||
|
||||
import at.procon.eventhub.dto.DriverCardRefDto;
|
||||
import at.procon.eventhub.dto.DriverRefDto;
|
||||
import at.procon.eventhub.reference.DriverCardNumberNormalizer;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.time.LocalDate;
|
||||
|
|
@ -16,9 +17,6 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
@Repository
|
||||
public class DriverIdentityRepository {
|
||||
|
||||
private static final String YELLOWFOX_SYNTHETIC_REFERENCE_NATION = "YELLOWFOX";
|
||||
private static final String UNKNOWN_CARD_NATION = "UNKNOWN";
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
|
|
@ -41,7 +39,7 @@ public class DriverIdentityRepository {
|
|||
DriverCardRefDto driverCard = driverRef.driverCard();
|
||||
String cardNation = driverCard == null ? null : normalizeNullable(driverCard.nation());
|
||||
Integer cardNationNumericCode = driverCard == null ? null : driverCard.nationNumericCode();
|
||||
String cardNumber = driverCard == null ? null : normalizeDriverCardNumber(cardNation, driverCard.number());
|
||||
String cardNumber = driverCard == null ? null : normalizeDriverCardNumber(driverCard.number());
|
||||
|
||||
UUID driverId = findBySourceDriverEntityId(normalizedTenantKey, eventSourceId, sourceDriverEntityId);
|
||||
UUID driverCardId = resolveOrCreateDriverCardId(cardNation, cardNationNumericCode, cardNumber, driverId);
|
||||
|
|
@ -782,20 +780,8 @@ public class DriverIdentityRepository {
|
|||
return legacyColumns != null && legacyColumns == 3;
|
||||
}
|
||||
|
||||
private String normalizeDriverCardNumber(String cardNation, String cardNumber) {
|
||||
String normalized = normalizeNullable(cardNumber);
|
||||
if (normalized == null) {
|
||||
return null;
|
||||
}
|
||||
if (isSyntheticYellowFoxCardNation(cardNation)) {
|
||||
return normalized.length() <= 14 ? normalized : normalized.substring(0, 14);
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private boolean isSyntheticYellowFoxCardNation(String cardNation) {
|
||||
return YELLOWFOX_SYNTHETIC_REFERENCE_NATION.equalsIgnoreCase(cardNation)
|
||||
|| UNKNOWN_CARD_NATION.equalsIgnoreCase(cardNation);
|
||||
private String normalizeDriverCardNumber(String cardNumber) {
|
||||
return DriverCardNumberNormalizer.canonical(cardNumber);
|
||||
}
|
||||
|
||||
private UUID createDriverCard(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package at.procon.eventhub.processing.model;
|
||||
|
||||
import at.procon.eventhub.reference.DriverCardNumberNormalizer;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
|
@ -25,7 +26,7 @@ public record UnifiedDriverEventsRequest(
|
|||
tenantKey = normalize(tenantKey);
|
||||
driverSourceEntityId = normalize(driverSourceEntityId);
|
||||
driverCardNation = normalizeUpper(driverCardNation);
|
||||
driverCardNumber = normalize(driverCardNumber);
|
||||
driverCardNumber = normalizeDriverCardNumber(driverCardNumber);
|
||||
vehicleSourceEntityId = normalize(vehicleSourceEntityId);
|
||||
vin = normalizeUpper(vin);
|
||||
registrationNation = normalizeUpper(registrationNation);
|
||||
|
|
@ -171,4 +172,8 @@ public record UnifiedDriverEventsRequest(
|
|||
private static String normalizeUpper(String value) {
|
||||
return value == null || value.isBlank() ? null : value.trim().toUpperCase();
|
||||
}
|
||||
|
||||
private static String normalizeDriverCardNumber(String value) {
|
||||
return DriverCardNumberNormalizer.canonical(value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package at.procon.eventhub.processing.model;
|
||||
|
||||
import at.procon.eventhub.reference.DriverCardNumberNormalizer;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
|
@ -23,7 +24,7 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
tenantKey = normalize(tenantKey);
|
||||
driverSourceEntityId = normalize(driverSourceEntityId);
|
||||
driverCardNation = normalizeUpper(driverCardNation);
|
||||
driverCardNumber = normalize(driverCardNumber);
|
||||
driverCardNumber = normalizeDriverCardNumber(driverCardNumber);
|
||||
boolean includesFileSession = sourceFamilies != null && sourceFamilies.contains(UnifiedEventSourceFamily.TACHOGRAPH_FILE_SESSION);
|
||||
boolean includesExternalDb = sourceFamilies != null && sourceFamilies.stream()
|
||||
.anyMatch(family -> family == UnifiedEventSourceFamily.TACHOGRAPH_DB || family == UnifiedEventSourceFamily.YELLOWFOX_DB);
|
||||
|
|
@ -196,4 +197,8 @@ public record UnifiedRuntimeProcessingRequest(
|
|||
private static String normalizeUpper(String value) {
|
||||
return value == null || value.isBlank() ? null : value.trim().toUpperCase();
|
||||
}
|
||||
|
||||
private static String normalizeDriverCardNumber(String value) {
|
||||
return DriverCardNumberNormalizer.canonical(value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ public class UnifiedEventTimelineReconstructor {
|
|||
BigDecimal longitude = event.position() == null ? null : event.position().longitude();
|
||||
result.add(new ExtractedSupportEvent(
|
||||
eventId,
|
||||
text(raw, "driverKey"),
|
||||
event.occurredAt(),
|
||||
event.eventDomain().name(),
|
||||
text(raw, "supportEventType") == null ? event.eventType().name() : text(raw, "supportEventType"),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package at.procon.eventhub.reference;
|
||||
|
||||
public final class DriverCardNumberNormalizer {
|
||||
|
||||
public static final int CANONICAL_LENGTH = 14;
|
||||
|
||||
private DriverCardNumberNormalizer() {
|
||||
}
|
||||
|
||||
public static String canonical(String rawCardNumber) {
|
||||
String normalized = normalize(rawCardNumber);
|
||||
if (normalized == null) {
|
||||
return null;
|
||||
}
|
||||
return normalized.length() <= CANONICAL_LENGTH
|
||||
? normalized
|
||||
: normalized.substring(0, CANONICAL_LENGTH);
|
||||
}
|
||||
|
||||
public static String full(String rawCardNumber) {
|
||||
return normalize(rawCardNumber);
|
||||
}
|
||||
|
||||
private static String normalize(String value) {
|
||||
if (value == null || value.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
return value.trim().toUpperCase();
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ public record ExtractedDriverCard(
|
|||
String sourceDriverCardId,
|
||||
String cardNation,
|
||||
String cardNumber,
|
||||
String fullCardNumber,
|
||||
String issuingAuthorityName,
|
||||
OffsetDateTime issueDate,
|
||||
OffsetDateTime validityBegin,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import java.time.OffsetDateTime;
|
|||
|
||||
public record ExtractedSupportEvent(
|
||||
String eventId,
|
||||
String driverKey,
|
||||
OffsetDateTime occurredAt,
|
||||
String eventDomain,
|
||||
String eventType,
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public class DriverCardXmlExtractionService {
|
|||
driverKeyFactory.createSourceDriverCardId(driverKey),
|
||||
driverCard.cardNation(),
|
||||
driverCard.cardNumber(),
|
||||
driverCard.fullCardNumber(),
|
||||
driverCard.issuingAuthorityName(),
|
||||
driverCard.issueDate(),
|
||||
driverCard.validityBegin(),
|
||||
|
|
@ -73,7 +74,7 @@ public class DriverCardXmlExtractionService {
|
|||
extractVehicleUsageIntervals(document, registrationsByKey, vehiclesByKey, warnings);
|
||||
List<ExtractedCardActivityInterval> activityIntervals =
|
||||
assignVehicleCoverage(extractActivityIntervals(document, warnings), vehicleUsageIntervals);
|
||||
List<ExtractedSupportEvent> supportEvents = extractSupportEvents(document, vehicleUsageIntervals, warnings);
|
||||
List<ExtractedSupportEvent> supportEvents = extractSupportEvents(document, driverKey, vehicleUsageIntervals, warnings);
|
||||
|
||||
DriverExtractionSession driverSession = new DriverExtractionSession(
|
||||
driverKey,
|
||||
|
|
@ -114,12 +115,14 @@ public class DriverCardXmlExtractionService {
|
|||
}
|
||||
Element cardIdentification = child(identification, "cardIdentification");
|
||||
String cardNation = childText(cardIdentification, "cardIssuingMemberState");
|
||||
String cardNumber = joinCardNumber(identification);
|
||||
String fullCardNumber = joinCardNumber(identification);
|
||||
String cardNumber = driverKeyFactory.canonicalCardNumber(fullCardNumber);
|
||||
String authority = childText(child(cardIdentification, "cardIssuingAuthorityName"), "name");
|
||||
return new ExtractedDriverCard(
|
||||
null,
|
||||
cardNation,
|
||||
cardNumber,
|
||||
fullCardNumber,
|
||||
authority,
|
||||
offsetDateTime(childText(cardIdentification, "cardIssueDate")),
|
||||
offsetDateTime(childText(cardIdentification, "cardValidityBegin")),
|
||||
|
|
@ -307,17 +310,18 @@ public class DriverCardXmlExtractionService {
|
|||
|
||||
private List<ExtractedSupportEvent> extractSupportEvents(
|
||||
Document document,
|
||||
String driverKey,
|
||||
List<ExtractedCardVehicleUsageInterval> vehicleUsageIntervals,
|
||||
List<ExtractionWarning> warnings
|
||||
) {
|
||||
VehicleUsageLookup vehicleUsageLookup = new VehicleUsageLookup(vehicleUsageIntervals);
|
||||
List<ExtractedSupportEvent> supportEvents = new ArrayList<>();
|
||||
Element root = document.getDocumentElement();
|
||||
extractCardPlaceSupportEvents(root, vehicleUsageLookup, supportEvents, warnings);
|
||||
extractCardGnssSupportEvents(root, vehicleUsageLookup, supportEvents, warnings);
|
||||
extractCardSpecificConditionSupportEvents(root, vehicleUsageLookup, supportEvents, warnings);
|
||||
extractCardBorderCrossingSupportEvents(root, vehicleUsageLookup, supportEvents, warnings);
|
||||
extractCardLoadUnloadSupportEvents(root, vehicleUsageLookup, supportEvents, warnings);
|
||||
extractCardPlaceSupportEvents(root, driverKey, vehicleUsageLookup, supportEvents, warnings);
|
||||
extractCardGnssSupportEvents(root, driverKey, vehicleUsageLookup, supportEvents, warnings);
|
||||
extractCardSpecificConditionSupportEvents(root, driverKey, vehicleUsageLookup, supportEvents, warnings);
|
||||
extractCardBorderCrossingSupportEvents(root, driverKey, vehicleUsageLookup, supportEvents, warnings);
|
||||
extractCardLoadUnloadSupportEvents(root, driverKey, vehicleUsageLookup, supportEvents, warnings);
|
||||
supportEvents.sort(Comparator.comparing(ExtractedSupportEvent::occurredAt)
|
||||
.thenComparing(ExtractedSupportEvent::eventDomain, Comparator.nullsLast(String::compareTo))
|
||||
.thenComparing(ExtractedSupportEvent::eventId, Comparator.nullsLast(String::compareTo)));
|
||||
|
|
@ -326,6 +330,7 @@ public class DriverCardXmlExtractionService {
|
|||
|
||||
private void extractCardPlaceSupportEvents(
|
||||
Element root,
|
||||
String driverKey,
|
||||
VehicleUsageLookup vehicleUsageLookup,
|
||||
List<ExtractedSupportEvent> supportEvents,
|
||||
List<ExtractionWarning> warnings
|
||||
|
|
@ -344,6 +349,10 @@ public class DriverCardXmlExtractionService {
|
|||
}
|
||||
|
||||
ExtractedCardVehicleUsageInterval usage = vehicleUsageLookup.resolve(occurredAt);
|
||||
if (!hasKnownRegistration(usage)) {
|
||||
warnings.add(new ExtractionWarning("CARD_PLACE_UNKNOWN_VRN", "Driver-card place record has unknown vehicle registration and was ignored.", path));
|
||||
continue;
|
||||
}
|
||||
Element gnss = child(record, "entryGnssPlaceRecord");
|
||||
Element geoCoordinates = child(gnss, "geoCoordinates");
|
||||
BigDecimal latitude = geoCoordinate(geoCoordinates, "latitude", true);
|
||||
|
|
@ -352,6 +361,7 @@ public class DriverCardXmlExtractionService {
|
|||
String entryType = childText(record, "entryTypeDailyWorkPeriod");
|
||||
supportEvents.add(new ExtractedSupportEvent(
|
||||
"CARDPLACE-" + (i + 1),
|
||||
driverKey,
|
||||
occurredAt,
|
||||
"PLACE",
|
||||
mapPlaceEntryType(entryType),
|
||||
|
|
@ -379,6 +389,7 @@ public class DriverCardXmlExtractionService {
|
|||
|
||||
private void extractCardGnssSupportEvents(
|
||||
Element root,
|
||||
String driverKey,
|
||||
VehicleUsageLookup vehicleUsageLookup,
|
||||
List<ExtractedSupportEvent> supportEvents,
|
||||
List<ExtractionWarning> warnings
|
||||
|
|
@ -397,6 +408,11 @@ public class DriverCardXmlExtractionService {
|
|||
}
|
||||
|
||||
ExtractedCardVehicleUsageInterval usage = vehicleUsageLookup.resolve(occurredAt);
|
||||
if (!hasKnownRegistration(usage)) {
|
||||
warnings.add(new ExtractionWarning("CARD_GNSS_MISSING_VRN", "Driver-card GNSS record is missing vehicle registration.", path));
|
||||
continue;
|
||||
}
|
||||
|
||||
Element gnss = child(record, "gnssPlaceRecord");
|
||||
Element geoCoordinates = child(gnss, "geoCoordinates");
|
||||
BigDecimal latitude = geoCoordinate(geoCoordinates, "latitude", true);
|
||||
|
|
@ -404,6 +420,7 @@ public class DriverCardXmlExtractionService {
|
|||
String authenticationStatus = normalizeToken(childText(gnss, "authenticationStatus"));
|
||||
supportEvents.add(new ExtractedSupportEvent(
|
||||
"CARDGNSS-" + (i + 1),
|
||||
driverKey,
|
||||
occurredAt,
|
||||
"POSITION",
|
||||
"POSITION_RECORDED",
|
||||
|
|
@ -431,6 +448,7 @@ public class DriverCardXmlExtractionService {
|
|||
|
||||
private void extractCardSpecificConditionSupportEvents(
|
||||
Element root,
|
||||
String driverKey,
|
||||
VehicleUsageLookup vehicleUsageLookup,
|
||||
List<ExtractedSupportEvent> supportEvents,
|
||||
List<ExtractionWarning> warnings
|
||||
|
|
@ -449,10 +467,15 @@ public class DriverCardXmlExtractionService {
|
|||
}
|
||||
|
||||
ExtractedCardVehicleUsageInterval usage = vehicleUsageLookup.resolve(occurredAt);
|
||||
if (!hasKnownRegistration(usage)) {
|
||||
warnings.add(new ExtractionWarning("CARD_SPECIFIC_CONDITION_UNKNOWN_VRN", "Driver-card specific-condition record has unknown vehicle registration and was ignored.", path));
|
||||
continue;
|
||||
}
|
||||
String conditionCode = normalizeToken(childText(record, "specificConditionType"));
|
||||
String[] specificCondition = mapSpecificCondition(conditionCode);
|
||||
supportEvents.add(new ExtractedSupportEvent(
|
||||
"CARDSC-" + (i + 1),
|
||||
driverKey,
|
||||
occurredAt,
|
||||
"SPECIFIC_CONDITION",
|
||||
specificCondition[0],
|
||||
|
|
@ -480,6 +503,7 @@ public class DriverCardXmlExtractionService {
|
|||
|
||||
private void extractCardBorderCrossingSupportEvents(
|
||||
Element root,
|
||||
String driverKey,
|
||||
VehicleUsageLookup vehicleUsageLookup,
|
||||
List<ExtractedSupportEvent> supportEvents,
|
||||
List<ExtractionWarning> warnings
|
||||
|
|
@ -499,12 +523,17 @@ public class DriverCardXmlExtractionService {
|
|||
}
|
||||
|
||||
ExtractedCardVehicleUsageInterval usage = vehicleUsageLookup.resolve(occurredAt);
|
||||
if (!hasKnownRegistration(usage)) {
|
||||
warnings.add(new ExtractionWarning("CARD_BORDER_CROSSING_UNKNOWN_VRN", "Driver-card border-crossing record has unknown vehicle registration and was ignored.", path));
|
||||
continue;
|
||||
}
|
||||
Element geoCoordinates = child(gnss, "geoCoordinates");
|
||||
BigDecimal latitude = geoCoordinate(geoCoordinates, "latitude", true);
|
||||
BigDecimal longitude = geoCoordinate(geoCoordinates, "longitude", false);
|
||||
String authenticationStatus = normalizeToken(childText(gnss, "authenticationStatus"));
|
||||
supportEvents.add(new ExtractedSupportEvent(
|
||||
"CARDBORDER-" + (i + 1),
|
||||
driverKey,
|
||||
occurredAt,
|
||||
"BORDER_CROSSING",
|
||||
"BORDER_OUTBOUND",
|
||||
|
|
@ -532,6 +561,7 @@ public class DriverCardXmlExtractionService {
|
|||
|
||||
private void extractCardLoadUnloadSupportEvents(
|
||||
Element root,
|
||||
String driverKey,
|
||||
VehicleUsageLookup vehicleUsageLookup,
|
||||
List<ExtractedSupportEvent> supportEvents,
|
||||
List<ExtractionWarning> warnings
|
||||
|
|
@ -550,6 +580,10 @@ public class DriverCardXmlExtractionService {
|
|||
}
|
||||
|
||||
ExtractedCardVehicleUsageInterval usage = vehicleUsageLookup.resolve(occurredAt);
|
||||
if (!hasKnownRegistration(usage)) {
|
||||
warnings.add(new ExtractionWarning("CARD_LOAD_UNLOAD_UNKNOWN_VRN", "Driver-card load/unload record has unknown vehicle registration and was ignored.", path));
|
||||
continue;
|
||||
}
|
||||
Element gnss = child(record, "gnssPlaceAuthRecord");
|
||||
Element geoCoordinates = child(gnss, "geoCoordinates");
|
||||
BigDecimal latitude = geoCoordinate(geoCoordinates, "latitude", true);
|
||||
|
|
@ -558,6 +592,7 @@ public class DriverCardXmlExtractionService {
|
|||
String operation = mapOperation(childText(record, "operationType"));
|
||||
supportEvents.add(new ExtractedSupportEvent(
|
||||
"CARDLOAD-" + (i + 1),
|
||||
driverKey,
|
||||
occurredAt,
|
||||
"LOAD_UNLOAD",
|
||||
operation,
|
||||
|
|
@ -640,6 +675,17 @@ public class DriverCardXmlExtractionService {
|
|||
return !usage.from().isAfter(timestamp) && timestamp.isBefore(usageEndExclusive(usage, null));
|
||||
}
|
||||
|
||||
private boolean hasKnownRegistration(ExtractedCardVehicleUsageInterval usage) {
|
||||
return usage != null && hasKnownRegistrationKey(usage.registrationKey());
|
||||
}
|
||||
|
||||
private boolean hasKnownRegistrationKey(String registrationKey) {
|
||||
return registrationKey != null
|
||||
&& !registrationKey.isBlank()
|
||||
&& !registrationKey.startsWith("UNKNOWN:")
|
||||
&& !registrationKey.endsWith(":UNKNOWN");
|
||||
}
|
||||
|
||||
private OffsetDateTime usageEndExclusive(ExtractedCardVehicleUsageInterval usage, OffsetDateTime fallbackExclusiveEnd) {
|
||||
if (usage.to() == null) {
|
||||
return fallbackExclusiveEnd == null ? OffsetDateTime.MAX : fallbackExclusiveEnd;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package at.procon.eventhub.tachographfilesession.service;
|
||||
|
||||
import at.procon.eventhub.reference.DriverCardNumberNormalizer;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
|
|
@ -7,10 +8,18 @@ public class DriverKeyFactory {
|
|||
|
||||
public String createDriverKey(String cardNation, String cardNumber) {
|
||||
String normalizedNation = normalize(cardNation, "UNKNOWN");
|
||||
String normalizedCardNumber = normalize(cardNumber, "UNKNOWN");
|
||||
String normalizedCardNumber = normalize(canonicalCardNumber(cardNumber), "UNKNOWN");
|
||||
return normalizedNation + ":" + normalizedCardNumber;
|
||||
}
|
||||
|
||||
public String canonicalCardNumber(String cardNumber) {
|
||||
return DriverCardNumberNormalizer.canonical(cardNumber);
|
||||
}
|
||||
|
||||
public String fullCardNumber(String cardNumber) {
|
||||
return DriverCardNumberNormalizer.full(cardNumber);
|
||||
}
|
||||
|
||||
public String createSourceDriverId(String driverKey) {
|
||||
return "DRV:" + driverKey;
|
||||
}
|
||||
|
|
@ -23,6 +32,6 @@ public class DriverKeyFactory {
|
|||
if (value == null || value.isBlank()) {
|
||||
return fallback;
|
||||
}
|
||||
return value.trim();
|
||||
return value.trim().toUpperCase();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,9 +111,7 @@ public class IntervalBackedDriverTimelineEventBuilder implements DriverTimelineE
|
|||
eventSource,
|
||||
sourcePackageRef
|
||||
);
|
||||
List<EventHubEventDto> supportEvents = List.of();
|
||||
/*
|
||||
buildSupportEvents(
|
||||
List<EventHubEventDto> supportEvents = buildSupportEvents(
|
||||
session,
|
||||
timeline.supportEvents(),
|
||||
driverRef,
|
||||
|
|
@ -122,7 +120,6 @@ public class IntervalBackedDriverTimelineEventBuilder implements DriverTimelineE
|
|||
eventSource,
|
||||
sourcePackageRef
|
||||
);
|
||||
*/
|
||||
return new TachographTimelineEventBundle(activityEvents, vehicleUsageEvents, supportEvents);
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +306,7 @@ public class IntervalBackedDriverTimelineEventBuilder implements DriverTimelineE
|
|||
Map<String, Object> raw = new LinkedHashMap<>();
|
||||
raw.put("sourceRowId", supportEvent.eventId());
|
||||
raw.put("supportEventId", supportEvent.eventId());
|
||||
raw.put("driverKey", supportEvent.driverKey());
|
||||
raw.put("supportEventType", supportEvent.eventType());
|
||||
raw.put("slot", supportEvent.slot());
|
||||
raw.put("registrationKey", supportEvent.registrationKey());
|
||||
|
|
|
|||
|
|
@ -64,7 +64,8 @@ public class VehicleUnitXmlExtractionService {
|
|||
continue;
|
||||
}
|
||||
String cardNation = text(record, "fullCardNumber/cardIssuingMemberState");
|
||||
String cardNumber = joinCardNumber(record, "fullCardNumber/cardNumber");
|
||||
String fullCardNumber = joinCardNumber(record, "fullCardNumber/cardNumber");
|
||||
String cardNumber = driverKeyFactory.canonicalCardNumber(fullCardNumber);
|
||||
if (cardNumber == null) {
|
||||
sessionWarnings.add(new ExtractionWarning(
|
||||
"MISSING_VU_DRIVER_CARD",
|
||||
|
|
@ -86,6 +87,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
driverKeyFactory.createSourceDriverCardId(driverKey),
|
||||
cardNation,
|
||||
cardNumber,
|
||||
fullCardNumber,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
|
|
@ -366,6 +368,14 @@ public class VehicleUnitXmlExtractionService {
|
|||
Map<String, DriverExtractionBuilder> driversByKey,
|
||||
List<ExtractionWarning> warnings
|
||||
) {
|
||||
if (!hasKnownRegistration(vehicleContext.registration())) {
|
||||
warnings.add(new ExtractionWarning(
|
||||
"VU_SUPPORT_EVENTS_UNKNOWN_VRN",
|
||||
"Vehicle-unit support events were ignored because vehicle registration is unknown.",
|
||||
"/VehicleUnit/Activities"
|
||||
));
|
||||
return;
|
||||
}
|
||||
extractVuPlaceSupportEvents(document, vehicleContext, vuCardIwIntervals, driversByKey, warnings);
|
||||
extractVuGnssSupportEvents(document, vehicleContext, vuCardIwIntervals, driversByKey, warnings);
|
||||
extractVuSpecificConditionSupportEvents(document, vehicleContext, vuCardIwIntervals, driversByKey, warnings);
|
||||
|
|
@ -415,6 +425,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
assignment,
|
||||
new ExtractedSupportEvent(
|
||||
"VUPLACE-" + (i + 1) + "-" + assignment.driverKey(),
|
||||
assignment.driverKey(),
|
||||
occurredAt,
|
||||
"PLACE",
|
||||
mapPlaceEntryType(entryType),
|
||||
|
|
@ -487,6 +498,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
assignment,
|
||||
new ExtractedSupportEvent(
|
||||
"VUGNSS-" + (i + 1) + "-" + assignment.driverKey() + "-" + assignment.slot(),
|
||||
assignment.driverKey(),
|
||||
occurredAt,
|
||||
"POSITION",
|
||||
"POSITION_RECORDED",
|
||||
|
|
@ -553,6 +565,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
assignment,
|
||||
new ExtractedSupportEvent(
|
||||
"VUSC-" + (i + 1) + "-" + assignment.driverKey() + "-" + assignment.slot(),
|
||||
assignment.driverKey(),
|
||||
occurredAt,
|
||||
"SPECIFIC_CONDITION",
|
||||
specificCondition[0],
|
||||
|
|
@ -625,6 +638,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
assignment,
|
||||
new ExtractedSupportEvent(
|
||||
"VUBORDER-" + (i + 1) + "-" + assignment.driverKey() + "-" + assignment.slot(),
|
||||
assignment.driverKey(),
|
||||
occurredAt,
|
||||
"BORDER_CROSSING",
|
||||
"BORDER_OUTBOUND",
|
||||
|
|
@ -698,6 +712,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
assignment,
|
||||
new ExtractedSupportEvent(
|
||||
"VULOAD-" + (i + 1) + "-" + assignment.driverKey() + "-" + assignment.slot(),
|
||||
assignment.driverKey(),
|
||||
occurredAt,
|
||||
"LOAD_UNLOAD",
|
||||
operation,
|
||||
|
|
@ -763,6 +778,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
assignment,
|
||||
new ExtractedSupportEvent(
|
||||
"VUSPEED-" + (i + 1) + "-" + assignment.driverKey() + "-BEGIN",
|
||||
assignment.driverKey(),
|
||||
beginAt,
|
||||
"SPEEDING",
|
||||
"SPEEDING",
|
||||
|
|
@ -793,6 +809,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
assignment,
|
||||
new ExtractedSupportEvent(
|
||||
"VUSPEED-" + (i + 1) + "-" + assignment.driverKey() + "-END",
|
||||
assignment.driverKey(),
|
||||
endAt,
|
||||
"SPEEDING",
|
||||
"SPEEDING",
|
||||
|
|
@ -899,6 +916,17 @@ public class VehicleUnitXmlExtractionService {
|
|||
builder.supportEvents.add(supportEvent);
|
||||
}
|
||||
|
||||
private boolean hasKnownRegistration(ExtractedVehicleRegistration registration) {
|
||||
return registration != null && hasKnownRegistrationKey(registration.registrationKey());
|
||||
}
|
||||
|
||||
private boolean hasKnownRegistrationKey(String registrationKey) {
|
||||
return registrationKey != null
|
||||
&& !registrationKey.isBlank()
|
||||
&& !registrationKey.startsWith("UNKNOWN:")
|
||||
&& !registrationKey.endsWith(":UNKNOWN");
|
||||
}
|
||||
|
||||
private List<DriverAssignment> resolveDriverAssignments(
|
||||
OffsetDateTime occurredAt,
|
||||
String explicitDriverKey,
|
||||
|
|
@ -925,7 +953,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
|
||||
private String driverKeyFromCardNode(Element node, String basePath) {
|
||||
String cardNation = text(node, basePath + "/cardIssuingMemberState");
|
||||
String cardNumber = joinCardNumber(node, basePath + "/cardNumber");
|
||||
String cardNumber = driverKeyFactory.canonicalCardNumber(joinCardNumber(node, basePath + "/cardNumber"));
|
||||
return cardNumber == null ? null : driverKeyFactory.createDriverKey(cardNation, cardNumber);
|
||||
}
|
||||
|
||||
|
|
@ -1109,6 +1137,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
String sourceDriverCardId,
|
||||
String cardNation,
|
||||
String cardNumber,
|
||||
String fullCardNumber,
|
||||
String issuingAuthorityName,
|
||||
OffsetDateTime issueDate,
|
||||
OffsetDateTime validityBegin,
|
||||
|
|
@ -1119,6 +1148,7 @@ public class VehicleUnitXmlExtractionService {
|
|||
sourceDriverCardId,
|
||||
cardNation,
|
||||
cardNumber,
|
||||
fullCardNumber,
|
||||
issuingAuthorityName,
|
||||
issueDate,
|
||||
validityBegin,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import at.procon.eventhub.dto.DriverCardRefDto;
|
|||
import at.procon.eventhub.dto.DriverRefDto;
|
||||
import at.procon.eventhub.dto.VehicleRefDto;
|
||||
import at.procon.eventhub.dto.VehicleRegistrationRefDto;
|
||||
import at.procon.eventhub.reference.DriverCardNumberNormalizer;
|
||||
import at.procon.eventhub.yellowfox.dto.YellowFoxD8BookingDto;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
|
@ -149,10 +150,6 @@ public class YellowFoxD8BookingRowMapper {
|
|||
}
|
||||
|
||||
private String normalizeBookingDriverCardNumber(String value) {
|
||||
if (value == null || value.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.length() <= 14 ? trimmed : trimmed.substring(0, 14);
|
||||
return DriverCardNumberNormalizer.canonical(value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ class UnifiedDriverEventsRequestTest {
|
|||
" default ",
|
||||
" DRIVER:42 ",
|
||||
"at",
|
||||
" 123 ",
|
||||
" 1234567890123457 ",
|
||||
OffsetDateTime.parse("2026-05-01T00:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-02T00:00:00Z")
|
||||
);
|
||||
|
|
@ -41,7 +41,7 @@ class UnifiedDriverEventsRequestTest {
|
|||
assertThat(request.tenantKey()).isEqualTo("default");
|
||||
assertThat(request.driverSourceEntityId()).isEqualTo("DRIVER:42");
|
||||
assertThat(request.driverCardNation()).isEqualTo("AT");
|
||||
assertThat(request.driverCardNumber()).isEqualTo("123");
|
||||
assertThat(request.driverCardNumber()).isEqualTo("12345678901234");
|
||||
assertThat(request.hasDriverSelector()).isTrue();
|
||||
assertThat(request.hasVehicleSelector()).isFalse();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class UnifiedRuntimeProcessingRequestTest {
|
|||
Set.of(UnifiedEventSourceFamily.TACHOGRAPH_DB, UnifiedEventSourceFamily.YELLOWFOX_DB),
|
||||
"DRIVER:42",
|
||||
"AT",
|
||||
"123",
|
||||
"1234567890123457",
|
||||
OffsetDateTime.parse("2026-05-01T00:00:00Z"),
|
||||
OffsetDateTime.parse("2026-05-02T00:00:00Z")
|
||||
);
|
||||
|
|
@ -29,7 +29,7 @@ class UnifiedRuntimeProcessingRequestTest {
|
|||
);
|
||||
assertThat(request.driverSourceEntityId()).isEqualTo("DRIVER:42");
|
||||
assertThat(request.driverCardNation()).isEqualTo("AT");
|
||||
assertThat(request.driverCardNumber()).isEqualTo("123");
|
||||
assertThat(request.driverCardNumber()).isEqualTo("12345678901234");
|
||||
assertThat(request.eventBackend()).isEqualTo(UnifiedRuntimeEventBackend.SOURCE_DB);
|
||||
assertThat(request.expandVehicleEvents()).isTrue();
|
||||
assertThat(request.vehicleOccurredFrom()).isEqualTo(OffsetDateTime.parse("2026-05-01T00:00:00Z"));
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class TachographFileSessionRuntimeEventLoaderTest {
|
|||
return new DriverExtractionSession(
|
||||
"12:123",
|
||||
new ExtractedDriver("12:123", "DRV:12:123", "Doe", "Jane", null, null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", "123", null, null, null, null),
|
||||
List.of(new ExtractedVehicleRegistration("12:REG-1", "VR:12:REG-1", "12", "REG-1")),
|
||||
List.of(new ExtractedVehicle("VIN-1", "VIN:VIN-1", "VIN-1")),
|
||||
List.of(new ExtractedCardVehicleUsageInterval(
|
||||
|
|
@ -99,6 +99,7 @@ class TachographFileSessionRuntimeEventLoaderTest {
|
|||
)),
|
||||
List.of(new ExtractedSupportEvent(
|
||||
"SUP-1",
|
||||
"12:123",
|
||||
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
||||
"POSITION",
|
||||
"POSITION_RECORDED",
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ class UnifiedDriverEventSourceServiceTest {
|
|||
return new DriverExtractionSession(
|
||||
"12:123",
|
||||
new ExtractedDriver("12:123", "DRV:12:123", "Doe", "Jane", null, null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", "123", null, null, null, null),
|
||||
List.of(new ExtractedVehicleRegistration("12:REG-1", "VR:12:REG-1", "12", "REG-1")),
|
||||
List.of(new ExtractedVehicle("VIN-1", "VIN:VIN-1", "VIN-1")),
|
||||
List.of(new ExtractedCardVehicleUsageInterval(
|
||||
|
|
@ -115,6 +115,7 @@ class UnifiedDriverEventSourceServiceTest {
|
|||
)),
|
||||
List.of(new ExtractedSupportEvent(
|
||||
"SUP-1",
|
||||
"12:123",
|
||||
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
||||
"POSITION",
|
||||
"POSITION_RECORDED",
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class UnifiedDriverTimelineServiceTest {
|
|||
return new DriverExtractionSession(
|
||||
"12:123",
|
||||
new ExtractedDriver("12:123", "DRV:12:123", "Doe", "Jane", null, null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", "123", null, null, null, null),
|
||||
List.of(new ExtractedVehicleRegistration("12:REG-1", "VR:12:REG-1", "12", "REG-1")),
|
||||
List.of(new ExtractedVehicle("VIN-1", "VIN:VIN-1", "VIN-1")),
|
||||
List.of(new ExtractedCardVehicleUsageInterval(
|
||||
|
|
@ -100,6 +100,7 @@ class UnifiedDriverTimelineServiceTest {
|
|||
)),
|
||||
List.of(new ExtractedSupportEvent(
|
||||
"SUP-1",
|
||||
"12:123",
|
||||
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
||||
"POSITION",
|
||||
"POSITION_RECORDED",
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ class UnifiedVehicleEventSourceServiceTest {
|
|||
return new DriverExtractionSession(
|
||||
"12:123",
|
||||
new ExtractedDriver("12:123", "DRV:12:123", "Doe", "Jane", null, null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", "123", null, null, null, null),
|
||||
List.of(new ExtractedVehicleRegistration("12:REG-1", "VR:12:REG-1", "12", "REG-1")),
|
||||
List.of(new ExtractedVehicle("VIN-1", "VIN:VIN-1", "VIN-1")),
|
||||
List.of(new ExtractedCardVehicleUsageInterval(
|
||||
|
|
@ -120,6 +120,7 @@ class UnifiedVehicleEventSourceServiceTest {
|
|||
)),
|
||||
List.of(new ExtractedSupportEvent(
|
||||
"SUP-1",
|
||||
"12:123",
|
||||
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
||||
"POSITION",
|
||||
"POSITION_RECORDED",
|
||||
|
|
|
|||
|
|
@ -110,5 +110,73 @@ class DriverCardXmlExtractionServiceTest {
|
|||
assertThat(driver.cardVehicleUsageIntervals().get(1).to()).isNull();
|
||||
assertThat(driver.cardActivityIntervals()).hasSize(3);
|
||||
assertThat(driver.cardActivityIntervals().get(2).registrationKey()).isEqualTo("12:W-54321B");
|
||||
assertThat(driver.supportEvents()).hasSize(5);
|
||||
assertThat(driver.supportEvents().stream()
|
||||
.filter(event -> "12:W-54321B".equals(event.registrationKey()))
|
||||
.map(event -> event.eventDomain() + ":" + event.eventType()))
|
||||
.containsExactly("BORDER_CROSSING:BORDER_OUTBOUND", "LOAD_UNLOAD:UNLOAD");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignoresSupportEventsWhenVehicleRegistrationIsUnknown() {
|
||||
String xml = DriverCardXmlSamples.validDriverCardXml()
|
||||
.replace("<vehicleRegNumber>W-12345A</vehicleRegNumber>", "<vehicleRegNumber></vehicleRegNumber>")
|
||||
.replace("<vehicleRegNumber>W-54321B</vehicleRegNumber>", "<vehicleRegNumber></vehicleRegNumber>");
|
||||
|
||||
TachographFileSession session = service.extract(
|
||||
parser.parse(xml),
|
||||
new TachographFileSessionMetadata(
|
||||
"default",
|
||||
"legalrequirements-drivercard",
|
||||
"sample",
|
||||
"sample.ddd",
|
||||
"abc",
|
||||
10,
|
||||
"42",
|
||||
"def",
|
||||
true,
|
||||
null
|
||||
),
|
||||
Instant.now(),
|
||||
Instant.now().plus(4, ChronoUnit.HOURS)
|
||||
);
|
||||
|
||||
DriverExtractionSession driver = session.driversByKey().values().iterator().next();
|
||||
assertThat(driver.cardVehicleUsageIntervals()).hasSize(2);
|
||||
assertThat(driver.cardVehicleUsageIntervals()).extracting("registrationKey")
|
||||
.containsOnly("12:UNKNOWN");
|
||||
assertThat(driver.supportEvents()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesCanonicalCardNumberForDriverIdentityAndKeepsFullCardNumberAsEvidence() {
|
||||
String xml = DriverCardXmlSamples.validDriverCardXml()
|
||||
.replace("<driverIdentification>123456789012</driverIdentification>", "<driverIdentification>12345678901234</driverIdentification>")
|
||||
.replace("<cardReplacementIndex>0</cardReplacementIndex>", "<cardReplacementIndex>5</cardReplacementIndex>")
|
||||
.replace("<cardRenewalIndex>0</cardRenewalIndex>", "<cardRenewalIndex>7</cardRenewalIndex>");
|
||||
|
||||
TachographFileSession session = service.extract(
|
||||
parser.parse(xml),
|
||||
new TachographFileSessionMetadata(
|
||||
"default",
|
||||
"legalrequirements-drivercard",
|
||||
"sample",
|
||||
"sample.ddd",
|
||||
"abc",
|
||||
10,
|
||||
"42",
|
||||
"def",
|
||||
true,
|
||||
null
|
||||
),
|
||||
Instant.now(),
|
||||
Instant.now().plus(4, ChronoUnit.HOURS)
|
||||
);
|
||||
|
||||
DriverExtractionSession driver = session.driversByKey().values().iterator().next();
|
||||
assertThat(driver.driverKey()).isEqualTo("12:12345678901234");
|
||||
assertThat(driver.driverCard().cardNumber()).isEqualTo("12345678901234");
|
||||
assertThat(driver.driverCard().fullCardNumber()).isEqualTo("1234567890123457");
|
||||
assertThat(driver.driverCard().sourceDriverCardId()).isEqualTo("CARD:12:12345678901234");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ class DriverTimelineBuilderTest {
|
|||
),
|
||||
List.of(new ExtractedSupportEvent(
|
||||
"SUP-1",
|
||||
"12:123",
|
||||
OffsetDateTime.parse("2026-05-01T08:30:00Z"),
|
||||
"PLACE",
|
||||
"BEGIN_DAILY_WORK_PERIOD",
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class EventBackedDriverTimelineBuilderTest {
|
|||
DriverExtractionSession driver = new DriverExtractionSession(
|
||||
"12:123",
|
||||
new ExtractedDriver("12:123", "DRV:12:123", "Doe", "Jane", null, null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", "123", null, null, null, null),
|
||||
List.of(new ExtractedVehicleRegistration("12:REG-1", "VR:12:REG-1", "12", "REG-1")),
|
||||
List.of(new ExtractedVehicle("VIN-1", "VIN:VIN-1", "VIN-1")),
|
||||
List.of(new ExtractedCardVehicleUsageInterval(
|
||||
|
|
@ -70,6 +70,7 @@ class EventBackedDriverTimelineBuilderTest {
|
|||
)),
|
||||
List.of(new ExtractedSupportEvent(
|
||||
"SUP-1",
|
||||
"12:123",
|
||||
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
||||
"POSITION",
|
||||
"POSITION_RECORDED",
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class IntervalBackedDriverTimelineEventBuilderTest {
|
|||
DriverExtractionSession driver = new DriverExtractionSession(
|
||||
"12:123",
|
||||
new ExtractedDriver("12:123", "DRV:12:123", "Doe", "Jane", null, null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", "123", null, null, null, null),
|
||||
List.of(new ExtractedVehicleRegistration("12:REG-1", "VR:12:REG-1", "12", "REG-1")),
|
||||
List.of(new ExtractedVehicle("VIN-1", "VIN:VIN-1", "VIN-1")),
|
||||
List.of(new ExtractedCardVehicleUsageInterval(
|
||||
|
|
@ -92,7 +92,7 @@ class IntervalBackedDriverTimelineEventBuilderTest {
|
|||
DriverExtractionSession driver = new DriverExtractionSession(
|
||||
"12:123",
|
||||
new ExtractedDriver("12:123", "DRV:12:123", "Doe", "Jane", null, null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", null, null, null, null),
|
||||
new ExtractedDriverCard("CARD:12:123", "12", "123", "123", null, null, null, null),
|
||||
List.of(new ExtractedVehicleRegistration("12:REG-1", "VR:12:REG-1", "12", "REG-1")),
|
||||
List.of(new ExtractedVehicle("VIN-1", "VIN:VIN-1", "VIN-1")),
|
||||
List.of(new ExtractedCardVehicleUsageInterval(
|
||||
|
|
@ -108,6 +108,7 @@ class IntervalBackedDriverTimelineEventBuilderTest {
|
|||
List.of(),
|
||||
List.of(new ExtractedSupportEvent(
|
||||
"VUGNSS-1",
|
||||
"12:123",
|
||||
OffsetDateTime.parse("2026-05-01T08:45:00Z"),
|
||||
"POSITION",
|
||||
"POSITION_RECORDED",
|
||||
|
|
|
|||
|
|
@ -132,6 +132,66 @@ class VehicleUnitXmlExtractionServiceTest {
|
|||
assertThat(secondDriver.cardVehicleUsageIntervals().get(0).to()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void ignoresSupportEventsWhenVehicleRegistrationIsUnknown() throws Exception {
|
||||
String xml = VehicleUnitXmlSamples.vehicleUnitXml()
|
||||
.replace("<vehicleRegNumber>W-1000V</vehicleRegNumber>", "<vehicleRegNumber></vehicleRegNumber>");
|
||||
|
||||
TachographFileSession session = service.extract(
|
||||
new TachographXmlParser.ParsedTachographXml(document(xml), "VehicleUnit"),
|
||||
new TachographFileSessionMetadata(
|
||||
"default",
|
||||
"legalrequirements-vehicleunit",
|
||||
"sample-vu",
|
||||
"sample-vu.ddd",
|
||||
"abc",
|
||||
10,
|
||||
"42",
|
||||
"def",
|
||||
false,
|
||||
null
|
||||
),
|
||||
Instant.now(),
|
||||
Instant.now().plus(4, ChronoUnit.HOURS)
|
||||
);
|
||||
|
||||
assertThat(session.driversByKey()).hasSize(2);
|
||||
assertThat(session.driversByKey().values())
|
||||
.allSatisfy(driver -> assertThat(driver.supportEvents()).isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void usesCanonicalCardNumberForVehicleUnitDriverIdentityAndKeepsFullCardNumberAsEvidence() throws Exception {
|
||||
String xml = VehicleUnitXmlSamples.vehicleUnitXml()
|
||||
.replaceFirst("<driverIdentification>123456789012</driverIdentification>", "<driverIdentification>12345678901234</driverIdentification>")
|
||||
.replaceFirst("<cardReplacementIndex>0</cardReplacementIndex>", "<cardReplacementIndex>5</cardReplacementIndex>")
|
||||
.replaceFirst("<cardRenewalIndex>0</cardRenewalIndex>", "<cardRenewalIndex>7</cardRenewalIndex>");
|
||||
|
||||
TachographFileSession session = service.extract(
|
||||
new TachographXmlParser.ParsedTachographXml(document(xml), "VehicleUnit"),
|
||||
new TachographFileSessionMetadata(
|
||||
"default",
|
||||
"legalrequirements-vehicleunit",
|
||||
"sample-vu",
|
||||
"sample-vu.ddd",
|
||||
"abc",
|
||||
10,
|
||||
"42",
|
||||
"def",
|
||||
false,
|
||||
null
|
||||
),
|
||||
Instant.now(),
|
||||
Instant.now().plus(4, ChronoUnit.HOURS)
|
||||
);
|
||||
|
||||
DriverExtractionSession firstDriver = session.driversByKey().get("12:12345678901234");
|
||||
assertThat(firstDriver).isNotNull();
|
||||
assertThat(firstDriver.driverCard().cardNumber()).isEqualTo("12345678901234");
|
||||
assertThat(firstDriver.driverCard().fullCardNumber()).isEqualTo("1234567890123457");
|
||||
assertThat(firstDriver.driverCard().sourceDriverCardId()).isEqualTo("CARD:12:12345678901234");
|
||||
}
|
||||
|
||||
private Document document(String xml) throws Exception {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(false);
|
||||
|
|
|
|||
Loading…
Reference in New Issue