From ba3fd6267d7018f4155395bc7d9d4f8992633e8c Mon Sep 17 00:00:00 2001 From: BKadirkhodjaev Date: Thu, 19 Dec 2024 19:01:37 +0500 Subject: [PATCH] [MODORDERS-1209-2]. Add integration details validation to Send Claims --- .../folio/models/claiming/ClaimingError.java | 3 +- .../service/pieces/PiecesClaimingService.java | 125 ++++++++++-------- .../rest/impl/PiecesClaimingApiTest.java | 5 +- .../pieces/PiecesClaimingServiceTest.java | 87 +++++++++++- 4 files changed, 158 insertions(+), 62 deletions(-) diff --git a/src/main/java/org/folio/models/claiming/ClaimingError.java b/src/main/java/org/folio/models/claiming/ClaimingError.java index 4f5c8ab5e..9b8520bd3 100644 --- a/src/main/java/org/folio/models/claiming/ClaimingError.java +++ b/src/main/java/org/folio/models/claiming/ClaimingError.java @@ -11,7 +11,8 @@ public enum ClaimingError { CANNOT_RETRIEVE_CONFIG_ENTRIES("Cannot retrieve config entries"), CANNOT_GROUP_PIECES_BY_VENDOR_MESSAGE("Cannot group pieces by vendor"), CANNOT_CREATE_JOBS_AND_UPDATE_PIECES("Cannot create jobs and update pieces"), - CANNOT_FIND_A_PIECE_BY_ID("Cannot find a piece by '%s' id"); + CANNOT_FIND_A_PIECE_BY_ID("Cannot find a piece by '%s' id"), + UNABLE_TO_GENERATE_CLAIMS_FOR_ORG_NO_INTEGRATION_DETAILS("Unable to generate claims for %s because no claim integrations exist"); private final String value; } diff --git a/src/main/java/org/folio/service/pieces/PiecesClaimingService.java b/src/main/java/org/folio/service/pieces/PiecesClaimingService.java index 46771689b..dd47f300c 100644 --- a/src/main/java/org/folio/service/pieces/PiecesClaimingService.java +++ b/src/main/java/org/folio/service/pieces/PiecesClaimingService.java @@ -6,6 +6,7 @@ import lombok.extern.log4j.Log4j2; import one.util.streamex.StreamEx; import org.apache.commons.lang3.tuple.Pair; +import org.folio.rest.acq.model.Organization; import org.folio.rest.core.RestClient; import org.folio.rest.core.models.RequestContext; import org.folio.rest.jaxrs.model.ClaimingCollection; @@ -37,6 +38,7 @@ import static org.folio.models.claiming.ClaimingError.CANNOT_GROUP_PIECES_BY_VENDOR_MESSAGE; import static org.folio.models.claiming.ClaimingError.CANNOT_RETRIEVE_CONFIG_ENTRIES; import static org.folio.models.claiming.ClaimingError.CANNOT_SEND_CLAIMS_PIECE_IDS_ARE_EMPTY; +import static org.folio.models.claiming.ClaimingError.UNABLE_TO_GENERATE_CLAIMS_FOR_ORG_NO_INTEGRATION_DETAILS; import static org.folio.models.claiming.IntegrationDetailField.CLAIM_PIECE_IDS; import static org.folio.models.claiming.IntegrationDetailField.EXPORT_TYPE_SPECIFIC_PARAMETERS; import static org.folio.models.claiming.IntegrationDetailField.VENDOR_EDI_ORDERS_EXPORT_CONFIG; @@ -67,8 +69,9 @@ public class PiecesClaimingService { /** * Sends claims by receiving pieces to be claimed, groups them by vendor, * updates piece statuses and finally creates jobs per vendor and associated integration details + * * @param claimingCollection An array of pieces ids - * @param requestContext Headers to make HTTP or Kafka requests + * @param requestContext Headers to make HTTP or Kafka requests * @return Future of an array of claimingResults */ public Future sendClaims(ClaimingCollection claimingCollection, RequestContext requestContext) { @@ -84,86 +87,109 @@ public Future sendClaims(ClaimingCollection claimingCollection, } var pieceIds = claimingCollection.getClaimingPieceIds().stream().toList(); log.info("sendClaims:: Received pieces to be claimed, pieceIds: {}", pieceIds); - return groupPieceIdsByVendorId(pieceIds, requestContext) - .compose(pieceIdsByVendorIds -> { - if (CollectionUtils.isEmpty(pieceIdsByVendorIds)) { + return groupPieceIdsByVendor(pieceIds, requestContext) + .compose(pieceIdsByVendors -> { + if (CollectionUtils.isEmpty(pieceIdsByVendors)) { return Future.succeededFuture(createEmptyClaimingResults(CANNOT_FIND_PIECES_WITH_LATE_STATUS_TO_PROCESS.getValue())); } - log.info("sendClaims:: Using pieces by vendor id map, map: {}", pieceIdsByVendorIds); - return createJobsByVendor(claimingCollection, config, pieceIdsByVendorIds, requestContext); + pieceIdsByVendors.forEach((key, value) -> + log.info("createVendorPiecePair:: Using pieces by vendor map, vendorId: {}, piecesByVendor: {}", key.getId(), value)); + var vendorWithoutIntegrationDetails = checkVendorIntegrationDetails(config, pieceIdsByVendors); + if (Objects.nonNull(vendorWithoutIntegrationDetails)) { + return Future.succeededFuture(new ClaimingResults() + .withClaimingPieceResults(List.of(new ClaimingPieceResult().withStatus(FAILURE) + .withError(new Error().withMessage(String.format(UNABLE_TO_GENERATE_CLAIMS_FOR_ORG_NO_INTEGRATION_DETAILS.getValue(), vendorWithoutIntegrationDetails.getCode())))))); + } + return createJobsByVendor(claimingCollection, config, pieceIdsByVendors, requestContext); }); }) .onFailure(t -> log.error("sendClaims:: Failed send claims: {}", JsonObject.mapFrom(claimingCollection).encodePrettily(), t)); } - private Future>> groupPieceIdsByVendorId(List pieceIds, RequestContext requestContext) { - log.info("groupPieceIdsByVendorId:: Grouping pieces by vendor, pieceIds count: {}", pieceIds.size()); + private Future>> groupPieceIdsByVendor(List pieceIds, RequestContext requestContext) { + log.info("groupPieceIdsByVendor:: Grouping pieces by vendor, pieceIds count: {}", pieceIds.size()); return pieceStorageService.getPiecesByIds(pieceIds, requestContext) .compose(pieces -> { if (CollectionUtils.isEmpty(pieces)) { - log.info("groupPieceIdsByVendorId:: No pieces are found by piece ids, pieceIds: {}", pieceIds); + log.info("groupPieceIdsByVendor:: No pieces are found by piece ids, pieceIds: {}", pieceIds); return Future.succeededFuture(); } var uniquePiecePoLinePairs = pieces.stream() .filter(Objects::nonNull).filter(piece -> Objects.nonNull(piece.getId()) && Objects.nonNull(piece.getPoLineId())) .map(piece -> Pair.of(piece.getPoLineId(), piece.getId())).distinct() .toList(); - log.info("groupPieceIdsByVendorId:: Prepared unique piece-poLine pairs, pairs: {}", uniquePiecePoLinePairs); + log.info("groupPieceIdsByVendor:: Prepared unique piece-poLine pairs, pairs: {}", uniquePiecePoLinePairs); return collectResultsOnSuccess(createPieceIdByVendorFutures(pieces, uniquePiecePoLinePairs, requestContext)) - .map(PiecesClaimingService::transformAndGroupPieceIdsByVendorId); + .map(PiecesClaimingService::transformAndGroupPieceIdsByVendor); }); } - private List>> createPieceIdByVendorFutures(List pieces, List> uniquePiecePoLinePairs, - RequestContext requestContext) { - var pieceIdByVendorIdFutures = new ArrayList>>(); + private List>> createPieceIdByVendorFutures(List pieces, List> uniquePiecePoLinePairs, + RequestContext requestContext) { + var pieceIdByVendorFutures = new ArrayList>>(); uniquePiecePoLinePairs.forEach(piecePoLinePairs -> { var foundPiece = pieces.stream() .filter(Objects::nonNull).filter(piece -> Objects.nonNull(piece.getId())).filter(piece -> piece.getId().equals(piecePoLinePairs.getRight())) .findFirst().orElseThrow(() -> new NoSuchElementException(String.format(CANNOT_FIND_A_PIECE_BY_ID.getValue(), piecePoLinePairs.getRight()))); - var pieceIdByVendorIdFuture = createVendorPiecePair(piecePoLinePairs, foundPiece, requestContext); - if (Objects.nonNull(pieceIdByVendorIdFuture)) { - pieceIdByVendorIdFutures.add(pieceIdByVendorIdFuture); + var pieceIdByVendorFuture = createVendorPiecePair(piecePoLinePairs, foundPiece, requestContext); + if (Objects.nonNull(pieceIdByVendorFuture)) { + pieceIdByVendorFutures.add(pieceIdByVendorFuture); } }); - return pieceIdByVendorIdFutures; + return pieceIdByVendorFutures; } - private Future> createVendorPiecePair(Pair piecePoLinePairs, - Piece piece, RequestContext requestContext) { + private Future> createVendorPiecePair(Pair piecePoLinePairs, + Piece piece, RequestContext requestContext) { if (!piece.getReceivingStatus().equals(Piece.ReceivingStatus.LATE)) { log.info("createVendorPiecePair:: Ignoring processing of a piece not in LATE state, piece id: {}", piece.getId()); return Future.succeededFuture(); } return purchaseOrderLineService.getOrderLineById(piecePoLinePairs.getLeft(), requestContext) .compose(poLine -> purchaseOrderStorageService.getPurchaseOrderById(poLine.getPurchaseOrderId(), requestContext) - .compose(purchaseOrder -> organizationService.getVendorById(purchaseOrder.getVendor(), requestContext))) + .compose(purchaseOrder -> organizationService.getVendorById(purchaseOrder.getVendor(), requestContext))) .map(vendor -> { if (Objects.nonNull(vendor) && Boolean.TRUE.equals(vendor.getIsVendor())) { - return Pair.of(vendor.getId(), piecePoLinePairs.getRight()); + return Pair.of(vendor, piecePoLinePairs.getRight()); } return null; }); } - private static Map> transformAndGroupPieceIdsByVendorId(List> piecesByVendorList) { + private Organization checkVendorIntegrationDetails(JsonObject config, Map> pieceIdsByVendors) { + return pieceIdsByVendors.keySet().stream() + .filter(vendor -> { + var vendorIntegrationDetails = config.stream() + .filter(configEntry -> isExportTypeClaimsAndCorrectVendorId(vendor.getId(), configEntry)) + .toList(); + log.info("checkVendorIntegrationDetails:: Found vendor integration details, vendorId: {}, integrationDetails: {}", vendor.getId(), vendorIntegrationDetails); + return vendorIntegrationDetails.isEmpty(); + }) + .findFirst().orElse(null); + } + + private boolean isExportTypeClaimsAndCorrectVendorId(String vendorId, Map.Entry configEntry) { + return configEntry.getKey().startsWith(String.format("%s_%s", EXPORT_TYPE_CLAIMS, vendorId)) && Objects.nonNull(configEntry.getValue()); + } + + private static Map> transformAndGroupPieceIdsByVendor(List> piecesByVendorList) { return StreamEx.of(piecesByVendorList).distinct().filter(Objects::nonNull) .groupingBy(Pair::getKey, mapping(Pair::getValue, toList())); } private Future createJobsByVendor(ClaimingCollection claimingCollection, JsonObject config, - Map> pieceIdsByVendorId, RequestContext requestContext) { - log.info("createJobsByVendor:: Creating jobs by vendor, vendors by pieces count: {}", pieceIdsByVendorId.size()); - if (CollectionUtils.isEmpty(pieceIdsByVendorId)) { - log.info("createJobsByVendor:: No jobs are created, pieceIdsByVendorId is empty"); + Map> pieceIdsByVendor, RequestContext requestContext) { + log.info("createJobsByVendor:: Creating jobs by vendor, vendors by pieces count: {}", pieceIdsByVendor.size()); + if (CollectionUtils.isEmpty(pieceIdsByVendor)) { + log.info("createJobsByVendor:: No jobs are created, pieceIdsByVendor is empty"); return Future.succeededFuture(new ClaimingResults() - .withClaimingPieceResults(createErrorClaimingResults(pieceIdsByVendorId, CANNOT_GROUP_PIECES_BY_VENDOR_MESSAGE.getValue()))); + .withClaimingPieceResults(createErrorClaimingResults(pieceIdsByVendor, CANNOT_GROUP_PIECES_BY_VENDOR_MESSAGE.getValue()))); } - return collectResultsOnSuccess(createUpdatePiecesAndJobFutures(claimingCollection, config, pieceIdsByVendorId, requestContext)) + return collectResultsOnSuccess(createUpdatePiecesAndJobFutures(claimingCollection, config, pieceIdsByVendor, requestContext)) .map(updatedPieceLists -> { if (CollectionUtils.isEmpty(updatedPieceLists)) { log.info("createJobsByVendor:: No pieces were processed for claiming"); - return new ClaimingResults().withClaimingPieceResults(createErrorClaimingResults(pieceIdsByVendorId, CANNOT_CREATE_JOBS_AND_UPDATE_PIECES.getValue())); + return new ClaimingResults().withClaimingPieceResults(createErrorClaimingResults(pieceIdsByVendor, CANNOT_CREATE_JOBS_AND_UPDATE_PIECES.getValue())); } var successClaimingPieceResults = createSuccessClaimingResults(updatedPieceLists); log.info("createJobsByVendor:: Successfully processed pieces for claiming, count: {}", successClaimingPieceResults.size()); @@ -174,15 +200,14 @@ private Future createJobsByVendor(ClaimingCollection claimingCo } private List>> createUpdatePiecesAndJobFutures(ClaimingCollection claimingCollection, JsonObject config, - Map> pieceIdsByVendorId, RequestContext requestContext) { + Map> pieceIdsByVendor, RequestContext requestContext) { var updatePiecesAndJobFutures = new ArrayList>>(); - pieceIdsByVendorId.forEach((vendorId, pieceIds) -> config.stream() - .filter(pieceIdsByVendorIdEntry -> isExportTypeClaimsAndCorrectVendorId(vendorId, pieceIdsByVendorIdEntry) - && Objects.nonNull(pieceIdsByVendorIdEntry.getValue())) - .forEach(pieceIdsByVendorIdEntry -> { - log.info("createJobsByVendor:: Preparing job integration detail for vendor, vendor id: {}, pieces: {}, job key: {}", - vendorId, pieceIds.size(), pieceIdsByVendorIdEntry.getKey()); - updatePiecesAndJobFutures.add(updatePiecesAndCreateJob(claimingCollection, pieceIds, pieceIdsByVendorIdEntry, requestContext)); + pieceIdsByVendor.forEach((vendor, pieceIds) -> config.stream() + .filter(pieceIdsByVendorIdEntry -> isExportTypeClaimsAndCorrectVendorId(vendor.getId(), pieceIdsByVendorIdEntry)) + .forEach(configEntry -> { + log.info("createUpdatePiecesAndJobFutures:: Preparing job integration detail for vendor, vendor id: {}, pieces: {}, job key: {}", + vendor.getId(), pieceIds.size(), configEntry.getKey()); + updatePiecesAndJobFutures.add(updatePiecesAndCreateJob(claimingCollection, pieceIds, configEntry, requestContext)); })); return updatePiecesAndJobFutures; } @@ -193,27 +218,23 @@ private static ClaimingResults createEmptyClaimingResults(String message) { private List createSuccessClaimingResults(List> updatedPieceLists) { return updatedPieceLists.stream().flatMap(Collection::stream).distinct() - .map(pieceId -> new ClaimingPieceResult().withPieceId(pieceId).withStatus(SUCCESS)) - .toList(); - } - - private List createErrorClaimingResults(Map> pieceIdsByVendorId, String message) { - return pieceIdsByVendorId.values().stream() - .flatMap(Collection::stream) - .map(pieceId -> new ClaimingPieceResult().withPieceId(pieceId).withStatus(FAILURE).withError(new Error().withMessage(message))) - .toList(); + .map(pieceId -> new ClaimingPieceResult().withPieceId(pieceId).withStatus(SUCCESS)) + .toList(); } - private static boolean isExportTypeClaimsAndCorrectVendorId(String vendorId, Map.Entry pieceIdsByVendorIdEntry) { - return pieceIdsByVendorIdEntry.getKey().startsWith(String.format("%s_%s", EXPORT_TYPE_CLAIMS, vendorId)); + private List createErrorClaimingResults(Map> pieceIdsByVendor, String message) { + return pieceIdsByVendor.values().stream() + .flatMap(Collection::stream) + .map(pieceId -> new ClaimingPieceResult().withPieceId(pieceId).withStatus(FAILURE).withError(new Error().withMessage(message))) + .toList(); } private Future> updatePiecesAndCreateJob(ClaimingCollection claimingCollection, List pieceIds, - Map.Entry pieceIdsByVendorIdEntry, RequestContext requestContext) { - log.info("updatePiecesAndCreateJob:: Updating pieces and creating a job, job key: {}, count: {}", pieceIdsByVendorIdEntry.getKey(), pieceIds.size()); + Map.Entry configEntry, RequestContext requestContext) { + log.info("updatePiecesAndCreateJob:: Updating pieces and creating a job, job key: {}, count: {}", configEntry.getKey(), pieceIds.size()); return pieceUpdateFlowManager.updatePiecesStatuses(pieceIds, PieceBatchStatusCollection.ReceivingStatus.CLAIM_SENT, claimingCollection.getClaimingInterval(), claimingCollection.getInternalNote(), claimingCollection.getExternalNote(), requestContext) - .compose(v -> createJob(pieceIdsByVendorIdEntry.getKey(), pieceIdsByVendorIdEntry.getValue(), pieceIds, requestContext).map(pieceIds)); + .compose(v -> createJob(configEntry.getKey(), configEntry.getValue(), pieceIds, requestContext).map(pieceIds)); } private Future createJob(String configKey, Object configValue, List pieceIds, RequestContext requestContext) { diff --git a/src/test/java/org/folio/rest/impl/PiecesClaimingApiTest.java b/src/test/java/org/folio/rest/impl/PiecesClaimingApiTest.java index 89bec2300..2a59dd47e 100644 --- a/src/test/java/org/folio/rest/impl/PiecesClaimingApiTest.java +++ b/src/test/java/org/folio/rest/impl/PiecesClaimingApiTest.java @@ -205,7 +205,6 @@ void testPostPiecesClaim(String name, int vendorIdx, int poLineIdx, int pieceIdx assertThat(jobExecutions, hasSize(dto.jobExecutions)); assertThat(response.getClaimingPieceResults().size(), equalTo(dto.claimingResults)); pieceUpdates.forEach(pieceUpdate -> logger.info("Updated piece: {}", pieceUpdate.encodePrettily())); - var claimedPieceIds = jobCreations.stream() .peek(job -> logger.info("Created job: {}", JsonObject.mapFrom(job).encodePrettily())) .map(job -> job.getJsonObject(EXPORT_TYPE_SPECIFIC_PARAMETERS.getValue()) @@ -217,13 +216,13 @@ void testPostPiecesClaim(String name, int vendorIdx, int poLineIdx, int pieceIdx response.getClaimingPieceResults() .forEach(result -> { - assertThat(result.getPieceId(), not(nullValue())); - assertThat(result.getStatus(), is(expectedStatus)); if (expectedStatus == SUCCESS) { + assertThat(result.getPieceId(), not(nullValue())); assertThat(result.getError(), is(nullValue())); } else { assertThat(result.getError(), is(notNullValue())); } + assertThat(result.getStatus(), is(expectedStatus)); }); } } diff --git a/src/test/java/org/folio/service/pieces/PiecesClaimingServiceTest.java b/src/test/java/org/folio/service/pieces/PiecesClaimingServiceTest.java index 81475bbd3..a9c29ca32 100644 --- a/src/test/java/org/folio/service/pieces/PiecesClaimingServiceTest.java +++ b/src/test/java/org/folio/service/pieces/PiecesClaimingServiceTest.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.UUID; import static org.folio.models.claiming.ClaimingError.CANNOT_FIND_PIECES_WITH_LATE_STATUS_TO_PROCESS; import static org.folio.models.claiming.ClaimingError.CANNOT_RETRIEVE_CONFIG_ENTRIES; @@ -39,6 +40,7 @@ import static org.folio.orders.utils.ResourcePathResolver.DATA_EXPORT_SPRING_CREATE_JOB; import static org.folio.orders.utils.ResourcePathResolver.resourcesPath; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @@ -142,7 +144,7 @@ void testSendClaims_success(VertxTestContext testContext) { when(pieceStorageService.getPiecesByIds(any(), any())).thenReturn(Future.succeededFuture(List.of(new Piece().withId("pieceId1").withPoLineId("poLineId1").withReceivingStatus(Piece.ReceivingStatus.LATE)))); when(purchaseOrderLineService.getOrderLineById(any(), any())).thenReturn(Future.succeededFuture(new PoLine().withPurchaseOrderId("orderId1"))); when(purchaseOrderStorageService.getPurchaseOrderById(any(), any())).thenReturn(Future.succeededFuture(new PurchaseOrder().withVendor("vendorId"))); - when(organizationService.getVendorById(any(), any())).thenReturn(Future.succeededFuture(new Organization().withId("vendorId").withIsVendor(true))); + when(organizationService.getVendorById(any(), any())).thenReturn(Future.succeededFuture(new Organization().withId("vendorId").withCode("VENDOR").withIsVendor(true))); when(pieceUpdateFlowManager.updatePiecesStatuses(any(), any(), any(), any(), any(), any())).thenReturn(Future.succeededFuture()); when(restClient.post(eq(resourcesPath(DATA_EXPORT_SPRING_CREATE_JOB)), any(), any(), any())).thenReturn(Future.succeededFuture(new JsonObject().put("status", "CREATED"))); when(restClient.postEmptyResponse(any(), any(), any())).thenReturn(Future.succeededFuture()); @@ -168,7 +170,7 @@ void testSendClaims_successWithTwoPieces(VertxTestContext testContext) { ))); when(purchaseOrderLineService.getOrderLineById(any(), any())).thenReturn(Future.succeededFuture(new PoLine().withPurchaseOrderId("orderId1"))); when(purchaseOrderStorageService.getPurchaseOrderById(any(), any())).thenReturn(Future.succeededFuture(new PurchaseOrder().withVendor("vendorId"))); - when(organizationService.getVendorById(any(), any())).thenReturn(Future.succeededFuture(new Organization().withId("vendorId").withIsVendor(true))); + when(organizationService.getVendorById(any(), any())).thenReturn(Future.succeededFuture(new Organization().withId("vendorId").withCode("VENDOR").withIsVendor(true))); when(pieceUpdateFlowManager.updatePiecesStatuses(any(), any(), any(), any(), any(), any())).thenReturn(Future.succeededFuture()); when(restClient.post(eq(resourcesPath(DATA_EXPORT_SPRING_CREATE_JOB)), any(), any(), any())).thenReturn(Future.succeededFuture(new JsonObject().put("status", "CREATED"))); when(restClient.postEmptyResponse(any(), any(), any())).thenReturn(Future.succeededFuture()); @@ -184,6 +186,71 @@ void testSendClaims_successWithTwoPieces(VertxTestContext testContext) { }))); } + @Test + void testSendClaims_missingOrganizationIntegrationDetailsForTwoOrganizations(VertxTestContext testContext) { + var pieceId = UUID.randomUUID().toString(); + var piece = new Piece().withId(pieceId).withPoLineId("poLineId").withReceivingStatus(Piece.ReceivingStatus.LATE); + var claimingCollection = new ClaimingCollection().withClaimingPieceIds(List.of(pieceId)); + var requestContext = mock(RequestContext.class); + + when(configurationEntriesCache.loadConfiguration(any(), any())).thenReturn(Future.succeededFuture(new JsonObject() + .put("CLAIMS_vendorId1", createIntegrationDetail()))); + when(pieceStorageService.getPiecesByIds(any(), any())).thenReturn(Future.succeededFuture(List.of(piece))); + when(purchaseOrderLineService.getOrderLineById(any(), any())).thenReturn(Future.succeededFuture(new PoLine().withPurchaseOrderId("orderId"))); + when(purchaseOrderStorageService.getPurchaseOrderById(any(), any())).thenReturn(Future.succeededFuture(new PurchaseOrder().withVendor("vendorId2"))); + when(organizationService.getVendorById(any(), any())).thenReturn(Future.succeededFuture(new Organization().withId("vendorId2").withCode("VENDOR2").withIsVendor(true))); + + piecesClaimingService.sendClaims(claimingCollection, requestContext) + .onComplete(testContext.succeeding(result -> testContext.verify(() -> { + assertEquals(1, result.getClaimingPieceResults().size()); + var claimingPieceResult = result.getClaimingPieceResults().get(0); + assertNull(claimingPieceResult.getPieceId()); + assertEquals(ClaimingPieceResult.Status.FAILURE, claimingPieceResult.getStatus()); + assertEquals("Unable to generate claims for VENDOR2 because no claim integrations exist", claimingPieceResult.getError().getMessage()); + testContext.completeNow(); + }))); + } + + @Test + void testSendClaims_missingOrganizationIntegrationDetailsForThreeOrganizations(VertxTestContext testContext) { + var pieceId1 = UUID.randomUUID().toString(); + var pieceId2 = UUID.randomUUID().toString(); + var pieceId3 = UUID.randomUUID().toString(); + var piece1 = new Piece().withId(pieceId1).withPoLineId("poLineId1").withReceivingStatus(Piece.ReceivingStatus.LATE); + var piece2 = new Piece().withId(pieceId2).withPoLineId("poLineId2").withReceivingStatus(Piece.ReceivingStatus.LATE); + var piece3 = new Piece().withId(pieceId3).withPoLineId("poLineId3").withReceivingStatus(Piece.ReceivingStatus.LATE); + var claimingCollection = new ClaimingCollection().withClaimingPieceIds(List.of(pieceId1, pieceId2, pieceId3)); + var requestContext = mock(RequestContext.class); + + when(configurationEntriesCache.loadConfiguration(any(), any())).thenReturn(Future.succeededFuture(new JsonObject() + .put("CLAIMS_vendorId1", createIntegrationDetail()))); + when(pieceStorageService.getPiecesByIds(any(), any())).thenReturn(Future.succeededFuture(List.of(piece1, piece2, piece3))); + when(purchaseOrderLineService.getOrderLineById(any(), any())).thenAnswer(invocation -> { + String poLineId = invocation.getArgument(0); + return Future.succeededFuture(new PoLine().withPurchaseOrderId(poLineId.equals("poLineId1") ? "orderId1" : poLineId.equals("poLineId2") ? "orderId2" : "orderId3")); + }); + when(purchaseOrderStorageService.getPurchaseOrderById(any(), any())).thenAnswer(invocation -> { + String orderId = invocation.getArgument(0); + return Future.succeededFuture(new PurchaseOrder().withVendor(orderId.equals("orderId1") ? "vendorId1" : orderId.equals("orderId2") ? "vendorId2" : "vendorId3")); + }); + when(organizationService.getVendorById(any(), any())).thenAnswer(invocation -> { + String vendorId = invocation.getArgument(0); + return Future.succeededFuture(new Organization().withId(vendorId).withCode(vendorId.equals("vendorId1") ? "VENDOR1" : vendorId.equals("vendorId2") ? "VENDOR2" : "VENDOR3").withIsVendor(true)); + }); + + piecesClaimingService.sendClaims(claimingCollection, requestContext) + .onComplete(testContext.succeeding(result -> testContext.verify(() -> { + assertEquals(1, result.getClaimingPieceResults().size()); + var claimingPieceResults = result.getClaimingPieceResults(); + claimingPieceResults.forEach(claimingPieceResult -> { + assertNull(claimingPieceResult.getPieceId()); + assertEquals(ClaimingPieceResult.Status.FAILURE, claimingPieceResult.getStatus()); + assertEquals("Unable to generate claims for VENDOR2 because no claim integrations exist", claimingPieceResult.getError().getMessage()); + }); + testContext.completeNow(); + }))); + } + @Test void testSendClaims_successWithMultipleOrganizations(VertxTestContext testContext) { var claimingCollection = new ClaimingCollection().withClaimingPieceIds(List.of("pieceId1", "pieceId2", "pieceId3", "pieceId4", "pieceId5")).withClaimingInterval(1); @@ -213,7 +280,7 @@ void testSendClaims_successWithMultipleOrganizations(VertxTestContext testContex when(organizationService.getVendorById(any(), any())).thenAnswer(invocation -> { String vendorId = invocation.getArgument(0); - return Future.succeededFuture(new Organization().withId(vendorId).withIsVendor(true)); + return Future.succeededFuture(new Organization().withId(vendorId).withCode(vendorId.equals("vendorId1") ? "VENDOR1" : "VENDOR2").withIsVendor(true)); }); when(pieceUpdateFlowManager.updatePiecesStatuses(any(), any(), any(), any(), any(), any())).thenReturn(Future.succeededFuture()); @@ -245,7 +312,9 @@ void testSendClaims_successWithMultipleOrganizationsAndOneIntegrationDetail(Vert var requestContext = mock(RequestContext.class); when(configurationEntriesCache.loadConfiguration(any(), any())).thenReturn(Future.succeededFuture(new JsonObject() - .put("CLAIMS_vendorId1", createIntegrationDetail()))); + .put("CLAIMS_vendorId1", createIntegrationDetail()) + .put("CLAIMS_vendorId2", createIntegrationDetail()) + )); when(pieceStorageService.getPiecesByIds(any(), any())).thenReturn(Future.succeededFuture(List.of( new Piece().withId("pieceId1").withPoLineId("poLineId1").withReceivingStatus(Piece.ReceivingStatus.LATE), @@ -267,7 +336,7 @@ void testSendClaims_successWithMultipleOrganizationsAndOneIntegrationDetail(Vert when(organizationService.getVendorById(any(), any())).thenAnswer(invocation -> { String vendorId = invocation.getArgument(0); - return Future.succeededFuture(new Organization().withId(vendorId).withIsVendor(true)); + return Future.succeededFuture(new Organization().withId(vendorId).withCode(vendorId.equals("vendorId1") ? "VENDOR1" : "VENDOR2").withIsVendor(true)); }); when(pieceUpdateFlowManager.updatePiecesStatuses(any(), any(), any(), any(), any(), any())).thenReturn(Future.succeededFuture()); @@ -276,13 +345,19 @@ void testSendClaims_successWithMultipleOrganizationsAndOneIntegrationDetail(Vert piecesClaimingService.sendClaims(claimingCollection, requestContext) .onComplete(testContext.succeeding(result -> testContext.verify(() -> { - assertEquals(2, result.getClaimingPieceResults().size()); + assertEquals(5, result.getClaimingPieceResults().size()); var copiedSortedResults = new ArrayList<>(result.getClaimingPieceResults()); copiedSortedResults.sort(Comparator.comparing(ClaimingPieceResult::getPieceId)); assertEquals("pieceId1", copiedSortedResults.get(0).getPieceId()); assertEquals(ClaimingPieceResult.Status.SUCCESS, copiedSortedResults.get(0).getStatus()); assertEquals("pieceId2", copiedSortedResults.get(1).getPieceId()); assertEquals(ClaimingPieceResult.Status.SUCCESS, copiedSortedResults.get(1).getStatus()); + assertEquals("pieceId3", copiedSortedResults.get(2).getPieceId()); + assertEquals(ClaimingPieceResult.Status.SUCCESS, copiedSortedResults.get(1).getStatus()); + assertEquals("pieceId4", copiedSortedResults.get(3).getPieceId()); + assertEquals(ClaimingPieceResult.Status.SUCCESS, copiedSortedResults.get(1).getStatus()); + assertEquals("pieceId5", copiedSortedResults.get(4).getPieceId()); + assertEquals(ClaimingPieceResult.Status.SUCCESS, copiedSortedResults.get(1).getStatus()); testContext.completeNow(); }))); }