Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MODORDERS -1087 Delete received pieces in bulk #905

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
eda88e0
draft
yuntianhu Apr 19, 2024
e64274c
remove the overide
yuntianhu Apr 19, 2024
28f1b6c
coding format correct
yuntianhu Apr 19, 2024
72ac005
modify pieces.rml, PiecesAPI.java
yuntianhu Apr 25, 2024
68d0484
Merge branch 'master' into MODORDERS-1087
yuntianhu Apr 25, 2024
f01b393
modify pieces.rml, PiecesAPI.java, add unit test, add batch delete in…
yuntianhu Apr 30, 2024
525c527
Merge remote-tracking branch 'origin/MODORDERS-1087' into MODORDERS-1087
yuntianhu Apr 30, 2024
6f668d5
Merge branch 'master' into MODORDERS-1087
yuntianhu Apr 30, 2024
a901c73
modify pieces.rml, PiecesAPI.java, add unit test, add batch delete in…
yuntianhu Apr 30, 2024
d0af7ee
modify add batch delete API test, remove debug comments, change refin…
yuntianhu Apr 30, 2024
e8f7699
modify correct batch delete API test,
yuntianhu Apr 30, 2024
21afa09
modify PiecesDeleteFlowManager.java, pieces.raml, code format correct…
yuntianhu May 7, 2024
2757e77
Merge branch 'master' into MODORDERS-1087
yuntianhu May 7, 2024
be962f1
remove the api bach test for now
yuntianhu May 7, 2024
2b281ef
Merge remote-tracking branch 'origin/MODORDERS-1087' into MODORDERS-1087
yuntianhu May 7, 2024
f5c448a
delete pieces manager test
yuntianhu May 7, 2024
87c595a
Merge branch 'master' into MODORDERS-1087
yuntianhu May 7, 2024
bceb008
remodify the batch delete and add test
yuntianhu May 7, 2024
bf581aa
Merge remote-tracking branch 'origin/MODORDERS-1087' into MODORDERS-1087
yuntianhu May 7, 2024
1cf716a
Merge branch 'master' into MODORDERS-1087
yuntianhu May 8, 2024
3bb8489
remodify test
yuntianhu May 8, 2024
7a2add6
Merge remote-tracking branch 'origin/MODORDERS-1087' into MODORDERS-1087
yuntianhu May 8, 2024
b20df9d
remodify test
yuntianhu May 8, 2024
d32be26
remodify test
yuntianhu May 8, 2024
cf510ae
remodify test with name
yuntianhu May 8, 2024
472c0ee
remove issues sonarcloud
yuntianhu May 8, 2024
8629560
remove sonarcloud issues
yuntianhu May 8, 2024
fca8ab8
Merge branch 'master' into MODORDERS-1087
yuntianhu May 9, 2024
a632499
Merge branch 'master' into MODORDERS-1087
yuntianhu May 10, 2024
eb142cc
Merge branch 'master' into MODORDERS-1087
yuntianhu May 28, 2024
01286f9
Update PieceDeleteFlowManager.java
yuntianhu May 28, 2024
3205ba6
Update PieceDeleteFlowManager.java
yuntianhu May 28, 2024
ac5d118
Update PieceDeleteFlowManager.java
yuntianhu May 28, 2024
6d1fd0d
try to resolve the conflict
yuntianhu May 28, 2024
b8d16d0
Merge remote-tracking branch 'origin/MODORDERS-1087' into MODORDERS-1087
yuntianhu May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion ramls/pieces.raml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ protocols: [ HTTP, HTTPS ]

documentation:
- title: Orders Business Logic API
content: <b>API for managing pieces</b>
content: <b>API for managing pieces including batch operations for deletion.</b>

