This is an automated email from the ASF dual-hosted git repository.
jleroux pushed a commit to branch release24.09
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/release24.09 by this push:
new 83eb6f86dd Fixed: Force Complete Purchase Order logic to support items
split into multiple ship groups (OFBIZ-13327) (#934)
83eb6f86dd is described below
commit 83eb6f86ddfe353458f9993b4e8feea81b85783a
Author: Anahita Goljahani <[email protected]>
AuthorDate: Sat Jan 3 09:23:23 2026 +0100
Fixed: Force Complete Purchase Order logic to support items split into
multiple ship groups (OFBIZ-13327) (#934)
The fix is needed because the cancelOrderItem service, that is used in
the 'Force Complete Purchase Order' workflow, doesn't work correctly in
case of item's units split into multiple ship groups.
The issue can be reproduced as described in the attached document.
[PR_force_complete_order_how_to_reproduce_the_issue.pdf](https://github.com/user-attachments/files/24367999/PR_force_complete_order_how_to_reproduce_the_issue.pdf)
---
.../apache/ofbiz/order/order/OrderServices.java | 123 ++++++++++++++-------
1 file changed, 86 insertions(+), 37 deletions(-)
diff --git
a/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderServices.java
b/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderServices.java
index 347f6ab1e5..3473d03e16 100644
---
a/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderServices.java
+++
b/applications/order/src/main/java/org/apache/ofbiz/order/order/OrderServices.java
@@ -2162,9 +2162,18 @@ public class OrderServices {
}
if (orderItemShipGroupAssocs != null) {
+ Map<String, List<BigDecimal>> itemQuantitiesMap = new HashMap<>();
for (GenericValue orderItemShipGroupAssoc :
orderItemShipGroupAssocs) {
+ BigDecimal aisgaCancelQuantity =
orderItemShipGroupAssoc.getBigDecimal("cancelQuantity");
+ if (aisgaCancelQuantity == null) {
+ aisgaCancelQuantity = BigDecimal.ZERO;
+ }
+ BigDecimal availableQuantity =
orderItemShipGroupAssoc.getBigDecimal("quantity").subtract(aisgaCancelQuantity);
+ if (availableQuantity == null) {
+ availableQuantity = BigDecimal.ZERO;
+ }
+
GenericValue orderItem = null;
- String itemStatus = "ITEM_CANCELLED";
try {
orderItem =
orderItemShipGroupAssoc.getRelatedOne("OrderItem", false);
} catch (GenericEntityException e) {
@@ -2176,46 +2185,80 @@ public class OrderServices {
"OrderErrorCannotCancelItemItemNotFound",
UtilMisc.toMap("itemMsgInfo", itemMsgInfo), locale));
}
- BigDecimal aisgaCancelQuantity =
orderItemShipGroupAssoc.getBigDecimal("cancelQuantity");
- if (aisgaCancelQuantity == null) {
- aisgaCancelQuantity = BigDecimal.ZERO;
- }
- BigDecimal availableQuantity =
orderItemShipGroupAssoc.getBigDecimal("quantity").subtract(aisgaCancelQuantity);
-
- BigDecimal itemCancelQuantity =
orderItem.getBigDecimal("cancelQuantity");
- if (itemCancelQuantity == null) {
- itemCancelQuantity = BigDecimal.ZERO;
- }
- BigDecimal itemQuantity =
orderItem.getBigDecimal("quantity").subtract(itemCancelQuantity);
- if (availableQuantity == null) {
- availableQuantity = BigDecimal.ZERO;
- }
- if (itemQuantity == null) {
- itemQuantity = BigDecimal.ZERO;
- }
+ BigDecimal itemQuantity = null;
+ BigDecimal itemCancelQuantity = null;
+ BigDecimal thisCancelQty = null;
+ if
(!itemQuantitiesMap.containsKey(orderItem.getString("orderItemSeqId"))) {
+ itemCancelQuantity =
orderItem.getBigDecimal("cancelQuantity");
+ if (itemCancelQuantity == null) {
+ itemCancelQuantity = BigDecimal.ZERO;
+ }
+ itemQuantity =
orderItem.getBigDecimal("quantity").subtract(itemCancelQuantity);
+ if (itemQuantity == null) {
+ itemQuantity = BigDecimal.ZERO;
+ }
- if ("PURCHASE_ORDER".equals(orh.getOrderTypeId())) {
- BigDecimal receivedQty =
orh.getItemReceivedQuantity(orderItem);
- if (receivedQty.compareTo(BigDecimal.ZERO) > 0) {
- itemStatus = "ITEM_COMPLETED";
+ if ("PURCHASE_ORDER".equals(orh.getOrderTypeId())) {
+ BigDecimal receivedQty =
orh.getItemReceivedQuantity(orderItem);
+ itemQuantity = itemQuantity.subtract(receivedQty);
+ } else {
+ BigDecimal shippedQty =
orh.getItemShippedQuantity(orderItem);
+ itemQuantity = itemQuantity.subtract(shippedQty);
}
- itemQuantity = itemQuantity.subtract(receivedQty);
- } else {
- BigDecimal shippedQty =
orh.getItemShippedQuantity(orderItem);
- if (shippedQty.compareTo(BigDecimal.ZERO) > 0) {
- itemStatus = "ITEM_COMPLETED";
+
+ if (cancelQuantity != null) {
+ thisCancelQty = cancelQuantity;
+ } else {
+ thisCancelQty = itemQuantity;
}
- itemQuantity = itemQuantity.subtract(shippedQty);
+ List<BigDecimal> itemQuantitiesList = new ArrayList<>();
+ itemQuantitiesList.add(itemQuantity);
+ itemQuantitiesList.add(itemCancelQuantity);
+ itemQuantitiesList.add(thisCancelQty);
+
itemQuantitiesMap.put(orderItem.getString("orderItemSeqId"),
itemQuantitiesList);
}
+ itemQuantity =
itemQuantitiesMap.get(orderItem.getString("orderItemSeqId")).get(0);
+ itemCancelQuantity =
itemQuantitiesMap.get(orderItem.getString("orderItemSeqId")).get(1);
+ thisCancelQty =
itemQuantitiesMap.get(orderItem.getString("orderItemSeqId")).get(2);
- BigDecimal thisCancelQty = null;
- if (cancelQuantity != null) {
- thisCancelQty = cancelQuantity;
- } else {
- thisCancelQty = itemQuantity;
+ fields.put("orderItemSeqId",
orderItemShipGroupAssoc.getString("orderItemSeqId"));
+ fields.put("shipGroupSeqId",
orderItemShipGroupAssoc.getString("shipGroupSeqId"));
+ BigDecimal totReceivedQuantity = BigDecimal.ZERO;
+ try {
+ List<GenericValue> orderShipments =
EntityQuery.use(delegator).from("OrderShipment").where(fields).queryList();
+ Map<String, String> shipmentReceiptCondition =
UtilMisc.<String, String>toMap("orderId", orderId);
+ shipmentReceiptCondition.put("orderItemSeqId",
orderItemShipGroupAssoc.getString("orderItemSeqId"));
+ for (GenericValue orderShipment : orderShipments) {
+ shipmentReceiptCondition.put("shipmentId",
orderShipment.getString("shipmentId"));
+ shipmentReceiptCondition.put("shipmentItemSeqId",
orderShipment.getString("shipmentItemSeqId"));
+ List<GenericValue> shipmentReceipts =
EntityQuery.use(delegator)
+
.from("ShipmentReceipt")
+
.where(shipmentReceiptCondition).queryList();
+ for (GenericValue shipmentReceipt : shipmentReceipts) {
+ BigDecimal quantityAccepted =
shipmentReceipt.getBigDecimal("quantityAccepted");
+ if (quantityAccepted != null) {
+ totReceivedQuantity =
totReceivedQuantity.add(quantityAccepted);
+ }
+ BigDecimal quantityRejected =
shipmentReceipt.getBigDecimal("quantityRejected");
+ if (quantityRejected != null) {
+ totReceivedQuantity =
totReceivedQuantity.add(quantityRejected);
+ }
+ }
+ }
+ } catch (GenericEntityException e) {
+ Debug.logError(e, MODULE);
+ return
ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
+ "OrderErrorCannotGetShipmentReceipts",
UtilMisc.toMap("itemMsgInfo", itemMsgInfo), locale));
}
+ availableQuantity =
availableQuantity.subtract(totReceivedQuantity);
+
+ if (itemQuantity.compareTo(thisCancelQty) >= 0) {
+ BigDecimal cancelQty = thisCancelQty;
+ thisCancelQty = thisCancelQty.min(availableQuantity);
+
itemQuantitiesMap.get(orderItem.getString("orderItemSeqId")).set(0,
itemQuantity.subtract(thisCancelQty));
+
itemQuantitiesMap.get(orderItem.getString("orderItemSeqId")).set(1,
itemCancelQuantity.add(thisCancelQty));
+
itemQuantitiesMap.get(orderItem.getString("orderItemSeqId")).set(2,
cancelQty.subtract(thisCancelQty));
- if (availableQuantity.compareTo(thisCancelQty) >= 0) {
if (availableQuantity.compareTo(BigDecimal.ZERO) == 0) {
continue; //OrderItemShipGroupAssoc already cancelled
}
@@ -2235,7 +2278,7 @@ public class OrderServices {
"orderId", orderItem.getString("orderId"),
"orderItemSeqId",
orderItem.getString("orderItemSeqId"),
"shipGroupSeqId",
orderItemShipGroupAssoc.getString("shipGroupSeqId"));
- if (availableQuantity.compareTo(thisCancelQty) == 0) {
+ if
(orderItemShipGroupAssoc.getBigDecimal("quantity").compareTo(orderItemShipGroupAssoc.getBigDecimal("cancelQuantity"))
== 0) {
try {
resp =
dispatcher.runSync("deleteOrderItemShipGroupAssoc", localCtx);
if (ServiceUtil.isError(resp)) {
@@ -2290,7 +2333,13 @@ public class OrderServices {
Debug.logError(e, MODULE);
}
- if (thisCancelQty.compareTo(itemQuantity) >= 0) {
+ if
(itemQuantitiesMap.get(orderItem.getString("orderItemSeqId")).get(0).compareTo(BigDecimal.ZERO)
== 0) {
+ String itemStatus = null;
+ if
(orderItem.getBigDecimal("quantity").compareTo(orderItem.getBigDecimal("cancelQuantity"))
== 0) {
+ itemStatus = "ITEM_CANCELLED";
+ } else {
+ itemStatus = "ITEM_COMPLETED";
+ }
if ("ITEM_COMPLETED".equals(itemStatus) &&
"SALES_ORDER".equals(orh.getOrderTypeId())) {
//If partial item shipped then release remaining
inventory of SO item and marked SO item as completed.
Map<String, Object> cancelOrderItemInvResCtx =
UtilMisc.toMap("orderId", orderId, "orderItemSeqId",
@@ -2304,7 +2353,7 @@ public class OrderServices {
UtilMisc.toMap("itemMsgInfo",
itemMsgInfo), locale));
}
}
- // all items are cancelled -- mark the item as
cancelled
+ // all item's units are cancelled -- mark the item as
cancelled
Map<String, Object> statusCtx = UtilMisc.<String,
Object>toMap("orderId", orderId, "orderItemSeqId", orderItem.getString(
"orderItemSeqId"), "statusId", itemStatus,
"changeReason", reasonEnumId, "userLogin", userLogin);
try {