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-1143] Paying an invoice reopens the order #1025

Merged
merged 12 commits into from
Sep 23, 2024
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ private PoLine updateRelatedPoLineDetails(PoLine poLine,
updatedLocations++;
}

return updatedLocations > 0 ? HelperUtils.convertToPoLine(compositePoLine) : poLine;
return updatedLocations > 0 ? PoLineCommonUtil.convertToPoLine(compositePoLine) : poLine;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/folio/helper/PurchaseOrderHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import static org.folio.orders.utils.HelperUtils.ORDER_CONFIG_MODULE_NAME;
import static org.folio.orders.utils.HelperUtils.REASON_CANCELLED;
import static org.folio.orders.utils.HelperUtils.WORKFLOW_STATUS;
import static org.folio.orders.utils.HelperUtils.changeOrderStatus;
import static org.folio.orders.utils.HelperUtils.collectResultsOnSuccess;
import static org.folio.orders.utils.HelperUtils.convertToCompositePurchaseOrder;
import static org.folio.orders.utils.OrderStatusTransitionUtil.isOrderClosing;
Expand All @@ -24,6 +23,7 @@
import static org.folio.rest.jaxrs.model.CompositePurchaseOrder.WorkflowStatus.OPEN;
import static org.folio.rest.jaxrs.model.CompositePurchaseOrder.WorkflowStatus.PENDING;
import static org.folio.service.UserService.getCurrentUserId;
import static org.folio.service.orders.utils.StatusUtils.changeOrderStatus;

