KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > order > order > OrderReturnServices


1 /* $$ID$ */
2 package org.ofbiz.order.order;
3
4 import java.math.BigDecimal JavaDoc;
5 import java.sql.Timestamp JavaDoc;
6 import java.util.ArrayList JavaDoc;
7 import java.util.HashMap JavaDoc;
8 import java.util.Iterator JavaDoc;
9 import java.util.LinkedList JavaDoc;
10 import java.util.List JavaDoc;
11 import java.util.Locale JavaDoc;
12 import java.util.Map JavaDoc;
13 import java.util.Set JavaDoc;
14
15 import javolution.util.FastMap;
16
17 import org.ofbiz.base.util.Debug;
18 import org.ofbiz.base.util.GeneralRuntimeException;
19 import org.ofbiz.base.util.UtilDateTime;
20 import org.ofbiz.base.util.UtilMisc;
21 import org.ofbiz.base.util.UtilNumber;
22 import org.ofbiz.base.util.UtilProperties;
23 import org.ofbiz.base.util.UtilValidate;
24 import org.ofbiz.base.util.collections.ResourceBundleMapWrapper;
25 import org.ofbiz.entity.GenericDelegator;
26 import org.ofbiz.entity.GenericEntityException;
27 import org.ofbiz.entity.GenericValue;
28 import org.ofbiz.entity.util.EntityUtil;
29 import org.ofbiz.product.store.ProductStoreWorker;
30 import org.ofbiz.service.DispatchContext;
31 import org.ofbiz.service.GenericServiceException;
32 import org.ofbiz.service.LocalDispatcher;
33 import org.ofbiz.service.ModelParam;
34 import org.ofbiz.service.ModelService;
35 import org.ofbiz.service.ServiceUtil;
36
37 /**
38  * OrderReturnServices
39  *
40  * @author <a HREF="mailto:jaz@ofbiz.org">Andy Zeneski</a>
41  * @version $Rev: 7232 $
42  * @since 3.5
43  */

