Skip to content

Commit

Permalink
add extra composite purchase order param to use status for item (#998)
Browse files Browse the repository at this point in the history
* add extra composite purchase order param to use status for item

* [MODORDERS-1140-2]. Updating piece flow tests

* Fixed unit tests and making improvements

* Fixed unit tests and making improvements

* Minor improvements

---------

Co-authored-by: BKadirkhodjaev <[email protected]>
  • Loading branch information
azizbekxm and BKadirkhodjaev authored Aug 19, 2024
1 parent 2fe3c48 commit 4012cf6
Show file tree
Hide file tree
Showing 23 changed files with 300 additions and 202 deletions.
8 changes: 6 additions & 2 deletions src/main/java/org/folio/helper/CheckinHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.apache.commons.lang3.tuple.Pair;
import org.folio.models.pieces.PiecesHolder;
import org.folio.orders.events.handlers.MessageAddress;
import org.folio.orders.utils.HelperUtils;
import org.folio.orders.utils.PoLineCommonUtil;
import org.folio.rest.core.models.RequestContext;
import org.folio.rest.jaxrs.model.CheckInPiece;
Expand Down Expand Up @@ -95,8 +96,11 @@ private Future<Map<String, List<Piece>>> createItemsWithPieceUpdate(CheckinColle
if (checkInPiece.getId().equals(piece.getId()) && Boolean.TRUE.equals(checkInPiece.getCreateItem())) {
pieceFutures.add(purchaseOrderLineService.getOrderLineById(poLineId, requestContext)
.map(PoLineCommonUtil::convertToCompositePoLine)
.compose(compPol -> pieceCreateFlowInventoryManager.processInventory(compPol, piece, checkInPiece.getCreateItem(), requestContext))
.map(voidResult -> new PiecesHolder.PiecePoLineDto(poLineId, piece)));
.compose(compPol -> purchaseOrderStorageService.getPurchaseOrderByIdAsJson(compPol.getPurchaseOrderId(), requestContext)
.map(HelperUtils::convertToCompositePurchaseOrder)
.compose(purchaseOrder -> pieceCreateFlowInventoryManager.processInventory(purchaseOrder, compPol, piece,
checkInPiece.getCreateItem(), requestContext))
.map(voidResult -> new PiecesHolder.PiecePoLineDto(poLineId, piece))));
} else if (checkInPiece.getId().equals(piece.getId()) && InventoryUtils.allowItemRecreate(srcTenantId, dstTenantId) && Objects.nonNull(piece.getItemId())) {
pieceFutures.add(purchaseOrderLineService.getOrderLineById(poLineId, requestContext)
.map(PoLineCommonUtil::convertToCompositePoLine)
Expand Down
69 changes: 49 additions & 20 deletions src/main/java/org/folio/helper/CheckinReceivePiecesHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.folio.rest.core.RestClient;
import org.folio.rest.core.models.RequestContext;
import org.folio.rest.jaxrs.model.CompositePoLine;
import org.folio.rest.jaxrs.model.CompositePurchaseOrder;
import org.folio.rest.jaxrs.model.Eresource;
import org.folio.rest.jaxrs.model.Error;
import org.folio.rest.jaxrs.model.Location;
Expand All @@ -40,6 +41,7 @@
import org.folio.service.inventory.InventoryItemManager;
import org.folio.service.inventory.InventoryUtils;
import org.folio.service.orders.PurchaseOrderLineService;
import org.folio.service.orders.PurchaseOrderStorageService;
import org.folio.service.pieces.ItemRecreateInventoryService;
import org.folio.service.pieces.PieceStorageService;
import org.folio.service.pieces.flows.create.PieceCreateFlowInventoryManager;
Expand Down Expand Up @@ -121,6 +123,9 @@ public abstract class CheckinReceivePiecesHelper<T> extends BaseHelper {
protected PieceUpdateFlowPoLineService pieceUpdateFlowPoLineService;
@Autowired
private ItemRecreateInventoryService itemRecreateInventoryService;
@Autowired
protected PurchaseOrderStorageService purchaseOrderStorageService;

private final RestClient restClient;

private List<PoLine> poLineList;
Expand Down Expand Up @@ -501,26 +506,50 @@ protected Future<Void> recreateItemRecords(Map<String, List<Piece>> piecesGroupe
if (Objects.isNull(holder.getItemsToRecreate()) || holder.getItemsToRecreate().isEmpty()) {
return Future.succeededFuture();
}
var futures = new ArrayList<Future<String>>();
piecesGroupedByPoLine.keySet().stream()
.map(poLineId -> holder.getItemsToRecreate().get(poLineId))
.forEach(itemToRecreateList ->
itemToRecreateList.forEach(itemToRecreate -> {
var piece = itemToRecreate.getPieceFromStorage();
var checkInPiece = itemToRecreate.getCheckInPiece();
var srcConfig = InventoryUtils.constructItemRecreateConfig(piece.getReceivingTenantId(), requestContext, true);
var dstConfig = InventoryUtils.constructItemRecreateConfig(checkInPiece.getReceivingTenantId(), requestContext, false);
if (InventoryUtils.allowItemRecreate(srcConfig.tenantId(), dstConfig.tenantId())) {
logger.info("recreateItemRecords:: recreating item by id '{}', srcTenantId: '{}', dstTenantId: '{}'", piece.getItemId(), srcConfig.tenantId(), dstConfig.tenantId());
futures.add(itemRecreateInventoryService.recreateItemInDestinationTenant(itemToRecreate.getCompositePoLine(), piece, srcConfig.context(), dstConfig.context()));
}
}));
return collectResultsOnSuccess(futures)
.map(itemIdsRecreated -> {
itemIdsRecreated.forEach(itemIdRecreated -> logger.info("recreateItemRecords:: recreated item by id '{}'", itemIdRecreated));
return null;
})
.compose(v -> Future.succeededFuture());

Map<String, Future<CompositePurchaseOrder>> purchaseOrderFutures = piecesGroupedByPoLine.keySet().stream()
.collect(Collectors.toMap(
poLineId -> poLineId,
poLineId -> purchaseOrderStorageService.getCompositeOrderByPoLineId(poLineId, requestContext)
.recover(throwable -> {
logger.warn("recreateItemRecords:: Composite Purchase order can't be found for poLine: {}", poLineId);
return Future.succeededFuture(null);
})
));

return GenericCompositeFuture.join(new ArrayList<>(purchaseOrderFutures.values())).compose(purchaseOrdersFuture -> {
Map<String, CompositePurchaseOrder> purchaseOrderMap = purchaseOrderFutures.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().result()
));

List<Future<String>> futures = new ArrayList<>();
piecesGroupedByPoLine.keySet().stream()
.map(poLineId -> holder.getItemsToRecreate().get(poLineId))
.forEach(itemToRecreateList ->
itemToRecreateList.forEach(itemToRecreate -> {
var piece = itemToRecreate.getPieceFromStorage();
var checkInPiece = itemToRecreate.getCheckInPiece();
var srcConfig = InventoryUtils.constructItemRecreateConfig(piece.getReceivingTenantId(), requestContext, true);
var dstConfig = InventoryUtils.constructItemRecreateConfig(checkInPiece.getReceivingTenantId(), requestContext, false);
if (InventoryUtils.allowItemRecreate(srcConfig.tenantId(), dstConfig.tenantId())) {
logger.info("recreateItemRecords:: recreating item by id '{}', srcTenantId: '{}', dstTenantId: '{}'", piece.getItemId(), srcConfig.tenantId(), dstConfig.tenantId());
var compPO = purchaseOrderMap.get(itemToRecreate.getPoLineId());
var itemIdFuture = itemRecreateInventoryService.recreateItemInDestinationTenant(compPO, itemToRecreate.getCompositePoLine(),
piece, srcConfig.context(), dstConfig.context());
futures.add(itemIdFuture);
}
}));

return collectResultsOnSuccess(futures)
.map(itemIdsRecreated -> {
itemIdsRecreated.forEach(itemIdRecreated ->
logger.info("recreateItemRecords:: recreated item by id '{}'", itemIdRecreated));
return null;
})
.compose(v -> Future.succeededFuture());
});
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/folio/orders/utils/PoLineCommonUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -290,4 +290,5 @@ private static void checkFieldsChanged(JsonPathParser oldObject, JsonPathParser
throw new HttpException(400, error, parameters);
}
}

}
60 changes: 30 additions & 30 deletions src/main/java/org/folio/service/inventory/InventoryItemManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
import org.folio.rest.core.models.RequestEntry;
import org.folio.rest.jaxrs.model.BindItem;
import org.folio.rest.jaxrs.model.CompositePoLine;
import org.folio.rest.jaxrs.model.CompositePurchaseOrder;
import org.folio.rest.jaxrs.model.Location;
import org.folio.rest.jaxrs.model.Parameter;
import org.folio.rest.jaxrs.model.Piece;
import org.folio.rest.jaxrs.model.PurchaseOrder;
import org.folio.rest.jaxrs.model.ReceivedItem;
import org.folio.service.caches.ConfigurationEntriesCache;
import org.folio.service.caches.InventoryCache;
Expand Down Expand Up @@ -175,7 +175,8 @@ public Future<List<Void>> deleteItems(List<String> itemIds, boolean skipNotFound
* @param location list of location holdingId is associated with
* @return future with list of piece objects
*/
public Future<List<Piece>> handleItemRecords(CompositePoLine compPOL, Location location, RequestContext requestContext) {
public Future<List<Piece>> handleItemRecords(CompositePurchaseOrder comPO, CompositePoLine compPOL,
Location location, RequestContext requestContext) {
Map<Piece.Format, Integer> piecesWithItemsQuantities = HelperUtils.calculatePiecesWithItemIdQuantity(compPOL, List.of(location));
int piecesWithItemsQty = IntStreamEx.of(piecesWithItemsQuantities.values()).sum();
String polId = compPOL.getId();
Expand Down Expand Up @@ -205,11 +206,13 @@ public Future<List<Piece>> handleItemRecords(CompositePoLine compPOL, Location l
List<String> existingItemIds;
if (pieceFormat == Piece.Format.ELECTRONIC) {
existingItemIds = getElectronicItemIds(compPOL, existingItems);
return createMissingElectronicItems(compPOL, pieceWithHoldingId, expectedQuantity - existingItemIds.size(), updatedRequestContext)
return createMissingElectronicItems(comPO, compPOL, pieceWithHoldingId,
expectedQuantity - existingItemIds.size(), updatedRequestContext)
.map(createdItemIds -> buildPieces(location, polId, pieceFormat, createdItemIds, existingItemIds));
} else {
existingItemIds = getPhysicalItemIds(compPOL, existingItems);
return createMissingPhysicalItems(compPOL, pieceWithHoldingId, expectedQuantity - existingItemIds.size(), updatedRequestContext)
return createMissingPhysicalItems(comPO, compPOL, pieceWithHoldingId,
expectedQuantity - existingItemIds.size(), updatedRequestContext)
.map(createdItemIds -> buildPieces(location, polId, pieceFormat, createdItemIds, existingItemIds));
}
});
Expand Down Expand Up @@ -306,18 +309,19 @@ public Future<List<JsonObject>> getItemsByHoldingId(String holdingId, RequestCon
});
}

public Future<String> openOrderCreateItemRecord(CompositePoLine compPOL, String holdingId, RequestContext requestContext) {
public Future<String> openOrderCreateItemRecord(CompositePurchaseOrder compPO, CompositePoLine compPOL,
String holdingId, RequestContext requestContext) {
final int ITEM_QUANTITY = 1;
logger.debug("Handling {} items for PO Line and holdings with id={}", ITEM_QUANTITY, holdingId);
Promise<String> itemFuture = Promise.promise();
try {
Piece pieceWithHoldingId = new Piece().withHoldingId(holdingId);
if (compPOL.getOrderFormat() == ELECTRONIC_RESOURCE) {
createMissingElectronicItems(compPOL, pieceWithHoldingId, ITEM_QUANTITY, requestContext)
createMissingElectronicItems(compPO, compPOL, pieceWithHoldingId, ITEM_QUANTITY, requestContext)
.onSuccess(idS -> itemFuture.complete(idS.get(0)))
.onFailure(itemFuture::fail);
} else {
createMissingPhysicalItems(compPOL, pieceWithHoldingId, ITEM_QUANTITY, requestContext)
createMissingPhysicalItems(compPO, compPOL, pieceWithHoldingId, ITEM_QUANTITY, requestContext)
.onSuccess(idS -> itemFuture.complete(idS.get(0)))
.onFailure(itemFuture::fail);
}
Expand All @@ -336,12 +340,13 @@ public Future<String> openOrderCreateItemRecord(CompositePoLine compPOL, String
* @param quantity expected number of items to create
* @return id of newly created Instance Record
*/
public Future<List<String>> createMissingElectronicItems(CompositePoLine compPOL, Piece piece, int quantity, RequestContext requestContext) {
public Future<List<String>> createMissingElectronicItems(CompositePurchaseOrder compPO, CompositePoLine compPOL,
Piece piece, int quantity, RequestContext requestContext) {
if (quantity <= 0) {
return Future.succeededFuture(List.of());
}
String holdingId = piece.getHoldingId();
return buildElectronicItemRecordJsonObject(compPOL, holdingId, requestContext)
return buildElectronicItemRecordJsonObject(compPO, compPOL, holdingId, requestContext)
.compose(item -> {
InventoryUtils.updateItemWithPieceFields(item, piece);
item.put(ID, piece.getItemId());
Expand All @@ -350,8 +355,9 @@ public Future<List<String>> createMissingElectronicItems(CompositePoLine compPOL
});
}

private Future<JsonObject> buildElectronicItemRecordJsonObject(CompositePoLine compPOL, String holdingId, RequestContext requestContext) {
return buildBaseItemRecordJsonObject(compPOL, holdingId, requestContext)
private Future<JsonObject> buildElectronicItemRecordJsonObject(CompositePurchaseOrder compPO, CompositePoLine compPOL,
String holdingId, RequestContext requestContext) {
return buildBaseItemRecordJsonObject(compPO, compPOL, holdingId, requestContext)
.map(itemRecord -> itemRecord.put(ITEM_MATERIAL_TYPE_ID, compPOL.getEresource().getMaterialType()));
}

Expand All @@ -364,13 +370,14 @@ private Future<JsonObject> buildElectronicItemRecordJsonObject(CompositePoLine c
* @param quantity expected number of items to create
* @return id of newly created Instance Record
*/
public Future<List<String>> createMissingPhysicalItems(CompositePoLine compPOL, Piece piece, int quantity,
public Future<List<String>> createMissingPhysicalItems(CompositePurchaseOrder compPO, CompositePoLine compPOL,
Piece piece, int quantity,
RequestContext requestContext) {
if (quantity <= 0) {
return Future.succeededFuture(List.of());
}
String holdingId = piece.getHoldingId();
return buildPhysicalItemRecordJsonObject(compPOL, holdingId, requestContext)
return buildPhysicalItemRecordJsonObject(compPO, compPOL, holdingId, requestContext)
.compose(item -> {
InventoryUtils.updateItemWithPieceFields(item, piece);
item.put(ID, piece.getItemId());
Expand All @@ -379,33 +386,26 @@ public Future<List<String>> createMissingPhysicalItems(CompositePoLine compPOL,
});
}

private Future<JsonObject> buildPhysicalItemRecordJsonObject(CompositePoLine compPOL, String holdingId, RequestContext requestContext) {
return buildBaseItemRecordJsonObject(compPOL, holdingId, requestContext)
private Future<JsonObject> buildPhysicalItemRecordJsonObject(CompositePurchaseOrder compPO, CompositePoLine compPOL,
String holdingId, RequestContext requestContext) {
return buildBaseItemRecordJsonObject(compPO, compPOL, holdingId, requestContext)
.map(itemRecord -> itemRecord.put(ITEM_MATERIAL_TYPE_ID, compPOL.getPhysical().getMaterialType()));
}

private Future<JsonObject> buildBaseItemRecordJsonObject(CompositePoLine compPOL, String holdingId, RequestContext requestContext) {
private Future<JsonObject> buildBaseItemRecordJsonObject(CompositePurchaseOrder compPO, CompositePoLine compPOL,
String holdingId, RequestContext requestContext) {
String itemStatus = compPO.getWorkflowStatus().equals(CompositePurchaseOrder.WorkflowStatus.CLOSED)
? ReceivedItem.ItemStatus.ORDER_CLOSED.value()
: ReceivedItem.ItemStatus.ON_ORDER.value();
return InventoryUtils.getLoanTypeId(configurationEntriesCache, inventoryCache, requestContext)
.map(loanTypeId -> {
JsonObject itemRecord = new JsonObject();
itemRecord.put(ITEM_HOLDINGS_RECORD_ID, holdingId);
itemRecord.put(ITEM_PERMANENT_LOAN_TYPE_ID, loanTypeId);
itemRecord.put(ITEM_PURCHASE_ORDER_LINE_IDENTIFIER, compPOL.getId());
itemRecord.put(ITEM_STATUS, new JsonObject().put(ITEM_STATUS_NAME, itemStatus));
return itemRecord;
})
.compose(itemRecord -> setItemStatus(compPOL, itemRecord, requestContext));
}

private Future<JsonObject> setItemStatus(CompositePoLine compPOL, JsonObject itemRecord, RequestContext requestContext) {
return purchaseOrderStorageService.getPurchaseOrderById(compPOL.getPurchaseOrderId(), requestContext)
.map(compPO -> {
String itemStatus = compPO.getWorkflowStatus().equals(PurchaseOrder.WorkflowStatus.CLOSED)
? ReceivedItem.ItemStatus.ORDER_CLOSED.value()
: ReceivedItem.ItemStatus.ON_ORDER.value();
itemRecord.put(ITEM_STATUS, new JsonObject().put(ITEM_STATUS_NAME, itemStatus));
return itemRecord;
}
);
});
}

public Future<String> createBindItem(CompositePoLine compPOL, String holdingId, BindItem bindItem, RequestContext locationContext) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public Future<Void> processInventory(Map<String, List<Title>> lineIdsTitles, Com
List<Future<Void>> futures = new ArrayList<>();
for (CompositePoLine poLine : compPO.getCompositePoLines()) {
semaphore.acquire(() -> {
Future<Void> future = processInventory(poLine, getFirstTitleIdIfExist(lineIdsTitles, poLine), isInstanceMatchingDisabled, requestContext)
Future<Void> future = processInventory(compPO, poLine, getFirstTitleIdIfExist(lineIdsTitles, poLine), isInstanceMatchingDisabled, requestContext)
.onComplete(asyncResult -> semaphore.release());
futures.add(future);
if (futures.size() == compPO.getCompositePoLines().size()) {
Expand All @@ -72,14 +72,12 @@ public Future<Void> processInventory(Map<String, List<Title>> lineIdsTitles, Com
.mapEmpty());
}

public Future<Void> processInventory(CompositePoLine compPOL, String titleId, boolean isInstanceMatchingDisabled,
RequestContext requestContext) {

if (logger.isDebugEnabled()) {
logger.debug("Executing a strategy for: {}", compPOL.getOrderFormat().value());
}
return processInventoryStrategyResolver.getHoldingAndItemStrategy(compPOL.getOrderFormat().value())
.processInventory(compPOL, titleId, isInstanceMatchingDisabled,
public Future<Void> processInventory(CompositePurchaseOrder compPO, CompositePoLine compPOL, String titleId,
boolean isInstanceMatchingDisabled, RequestContext requestContext) {
logger.debug("processInventory:: Executing a strategy for: {}", compPOL.getOrderFormat().value());
return processInventoryStrategyResolver
.getHoldingAndItemStrategy(compPOL.getOrderFormat().value())
.processInventory(compPO, compPOL, titleId, isInstanceMatchingDisabled,
inventoryItemManager, inventoryHoldingManager, inventoryInstanceManager, openCompositeOrderPieceService, restClient, requestContext);
}

Expand Down
Loading

0 comments on commit 4012cf6

Please sign in to comment.