diff --git a/srv/src/main/java/sap/capire/xtravels/handler/FederationHandler.java b/srv/src/main/java/sap/capire/xtravels/handler/FederationHandler.java index a342b57..c08fee2 100644 --- a/srv/src/main/java/sap/capire/xtravels/handler/FederationHandler.java +++ b/srv/src/main/java/sap/capire/xtravels/handler/FederationHandler.java @@ -12,7 +12,6 @@ import cds.gen.sap.capire.flights.data.Data; import cds.gen.sap.capire.xflights.Flights; import cds.gen.sap.capire.xflights.Supplements; -import com.google.common.collect.Maps; import com.sap.cds.CdsData; import com.sap.cds.Result; import com.sap.cds.impl.DataProcessor; @@ -36,18 +35,22 @@ import com.sap.cds.services.handler.annotations.ServiceName; import com.sap.cds.services.persistence.PersistenceService; import com.sap.cds.services.runtime.CdsRuntime; +import com.sap.cds.util.CdsModelUtils; import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceConfiguration; import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceConfiguration.TimeLimiterConfiguration; import com.sap.cloud.sdk.cloudplatform.resilience.ResilienceDecorator; import java.time.Duration; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.env.Environment; import org.springframework.stereotype.Component; @Component @@ -62,15 +65,19 @@ class FederationHandler implements EventHandler { private final PersistenceService db; private final Data dataService; private final CdsRuntime runtime; + private final Environment env; - FederationHandler(PersistenceService db, Data dataService, CdsRuntime runtime) { + FederationHandler(PersistenceService db, Data dataService, CdsRuntime runtime, Environment env) { this.db = db; this.dataService = dataService; this.runtime = runtime; + this.env = env; } @On(serviceType = ApplicationLifecycleService.class) void initialLoad(ApplicationPreparedEventContext context) { + if (env.getProperty("skip-initial-load", Boolean.class, false)) return; + // initial load for Flights logger.info("Performing initial load for Flights"); var bookingFlights = @@ -127,10 +134,18 @@ void replicateAssociations(CdsStructuredType type, Map data) { CdsAssociationType assoc = element.getType().as(CdsAssociationType.class); CdsEntity target = assoc.getTarget(); if (isFederated(target)) { - List fks = assoc.refs().map(r -> r.path()).toList(); - Map fkValues = Maps.filterKeys(data, fks::contains); - if (fks.size() == target.keyElements().count() && !isReplicated(target, fkValues)) { - replicateInstance(target, fkValues); + Map keyValues = new HashMap<>(); + if (data.get(element.getName()) instanceof Map assocData) { // + Set keys = CdsModelUtils.keyNames(target); + keys.forEach(k -> keyValues.put(k, assocData.get(k))); + } else { + assoc + .refs() + .forEach( + r -> keyValues.put(r.path(), data.get(element.getName() + "_" + r.path()))); + } + if (!keyValues.containsValue(null) && !isReplicated(target, keyValues)) { + replicateInstance(target, keyValues); } } }; diff --git a/srv/src/main/java/sap/capire/xtravels/handler/RecalculatePriceHandler.java b/srv/src/main/java/sap/capire/xtravels/handler/RecalculatePriceHandler.java index 3f55b09..9fce291 100644 --- a/srv/src/main/java/sap/capire/xtravels/handler/RecalculatePriceHandler.java +++ b/srv/src/main/java/sap/capire/xtravels/handler/RecalculatePriceHandler.java @@ -16,8 +16,9 @@ import com.sap.cds.ql.cqn.CqnSelectListValue; import com.sap.cds.ql.cqn.CqnStructuredTypeRef; import com.sap.cds.ql.cqn.CqnValue; -import com.sap.cds.services.draft.DraftCancelEventContext; -import com.sap.cds.services.draft.DraftPatchEventContext; +import com.sap.cds.services.EventContext; +import com.sap.cds.services.cds.CqnService; +import com.sap.cds.services.draft.DraftService; import com.sap.cds.services.handler.EventHandler; import com.sap.cds.services.handler.annotations.After; import com.sap.cds.services.handler.annotations.ServiceName; @@ -39,16 +40,25 @@ class RecalculatePriceHandler implements EventHandler { this.service = service; } - @After(entity = {Travels_.CDS_NAME, Bookings_.CDS_NAME, Bookings_.Supplements_.CDS_NAME}) - void updateTotalsOnPatch(CqnStructuredTypeRef ref, CdsData data, DraftPatchEventContext context) { + @After( + entity = {Travels_.CDS_NAME, Bookings_.CDS_NAME, Bookings_.Supplements_.CDS_NAME}, + event = {CqnService.EVENT_CREATE, CqnService.EVENT_UPDATE, DraftService.EVENT_DRAFT_PATCH}) + void updateTotalsOnPatch(CqnStructuredTypeRef ref, CdsData data, EventContext context) { if (!(data.containsKey(Travels.BOOKING_FEE) || data.containsKey(Bookings.FLIGHT_PRICE) || data.containsKey(Bookings.Supplements.PRICE))) return; + + if (context.getEvent().equals(CqnService.EVENT_CREATE) + && context.getTarget().getQualifiedName().equals(Travels_.CDS_NAME)) { + ref = Travels.of(data).ref().asRef(); + } updateTotals(ref); } - @After(entity = {Bookings_.CDS_NAME, Bookings_.Supplements_.CDS_NAME}) - void updateTotalsOnDelete(CqnStructuredTypeRef ref, DraftCancelEventContext context) { + @After( + entity = {Bookings_.CDS_NAME, Bookings_.Supplements_.CDS_NAME}, + event = {CqnService.EVENT_DELETE, DraftService.EVENT_DRAFT_CANCEL}) + void updateTotalsOnDelete(CqnStructuredTypeRef ref) { updateTotals(ref); } diff --git a/srv/src/test/java/sap/capire/xtravels/TestData.java b/srv/src/test/java/sap/capire/xtravels/TestData.java index e1ff0e6..9f691f1 100644 --- a/srv/src/test/java/sap/capire/xtravels/TestData.java +++ b/srv/src/test/java/sap/capire/xtravels/TestData.java @@ -1,6 +1,7 @@ package sap.capire.xtravels; import cds.gen.travelservice.Bookings; +import cds.gen.travelservice.Supplements; import cds.gen.travelservice.Travels; import java.math.BigDecimal; import java.time.LocalDate; @@ -32,7 +33,7 @@ public static Bookings createBookingData() { public static Bookings.Supplements createSupplementData() { Bookings.Supplements supplement = Bookings.Supplements.create(); - supplement.setBookedId("bv-0001"); + supplement.setBooked(Supplements.create("bv-0001")); supplement.setPrice(new BigDecimal("2.30")); supplement.setCurrencyCode("EUR"); return supplement; diff --git a/srv/src/test/java/sap/capire/xtravels/it/TravelServiceIntegrationTest.java b/srv/src/test/java/sap/capire/xtravels/it/TravelServiceIntegrationTest.java index 9b2fbc2..c05e56d 100644 --- a/srv/src/test/java/sap/capire/xtravels/it/TravelServiceIntegrationTest.java +++ b/srv/src/test/java/sap/capire/xtravels/it/TravelServiceIntegrationTest.java @@ -29,7 +29,7 @@ import org.springframework.test.web.servlet.MockMvc; /** Integration tests for the CAP Travel Service OData endpoints */ -@SpringBootTest +@SpringBootTest(properties = "skip-initial-load=true") @AutoConfigureMockMvc class TravelServiceIntegrationTest { @@ -147,6 +147,7 @@ void shouldCreateAndRetrieveTravelWithBookingsSuccessfully() throws Exception { + ",IsActiveEntity=true)?$expand=Bookings($expand=Flight,Supplements($expand=booked))")) .andExpect(status().isOk()) .andExpect(content().contentTypeCompatibleWith("application/json")) + .andExpect(jsonPath("$.TotalPrice").value(1205)) .andExpect(jsonPath("$.Bookings[0].Flight.origin").value("Miami International Airport")) .andExpect(jsonPath("$.Bookings[0].Supplements[0].booked.descr").value("Hot Chocolate")); }