44 public class OrderReturnServices {
45
46     public static final String JavaDoc module = OrderReturnServices.class.getName();
47     public static final String JavaDoc resource = "OrderUiLabels";
48     public static final String JavaDoc resource_error = "OrderErrorUiLabels";
49
50     // set some BigDecimal properties
51
private static BigDecimal JavaDoc ZERO = new BigDecimal JavaDoc("0");
52     private static int decimals = -1;
53     private static int rounding = -1;
54     static {
55         decimals = UtilNumber.getBigDecimalScale("invoice.decimals");
56         rounding = UtilNumber.getBigDecimalRoundingMode("invoice.rounding");
57
58         // set zero to the proper scale
59
if (decimals != -1) ZERO.setScale(decimals);
60     }
61
62     // locate the return item's initial inventory item cost
63
public static Map JavaDoc getReturnItemInitialCost(DispatchContext dctx, Map JavaDoc context) {
64         GenericDelegator delegator = dctx.getDelegator();
65         String JavaDoc returnId = (String JavaDoc) context.get("returnId");
66         String JavaDoc returnItemSeqId = (String JavaDoc) context.get("returnItemSeqId");
67
68         Map JavaDoc result = ServiceUtil.returnSuccess();
69         result.put("initialItemCost", getReturnItemInitialCost(delegator, returnId, returnItemSeqId));
70         return result;
71     }
72
73     // obtain order/return total information
74
public static Map JavaDoc getOrderAvailableReturnedTotal(DispatchContext dctx, Map JavaDoc context) {
75         GenericDelegator delegator = dctx.getDelegator();
76         String JavaDoc orderId = (String JavaDoc) context.get("orderId");
77         OrderReadHelper orh = null;
78         try {
79             orh = new OrderReadHelper(delegator, orderId);
80         } catch (IllegalArgumentException JavaDoc e) {
81             return ServiceUtil.returnError(e.getMessage());
82         }
83
84         // an adjustment value to test
85
Double JavaDoc adj = (Double JavaDoc) context.get("adjustment");
86         if (adj == null) {
87             adj = new Double JavaDoc(0);
88         }
89
90         Boolean JavaDoc countNewReturnItems = (Boolean JavaDoc) context.get("countNewReturnItems");
91         if (countNewReturnItems == null) {
92             countNewReturnItems = Boolean.FALSE;
93         }
94         double returnTotal = orh.getOrderReturnedTotal(countNewReturnItems.booleanValue());
95         double orderTotal = orh.getOrderGrandTotal();
96         double available = orderTotal - returnTotal - adj.doubleValue();
97
98
99         Map JavaDoc result = ServiceUtil.returnSuccess();
100         result.put("availableReturnTotal", new Double JavaDoc(available));
101         result.put("orderTotal", new Double JavaDoc(orderTotal));
102         result.put("returnTotal", new Double JavaDoc(returnTotal));
103         return result;
104     }
105
106     // worker method which can be used in screen iterations
107
public static Double JavaDoc getReturnItemInitialCost(GenericDelegator delegator, String JavaDoc returnId, String JavaDoc returnItemSeqId) {
108         if (delegator == null || returnId == null || returnItemSeqId == null) {
109             throw new IllegalArgumentException JavaDoc("Method parameters cannot contain nulls");
110         }
111         Debug.log("Finding the initial item cost for return item : " + returnId + " / " + returnItemSeqId, module);
112
113         // the cost holder
114
Double JavaDoc itemCost = new Double JavaDoc(0.00);
115
116         // get the return item information
117
GenericValue returnItem = null;
118         try {
119             returnItem = delegator.findByPrimaryKey("ReturnItem", UtilMisc.toMap("returnId", returnId, "returnItemSeqId", returnItemSeqId));
120         } catch (GenericEntityException e) {
121             Debug.logError(e, module);
122             throw new GeneralRuntimeException(e.getMessage());
123         }
124         Debug.log("Return item value object - " + returnItem, module);
125
126         // check for an orderItem association
127
if (returnItem != null) {
128             String JavaDoc orderId = returnItem.getString("orderId");
129             String JavaDoc orderItemSeqId = returnItem.getString("orderItemSeqId");
130             if (orderItemSeqId != null && orderId != null) {
131                 Debug.log("Found order item reference", module);
132                 // locate the item issuance(s) for this order item
133
List JavaDoc itemIssue = null;
134                 try {
135                     itemIssue = delegator.findByAnd("ItemIssuance", UtilMisc.toMap("orderId", orderId, "orderItemSeqId", orderItemSeqId));
136                 } catch (GenericEntityException e) {
137                     Debug.logError(e, module);
138                     throw new GeneralRuntimeException(e.getMessage());
139                 }
140                 if (itemIssue != null && itemIssue.size() > 0) {
141                     Debug.log("Found item issuance referece", module);
142                     // just use the first one for now; maybe later we can find a better way to determine which was the
143
// actual item being returned; maybe by serial number
144
GenericValue issue = EntityUtil.getFirst(itemIssue);
145                     GenericValue inventoryItem = null;
146                     try {
147                         inventoryItem = issue.getRelatedOne("InventoryItem");
148                     } catch (GenericEntityException e) {
149                         Debug.logError(e, module);
150                         throw new GeneralRuntimeException(e.getMessage());
151                     }
152                     if (inventoryItem != null) {
153                         Debug.log("Located inventory item - " + inventoryItem.getString("inventoryItemId"), module);
154                         if (inventoryItem.get("unitCost") != null) {
155                             itemCost = inventoryItem.getDouble("unitCost");
156                         } else {
157                             Debug.logInfo("Found item cost; but cost was null. Returning default amount (0.00)", module);
158                         }
159                     }
160                 }
161             }
162         }
163
164         Debug.log("Initial item cost - " + itemCost, module);
165         return itemCost;
166     }
167
168     // helper method for sending return notifications
169
private static Map JavaDoc sendReturnNotificationScreen(DispatchContext dctx, Map JavaDoc context, String JavaDoc emailType) {
170         GenericDelegator delegator = dctx.getDelegator();
171         LocalDispatcher dispatcher = dctx.getDispatcher();
172         GenericValue userLogin = (GenericValue) context.get("userLogin");
173         String JavaDoc returnId = (String JavaDoc) context.get("returnId");
174         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
175
176         // get the return header
177
GenericValue returnHeader = null;
178         try {
179             returnHeader = delegator.findByPrimaryKey("ReturnHeader", UtilMisc.toMap("returnId", returnId));
180         } catch (GenericEntityException e) {
181             Debug.logError(e, module);
182             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderErrorUnableToGetReturnHeaderForID", UtilMisc.toMap("returnId",returnId), locale));
183         }
184
185         // get the return items
186
List JavaDoc returnItems = null;
187         try {
188             returnItems = returnHeader.getRelated("ReturnItem");
189         } catch (GenericEntityException e) {
190             Debug.logError(e, module);
191             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderErrorUnableToGetReturnItemRecordsFromReturnHeader", locale));
192         }
193
194         // get the order header -- the first item will determine which product store to use from the order
195
String JavaDoc productStoreId = null;
196         String JavaDoc emailAddress = null;
197         if (returnItems != null && returnItems.size() > 0) {
198             GenericValue firstItem = EntityUtil.getFirst(returnItems);
199             GenericValue orderHeader = null;
200             try {
201                 orderHeader = firstItem.getRelatedOne("OrderHeader");
202             } catch (GenericEntityException e) {
203                 Debug.logError(e, module);
204                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderErrorUnableToGetOrderHeaderFromReturnItem", locale));
205             }
206
207             if (orderHeader != null && UtilValidate.isNotEmpty(orderHeader.getString("productStoreId"))) {
208                 OrderReadHelper orh = new OrderReadHelper(orderHeader);
209                 productStoreId = orh.getProductStoreId();
210                 emailAddress = orh.getOrderEmailString();
211             }
212         }
213
214         // get the email setting and send the mail
215
if (productStoreId != null && productStoreId.length() > 0) {
216             Map JavaDoc sendMap = FastMap.newInstance();
217
218             GenericValue productStoreEmail = null;
219             try {
220                 productStoreEmail = delegator.findByPrimaryKey("ProductStoreEmailSetting", UtilMisc.toMap("productStoreId", productStoreId, "emailType", emailType));
221             } catch (GenericEntityException e) {
222                 Debug.logError(e, module);
223             }
224
225             if (productStoreEmail != null && emailAddress != null) {
226                 String JavaDoc bodyScreenLocation = productStoreEmail.getString("bodyScreenLocation");
227                 if (UtilValidate.isEmpty(bodyScreenLocation)) {
228                     bodyScreenLocation = (String JavaDoc) ProductStoreWorker.getDefaultProductStoreEmailScreenLocation(emailType);
229                 }
230                 sendMap.put("bodyScreenUri", bodyScreenLocation);
231
232                 ResourceBundleMapWrapper uiLabelMap = (ResourceBundleMapWrapper) UtilProperties.getResourceBundleMap("EcommerceUiLabels", locale);
233                 uiLabelMap.addBottomResourceBundle("OrderUiLabels");
234                 uiLabelMap.addBottomResourceBundle("CommonUiLabels");
235
236                 Map JavaDoc bodyParameters = UtilMisc.toMap("returnHeader", returnHeader, "returnItems", returnItems, "uiLabelMap", uiLabelMap, "locale", locale);
237                 sendMap.put("bodyParameters", bodyParameters);
238
239                 sendMap.put("subject", productStoreEmail.getString("subject"));
240                 sendMap.put("contentType", productStoreEmail.get("contentType"));
241                 sendMap.put("sendFrom", productStoreEmail.get("fromAddress"));
242                 sendMap.put("sendCc", productStoreEmail.get("ccAddress"));
243                 sendMap.put("sendBcc", productStoreEmail.get("bccAddress"));
244                 sendMap.put("sendTo", emailAddress);
245
246                 sendMap.put("userLogin", userLogin);
247
248                 Map JavaDoc sendResp = null;
249                 try {
250                     sendResp = dispatcher.runSync("sendMailFromScreen", sendMap);
251                 } catch (GenericServiceException e) {
252                     Debug.logError(e, "Problem sending mail", module);
253                     return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderProblemSendingEmail", locale));
254                 }
255
256                 // check for errors
257
if (sendResp != null && !ServiceUtil.isError(sendResp)) {
258                     sendResp.put("emailType", emailType);
259                     return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderProblemSendingEmail", locale), null, null, sendResp);
260                 }
261                 return sendResp;
262             }
263         }
264
265         return ServiceUtil.returnFailure("No valid email setting for store");
266     }
267
268     // return request notification
269
public static Map JavaDoc sendReturnAcceptNotification(DispatchContext dctx, Map JavaDoc context) {
270         return sendReturnNotificationScreen(dctx, context, "PRDS_RTN_ACCEPT");
271     }
272
273     // return complete notification
274
public static Map JavaDoc sendReturnCompleteNotification(DispatchContext dctx, Map JavaDoc context) {
275         return sendReturnNotificationScreen(dctx, context, "PRDS_RTN_COMPLETE");
276     }
277
278     // return cancel notification
279
public static Map JavaDoc sendReturnCancelNotification(DispatchContext dctx, Map JavaDoc context) {
280         return sendReturnNotificationScreen(dctx, context, "PRDS_RTN_CANCEL");
281     }
282
283     // get the returnable quantiy for an order item
284
public static Map JavaDoc getReturnableQuantity(DispatchContext dctx, Map JavaDoc context) {
285         GenericDelegator delegator = dctx.getDelegator();
286         GenericValue orderItem = (GenericValue) context.get("orderItem");
287         GenericValue product = null;
288         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
289         if (orderItem.get("productId") != null) {
290             try {
291                 product = orderItem.getRelatedOne("Product");
292             } catch (GenericEntityException e) {
293                 Debug.logError(e, "ERROR: Unable to get Product from OrderItem", module);
294             }
295         }
296
297         // check returnable status
298
boolean returnable = true;
299
300         // first check returnable flag
301
if (product != null && product.get("returnable") != null &&
302                 "N".equalsIgnoreCase(product.getString("returnable"))) {
303             // the product is not returnable at all
304
returnable = false;
305         }
306
307         // next check support discontinuation
308
if (product != null && product.get("supportDiscontinuationDate") != null &&
309                 !UtilDateTime.nowTimestamp().before(product.getTimestamp("supportDiscontinuationDate"))) {
310             // support discontinued either now or in the past
311
returnable = false;
312         }
313
314         String JavaDoc itemStatus = orderItem.getString("statusId");
315         double orderQty = orderItem.getDouble("quantity").doubleValue();
316         if (orderItem.getDouble("cancelQuantity") != null) {
317             orderQty -= orderItem.getDouble("cancelQuantity").doubleValue();
318         }
319
320         // get the returnable quantity
321
double returnableQuantity = 0.00;
322         if (returnable && itemStatus.equals("ITEM_COMPLETED")) {
323             List JavaDoc returnedItems = null;
324             try {
325                 returnedItems = orderItem.getRelated("ReturnItem");
326             } catch (GenericEntityException e) {
327                 Debug.logError(e, module);
328                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorUnableToGetReturnItemInformation", locale));
329             }
330             if (returnedItems == null || returnedItems.size() == 0) {
331                 returnableQuantity = orderQty;
332             } else {
333                 double returnedQty = 0.00;
334                 Iterator JavaDoc ri = returnedItems.iterator();
335                 while (ri.hasNext()) {
336                     GenericValue returnItem = (GenericValue) ri.next();
337                     GenericValue returnHeader = null;
338                     try {
339                         returnHeader = returnItem.getRelatedOne("ReturnHeader");
340                     } catch (GenericEntityException e) {
341                         Debug.logError(e, module);
342                         return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorUnableToGetReturnHeaderFromItem", locale));
343                     }
344                     String JavaDoc returnStatus = returnHeader.getString("statusId");
345                     if (!returnStatus.equals("RETURN_CANCELLED")) {
346                         returnedQty += returnItem.getDouble("returnQuantity").doubleValue();
347                     }
348                 }
349                 if (returnedQty < orderQty) {
350                     returnableQuantity = orderQty - returnedQty;
351                 }
352             }
353         }
354
355         // get the returnable price now equals to orderItem.unitPrice, since adjustments are booked separately
356

357         Map JavaDoc result = ServiceUtil.returnSuccess();
358         result.put("returnableQuantity", new Double JavaDoc(returnableQuantity));
359         result.put("returnablePrice", orderItem.get("unitPrice"));
360         return result;
361     }
362
363     // get a map of returnable items (items not already returned) and quantities
364
public static Map JavaDoc getReturnableItems(DispatchContext dctx, Map JavaDoc context) {
365         LocalDispatcher dispatcher = dctx.getDispatcher();
366         GenericDelegator delegator = dctx.getDelegator();
367         String JavaDoc orderId = (String JavaDoc) context.get("orderId");
368         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
369
370         GenericValue orderHeader = null;
371         try {
372             orderHeader = delegator.findByPrimaryKey("OrderHeader", UtilMisc.toMap("orderId", orderId));
373         } catch (GenericEntityException e) {
374             Debug.logError(e, module);
375             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorUnableToGetReturnItemInformation", locale));
376         }
377
378         Map JavaDoc returnable = new HashMap JavaDoc();
379         if (orderHeader != null) {
380             List JavaDoc orderItems = null;
381             try {
382                 orderItems = orderHeader.getRelatedByAnd("OrderItem", UtilMisc.toMap("statusId", "ITEM_COMPLETED"));
383             } catch (GenericEntityException e) {
384                 Debug.logError(e, module);
385                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorUnableToGetReturnHeaderFromItem", locale));
386             }
387             if (orderItems != null) {
388                 Iterator JavaDoc i = orderItems.iterator();
389                 while (i.hasNext()) {
390                     GenericValue item = (GenericValue) i.next();
391                     Map JavaDoc serviceResult = null;
392                     try {
393                         serviceResult = dispatcher.runSync("getReturnableQuantity", UtilMisc.toMap("orderItem", item));
394                     } catch (GenericServiceException e) {
395                         Debug.logError(e, module);
396                         return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorUnableToGetTheItemReturnableQuantity", locale));
397                     }
398                     if (serviceResult.containsKey(ModelService.ERROR_MESSAGE)) {
399                         return ServiceUtil.returnError((String JavaDoc) serviceResult.get(ModelService.ERROR_MESSAGE));
400                     } else {
401                         Map JavaDoc returnInfo = new HashMap JavaDoc();
402                         // first the return info (quantity/price)
403
returnInfo.put("returnableQuantity", serviceResult.get("returnableQuantity"));
404                         returnInfo.put("returnablePrice", serviceResult.get("returnablePrice"));
405
406                         // now the product type information
407
String JavaDoc itemTypeKey = "FINISHED_GOOD"; // default item type (same as invoice)
408
GenericValue product = null;
409                         if (item.get("productId") != null) {
410                             try {
411                                 product = item.getRelatedOne("Product");
412                             } catch (GenericEntityException e) {
413                                 Debug.logError(e, module);
414                                 return ServiceUtil.returnError("Unable to obtain order item information!");
415                             }
416                         }
417                         if (product != null) {
418                             itemTypeKey = product.getString("productTypeId");
419                         } else if (item != null) {
420                             itemTypeKey = item.getString("orderItemTypeId");
421                         }
422                         returnInfo.put("itemTypeKey", itemTypeKey);
423
424                         returnable.put(item, returnInfo);
425                     }
426                 }
427             } else {
428                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorNoOrderItemsFound", locale));
429             }
430         } else {
431             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorUnableToFindOrderHeader", locale));
432         }
433
434         Map JavaDoc result = ServiceUtil.returnSuccess();
435         result.put("returnableItems", returnable);
436         return result;
437     }
438
439     // check return items status and update return header status
440
public static Map JavaDoc checkReturnComplete(DispatchContext dctx, Map JavaDoc context) {
441         //appears to not be used: LocalDispatcher dispatcher = ctx.getDispatcher();
442
GenericDelegator delegator = dctx.getDelegator();
443         String JavaDoc returnId = (String JavaDoc) context.get("returnId");
444         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
445
446         GenericValue returnHeader = null;
447         List JavaDoc returnItems = null;
448         try {
449             returnHeader = delegator.findByPrimaryKey("ReturnHeader", UtilMisc.toMap("returnId", returnId));
450             if (returnHeader != null) {
451                 returnItems = returnHeader.getRelated("ReturnItem");
452             }
453         } catch (GenericEntityException e) {
454             Debug.logError(e, "Problems looking up return information", module);
455             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorGettingReturnHeaderItemInformation", locale));
456         }
457
458         // if already completed just return
459
if (returnHeader != null && returnHeader.get("statusId") != null) {
460             String JavaDoc currentStatus = returnHeader.getString("statusId");
461             if ("RETURN_COMPLETED".equals(currentStatus) || "RETURN_CANCELLED".equals(currentStatus)) {
462                 return ServiceUtil.returnSuccess();
463             }
464         }
465
466         // now; to be used for all timestamps
467
Timestamp JavaDoc now = UtilDateTime.nowTimestamp();
468
469         List JavaDoc completedItems = new ArrayList JavaDoc();
470         if (returnHeader != null && returnItems != null && returnItems.size() > 0) {
471             Iterator JavaDoc itemsIter = returnItems.iterator();
472             while (itemsIter.hasNext()) {
473                 GenericValue item = (GenericValue) itemsIter.next();
474                 String JavaDoc itemStatus = item != null ? item.getString("statusId") : null;
475                 if (itemStatus != null) {
476                     // both completed and cancelled items qualify for completed status change
477
if ("RETURN_COMPLETED".equals(itemStatus) || "RETURN_CANCELLED".equals(itemStatus)) {
478                         completedItems.add(item);
479                     }
480                 }
481             }
482
483             // if all items are completed/cancelled these should match
484
if (completedItems.size() == returnItems.size()) {
485                 List JavaDoc toStore = new LinkedList JavaDoc();
486                 returnHeader.set("statusId", "RETURN_COMPLETED");
487                 toStore.add(returnHeader);
488
489                 // create the status change history and set it to be stored
490
String JavaDoc returnStatusId = delegator.getNextSeqId("ReturnStatus").toString();
491                 GenericValue returnStatus = delegator.makeValue("ReturnStatus", UtilMisc.toMap("returnStatusId", returnStatusId));
492                 returnStatus.set("statusId", "RETURN_COMPLETED");
493                 returnStatus.set("returnId", returnId);
494                 returnStatus.set("statusDatetime", now);
495                 toStore.add(returnStatus);
496                 try {
497                     delegator.storeAll(toStore);
498                 } catch (GenericEntityException e) {
499                     Debug.logError(e, module);
500                     return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorUnableToCreateReturnStatusHistory", locale));
501                 }
502             }
503
504         }
505
506         Map JavaDoc result = ServiceUtil.returnSuccess();
507         result.put("statusId", returnHeader.get("statusId"));
508         return result;
509     }
510
511     // credit (billingAccount) return
512
public static Map JavaDoc processCreditReturn(DispatchContext dctx, Map JavaDoc context) {
513         LocalDispatcher dispatcher = dctx.getDispatcher();
514         GenericDelegator delegator = dctx.getDelegator();
515         String JavaDoc returnId = (String JavaDoc) context.get("returnId");
516         GenericValue userLogin = (GenericValue) context.get("userLogin");
517         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
518
519         GenericValue returnHeader = null;
520         List JavaDoc returnItems = null;
521         try {
522             returnHeader = delegator.findByPrimaryKey("ReturnHeader", UtilMisc.toMap("returnId", returnId));
523             if (returnHeader != null) {
524                 returnItems = returnHeader.getRelatedByAnd("ReturnItem", UtilMisc.toMap("returnTypeId", "RTN_CREDIT"));
525             }
526         } catch (GenericEntityException e) {
527             Debug.logError(e, "Problems looking up return information", module);
528             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorGettingReturnHeaderItemInformation", locale));
529         }
530
531         if (returnHeader != null && returnItems != null && returnItems.size() > 0) {
532             String JavaDoc billingAccountId = returnHeader.getString("billingAccountId");
533             String JavaDoc fromPartyId = returnHeader.getString("fromPartyId");
534             String JavaDoc toPartyId = returnHeader.getString("toPartyId");
535             
536             // make sure total refunds on a return don't exceed amount of returned orders
537
Map JavaDoc serviceResult = null;
538             try {
539                 serviceResult = dispatcher.runSync("checkPaymentAmountForRefund", UtilMisc.toMap("returnId", returnId));
540             } catch (GenericServiceException e) {
541                 Debug.logError(e, "Problem running the checkPaymentAmountForRefund service", module);
542                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemsWithCheckPaymentAmountForRefund", locale));
543             }
544             if (ServiceUtil.isError(serviceResult)) {
545                 return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult));
546             }
547             if (billingAccountId == null) {
548                 // create new BillingAccount w/ 0 balance
549
try {
550                     // Note that accountLimit must be 0.0 for store credits, because the available balance of BillingAccounts is calculated as accountLimit + sum of Payments - sum of Invoices
551
Map JavaDoc newBa = dispatcher.runSync("createBillingAccount", UtilMisc.toMap("accountLimit", new Double JavaDoc(0.00), "description", "Credit Account", "userLogin", userLogin, "accountCurrencyUomId", returnHeader.get("currencyUomId")));
552                     if (!newBa.get(ModelService.RESPONSE_MESSAGE).equals(ModelService.RESPOND_ERROR)) {
553                         billingAccountId = (String JavaDoc) newBa.get("billingAccountId");
554                         if (billingAccountId != null) {
555                             // set the role on the account
556
Map JavaDoc newBaR = dispatcher.runSync("createBillingAccountRole", UtilMisc.toMap("billingAccountId", billingAccountId, "partyId", fromPartyId, "roleTypeId", "BILL_TO_CUSTOMER", "userLogin", userLogin));
557                             if (newBaR.get(ModelService.RESPONSE_MESSAGE).equals(ModelService.RESPOND_ERROR)) {
558                                 Debug.logError("Error with createBillingAccountRole: " + newBaR.get(ModelService.ERROR_MESSAGE), module);
559                                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorWithCreateBillingAccountRole", locale) + newBaR.get(ModelService.ERROR_MESSAGE));
560                             }
561                         }
562                     } else {
563                         Debug.logError("Error with createBillingAccount: " + newBa.get(ModelService.ERROR_MESSAGE), module);
564                         return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorWithCreateBillingAccount", locale) + newBa.get(ModelService.ERROR_MESSAGE));
565                     }
566                 } catch (GenericServiceException e) {
567                     Debug.logError(e, "Problems creating BillingAccount", module);
568                     return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemsCreatingBillingAccount", locale));
569                 }
570             }
571
572             // double check; make sure we have a billingAccount
573
if (billingAccountId == null) {
574                 Debug.logError("No available billing account, none was created", module);
575                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderNoAvailableBillingAccount", locale));
576             }
577
578             // now; to be used for all timestamps
579
Timestamp JavaDoc now = UtilDateTime.nowTimestamp();
580
581             // first, compute the total credit from the return items
582
BigDecimal JavaDoc creditTotal = ZERO;
583             for (Iterator JavaDoc itemsIter = returnItems.iterator(); itemsIter.hasNext(); ) {
584                 GenericValue item = (GenericValue) itemsIter.next();
585                 BigDecimal JavaDoc quantity = item.getBigDecimal("returnQuantity");
586                 BigDecimal JavaDoc price = item.getBigDecimal("returnPrice");
587                 if (quantity == null) quantity = ZERO;
588                 if (price == null) price = ZERO;
589                 creditTotal = creditTotal.add(price.multiply(quantity).setScale(decimals, rounding));
590             }
591
592             // add the adjustments to the total
593
BigDecimal JavaDoc adjustments = new BigDecimal JavaDoc(getReturnAdjustmentTotal(delegator, UtilMisc.toMap("returnId", returnId)));
594             creditTotal = creditTotal.add(adjustments.setScale(decimals, rounding));
595
596             // create a Payment record for this credit; will look just like a normal payment
597
// However, since this payment is not a DISBURSEMENT or RECEIPT but really a matter of internal record
598
// it is of type "Other (Non-posting)"
599
String JavaDoc paymentId = delegator.getNextSeqId("Payment").toString();
600             GenericValue payment = delegator.makeValue("Payment", UtilMisc.toMap("paymentId", paymentId));
601             payment.set("paymentTypeId", "CUSTOMER_REFUND");
602             payment.set("paymentMethodTypeId", "EXT_BILLACT");
603             payment.set("partyIdFrom", toPartyId); // if you receive a return FROM someone, then you'd have to give a return TO that person
604
payment.set("partyIdTo", fromPartyId);
605             payment.set("effectiveDate", now);
606             payment.set("amount", creditTotal);
607             payment.set("comments", "Return Credit");
608             payment.set("statusId", "PMNT_CONFIRMED"); // set the status to confirmed so nothing else can happen to the payment
609
try {
610                 delegator.create(payment);
611             } catch (GenericEntityException e) {
612                 Debug.logError(e, "Problem creating Payment record", module);
613                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemCreatingPaymentRecord", locale));
614             }
615
616             // create a return item response
617
Map JavaDoc itemResponse = UtilMisc.toMap("paymentId", paymentId);
618             itemResponse.put("billingAccountId", billingAccountId);
619             itemResponse.put("responseAmount", new Double JavaDoc(creditTotal.doubleValue()));
620             itemResponse.put("responseDate", now);
621             itemResponse.put("userLogin", userLogin);
622             Map JavaDoc serviceResults = null;
623             try {
624                 serviceResults = dispatcher.runSync("createReturnItemResponse", itemResponse);
625                 if (ServiceUtil.isError(serviceResults)) {
626                     return ServiceUtil.returnError("Could not create ReturnItemResponse record", null, null, serviceResults);
627                 }
628             } catch (GenericServiceException e) {
629                 Debug.logError(e, "Problem creating ReturnItemResponse record", module);
630                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemCreatingReturnItemResponseRecord", locale));
631             }
632
633             // the resulting response ID will be associated with the return items
634
String JavaDoc itemResponseId = (String JavaDoc) serviceResults.get("returnItemResponseId");
635
636             // loop through the items again to update them and store a status change history
637
List JavaDoc toBeStored = new ArrayList JavaDoc();
638             for (Iterator JavaDoc itemsIter = returnItems.iterator(); itemsIter.hasNext(); ) {
639                 GenericValue item = (GenericValue) itemsIter.next();
640
641                 // set the response on the item and flag the item to be stored
642
item.set("returnItemResponseId", itemResponseId);
643                 item.set("statusId", "RETURN_COMPLETED");
644                 toBeStored.add(item);
645
646                 // create the status change history and set it to be stored
647
String JavaDoc returnStatusId = delegator.getNextSeqId("ReturnStatus").toString();
648                 GenericValue returnStatus = delegator.makeValue("ReturnStatus", UtilMisc.toMap("returnStatusId", returnStatusId));
649                 returnStatus.set("statusId", item.get("statusId"));
650                 returnStatus.set("returnId", item.get("returnId"));
651                 returnStatus.set("returnItemSeqId", item.get("returnItemSeqId"));
652                 returnStatus.set("statusDatetime", now);
653                 toBeStored.add(returnStatus);
654             }
655
656             // store the item changes (attached responseId)
657
try {
658                 delegator.storeAll(toBeStored);
659             } catch (GenericEntityException e) {
660                 Debug.logError(e, "Problem storing ReturnItem updates", module);
661                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemStoringReturnItemUpdates", locale));
662             }
663
664             // create the PaymentApplication for the billing account
665
String JavaDoc paId = delegator.getNextSeqId("PaymentApplication").toString();
666             GenericValue pa = delegator.makeValue("PaymentApplication", UtilMisc.toMap("paymentApplicationId", paId));
667             pa.set("paymentId", paymentId);
668             pa.set("billingAccountId", billingAccountId);
669             pa.set("amountApplied", creditTotal);
670             try {
671                 delegator.create(pa);
672             } catch (GenericEntityException e) {
673                 Debug.logError(e, "Problem creating PaymentApplication record for billing account", module);
674                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemCreatingPaymentApplicationRecord", locale));
675             }
676
677             // create the payment applications for the return invoice
678
try {
679                 serviceResults = dispatcher.runSync("createPaymentApplicationsFromReturnItemResponse",
680                         UtilMisc.toMap("returnItemResponseId", itemResponseId, "userLogin", userLogin));
681                 if (ServiceUtil.isError(serviceResults)) {
682                     return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemCreatingPaymentApplicationRecord", locale), null, null, serviceResults);
683                 }
684             } catch (GenericServiceException e) {
685                 Debug.logError(e, "Problem creating PaymentApplication records for return invoice", module);
686                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemCreatingPaymentApplicationRecord", locale));
687             }
688         }
689
690         return ServiceUtil.returnSuccess();
691     }
692
693     // refund (cash/charge) return
694
//TODO add adjustment total
695
public static Map JavaDoc processRefundReturn(DispatchContext dctx, Map JavaDoc context) {
696         GenericDelegator delegator = dctx.getDelegator();
697         LocalDispatcher dispatcher = dctx.getDispatcher();
698         String JavaDoc returnId = (String JavaDoc) context.get("returnId");
699         GenericValue userLogin = (GenericValue) context.get("userLogin");
700         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
701
702         GenericValue returnHeader = null;
703         List JavaDoc returnItems = null;
704         try {
705             returnHeader = delegator.findByPrimaryKey("ReturnHeader", UtilMisc.toMap("returnId", returnId));
706             if (returnHeader != null) {
707                 returnItems = returnHeader.getRelatedByAnd("ReturnItem", UtilMisc.toMap("returnTypeId", "RTN_REFUND"));
708             }
709         } catch (GenericEntityException e) {
710             Debug.logError(e, "Problems looking up return information", module);
711             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorGettingReturnHeaderItemInformation", locale));
712         }
713
714         if (returnHeader != null && returnItems != null && returnItems.size() > 0) {
715             Map JavaDoc itemsByOrder = new HashMap JavaDoc();
716             Map JavaDoc totalByOrder = new HashMap JavaDoc();
717             
718             // make sure total refunds on a return don't exceed amount of returned orders
719
Map JavaDoc serviceResult = null;
720             try {
721                 serviceResult = dispatcher.runSync("checkPaymentAmountForRefund", UtilMisc.toMap("returnId", returnId));
722             } catch (GenericServiceException e){
723                 Debug.logError(e, "Problem running the checkPaymentAmountForRefund service", module);
724                 return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemsWithCheckPaymentAmountForRefund", locale));
725             }
726             if (ServiceUtil.isError(serviceResult)) {
727                 return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult));
728             }
729             
730             groupReturnItemsByOrder(returnItems, itemsByOrder, totalByOrder, delegator, returnId);
731             
732             // process each one by order
733
Set JavaDoc itemSet = itemsByOrder.entrySet();
734             Iterator JavaDoc itemByOrderIt = itemSet.iterator();
735             while (itemByOrderIt.hasNext()) {
736                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) itemByOrderIt.next();
737                 String JavaDoc orderId = (String JavaDoc) entry.getKey();
738                 List JavaDoc items = (List JavaDoc) entry.getValue();
739                 Double JavaDoc orderTotal = (Double JavaDoc) totalByOrder.get(orderId);
740
741                 // get order header & payment prefs
742
GenericValue orderHeader = null;
743                 List JavaDoc orderPayPrefs = null;
744                 try {
745                     orderHeader = delegator.findByPrimaryKey("OrderHeader", UtilMisc.toMap("orderId", orderId));
746                     // sort these desending by maxAmount
747
orderPayPrefs = orderHeader.getRelated("OrderPaymentPreference", null, UtilMisc.toList("-maxAmount"));
748                 } catch (GenericEntityException e) {
749                     Debug.logError(e, "Cannot get Order details for #" + orderId, module);
750                     continue;
751                 }
752
753                 // get the payment prefs to use (will use them in order of amount charged)
754
List JavaDoc prefsToUse = new ArrayList JavaDoc();
755                 Map JavaDoc prefsAmount = new HashMap JavaDoc();
756                 double neededAmount = orderTotal.doubleValue();
757                 if (orderPayPrefs != null && orderPayPrefs.size() > 0) {
758                     Iterator JavaDoc payPrefIter = orderPayPrefs.iterator();
759                     do {
760                         GenericValue pref = (GenericValue) payPrefIter.next();
761                         Double JavaDoc maxAmount = pref.getDouble("maxAmount");
762                         String JavaDoc statusId = pref.getString("statusId");
763                         Debug.logInfo(" maxAmount:" + maxAmount +", statusId:" + statusId, module);
764                         if ("PAYMENT_SETTLED".equals(statusId)) {
765                             if (maxAmount == null || maxAmount.doubleValue() == 0.00) {
766                                 prefsToUse.add(pref);
767                                 prefsAmount.put(pref, orderTotal);
768                                 neededAmount = 0.00;
769                             } else if (maxAmount.doubleValue() > orderTotal.doubleValue()) {
770                                 prefsToUse.add(pref);
771                                 prefsAmount.put(pref, orderTotal);
772                                 neededAmount = 0.00;
773                             } else {
774                                 prefsToUse.add(pref);
775                                 if (maxAmount.doubleValue() > neededAmount) {
776                                     prefsAmount.put(pref, new Double JavaDoc(maxAmount.doubleValue() - neededAmount));
777                                 } else {
778                                     prefsAmount.put(pref, maxAmount);
779                                 }
780                                 neededAmount -= maxAmount.doubleValue();
781                             }
782                         }
783                     } while (neededAmount > 0 && payPrefIter.hasNext());
784                 }
785                 if (neededAmount != 0) {
786                     Debug.logError("Was not able to find needed payment preferences for the order RTN: " + returnId + " ORD: " + orderId, module);
787                     return ServiceUtil.returnError("Unable to refund order #" + orderId + "; there are no available payment preferences.");
788                 }
789
790                 Map JavaDoc prefSplitMap = new HashMap JavaDoc();
791                 if (prefsToUse == null || prefsToUse.size() == 0) {
792                     Debug.logError("We didn't find any possible payment prefs to use for RTN: " + returnId + " ORD: " + orderId, module);
793                     return ServiceUtil.returnError("Unable to refund order #" + orderId + "; there are no available payment preferences.");
794                 } else if (prefsToUse.size() > 1) {
795                     // we need to spit the items up to log which pref it was refunded to
796
// TODO: add the split of items for multiple payment prefs
797
} else {
798                     // single payment / single refund
799
prefSplitMap.put(prefsToUse.get(0), items);
800                 }
801
802                 // now process all items for each preference
803
Set JavaDoc prefItemSet = prefSplitMap.entrySet();
804                 Iterator JavaDoc prefItemIt = prefItemSet.iterator();
805                 while (prefItemIt.hasNext()) {
806                     Map.Entry JavaDoc prefItemEntry = (Map.Entry JavaDoc) prefItemIt.next();
807                     GenericValue orderPayPref = (GenericValue) prefItemEntry.getKey();
808                     List JavaDoc itemList = (List JavaDoc) prefItemEntry.getValue();
809
810                     // Get the refund amount as a BigDecimal due to rounding issues (the createReturnItemResponse simple method will turn 203.37999999999997 into 203.37)
811
BigDecimal JavaDoc thisRefundAmount = ZERO;
812                     Double JavaDoc thisRefundAmountDouble = (Double JavaDoc) prefsAmount.get(orderPayPref);
813                     if (thisRefundAmountDouble != null) thisRefundAmount = new BigDecimal JavaDoc(thisRefundAmountDouble.doubleValue());
814                     thisRefundAmount = thisRefundAmount.setScale(decimals, rounding);
815
816                     String JavaDoc paymentId = null;
817
818                     // this can be extended to support additional electronic types
819
List JavaDoc electronicTypes = UtilMisc.toList("CREDIT_CARD", "EFT_ACCOUNT", "GIFT_CARD");
820                     //List electronicTypes = new ArrayList();
821

822                     if (electronicTypes.contains(orderPayPref.getString("paymentMethodTypeId"))) {
823                         // call the refund service to refund the payment
824
try {
825                             serviceResult = dispatcher.runSync("refundPayment", UtilMisc.toMap("orderPaymentPreference", orderPayPref, "refundAmount", new Double JavaDoc(thisRefundAmount.doubleValue()), "userLogin", userLogin));
826                             if (ServiceUtil.isError(serviceResult)) {
827                                 return ServiceUtil.returnError("Error in refund payment", null, null, serviceResult);
828                             }
829
830                             paymentId = (String JavaDoc) serviceResult.get("paymentId");
831                         } catch (GenericServiceException e) {
832                             Debug.logError(e, "Problem running the refundPayment service", module);
833                             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemsWithTheRefundSeeLogs", locale));
834                         }
835                     } else {
836                         // TODO: handle manual refunds (accounts payable)
837
}
838
839                     //Debug.log("Finished handing refund payments", module);
840

841                     // now; for all timestamps
842
Timestamp JavaDoc now = UtilDateTime.nowTimestamp();
843
844                     // fill out the data for the new ReturnItemResponse
845
Map JavaDoc response = FastMap.newInstance();
846                     response.put("orderPaymentPreferenceId", orderPayPref.getString("orderPaymentPreferenceId"));
847                     response.put("responseAmount", new Double JavaDoc(thisRefundAmount.doubleValue()));
848                     response.put("responseDate", now);
849                     response.put("userLogin", userLogin);
850                     if (paymentId != null) {
851                         // a null payment ID means no electronic refund was available; manual refund needed
852
response.put("paymentId", paymentId);
853                     }
854                     Map JavaDoc serviceResults = null;
855                     try {
856                         serviceResults = dispatcher.runSync("createReturnItemResponse", response);
857                         if (ServiceUtil.isError(serviceResults)) {
858                             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemsCreatingReturnItemResponseEntity", locale), null, null, serviceResults);
859                         }
860                     } catch (GenericServiceException e) {
861                         Debug.logError(e, "Problems creating new ReturnItemResponse entity", module);
862                         return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemsCreatingReturnItemResponseEntity", locale));
863                     }
864                     String JavaDoc responseId = (String JavaDoc) serviceResults.get("returnItemResponseId");
865
866                     // set the response on each item
867
Iterator JavaDoc itemsIter = itemList.iterator();
868                     while (itemsIter.hasNext()) {
869                         GenericValue item = (GenericValue) itemsIter.next();
870                         item.set("returnItemResponseId", responseId);
871                         item.set("statusId", "RETURN_COMPLETED");
872
873                         // create the status history
874
String JavaDoc returnStatusId = delegator.getNextSeqId("ReturnStatus");
875                         GenericValue returnStatus = delegator.makeValue("ReturnStatus", UtilMisc.toMap("returnStatusId", returnStatusId));
876                         returnStatus.set("statusId", item.get("statusId"));
877                         returnStatus.set("returnId", item.get("returnId"));
878                         returnStatus.set("returnItemSeqId", item.get("returnItemSeqId"));
879                         returnStatus.set("statusDatetime", now);
880
881                         //Debug.log("Updating item status", module);
882
try {
883                             item.store();
884                             delegator.create(returnStatus);
885                         } catch (GenericEntityException e) {
886                             Debug.logError("Problem updating the ReturnItem entity", module);
887                             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemUpdatingReturnItemReturnItemResponseId", locale));
888                         }
889
890                         //Debug.log("Item status and return status history created", module);
891
}
892
893                     // create the payment applications for the return invoice
894
try {
895                         serviceResults = dispatcher.runSync("createPaymentApplicationsFromReturnItemResponse",
896                                 UtilMisc.toMap("returnItemResponseId", responseId, "userLogin", userLogin));
897                         if (ServiceUtil.isError(serviceResults)) {
898                             return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemUpdatingReturnItemReturnItemResponseId", locale), null, null, serviceResults);
899                         }
900                     } catch (GenericServiceException e) {
901                         Debug.logError(e, "Problem creating PaymentApplication records for return invoice", module);
902                         return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderProblemUpdatingReturnItemReturnItemResponseId", locale));
903                     }
904                 }
905             }
906         }
907
908         return ServiceUtil.returnSuccess();
909     }
910
911     public static Map JavaDoc createPaymentApplicationsFromReturnItemResponse(DispatchContext dctx, Map JavaDoc context) {
912         LocalDispatcher dispatcher = dctx.getDispatcher();
913         GenericDelegator delegator = dctx.getDelegator();
914         GenericValue userLogin = (GenericValue) context.get("userLogin");
915
916         // the strategy for this service is to get a list of return invoices via the return items -> return item billing relationships
917
// then split up the responseAmount among the invoices evenly
918
String JavaDoc responseId = (String JavaDoc) context.get("returnItemResponseId");
919         String JavaDoc errorMsg = "Failed to create payment applications for return item response [" + responseId + "]. ";
920         try {
921             GenericValue response = delegator.findByPrimaryKey("ReturnItemResponse", UtilMisc.toMap("returnItemResponseId", responseId));
922             if (response == null) {
923                 return ServiceUtil.returnError(errorMsg + "Return Item Response not found with ID [" + responseId + "].");
924             }
925             BigDecimal JavaDoc responseAmount = response.getBigDecimal("responseAmount").setScale(decimals, rounding);
926             String JavaDoc paymentId = response.getString("paymentId");
927
928             // for each return item in the response, get the list of return item billings and then a list of invoices
929
Map JavaDoc returnInvoices = FastMap.newInstance(); // key is invoiceId, value is Invoice GenericValue
930
List JavaDoc items = response.getRelated("ReturnItem");
931             for (Iterator JavaDoc itemIter = items.iterator(); itemIter.hasNext(); ) {
932                 GenericValue item = (GenericValue) itemIter.next();
933                 List JavaDoc billings = item.getRelated("ReturnItemBilling");
934                 for (Iterator JavaDoc billIter = billings.iterator(); billIter.hasNext(); ) {
935                     GenericValue billing = (GenericValue) billIter.next();
936                     GenericValue invoice = billing.getRelatedOne("Invoice");
937
938                     // put the invoice in the map if it doesn't already exist (a very loopy way of doing group by invoiceId without creating a view)
939
if (returnInvoices.get(invoice.getString("invoiceId")) == null) {
940                         returnInvoices.put(invoice.getString("invoiceId"), invoice);
941                     }
942                 }
943             }
944
945             // for each return invoice found, sum up the related billings
946
Map JavaDoc invoiceTotals = FastMap.newInstance(); // key is invoiceId, value is the sum of all billings for that invoice
947
BigDecimal JavaDoc grandTotal = ZERO; // The sum of all return invoice totals
948
for (Iterator JavaDoc iter = returnInvoices.values().iterator(); iter.hasNext(); ) {
949                 GenericValue invoice = (GenericValue) iter.next();
950
951                 List JavaDoc billings = invoice.getRelated("ReturnItemBilling");
952                 BigDecimal JavaDoc runningTotal = ZERO;
953                 for (Iterator JavaDoc billIter = billings.iterator(); billIter.hasNext(); ) {
954                     GenericValue billing = (GenericValue) billIter.next();
955                     runningTotal = runningTotal.add(billing.getBigDecimal("amount").multiply(billing.getBigDecimal("quantity")).setScale(decimals, rounding));
956                 }
957
958                 invoiceTotals.put(invoice.getString("invoiceId"), runningTotal);
959                 grandTotal = grandTotal.add(runningTotal);
960             }
961
962             // now allocate responseAmount * invoiceTotal / grandTotal to each invoice
963
for (Iterator JavaDoc iter = returnInvoices.values().iterator(); iter.hasNext(); ) {
964                 GenericValue invoice = (GenericValue) iter.next();
965                 String JavaDoc invoiceId = invoice.getString("invoiceId");
966                 BigDecimal JavaDoc invoiceTotal = (BigDecimal JavaDoc) invoiceTotals.get(invoiceId);
967
968                 BigDecimal JavaDoc amountApplied = responseAmount.multiply(invoiceTotal).divide(grandTotal, decimals, rounding).setScale(decimals, rounding);
969
970                 if (paymentId != null) {
971                     // create a payment application for the invoice
972
Map JavaDoc input = UtilMisc.toMap("paymentId", paymentId, "invoiceId", invoice.getString("invoiceId"));
973                     input.put("amountApplied", new Double JavaDoc(amountApplied.doubleValue()));
974                     input.put("userLogin", userLogin);
975                     Map JavaDoc serviceResults = dispatcher.runSync("createPaymentApplication", input);
976                     if (ServiceUtil.isError(serviceResults)) {
977                         return ServiceUtil.returnError(errorMsg, null, null, serviceResults);
978                     }
979                     if (Debug.verboseOn()) { Debug.logInfo("Created PaymentApplication for response with amountApplied " + amountApplied.toString(), module); }
980                 }
981             }
982         } catch (GenericServiceException e) {
983             Debug.logError(e, errorMsg + e.getMessage(), module);
984             return ServiceUtil.returnError(errorMsg + e.getMessage());
985         } catch (GenericEntityException e) {
986             Debug.logError(e, errorMsg + e.getMessage(), module);
987             return ServiceUtil.returnError(errorMsg + e.getMessage());
988         }
989         return ServiceUtil.returnSuccess();
990     }
991
992     // replacement return (create new order adjusted to be at no charge)
993
public static Map JavaDoc processReplacementReturn(DispatchContext dctx, Map JavaDoc context) {
994         LocalDispatcher dispatcher = dctx.getDispatcher();
995         GenericDelegator delegator = dctx.getDelegator();
996         String JavaDoc returnId = (String JavaDoc) context.get("returnId");
997         GenericValue userLogin = (GenericValue) context.get("userLogin");
998         Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
999
1000        GenericValue returnHeader = null;
1001        List JavaDoc returnItems = null;
1002        try {
1003            returnHeader = delegator.findByPrimaryKey("ReturnHeader", UtilMisc.toMap("returnId", returnId));
1004            if (returnHeader != null) {
1005                returnItems = returnHeader.getRelatedByAnd("ReturnItem", UtilMisc.toMap("returnTypeId", "RTN_REPLACE"));
1006            }
1007        } catch (GenericEntityException e) {
1008            Debug.logError(e, "Problems looking up return information", module);
1009            return ServiceUtil.returnError(UtilProperties.getMessage(resource_error,"OrderErrorGettingReturnHeaderItemInformation", locale));
1010        }
1011
1012        List JavaDoc createdOrderIds = new ArrayList JavaDoc();
1013        if (returnHeader != null && returnItems != null && returnItems.size() > 0) {
1014            Map JavaDoc itemsByOrder = new HashMap JavaDoc();
1015            Map JavaDoc totalByOrder = new HashMap JavaDoc();
1016            groupReturnItemsByOrder(returnItems, itemsByOrder, totalByOrder, delegator, returnId);
1017
1018            // process each one by order
1019
Set JavaDoc itemSet = itemsByOrder.entrySet();
1020            Iterator JavaDoc itemByOrderIt = itemSet.iterator();
1021            while (itemByOrderIt.hasNext()) {
1022                Map.Entry JavaDoc entry = (Map.Entry JavaDoc) itemByOrderIt.next();
1023                String JavaDoc orderId = (String JavaDoc) entry.getKey();
1024                List JavaDoc items = (List JavaDoc) entry.getValue();
1025
1026                // get order header & payment prefs
1027
GenericValue orderHeader = null;
1028                try {
1029                    orderHeader = delegator.findByPrimaryKey("OrderHeader", UtilMisc.toMap("orderId", orderId));
1030                } catch (GenericEntityException e) {
1031                    Debug.logError(e, "Cannot get Order details for #" + orderId, module);
1032                    continue;
1033                }
1034
1035                OrderReadHelper orh = new OrderReadHelper(orderHeader);
1036
1037                // create the replacement order
1038
Map JavaDoc orderMap = UtilMisc.toMap("userLogin", userLogin);
1039                GenericValue placingParty = orh.getPlacingParty();
1040                String JavaDoc placingPartyId = null;
1041                if (placingParty != null) {
1042                    placingPartyId = placingParty.getString("partyId");
1043                }
1044
1045                orderMap.put("orderTypeId", "SALES_ORDER");
1046                orderMap.put("partyId", placingPartyId);
1047                orderMap.put("productStoreId", orderHeader.get("productStoreId"));
1048                orderMap.put("webSiteId", orderHeader.get("webSiteId"));
1049                orderMap.put("visitId", orderHeader.get("visitId"));
1050                orderMap.put("currencyUom", orderHeader.get("currencyUom"));
1051                orderMap.put("grandTotal", new Double JavaDoc(0.00));
1052
1053                // make the contact mechs
1054
List JavaDoc contactMechs = new ArrayList JavaDoc();
1055                List JavaDoc orderCm = null;
1056                try {
1057                    orderCm = orderHeader.getRelated("OrderContactMech");
1058                } catch (GenericEntityException e) {
1059                    Debug.logError(e, module);
1060                }
1061                if (orderCm != null) {
1062                    Iterator JavaDoc orderCmi = orderCm.iterator();
1063                    while (orderCmi.hasNext()) {
1064                        GenericValue v = (GenericValue) orderCmi.next();
1065                        contactMechs.add(GenericValue.create(v));
1066                    }
1067                    orderMap.put("orderContactMechs", contactMechs);
1068                }
1069
1070                // make the shipment prefs
1071
List JavaDoc shipmentPrefs = new ArrayList JavaDoc();
1072                List JavaDoc orderSp = null;
1073                try {
1074                    orderSp = orderHeader.getRelated("OrderShipmentPreference");
1075                } catch (GenericEntityException e) {
1076                    Debug.logError(e, module);
1077                }
1078                if (orderSp != null) {
1079                    Iterator JavaDoc orderSpi = orderSp.iterator();
1080                    while (orderSpi.hasNext()) {
1081                        GenericValue v = (GenericValue) orderSpi.next();
1082                        shipmentPrefs.add(GenericValue.create(v));
1083                    }
1084                    orderMap.put("orderShipmentPreferences", shipmentPrefs);
1085                }
1086
1087                // make the order items
1088
double itemTotal = 0.00;
1089                List JavaDoc orderItems = new ArrayList JavaDoc();
1090                if (items != null) {
1091                    Iterator JavaDoc ri = items.iterator();
1092                    int itemCount = 1;
1093                    while (ri.hasNext()) {
1094                        GenericValue returnItem = (GenericValue) ri.next();
1095                        GenericValue orderItem = null;
1096                        try {
1097                            orderItem = returnItem.getRelatedOne("OrderItem");
1098                        } catch (GenericEntityException e) {
1099                            Debug.logError(e, module);
1100                            continue;
1101                        }
1102                        if (orderItem != null) {
1103                            Double JavaDoc quantity = returnItem.getDouble("returnQuantity");
1104                            Double JavaDoc unitPrice = returnItem.getDouble("returnPrice");
1105                            if (quantity != null && unitPrice != null) {
1106                                itemTotal = (quantity.doubleValue() * unitPrice.doubleValue());
1107                                GenericValue newItem = delegator.makeValue("OrderItem", UtilMisc.toMap("orderItemSeqId", new Integer JavaDoc(itemCount).toString()));
1108
1109                                newItem.set("orderItemTypeId", orderItem.get("orderItemTypeId"));
1110                                newItem.set("productId", orderItem.get("productId"));
1111                                newItem.set("productFeatureId", orderItem.get("productFeatureId"));
1112                                newItem.set("prodCatalogId", orderItem.get("prodCatalogId"));
1113                                newItem.set("productCategoryId", orderItem.get("productCategoryId"));
1114                                newItem.set("quantity", quantity);
1115                                newItem.set("unitPrice", unitPrice);
1116                                newItem.set("unitListPrice", orderItem.get("unitListPrice"));
1117                                newItem.set("itemDescription", orderItem.get("itemDescription"));
1118                                newItem.set("comments", orderItem.get("comments"));
1119                                newItem.set("correspondingPoId", orderItem.get("correspondingPoId"));
1120                                newItem.set("statusId", "ITEM_CREATED");
1121                                orderItems.add(newItem);
1122                            }
1123                        }
1124                    }
1125                    orderMap.put("orderItems", orderItems);
1126                } else {
1127                    Debug.logError("No return items found??", module);
1128                    continue;
1129                }
1130
1131                // create the replacement adjustment
1132
GenericValue adj = delegator.makeValue("OrderAdjustment", new HashMap JavaDoc());
1133                adj.set("orderAdjustmentTypeId", "REPLACE_ADJUSTMENT");
1134                adj.set("amount", new Double JavaDoc(itemTotal * -1));
1135                adj.set("comments", "Replacement Item Return #" + returnId);
1136                adj.set("createdDate", UtilDateTime.nowTimestamp());
1137                adj.set("createdByUserLogin", userLogin.getString("userLoginId"));
1138                orderMap.put("orderAdjustments", UtilMisc.toList(adj));
1139
1140                // we'll assume new order is under same terms as original. note orderTerms is a required parameter of storeOrder
1141
try {
1142                    orderMap.put("orderTerms", orderHeader.getRelated("OrderTerm"));
1143                } catch (GenericEntityException e) {
1144                    Debug.logError(e, "Cannot create replacement order because order terms for original order is not available", module);
1145                }
1146
1147                // create the order
1148
String JavaDoc createdOrderId = null;
1149                Map JavaDoc orderResult = null;
1150                try {
1151                    orderResult = dispatcher.runSync("storeOrder", orderMap);
1152                } catch (GenericServiceException e) {
1153                    Debug.logInfo(e, "Problem creating the order!", module);
1154                }
1155                if (orderResult != null) {
1156                    createdOrderId = (String JavaDoc) orderResult.get("orderId");
1157                    createdOrderIds.add(createdOrderId);
1158                }
1159
1160                // since there is no payments required; order is ready for processing/shipment
1161
if (createdOrderId != null) {
1162                    OrderChangeHelper.approveOrder(dispatcher, userLogin, createdOrderId);
1163                }
1164            }
1165        }
1166
1167        StringBuffer JavaDoc successMessage = new StringBuffer JavaDoc();
1168        if (createdOrderIds.size() > 0) {
1169            successMessage.append("The following new orders have been created : ");
1170            Iterator JavaDoc i = createdOrderIds.iterator();
1171            while (i.hasNext()) {
1172                successMessage.append(i.next());
1173                if (i.hasNext()) {
1174                    successMessage.append(", ");
1175                }
1176            }
1177        } else {
1178            successMessage.append("No orders were created.");
1179        }
1180
1181        return ServiceUtil.returnSuccess(successMessage.toString());
1182    }
1183
1184    /**
1185     * Takes a List of returnItems and returns a Map of orderId -> items and a Map of orderId -> orderTotal
1186     * @param returnItems
1187     * @param itemsByOrder
1188     * @param totalByOrder
1189     * @param delegator
1190     * @param returnId
1191     */

