diff --git a/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java b/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java index 2b0857269..19e548f57 100644 --- a/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java +++ b/src/main/java/org/gridsuite/modification/server/NetworkModificationController.java @@ -342,6 +342,17 @@ public ResponseEntity>> searchModifica .body(networkModificationService.searchNetworkModifications(networkUuid, userInput)); } + @GetMapping(value = "/network-composite-modifications/network-modifications-with-missing-info", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Get the list of all the network modifications inside a list of composite modifications with information about missing composite modifications") + @ApiResponse(responseCode = "200", description = "List of modifications inside the composite modifications and list of missing composite modifications UUIDs") + public ResponseEntity getNetworkModificationsFromCompositeWithMissingInfo( + @Parameter(description = "Composite modifications uuids list") @RequestParam("uuids") List compositeModificationUuids) { + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_JSON) + .body(networkModificationService.getNetworkModificationsFromCompositeWithMissingInfo(compositeModificationUuids) + ); + } + @GetMapping(value = "/network-modifications/busbar-sections-for-new-coupler", produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Generate bus bar section suggestions for new coupler") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "List of generated bus bar sections ids") diff --git a/src/main/java/org/gridsuite/modification/server/dto/NetworkModificationsWithMissingInfo.java b/src/main/java/org/gridsuite/modification/server/dto/NetworkModificationsWithMissingInfo.java new file mode 100644 index 000000000..52f5b7ab1 --- /dev/null +++ b/src/main/java/org/gridsuite/modification/server/dto/NetworkModificationsWithMissingInfo.java @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.modification.server.dto; + +import org.gridsuite.modification.dto.ModificationInfos; + +import java.util.List; +import java.util.UUID; + +/** + * @author Franck Lecuyer + */ +public record NetworkModificationsWithMissingInfo(List networkModifications, List missingCompositeModifications) { +} diff --git a/src/main/java/org/gridsuite/modification/server/repositories/ModificationRepository.java b/src/main/java/org/gridsuite/modification/server/repositories/ModificationRepository.java index 2ee765f40..e3ef3a6cb 100644 --- a/src/main/java/org/gridsuite/modification/server/repositories/ModificationRepository.java +++ b/src/main/java/org/gridsuite/modification/server/repositories/ModificationRepository.java @@ -77,4 +77,7 @@ public interface ModificationRepository extends JpaRepository findCurrentLimitsIdsByOpLimitsGroupsIds(List uuids); void deleteAllByIdIn(List ids); + + @Query(value = "SELECT DISTINCT cast(id AS VARCHAR) FROM composite_modification_sub_modifications WHERE id IN (?1)", nativeQuery = true) + Set findExistingCompositeModificationIds(List compositeIds); } diff --git a/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java b/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java index 330939a48..cc7e82672 100644 --- a/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java +++ b/src/main/java/org/gridsuite/modification/server/service/NetworkModificationService.java @@ -580,6 +580,14 @@ private BoolQuery buildSearchModificationsQuery( return boolQueryBuilder.build(); } + @Transactional(readOnly = true) + public NetworkModificationsWithMissingInfo getNetworkModificationsFromCompositeWithMissingInfo(List compositeModificationUuids) { + Set foundUuids = modificationRepository.findExistingCompositeModificationIds(compositeModificationUuids); + List networkModifications = networkModificationRepository.getCompositeModificationsInfos(compositeModificationUuids); + List missingUuids = compositeModificationUuids.stream().filter(uuid -> !foundUuids.contains(uuid)).toList(); + return new NetworkModificationsWithMissingInfo(networkModifications, missingUuids); + } + public List getBusBarSectionsForNewCoupler(@NonNull String voltageLevelId, @NonNull Integer busBarCount, @NonNull Integer sectionCount, List switchKindList) { List bbsIds = new ArrayList<>(); for (int i = 1; i < busBarCount + 1; i++) { diff --git a/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java b/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java index a83da3a4b..9b5d2ca2f 100644 --- a/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java +++ b/src/test/java/org/gridsuite/modification/server/ModificationControllerTest.java @@ -981,6 +981,55 @@ void testNetworkCompositeModification() throws Exception { checkCompositeModificationContent(insertedComposite.getModifications()); } + @Test + void testNetworkCompositeModificationWithMissingInfo() throws Exception { + // Insert some switch modifications in the group + int modificationsNumber = 2; + List modificationList = createSomeSwitchModifications(TEST_GROUP_ID, modificationsNumber); + assertEquals(modificationsNumber, modificationRepository.getModifications(TEST_GROUP_ID, true, true).size()); + + // Create a composite modification with the switch modifications + List modificationUuids = modificationList.stream().map(ModificationInfos::getUuid).toList(); + MvcResult mvcResult = mockMvc.perform(post(URI_COMPOSITE_NETWORK_MODIF_BASE) + .content(mapper.writeValueAsString(modificationUuids)).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andReturn(); + UUID compositeModificationUuid = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); + + // Create another composite modification + List otherModificationList = createSomeSwitchModifications(TEST_GROUP2_ID, modificationsNumber); + List otherModificationUuids = otherModificationList.stream().map(ModificationInfos::getUuid).toList(); + mvcResult = mockMvc.perform(post(URI_COMPOSITE_NETWORK_MODIF_BASE) + .content(mapper.writeValueAsString(otherModificationUuids)).contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andReturn(); + UUID otherCompositeModificationUuid = mapper.readValue(mvcResult.getResponse().getContentAsString(), new TypeReference<>() { }); + + UUID nonExistingUuid1 = UUID.randomUUID(); + UUID nonExistingUuid2 = UUID.randomUUID(); + + // Test with mixed existing/non-existing UUIDs + mvcResult = mockMvc.perform(get(URI_GET_COMPOSITE_NETWORK_MODIF_CONTENT + "/network-modifications-with-missing-info") + .param("uuids", compositeModificationUuid.toString()) + .param("uuids", nonExistingUuid1.toString()) + .param("uuids", otherCompositeModificationUuid.toString()) + .param("uuids", nonExistingUuid2.toString())) + .andExpect(status().isOk()) + .andReturn(); + + NetworkModificationsWithMissingInfo result = mapper.readValue( + mvcResult.getResponse().getContentAsString(), + new TypeReference<>() { }); + + // Verify network modifications are returned for existing composite modifications + assertEquals(modificationsNumber * 2, result.networkModifications().size()); + assertNotNull(((EquipmentAttributeModificationInfos) result.networkModifications().get(0)).getEquipmentAttributeName()); + assertNotNull(((EquipmentAttributeModificationInfos) result.networkModifications().get(0)).getEquipmentAttributeValue()); + + // Verify missing UUIDs are reported + assertEquals(2, result.missingCompositeModifications().size()); + assertTrue(result.missingCompositeModifications().contains(nonExistingUuid1)); + assertTrue(result.missingCompositeModifications().contains(nonExistingUuid2)); + } + private static void checkCompositeModificationContent(List compositeModificationContent) { assertEquals("open", ((EquipmentAttributeModificationInfos) compositeModificationContent.getFirst()).getEquipmentAttributeName()); assertEquals(Boolean.TRUE, ((EquipmentAttributeModificationInfos) compositeModificationContent.getFirst()).getEquipmentAttributeValue());