in applications/order/src/main/java/org/apache/ofbiz/order/order/OrderReturnServices.java [1725:2218]
public static Map<String, Object> processReplacementReturn(DispatchContext dctx, Map<String, ? extends Object> context) {
LocalDispatcher dispatcher = dctx.getDispatcher();
Delegator delegator = dctx.getDelegator();
String returnId = (String) context.get("returnId");
String returnTypeId = (String) context.get("returnTypeId");
GenericValue userLogin = (GenericValue) context.get("userLogin");
Locale locale = (Locale) context.get("locale");
Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
GenericValue returnHeader = null;
List<GenericValue> returnItems = null;
try {
returnHeader = EntityQuery.use(delegator).from("ReturnHeader").where("returnId", returnId).queryOne();
if (returnHeader != null) {
returnItems = returnHeader.getRelated("ReturnItem", UtilMisc.toMap("returnTypeId", returnTypeId), null, false);
}
} catch (GenericEntityException e) {
Debug.logError(e, "Problems looking up return information", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderErrorGettingReturnHeaderItemInformation", locale));
}
List<String> createdOrderIds = new LinkedList<>();
if (returnHeader != null && UtilValidate.isNotEmpty(returnItems)) {
String returnHeaderTypeId = returnHeader.getString("returnHeaderTypeId");
Map<String, List<GenericValue>> returnItemsByOrderId = new HashMap<>();
Map<String, BigDecimal> totalByOrder = new HashMap<>();
groupReturnItemsByOrder(returnItems, returnItemsByOrderId, totalByOrder, delegator, returnId, returnTypeId);
// process each one by order
for (Map.Entry<String, List<GenericValue>> entry : returnItemsByOrderId.entrySet()) {
String orderId = entry.getKey();
List<GenericValue> returnItemList = entry.getValue();
// get order header & payment prefs
GenericValue orderHeader = null;
try {
orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne();
} catch (GenericEntityException e) {
Debug.logError(e, "Cannot get Order details for #" + orderId, MODULE);
continue;
}
OrderReadHelper orh = new OrderReadHelper(orderHeader);
// create the replacement order
Map<String, Object> orderMap = UtilMisc.<String, Object>toMap("userLogin", userLogin);
String placingPartyId = null;
GenericValue placingParty = null;
if ("CUSTOMER_RETURN".equals(returnHeaderTypeId)) {
placingParty = orh.getPlacingParty();
if (placingParty != null) {
placingPartyId = placingParty.getString("partyId");
}
orderMap.put("orderTypeId", "SALES_ORDER");
} else {
placingParty = orh.getSupplierAgent();
if (placingParty != null) {
placingPartyId = placingParty.getString("partyId");
}
orderMap.put("orderTypeId", "PURCHASE_ORDER");
}
orderMap.put("partyId", placingPartyId);
orderMap.put("productStoreId", orderHeader.get("productStoreId"));
orderMap.put("webSiteId", orderHeader.get("webSiteId"));
orderMap.put("visitId", orderHeader.get("visitId"));
orderMap.put("currencyUom", orderHeader.get("currencyUom"));
orderMap.put("grandTotal", BigDecimal.ZERO);
// make the contact mechs
List<GenericValue> contactMechs = new LinkedList<>();
List<GenericValue> orderCm = null;
try {
orderCm = orderHeader.getRelated("OrderContactMech", null, null, false);
} catch (GenericEntityException e) {
Debug.logError(e, MODULE);
}
if (orderCm != null) {
for (GenericValue v : orderCm) {
contactMechs.add(GenericValue.create(v));
}
orderMap.put("orderContactMechs", contactMechs);
}
// make the order items
BigDecimal orderPriceTotal = BigDecimal.ZERO;
BigDecimal additionalItemTotal = BigDecimal.ZERO;
List<GenericValue> orderItems = new LinkedList<>();
List<GenericValue> orderItemShipGroupInfo = new LinkedList<>();
List<String> orderItemShipGroupIds = new LinkedList<>(); // this is used to store the ship group ids of the groups already added
// to the orderItemShipGroupInfo list
List<GenericValue> orderItemAssocs = new LinkedList<>();
if (returnItemList != null) {
int itemCount = 1;
for (GenericValue returnItem : returnItemList) {
GenericValue orderItem = null;
GenericValue product = null;
try {
orderItem = returnItem.getRelatedOne("OrderItem", false);
product = orderItem.getRelatedOne("Product", false);
} catch (GenericEntityException e) {
Debug.logError(e, MODULE);
continue;
}
BigDecimal quantity = returnItem.getBigDecimal("returnQuantity");
BigDecimal unitPrice = returnItem.getBigDecimal("returnPrice");
if (quantity != null && unitPrice != null) {
orderPriceTotal = orderPriceTotal.add(quantity.multiply(unitPrice));
// Check if the product being returned has a Refurbished Equivalent and if so
// (and there is inventory for the assoc product) use that product instead
GenericValue refurbItem = null;
if ("CUSTOMER_RETURN".equals(returnHeaderTypeId)) {
try {
if (product != null) {
GenericValue refurbItemAssoc = EntityUtil.getFirst(EntityUtil.filterByDate(
product.getRelated("MainProductAssoc", UtilMisc.toMap("productAssocTypeId", "PRODUCT_REFURB"),
UtilMisc.toList("sequenceNum"), false)));
if (refurbItemAssoc != null) {
refurbItem = refurbItemAssoc.getRelatedOne("AssocProduct", false);
}
}
} catch (GenericEntityException e) {
Debug.logError(e, MODULE);
}
if (refurbItem != null) {
boolean inventoryAvailable = false;
try {
Map<String, Object> invReqResult = dispatcher.runSync("isStoreInventoryAvailable",
UtilMisc.toMap("productStoreId", orderHeader.get("productStoreId"),
"productId", refurbItem.getString("productId"),
"product", refurbItem, "quantity", quantity));
if (ServiceUtil.isError(invReqResult)) {
Debug.logError("Error calling isStoreInventoryAvailable service, result is: " + invReqResult, MODULE);
} else {
inventoryAvailable = "Y".equals(invReqResult.get("available"));
}
} catch (GenericServiceException e) {
Debug.logError(e, "Fatal error calling inventory checking services: " + e.toString(), MODULE);
}
if (!inventoryAvailable) {
// If the Refurbished Equivalent is not available,
// then use the original product.
refurbItem = null;
}
}
GenericValue newItem = delegator.makeValue("OrderItem", UtilMisc.toMap("orderItemSeqId",
UtilFormatOut.formatPaddedNumber(itemCount++, 5)));
if (UtilValidate.isEmpty(refurbItem)) {
newItem.set("productId", orderItem.get("productId"));
newItem.set("itemDescription", orderItem.get("itemDescription"));
} else {
newItem.set("productId", refurbItem.get("productId"));
newItem.set("itemDescription", ProductContentWrapper.getProductContentAsText(refurbItem, "PRODUCT_NAME", locale,
dispatcher, "html"));
}
newItem.set("orderItemTypeId", orderItem.get("orderItemTypeId"));
newItem.set("productFeatureId", orderItem.get("productFeatureId"));
newItem.set("prodCatalogId", orderItem.get("prodCatalogId"));
newItem.set("productCategoryId", orderItem.get("productCategoryId"));
newItem.set("quantity", quantity);
newItem.set("unitPrice", unitPrice);
newItem.set("unitListPrice", orderItem.get("unitListPrice"));
newItem.set("comments", orderItem.get("comments"));
newItem.set("correspondingPoId", orderItem.get("correspondingPoId"));
newItem.set("statusId", "ITEM_CREATED");
orderItems.add(newItem);
// Set the order item ship group information
// TODO: only the first ship group associated to the item
// of the original order is considered and cloned,
// anIs there a better way to handle this?d the returned units are assigned to it.
//
GenericValue orderItemShipGroupAssoc = null;
try {
orderItemShipGroupAssoc = EntityUtil.getFirst(orderItem.getRelated("OrderItemShipGroupAssoc", null, null, false));
if (orderItemShipGroupAssoc != null) {
if (!orderItemShipGroupIds.contains(orderItemShipGroupAssoc.getString("shipGroupSeqId"))) {
GenericValue orderItemShipGroup = orderItemShipGroupAssoc.getRelatedOne("OrderItemShipGroup", false);
GenericValue newOrderItemShipGroup = (GenericValue) orderItemShipGroup.clone();
newOrderItemShipGroup.set("orderId", null);
orderItemShipGroupInfo.add(newOrderItemShipGroup);
orderItemShipGroupIds.add(orderItemShipGroupAssoc.getString("shipGroupSeqId"));
}
GenericValue newOrderItemShipGroupAssoc = delegator.makeValue("OrderItemShipGroupAssoc",
UtilMisc.toMap("orderItemSeqId", newItem.getString("orderItemSeqId"), "shipGroupSeqId",
orderItemShipGroupAssoc.getString("shipGroupSeqId"), "quantity", quantity));
orderItemShipGroupInfo.add(newOrderItemShipGroupAssoc);
}
} catch (GenericEntityException e) {
String errMsg = "Problem calling the approveRequirement service";
Debug.logError(e, errMsg, MODULE);
return ServiceUtil.returnError(errMsg);
}
// Create an association between the replacement order item and the order item of the original order
GenericValue newOrderItemAssoc = delegator.makeValue("OrderItemAssoc", UtilMisc.toMap("orderId",
orderHeader.getString("orderId"),
"orderItemSeqId", orderItem.getString("orderItemSeqId"), "shipGroupSeqId", "_NA_",
"toOrderItemSeqId", newItem.getString("orderItemSeqId"), "toShipGroupSeqId", "_NA_", "orderItemAssocTypeId",
"REPLACEMENT"));
orderItemAssocs.add(newOrderItemAssoc);
// For repair replacement orders, add to the order also the repair items
if ("RTN_REPAIR_REPLACE".equals(returnTypeId)) {
List<GenericValue> repairItems = null;
try {
if (product != null) {
repairItems = EntityUtil.filterByDate(product.getRelated("MainProductAssoc",
UtilMisc.toMap("productAssocTypeId", "PRODUCT_REPAIR_SRV"), UtilMisc.toList("sequenceNum"),
false));
}
} catch (GenericEntityException e) {
Debug.logError(e, MODULE);
continue;
}
if (UtilValidate.isNotEmpty(repairItems)) {
for (GenericValue repairItem : repairItems) {
GenericValue repairItemProduct = null;
try {
repairItemProduct = repairItem.getRelatedOne("AssocProduct", false);
} catch (GenericEntityException e) {
Debug.logError(e, MODULE);
continue;
}
if (repairItemProduct != null) {
BigDecimal repairUnitQuantity = repairItem.getBigDecimal("quantity");
if (UtilValidate.isEmpty(repairUnitQuantity)) {
repairUnitQuantity = BigDecimal.ONE;
}
BigDecimal repairQuantity = quantity.multiply(repairUnitQuantity);
newItem = delegator.makeValue("OrderItem", UtilMisc.toMap("orderItemSeqId",
UtilFormatOut.formatPaddedNumber(itemCount++, 5)));
// price
Map<String, Object> priceContext = new HashMap<>();
priceContext.put("currencyUomId", orderHeader.get("currencyUom"));
if (placingPartyId != null) {
priceContext.put("partyId", placingPartyId);
}
priceContext.put("quantity", repairUnitQuantity);
priceContext.put("product", repairItemProduct);
priceContext.put("webSiteId", orderHeader.get("webSiteId"));
priceContext.put("productStoreId", orderHeader.get("productStoreId"));
// TODO: prodCatalogId, agreementId
priceContext.put("productPricePurposeId", "PURCHASE");
priceContext.put("checkIncludeVat", "Y");
Map<String, Object> priceResult = null;
try {
priceResult = dispatcher.runSync("calculateProductPrice", priceContext);
} catch (GenericServiceException gse) {
Debug.logError(gse, MODULE);
continue;
}
if (ServiceUtil.isError(priceResult)) {
Debug.logError(ServiceUtil.getErrorMessage(priceResult), MODULE);
continue;
}
Boolean validPriceFound = (Boolean) priceResult.get("validPriceFound");
if (Boolean.FALSE.equals(validPriceFound)) {
Debug.logError("Could not find a valid price for the product with ID ["
+ repairItemProduct.get("productId") + "].", MODULE);
continue;
}
if (priceResult.get("listPrice") != null) {
newItem.set("unitListPrice", priceResult.get("listPrice"));
}
BigDecimal repairUnitPrice = null;
if (priceResult.get("basePrice") != null) {
repairUnitPrice = (BigDecimal) priceResult.get("basePrice");
} else {
repairUnitPrice = BigDecimal.ZERO;
}
newItem.set("unitPrice", repairUnitPrice);
newItem.set("productId", repairItemProduct.get("productId"));
// TODO: orderItemTypeId, prodCatalogId, productCategoryId
newItem.set("quantity", repairQuantity);
newItem.set("itemDescription", ProductContentWrapper.getProductContentAsText(repairItemProduct,
"PRODUCT_NAME", locale, dispatcher, "html"));
newItem.set("statusId", "ITEM_CREATED");
orderItems.add(newItem);
additionalItemTotal = additionalItemTotal.add(repairQuantity.multiply(repairUnitPrice));
if (orderItemShipGroupAssoc != null) {
GenericValue newOrderItemShipGroupAssoc = delegator.makeValue("OrderItemShipGroupAssoc",
UtilMisc.toMap("orderItemSeqId", newItem.getString("orderItemSeqId"), "shipGroupSeqId",
orderItemShipGroupAssoc.getString("shipGroupSeqId"), "quantity", repairQuantity));
orderItemShipGroupInfo.add(newOrderItemShipGroupAssoc);
}
// Create an association between the repair order item and the order item of the original order
newOrderItemAssoc = delegator.makeValue("OrderItemAssoc", UtilMisc.toMap("orderId",
orderHeader.getString("orderId"),
"orderItemSeqId", orderItem.getString("orderItemSeqId"), "shipGroupSeqId", "_NA_",
"toOrderItemSeqId", newItem.getString("orderItemSeqId"), "toShipGroupSeqId", "_NA_",
"orderItemAssocTypeId", "REPLACEMENT"));
orderItemAssocs.add(newOrderItemAssoc);
}
}
}
}
}
}
}
orderMap.put("orderItems", orderItems);
if (!orderItemShipGroupInfo.isEmpty()) {
orderMap.put("orderItemShipGroupInfo", orderItemShipGroupInfo);
}
if (!orderItemAssocs.isEmpty()) {
orderMap.put("orderItemAssociations", orderItemAssocs);
}
} else {
Debug.logError("No return items found??", MODULE);
continue;
}
// create the replacement adjustment
GenericValue adj = delegator.makeValue("OrderAdjustment");
adj.set("orderAdjustmentTypeId", "REPLACE_ADJUSTMENT");
adj.set("amount", orderPriceTotal.negate());
adj.set("comments", "Replacement Item Return #" + returnId);
adj.set("createdDate", nowTimestamp);
adj.set("createdByUserLogin", userLogin.getString("userLoginId"));
orderMap.put("orderAdjustments", UtilMisc.toList(adj));
// Payment preference
if ((additionalItemTotal.compareTo(BigDecimal.ZERO) > 0)
|| ("RTN_CSREPLACE".equals(returnTypeId) && orderPriceTotal.compareTo(ZERO) > 0)) {
GenericValue paymentMethod = null;
try {
paymentMethod = returnHeader.getRelatedOne("PaymentMethod", false);
} catch (GenericEntityException e) {
Debug.logError(e, MODULE);
}
if (paymentMethod != null) {
String paymentMethodId = paymentMethod.getString("paymentMethodId");
String paymentMethodTypeId = paymentMethod.getString("paymentMethodTypeId");
GenericValue opp = delegator.makeValue("OrderPaymentPreference");
opp.set("paymentMethodTypeId", paymentMethodTypeId);
opp.set("paymentMethodId", paymentMethodId);
// TODO: manualRefNum, manualAuthCode, securityCode, presentFlag, overflowFlag
if (paymentMethodId != null || "FIN_ACCOUNT".equals(paymentMethodTypeId)) {
opp.set("statusId", "PAYMENT_NOT_AUTH");
} else if (paymentMethodTypeId != null) {
// external payment method types require notification when received
// internal payment method types are assumed to be in-hand
if (paymentMethodTypeId.startsWith("EXT_")) {
opp.set("statusId", "PAYMENT_NOT_RECEIVED");
} else {
opp.set("statusId", "PAYMENT_RECEIVED");
}
}
if ("RTN_CSREPLACE".equals(returnTypeId)) {
opp.set("maxAmount", orderPriceTotal);
}
orderMap.put("orderPaymentInfo", UtilMisc.toList(opp));
}
}
// we'll assume new order is under same terms as original. note orderTerms is a required parameter of storeOrder
try {
orderMap.put("orderTerms", orderHeader.getRelated("OrderTerm", null, null, false));
} catch (GenericEntityException e) {
Debug.logError(e, "Cannot create replacement order because order terms for original order are not available", MODULE);
}
// we'll assume the new order has the same order roles of the original one
try {
List<GenericValue> orderRoles = orderHeader.getRelated("OrderRole", null, null, false);
Map<String, List<String>> orderRolesMap = new HashMap<>();
if (orderRoles != null) {
for (GenericValue orderRole : orderRoles) {
List<String> parties = orderRolesMap.get(orderRole.getString("roleTypeId"));
if (parties == null) {
parties = new LinkedList<>();
orderRolesMap.put(orderRole.getString("roleTypeId"), parties);
}
parties.add(orderRole.getString("partyId"));
}
}
if (!orderRolesMap.isEmpty()) {
orderMap.put("orderAdditionalPartyRoleMap", orderRolesMap);
}
} catch (GenericEntityException e) {
Debug.logError(e, "Cannot create replacement order because order roles for original order are not available", MODULE);
}
// create the order
String createdOrderId = null;
Map<String, Object> orderResult = null;
try {
orderResult = dispatcher.runSync("storeOrder", orderMap);
if (ServiceUtil.isError(orderResult)) {
return ServiceUtil.returnError(ServiceUtil.getErrorMessage(orderResult));
}
} catch (GenericServiceException e) {
Debug.logInfo(e, "Problem creating the order!", MODULE);
}
if (orderResult != null) {
createdOrderId = (String) orderResult.get("orderId");
createdOrderIds.add(createdOrderId);
}
// since there is no payments required; order is ready for processing/shipment
if (createdOrderId != null) {
if ("RETURN_ACCEPTED".equals(returnHeader.get("statusId")) && "RTN_WAIT_REPLACE_RES".equals(returnTypeId)) {
Map<String, Object> serviceResult = null;
try {
serviceResult = dispatcher.runSync("changeOrderStatus", UtilMisc.toMap("orderId", createdOrderId, "statusId",
"ORDER_HOLD", "userLogin", userLogin));
if (ServiceUtil.isError(serviceResult)) {
return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult));
}
} catch (GenericServiceException e) {
Debug.logError(e, "Service invocation error, status changes were not updated for order #" + createdOrderId, MODULE);
return ServiceUtil.returnError(e.getMessage());
}
if (ServiceUtil.isError(serviceResult)) {
return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult));
}
} else {
if ("CUSTOMER_RETURN".equals(returnHeaderTypeId)) {
OrderChangeHelper.approveOrder(dispatcher, userLogin, createdOrderId);
} else {
try {
OrderChangeHelper.orderStatusChanges(dispatcher, userLogin, createdOrderId, "ORDER_APPROVED", null,
"ITEM_APPROVED", null);
} catch (GenericServiceException e) {
Debug.logError(e, "Service invocation error, status changes were not updated for order #" + createdOrderId, MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderErrorCannotStoreStatusChanges", locale) + createdOrderId);
}
}
}
// create a ReturnItemResponse and attach to each ReturnItem
Map<String, Object> itemResponse = new HashMap<>();
itemResponse.put("replacementOrderId", createdOrderId);
itemResponse.put("responseAmount", orderPriceTotal);
itemResponse.put("responseDate", nowTimestamp);
itemResponse.put("userLogin", userLogin);
String returnItemResponseId = null;
try {
Map<String, Object> createReturnItemResponseResult = dispatcher.runSync("createReturnItemResponse", itemResponse);
if (ServiceUtil.isError(createReturnItemResponseResult)) {
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingReturnItemResponseRecord", locale),
null, null, createReturnItemResponseResult);
}
returnItemResponseId = (String) createReturnItemResponseResult.get("returnItemResponseId");
} catch (GenericServiceException e) {
Debug.logError(e, "Problem creating ReturnItemResponse record", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingReturnItemResponseRecord", locale));
}
for (GenericValue returnItem : returnItemList) {
Map<String, Object> updateReturnItemCtx = new HashMap<>();
updateReturnItemCtx.put("returnId", returnId);
updateReturnItemCtx.put("returnItemSeqId", returnItem.get("returnItemSeqId"));
updateReturnItemCtx.put("returnItemResponseId", returnItemResponseId);
updateReturnItemCtx.put("userLogin", userLogin);
try {
Map<String, Object> updateReturnItemResult = dispatcher.runSync("updateReturnItem", updateReturnItemCtx);
if (ServiceUtil.isError(updateReturnItemResult)) {
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemStoringReturnItemUpdates", locale), null, null, updateReturnItemResult);
}
} catch (GenericServiceException e) {
Debug.logError(e, "Could not update ReturnItem record", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemStoringReturnItemUpdates", locale));
}
}
}
}
}
// create a return message AND create ReturnItemResponse record(s)
StringBuilder successMessage = new StringBuilder();
if (!createdOrderIds.isEmpty()) {
successMessage.append("The following new orders have been created : ");
Iterator<String> i = createdOrderIds.iterator();
while (i.hasNext()) {
successMessage.append(i.next());
if (i.hasNext()) {
successMessage.append(", ");
}
}
} else {
successMessage.append("No orders were created.");
}
return ServiceUtil.returnSuccess(successMessage.toString());
}