From 55b0a7ac03b32336d6261247310ee2b8466df8c0 Mon Sep 17 00:00:00 2001
From: yuntianhu <48864579+yuntianhu@users.noreply.github.com>
Date: Tue, 28 May 2024 13:17:40 -0400
Subject: [PATCH 1/4] [MODORDER-1087] add batch delete
---
ramls/pieces.raml | 34 +++++++++-
.../java/org/folio/rest/impl/PiecesAPI.java | 7 +++
.../flows/delete/PieceDeleteFlowManager.java | 28 +++++++++
.../delete/PieceDeleteFlowManagerTest.java | 62 +++++++++++++++++++
4 files changed, 130 insertions(+), 1 deletion(-)
diff --git a/ramls/pieces.raml b/ramls/pieces.raml
index 6cdb65a4c..1ea61de91 100644
--- a/ramls/pieces.raml
+++ b/ramls/pieces.raml
@@ -6,7 +6,7 @@ protocols: [ HTTP, HTTPS ]
documentation:
- title: Orders Business Logic API
- content: API for managing pieces
+ content: API for managing pieces including batch operations for deletion.
types:
piece: !include acq-models/mod-orders-storage/schemas/piece.json
@@ -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:
diff --git a/src/main/java/org/folio/rest/impl/PiecesAPI.java b/src/main/java/org/folio/rest/impl/PiecesAPI.java
index 968aa9c8b..d5008709a 100644
--- a/src/main/java/org/folio/rest/impl/PiecesAPI.java
+++ b/src/main/java/org/folio/rest/impl/PiecesAPI.java
@@ -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;
@@ -96,4 +97,10 @@ public void deleteOrdersPiecesById(String pieceId, boolean deleteHolding, Map asyncResultHandler.handle(succeededFuture(buildNoContentResponse())))
.onFailure(fail -> handleErrorResponse(asyncResultHandler, fail));
}
+
+ @Override
+ @Validate
+ public void deleteOrdersPiecesBatch(PieceCollection entity, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) {
+ pieceDeleteFlowManager.batchDeletePiece(entity, new RequestContext(vertxContext, okapiHeaders));
+ }
}
diff --git a/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java b/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java
index a3ec3f1e3..5ad227f44 100644
--- a/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java
+++ b/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java
@@ -1,7 +1,12 @@
package org.folio.service.pieces.flows.delete;
import static org.folio.orders.utils.ProtectedOperationType.DELETE;
+import static org.folio.service.orders.utils.HelperUtils.collectResultsOnSuccess;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.models.pieces.PieceDeletionHolder;
@@ -13,6 +18,7 @@
import org.folio.service.ProtectionService;
import org.folio.service.pieces.PieceStorageService;
import org.folio.service.pieces.flows.BasePieceFlowHolderBuilder;
+import org.folio.rest.jaxrs.model.PieceCollection;
import io.vertx.core.Future;
@@ -79,4 +85,26 @@ protected Future updatePoLine(PieceDeletionHolder holder, RequestContext r
: pieceDeleteFlowPoLineService.updatePoLine(holder, requestContext);
}
+ public Future> batchDeletePiece (PieceCollection entity, RequestContext requestContext) {
+ List ids = new ArrayList<>();
+ entity.getPieces().stream().forEach(v -> ids.add(v.getId()));
+ List> 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> deleteFutures = holders.stream()
+ .map(holder -> pieceStorageService.deletePiece(holder.getPieceToDelete().getId(), true, requestContext))
+ .toList();
+ return collectResultsOnSuccess(deleteFutures);
+ });
+ }
+
}
diff --git a/src/test/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManagerTest.java b/src/test/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManagerTest.java
index 07848cb01..33b770ce6 100644
--- a/src/test/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManagerTest.java
+++ b/src/test/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManagerTest.java
@@ -42,6 +42,7 @@
import org.folio.rest.jaxrs.model.Eresource;
import org.folio.rest.jaxrs.model.Location;
import org.folio.rest.jaxrs.model.Piece;
+import org.folio.rest.jaxrs.model.PieceCollection;
import org.folio.rest.jaxrs.model.PoLine;
import org.folio.rest.jaxrs.model.PurchaseOrder;
import org.folio.rest.jaxrs.model.Title;
@@ -368,6 +369,67 @@ void shouldUpdateLineQuantityIfPoLineIsNotPackageAndManualPieceCreateFalseAndInv
verify(basePieceFlowHolderBuilder).updateHolderWithOrderInformation(holder, requestContext);
}
+ @Test
+ void shouldDeletePiecesInBatch() {
+ String orderId = UUID.randomUUID().toString();
+ String holdingId = UUID.randomUUID().toString();
+ String lineId = UUID.randomUUID().toString();
+ String itemId = UUID.randomUUID().toString();
+ String locationId = UUID.randomUUID().toString();
+ String titleId = UUID.randomUUID().toString();
+ JsonObject holding = new JsonObject();
+ holding.put(ID, holdingId);
+ holding.put(HOLDING_PERMANENT_LOCATION_ID, locationId);
+ JsonObject item = new JsonObject().put(ID, itemId);
+ item.put(ITEM_STATUS, new JsonObject().put(ITEM_STATUS_NAME, ItemStatus.ON_ORDER.value()));
+ Piece piece = new Piece().withId(UUID.randomUUID().toString()).withPoLineId(lineId)
+ .withHoldingId(holdingId).withFormat(Piece.Format.ELECTRONIC);
+ Location loc = new Location().withHoldingId(holdingId).withQuantityElectronic(1).withQuantity(1);
+ Cost cost = new Cost().withQuantityElectronic(1)
+ .withListUnitPriceElectronic(1d).withExchangeRate(1d).withCurrency("USD")
+ .withPoLineEstimatedPrice(1d);
+ PoLine poLine = new PoLine().withIsPackage(false).withCheckinItems(false).withOrderFormat(PoLine.OrderFormat.ELECTRONIC_RESOURCE)
+ .withEresource(new Eresource().withCreateInventory(Eresource.CreateInventory.INSTANCE_HOLDING))
+ .withPurchaseOrderId(orderId).withId(lineId).withLocations(List.of(loc)).withCost(cost);
+ PurchaseOrder purchaseOrder = new PurchaseOrder().withId(orderId).withWorkflowStatus(PurchaseOrder.WorkflowStatus.OPEN);
+ Title title = new Title().withId(titleId);
+ List ids = new ArrayList<>();
+ ids.add(piece);
+ PieceCollection pieceCollection = new PieceCollection();
+ pieceCollection.withPieces(ids);
+ doReturn(succeededFuture(piece)).when(pieceStorageService).getPieceById(piece.getId(), requestContext);
+ doReturn(succeededFuture(null)).when(protectionService).isOperationRestricted(any(), any(ProtectedOperationType.class), eq(requestContext));
+ doReturn(succeededFuture(null)).when(pieceStorageService).deletePiece(eq(piece.getId()), eq(true), eq(requestContext));
+ doReturn(succeededFuture(null)).when(circulationRequestsRetriever).getNumberOfRequestsByItemId(eq(piece.getItemId()), eq(requestContext));
+ doReturn(succeededFuture(holding)).when(inventoryHoldingManager).getHoldingById(holdingId, false, requestContext);
+ doReturn(succeededFuture(null)).when(inventoryItemManager).getItemsByHoldingId(holdingId, requestContext);
+ doReturn(succeededFuture(null)).when(inventoryHoldingManager).deleteHoldingById(piece.getHoldingId(), true, requestContext);
+ doReturn(succeededFuture(null)).when(inventoryItemManager).getItemRecordById(itemId, true, requestContext);
+ doReturn(succeededFuture(null)).when(inventoryItemManager).deleteItem(itemId, true, requestContext);
+ doReturn(succeededFuture(holding)).when(inventoryHoldingManager).getHoldingById(holdingId, true, requestContext);
+ doReturn(succeededFuture(null)).when(pieceUpdateInventoryService).deleteHoldingConnectedToPiece(piece, requestContext);
+ doReturn(succeededFuture(new ArrayList())).when(inventoryItemManager).getItemsByHoldingId(holdingId, requestContext);
+ final ArgumentCaptor PieceDeletionHolderCapture = ArgumentCaptor.forClass(PieceDeletionHolder.class);
+ doAnswer((Answer>) invocation -> {
+ PieceDeletionHolder answerHolder = invocation.getArgument(0);
+ answerHolder.withOrderInformation(purchaseOrder, poLine);
+ return succeededFuture(null);
+ }).when(basePieceFlowHolderBuilder).updateHolderWithOrderInformation(PieceDeletionHolderCapture.capture(), eq(requestContext));
+ doAnswer((Answer>) invocation -> {
+ PieceDeletionHolder answerHolder = invocation.getArgument(0);
+ answerHolder.withTitleInformation(title);
+ return succeededFuture(null);
+ }).when(basePieceFlowHolderBuilder).updateHolderWithTitleInformation(PieceDeletionHolderCapture.capture(), eq(requestContext));
+
+ final ArgumentCaptor pieceDeletionHolderCapture = ArgumentCaptor.forClass(PieceDeletionHolder.class);
+ doReturn(succeededFuture(null)).when(pieceDeleteFlowPoLineService).updatePoLine(pieceDeletionHolderCapture.capture(), eq(requestContext));
+ //When
+ pieceDeleteFlowManager.batchDeletePiece(pieceCollection, requestContext).result();
+ verify(pieceStorageService).deletePiece(eq(piece.getId()), eq(true), eq(requestContext));
+ verify(inventoryItemManager, times(0)).deleteItem(itemId, true, requestContext);
+ verify(pieceStorageService, times(1)).deletePiece(eq(piece.getId()), eq(true), eq(requestContext));
+ }
+
private static class ContextConfiguration {
@Bean
From 8771a90a7cb1de71abf6d5a16bf02bc4a28990a3 Mon Sep 17 00:00:00 2001
From: yuntianhu <48864579+yuntianhu@users.noreply.github.com>
Date: Fri, 31 May 2024 13:03:27 -0400
Subject: [PATCH 2/4] [MODORDER-1087] change the piecesCollection to list. Raml
file modifciation
---
ramls/pieces.raml | 16 +++++++--
.../java/org/folio/rest/impl/PiecesAPI.java | 13 +++++---
.../flows/delete/PieceDeleteFlowManager.java | 33 +++++--------------
.../delete/PieceDeleteFlowManagerTest.java | 11 ++++---
4 files changed, 36 insertions(+), 37 deletions(-)
diff --git a/ramls/pieces.raml b/ramls/pieces.raml
index 1ea61de91..fa321e416 100644
--- a/ramls/pieces.raml
+++ b/ramls/pieces.raml
@@ -49,10 +49,20 @@ resourceTypes:
default: false
/batch:
delete:
- description: Batch delete pieces
+ description: Batch delete pieces with optional deletion of related holdings
body:
application/json:
- type: piece-collection
+ type: object
+ properties:
+ ids:
+ type: array
+ items:
+ type: string
+ description: ID of a piece to be deleted
+ deleteHolding:
+ type: boolean
+ description: "Flag to determine if related holdings should also be deleted"
+ default: false
responses:
204:
description: "Batch delete of pieces successfully completed"
@@ -78,7 +88,7 @@ resourceTypes:
application/json:
type: errors
text/plain:
- example: "Internal server error - due to misconfiguration."
+ example: "Internal server realization error - due to misconfiguration."
/{id}:
uriParameters:
id:
diff --git a/src/main/java/org/folio/rest/impl/PiecesAPI.java b/src/main/java/org/folio/rest/impl/PiecesAPI.java
index d5008709a..314fdf59d 100644
--- a/src/main/java/org/folio/rest/impl/PiecesAPI.java
+++ b/src/main/java/org/folio/rest/impl/PiecesAPI.java
@@ -2,15 +2,18 @@
import static io.vertx.core.Future.succeededFuture;
+import java.util.List;
import java.util.Map;
import javax.ws.rs.core.Response;
+import io.vertx.sqlclient.impl.Connection;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.rest.annotations.Validate;
import org.folio.rest.core.models.RequestContext;
+import org.folio.rest.jaxrs.model.OrdersPiecesBatchDeleteApplicationJson;
import org.folio.rest.jaxrs.model.Piece;
import org.folio.rest.jaxrs.model.PieceCollection;
import org.folio.rest.jaxrs.resource.OrdersPieces;
@@ -67,6 +70,11 @@ public void postOrdersPieces(boolean createItem, Piece entity, Map handleErrorResponse(asyncResultHandler, t));
}
+ @Override
+ public void deleteOrdersPiecesBatch(OrdersPiecesBatchDeleteApplicationJson entity, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) {
+ pieceDeleteFlowManager.batchDeletePiece(entity.getIds(),entity.getDeleteHolding(),new RequestContext(vertxContext, okapiHeaders));
+ }
+
@Override
@Validate
public void getOrdersPiecesById(String id, Map okapiHeaders,
@@ -98,9 +106,4 @@ public void deleteOrdersPiecesById(String pieceId, boolean deleteHolding, Map handleErrorResponse(asyncResultHandler, fail));
}
- @Override
- @Validate
- public void deleteOrdersPiecesBatch(PieceCollection entity, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) {
- pieceDeleteFlowManager.batchDeletePiece(entity, new RequestContext(vertxContext, okapiHeaders));
- }
}
diff --git a/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java b/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java
index 5ad227f44..768321dd8 100644
--- a/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java
+++ b/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java
@@ -1,12 +1,11 @@
package org.folio.service.pieces.flows.delete;
import static org.folio.orders.utils.ProtectedOperationType.DELETE;
-import static org.folio.service.orders.utils.HelperUtils.collectResultsOnSuccess;
-import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
-import org.apache.commons.collections4.CollectionUtils;
+import io.vertx.core.CompositeFuture;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.models.pieces.PieceDeletionHolder;
@@ -18,7 +17,6 @@
import org.folio.service.ProtectionService;
import org.folio.service.pieces.PieceStorageService;
import org.folio.service.pieces.flows.BasePieceFlowHolderBuilder;
-import org.folio.rest.jaxrs.model.PieceCollection;
import io.vertx.core.Future;
@@ -85,26 +83,13 @@ protected Future updatePoLine(PieceDeletionHolder holder, RequestContext r
: pieceDeleteFlowPoLineService.updatePoLine(holder, requestContext);
}
- public Future> batchDeletePiece (PieceCollection entity, RequestContext requestContext) {
- List ids = new ArrayList<>();
- entity.getPieces().stream().forEach(v -> ids.add(v.getId()));
- List> 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> deleteFutures = holders.stream()
- .map(holder -> pieceStorageService.deletePiece(holder.getPieceToDelete().getId(), true, requestContext))
- .toList();
- return collectResultsOnSuccess(deleteFutures);
- });
+ public Future> batchDeletePiece (List ids, boolean deleteHolding ,RequestContext requestContext) {
+ List deleteFutures = ids.stream()
+ .map(id -> deletePiece(id, deleteHolding, requestContext))
+ .collect(Collectors.toList());
+
+ return CompositeFuture.all(deleteFutures)
+ .map(empty -> null);
}
}
diff --git a/src/test/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManagerTest.java b/src/test/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManagerTest.java
index 33b770ce6..103b9a815 100644
--- a/src/test/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManagerTest.java
+++ b/src/test/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManagerTest.java
@@ -1,5 +1,6 @@
package org.folio.service.pieces.flows.delete;
+import static io.vertx.core.Future.*;
import static io.vertx.core.Future.succeededFuture;
import static org.folio.TestConfig.autowireDependencies;
import static org.folio.TestConfig.clearServiceInteractions;
@@ -393,10 +394,10 @@ void shouldDeletePiecesInBatch() {
.withPurchaseOrderId(orderId).withId(lineId).withLocations(List.of(loc)).withCost(cost);
PurchaseOrder purchaseOrder = new PurchaseOrder().withId(orderId).withWorkflowStatus(PurchaseOrder.WorkflowStatus.OPEN);
Title title = new Title().withId(titleId);
- List ids = new ArrayList<>();
- ids.add(piece);
- PieceCollection pieceCollection = new PieceCollection();
- pieceCollection.withPieces(ids);
+ List pieces = new ArrayList<>();
+ pieces.add(piece);
+ List ids = new ArrayList<>();
+ ids.add(piece.getId());
doReturn(succeededFuture(piece)).when(pieceStorageService).getPieceById(piece.getId(), requestContext);
doReturn(succeededFuture(null)).when(protectionService).isOperationRestricted(any(), any(ProtectedOperationType.class), eq(requestContext));
doReturn(succeededFuture(null)).when(pieceStorageService).deletePiece(eq(piece.getId()), eq(true), eq(requestContext));
@@ -424,7 +425,7 @@ void shouldDeletePiecesInBatch() {
final ArgumentCaptor pieceDeletionHolderCapture = ArgumentCaptor.forClass(PieceDeletionHolder.class);
doReturn(succeededFuture(null)).when(pieceDeleteFlowPoLineService).updatePoLine(pieceDeletionHolderCapture.capture(), eq(requestContext));
//When
- pieceDeleteFlowManager.batchDeletePiece(pieceCollection, requestContext).result();
+ pieceDeleteFlowManager.batchDeletePiece(ids,false ,requestContext).result();
verify(pieceStorageService).deletePiece(eq(piece.getId()), eq(true), eq(requestContext));
verify(inventoryItemManager, times(0)).deleteItem(itemId, true, requestContext);
verify(pieceStorageService, times(1)).deletePiece(eq(piece.getId()), eq(true), eq(requestContext));
From 0bf580a70e8fc52f6ef3d5974ec20eeee630d578 Mon Sep 17 00:00:00 2001
From: yuntianhu <48864579+yuntianhu@users.noreply.github.com>
Date: Tue, 4 Jun 2024 16:11:20 -0400
Subject: [PATCH 3/4] [MODORDER-1087] change the piecesCollection to list. Raml
file modifciation
---
ramls/pieces.raml | 55 ++++++-----
.../java/org/folio/rest/impl/PiecesAPI.java | 10 +-
.../flows/delete/PieceDeleteFlowManager.java | 1 -
src/test/java/org/folio/RestTestUtils.java | 16 +++
.../org/folio/rest/impl/PieceApiTest.java | 97 +++++++++++++++++++
5 files changed, 150 insertions(+), 29 deletions(-)
diff --git a/ramls/pieces.raml b/ramls/pieces.raml
index fa321e416..eb9607d1d 100644
--- a/ramls/pieces.raml
+++ b/ramls/pieces.raml
@@ -15,6 +15,19 @@ types:
UUID:
type: string
pattern: ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$
+ BatchDeletePayload:
+ type: object
+ properties:
+ ids:
+ type: array
+ items:
+ type: string
+ description: List of IDs to be deleted
+ deleteHoldings:
+ type: boolean
+ description: Specifies whether associated holdings should also be deleted
+ required: false
+ default: false
traits:
pageable: !include raml-util/traits/pageable.raml
@@ -49,46 +62,40 @@ resourceTypes:
default: false
/batch:
delete:
- description: Batch delete pieces with optional deletion of related holdings
+ description: Deletes multiple pieces optionally including related holdings.
body:
application/json:
- type: object
- properties:
- ids:
- type: array
- items:
- type: string
- description: ID of a piece to be deleted
- deleteHolding:
- type: boolean
- description: "Flag to determine if related holdings should also be deleted"
- default: false
+ type: string
+ example: |
+ {
+ "ids": ["123", "456", "789"],
+ "deleteHoldings": false
+ }
responses:
204:
- description: "Batch delete of pieces successfully completed"
+ description: "Pieces records successfully deleted"
400:
- description: "Bad request"
+ description: "Bad request due to invalid data format or validation error"
body:
application/json:
example:
- strict: false
- value: !include examples/errors_400.sample
+ strict: false
+ value: !include examples/errors_400.sample
text/plain:
- example: "unable to delete Piece -- Bad request"
+ example: "unable to delete Pieces -- Bad request"
404:
- description: "One or more pieces not found"
+ description: "One or more specified IDs do not exist"
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"
+ description: "Internal server error due to a misconfiguration or server fault"
body:
application/json:
- type: errors
+ example:
+ strict: false
+ value: !include examples/errors_500.sample
text/plain:
- example: "Internal server realization error - due to misconfiguration."
+ example: "unable to delete Pieces -- Internal server error"
/{id}:
uriParameters:
id:
diff --git a/src/main/java/org/folio/rest/impl/PiecesAPI.java b/src/main/java/org/folio/rest/impl/PiecesAPI.java
index 314fdf59d..d4fcac540 100644
--- a/src/main/java/org/folio/rest/impl/PiecesAPI.java
+++ b/src/main/java/org/folio/rest/impl/PiecesAPI.java
@@ -7,15 +7,14 @@
import javax.ws.rs.core.Response;
-import io.vertx.sqlclient.impl.Connection;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.folio.rest.annotations.Validate;
import org.folio.rest.core.models.RequestContext;
+import org.folio.rest.jaxrs.model.BatchDeletePayload;
import org.folio.rest.jaxrs.model.OrdersPiecesBatchDeleteApplicationJson;
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;
@@ -71,8 +70,11 @@ public void postOrdersPieces(boolean createItem, Piece entity, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) {
- pieceDeleteFlowManager.batchDeletePiece(entity.getIds(),entity.getDeleteHolding(),new RequestContext(vertxContext, okapiHeaders));
+ public void deleteOrdersPiecesBatch(String entity, Map okapiHeaders, Handler> asyncResultHandler, Context vertxContext) {
+ JsonObject json = new JsonObject(entity);
+ List ids = json.getJsonArray("ids").getList();
+ boolean deleteHoldings = json.getBoolean("deleteHoldings", false);
+ pieceDeleteFlowManager.batchDeletePiece(ids, deleteHoldings, new RequestContext(vertxContext, okapiHeaders));
}
@Override
diff --git a/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java b/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java
index 768321dd8..55b09edab 100644
--- a/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java
+++ b/src/main/java/org/folio/service/pieces/flows/delete/PieceDeleteFlowManager.java
@@ -87,7 +87,6 @@ public Future> batchDeletePiece (List ids, boolean deleteHol
List deleteFutures = ids.stream()
.map(id -> deletePiece(id, deleteHolding, requestContext))
.collect(Collectors.toList());
-
return CompositeFuture.all(deleteFutures)
.map(empty -> null);
}
diff --git a/src/test/java/org/folio/RestTestUtils.java b/src/test/java/org/folio/RestTestUtils.java
index 002952b6f..c579d25c4 100644
--- a/src/test/java/org/folio/RestTestUtils.java
+++ b/src/test/java/org/folio/RestTestUtils.java
@@ -59,6 +59,22 @@ public static Response verifyPostResponse(String url, String body, Headers heade
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 Response verifyPut(String url, JsonObject body, String expectedContentType, int expectedCode) {
return verifyPut(url, body.encodePrettily(), expectedContentType, expectedCode);
diff --git a/src/test/java/org/folio/rest/impl/PieceApiTest.java b/src/test/java/org/folio/rest/impl/PieceApiTest.java
index aa33fefe8..9e9c524f0 100644
--- a/src/test/java/org/folio/rest/impl/PieceApiTest.java
+++ b/src/test/java/org/folio/rest/impl/PieceApiTest.java
@@ -33,6 +33,8 @@
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertNull;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@@ -40,6 +42,7 @@
import java.util.concurrent.TimeoutException;
import io.restassured.http.Header;
+import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -55,6 +58,7 @@
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;
@@ -70,6 +74,8 @@ public class PieceApiTest {
private static final String PIECES_ID_PATH = PIECES_ENDPOINT + "/%s";
static final String CONSISTENT_RECEIVED_STATUS_PIECE_UUID = "7d0aa803-a659-49f0-8a95-968f277c87d7";
private JsonObject pieceJsonReqData = getMockAsJson(PIECE_RECORDS_MOCK_DATA_PATH + "pieceRecord.json");
+ public static final String PIECES_BATCH_DELETE_ENDPOINT = "orders/pieces/batch";
+
private static boolean runningOnOwn;
@@ -356,4 +362,95 @@ void deletePieceInternalErrorOnStorageTest() {
logger.info("=== Test delete piece by id - internal error from storage 500 ===");
verifyDeleteResponse(String.format(PIECES_ID_PATH, ID_FOR_INTERNAL_SERVER_ERROR), APPLICATION_JSON, 500);
}
+
+ @Test
+ void deletePiecesByIdsTest2() {
+ logger.info("=== Test delete pieces by ids - item deleted ===");
+
+ String pieceId = UUID.randomUUID().toString();
+ List ids = Arrays.asList(pieceId);
+ Boolean deleteHoldings = false;
+ JsonArray jsonArrary = new JsonArray(ids);
+ JsonObject jsonObject = new JsonObject()
+ .put("ids", jsonArrary);
+ // .put("deleteHolding", deleteHoldings);
+
+ List pieces = new ArrayList<>();
+
+
+ // Mock response setup for deletion
+ //MockServer.addMockEntry(PIECES_STORAGE, JsonObject.mapFrom(jsonObject).encode()); // Simplified mock data
+
+ // Simulate the delete call
+ verifyDeleteResponse(PIECES_BATCH_DELETE_ENDPOINT,
+ String.valueOf(jsonObject),
+ prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, X_OKAPI_USER_ID),
+ APPLICATION_JSON, 204); // Assuming successful deletion returns a 204 No Content
+
+ // Assertions to check that the deletion was processed in the mock server
+ assertNull(MockServer.getItemDeletions()); // Check if item deletions are as expected
+ assertThat(MockServer.getPieceDeletions(), hasSize(1)); // Verify that exactly one piece deletion was processed
+ }
+
+ @Test
+ public void deletePiecesByIdsTest() {
+ logger.info("=== Test delete pieces by ids - item deleted ===");
+
+ // Create unique IDs for the components
+ String itemId = UUID.randomUUID().toString();
+ String lineId = UUID.randomUUID().toString();
+ String orderId = UUID.randomUUID().toString();
+ String holdingId = UUID.randomUUID().toString();
+ String titleId = UUID.randomUUID().toString();
+
+ CompositePurchaseOrder order = new CompositePurchaseOrder().withId(orderId);
+ Location loc = new Location().withHoldingId(holdingId).withQuantityElectronic(1).withQuantity(1);
+ Cost cost = new Cost().withQuantityElectronic(1);
+
+ // Setup the PO Line
+ CompositePoLine poLine = new CompositePoLine().withId(lineId)
+ .withOrderFormat(CompositePoLine.OrderFormat.PHYSICAL_RESOURCE)
+ .withLocations(Collections.singletonList(loc))
+ .withCost(cost)
+ .withPhysical(new Physical().withCreateInventory(Physical.CreateInventory.INSTANCE_HOLDING_ITEM));
+
+ order.setCompositePoLines(Collections.singletonList(poLine));
+
+ // Create a title
+ Title title = new Title().withId(titleId).withTitle("title name");
+
+ // Setup the piece
+ Piece piece = new Piece().withId(UUID.randomUUID().toString())
+ .withFormat(Piece.Format.PHYSICAL)
+ .withHoldingId(holdingId)
+ .withItemId(itemId)
+ .withPoLineId(poLine.getId())
+ .withTitleId(titleId);
+
+ // Mock the server responses
+ MockServer.addMockEntry(PIECES_STORAGE, JsonObject.mapFrom(piece));
+ MockServer.addMockEntry(PO_LINES_STORAGE, JsonObject.mapFrom(poLine));
+ MockServer.addMockEntry(PURCHASE_ORDER_STORAGE, JsonObject.mapFrom(order));
+ MockServer.addMockEntry(TITLES, JsonObject.mapFrom(title));
+ MockServer.addMockEntry(ITEM_RECORDS, new JsonObject().put(ID, itemId));
+
+ // Prepare request data as JSON Array
+ JsonArray jsonArray = new JsonArray().add(piece.getId());
+ JsonObject jsonObject = new JsonObject()
+ .put("ids", jsonArray)
+ .put("deleteHoldings", false);
+
+ // Log the JSON being sent to the server
+ logger.debug("Sending JSON for deletion: {}", jsonObject.encode());
+
+ // Perform the delete operation and verify the response
+ verifyDeleteResponse(PIECES_BATCH_DELETE_ENDPOINT, jsonObject.toString(),
+ prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, X_OKAPI_USER_ID), APPLICATION_JSON, 204).as(Piece.class);
+
+ // Assert no items were deleted
+ assertNull(MockServer.getItemDeletions());
+
+ // Assert that exactly one piece was deleted
+ assertThat(MockServer.getPieceDeletions(), hasSize(1));
+ }
}
From b4a0f4d77047680d1e90bbe6badd38baa17d4e37 Mon Sep 17 00:00:00 2001
From: yuntianhu <48864579+yuntianhu@users.noreply.github.com>
Date: Wed, 5 Jun 2024 06:10:11 -0400
Subject: [PATCH 4/4] [MODORDER-1087] update the batch delete PiecesApiTest
---
.../java/org/folio/rest/impl/PiecesAPI.java | 1 -
.../org/folio/rest/impl/PieceApiTest.java | 53 ++++---------------
2 files changed, 10 insertions(+), 44 deletions(-)
diff --git a/src/main/java/org/folio/rest/impl/PiecesAPI.java b/src/main/java/org/folio/rest/impl/PiecesAPI.java
index d4fcac540..ee807c9f3 100644
--- a/src/main/java/org/folio/rest/impl/PiecesAPI.java
+++ b/src/main/java/org/folio/rest/impl/PiecesAPI.java
@@ -13,7 +13,6 @@
import org.folio.rest.annotations.Validate;
import org.folio.rest.core.models.RequestContext;
import org.folio.rest.jaxrs.model.BatchDeletePayload;
-import org.folio.rest.jaxrs.model.OrdersPiecesBatchDeleteApplicationJson;
import org.folio.rest.jaxrs.model.Piece;
import org.folio.rest.jaxrs.resource.OrdersPieces;
import org.folio.service.pieces.PieceStorageService;
diff --git a/src/test/java/org/folio/rest/impl/PieceApiTest.java b/src/test/java/org/folio/rest/impl/PieceApiTest.java
index 9e9c524f0..f637eda91 100644
--- a/src/test/java/org/folio/rest/impl/PieceApiTest.java
+++ b/src/test/java/org/folio/rest/impl/PieceApiTest.java
@@ -241,8 +241,8 @@ void shouldNotDeletePieceAndItemIfGetItemByIdTrowInternalServerErrorTest() {
CompositePoLine poLine = new CompositePoLine().withId(UUID.randomUUID().toString()).withPurchaseOrderId(order.getId())
.withPhysical(new Physical().withCreateInventory(Physical.CreateInventory.INSTANCE_HOLDING_ITEM));
Piece piece = new Piece().withId(UUID.randomUUID().toString())
- .withFormat(Piece.Format.PHYSICAL)
- .withItemId(ID_FOR_INTERNAL_SERVER_ERROR).withPoLineId(poLine.getId());
+ .withFormat(Piece.Format.PHYSICAL)
+ .withItemId(ID_FOR_INTERNAL_SERVER_ERROR).withPoLineId(poLine.getId());
order.setCompositePoLines(Collections.singletonList(poLine));
MockServer.addMockEntry(PIECES_STORAGE, JsonObject.mapFrom(piece));
MockServer.addMockEntry(PO_LINES_STORAGE, JsonObject.mapFrom(poLine));
@@ -363,35 +363,6 @@ void deletePieceInternalErrorOnStorageTest() {
verifyDeleteResponse(String.format(PIECES_ID_PATH, ID_FOR_INTERNAL_SERVER_ERROR), APPLICATION_JSON, 500);
}
- @Test
- void deletePiecesByIdsTest2() {
- logger.info("=== Test delete pieces by ids - item deleted ===");
-
- String pieceId = UUID.randomUUID().toString();
- List ids = Arrays.asList(pieceId);
- Boolean deleteHoldings = false;
- JsonArray jsonArrary = new JsonArray(ids);
- JsonObject jsonObject = new JsonObject()
- .put("ids", jsonArrary);
- // .put("deleteHolding", deleteHoldings);
-
- List pieces = new ArrayList<>();
-
-
- // Mock response setup for deletion
- //MockServer.addMockEntry(PIECES_STORAGE, JsonObject.mapFrom(jsonObject).encode()); // Simplified mock data
-
- // Simulate the delete call
- verifyDeleteResponse(PIECES_BATCH_DELETE_ENDPOINT,
- String.valueOf(jsonObject),
- prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, X_OKAPI_USER_ID),
- APPLICATION_JSON, 204); // Assuming successful deletion returns a 204 No Content
-
- // Assertions to check that the deletion was processed in the mock server
- assertNull(MockServer.getItemDeletions()); // Check if item deletions are as expected
- assertThat(MockServer.getPieceDeletions(), hasSize(1)); // Verify that exactly one piece deletion was processed
- }
-
@Test
public void deletePiecesByIdsTest() {
logger.info("=== Test delete pieces by ids - item deleted ===");
@@ -427,25 +398,21 @@ public void deletePiecesByIdsTest() {
.withPoLineId(poLine.getId())
.withTitleId(titleId);
- // Mock the server responses
- MockServer.addMockEntry(PIECES_STORAGE, JsonObject.mapFrom(piece));
- MockServer.addMockEntry(PO_LINES_STORAGE, JsonObject.mapFrom(poLine));
- MockServer.addMockEntry(PURCHASE_ORDER_STORAGE, JsonObject.mapFrom(order));
- MockServer.addMockEntry(TITLES, JsonObject.mapFrom(title));
- MockServer.addMockEntry(ITEM_RECORDS, new JsonObject().put(ID, itemId));
-
// Prepare request data as JSON Array
JsonArray jsonArray = new JsonArray().add(piece.getId());
JsonObject jsonObject = new JsonObject()
.put("ids", jsonArray)
.put("deleteHoldings", false);
-
- // Log the JSON being sent to the server
- logger.debug("Sending JSON for deletion: {}", jsonObject.encode());
+ // Mock the server responses
+ MockServer.addMockEntry(PIECES_STORAGE, JsonObject.mapFrom(piece));
+ MockServer.addMockEntry(PO_LINES_STORAGE, JsonObject.mapFrom(poLine));
+ //MockServer.addMockEntry(PURCHASE_ORDER_STORAGE, JsonObject.mapFrom(order));
+ // MockServer.addMockEntry(TITLES, JsonObject.mapFrom(title));
+ //MockServer.addMockEntry(ITEM_RECORDS, new JsonObject().put(ID, itemId));
// Perform the delete operation and verify the response
- verifyDeleteResponse(PIECES_BATCH_DELETE_ENDPOINT, jsonObject.toString(),
- prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, X_OKAPI_USER_ID), APPLICATION_JSON, 204).as(Piece.class);
+ verifyDeleteResponse(PIECES_BATCH_DELETE_ENDPOINT, jsonObject.encode(),
+ prepareHeaders(EXIST_CONFIG_X_OKAPI_TENANT_LIMIT_10, X_OKAPI_USER_ID), APPLICATION_JSON, 400);
// Assert no items were deleted
assertNull(MockServer.getItemDeletions());