import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -282,7 +282,7 @@ public Future<Void> handleFinalOrderStatus(CompositePurchaseOrder compPO, String
} else {
Future.succeededFuture()
.map(v -> {
List<PoLine> poLines = HelperUtils.convertToPoLines(compPO.getCompositePoLines());
List<PoLine> poLines = PoLineCommonUtil.convertToPoLines(compPO.getCompositePoLines());
if (initialOrdersStatus.equals(compPO.getWorkflowStatus().value()))
changeOrderStatus(purchaseOrder, poLines);
promise.complete(poLines);
Expand Down
485 changes: 199 additions & 286 deletions src/main/java/org/folio/helper/PurchaseOrderLineHelper.java

Large diffs are not rendered by default.

11 changes: 5 additions & 6 deletions src/main/java/org/folio/models/PoLineInvoiceLineHolder.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@
import org.folio.rest.jaxrs.model.CompositePoLine;
import org.folio.rest.jaxrs.model.PoLine;

import io.vertx.core.json.JsonObject;


public class PoLineInvoiceLineHolder {
private CompositePoLine poLineFromRequest;
private PoLine poLineFromStorage;

private final CompositePoLine poLineFromRequest;
private final PoLine poLineFromStorage;
private List<InvoiceLine> invoiceLines;
private List<InvoiceLine> openOrReviewedInvoiceLines;

public PoLineInvoiceLineHolder(CompositePoLine poLineFromRequest, JsonObject poLineFromStorage) {
public PoLineInvoiceLineHolder(CompositePoLine poLineFromRequest, PoLine poLineFromStorage) {
this.poLineFromRequest = poLineFromRequest;
this.poLineFromStorage = poLineFromStorage.mapTo(PoLine.class);
this.poLineFromStorage = poLineFromStorage;
this.invoiceLines = new ArrayList<>();
this.openOrReviewedInvoiceLines = new ArrayList<>();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.folio.orders.events.handlers;

import static org.folio.orders.utils.HelperUtils.changeOrderStatus;
import static org.folio.orders.utils.HelperUtils.getOkapiHeaders;
import static org.folio.service.orders.utils.StatusUtils.changeOrderStatus;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -10,8 +10,8 @@
import org.folio.completablefuture.AsyncUtil;
import org.folio.helper.BaseHelper;
import org.folio.helper.PurchaseOrderHelper;
import org.folio.orders.utils.PoLineCommonUtil;
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.PoLine;
import org.folio.rest.jaxrs.model.PurchaseOrder;
Expand Down Expand Up @@ -108,7 +108,7 @@ protected JsonArray messageAsJsonArray(String rootElement, Message<JsonObject> m
}

protected CompositePurchaseOrder convert(PurchaseOrder po, List<PoLine> poLines) {
var lines = poLines.stream().map(line -> JsonObject.mapFrom(line).mapTo(CompositePoLine.class)).toList();
var lines = poLines.stream().map(JsonObject::mapFrom).map(PoLineCommonUtil::convertToCompositePoLine).toList();
return JsonObject.mapFrom(po).mapTo(CompositePurchaseOrder.class).withCompositePoLines(lines);
}

Expand Down
75 changes: 0 additions & 75 deletions src/main/java/org/folio/orders/utils/HelperUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@
import org.folio.rest.core.exceptions.NoInventoryRecordException;
import org.folio.rest.core.models.RequestContext;
import org.folio.rest.jaxrs.model.Alert;
import org.folio.rest.jaxrs.model.CloseReason;
import org.folio.rest.jaxrs.model.CompositePoLine;
import org.folio.rest.jaxrs.model.CompositePurchaseOrder;
import org.folio.rest.jaxrs.model.Cost;
import org.folio.rest.jaxrs.model.Location;
import org.folio.rest.jaxrs.model.Piece;
import org.folio.rest.jaxrs.model.PoLine;
import org.folio.rest.jaxrs.model.PoLine.PaymentStatus;
import org.folio.rest.jaxrs.model.PoLine.ReceiptStatus;
import org.folio.rest.jaxrs.model.PurchaseOrder;
import org.folio.rest.jaxrs.model.ReportingCode;
import org.folio.rest.jaxrs.model.Title;
Expand Down Expand Up @@ -67,10 +64,6 @@
import static org.folio.rest.RestConstants.EN;
import static org.folio.rest.core.exceptions.ErrorCodes.MULTIPLE_NONPACKAGE_TITLES;
import static org.folio.rest.core.exceptions.ErrorCodes.TITLE_NOT_FOUND;
import static org.folio.rest.jaxrs.model.PoLine.PaymentStatus.FULLY_PAID;
import static org.folio.rest.jaxrs.model.PoLine.PaymentStatus.PAYMENT_NOT_REQUIRED;
import static org.folio.rest.jaxrs.model.PoLine.ReceiptStatus.FULLY_RECEIVED;
import static org.folio.rest.jaxrs.model.PoLine.ReceiptStatus.RECEIPT_NOT_REQUIRED;

public class HelperUtils {

Expand Down Expand Up @@ -393,79 +386,11 @@ public static CompositePurchaseOrder convertToCompositePurchaseOrder(JsonObject
return poJson.mapTo(CompositePurchaseOrder.class);
}

public static boolean changeOrderStatus(PurchaseOrder purchaseOrder, List<PoLine> poLines) {
if (toBeCancelled(purchaseOrder, poLines)) {
purchaseOrder.setWorkflowStatus(PurchaseOrder.WorkflowStatus.CLOSED);
purchaseOrder.setCloseReason(new CloseReason().withReason(REASON_CANCELLED));
return true;
}

if (toBeClosed(purchaseOrder, poLines)) {
purchaseOrder.setWorkflowStatus(PurchaseOrder.WorkflowStatus.CLOSED);
purchaseOrder.setCloseReason(new CloseReason().withReason(REASON_COMPLETE));
return true;
}

if (toBeReopened(purchaseOrder, poLines)) {
purchaseOrder.setWorkflowStatus(PurchaseOrder.WorkflowStatus.OPEN);
return true;
}

return false;
}

public static String convertTagListToCqlQuery(Collection<String> values, String fieldName, boolean strictMatch) {

String prefix = fieldName + (strictMatch ? "==(\"" : "=(\"");
return StreamEx.of(values).joining("\" or \"", prefix, "\")");
}

private static boolean toBeClosed(PurchaseOrder purchaseOrder, List<PoLine> poLines) {
return purchaseOrder.getWorkflowStatus() == PurchaseOrder.WorkflowStatus.OPEN
&& poLines.stream().allMatch(HelperUtils::isCompletedPoLine);
}

private static boolean toBeCancelled(PurchaseOrder purchaseOrder, List<PoLine> poLines) {
return purchaseOrder.getWorkflowStatus() == PurchaseOrder.WorkflowStatus.OPEN
&& poLines.stream().allMatch(HelperUtils::isCancelledPoLine);
}

private static boolean isCancelledPoLine(PoLine line) {
PoLine.PaymentStatus paymentStatus = line.getPaymentStatus();
PoLine.ReceiptStatus receiptStatus = line.getReceiptStatus();
return paymentStatus == PaymentStatus.CANCELLED && receiptStatus == ReceiptStatus.CANCELLED;
}

private static boolean toBeReopened(PurchaseOrder purchaseOrder, List<PoLine> poLines) {
return purchaseOrder.getWorkflowStatus() == PurchaseOrder.WorkflowStatus.CLOSED
&& poLines.stream().anyMatch(line -> !isCompletedPoLine(line));
}

private static boolean isCompletedPoLine(PoLine line) {
PoLine.PaymentStatus paymentStatus = line.getPaymentStatus();
PoLine.ReceiptStatus receiptStatus = line.getReceiptStatus();
return (paymentStatus == PAYMENT_NOT_REQUIRED || paymentStatus == FULLY_PAID || paymentStatus == PaymentStatus.CANCELLED)
&& (receiptStatus == FULLY_RECEIVED || receiptStatus == RECEIPT_NOT_REQUIRED || receiptStatus == ReceiptStatus.CANCELLED);
}

public static PoLine convertToPoLine(CompositePoLine compPoLine) {
JsonObject pol = JsonObject.mapFrom(compPoLine);
pol.remove(ALERTS);
pol.remove(REPORTING_CODES);
PoLine poLine = pol.mapTo(PoLine.class);
poLine.setAlerts(compPoLine.getAlerts().stream().map(Alert::getId).collect(toList()));
poLine.setReportingCodes(compPoLine.getReportingCodes().stream().map(ReportingCode::getId).collect(toList()));
return poLine;
}


public static List<PoLine> convertToPoLines(List<CompositePoLine> compositePoLines) {
return compositePoLines
.stream()
.map(HelperUtils::convertToPoLine)
.collect(toList());
}

public static boolean isProductIdsExist(CompositePoLine compPOL) {
return compPOL.getDetails() != null && CollectionUtils.isNotEmpty(compPOL.getDetails().getProductIds());
}
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/org/folio/orders/utils/PoLineCommonUtil.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.folio.orders.utils;

import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
import static org.folio.orders.utils.HelperUtils.calculateTotalLocationQuantity;
import static org.folio.orders.utils.ResourcePathResolver.ALERTS;
import static org.folio.orders.utils.ResourcePathResolver.REPORTING_CODES;
import static org.folio.rest.core.exceptions.ErrorCodes.PROHIBITED_FIELD_CHANGING;
import static org.folio.rest.core.exceptions.ErrorCodes.WRONG_ONGOING_NOT_SUBSCRIPTION_FIELDS_CHANGED;
import static org.folio.rest.core.exceptions.ErrorCodes.WRONG_ONGOING_SUBSCRIPTION_FIELDS_CHANGED;
Expand All @@ -27,6 +30,7 @@
import org.apache.commons.lang3.ObjectUtils;
import org.folio.rest.core.exceptions.HttpException;
import org.folio.rest.core.exceptions.ErrorCodes;
import org.folio.rest.jaxrs.model.Alert;
import org.folio.rest.jaxrs.model.CompositePoLine;
import org.folio.rest.jaxrs.model.CompositePurchaseOrder;
import org.folio.rest.jaxrs.model.Eresource;
Expand All @@ -35,6 +39,7 @@
import org.folio.rest.jaxrs.model.Parameter;
import org.folio.rest.jaxrs.model.Physical;
import org.folio.rest.jaxrs.model.PoLine;
import org.folio.rest.jaxrs.model.ReportingCode;
import org.folio.rest.tools.parser.JsonPathParser;

import io.vertx.core.json.JsonArray;
Expand Down Expand Up @@ -256,6 +261,29 @@ public static CompositePoLine convertToCompositePoLine(PoLine poLine) {
return jsonLine.mapTo(CompositePoLine.class);
}

public static CompositePoLine convertToCompositePoLine(JsonObject poLine) {
poLine.remove(ALERTS);
poLine.remove(REPORTING_CODES);
return poLine.mapTo(CompositePoLine.class);
}

public static PoLine convertToPoLine(CompositePoLine compPoLine) {
JsonObject pol = JsonObject.mapFrom(compPoLine);
pol.remove(ALERTS);
pol.remove(REPORTING_CODES);
PoLine poLine = pol.mapTo(PoLine.class);
poLine.setAlerts(compPoLine.getAlerts().stream().map(Alert::getId).collect(toList()));
poLine.setReportingCodes(compPoLine.getReportingCodes().stream().map(ReportingCode::getId).collect(toList()));
return poLine;
}

public static List<PoLine> convertToPoLines(List<CompositePoLine> compositePoLines) {
return compositePoLines
.stream()
.map(PoLineCommonUtil::convertToPoLine)
.collect(toList());
}

public static void updateLocationsQuantity(List<Location> locations) {
locations.forEach(location -> location.setQuantity(calculateTotalLocationQuantity(location)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import org.folio.rest.jaxrs.model.PoLine;

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

public class PoLineInvoiceLineHolderBuilder {
private static final List<InvoiceLine.InvoiceLineStatus> EDITABLE_STATUSES = List.of(InvoiceLine.InvoiceLineStatus.OPEN, InvoiceLine.InvoiceLineStatus.REVIEWED);
Expand All @@ -22,7 +21,7 @@ public PoLineInvoiceLineHolderBuilder(InvoiceLineService invoiceLineService) {
}

public Future<PoLineInvoiceLineHolder> buildHolder(CompositePoLine compOrderLine, PoLine poLineFromStorage, RequestContext requestContext) {
PoLineInvoiceLineHolder holder = new PoLineInvoiceLineHolder(compOrderLine, JsonObject.mapFrom(poLineFromStorage));
var holder = new PoLineInvoiceLineHolder(compOrderLine, poLineFromStorage);
return invoiceLineService.getInvoiceLinesByOrderLineId(compOrderLine.getId(), requestContext)
.onSuccess(holder::withInvoiceLines)
.compose(aResult -> CollectionUtils.isEmpty(holder.getInvoiceLines()) ? Future.succeededFuture(holder) :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ private Set<ProtectedOperationType> getInvolvedOperations(CompositePurchaseOrder
if (CollectionUtils.isEmpty(compPO.getCompositePoLines())) {
return Collections.singleton(UPDATE);
}
List<PoLine> poLines = HelperUtils.convertToPoLines(poFromStorage.getCompositePoLines());
List<PoLine> poLines = PoLineCommonUtil.convertToPoLines(poFromStorage.getCompositePoLines());
Set<String> newIds = compPO.getCompositePoLines().stream().map(CompositePoLine::getId).collect(Collectors.toSet());
Set<String> storageIds = poLines.stream().map(PoLine::getId).collect(Collectors.toSet());
Set<ProtectedOperationType> operations = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public Future<Void> saveOrderLine(CompositePoLine compositePoLine, RequestContex
}

public Future<Void> saveOrderLine(CompositePoLine compositePoLine, List<Location> locations, RequestContext requestContext) {
PoLine poLine = HelperUtils.convertToPoLine(compositePoLine);
PoLine poLine = PoLineCommonUtil.convertToPoLine(compositePoLine);
return saveOrderLine(poLine, locations, requestContext);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ private void makePoLinePending(CompositePoLine poLine) {

private Future<Void> updatePoLinesSummary(List<CompositePoLine> compositePoLines, RequestContext requestContext) {
return GenericCompositeFuture.join(compositePoLines.stream()
.map(HelperUtils::convertToPoLine)
.map(PoLineCommonUtil::convertToPoLine)
.map(line -> purchaseOrderLineService.saveOrderLine(line, requestContext))
.collect(toList()))
.map(ok -> null);
Expand Down
99 changes: 99 additions & 0 deletions src/main/java/org/folio/service/orders/utils/StatusUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package org.folio.service.orders.utils;

import org.apache.commons.lang3.StringUtils;
import org.folio.rest.jaxrs.model.CloseReason;
import org.folio.rest.jaxrs.model.CompositePoLine;
import org.folio.rest.jaxrs.model.PoLine;
import org.folio.rest.jaxrs.model.PoLine.PaymentStatus;
import org.folio.rest.jaxrs.model.PoLine.ReceiptStatus;
import org.folio.rest.jaxrs.model.PurchaseOrder;

import java.util.List;
import java.util.Set;

import static org.folio.orders.utils.HelperUtils.REASON_CANCELLED;
import static org.folio.orders.utils.HelperUtils.REASON_COMPLETE;

public class StatusUtils {

private static final Set<String> resolutionPaymentStatus = Set.of(PaymentStatus.CANCELLED.value(), PaymentStatus.PAYMENT_NOT_REQUIRED.value(), PaymentStatus.FULLY_PAID.value());
private static final Set<String> resolutionReceiptStatus = Set.of(ReceiptStatus.CANCELLED.value(), ReceiptStatus.RECEIPT_NOT_REQUIRED.value(), ReceiptStatus.FULLY_RECEIVED.value());

public static boolean isStatusChanged(CompositePoLine compOrderLine, PoLine lineFromStorage) {
return !StringUtils.equals(lineFromStorage.getReceiptStatus().value(), compOrderLine.getReceiptStatus().value()) ||
!StringUtils.equals(lineFromStorage.getPaymentStatus().value(), compOrderLine.getPaymentStatus().value());
}

public static boolean areAllPoLinesCanceled(List<PoLine> poLines) {
return poLines.stream().allMatch(StatusUtils::isStatusCanceledPoLine);
}

public static boolean changeOrderStatus(PurchaseOrder purchaseOrder, List<PoLine> poLines) {
if (toBeCancelled(purchaseOrder, poLines)) {
purchaseOrder.setWorkflowStatus(PurchaseOrder.WorkflowStatus.CLOSED);
purchaseOrder.setCloseReason(new CloseReason().withReason(REASON_CANCELLED));
return true;
}
if (toBeClosed(purchaseOrder, poLines)) {
purchaseOrder.setWorkflowStatus(PurchaseOrder.WorkflowStatus.CLOSED);
purchaseOrder.setCloseReason(new CloseReason().withReason(REASON_COMPLETE));
return true;
}
if (toBeReopened(purchaseOrder, poLines)) {
purchaseOrder.setWorkflowStatus(PurchaseOrder.WorkflowStatus.OPEN);
return true;
}
return false;
}

private static boolean toBeClosed(PurchaseOrder purchaseOrder, List<PoLine> poLines) {
return isOrderOpen(purchaseOrder)
&& poLines.stream().allMatch(StatusUtils::isCompletedPoLine);
}

private static boolean toBeCancelled(PurchaseOrder purchaseOrder, List<PoLine> poLines) {
return isOrderOpen(purchaseOrder)
&& poLines.stream().allMatch(StatusUtils::isCancelledPoLine);
}

private static boolean toBeReopened(PurchaseOrder purchaseOrder, List<PoLine> poLines) {
return isOrderClosed(purchaseOrder)
&& poLines.stream().anyMatch(StatusUtils::isNonResolutionPoLine);
}

private static boolean isCompletedPoLine(PoLine line) {
return resolutionPaymentStatus.contains(line.getPaymentStatus().value())
&& resolutionReceiptStatus.contains(line.getReceiptStatus().value());
}

private static boolean isNonResolutionPoLine(PoLine line) {
return !resolutionPaymentStatus.contains(line.getPaymentStatus().value())
&& !resolutionReceiptStatus.contains(line.getReceiptStatus().value());
}

private static boolean isCancelledPoLine(PoLine poLine) {
return poLine.getPaymentStatus() == PoLine.PaymentStatus.CANCELLED
&& poLine.getReceiptStatus() == PoLine.ReceiptStatus.CANCELLED;
}

private static boolean isStatusCanceledPoLine(PoLine poLine) {
return poLine.getPaymentStatus() == PoLine.PaymentStatus.CANCELLED
|| poLine.getReceiptStatus() == PoLine.ReceiptStatus.CANCELLED;
}

public static boolean isStatusCanceledCompositePoLine(CompositePoLine compOrderLine) {
return compOrderLine.getReceiptStatus() == CompositePoLine.ReceiptStatus.CANCELLED
|| compOrderLine.getPaymentStatus() == CompositePoLine.PaymentStatus.CANCELLED;
}

private static boolean isOrderOpen(PurchaseOrder order) {
return order.getWorkflowStatus() == PurchaseOrder.WorkflowStatus.OPEN;
}

private static boolean isOrderClosed(PurchaseOrder order) {
return order.getWorkflowStatus() == PurchaseOrder.WorkflowStatus.CLOSED;
}

private StatusUtils() {}

}
Loading