1192    public static void groupReturnItemsByOrder(List JavaDoc returnItems, Map JavaDoc itemsByOrder, Map JavaDoc totalByOrder, GenericDelegator delegator, String JavaDoc returnId) {
1193        Iterator JavaDoc itemIt = returnItems.iterator();
1194        while (itemIt.hasNext()) {
1195            GenericValue item = (GenericValue) itemIt.next();
1196            String JavaDoc orderId = item.getString("orderId");
1197            if (orderId != null) {
1198                if (itemsByOrder != null) {
1199                    List JavaDoc orderList = (List JavaDoc) itemsByOrder.get(orderId);
1200                    Double JavaDoc totalForOrder = null;
1201                    if (totalByOrder != null) {
1202                        totalForOrder = (Double JavaDoc) totalByOrder.get(orderId);
1203                    }
1204                    if (orderList == null) {
1205                        orderList = new ArrayList JavaDoc();
1206                    }
1207                    if (totalForOrder == null) {
1208                        totalForOrder = new Double JavaDoc(0.00);
1209                    }
1210
1211                    // add to the items list
1212
orderList.add(item);
1213                    itemsByOrder.put(orderId, orderList);
1214
1215                    if (totalByOrder != null) {
1216                        // add on the total for this line
1217
Double JavaDoc quantity = item.getDouble("returnQuantity");
1218                        Double JavaDoc amount = item.getDouble("returnPrice");
1219                        if (quantity == null) {
1220                            quantity = new Double JavaDoc(0);
1221                        }
1222                        if (amount == null) {
1223                            amount = new Double JavaDoc(0.00);
1224                        }
1225                        double thisTotal = amount.doubleValue() * quantity.doubleValue();
1226                        double existingTotal = totalForOrder.doubleValue();
1227                        Map JavaDoc condition = UtilMisc.toMap("returnId", item.get("returnId"), "returnItemSeqId", item.get("returnItemSeqId"));
1228                        Double JavaDoc newTotal = new Double JavaDoc(existingTotal + thisTotal + getReturnAdjustmentTotal(delegator, condition) );
1229                        totalByOrder.put(orderId, newTotal);
1230                    }
1231                }
1232            }
1233        }
1234        
1235        // We may also have some order-level adjustments, so we need to go through each order again and add those as well
1236
if ((totalByOrder != null) && (totalByOrder.keySet() != null)) {
1237            Iterator JavaDoc orderIterator = totalByOrder.keySet().iterator();
1238            while (orderIterator.hasNext()) {
1239                String JavaDoc orderId = (String JavaDoc) orderIterator.next();
1240                // find returnAdjustment for returnHeader
1241
Map JavaDoc condition = UtilMisc.toMap("returnId", returnId, "returnItemSeqId", org.ofbiz.common.DataModelConstants.SEQ_ID_NA);
1242                double existingTotal = ((Double JavaDoc) totalByOrder.get(orderId)).doubleValue() + getReturnAdjustmentTotal(delegator, condition);
1243                totalByOrder.put(orderId, new Double JavaDoc(existingTotal));
1244            }
1245        }
1246    }
1247
1248   
1249    public static Map JavaDoc getReturnAmountByOrder(DispatchContext dctx, Map JavaDoc context) {
1250        GenericDelegator delegator = dctx.getDelegator();
1251        String JavaDoc returnId = (String JavaDoc) context.get("returnId");
1252        Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
1253        List JavaDoc returnItems = null;
1254        Map JavaDoc returnAmountByOrder = new HashMap JavaDoc();
1255        try {
1256            returnItems = delegator.findByAnd("ReturnItem", UtilMisc.toMap("returnId", returnId));
1257            
1258        } catch (GenericEntityException e) {
1259            Debug.logError(e, "Problems looking up return information", module);
1260            return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderErrorGettingReturnHeaderItemInformation", locale));
1261        }
1262        if ((returnItems != null) && (returnItems.size() > 0)) {
1263            Iterator JavaDoc returnItemIterator = returnItems.iterator();
1264            GenericValue returnItem = null;
1265            GenericValue returnItemResponse = null;
1266            GenericValue payment = null;
1267            String JavaDoc orderId;
1268            List JavaDoc paymentList = new ArrayList JavaDoc();
1269            while (returnItemIterator.hasNext()) {
1270                returnItem = (GenericValue) returnItemIterator.next();
1271                orderId = returnItem.getString("orderId");
1272                try {
1273                    returnItemResponse = returnItem.getRelatedOne("ReturnItemResponse");
1274                    if ((returnItemResponse != null) && (orderId != null)) {
1275                        // TODO should we filter on payment's status (PMNT_SENT,PMNT_RECEIVED)
1276
payment = returnItemResponse.getRelatedOne("Payment");
1277                        if ((payment != null) && (payment.getDouble("amount") != null) &&
1278                                !paymentList.contains(payment.get("paymentId"))) {
1279                            UtilMisc.addToDoubleInMap(returnAmountByOrder, orderId, payment.getDouble("amount"));
1280                            paymentList.add(payment.get("paymentId")); // make sure we don't add duplicated payment amount
1281
}
1282                    }
1283                } catch (GenericEntityException e) {
1284                    Debug.logError(e, "Problems looking up return item related information", module);
1285                    return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderErrorGettingReturnHeaderItemInformation", locale));
1286                }
1287            }
1288        }
1289        return UtilMisc.toMap("orderReturnAmountMap", returnAmountByOrder);
1290    }
1291
1292    public static Map JavaDoc checkPaymentAmountForRefund(DispatchContext dctx, Map JavaDoc context) {
1293        LocalDispatcher dispatcher = dctx.getDispatcher();
1294        GenericDelegator delegator = dctx.getDelegator();
1295        String JavaDoc returnId = (String JavaDoc) context.get("returnId");
1296        Locale JavaDoc locale = (Locale JavaDoc) context.get("locale");
1297        Map JavaDoc returnAmountByOrder = null;
1298        Map JavaDoc serviceResult = null;
1299        //GenericValue orderHeader = null;
1300
try {
1301            serviceResult = dispatcher.runSync("getReturnAmountByOrder", org.ofbiz.base.util.UtilMisc.toMap("returnId", returnId));
1302        } catch (GenericServiceException e) {
1303            Debug.logError(e, "Problem running the getReturnAmountByOrder service", module);
1304            return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderProblemsWithGetReturnAmountByOrder", locale));
1305        }
1306        if (ServiceUtil.isError(serviceResult)) {
1307            return ServiceUtil.returnError((String JavaDoc) serviceResult.get(ModelService.ERROR_MESSAGE));
1308        } else {
1309            returnAmountByOrder = (Map JavaDoc) serviceResult.get("orderReturnAmountMap");
1310        }
1311
1312        if ((returnAmountByOrder != null) && (returnAmountByOrder.keySet() != null)) {
1313            Iterator JavaDoc orderIterator = returnAmountByOrder.keySet().iterator();
1314            while (orderIterator.hasNext()) {
1315                String JavaDoc orderId = (String JavaDoc) orderIterator.next();
1316                Double JavaDoc returnAmount = (Double JavaDoc) returnAmountByOrder.get(orderId);
1317                if (Math.abs(returnAmount.doubleValue()) < 0.000001) {
1318                    Debug.logError("Order [" + orderId + "] refund amount[ " + returnAmount + "] less than zero", module);
1319                    return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderReturnTotalCannotLessThanZero", locale));
1320                }
1321                OrderReadHelper helper = new OrderReadHelper(OrderReadHelper.getOrderHeader(delegator, orderId));
1322                double grandTotal = helper.getOrderGrandTotal();
1323                if (returnAmount == null) {
1324                    Debug.logInfo("No returnAmount found for order:" + orderId, module);
1325                } else {
1326                    if ((returnAmount.doubleValue() - grandTotal) > 0.01) {
1327                        Debug.logError("Order [" + orderId + "] refund amount[ " + returnAmount + "] exceeds order total [" + grandTotal + "]", module);
1328                        return ServiceUtil.returnError(UtilProperties.getMessage(resource_error, "OrderRefundAmountExceedsOrderTotal", locale));
1329                    }
1330                }
1331            }
1332        }
1333        return ServiceUtil.returnSuccess();
1334    }
1335
1336    public static Map JavaDoc createReturnAdjustment(DispatchContext dctx, Map JavaDoc context) {
1337        GenericDelegator delegator = dctx.getDelegator();
1338        String JavaDoc orderAdjustmentId = (String JavaDoc) context.get("orderAdjustmentId");
1339        String JavaDoc returnAdjustmentTypeId = (String JavaDoc) context.get("returnAdjustmentTypeId");
1340        String JavaDoc returnId = (String JavaDoc) context.get("returnId");
1341        String JavaDoc returnItemSeqId = (String JavaDoc) context.get("returnItemSeqId");
1342        String JavaDoc description = (String JavaDoc) context.get("description");
1343        
1344        GenericValue returnItemTypeMap = null;
1345        GenericValue orderAdjustment = null;
1346        GenericValue returnAdjustmentType = null;
1347        GenericValue orderItem = null;
1348        GenericValue returnItem = null;
1349        GenericValue returnHeader = null;
1350        
1351        Double JavaDoc amount;
1352        
1353        // if orderAdjustment is not empty, then copy most return adjustment information from orderAdjustment's
1354
if (orderAdjustmentId != null) {
1355            try {
1356                orderAdjustment = delegator.findByPrimaryKey("OrderAdjustment", UtilMisc.toMap("orderAdjustmentId", orderAdjustmentId));
1357
1358                // get returnHeaderTypeId from ReturnHeader and then use it to figure out return item type mapping
1359
returnHeader = delegator.findByPrimaryKey("ReturnHeader", UtilMisc.toMap("returnId", returnId));
1360                String JavaDoc returnHeaderTypeId = ((returnHeader != null) && (returnHeader.getString("returnHeaderTypeId") != null)) ? returnHeader.getString("returnHeaderTypeId") : "CUSTOMER_RETURN";
1361                returnItemTypeMap = delegator.findByPrimaryKey("ReturnItemTypeMap",
1362                        UtilMisc.toMap("returnHeaderTypeId", returnHeaderTypeId, "returnItemMapKey", orderAdjustment.get("orderAdjustmentTypeId")));
1363                returnAdjustmentType = returnItemTypeMap.getRelatedOne("ReturnAdjustmentType");
1364                if (returnAdjustmentType != null && UtilValidate.isEmpty(description)) {
1365                    description = returnAdjustmentType.getString("description");
1366                }
1367                if ((returnItemSeqId != null) && !("_NA_".equals(returnItemSeqId))) {
1368                    returnItem = delegator.findByPrimaryKey("ReturnItem",
1369                            UtilMisc.toMap("returnId", returnId, "returnItemSeqId", returnItemSeqId));
1370                    Debug.log("returnId:" + returnId + ",returnItemSeqId:" + returnItemSeqId);
1371                    orderItem = returnItem.getRelatedOne("OrderItem");
1372                }
1373            } catch (GenericEntityException e) {
1374                Debug.logError(e, module);
1375                throw new GeneralRuntimeException(e.getMessage());
1376            }
1377            context.putAll(orderAdjustment.getAllFields());
1378        }
1379
1380        // if orderAdjustmentTypeId is empty, ie not found from orderAdjustmentId, then try to get returnAdjustmentTypeId from returnItemTypeMap,
1381
// if still empty, use default RET_MAN_ADJ
1382
if (returnAdjustmentTypeId == null) {
1383            String JavaDoc mappingTypeId = returnItemTypeMap != null ? returnItemTypeMap.get("returnItemTypeId").toString() : null;
1384            returnAdjustmentTypeId = mappingTypeId != null ? mappingTypeId : "RET_MAN_ADJ";
1385        }
1386        // calculate the returnAdjustment amount
1387
if (returnItem != null) { // returnAdjustment for returnItem
1388
if (needRecalculate(returnAdjustmentTypeId)) {
1389                Debug.logInfo("returnPrice:" + returnItem.getDouble("returnPrice") + ",returnQuantity:" + returnItem.getDouble("returnQuantity") + ",sourcePercentage:" + orderAdjustment.getDouble("sourcePercentage"), module);
1390                if (orderAdjustment == null) {
1391                    Debug.logError("orderAdjustment [" + orderAdjustmentId + "] not found", module);
1392                    return ServiceUtil.returnError("orderAdjustment [" + orderAdjustmentId + "] not found");
1393                }
1394                BigDecimal JavaDoc returnTotal = returnItem.getBigDecimal("returnPrice").multiply(returnItem.getBigDecimal("returnQuantity"));
1395                BigDecimal JavaDoc orderTotal = orderItem.getBigDecimal("quantity").multiply(orderItem.getBigDecimal("unitPrice"));
1396                amount = getAdjustmentAmount("RET_SALES_TAX_ADJ".equals(returnAdjustmentType), returnTotal, orderTotal, orderAdjustment.getBigDecimal("amount"));
1397            } else {
1398                amount = (Double JavaDoc) context.get("amount");
1399            }
1400        } else { // returnAdjustment for returnHeader
1401
amount = (Double JavaDoc) context.get("amount");
1402        }
1403
1404        // store the return adjustment
1405
String JavaDoc seqId = delegator.getNextSeqId("ReturnAdjustment");
1406        GenericValue newReturnAdjustment = delegator.makeValue("ReturnAdjustment",
1407                UtilMisc.toMap("returnAdjustmentId", seqId));
1408
1409        try {
1410            newReturnAdjustment.setNonPKFields(context);
1411            if (orderAdjustment != null && orderAdjustment.get("taxAuthorityRateSeqId") != null) {
1412                newReturnAdjustment.set("taxAuthorityRateSeqId", orderAdjustment.getString("taxAuthorityRateSeqId"));
1413            }
1414            newReturnAdjustment.set("amount", amount);
1415            newReturnAdjustment.set("returnAdjustmentTypeId", returnAdjustmentTypeId);
1416            newReturnAdjustment.set("description", description);
1417            newReturnAdjustment.set("returnItemSeqId", UtilValidate.isEmpty(returnItemSeqId) ? "_NA_" : returnItemSeqId);
1418
1419            delegator.create(newReturnAdjustment);
1420            Map JavaDoc result = ServiceUtil.returnSuccess("Create ReturnAdjustment with Id:" + seqId + " successfully.");
1421            result.put("returnAdjustmentId", seqId);
1422            return result;
1423        } catch (GenericEntityException e) {
1424            Debug.logError(e, "Failed to store returnAdjustment", module);
1425            return ServiceUtil.returnError("Failed to store returnAdjustment");
1426        }
1427    }
1428
1429    public static Map JavaDoc updateReturnAdjustment(DispatchContext dctx, Map JavaDoc context) {
1430        GenericDelegator delegator = dctx.getDelegator();
1431
1432        GenericValue returnItem = null;
1433        GenericValue returnAdjustment = null;
1434        String JavaDoc returnAdjustmentTypeId = null;
1435        Double JavaDoc amount;
1436
1437
1438        try {
1439            returnAdjustment = delegator.findByPrimaryKey("ReturnAdjustment", UtilMisc.toMap("returnAdjustmentId", context.get("returnAdjustmentId")));
1440
1441            if (returnAdjustment != null) {
1442                returnItem = delegator.findByPrimaryKey("ReturnItem",
1443                        UtilMisc.toMap("returnId", returnAdjustment.get("returnId"), "returnItemSeqId", returnAdjustment.get("returnItemSeqId")));
1444                returnAdjustmentTypeId = returnAdjustment.getString("returnAdjustmentTypeId");
1445            }
1446
1447            // calculate the returnAdjustment amount
1448
if (returnItem != null) { // returnAdjustment for returnItem
1449
double originalReturnPrice = (context.get("originalReturnPrice") != null) ? ((Double JavaDoc) context.get("originalReturnPrice")).doubleValue() : returnItem.getDouble("returnPrice").doubleValue();
1450                double originalReturnQuantity = (context.get("originalReturnQuantity") != null) ? ((Double JavaDoc) context.get("originalReturnQuantity")).doubleValue() : returnItem.getDouble("returnQuantity").doubleValue();
1451
1452                if (needRecalculate(returnAdjustmentTypeId)) {
1453                    BigDecimal JavaDoc returnTotal = returnItem.getBigDecimal("returnPrice").multiply(returnItem.getBigDecimal("returnQuantity"));
1454                    BigDecimal JavaDoc originalReturnTotal = new BigDecimal JavaDoc(originalReturnPrice).multiply(new BigDecimal JavaDoc(originalReturnQuantity));
1455                    amount = getAdjustmentAmount("RET_SALES_TAX_ADJ".equals(returnAdjustmentTypeId), returnTotal, originalReturnTotal, returnAdjustment.getBigDecimal("amount"));
1456                } else {
1457                    amount = (Double JavaDoc) context.get("amount");
1458                }
1459            } else { // returnAdjustment for returnHeader
1460
amount = (Double JavaDoc) context.get("amount");
1461            }
1462
1463            returnAdjustment.setNonPKFields(context);
1464            returnAdjustment.set("amount", amount);
1465            delegator.store(returnAdjustment);
1466            Debug.logInfo("Update ReturnAdjustment with Id:" + context.get("returnAdjustmentId") + " to amount " + amount +" successfully.", module);
1467            Map JavaDoc result = ServiceUtil.returnSuccess("Update ReturnAdjustment with Id:" + context.get("returnAdjustmentId") + " to amount " + amount +" successfully.");
1468            return result;
1469        } catch (GenericEntityException e) {
1470            Debug.logError(e, "Failed to store returnAdjustment", module);
1471            return ServiceUtil.returnError("Failed to store returnAdjustment");
1472        }
1473    }
1474
1475    // used as a dispatch service, invoke different service based on the parameters passed in
1476
public static Map JavaDoc createReturnItemOrAdjustment(DispatchContext dctx, Map JavaDoc context){
1477        Debug.logInfo("createReturnItemOrAdjustment's context:" + context, module);
1478        String JavaDoc orderItemSeqId = (String JavaDoc) context.get("orderItemSeqId");
1479        Debug.logInfo("orderItemSeqId:" + orderItemSeqId +"#", module);
1480        LocalDispatcher dispatcher = dctx.getDispatcher();
1481        //if the request is to create returnItem, orderItemSeqId should not be empty
1482
String JavaDoc serviceName = UtilValidate.isNotEmpty(orderItemSeqId) ? "createReturnItem" : "createReturnAdjustment";
1483        Debug.logInfo("serviceName:" + serviceName, module);
1484        try {
1485            return dispatcher.runSync(serviceName, filterServiceContext(dctx, serviceName, context));
1486        } catch (org.ofbiz.service.GenericServiceException e) {
1487            Debug.logError(e, module);
1488            return ServiceUtil.returnError(e.getMessage());
1489        }
1490    }
1491    
1492    // used as a dispatch service, invoke different service based on the parameters passed in
1493
public static Map JavaDoc updateReturnItemOrAdjustment(DispatchContext dctx, Map JavaDoc context){
1494        Debug.logInfo("updateReturnItemOrAdjustment's context:" + context, module);
1495        String JavaDoc returnAdjustmentId = (String JavaDoc) context.get("returnAdjustmentId");
1496        Debug.logInfo("returnAdjustmentId:" + returnAdjustmentId +"#", module);
1497        LocalDispatcher dispatcher = dctx.getDispatcher();
1498        //if the request is to create returnItem, orderItemSeqId should not be empty
1499
String JavaDoc serviceName = UtilValidate.isEmpty(returnAdjustmentId) ? "updateReturnItem" : "updateReturnAdjustment";
1500        Debug.logInfo("serviceName:" + serviceName, module);
1501        try {
1502            return dispatcher.runSync(serviceName, filterServiceContext(dctx, serviceName, context));
1503        } catch (org.ofbiz.service.GenericServiceException e) {
1504            Debug.logError(e, module);
1505            return ServiceUtil.returnError(e.getMessage());
1506        }
1507    }
1508    
1509    /**
1510     * These return adjustment types need to be recalculated when the return item is updated
1511     * @param returnAdjustmentTypeId
1512     * @return
1513     */