types:
piece: !include acq-models/mod-orders-storage/schemas/piece.json
Expand Down Expand Up @@ -47,6 +47,38 @@ resourceTypes:
example: true
required: false
default: false
/batch:
delete:
description: Batch delete pieces
body:
application/json:
type: piece-collection
responses:
204:
description: "Batch delete of pieces successfully completed"
400:
description: "Bad request"
body:
application/json:
example:
strict: false
value: !include examples/errors_400.sample
text/plain:
example: "unable to delete Piece -- Bad request"
404:
description: "One or more pieces not found"
body:
application/json:
type: errors
text/plain:
example: "Error - one or more pieces not found."
500:
description: "Internal server error, e.g. due to misconfiguration"
body:
application/json:
type: errors
text/plain:
example: "Internal server error - due to misconfiguration."
/{id}:
uriParameters:
id:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ private ResourcePathResolver() {
public static final String REPORTING_CODES = "reportingCodes";
public static final String PURCHASE_ORDER_STORAGE = "purchaseOrder";
public static final String PIECES_STORAGE = "pieces";
public static final String PIECES_COLLECTION_STORAGE = "PiecesCollection";
public static final String RECEIVING_HISTORY = "receiving-history";
public static final String RECEIPT_STATUS = "receiptStatus";
public static final String PAYMENT_STATUS = "paymentStatus";
Expand Down Expand Up @@ -96,6 +97,7 @@ private ResourcePathResolver() {
apis.put(USERS, "/users");
apis.put(ORDER_SETTINGS, "/orders-storage/settings");
apis.put(ROUTING_LISTS, "/orders-storage/routing-lists");
apis.put(PIECES_COLLECTION_STORAGE, "/orders-storage/pieces-collecton");

SUB_OBJECT_COLLECTION_APIS = Collections.unmodifiableMap(apis);
SUB_OBJECT_ITEM_APIS = Collections.unmodifiableMap(
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/org/folio/rest/impl/PiecesAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.folio.rest.annotations.Validate;
import org.folio.rest.core.models.RequestContext;
import org.folio.rest.jaxrs.model.Piece;
import org.folio.rest.jaxrs.model.PieceCollection;
import org.folio.rest.jaxrs.resource.OrdersPieces;
import org.folio.service.pieces.PieceStorageService;
import org.folio.service.pieces.flows.create.PieceCreateFlowManager;
Expand All @@ -38,6 +39,7 @@ public class PiecesAPI extends BaseApi implements OrdersPieces {
@Autowired
private PieceUpdateFlowManager pieceUpdateFlowManager;


public PiecesAPI() {
SpringContextUtil.autowireDependencies(this, Vertx.currentContext());
}
Expand Down Expand Up @@ -91,9 +93,16 @@ public void putOrdersPiecesById(String pieceId, boolean createItem, boolean dele
@Override
@Validate
public void deleteOrdersPiecesById(String pieceId, boolean deleteHolding, Map<String, String> okapiHeaders,
Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
pieceDeleteFlowManager.deletePiece(pieceId, deleteHolding, new RequestContext(vertxContext, okapiHeaders))
.onSuccess(ok -> asyncResultHandler.handle(succeededFuture(buildNoContentResponse())))
.onFailure(fail -> handleErrorResponse(asyncResultHandler, fail));
}

@Override
@Validate
public void deleteOrdersPiecesBatch(PieceCollection entity, Map<String, String> okapiHeaders, Handler<AsyncResult<Response>> asyncResultHandler, Context vertxContext) {
pieceDeleteFlowManager.batchDeletePiece(entity, new RequestContext(vertxContext, okapiHeaders));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@

public class PieceStorageService {
private static final Logger logger = LogManager.getLogger(PieceStorageService.class);

private static final String PIECES_BY_POL_ID_AND_STATUS_QUERY = "poLineId==%s and receivingStatus==%s";
private static final String PIECES_BY_HOLDING_ID_QUERY = "holdingId==%s";
private static final String PIECE_STORAGE_ENDPOINT = resourcesPath(PIECES_STORAGE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,39 @@

import static org.folio.orders.utils.ProtectedOperationType.DELETE;

import static org.folio.service.inventory.InventoryItemManager.ITEM_STATUS;
import static org.folio.service.inventory.InventoryItemManager.ITEM_STATUS_NAME;
import static org.folio.service.orders.utils.HelperUtils.collectResultsOnSuccess;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.models.pieces.PieceDeletionHolder;
import org.folio.rest.RestConstants;
import org.folio.models.ItemStatus;
import org.folio.rest.core.exceptions.ErrorCodes;
import org.folio.rest.core.exceptions.HttpException;
import org.folio.rest.core.models.RequestContext;
import org.folio.rest.jaxrs.model.Error;
import org.folio.rest.jaxrs.model.Errors;
import org.folio.rest.jaxrs.model.Piece;
import org.folio.rest.jaxrs.model.PieceCollection;
import org.folio.service.ProtectionService;
import org.folio.service.inventory.InventoryItemManager;
import org.folio.service.CirculationRequestsRetriever;
import org.folio.service.ProtectionService;
import org.folio.service.pieces.PieceStorageService;
import org.folio.service.pieces.PieceUpdateInventoryService;
import org.folio.service.pieces.flows.BasePieceFlowHolderBuilder;

import io.vertx.core.Future;
import io.vertx.core.json.JsonObject;

public class PieceDeleteFlowManager {

Expand All @@ -26,6 +46,8 @@ public class PieceDeleteFlowManager {
private final PieceDeleteFlowPoLineService pieceDeleteFlowPoLineService;
private final BasePieceFlowHolderBuilder basePieceFlowHolderBuilder;
private final CirculationRequestsRetriever circulationRequestsRetriever;
private final InventoryItemManager inventoryItemManager;
private final PieceUpdateInventoryService pieceUpdateInventoryService;

public PieceDeleteFlowManager(PieceDeleteFlowInventoryManager pieceDeleteFlowInventoryManager,
PieceStorageService pieceStorageService,
Expand All @@ -43,6 +65,7 @@ public PieceDeleteFlowManager(PieceDeleteFlowInventoryManager pieceDeleteFlowInv

public Future<Void> deletePiece(String pieceId, boolean deleteHolding, RequestContext requestContext) {
PieceDeletionHolder holder = new PieceDeletionHolder().withDeleteHolding(deleteHolding);

return pieceStorageService.getPieceById(pieceId, requestContext)
.map(holder::withPieceToDelete)
.compose(aHolder -> basePieceFlowHolderBuilder.updateHolderWithOrderInformation(holder, requestContext))
Expand Down Expand Up @@ -72,11 +95,77 @@ private Future<Void> isDeletePieceRequestValid(PieceDeletionHolder holder, Reque
.mapEmpty();
}

private Future<Pair<String, String>> processInventory(PieceDeletionHolder holder, RequestContext requestContext) {
return deleteItem(holder, requestContext)
.compose(aVoid -> {
if (holder.isDeleteHolding()) {
return pieceUpdateInventoryService.deleteHoldingConnectedToPiece(holder.getPieceToDelete(), requestContext);
}
return Future.succeededFuture();
});
}

protected Future<Void> updatePoLine(PieceDeletionHolder holder, RequestContext requestContext) {
var comPOL = holder.getOriginPoLine();
return Boolean.TRUE.equals(comPOL.getIsPackage()) || Boolean.TRUE.equals(comPOL.getCheckinItems())
? Future.succeededFuture()
: pieceDeleteFlowPoLineService.updatePoLine(holder, requestContext);
}

private Future<Void> deleteItem(PieceDeletionHolder holder, RequestContext requestContext) {
Piece piece = holder.getPieceToDelete();
if (piece.getItemId() != null) {
return getOnOrderItemForPiece(piece, requestContext).compose(item -> {
if (item != null) {
return inventoryItemManager.deleteItem(piece.getItemId(), true, requestContext);
}
return Future.succeededFuture();
});
}
return Future.succeededFuture();
}

private boolean isItemWithStatus(JsonObject item, String status) {
return Optional.ofNullable(item).map(itemP -> item.getJsonObject(ITEM_STATUS))
.filter(itemStatus -> status.equalsIgnoreCase(itemStatus.getString(ITEM_STATUS_NAME)))
.isPresent();
}

private Future<JsonObject> getOnOrderItemForPiece(Piece piece, RequestContext requestContext) {
if (StringUtils.isNotEmpty(piece.getItemId())) {
return inventoryItemManager.getItemRecordById(piece.getItemId(), true, requestContext)
.map(item -> {
boolean isOnOrderItem = isItemWithStatus(item, ItemStatus.ON_ORDER.value());
if (isOnOrderItem) {
return item;
}
return null;
});
} else {
return Future.succeededFuture();
}
}

public Future<List<Void>> batchDeletePiece (PieceCollection entity, RequestContext requestContext) {
List <String> ids = new ArrayList<>();
entity.getPieces().stream().forEach(v -> ids.add(v.getId()));
List<Future<PieceDeletionHolder>> deletionHolders = ids.stream()
.map(pieceId -> {
PieceDeletionHolder holder = new PieceDeletionHolder().withDeleteHolding(true);
return pieceStorageService.getPieceById(pieceId, requestContext)
.map(pieceToDelete -> {
holder.withPieceToDelete(pieceToDelete);
return holder;
});
})
.toList();
return collectResultsOnSuccess(deletionHolders)
.compose(holders -> {
List<Future<Void>> deleteFutures = holders.stream()
.map(holder -> pieceStorageService.deletePiece(holder.getPieceToDelete().getId(), true, requestContext))
.toList();

return collectResultsOnSuccess(deleteFutures);
});
}
}
19 changes: 19 additions & 0 deletions src/test/java/org/folio/RestTestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@

import java.util.Map;

import jakarta.validation.Payload;
import org.apache.commons.lang3.StringUtils;
import org.folio.orders.events.handlers.HandlersTestHelper;
import org.folio.rest.jaxrs.model.Error;
import org.folio.rest.jaxrs.model.Errors;
import org.folio.rest.jaxrs.model.PieceCollection;
import org.folio.rest.tools.parser.JsonPathParser;
import org.hamcrest.Matchers;

Expand Down Expand Up @@ -171,6 +173,23 @@ public static Response verifyDeleteResponse(String url, Headers headers, String
return response;
}

public static Response verifyDeleteResponse(String url, String body, Headers headers, String expectedContentType, int expectedCode) {
return RestAssured
.with()
.header(X_OKAPI_URL)
.header(X_OKAPI_TOKEN)
.headers(headers)
.contentType(APPLICATION_JSON)
.body(body)
.when()
.delete(url)
.then()
.statusCode(expectedCode)
.contentType(expectedContentType)
.extract()
.response();
}

public static void checkPreventProtectedFieldsModificationRule(String path, JsonObject compPO, Map<String, Object> updatedFields) {
JsonObject compPOJson = JsonObject.mapFrom(compPO);
JsonPathParser compPOParser = new JsonPathParser(compPOJson);
Expand Down
15 changes: 15 additions & 0 deletions src/test/java/org/folio/rest/impl/PieceApiTest.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package org.folio.rest.impl;

import static io.restassured.RestAssured.given;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static org.folio.RestTestUtils.prepareHeaders;
import static org.folio.RestTestUtils.verifyDeleteResponse;
import static org.folio.RestTestUtils.verifyPatch;
import static org.folio.RestTestUtils.verifyPostResponse;
import static org.folio.RestTestUtils.verifyPut;
import static org.folio.TestConfig.X_OKAPI_URL;
import static org.folio.TestConfig.clearServiceInteractions;
import static org.folio.TestConfig.initSpringContext;
import static org.folio.TestConfig.isVerticleNotDeployed;
Expand All @@ -15,9 +18,12 @@
import static org.folio.TestConstants.ID_DOES_NOT_EXIST;
import static org.folio.TestConstants.ID_FOR_INTERNAL_SERVER_ERROR;
import static org.folio.TestConstants.X_ECHO_STATUS;
import static org.folio.TestConstants.X_OKAPI_TOKEN;
import static org.folio.TestConstants.X_OKAPI_USER_ID;
import static org.folio.TestConstants.X_OKAPI_USER_ID_WITH_ACQ_UNITS;
import static org.folio.TestUtils.getMockAsJson;
import static org.folio.TestUtils.getMockData;
import static org.folio.orders.utils.ResourcePathResolver.PIECES_COLLECTION_STORAGE;
import static org.folio.orders.utils.ResourcePathResolver.PIECES_STORAGE;
import static org.folio.orders.utils.ResourcePathResolver.PO_LINES_STORAGE;
import static org.folio.orders.utils.ResourcePathResolver.PURCHASE_ORDER_STORAGE;
Expand All @@ -31,15 +37,20 @@
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

import javax.ws.rs.core.Response;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

import io.restassured.http.Header;
import io.restassured.http.Headers;
import io.vertx.core.json.JsonObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand All @@ -55,12 +66,15 @@
import org.folio.rest.jaxrs.model.Location;
import org.folio.rest.jaxrs.model.Physical;
import org.folio.rest.jaxrs.model.Piece;
import org.folio.rest.jaxrs.model.PieceCollection;
import org.folio.rest.jaxrs.model.PurchaseOrder;
import org.folio.rest.jaxrs.model.Title;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.testcontainers.shaded.com.fasterxml.jackson.core.JsonProcessingException;

public class PieceApiTest {

Expand All @@ -69,6 +83,7 @@ public class PieceApiTest {
public static final String PIECES_ENDPOINT = "/orders/pieces";
private static final String PIECES_ID_PATH = PIECES_ENDPOINT + "/%s";
static final String CONSISTENT_RECEIVED_STATUS_PIECE_UUID = "7d0aa803-a659-49f0-8a95-968f277c87d7";
private static final String PIECES_BATCH_PATH = PIECES_ENDPOINT+"/batch";
private JsonObject pieceJsonReqData = getMockAsJson(PIECE_RECORDS_MOCK_DATA_PATH + "pieceRecord.json");

private static boolean runningOnOwn;
Expand Down
Loading
Loading