in applications/order/src/main/java/org/apache/ofbiz/order/order/OrderReturnServices.java [696:1027]
public static Map<String, Object> processCreditReturn(DispatchContext dctx, Map<String, ? extends Object> context) {
LocalDispatcher dispatcher = dctx.getDispatcher();
Delegator delegator = dctx.getDelegator();
String returnId = (String) context.get("returnId");
GenericValue userLogin = (GenericValue) context.get("userLogin");
Locale locale = (Locale) context.get("locale");
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", "RTN_CREDIT"), null, false);
}
} catch (GenericEntityException e) {
Debug.logError(e, "Problems looking up return information", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderErrorGettingReturnHeaderItemInformation", locale));
}
BigDecimal adjustments = getReturnAdjustmentTotal(delegator, UtilMisc.toMap("returnId", returnId, "returnTypeId", "RTN_CREDIT"));
if (returnHeader != null && (UtilValidate.isNotEmpty(returnItems) || adjustments.compareTo(ZERO) > 0)) {
String finAccountId = returnHeader.getString("finAccountId");
String billingAccountId = returnHeader.getString("billingAccountId");
String fromPartyId = returnHeader.getString("fromPartyId");
String toPartyId = returnHeader.getString("toPartyId");
// make sure total refunds on a return don't exceed amount of returned orders
Map<String, Object> serviceResult = null;
try {
serviceResult = dispatcher.runSync("checkPaymentAmountForRefund", UtilMisc.toMap("returnId", returnId));
} catch (GenericServiceException e) {
Debug.logError(e, "Problem running the checkPaymentAmountForRefund service", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemsWithCheckPaymentAmountForRefund", locale));
}
if (ServiceUtil.isError(serviceResult)) {
return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult));
}
// Fetch the ProductStore
GenericValue productStore = null;
GenericValue orderHeader = null;
GenericValue returnItem = null;
if (UtilValidate.isNotEmpty(returnItems)) {
returnItem = EntityUtil.getFirst(returnItems);
}
if (returnItem != null) {
try {
orderHeader = returnItem.getRelatedOne("OrderHeader", false);
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
}
if (orderHeader != null) {
OrderReadHelper orderReadHelper = new OrderReadHelper(orderHeader);
productStore = orderReadHelper.getProductStore();
}
// if both billingAccountId and finAccountId are supplied, look for productStore.storeCreditAccountEnumId preference
if (finAccountId != null && billingAccountId != null && productStore != null
&& productStore.getString("storeCreditAccountEnumId") != null) {
Debug.logWarning("You have entered both financial account and billing account for store credit. Based on the configuration on"
+ "product store, only one of them will be selected.", MODULE);
if ("BILLING_ACCOUNT".equals(productStore.getString("storeCreditAccountEnumId"))) {
finAccountId = null;
Debug.logWarning("Default setting on product store is billing account. Store credit will goes to billing account ["
+ billingAccountId + "]", MODULE);
} else {
billingAccountId = null;
Debug.logWarning("Default setting on product store is financial account. Store credit will goes to financial account ["
+ finAccountId + "]", MODULE);
}
}
if (finAccountId == null && billingAccountId == null) {
// First find a Billing Account with negative balance, and if found store credit to that
List<GenericValue> billingAccounts;
try {
billingAccounts = EntityQuery.use(delegator).from("BillingAccountRoleAndAddress")
.where("partyId", fromPartyId, "roleTypeId", "BILL_TO_CUSTOMER")
.filterByDate()
.orderBy("-fromDate")
.queryList();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (UtilValidate.isNotEmpty(billingAccounts)) {
ListIterator<GenericValue> billingAccountItr = billingAccounts.listIterator();
while (billingAccountItr.hasNext() && billingAccountId == null) {
String thisBillingAccountId = billingAccountItr.next().getString("billingAccountId");
BigDecimal billingAccountBalance = ZERO;
try {
GenericValue billingAccount = EntityQuery.use(delegator).from("BillingAccount").where("billingAccountId",
thisBillingAccountId).queryOne();
billingAccountBalance = OrderReadHelper.getBillingAccountBalance(billingAccount);
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (billingAccountBalance.signum() == -1) {
billingAccountId = thisBillingAccountId;
}
}
}
// if no billing account with negative balance is found, look for productStore.storeCreditAccountEnumId settings
if (billingAccountId == null) {
if (productStore != null && productStore.getString("storeCreditAccountEnumId") != null
&& "BILLING_ACCOUNT".equals(productStore.getString("storeCreditAccountEnumId"))) {
if (UtilValidate.isNotEmpty(billingAccounts)) {
billingAccountId = EntityUtil.getFirst(billingAccounts).getString("billingAccountId");
} else {
// create new BillingAccount w/ 0 balance
Map<String, Object> results = createBillingAccountFromReturn(returnHeader, returnItems, dctx, context);
if (ServiceUtil.isError(results)) {
Debug.logError("Error creating BillingAccount: " + results.get(ModelService.ERROR_MESSAGE), MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderErrorWithCreateBillingAccount", locale) + results.get(ModelService.ERROR_MESSAGE));
}
billingAccountId = (String) results.get("billingAccountId");
// double check; make sure we have a billingAccount
if (billingAccountId == null) {
Debug.logError("No available billing account, none was created", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderNoAvailableBillingAccount", locale));
}
}
} else {
GenericValue finAccount = null;
try {
finAccount = EntityQuery.use(delegator).from("FinAccountAndRole")
.where("partyId", fromPartyId, "finAccountTypeId", "STORE_CREDIT_ACCT", "roleTypeId", "OWNER", "statusId",
"FNACT_ACTIVE", "currencyUomId", returnHeader.getString("currencyUomId"))
.filterByDate()
.orderBy("-fromDate")
.queryFirst();
} catch (GenericEntityException e) {
return ServiceUtil.returnError(e.getMessage());
}
if (finAccount != null) {
finAccountId = finAccount.getString("finAccountId");
}
if (finAccountId == null) {
Map<String, Object> createAccountCtx = new HashMap<>();
createAccountCtx.put("ownerPartyId", fromPartyId);
createAccountCtx.put("finAccountTypeId", "STORE_CREDIT_ACCT");
createAccountCtx.put("productStoreId", productStore.getString("productStoreId"));
createAccountCtx.put("currencyUomId", returnHeader.getString("currencyUomId"));
createAccountCtx.put("finAccountName", "Store Credit Account for party [" + fromPartyId + "]");
createAccountCtx.put("userLogin", userLogin);
Map<String, Object> createAccountResult = null;
try {
createAccountResult = dispatcher.runSync("createFinAccountForStore", createAccountCtx);
} catch (GenericServiceException e) {
Debug.logError(e, "Problems running the createFinAccountForStore service", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemsCreatingFinAccountForStore", locale));
}
if (ServiceUtil.isError(createAccountResult)) {
return ServiceUtil.returnError(ServiceUtil.getErrorMessage(createAccountResult));
}
finAccountId = (String) createAccountResult.get("finAccountId");
// double check; make sure we have a FinAccount
if (finAccountId == null) {
Debug.logError("No available fin account, none was created", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderNoAvailableFinAccount", locale));
}
Map<String, Object> finAccountRoleResult = null;
try {
finAccountRoleResult = dispatcher.runSync("createFinAccountRole", UtilMisc.toMap("finAccountId",
finAccountId, "partyId", fromPartyId, "roleTypeId", "OWNER", "userLogin", userLogin));
} catch (GenericServiceException e) {
Debug.logError(e, "Problem running the createFinAccountRole service", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingFinAccountRoleRecord", locale));
}
if (ServiceUtil.isError(finAccountRoleResult)) {
return ServiceUtil.returnError(ServiceUtil.getErrorMessage(finAccountRoleResult));
}
}
}
}
}
// now; to be used for all timestamps
Timestamp now = UtilDateTime.nowTimestamp();
// first, compute the total credit from the return items
BigDecimal creditTotal = ZERO;
for (GenericValue item : returnItems) {
BigDecimal quantity = item.getBigDecimal("returnQuantity");
BigDecimal price = item.getBigDecimal("returnPrice");
if (quantity == null) {
quantity = ZERO;
}
if (price == null) {
price = ZERO;
}
creditTotal = creditTotal.add(price.multiply(quantity).setScale(DECIMALS, ROUNDING));
}
// add the adjustments to the total
creditTotal = creditTotal.add(adjustments.setScale(DECIMALS, ROUNDING));
// create finAccountRole and finAccountTrans
String finAccountTransId = null;
if (finAccountId != null) {
Map<String, Object> finAccountTransResult = null;
try {
finAccountTransResult = dispatcher.runSync("createFinAccountTrans", UtilMisc.toMap("finAccountId", finAccountId,
"finAccountTransTypeId", "DEPOSIT", "partyId", toPartyId, "amount", creditTotal, "reasonEnumId", "FATR_REFUND",
"userLogin", userLogin));
} catch (GenericServiceException e) {
Debug.logError(e, "Problem creating FinAccountTrans record", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingFinAccountTransRecord", locale));
}
if (ServiceUtil.isError(finAccountTransResult)) {
return ServiceUtil.returnError(ServiceUtil.getErrorMessage(finAccountTransResult));
}
finAccountTransId = (String) finAccountTransResult.get("finAccountTransId");
}
// create a Payment record for this credit; will look just like a normal payment
// However, since this payment is not a DISBURSEMENT or RECEIPT but really a matter of internal record
// it is of type "Other (Non-posting)"
String paymentId = delegator.getNextSeqId("Payment");
GenericValue payment = delegator.makeValue("Payment", UtilMisc.toMap("paymentId", paymentId));
payment.set("paymentTypeId", "CUSTOMER_REFUND");
payment.set("partyIdFrom", toPartyId); // if you receive a return FROM someone, then you'd have to give a return TO that person
payment.set("partyIdTo", fromPartyId);
payment.set("effectiveDate", now);
payment.set("amount", creditTotal);
payment.set("comments", "Return Credit");
payment.set("statusId", "PMNT_CONFIRMED"); // set the status to confirmed so nothing else can happen to the payment
if (billingAccountId != null) {
payment.set("paymentMethodTypeId", "EXT_BILLACT");
} else {
payment.set("paymentMethodTypeId", "FIN_ACCOUNT");
}
try {
delegator.create(payment);
} catch (GenericEntityException e) {
Debug.logError(e, "Problem creating Payment record", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingPaymentRecord", locale));
}
// create a return item response
Map<String, Object> itemResponse = UtilMisc.<String, Object>toMap("paymentId", paymentId);
itemResponse.put("responseAmount", creditTotal);
itemResponse.put("responseDate", now);
itemResponse.put("userLogin", userLogin);
if (billingAccountId != null) {
itemResponse.put("billingAccountId", billingAccountId);
} else {
itemResponse.put("finAccountTransId", finAccountTransId);
}
Map<String, Object> serviceResults = null;
try {
serviceResults = dispatcher.runSync("createReturnItemResponse", itemResponse);
if (ServiceUtil.isError(serviceResults)) {
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingReturnItemResponseRecord", locale), null, null, serviceResults);
}
} catch (GenericServiceException e) {
Debug.logError(e, "Problem creating ReturnItemResponse record", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingReturnItemResponseRecord", locale));
}
// the resulting response ID will be associated with the return items
String itemResponseId = (String) serviceResults.get("returnItemResponseId");
// loop through the items again to update them and store a status change history
for (GenericValue item : returnItems) {
Map<String, Object> returnItemMap = UtilMisc.<String, Object>toMap("returnItemResponseId", itemResponseId, "returnId",
item.get("returnId"), "returnItemSeqId", item.get("returnItemSeqId"), "statusId", "RETURN_COMPLETED", "userLogin",
userLogin);
// store the item changes (attached responseId)
try {
serviceResults = dispatcher.runSync("updateReturnItem", returnItemMap);
if (ServiceUtil.isError(serviceResults)) {
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemStoringReturnItemUpdates", locale), null, null, serviceResults);
}
} catch (GenericServiceException e) {
Debug.logError(e, "Problem storing ReturnItem updates", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemStoringReturnItemUpdates", locale));
}
}
if (billingAccountId != null) {
// create the PaymentApplication for the billing account
String paId = delegator.getNextSeqId("PaymentApplication");
GenericValue pa = delegator.makeValue("PaymentApplication", UtilMisc.toMap("paymentApplicationId", paId));
pa.set("paymentId", paymentId);
pa.set("billingAccountId", billingAccountId);
pa.set("amountApplied", creditTotal);
try {
delegator.create(pa);
} catch (GenericEntityException e) {
Debug.logError(e, "Problem creating PaymentApplication record for billing account", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingPaymentApplicationRecord", locale));
}
// create the payment applications for the return invoice in case of billing account
try {
serviceResults = dispatcher.runSync("createPaymentApplicationsFromReturnItemResponse",
UtilMisc.<String, Object>toMap("returnItemResponseId", itemResponseId, "userLogin", userLogin));
if (ServiceUtil.isError(serviceResults)) {
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingPaymentApplicationRecord", locale), null, null, serviceResults);
}
} catch (GenericServiceException e) {
Debug.logError(e, "Problem creating PaymentApplication records for return invoice", MODULE);
return ServiceUtil.returnError(UtilProperties.getMessage(RES_ERROR,
"OrderProblemCreatingPaymentApplicationRecord", locale));
}
}
}
return ServiceUtil.returnSuccess();
}