Skip to content

Commit e9a95a5

Browse files
[MODORDERS-1120] - Support populating searchLocationId for correct tenant during order opening (#957)
[MODORDERS-1120] - Support populating searchLocationId for correct tenant during order opening
1 parent fedc3a9 commit e9a95a5

File tree

11 files changed

+316
-152
lines changed

11 files changed

+316
-152
lines changed

ramls/acq-models

src/main/java/org/folio/helper/PurchaseOrderLineHelper.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import static org.folio.helper.BaseHelper.EVENT_PAYLOAD;
88
import static org.folio.helper.BaseHelper.ORDER_ID;
99
import static org.folio.orders.utils.HelperUtils.calculateEstimatedPrice;
10-
import static org.folio.orders.utils.HelperUtils.convertToPoLine;
1110
import static org.folio.orders.utils.HelperUtils.getPoLineLimit;
1211
import static org.folio.orders.utils.PoLineCommonUtil.verifyProtectedFieldsChanged;
1312
import static org.folio.orders.utils.ProtectedOperationType.DELETE;
@@ -224,7 +223,7 @@ public Future<CompositePoLine> createPoLineWithOrder(CompositePoLine compPoLine,
224223
return GenericCompositeFuture.join(new ArrayList<>(subObjFuts))
225224
.compose(v -> generateLineNumber(compOrder, requestContext))
226225
.map(lineNumber -> line.put(PO_LINE_NUMBER, lineNumber))
227-
.compose(v -> updateSearchLocations(compPoLine, requestContext))
226+
.compose(v -> purchaseOrderLineService.updateSearchLocations(compPoLine, requestContext))
228227
.map(v -> line.put(SEARCH_LOCATION_IDS, compPoLine.getSearchLocationIds()))
229228
.compose(v -> createPoLineSummary(compPoLine, line, requestContext));
230229
}
@@ -355,7 +354,7 @@ private boolean isUnreleasedEncumbrances(CompositePoLine compOrderLine, PoLine p
355354
public Future<Void> updateOrderLine(CompositePoLine compOrderLine, JsonObject lineFromStorage, RequestContext requestContext) {
356355
Promise<Void> promise = Promise.promise();
357356

358-
updateSearchLocations(compOrderLine, requestContext)
357+
purchaseOrderLineService.updateSearchLocations(compOrderLine, requestContext)
359358
.compose(v -> purchaseOrderLineService.updatePoLineSubObjects(compOrderLine, lineFromStorage, requestContext))
360359
.compose(poLine -> purchaseOrderLineService.updateOrderLineSummary(compOrderLine.getId(), poLine, requestContext))
361360
.onSuccess(json -> promise.complete())
@@ -549,12 +548,6 @@ private List<Future<?>> processPoLinesUpdate(CompositePurchaseOrder compOrder, L
549548
return futures;
550549
}
551550

552-
private Future<Void> updateSearchLocations(CompositePoLine compositePoLine, RequestContext requestContext) {
553-
return purchaseOrderLineService.retrieveSearchLocationIds(convertToPoLine(compositePoLine), requestContext)
554-
.map(compositePoLine::withSearchLocationIds)
555-
.mapEmpty();
556-
}
557-
558551
private List<Future<CompositePoLine>> processPoLinesCreation(CompositePurchaseOrder compOrder, List<PoLine> poLinesFromStorage,
559552
RequestContext requestContext) {
560553
return getNewPoLines(compOrder, poLinesFromStorage)

src/main/java/org/folio/orders/utils/HelperUtils.java

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,14 @@
11
package org.folio.orders.utils;
22

3-
import static io.vertx.core.Future.succeededFuture;
4-
import static java.util.stream.Collectors.toList;
5-
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
6-
import static org.apache.commons.lang3.StringUtils.EMPTY;
7-
import static org.apache.commons.lang3.StringUtils.isEmpty;
8-
import static org.folio.orders.utils.ResourcePathResolver.ALERTS;
9-
import static org.folio.orders.utils.ResourcePathResolver.REPORTING_CODES;
10-
import static org.folio.rest.RestConstants.EN;
11-
import static org.folio.rest.core.exceptions.ErrorCodes.MULTIPLE_NONPACKAGE_TITLES;
12-
import static org.folio.rest.core.exceptions.ErrorCodes.TITLE_NOT_FOUND;
13-
import static org.folio.rest.jaxrs.model.PoLine.PaymentStatus.FULLY_PAID;
14-
import static org.folio.rest.jaxrs.model.PoLine.PaymentStatus.PAYMENT_NOT_REQUIRED;
15-
import static org.folio.rest.jaxrs.model.PoLine.ReceiptStatus.FULLY_RECEIVED;
16-
import static org.folio.rest.jaxrs.model.PoLine.ReceiptStatus.RECEIPT_NOT_REQUIRED;
17-
import static org.folio.service.exchange.ExchangeRateProviderResolver.RATE_KEY;
18-
19-
import java.net.URLEncoder;
20-
import java.nio.charset.StandardCharsets;
21-
import java.util.ArrayList;
22-
import java.util.Collection;
23-
import java.util.Collections;
24-
import java.util.EnumMap;
25-
import java.util.List;
26-
import java.util.Map;
27-
import java.util.Objects;
28-
import java.util.Optional;
29-
import java.util.concurrent.CompletionException;
30-
import java.util.regex.Matcher;
31-
import java.util.regex.Pattern;
32-
33-
import javax.money.CurrencyUnit;
34-
import javax.money.Monetary;
35-
import javax.money.MonetaryAmount;
36-
import javax.money.convert.ConversionQuery;
37-
import javax.money.convert.ConversionQueryBuilder;
38-
3+
import io.vertx.core.AsyncResult;
4+
import io.vertx.core.CompositeFuture;
5+
import io.vertx.core.Future;
6+
import io.vertx.core.Handler;
7+
import io.vertx.core.eventbus.DeliveryOptions;
8+
import io.vertx.core.eventbus.Message;
9+
import io.vertx.core.json.JsonObject;
10+
import one.util.streamex.IntStreamEx;
11+
import one.util.streamex.StreamEx;
3912
import org.apache.commons.collections4.CollectionUtils;
4013
import org.apache.commons.collections4.map.CaseInsensitiveMap;
4114
import org.apache.commons.lang3.ArrayUtils;
@@ -65,15 +38,40 @@
6538
import org.javamoney.moneta.function.MonetaryFunctions;
6639
import org.javamoney.moneta.function.MonetaryOperators;
6740

68-
import io.vertx.core.AsyncResult;
69-
import io.vertx.core.CompositeFuture;
70-
import io.vertx.core.Future;
71-
import io.vertx.core.Handler;
72-
import io.vertx.core.eventbus.DeliveryOptions;
73-
import io.vertx.core.eventbus.Message;
74-
import io.vertx.core.json.JsonObject;
75-
import one.util.streamex.IntStreamEx;
76-
import one.util.streamex.StreamEx;
41+
import javax.money.CurrencyUnit;
42+
import javax.money.Monetary;
43+
import javax.money.MonetaryAmount;
44+
import javax.money.convert.ConversionQuery;
45+
import javax.money.convert.ConversionQueryBuilder;
46+
import java.net.URLEncoder;
47+
import java.nio.charset.StandardCharsets;
48+
import java.util.ArrayList;
49+
import java.util.Collection;
50+
import java.util.Collections;
51+
import java.util.EnumMap;
52+
import java.util.List;
53+
import java.util.Map;
54+
import java.util.Objects;
55+
import java.util.Optional;
56+
import java.util.concurrent.CompletionException;
57+
import java.util.regex.Matcher;
58+
import java.util.regex.Pattern;
59+
60+
import static io.vertx.core.Future.succeededFuture;
61+
import static java.util.stream.Collectors.toList;
62+
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
63+
import static org.apache.commons.lang3.StringUtils.EMPTY;
64+
import static org.apache.commons.lang3.StringUtils.isEmpty;
65+
import static org.folio.orders.utils.ResourcePathResolver.ALERTS;
66+
import static org.folio.orders.utils.ResourcePathResolver.REPORTING_CODES;
67+
import static org.folio.rest.RestConstants.EN;
68+
import static org.folio.rest.core.exceptions.ErrorCodes.MULTIPLE_NONPACKAGE_TITLES;
69+
import static org.folio.rest.core.exceptions.ErrorCodes.TITLE_NOT_FOUND;
70+
import static org.folio.rest.jaxrs.model.PoLine.PaymentStatus.FULLY_PAID;
71+
import static org.folio.rest.jaxrs.model.PoLine.PaymentStatus.PAYMENT_NOT_REQUIRED;
72+
import static org.folio.rest.jaxrs.model.PoLine.ReceiptStatus.FULLY_RECEIVED;
73+
import static org.folio.rest.jaxrs.model.PoLine.ReceiptStatus.RECEIPT_NOT_REQUIRED;
74+
import static org.folio.service.exchange.ExchangeRateProviderResolver.RATE_KEY;
7775

7876
public class HelperUtils {
7977

@@ -189,7 +187,7 @@ public static int calculateInventoryItemsQuantity(CompositePoLine compPOL, List<
189187
/**
190188
* Calculates pieces quantity for list of locations and return map where piece format is a key and corresponding quantity of pieces as value.
191189
*
192-
* @param compPOL composite PO Line
190+
* @param compPOL composite PO Line
193191
* @param locations list of locations to calculate quantity for
194192
* @return quantity of pieces per piece format either required Inventory item for PO Line
195193
*/
@@ -231,7 +229,7 @@ public static Map<Piece.Format, Integer> calculatePiecesWithItemIdQuantity(Compo
231229
/**
232230
* Calculates pieces quantity for specified locations based on piece format.
233231
*
234-
* @param format piece format
232+
* @param format piece format
235233
* @param locations list of locations to calculate quantity for
236234
* @return quantity of items expected in the inventory for PO Line
237235
*/
@@ -244,6 +242,7 @@ public static int calculatePiecesQuantity(Piece.Format format, List<Location> lo
244242

245243
/**
246244
* Calculates total estimated price. See MODORDERS-180 for more details.
245+
*
247246
* @param cost PO Line's cost
248247
*/
249248
public static MonetaryAmount calculateEstimatedPrice(Cost cost) {
@@ -318,19 +317,34 @@ public static int getElectronicLocationsQuantity(List<Location> locations) {
318317
.sum();
319318
}
320319

320+
/**
321+
* Almost same as collectResultsOnSuccess with addition that each future itself returns a list and
322+
* this implementation combines all elements of all lists into the single list.
323+
* @param futures The list of futures to be combined
324+
* @return Single list containing all elements returned from all futures
325+
* @param <E> element type
326+
* @param <T> list type
327+
*/
328+
public static <E, T extends List<E>> Future<List<E>> combineResultListsOnSuccess(Collection<Future<T>> futures) {
329+
return collectResultsOnSuccess(futures)
330+
.map(lists -> lists.stream().flatMap(List::stream).toList());
331+
}
332+
321333
/**
322334
* Wait for all requests completion and collect all resulting objects. In case any failed, complete resulting future with the exception
335+
*
323336
* @param futures list of futures and each produces resulting object on completion
324-
* @param <T> resulting type
337+
* @param <T> resulting type
325338
* @return resulting objects
326339
*/
327-
public static <T> Future<List<T>> collectResultsOnSuccess(List<Future<T>> futures) {
340+
public static <T> Future<List<T>> collectResultsOnSuccess(Collection<Future<T>> futures) {
328341
return GenericCompositeFuture.join(new ArrayList<>(futures))
329342
.map(CompositeFuture::list);
330343
}
331344

332345
/**
333346
* Transform list of id's to CQL query using 'or' operation
347+
*
334348
* @param ids list of id's
335349
* @return String representing CQL query to get records by id's
336350
*/
@@ -344,8 +358,9 @@ public static String convertIdsToCqlQuery(Collection<String> ids) {
344358

345359
/**
346360
* Transform list of values for some property to CQL query using 'or' operation
347-
* @param values list of field values
348-
* @param fieldName the property name to search by
361+
*
362+
* @param values list of field values
363+
* @param fieldName the property name to search by
349364
* @param strictMatch indicates whether strict match mode (i.e. ==) should be used or not (i.e. =)
350365
* @return String representing CQL query to get records by some property values
351366
*/
@@ -365,6 +380,7 @@ public static int getPoLineLimit(JsonObject config) {
365380
/**
366381
* Convert {@link JsonObject} which actually represents org.folio.rest.acq.model.PurchaseOrder to {@link CompositePurchaseOrder}
367382
* These objects are the same except PurchaseOrder doesn't contain poLines field.
383+
*
368384
* @param poJson {@link JsonObject} representing org.folio.rest.acq.model.PurchaseOrder
369385
* @return {@link CompositePurchaseOrder}
370386
*/
@@ -450,23 +466,24 @@ public static boolean isProductIdsExist(CompositePoLine compPOL) {
450466
}
451467

452468
public static Void handleErrorResponse(Handler<AsyncResult<javax.ws.rs.core.Response>> asyncResultHandler, BaseHelper helper,
453-
Throwable t) {
469+
Throwable t) {
454470
asyncResultHandler.handle(succeededFuture(helper.buildErrorResponse(t)));
455471
return null;
456472
}
457473

458474
/**
459475
* Check the number of titles per po line.
476+
*
460477
* @param lineIdTitles Map po line id -> list of titles
461-
* @param poLineById Map po line id -> composite po line
478+
* @param poLineById Map po line id -> composite po line
462479
*/
463480
public static void verifyTitles(Map<String, List<Title>> lineIdTitles, Map<String, CompositePoLine> poLineById) {
464481
verifyAllTitlesExist(lineIdTitles, poLineById);
465482
verifyNonPackageLinesHaveSingleTitle(lineIdTitles, poLineById);
466483
}
467484

468485
private static void verifyNonPackageLinesHaveSingleTitle(Map<String, List<Title>> titles,
469-
Map<String, CompositePoLine> poLineById) {
486+
Map<String, CompositePoLine> poLineById) {
470487
if (titles.keySet().stream().anyMatch(lineId -> titles.get(lineId).size() > 1 && !poLineById.get(lineId).getIsPackage())) {
471488
throw new HttpException(400, MULTIPLE_NONPACKAGE_TITLES);
472489
}
@@ -508,6 +525,7 @@ public static ConversionQuery buildConversionQuery(PoLine poLine, String systemC
508525
/**
509526
* Accepts response with collection of the elements and tries to extract the first one.
510527
* In case the response is incorrect or empty, the {@link CompletionException} will be thrown
528+
*
511529
* @param response {@link JsonObject} representing service response which should contain array of objects
512530
* @param propertyName name of the property which holds array of objects
513531
* @return the first element of the array
@@ -517,7 +535,7 @@ public static JsonObject getFirstObjectFromResponse(JsonObject response, String
517535
.flatMap(items -> items.stream().findFirst())
518536
.map(JsonObject.class::cast)
519537
.orElseThrow(() -> new CompletionException(new NoInventoryRecordException(
520-
String.format("No records of '%s' can be found", propertyName))));
538+
String.format("No records of '%s' can be found", propertyName))));
521539
}
522540

523541
public static String extractId(JsonObject json) {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.folio.orders.utils;
2+
3+
import lombok.experimental.UtilityClass;
4+
5+
import java.util.ArrayList;
6+
import java.util.Collection;
7+
import java.util.HashMap;
8+
import java.util.List;
9+
import java.util.Map;
10+
import java.util.Set;
11+
import java.util.function.Function;
12+
import java.util.function.Predicate;
13+
import java.util.stream.Collectors;
14+
15+
/**
16+
* Utility class allowing to perform stream operations in a more convenient way
17+
*/
18+
@UtilityClass
19+
public class StreamUtils {
20+
21+
public static <T> T find(Collection<T> collection, Predicate<T> predicate) {
22+
for (T t : collection) {
23+
if (predicate.test(t)) {
24+
return t;
25+
}
26+
}
27+
return null;
28+
}
29+
30+
public static <T> List<T> filter(Collection<T> collection, Predicate<T> predicate) {
31+
return collection.stream().filter(predicate).toList();
32+
}
33+
34+
public static <K, V> List<V> map(Collection<K> collection, Function<K, V> mapper) {
35+
return collection.stream().map(mapper).toList();
36+
}
37+
38+
public static <K, V> Set<V> mapToSet(Collection<K> collection, Function<K, V> mapper) {
39+
return collection.stream().map(mapper).collect(Collectors.toSet());
40+
}
41+
42+
public static <T, K> Map<K, T> listToMap(Collection<T> collection, Function<T, K> toKey) {
43+
return listToMap(collection, toKey, Function.identity());
44+
}
45+
46+
public static <T, K, V> Map<K, V> listToMap(Collection<T> collection, Function<T, K> toKey, Function<T, V> toValue) {
47+
return collection.stream().collect(Collectors.toMap(toKey, toValue, (a, b) -> a));
48+
}
49+
50+
public static <T, K> Map<K, List<T>> groupBy(Collection<T> collection, Function<T, K> toKey) {
51+
return groupBy(collection, toKey, Function.identity());
52+
}
53+
54+
public static <T, K, V> Map<K, List<V>> groupBy(Collection<T> collection, Function<T, K> toKey, Function<T, V> toValue) {
55+
Map<K, List<V>> map = new HashMap<>();
56+
for (T t : collection) {
57+
K key = toKey.apply(t);
58+
List<V> sublist = map.computeIfAbsent(key, k -> new ArrayList<>());
59+
sublist.add(toValue.apply(t));
60+
}
61+
return map;
62+
}
63+
64+
}

0 commit comments

Comments
 (0)