From dfdc5cdeb99041cafbd93442cefbcf38bc3350cd Mon Sep 17 00:00:00 2001 From: trifonovt <87468028+TihomirTrifonov@users.noreply.github.com> Date: Fri, 1 May 2026 09:47:00 +0200 Subject: [PATCH] Add tachograph load unload extractors --- README.md | 4 + ...AbstractTachographLoadUnloadRowMapper.java | 220 ++++++++++++++++++ .../service/CardLoadUnloadRowMapper.java | 12 + ...achographExtractionDefinitionRegistry.java | 20 +- .../service/VuLoadUnloadRowMapper.java | 12 + .../sql/tachograph/card-load-unload.sql | 101 ++++++++ .../sql/tachograph/vu-load-unload.sql | 105 +++++++++ .../TachographImportPlanServiceTest.java | 19 +- 8 files changed, 490 insertions(+), 3 deletions(-) create mode 100644 src/main/java/at/procon/eventhub/tachograph/service/AbstractTachographLoadUnloadRowMapper.java create mode 100644 src/main/java/at/procon/eventhub/tachograph/service/CardLoadUnloadRowMapper.java create mode 100644 src/main/java/at/procon/eventhub/tachograph/service/VuLoadUnloadRowMapper.java create mode 100644 src/main/resources/sql/tachograph/card-load-unload.sql create mode 100644 src/main/resources/sql/tachograph/vu-load-unload.sql diff --git a/README.md b/README.md index 1d805b7..6895ed8 100644 --- a/README.md +++ b/README.md @@ -820,16 +820,20 @@ CARD_VEHICLES_USED -> DRIVER_CARD / DRIVER_CARD / CardVehiclesUsed IW_CYCLE -> DRIVER_CARD / VEHICLE_UNIT / IWCycle CARD_BORDER_CROSSING -> BORDER_CROSSING / DRIVER_CARD / CardBorderCrossing VU_BORDER_CROSSING -> BORDER_CROSSING / VEHICLE_UNIT / VUBorderCrossing +CARD_LOAD_UNLOAD -> LOAD_UNLOAD / DRIVER_CARD / CardLoadUnload +VU_LOAD_UNLOAD -> LOAD_UNLOAD / VEHICLE_UNIT / VULoadUnload ``` SQL resources: ```text src/main/resources/sql/tachograph/card-border-crossing.sql +src/main/resources/sql/tachograph/card-load-unload.sql src/main/resources/sql/tachograph/card-vehicles-used.sql src/main/resources/sql/tachograph/card-activity.sql src/main/resources/sql/tachograph/iw-cycle.sql src/main/resources/sql/tachograph/vu-border-crossing.sql +src/main/resources/sql/tachograph/vu-load-unload.sql src/main/resources/sql/tachograph/vu-activity.sql ``` diff --git a/src/main/java/at/procon/eventhub/tachograph/service/AbstractTachographLoadUnloadRowMapper.java b/src/main/java/at/procon/eventhub/tachograph/service/AbstractTachographLoadUnloadRowMapper.java new file mode 100644 index 0000000..85c9120 --- /dev/null +++ b/src/main/java/at/procon/eventhub/tachograph/service/AbstractTachographLoadUnloadRowMapper.java @@ -0,0 +1,220 @@ +package at.procon.eventhub.tachograph.service; + +import at.procon.eventhub.dto.DriverCardRefDto; +import at.procon.eventhub.dto.DriverRefDto; +import at.procon.eventhub.dto.EventDomain; +import at.procon.eventhub.dto.EventHubEventDto; +import at.procon.eventhub.dto.EventLifecycle; +import at.procon.eventhub.dto.EventType; +import at.procon.eventhub.dto.GeoPointDto; +import at.procon.eventhub.dto.SourcePackageRefDto; +import at.procon.eventhub.dto.VehicleRefDto; +import at.procon.eventhub.dto.VehicleRegistrationRefDto; +import at.procon.eventhub.importing.extraction.ExtractionContext; +import at.procon.eventhub.importing.extraction.ExtractionRowMapper; +import at.procon.eventhub.service.EventDetailsFactory; +import at.procon.eventhub.tachograph.dto.TachographImportRequest; +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +abstract class AbstractTachographLoadUnloadRowMapper implements ExtractionRowMapper { + + private final EventDetailsFactory detailsFactory; + + protected AbstractTachographLoadUnloadRowMapper(EventDetailsFactory detailsFactory) { + this.detailsFactory = detailsFactory; + } + + @Override + public EventHubEventDto map(ResultSet rs, int rowNum, ExtractionContext context) throws SQLException { + OffsetDateTime occurredAt = offsetDateTime(rs, "occurred_at"); + SourcePackageRefDto sourcePackageRef = sourcePackageRef(rs); + DriverRefDto driverRef = driverRef(rs); + VehicleRefDto vehicleRef = vehicleRef(rs); + EventType eventType = eventType(rs); + + String externalSourceEventId = string(rs, "external_source_event_id"); + if (externalSourceEventId == null) { + externalSourceEventId = defaultExternalSourceEventId(context, rowNum, occurredAt, sourcePackageRef, driverRef, vehicleRef, eventType); + } + + return new EventHubEventDto( + UUID.randomUUID(), + externalSourceEventId, + driverRef, + vehicleRef, + occurredAt, + offsetDateTime(rs, "received_partner_at"), + OffsetDateTime.now(), + EventDomain.LOAD_UNLOAD, + eventType, + EventLifecycle.SNAPSHOT, + longValue(rs, "odometer_m"), + position(rs), + detailsFactory.loadUnload(string(rs, "operation")), + sourcePackageRef != null && sourcePackageRef.hasAnyReference() ? sourcePackageRef : null, + detailsFactory.payloadFromMap(payload(rs)), + false, + context.packageInfo() + ); + } + + protected Map sourceSpecificPayload(ResultSet rs) throws SQLException { + return Map.of(); + } + + private DriverRefDto driverRef(ResultSet rs) throws SQLException { + DriverCardRefDto driverCard = null; + String cardNumber = string(rs, "driver_card_number"); + if (cardNumber != null) { + driverCard = new DriverCardRefDto(string(rs, "driver_card_nation"), cardNumber); + } + DriverRefDto driverRef = new DriverRefDto(string(rs, "driver_source_entity_id"), driverCard); + return driverRef.hasAnyReference() ? driverRef : null; + } + + private VehicleRefDto vehicleRef(ResultSet rs) throws SQLException { + VehicleRegistrationRefDto registration = null; + String registrationNumber = string(rs, "vehicle_registration_number"); + if (registrationNumber != null) { + registration = new VehicleRegistrationRefDto(string(rs, "vehicle_registration_nation"), registrationNumber); + } + VehicleRefDto vehicleRef = new VehicleRefDto( + string(rs, "vehicle_source_entity_id"), + string(rs, "vehicle_vin"), + string(rs, "vehicle_registration_source_entity_id"), + registration + ); + return vehicleRef.hasAnyReference() ? vehicleRef : null; + } + + private SourcePackageRefDto sourcePackageRef(ResultSet rs) throws SQLException { + return new SourcePackageRefDto( + string(rs, "source_package_kind"), + string(rs, "source_package_id"), + string(rs, "source_package_entity_id"), + offsetDateTime(rs, "source_package_period_from"), + offsetDateTime(rs, "source_package_period_to"), + offsetDateTime(rs, "source_package_imported_at") + ); + } + + private GeoPointDto position(ResultSet rs) throws SQLException { + BigDecimal latitude = decimal(rs, "latitude"); + BigDecimal longitude = decimal(rs, "longitude"); + return latitude == null || longitude == null ? null : new GeoPointDto(latitude, longitude); + } + + private Map payload(ResultSet rs) throws SQLException { + Map raw = new LinkedHashMap<>(); + put(raw, "sourceRowId", string(rs, "source_row_id")); + raw.putAll(sourceSpecificPayload(rs)); + return Map.of("raw", raw); + } + + private String defaultExternalSourceEventId( + ExtractionContext context, + int rowNum, + OffsetDateTime occurredAt, + SourcePackageRefDto sourcePackageRef, + DriverRefDto driverRef, + VehicleRefDto vehicleRef, + EventType eventType + ) { + String sourcePackageId = sourcePackageRef == null || sourcePackageRef.sourcePackageId() == null + ? "NO_SOURCE_PACKAGE" + : sourcePackageRef.sourcePackageId(); + String subject = driverRef != null && driverRef.hasAnyReference() + ? driverRef.stableKey() + : vehicleRef == null ? "NO_SUBJECT" : vehicleRef.stableKey(); + return "TACHOGRAPH:" + context.planItem().extractionCode() + + ":" + sourcePackageId + + ":" + eventType + + ":" + occurredAt + + ":" + subject + + ":ROW-" + rowNum; + } + + protected String string(ResultSet rs, String column) throws SQLException { + String value = rs.getString(column); + return value == null || value.isBlank() ? null : value.trim(); + } + + protected OffsetDateTime offsetDateTime(ResultSet rs, String column) throws SQLException { + Object value = rs.getObject(column); + if (value == null) { + return null; + } + if (value instanceof OffsetDateTime offsetDateTime) { + return offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC); + } + if (value instanceof Timestamp timestamp) { + return timestamp.toLocalDateTime().atOffset(ZoneOffset.UTC); + } + if (value instanceof LocalDateTime localDateTime) { + return localDateTime.atOffset(ZoneOffset.UTC); + } + String text = value.toString(); + try { + return OffsetDateTime.parse(text).withOffsetSameInstant(ZoneOffset.UTC); + } catch (RuntimeException ignored) { + return LocalDateTime.parse(text).atOffset(ZoneOffset.UTC); + } + } + + private Long longValue(ResultSet rs, String column) throws SQLException { + Object value = rs.getObject(column); + if (value == null) { + return null; + } + if (value instanceof Number number) { + return number.longValue(); + } + return Long.parseLong(value.toString()); + } + + private BigDecimal decimal(ResultSet rs, String column) throws SQLException { + Object value = rs.getObject(column); + if (value == null) { + return null; + } + if (value instanceof BigDecimal bigDecimal) { + return bigDecimal; + } + if (value instanceof Number number) { + return BigDecimal.valueOf(number.doubleValue()); + } + return new BigDecimal(value.toString()); + } + + private EventType eventType(ResultSet rs) throws SQLException { + return parseEnum(EventType.class, string(rs, "event_type"), EventType.LOAD_UNLOAD); + } + + private > T parseEnum(Class type, String value, T fallback) { + if (value == null) { + return fallback; + } + String normalized = value.trim().toUpperCase(Locale.ROOT).replace('-', '_').replace(' ', '_'); + try { + return Enum.valueOf(type, normalized); + } catch (IllegalArgumentException ignored) { + return fallback; + } + } + + protected void put(Map target, String key, Object value) { + if (value != null) { + target.put(key, value); + } + } +} diff --git a/src/main/java/at/procon/eventhub/tachograph/service/CardLoadUnloadRowMapper.java b/src/main/java/at/procon/eventhub/tachograph/service/CardLoadUnloadRowMapper.java new file mode 100644 index 0000000..bfeff59 --- /dev/null +++ b/src/main/java/at/procon/eventhub/tachograph/service/CardLoadUnloadRowMapper.java @@ -0,0 +1,12 @@ +package at.procon.eventhub.tachograph.service; + +import at.procon.eventhub.service.EventDetailsFactory; +import org.springframework.stereotype.Component; + +@Component +public class CardLoadUnloadRowMapper extends AbstractTachographLoadUnloadRowMapper { + + public CardLoadUnloadRowMapper(EventDetailsFactory detailsFactory) { + super(detailsFactory); + } +} diff --git a/src/main/java/at/procon/eventhub/tachograph/service/TachographExtractionDefinitionRegistry.java b/src/main/java/at/procon/eventhub/tachograph/service/TachographExtractionDefinitionRegistry.java index 773e31b..428c961 100644 --- a/src/main/java/at/procon/eventhub/tachograph/service/TachographExtractionDefinitionRegistry.java +++ b/src/main/java/at/procon/eventhub/tachograph/service/TachographExtractionDefinitionRegistry.java @@ -16,7 +16,9 @@ public class TachographExtractionDefinitionRegistry extends ExtractionDefinition IwCycleCardEventRowMapper iwCycleCardEventRowMapper, CardVehiclesUsedCardEventRowMapper cardVehiclesUsedCardEventRowMapper, VuBorderCrossingRowMapper vuBorderCrossingRowMapper, - CardBorderCrossingRowMapper cardBorderCrossingRowMapper + CardBorderCrossingRowMapper cardBorderCrossingRowMapper, + VuLoadUnloadRowMapper vuLoadUnloadRowMapper, + CardLoadUnloadRowMapper cardLoadUnloadRowMapper ) { super(List.of( new ExtractionDefinition<>( @@ -66,6 +68,22 @@ public class TachographExtractionDefinitionRegistry extends ExtractionDefinition "DRIVER", "classpath:sql/tachograph/card-border-crossing.sql", cardBorderCrossingRowMapper + ), + new ExtractionDefinition<>( + "VU_LOAD_UNLOAD", + EventFamily.LOAD_UNLOAD, + "VEHICLE_UNIT", + "VEHICLE", + "classpath:sql/tachograph/vu-load-unload.sql", + vuLoadUnloadRowMapper + ), + new ExtractionDefinition<>( + "CARD_LOAD_UNLOAD", + EventFamily.LOAD_UNLOAD, + "DRIVER_CARD", + "DRIVER", + "classpath:sql/tachograph/card-load-unload.sql", + cardLoadUnloadRowMapper ) )); } diff --git a/src/main/java/at/procon/eventhub/tachograph/service/VuLoadUnloadRowMapper.java b/src/main/java/at/procon/eventhub/tachograph/service/VuLoadUnloadRowMapper.java new file mode 100644 index 0000000..151e110 --- /dev/null +++ b/src/main/java/at/procon/eventhub/tachograph/service/VuLoadUnloadRowMapper.java @@ -0,0 +1,12 @@ +package at.procon.eventhub.tachograph.service; + +import at.procon.eventhub.service.EventDetailsFactory; +import org.springframework.stereotype.Component; + +@Component +public class VuLoadUnloadRowMapper extends AbstractTachographLoadUnloadRowMapper { + + public VuLoadUnloadRowMapper(EventDetailsFactory detailsFactory) { + super(detailsFactory); + } +} diff --git a/src/main/resources/sql/tachograph/card-load-unload.sql b/src/main/resources/sql/tachograph/card-load-unload.sql new file mode 100644 index 0000000..ec837e4 --- /dev/null +++ b/src/main/resources/sql/tachograph/card-load-unload.sql @@ -0,0 +1,101 @@ +/* + * CardLoadUnload LOAD_UNLOAD extraction for the bytebar tachograph schema. + */ +with OrgTree as ( + select org.I_90021_OID + from dbo.GetOrganisationTree(null, :organisationId, 0, null) org + where :organisationId is not null +) +, +Base as ( + select + lu.ID, + lu.Timestamp as occurred_at, + lu.OperationType, + lu.Odo, + lu.ID_FileLog, + c.ID as card_id, + c.ID_Driver as driver_id, + cn.AlphaCode as driver_card_nation, + c.CardNumber as driver_card_number, + gnss.Latitude as latitude, + gnss.Longitude as longitude, + v.ID as vehicle_registration_id, + v.ID_VehicleIdentification as vehicle_identification_id, + vi.VIN as vehicle_vin, + vehicleNation.AlphaCode as vehicle_registration_nation, + v.VRN as vehicle_registration_number, + coalesce(fl.DownloadDate, fl.OriginalDownloadDate, fl.TStamp, fl.CreationDate) as received_partner_at, + coalesce(fl.ID, lu.ID_FileLog, lu.ID) as source_package_id_raw, + coalesce(fl.ID_Card, lu.ID_Card) as source_package_entity_id_raw, + coalesce(fl.DownloadFrom, lu.Timestamp) as source_package_period_from, + coalesce(fl.DownloadTo, lu.Timestamp) as source_package_period_to, + coalesce(fl.CreationDate, fl.TStamp) as source_package_imported_at + from dbo.CardLoadUnload lu + join dbo.Card c on c.ID = lu.ID_Card + left join dbo.Nation cn on cn.ID = c.ID_Nation + left join dbo.GnssPlace gnss on gnss.ID = lu.ID_GnssPlace + left join dbo.FileLog fl on fl.ID = lu.ID_FileLog + outer apply ( + select top 1 used.ID_Vehicle + from dbo.CardVehiclesUsed used + where used.ID_Card = lu.ID_Card + and (used.FirstUse is null or used.FirstUse <= lu.Timestamp) + and (used.LastUse is null or used.LastUse >= lu.Timestamp) + order by + used.FirstUse desc, + used.ID desc + ) cvu + left join dbo.Vehicle v on v.ID = cvu.ID_Vehicle + left join dbo.VehicleIdentification vi on vi.ID = v.ID_VehicleIdentification + left join dbo.Nation vehicleNation on vehicleNation.ID = v.ID_Nation + where (:occurredFrom is null or lu.Timestamp >= :occurredFrom) + and (:occurredTo is null or lu.Timestamp < :occurredTo) + and ( + :organisationId is null + or exists ( + select 1 + from dbo.Driver_I_90021 rel + join OrgTree on OrgTree.I_90021_OID = rel.ID_I_90021 + where rel.ID_Driver = c.ID_Driver + and rel.GILT_BIS is null + ) + ) +) +select + cast(base.ID as varchar(128)) as source_row_id, + concat('TACHOGRAPH:CARD_LOAD_UNLOAD:', base.ID) as external_source_event_id, + + base.occurred_at, + base.received_partner_at, + cast(base.Odo as bigint) * 1000 as odometer_m, + base.latitude, + base.longitude, + case base.OperationType + when 1 then 'LOAD' + when 2 then 'UNLOAD' + else 'LOAD_UNLOAD' + end as operation, + case base.OperationType + when 1 then 'LOAD' + when 2 then 'UNLOAD' + else 'LOAD_UNLOAD' + end as event_type, + + cast(base.driver_id as varchar(128)) as driver_source_entity_id, + base.driver_card_nation, + base.driver_card_number, + + cast(base.vehicle_identification_id as varchar(128)) as vehicle_source_entity_id, + base.vehicle_vin, + cast(base.vehicle_registration_id as varchar(128)) as vehicle_registration_source_entity_id, + base.vehicle_registration_nation, + base.vehicle_registration_number, + + 'DRIVER_CARD' as source_package_kind, + cast(base.source_package_id_raw as varchar(128)) as source_package_id, + cast(base.source_package_entity_id_raw as varchar(128)) as source_package_entity_id, + base.source_package_period_from, + base.source_package_period_to, + base.source_package_imported_at +from Base base diff --git a/src/main/resources/sql/tachograph/vu-load-unload.sql b/src/main/resources/sql/tachograph/vu-load-unload.sql new file mode 100644 index 0000000..0716b65 --- /dev/null +++ b/src/main/resources/sql/tachograph/vu-load-unload.sql @@ -0,0 +1,105 @@ +/* + * VULoadUnload LOAD_UNLOAD extraction for the bytebar tachograph schema. + */ +with OrgTree as ( + select org.I_90021_OID + from dbo.GetOrganisationTree(null, :organisationId, 0, null) org + where :organisationId is not null +) +, +Base as ( + select + lu.ID, + lu.Timestamp as occurred_at, + lu.OperationType, + lu.Odo, + lu.ID_FileLog, + lu.ID_VUInstallation, + coalesce(driverCard.ID, coDriverCard.ID) as card_id, + coalesce(driverCard.ID_Driver, coDriverCard.ID_Driver) as driver_id, + coalesce(driverNation.AlphaCode, coDriverNation.AlphaCode) as driver_card_nation, + coalesce(driverCard.CardNumber, coDriverCard.CardNumber) as driver_card_number, + gnss.Latitude as latitude, + gnss.Longitude as longitude, + vui.ID_FileLog as vui_filelog_id, + vui.ID_VehicleIdentification, + vi.ID as vehicle_identification_id, + vi.VIN as vehicle_vin, + coalesce(fl.DownloadDate, fl.OriginalDownloadDate, fl.TStamp, fl.CreationDate) as received_partner_at, + coalesce(fl.ID, lu.ID_FileLog, vui.ID_FileLog, lu.ID) as source_package_id_raw, + coalesce(fl.ID_VehicleIdentification, vui.ID_VehicleIdentification) as source_package_entity_id_raw, + coalesce(fl.DownloadFrom, lu.Timestamp) as source_package_period_from, + coalesce(fl.DownloadTo, lu.Timestamp) as source_package_period_to, + coalesce(fl.CreationDate, fl.TStamp) as source_package_imported_at + from dbo.VULoadUnload lu + join dbo.VUInstallation vui on vui.ID = lu.ID_VUInstallation + join dbo.VehicleIdentification vi on vi.ID = vui.ID_VehicleIdentification + left join dbo.Card driverCard on driverCard.ID = lu.ID_DriverCard + left join dbo.Nation driverNation on driverNation.ID = driverCard.ID_Nation + left join dbo.Card coDriverCard on coDriverCard.ID = lu.ID_CoDriverCard + left join dbo.Nation coDriverNation on coDriverNation.ID = coDriverCard.ID_Nation + left join dbo.GnssPlace gnss on gnss.ID = lu.ID_GnssPlace + left join dbo.FileLog fl on fl.ID = coalesce(lu.ID_FileLog, vui.ID_FileLog) + where (:occurredFrom is null or lu.Timestamp >= :occurredFrom) + and (:occurredTo is null or lu.Timestamp < :occurredTo) +) +select + cast(base.ID as varchar(128)) as source_row_id, + concat('TACHOGRAPH:VU_LOAD_UNLOAD:', base.ID) as external_source_event_id, + + base.occurred_at, + base.received_partner_at, + cast(base.Odo as bigint) * 1000 as odometer_m, + base.latitude, + base.longitude, + case base.OperationType + when 1 then 'LOAD' + when 2 then 'UNLOAD' + else 'LOAD_UNLOAD' + end as operation, + case base.OperationType + when 1 then 'LOAD' + when 2 then 'UNLOAD' + else 'LOAD_UNLOAD' + end as event_type, + + cast(base.driver_id as varchar(128)) as driver_source_entity_id, + base.driver_card_nation, + base.driver_card_number, + + cast(base.vehicle_identification_id as varchar(128)) as vehicle_source_entity_id, + base.vehicle_vin, + cast(v.ID as varchar(128)) as vehicle_registration_source_entity_id, + vn.AlphaCode as vehicle_registration_nation, + v.VRN as vehicle_registration_number, + + 'VEHICLE_UNIT' as source_package_kind, + cast(base.source_package_id_raw as varchar(128)) as source_package_id, + cast(base.source_package_entity_id_raw as varchar(128)) as source_package_entity_id, + base.source_package_period_from, + base.source_package_period_to, + base.source_package_imported_at +from Base base +outer apply ( + select top 1 vehicle.ID, + vehicle.VRN, + vehicle.ID_Nation + from dbo.Vehicle vehicle + where vehicle.ID_VehicleIdentification = base.vehicle_identification_id + and (vehicle.ValidFrom is null or vehicle.ValidFrom <= base.occurred_at) + and (vehicle.ValidTo is null or vehicle.ValidTo > base.occurred_at) + order by + vehicle.ValidFrom desc, + vehicle.ID desc +) v +left join dbo.Nation vn on vn.ID = v.ID_Nation +where ( + :organisationId is null + or exists ( + select 1 + from dbo.Vehicle_I_90021 rel + join OrgTree on OrgTree.I_90021_OID = rel.ID_I_90021 + where rel.ID_Vehicle = v.ID + and rel.GILT_BIS is null + ) + ) diff --git a/src/test/java/at/procon/eventhub/tachograph/service/TachographImportPlanServiceTest.java b/src/test/java/at/procon/eventhub/tachograph/service/TachographImportPlanServiceTest.java index 078af6f..70db0df 100644 --- a/src/test/java/at/procon/eventhub/tachograph/service/TachographImportPlanServiceTest.java +++ b/src/test/java/at/procon/eventhub/tachograph/service/TachographImportPlanServiceTest.java @@ -24,7 +24,9 @@ class TachographImportPlanServiceTest { new IwCycleCardEventRowMapper(detailsFactory), new CardVehiclesUsedCardEventRowMapper(detailsFactory), new VuBorderCrossingRowMapper(detailsFactory), - new CardBorderCrossingRowMapper(detailsFactory) + new CardBorderCrossingRowMapper(detailsFactory), + new VuLoadUnloadRowMapper(detailsFactory), + new CardLoadUnloadRowMapper(detailsFactory) ); @Test @@ -38,7 +40,8 @@ class TachographImportPlanServiceTest { .hasMessageContaining("Supported JDBC extraction codes") .hasMessageContaining("DRIVER_ACTIVITY") .hasMessageContaining("DRIVER_CARD") - .hasMessageContaining("BORDER_CROSSING"); + .hasMessageContaining("BORDER_CROSSING") + .hasMessageContaining("LOAD_UNLOAD"); } @Test @@ -77,6 +80,18 @@ class TachographImportPlanServiceTest { .containsExactlyInAnyOrder("VU_BORDER_CROSSING", "CARD_BORDER_CROSSING"); } + @Test + void allowsSupportedLoadUnloadFamilyWhenJdbcExtractionIsEnabled() { + TachographImportPlanService service = serviceWithJdbcExtractor(); + TachographImportRequest request = requestForFamilies(EventFamily.LOAD_UNLOAD); + + var plan = service.createPlan(request); + + assertThat(plan.items()) + .extracting(item -> item.extractionCode()) + .containsExactlyInAnyOrder("VU_LOAD_UNLOAD", "CARD_LOAD_UNLOAD"); + } + private TachographImportPlanService serviceWithJdbcExtractor() { EventHubProperties properties = new EventHubProperties(); properties.getTachograph().getDatasource().setJdbcUrl("jdbc:sqlserver://tachograph-db");