1514    public static boolean needRecalculate(String JavaDoc returnAdjustmentTypeId) {
1515        return "RET_PROMOTION_ADJ".equals(returnAdjustmentTypeId) ||
1516                "RET_DISCOUNT_ADJ".equals(returnAdjustmentTypeId) ||
1517                "RET_SALES_TAX_ADJ".equals(returnAdjustmentTypeId);
1518
1519    }
1520
1521    /**
1522     * Get the total return adjustments for a set of key -> value condition pairs. Done for code efficiency.
1523     * @param delegator
1524     * @param condition
1525     * @return
1526     */

1527    public static double getReturnAdjustmentTotal(GenericDelegator delegator, Map JavaDoc condition) {
1528        double total = 0.0;
1529        List JavaDoc adjustments;
1530        try {
1531            // TODO: find on a view-entity with a sum is probably more efficient
1532
adjustments = delegator.findByAnd("ReturnAdjustment", condition);
1533            if (adjustments != null) {
1534                Iterator JavaDoc adjustmentIterator = adjustments.iterator();
1535                while (adjustmentIterator.hasNext()) {
1536                    GenericValue returnAdjustment = (GenericValue) adjustmentIterator.next();
1537                    total += returnAdjustment.getDouble("amount").doubleValue();
1538                }
1539            }
1540        } catch (org.ofbiz.entity.GenericEntityException e) {
1541            Debug.logError(e, module);
1542        }
1543        return total;
1544    }
1545
1546    /**
1547     * Get rid of unnecessary parameters based on the given service name
1548     * @param dctx Service DispatchContext
1549     * @param serviceName
1550     * @param context context before clean up
1551     * @return filtered context
1552     * @throws GenericServiceException
1553     */

