diff --git a/src/main/java/org/folio/models/ClaimingHolder.java b/src/main/java/org/folio/models/ClaimingHolder.java deleted file mode 100644 index f4a0ffbc9..000000000 --- a/src/main/java/org/folio/models/ClaimingHolder.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.folio.models; - -import org.folio.rest.jaxrs.model.Piece; - -import java.util.List; - -public class ClaimingHolder { - - private List pieces; - - public ClaimingHolder() { - } - - public ClaimingHolder withPieces(List pieces) { - this.pieces = pieces; - return this; - } - - public List getPieces() { - return pieces; - } -} diff --git a/src/main/java/org/folio/service/claiming/ClaimingService.java b/src/main/java/org/folio/service/claiming/ClaimingService.java index 98563e33f..9c522cad4 100644 --- a/src/main/java/org/folio/service/claiming/ClaimingService.java +++ b/src/main/java/org/folio/service/claiming/ClaimingService.java @@ -7,18 +7,20 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.folio.models.ClaimingHolder; import org.folio.rest.core.RestClient; import org.folio.rest.core.models.RequestContext; import org.folio.rest.jaxrs.model.ClaimingCollection; import org.folio.rest.jaxrs.model.ClaimingPieceResult; import org.folio.rest.jaxrs.model.ClaimingResults; +import org.folio.rest.jaxrs.model.Error; import org.folio.rest.jaxrs.model.Piece; +import org.folio.rest.jaxrs.model.PieceBatchStatusCollection; import org.folio.service.caches.ConfigurationEntriesCache; import org.folio.service.orders.PurchaseOrderLineService; import org.folio.service.orders.PurchaseOrderStorageService; import org.folio.service.organization.OrganizationService; import org.folio.service.pieces.PieceStorageService; +import org.folio.service.pieces.flows.update.PieceUpdateFlowManager; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -36,6 +38,8 @@ import static org.folio.orders.utils.ResourcePathResolver.DATA_EXPORT_SPRING_CREATE_JOB; import static org.folio.orders.utils.ResourcePathResolver.DATA_EXPORT_SPRING_EXECUTE_JOB; import static org.folio.orders.utils.ResourcePathResolver.resourcesPath; +import static org.folio.rest.jaxrs.model.ClaimingPieceResult.Status.FAILURE; +import static org.folio.rest.jaxrs.model.ClaimingPieceResult.Status.SUCCESS; @Log4j2 @Service @@ -44,22 +48,28 @@ public class ClaimingService { private static final Logger logger = LogManager.getLogger(ClaimingService.class); private static final String JOB_STATUS = "status"; private static final String EXPORT_TYPE_CLAIMS = "CLAIMS"; + private static final String CANNOT_SEND_CLAIMS_PIECE_IDS_ARE_EMPTY = "Cannot send claims, piece ids are empty"; + private static final String CANNOT_RETRIEVE_CONFIG_ENTRIES = "Cannot retrieve config entries"; + private static final String CANNOT_GROUP_PIECES_BY_VENDOR_MESSAGE = "Cannot group pieces by vendor"; + private static final String CANNOT_CREATE_JOBS_AND_UPDATE_PIECES = "Cannot create jobs and update pieces"; private final ConfigurationEntriesCache configurationEntriesCache; private final PieceStorageService pieceStorageService; private final PurchaseOrderLineService purchaseOrderLineService; private final PurchaseOrderStorageService purchaseOrderStorageService; private final OrganizationService organizationService; + private final PieceUpdateFlowManager pieceUpdateFlowManager; private final RestClient restClient; public ClaimingService(ConfigurationEntriesCache configurationEntriesCache, PieceStorageService pieceStorageService, PurchaseOrderLineService purchaseOrderLineService, PurchaseOrderStorageService purchaseOrderStorageService, - OrganizationService organizationService, RestClient restClient) { + OrganizationService organizationService, PieceUpdateFlowManager pieceUpdateFlowManager, RestClient restClient) { this.configurationEntriesCache = configurationEntriesCache; this.pieceStorageService = pieceStorageService; this.purchaseOrderLineService = purchaseOrderLineService; this.purchaseOrderStorageService = purchaseOrderStorageService; this.organizationService = organizationService; + this.pieceUpdateFlowManager = pieceUpdateFlowManager; this.restClient = restClient; } @@ -71,29 +81,31 @@ public ClaimingService(ConfigurationEntriesCache configurationEntriesCache, Piec * @return Future of an array of claimingResults */ public Future sendClaims(ClaimingCollection claimingCollection, RequestContext requestContext) { - var claimingHolder = new ClaimingHolder(); + if (CollectionUtils.isEmpty(claimingCollection.getClaimingPieceIds())) { + logger.info("sendClaims:: No claims are sent, claiming piece ids are empty"); + return Future.succeededFuture(createEmptyClaimingResults(CANNOT_SEND_CLAIMS_PIECE_IDS_ARE_EMPTY)); + } return configurationEntriesCache.loadConfiguration(DATA_EXPORT_SPRING_CONFIG_MODULE_NAME, requestContext) .compose(config -> { if (CollectionUtils.isEmpty(config.getMap())) { logger.info("sendClaims:: No claims are sent, config has no entries"); - return Future.succeededFuture(new ClaimingResults()); + return Future.succeededFuture(createEmptyClaimingResults(CANNOT_RETRIEVE_CONFIG_ENTRIES)); } var pieceIds = claimingCollection.getClaimingPieceIds().stream().toList(); logger.info("sendClaims:: Received pieces to be claimed, pieceIds: {}", pieceIds); - return groupPieceIdsByVendorId(claimingHolder, pieceIds, requestContext) - .compose(pieceIdsByVendorIds -> createJobsByVendor(claimingHolder, config, pieceIdsByVendorIds, requestContext)); + return groupPieceIdsByVendorId(pieceIds, requestContext) + .compose(pieceIdsByVendorIds -> createJobsByVendor(config, pieceIdsByVendorIds, requestContext)); }) .onFailure(t -> logger.error("sendClaims :: Failed send claims: {}", JsonObject.mapFrom(claimingCollection).encodePrettily(), t)); } - private Future>> groupPieceIdsByVendorId(ClaimingHolder claimingHolder, List pieceIds, RequestContext requestContext) { + private Future>> groupPieceIdsByVendorId(List pieceIds, RequestContext requestContext) { if (CollectionUtils.isEmpty(pieceIds)) { logger.info("groupPieceIdsByVendorId:: No pieces are grouped by vendor, pieceIds is empty"); return Future.succeededFuture(); } return pieceStorageService.getPiecesByIds(pieceIds, requestContext) .compose(pieces -> { - claimingHolder.withPieces(pieces); var uniquePiecePoLinePairs = pieces.stream() .map(piece -> Pair.of(piece.getPoLineId(), piece.getId())).distinct() .toList(); @@ -131,48 +143,56 @@ private static Map> transformAndGroupPieceIdsByVendorId(Lis .groupingBy(Pair::getKey, mapping(Pair::getValue, collectingAndThen(toList(), lists -> StreamEx.of(lists).toList()))); } - private Future createJobsByVendor(ClaimingHolder claimingHolder, JsonObject config, Map> pieceIdsByVendorId, RequestContext requestContext) { + private Future createJobsByVendor(JsonObject config, Map> pieceIdsByVendorId, + RequestContext requestContext) { if (CollectionUtils.isEmpty(pieceIdsByVendorId)) { logger.info("createJobsByVendor:: No jobs are created, pieceIdsByVendorId is empty"); - return Future.succeededFuture(new ClaimingResults()); + return Future.succeededFuture(new ClaimingResults().withClaimingPieceResults(createErrorClaimingResults(pieceIdsByVendorId, CANNOT_GROUP_PIECES_BY_VENDOR_MESSAGE))); } var updatePiecesAndJobFutures = new ArrayList>>(); - pieceIdsByVendorId.forEach((vendorId, pieceIds) -> { - config.stream() - .filter(entry -> isExportTypeClaimsAndCorrectVendorId(vendorId, entry)) - .filter(entry -> Objects.nonNull(entry.getValue())) - .forEach(entry -> { - logger.info("createJobsByVendor:: Preparing job integration detail for vendor, vendor id: {}, pieces: {}, job key: {}", vendorId, pieceIds.size(), entry.getKey()); - var updatePiecesAndJobFuture = updatePieces(claimingHolder, pieceIds, requestContext) - .compose(updatePieceIds -> createJob(entry.getKey(), entry.getValue(), requestContext).map(updatePieceIds)); - updatePiecesAndJobFutures.add(updatePiecesAndJobFuture); - }); - }); + pieceIdsByVendorId.forEach((vendorId, pieceIds) -> config.stream() + .filter(entry -> isExportTypeClaimsAndCorrectVendorId(vendorId, entry) && Objects.nonNull(entry.getValue())) + .forEach(entry -> { + logger.info("createJobsByVendor:: Preparing job integration detail for vendor, vendor id: {}, pieces: {}, job key: {}", vendorId, pieceIds.size(), entry.getKey()); + updatePiecesAndJobFutures.add(updatePiecesAndCreateJob(requestContext, pieceIds, entry)); + })); return collectResultsOnSuccess(updatePiecesAndJobFutures) .map(updatedPieceLists -> { - var processedPieces = updatedPieceLists.stream().flatMap(Collection::stream).distinct() - .map(pieceId -> new ClaimingPieceResult().withPieceId(pieceId).withStatus(ClaimingPieceResult.Status.SUCCESS)) - .toList(); - logger.info("createJobsByVendor:: Processed pieces for claiming, count: {}", processedPieces.size()); - return new ClaimingResults().withClaimingPieceResults(processedPieces); + if (updatedPieceLists.isEmpty()) { + logger.info("createJobsByVendor:: No pieces were processes for claiming"); + return new ClaimingResults().withClaimingPieceResults(createErrorClaimingResults(pieceIdsByVendorId, CANNOT_CREATE_JOBS_AND_UPDATE_PIECES)); + } + var successClaimingPieceResults = createSuccessClaimingResults(updatedPieceLists); + logger.info("createJobsByVendor:: Successfully processed pieces for claiming, count: {}", successClaimingPieceResults.size()); + return new ClaimingResults().withClaimingPieceResults(successClaimingPieceResults); }); } + private static ClaimingResults createEmptyClaimingResults(String message) { + return new ClaimingResults().withClaimingPieceResults(List.of(new ClaimingPieceResult().withError(new Error().withMessage(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(); + } + private static boolean isExportTypeClaimsAndCorrectVendorId(String vendorId, Map.Entry entry) { + log.info("isExportTypeClaimsAndCorrectVendorId:: Checking integration detail, vendorId: {}, job key: {}", vendorId, entry.getKey()); return entry.getKey().startsWith(String.format("%s_%s", EXPORT_TYPE_CLAIMS, vendorId)); } - private Future> updatePieces(ClaimingHolder claimingHolder, List pieceIds, RequestContext requestContext) { - var piecesByVendorFutures = new ArrayList>(); - pieceIds.forEach(pieceId -> { - var piece = claimingHolder.getPieces().stream() - .filter(pieceFromStorage -> pieceFromStorage.getId().equals(pieceId)) - .findFirst().orElseThrow() - .withReceivingStatus(Piece.ReceivingStatus.CLAIM_SENT); - piecesByVendorFutures.add(pieceStorageService.updatePiece(piece, requestContext).map(pieceId)); - }); - return collectResultsOnSuccess(piecesByVendorFutures); + private Future> updatePiecesAndCreateJob(RequestContext requestContext, List pieceIds, Map.Entry entry) { + return pieceUpdateFlowManager.updatePiecesStatuses(pieceIds, PieceBatchStatusCollection.ReceivingStatus.CLAIM_SENT, requestContext).map(pieceIds) + .compose(updatePieceIds -> createJob(entry.getKey(), entry.getValue(), requestContext).map(updatePieceIds)); } private Future createJob(String configKey, Object configValue, RequestContext requestContext) { diff --git a/src/test/java/org/folio/rest/impl/ClaimingApiTest.java b/src/test/java/org/folio/rest/impl/ClaimingApiTest.java index b30a0861b..80d30652f 100644 --- a/src/test/java/org/folio/rest/impl/ClaimingApiTest.java +++ b/src/test/java/org/folio/rest/impl/ClaimingApiTest.java @@ -55,6 +55,7 @@ import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; public class ClaimingApiTest { @@ -168,10 +169,12 @@ void testPostOrdersClaim(String name, int vendorIdx, int polIdx, int pieceIdx, M } response.getClaimingPieceResults().forEach(result -> { + assertThat(result.getPieceId(), not(nullValue())); + assertThat(result.getStatus(), is(expectedStatus)); if (expectedStatus == ClaimingPieceResult.Status.SUCCESS) { - assertThat(result.getPieceId(), not(nullValue())); - assertThat(result.getStatus(), is(expectedStatus)); assertThat(result.getError(), is(nullValue())); + } else { + assertThat(result.getError(), is(notNullValue())); } }); }