1554    public static Map JavaDoc filterServiceContext(DispatchContext dctx, String JavaDoc serviceName, Map JavaDoc context) throws GenericServiceException {
1555        ModelService modelService = dctx.getModelService(serviceName);
1556
1557        if (modelService == null) {
1558            throw new GenericServiceException("Problems getting the service model");
1559        }
1560        Map JavaDoc serviceContext = FastMap.newInstance();
1561        List JavaDoc modelParmInList = modelService.getInModelParamList();
1562        Iterator JavaDoc modelParmInIter = modelParmInList.iterator();
1563        while (modelParmInIter.hasNext()) {
1564            ModelParam modelParam = (ModelParam) modelParmInIter.next();
1565            String JavaDoc paramName = modelParam.name;
1566 
1567            Object JavaDoc value = context.get(paramName);
1568            if(value != null){
1569                serviceContext.put(paramName, value);
1570            }
1571        }
1572        return serviceContext;
1573    }
1574
1575    /**
1576     * Calculate new returnAdjustment amount and set scale and rounding mode based on returnAdjustmentType: RET_SALES_TAX_ADJ use sales.tax._ and others use order._
1577     * @param isSalesTax if returnAdjustmentType is SaleTax
1578     * @param returnTotal
1579     * @param originalTotal
1580     * @param amount
1581     * @return new returnAdjustment amount
1582     */

1583    public static Double JavaDoc getAdjustmentAmount(boolean isSalesTax, BigDecimal JavaDoc returnTotal, BigDecimal JavaDoc originalTotal, BigDecimal JavaDoc amount) {
1584        String JavaDoc settingPrefix = isSalesTax ? "salestax" : "order";
1585        String JavaDoc decimalsPrefix = isSalesTax ? ".calc" : "";
1586        int decimals = UtilNumber.getBigDecimalScale(settingPrefix + decimalsPrefix + ".decimals");
1587        int rounding = UtilNumber.getBigDecimalRoundingMode(settingPrefix + ".rounding");
1588        int finalDecimals = isSalesTax ? UtilNumber.getBigDecimalScale(settingPrefix + ".final.decimals") : decimals;
1589        returnTotal = returnTotal.setScale(decimals, rounding);
1590        originalTotal = originalTotal.setScale(decimals, rounding);
1591        BigDecimal JavaDoc newAmount = returnTotal.divide(originalTotal, decimals, rounding).multiply(amount).setScale(finalDecimals, rounding);
1592        return new Double JavaDoc(newAmount.doubleValue());
1593    }
1594}
1595
Popular Tags