Source Code Cross Referenced for OrderReturnServices.java in  » ERP-CRM-Financial » ofbiz » org » ofbiz » order » order » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » ofbiz » org.ofbiz.order.order 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * Licensed to the Apache Software Foundation (ASF) under one
0003:         * or more contributor license agreements.  See the NOTICE file
0004:         * distributed with this work for additional information
0005:         * regarding copyright ownership.  The ASF licenses this file
0006:         * to you under the Apache License, Version 2.0 (the
0007:         * "License"); you may not use this file except in compliance
0008:         * with the License.  You may obtain a copy of the License at
0009:         * 
0010:         * http://www.apache.org/licenses/LICENSE-2.0
0011:         * 
0012:         * Unless required by applicable law or agreed to in writing,
0013:         * software distributed under the License is distributed on an
0014:         * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015:         * KIND, either express or implied.  See the License for the
0016:         * specific language governing permissions and limitations
0017:         * under the License.
0018:         *******************************************************************************/package org.ofbiz.order.order;
0019:
0020:        import java.math.BigDecimal;
0021:        import java.sql.Timestamp;
0022:        import java.util.ArrayList;
0023:        import java.util.HashMap;
0024:        import java.util.Iterator;
0025:        import java.util.LinkedList;
0026:        import java.util.List;
0027:        import java.util.Locale;
0028:        import java.util.Map;
0029:        import java.util.Set;
0030:
0031:        import javolution.util.FastMap;
0032:        import javolution.util.FastList;
0033:
0034:        import org.ofbiz.base.util.Debug;
0035:        import org.ofbiz.base.util.GeneralRuntimeException;
0036:        import org.ofbiz.base.util.UtilDateTime;
0037:        import org.ofbiz.base.util.UtilFormatOut;
0038:        import org.ofbiz.base.util.UtilMisc;
0039:        import org.ofbiz.base.util.UtilNumber;
0040:        import org.ofbiz.base.util.UtilProperties;
0041:        import org.ofbiz.base.util.UtilValidate;
0042:        import org.ofbiz.base.util.collections.ResourceBundleMapWrapper;
0043:        import org.ofbiz.entity.GenericDelegator;
0044:        import org.ofbiz.entity.GenericEntityException;
0045:        import org.ofbiz.entity.GenericValue;
0046:        import org.ofbiz.entity.condition.EntityConditionList;
0047:        import org.ofbiz.entity.condition.EntityExpr;
0048:        import org.ofbiz.entity.condition.EntityOperator;
0049:        import org.ofbiz.entity.util.EntityUtil;
0050:        import org.ofbiz.product.store.ProductStoreWorker;
0051:        import org.ofbiz.service.DispatchContext;
0052:        import org.ofbiz.service.GenericServiceException;
0053:        import org.ofbiz.service.LocalDispatcher;
0054:        import org.ofbiz.service.ModelParam;
0055:        import org.ofbiz.service.ModelService;
0056:        import org.ofbiz.service.ServiceUtil;
0057:
0058:        /**
0059:         * OrderReturnServices
0060:         */
0061:        public class OrderReturnServices {
0062:
0063:            public static final String module = OrderReturnServices.class
0064:                    .getName();
0065:            public static final String resource = "OrderUiLabels";
0066:            public static final String resource_error = "OrderErrorUiLabels";
0067:
0068:            //  set some BigDecimal properties
0069:            private static BigDecimal ZERO = new BigDecimal("0");
0070:            private static int decimals = -1;
0071:            private static int rounding = -1;
0072:            static {
0073:                decimals = UtilNumber.getBigDecimalScale("invoice.decimals");
0074:                rounding = UtilNumber
0075:                        .getBigDecimalRoundingMode("invoice.rounding");
0076:
0077:                // set zero to the proper scale
0078:                if (decimals != -1)
0079:                    ZERO = ZERO.setScale(decimals);
0080:            }
0081:
0082:            // locate the return item's initial inventory item cost
0083:            public static Map getReturnItemInitialCost(DispatchContext dctx,
0084:                    Map context) {
0085:                GenericDelegator delegator = dctx.getDelegator();
0086:                String returnId = (String) context.get("returnId");
0087:                String returnItemSeqId = (String) context
0088:                        .get("returnItemSeqId");
0089:
0090:                Map result = ServiceUtil.returnSuccess();
0091:                result.put("initialItemCost", getReturnItemInitialCost(
0092:                        delegator, returnId, returnItemSeqId));
0093:                return result;
0094:            }
0095:
0096:            // obtain order/return total information
0097:            public static Map getOrderAvailableReturnedTotal(
0098:                    DispatchContext dctx, Map context) {
0099:                GenericDelegator delegator = dctx.getDelegator();
0100:                String orderId = (String) context.get("orderId");
0101:                OrderReadHelper orh = null;
0102:                try {
0103:                    orh = new OrderReadHelper(delegator, orderId);
0104:                } catch (IllegalArgumentException e) {
0105:                    return ServiceUtil.returnError(e.getMessage());
0106:                }
0107:
0108:                // an adjustment value to test
0109:                BigDecimal adj = (BigDecimal) context.get("adjustment");
0110:                if (adj == null) {
0111:                    adj = ZERO;
0112:                }
0113:
0114:                Boolean countNewReturnItems = (Boolean) context
0115:                        .get("countNewReturnItems");
0116:                if (countNewReturnItems == null) {
0117:                    countNewReturnItems = Boolean.FALSE;
0118:                }
0119:                BigDecimal returnTotal = orh
0120:                        .getOrderReturnedTotalBd(countNewReturnItems
0121:                                .booleanValue());
0122:                BigDecimal orderTotal = orh.getOrderGrandTotalBd();
0123:                BigDecimal available = orderTotal.subtract(returnTotal)
0124:                        .subtract(adj);
0125:
0126:                Map result = ServiceUtil.returnSuccess();
0127:                result.put("availableReturnTotal", available);
0128:                result.put("orderTotal", orderTotal);
0129:                result.put("returnTotal", returnTotal);
0130:                return result;
0131:            }
0132:
0133:            // worker method which can be used in screen iterations
0134:            public static Double getReturnItemInitialCost(
0135:                    GenericDelegator delegator, String returnId,
0136:                    String returnItemSeqId) {
0137:                if (delegator == null || returnId == null
0138:                        || returnItemSeqId == null) {
0139:                    throw new IllegalArgumentException(
0140:                            "Method parameters cannot contain nulls");
0141:                }
0142:                Debug.log("Finding the initial item cost for return item : "
0143:                        + returnId + " / " + returnItemSeqId, module);
0144:
0145:                // the cost holder
0146:                Double itemCost = new Double(0.00);
0147:
0148:                // get the return item information
0149:                GenericValue returnItem = null;
0150:                try {
0151:                    returnItem = delegator.findByPrimaryKey("ReturnItem",
0152:                            UtilMisc.toMap("returnId", returnId,
0153:                                    "returnItemSeqId", returnItemSeqId));
0154:                } catch (GenericEntityException e) {
0155:                    Debug.logError(e, module);
0156:                    throw new GeneralRuntimeException(e.getMessage());
0157:                }
0158:                Debug.log("Return item value object - " + returnItem, module);
0159:
0160:                // check for an orderItem association
0161:                if (returnItem != null) {
0162:                    String orderId = returnItem.getString("orderId");
0163:                    String orderItemSeqId = returnItem
0164:                            .getString("orderItemSeqId");
0165:                    if (orderItemSeqId != null && orderId != null) {
0166:                        Debug.log("Found order item reference", module);
0167:                        // locate the item issuance(s) for this order item
0168:                        List itemIssue = null;
0169:                        try {
0170:                            itemIssue = delegator.findByAnd("ItemIssuance",
0171:                                    UtilMisc.toMap("orderId", orderId,
0172:                                            "orderItemSeqId", orderItemSeqId));
0173:                        } catch (GenericEntityException e) {
0174:                            Debug.logError(e, module);
0175:                            throw new GeneralRuntimeException(e.getMessage());
0176:                        }
0177:                        if (itemIssue != null && itemIssue.size() > 0) {
0178:                            Debug.log("Found item issuance referece", module);
0179:                            // just use the first one for now; maybe later we can find a better way to determine which was the
0180:                            // actual item being returned; maybe by serial number
0181:                            GenericValue issue = EntityUtil.getFirst(itemIssue);
0182:                            GenericValue inventoryItem = null;
0183:                            try {
0184:                                inventoryItem = issue
0185:                                        .getRelatedOne("InventoryItem");
0186:                            } catch (GenericEntityException e) {
0187:                                Debug.logError(e, module);
0188:                                throw new GeneralRuntimeException(e
0189:                                        .getMessage());
0190:                            }
0191:                            if (inventoryItem != null) {
0192:                                Debug.log("Located inventory item - "
0193:                                        + inventoryItem
0194:                                                .getString("inventoryItemId"),
0195:                                        module);
0196:                                if (inventoryItem.get("unitCost") != null) {
0197:                                    itemCost = inventoryItem
0198:                                            .getDouble("unitCost");
0199:                                } else {
0200:                                    Debug
0201:                                            .logInfo(
0202:                                                    "Found item cost; but cost was null. Returning default amount (0.00)",
0203:                                                    module);
0204:                                }
0205:                            }
0206:                        }
0207:                    }
0208:                }
0209:
0210:                Debug.log("Initial item cost - " + itemCost, module);
0211:                return itemCost;
0212:            }
0213:
0214:            // helper method for sending return notifications
0215:            private static Map sendReturnNotificationScreen(
0216:                    DispatchContext dctx, Map context, String emailType) {
0217:                GenericDelegator delegator = dctx.getDelegator();
0218:                LocalDispatcher dispatcher = dctx.getDispatcher();
0219:                GenericValue userLogin = (GenericValue) context
0220:                        .get("userLogin");
0221:                String returnId = (String) context.get("returnId");
0222:                Locale locale = (Locale) context.get("locale");
0223:
0224:                // get the return header
0225:                GenericValue returnHeader = null;
0226:                try {
0227:                    returnHeader = delegator.findByPrimaryKey("ReturnHeader",
0228:                            UtilMisc.toMap("returnId", returnId));
0229:                } catch (GenericEntityException e) {
0230:                    Debug.logError(e, module);
0231:                    return ServiceUtil.returnError(UtilProperties.getMessage(
0232:                            resource_error,
0233:                            "OrderErrorUnableToGetReturnHeaderForID", UtilMisc
0234:                                    .toMap("returnId", returnId), locale));
0235:                }
0236:
0237:                // get the return items
0238:                List returnItems = null;
0239:                try {
0240:                    returnItems = returnHeader.getRelated("ReturnItem");
0241:                } catch (GenericEntityException e) {
0242:                    Debug.logError(e, module);
0243:                    return ServiceUtil
0244:                            .returnError(UtilProperties
0245:                                    .getMessage(
0246:                                            resource_error,
0247:                                            "OrderErrorUnableToGetReturnItemRecordsFromReturnHeader",
0248:                                            locale));
0249:                }
0250:
0251:                // get the order header -- the first item will determine which product store to use from the order
0252:                String productStoreId = null;
0253:                String emailAddress = null;
0254:                if (returnItems != null && returnItems.size() > 0) {
0255:                    GenericValue firstItem = EntityUtil.getFirst(returnItems);
0256:                    GenericValue orderHeader = null;
0257:                    try {
0258:                        orderHeader = firstItem.getRelatedOne("OrderHeader");
0259:                    } catch (GenericEntityException e) {
0260:                        Debug.logError(e, module);
0261:                        return ServiceUtil
0262:                                .returnError(UtilProperties
0263:                                        .getMessage(
0264:                                                resource_error,
0265:                                                "OrderErrorUnableToGetOrderHeaderFromReturnItem",
0266:                                                locale));
0267:                    }
0268:
0269:                    if (orderHeader != null
0270:                            && UtilValidate.isNotEmpty(orderHeader
0271:                                    .getString("productStoreId"))) {
0272:                        OrderReadHelper orh = new OrderReadHelper(orderHeader);
0273:                        productStoreId = orh.getProductStoreId();
0274:                        emailAddress = orh.getOrderEmailString();
0275:                    }
0276:                }
0277:
0278:                // get the email setting and send the mail
0279:                if (productStoreId != null && productStoreId.length() > 0) {
0280:                    Map sendMap = FastMap.newInstance();
0281:
0282:                    GenericValue productStoreEmail = null;
0283:                    try {
0284:                        productStoreEmail = delegator.findByPrimaryKey(
0285:                                "ProductStoreEmailSetting", UtilMisc.toMap(
0286:                                        "productStoreId", productStoreId,
0287:                                        "emailType", emailType));
0288:                    } catch (GenericEntityException e) {
0289:                        Debug.logError(e, module);
0290:                    }
0291:
0292:                    if (productStoreEmail != null && emailAddress != null) {
0293:                        String bodyScreenLocation = productStoreEmail
0294:                                .getString("bodyScreenLocation");
0295:                        if (UtilValidate.isEmpty(bodyScreenLocation)) {
0296:                            bodyScreenLocation = ProductStoreWorker
0297:                                    .getDefaultProductStoreEmailScreenLocation(emailType);
0298:                        }
0299:                        sendMap.put("bodyScreenUri", bodyScreenLocation);
0300:
0301:                        ResourceBundleMapWrapper uiLabelMap = (ResourceBundleMapWrapper) UtilProperties
0302:                                .getResourceBundleMap("EcommerceUiLabels",
0303:                                        locale);
0304:                        uiLabelMap.addBottomResourceBundle("OrderUiLabels");
0305:                        uiLabelMap.addBottomResourceBundle("CommonUiLabels");
0306:
0307:                        Map bodyParameters = UtilMisc.toMap("returnHeader",
0308:                                returnHeader, "returnItems", returnItems,
0309:                                "uiLabelMap", uiLabelMap, "locale", locale);
0310:                        sendMap.put("bodyParameters", bodyParameters);
0311:
0312:                        sendMap.put("subject", productStoreEmail
0313:                                .getString("subject"));
0314:                        sendMap.put("contentType", productStoreEmail
0315:                                .get("contentType"));
0316:                        sendMap.put("sendFrom", productStoreEmail
0317:                                .get("fromAddress"));
0318:                        sendMap.put("sendCc", productStoreEmail
0319:                                .get("ccAddress"));
0320:                        sendMap.put("sendBcc", productStoreEmail
0321:                                .get("bccAddress"));
0322:                        sendMap.put("sendTo", emailAddress);
0323:
0324:                        sendMap.put("userLogin", userLogin);
0325:
0326:                        Map sendResp = null;
0327:                        try {
0328:                            sendResp = dispatcher.runSync("sendMailFromScreen",
0329:                                    sendMap);
0330:                        } catch (GenericServiceException e) {
0331:                            Debug.logError(e, "Problem sending mail", module);
0332:                            return ServiceUtil
0333:                                    .returnError(UtilProperties.getMessage(
0334:                                            resource_error,
0335:                                            "OrderProblemSendingEmail", locale));
0336:                        }
0337:
0338:                        // check for errors
0339:                        if (sendResp != null && ServiceUtil.isError(sendResp)) {
0340:                            sendResp.put("emailType", emailType);
0341:                            return ServiceUtil
0342:                                    .returnError(
0343:                                            UtilProperties.getMessage(
0344:                                                    resource_error,
0345:                                                    "OrderProblemSendingEmail",
0346:                                                    locale), null, null,
0347:                                            sendResp);
0348:                        }
0349:                        return ServiceUtil.returnSuccess();
0350:                    }
0351:                }
0352:
0353:                return ServiceUtil
0354:                        .returnFailure("No valid email setting for store");
0355:            }
0356:
0357:            // return request notification
0358:            public static Map sendReturnAcceptNotification(
0359:                    DispatchContext dctx, Map context) {
0360:                return sendReturnNotificationScreen(dctx, context,
0361:                        "PRDS_RTN_ACCEPT");
0362:            }
0363:
0364:            // return complete notification
0365:            public static Map sendReturnCompleteNotification(
0366:                    DispatchContext dctx, Map context) {
0367:                return sendReturnNotificationScreen(dctx, context,
0368:                        "PRDS_RTN_COMPLETE");
0369:            }
0370:
0371:            // return cancel notification
0372:            public static Map sendReturnCancelNotification(
0373:                    DispatchContext dctx, Map context) {
0374:                return sendReturnNotificationScreen(dctx, context,
0375:                        "PRDS_RTN_CANCEL");
0376:            }
0377:
0378:            // get the returnable quantiy for an order item
0379:            public static Map getReturnableQuantity(DispatchContext dctx,
0380:                    Map context) {
0381:                GenericValue orderItem = (GenericValue) context
0382:                        .get("orderItem");
0383:                GenericValue product = null;
0384:                Locale locale = (Locale) context.get("locale");
0385:                if (orderItem.get("productId") != null) {
0386:                    try {
0387:                        product = orderItem.getRelatedOne("Product");
0388:                    } catch (GenericEntityException e) {
0389:                        Debug.logError(e,
0390:                                "ERROR: Unable to get Product from OrderItem",
0391:                                module);
0392:                    }
0393:                }
0394:
0395:                // check returnable status
0396:                boolean returnable = true;
0397:
0398:                // first check returnable flag
0399:                if (product != null
0400:                        && product.get("returnable") != null
0401:                        && "N"
0402:                                .equalsIgnoreCase(product
0403:                                        .getString("returnable"))) {
0404:                    // the product is not returnable at all
0405:                    returnable = false;
0406:                }
0407:
0408:                // next check support discontinuation
0409:                if (product != null
0410:                        && product.get("supportDiscontinuationDate") != null
0411:                        && !UtilDateTime
0412:                                .nowTimestamp()
0413:                                .before(
0414:                                        product
0415:                                                .getTimestamp("supportDiscontinuationDate"))) {
0416:                    // support discontinued either now or in the past
0417:                    returnable = false;
0418:                }
0419:
0420:                String itemStatus = orderItem.getString("statusId");
0421:                double orderQty = orderItem.getDouble("quantity").doubleValue();
0422:                if (orderItem.getDouble("cancelQuantity") != null) {
0423:                    orderQty -= orderItem.getDouble("cancelQuantity")
0424:                            .doubleValue();
0425:                }
0426:
0427:                // get the returnable quantity
0428:                double returnableQuantity = 0.00;
0429:                if (returnable
0430:                        && (itemStatus.equals("ITEM_APPROVED") || itemStatus
0431:                                .equals("ITEM_COMPLETED"))) {
0432:                    List returnedItems = null;
0433:                    try {
0434:                        returnedItems = orderItem.getRelated("ReturnItem");
0435:                    } catch (GenericEntityException e) {
0436:                        Debug.logError(e, module);
0437:                        return ServiceUtil
0438:                                .returnError(UtilProperties
0439:                                        .getMessage(
0440:                                                resource_error,
0441:                                                "OrderErrorUnableToGetReturnItemInformation",
0442:                                                locale));
0443:                    }
0444:                    if (returnedItems == null || returnedItems.size() == 0) {
0445:                        returnableQuantity = orderQty;
0446:                    } else {
0447:                        double returnedQty = 0.00;
0448:                        Iterator ri = returnedItems.iterator();
0449:                        while (ri.hasNext()) {
0450:                            GenericValue returnItem = (GenericValue) ri.next();
0451:                            GenericValue returnHeader = null;
0452:                            try {
0453:                                returnHeader = returnItem
0454:                                        .getRelatedOne("ReturnHeader");
0455:                            } catch (GenericEntityException e) {
0456:                                Debug.logError(e, module);
0457:                                return ServiceUtil
0458:                                        .returnError(UtilProperties
0459:                                                .getMessage(
0460:                                                        resource_error,
0461:                                                        "OrderErrorUnableToGetReturnHeaderFromItem",
0462:                                                        locale));
0463:                            }
0464:                            String returnStatus = returnHeader
0465:                                    .getString("statusId");
0466:                            if (!returnStatus.equals("RETURN_CANCELLED")) {
0467:                                returnedQty += returnItem.getDouble(
0468:                                        "returnQuantity").doubleValue();
0469:                            }
0470:                        }
0471:                        if (returnedQty < orderQty) {
0472:                            returnableQuantity = orderQty - returnedQty;
0473:                        }
0474:                    }
0475:                }
0476:
0477:                // get the returnable price now equals to orderItem.unitPrice, since adjustments are booked separately
0478:
0479:                Map result = ServiceUtil.returnSuccess();
0480:                result
0481:                        .put("returnableQuantity", new Double(
0482:                                returnableQuantity));
0483:                result.put("returnablePrice", orderItem.get("unitPrice"));
0484:                return result;
0485:            }
0486:
0487:            // get a map of returnable items (items not already returned) and quantities
0488:            public static Map getReturnableItems(DispatchContext dctx,
0489:                    Map context) {
0490:                LocalDispatcher dispatcher = dctx.getDispatcher();
0491:                GenericDelegator delegator = dctx.getDelegator();
0492:                String orderId = (String) context.get("orderId");
0493:                Locale locale = (Locale) context.get("locale");
0494:
0495:                GenericValue orderHeader = null;
0496:                try {
0497:                    orderHeader = delegator.findByPrimaryKey("OrderHeader",
0498:                            UtilMisc.toMap("orderId", orderId));
0499:                } catch (GenericEntityException e) {
0500:                    Debug.logError(e, module);
0501:                    return ServiceUtil.returnError(UtilProperties.getMessage(
0502:                            resource_error,
0503:                            "OrderErrorUnableToGetReturnItemInformation",
0504:                            locale));
0505:                }
0506:
0507:                Map returnable = new HashMap();
0508:                if (orderHeader != null) {
0509:
0510:                    // OrderItems which have been issued may be returned.
0511:                    EntityConditionList whereConditions = new EntityConditionList(
0512:                            UtilMisc.toList(new EntityExpr("orderId",
0513:                                    EntityOperator.EQUALS, orderHeader
0514:                                            .getString("orderId")),
0515:                                    new EntityExpr("orderItemStatusId",
0516:                                            EntityOperator.IN, UtilMisc.toList(
0517:                                                    "ITEM_APPROVED",
0518:                                                    "ITEM_COMPLETED"))),
0519:                            EntityOperator.AND);
0520:                    EntityConditionList havingConditions = new EntityConditionList(
0521:                            UtilMisc
0522:                                    .toList(new EntityExpr("quantityIssued",
0523:                                            EntityOperator.GREATER_THAN,
0524:                                            new Double(0))), EntityOperator.AND);
0525:                    List orderItemQuantitiesIssued = null;
0526:                    try {
0527:                        orderItemQuantitiesIssued = delegator.findByCondition(
0528:                                "OrderItemQuantityReportGroupByItem",
0529:                                whereConditions, havingConditions, UtilMisc
0530:                                        .toList("orderId", "orderItemSeqId"),
0531:                                UtilMisc.toList("orderItemSeqId"), null);
0532:                    } catch (GenericEntityException e) {
0533:                        Debug.logError(e, module);
0534:                        return ServiceUtil
0535:                                .returnError(UtilProperties
0536:                                        .getMessage(
0537:                                                resource_error,
0538:                                                "OrderErrorUnableToGetReturnHeaderFromItem",
0539:                                                locale));
0540:                    }
0541:                    if (orderItemQuantitiesIssued != null) {
0542:                        Iterator i = orderItemQuantitiesIssued.iterator();
0543:                        while (i.hasNext()) {
0544:                            GenericValue orderItemQuantityIssued = (GenericValue) i
0545:                                    .next();
0546:                            GenericValue item = null;
0547:                            try {
0548:                                item = orderItemQuantityIssued
0549:                                        .getRelatedOne("OrderItem");
0550:                            } catch (GenericEntityException e) {
0551:                                Debug.logError(e, module);
0552:                                return ServiceUtil
0553:                                        .returnError(UtilProperties
0554:                                                .getMessage(
0555:                                                        resource_error,
0556:                                                        "OrderErrorUnableToGetOrderItemInformation",
0557:                                                        locale));
0558:                            }
0559:                            Map serviceResult = null;
0560:                            try {
0561:                                serviceResult = dispatcher.runSync(
0562:                                        "getReturnableQuantity", UtilMisc
0563:                                                .toMap("orderItem", item));
0564:                            } catch (GenericServiceException e) {
0565:                                Debug.logError(e, module);
0566:                                return ServiceUtil
0567:                                        .returnError(UtilProperties
0568:                                                .getMessage(
0569:                                                        resource_error,
0570:                                                        "OrderErrorUnableToGetTheItemReturnableQuantity",
0571:                                                        locale));
0572:                            }
0573:                            if (serviceResult
0574:                                    .containsKey(ModelService.ERROR_MESSAGE)) {
0575:                                return ServiceUtil
0576:                                        .returnError((String) serviceResult
0577:                                                .get(ModelService.ERROR_MESSAGE));
0578:                            } else {
0579:
0580:                                // Don't add the OrderItem to the map of returnable OrderItems if there isn't any returnable quantity.
0581:                                if (((Double) serviceResult
0582:                                        .get("returnableQuantity"))
0583:                                        .doubleValue() == 0) {
0584:                                    continue;
0585:                                }
0586:                                Map returnInfo = new HashMap();
0587:                                // first the return info (quantity/price)
0588:                                returnInfo
0589:                                        .put(
0590:                                                "returnableQuantity",
0591:                                                serviceResult
0592:                                                        .get("returnableQuantity"));
0593:                                returnInfo.put("returnablePrice", serviceResult
0594:                                        .get("returnablePrice"));
0595:
0596:                                // now the product type information
0597:                                String itemTypeKey = "FINISHED_GOOD"; // default item type (same as invoice)
0598:                                GenericValue product = null;
0599:                                if (item.get("productId") != null) {
0600:                                    try {
0601:                                        product = item.getRelatedOne("Product");
0602:                                    } catch (GenericEntityException e) {
0603:                                        Debug.logError(e, module);
0604:                                        return ServiceUtil
0605:                                                .returnError("Unable to obtain order item information!");
0606:                                    }
0607:                                }
0608:                                if (product != null) {
0609:                                    itemTypeKey = product
0610:                                            .getString("productTypeId");
0611:                                } else if (item != null
0612:                                        && item.getString("orderItemTypeId") != null) {
0613:                                    itemTypeKey = item
0614:                                            .getString("orderItemTypeId");
0615:                                }
0616:                                returnInfo.put("itemTypeKey", itemTypeKey);
0617:
0618:                                returnable.put(item, returnInfo);
0619:                            }
0620:                        }
0621:                    } else {
0622:                        return ServiceUtil.returnError(UtilProperties
0623:                                .getMessage(resource_error,
0624:                                        "OrderErrorNoOrderItemsFound", locale));
0625:                    }
0626:                } else {
0627:                    return ServiceUtil.returnError(UtilProperties.getMessage(
0628:                            resource_error,
0629:                            "OrderErrorUnableToFindOrderHeader", locale));
0630:                }
0631:
0632:                Map result = ServiceUtil.returnSuccess();
0633:                result.put("returnableItems", returnable);
0634:                return result;
0635:            }
0636:
0637:            // check return items status and update return header status
0638:            public static Map checkReturnComplete(DispatchContext dctx,
0639:                    Map context) {
0640:                LocalDispatcher dispatcher = dctx.getDispatcher();
0641:                GenericDelegator delegator = dctx.getDelegator();
0642:                String returnId = (String) context.get("returnId");
0643:                Locale locale = (Locale) context.get("locale");
0644:                GenericValue userLogin = (GenericValue) context
0645:                        .get("userLogin");
0646:
0647:                GenericValue returnHeader = null;
0648:                List returnItems = null;
0649:
0650:                try {
0651:                    returnHeader = delegator.findByPrimaryKey("ReturnHeader",
0652:                            UtilMisc.toMap("returnId", returnId));
0653:                    if (returnHeader != null) {
0654:                        returnItems = returnHeader.getRelated("ReturnItem");
0655:                    }
0656:                } catch (GenericEntityException e) {
0657:                    Debug.logError(e, "Problems looking up return information",
0658:                            module);
0659:                    return ServiceUtil.returnError(UtilProperties.getMessage(
0660:                            resource_error,
0661:                            "OrderErrorGettingReturnHeaderItemInformation",
0662:                            locale));
0663:                }
0664:
0665:                // if already completed just return
0666:                if (returnHeader != null
0667:                        && returnHeader.get("statusId") != null) {
0668:                    String currentStatus = returnHeader.getString("statusId");
0669:                    if ("RETURN_COMPLETED".equals(currentStatus)
0670:                            || "RETURN_CANCELLED".equals(currentStatus)) {
0671:                        return ServiceUtil.returnSuccess();
0672:                    }
0673:                }
0674:
0675:                // statusId resulting from the run of this service, which will be modified if we set it to completed
0676:                String resultStatusId = returnHeader.getString("statusId");
0677:
0678:                // now; to be used for all timestamps
0679:                Timestamp now = UtilDateTime.nowTimestamp();
0680:
0681:                List completedItems = new ArrayList();
0682:                if (returnHeader != null && returnItems != null
0683:                        && returnItems.size() > 0) {
0684:                    Iterator itemsIter = returnItems.iterator();
0685:                    while (itemsIter.hasNext()) {
0686:                        GenericValue item = (GenericValue) itemsIter.next();
0687:                        String itemStatus = item != null ? item
0688:                                .getString("statusId") : null;
0689:                        if (itemStatus != null) {
0690:                            // both completed and cancelled items qualify for completed status change
0691:                            if ("RETURN_COMPLETED".equals(itemStatus)
0692:                                    || "RETURN_CANCELLED".equals(itemStatus)) {
0693:                                completedItems.add(item);
0694:                            }
0695:                        }
0696:                    }
0697:
0698:                    // if all items are completed/cancelled these should match
0699:                    if (completedItems.size() == returnItems.size()) {
0700:                        resultStatusId = "RETURN_COMPLETED";
0701:
0702:                        // create the status change history and set it to be stored
0703:                        String returnStatusId = delegator
0704:                                .getNextSeqId("ReturnStatus");
0705:                        GenericValue returnStatus = delegator.makeValue(
0706:                                "ReturnStatus", UtilMisc.toMap(
0707:                                        "returnStatusId", returnStatusId));
0708:                        returnStatus.set("statusId", resultStatusId);
0709:                        returnStatus.set("returnId", returnId);
0710:                        returnStatus.set("statusDatetime", now);
0711:                        try {
0712:                            returnStatus.create();
0713:                        } catch (GenericEntityException e) {
0714:                            Debug.logError(e, module);
0715:                            return ServiceUtil
0716:                                    .returnError(UtilProperties
0717:                                            .getMessage(
0718:                                                    resource_error,
0719:                                                    "OrderErrorUnableToCreateReturnStatusHistory",
0720:                                                    locale));
0721:                        }
0722:
0723:                        // update the return header to completed
0724:                        try {
0725:                            Map tmpResult = dispatcher.runSync(
0726:                                    "updateReturnHeader", UtilMisc.toMap(
0727:                                            "returnId", returnId, "statusId",
0728:                                            resultStatusId, "userLogin",
0729:                                            userLogin));
0730:
0731:                            if (ServiceUtil.isError(tmpResult)) {
0732:                                return tmpResult;
0733:                            }
0734:                        } catch (GenericServiceException ex) {
0735:                            return ServiceUtil.returnError(ex.getMessage());
0736:                        }
0737:                    }
0738:
0739:                }
0740:
0741:                Map result = ServiceUtil.returnSuccess();
0742:                result.put("statusId", resultStatusId);
0743:                return result;
0744:            }
0745:
0746:            // credit (billingAccount) return
0747:            public static Map processCreditReturn(DispatchContext dctx,
0748:                    Map context) {
0749:                LocalDispatcher dispatcher = dctx.getDispatcher();
0750:                GenericDelegator delegator = dctx.getDelegator();
0751:                String returnId = (String) context.get("returnId");
0752:                GenericValue userLogin = (GenericValue) context
0753:                        .get("userLogin");
0754:                Locale locale = (Locale) context.get("locale");
0755:
0756:                GenericValue returnHeader = null;
0757:                List returnItems = null;
0758:                try {
0759:                    returnHeader = delegator.findByPrimaryKey("ReturnHeader",
0760:                            UtilMisc.toMap("returnId", returnId));
0761:                    if (returnHeader != null) {
0762:                        returnItems = returnHeader.getRelatedByAnd(
0763:                                "ReturnItem", UtilMisc.toMap("returnTypeId",
0764:                                        "RTN_CREDIT"));
0765:                    }
0766:                } catch (GenericEntityException e) {
0767:                    Debug.logError(e, "Problems looking up return information",
0768:                            module);
0769:                    return ServiceUtil.returnError(UtilProperties.getMessage(
0770:                            resource_error,
0771:                            "OrderErrorGettingReturnHeaderItemInformation",
0772:                            locale));
0773:                }
0774:
0775:                if (returnHeader != null && returnItems != null
0776:                        && returnItems.size() > 0) {
0777:                    String billingAccountId = returnHeader
0778:                            .getString("billingAccountId");
0779:                    String fromPartyId = returnHeader.getString("fromPartyId");
0780:                    String toPartyId = returnHeader.getString("toPartyId");
0781:
0782:                    // make sure total refunds on a return don't exceed amount of returned orders
0783:                    Map serviceResult = null;
0784:                    try {
0785:                        serviceResult = dispatcher.runSync(
0786:                                "checkPaymentAmountForRefund", UtilMisc.toMap(
0787:                                        "returnId", returnId));
0788:                    } catch (GenericServiceException e) {
0789:                        Debug
0790:                                .logError(
0791:                                        e,
0792:                                        "Problem running the checkPaymentAmountForRefund service",
0793:                                        module);
0794:                        return ServiceUtil
0795:                                .returnError(UtilProperties
0796:                                        .getMessage(
0797:                                                resource_error,
0798:                                                "OrderProblemsWithCheckPaymentAmountForRefund",
0799:                                                locale));
0800:                    }
0801:                    if (ServiceUtil.isError(serviceResult)) {
0802:                        return ServiceUtil.returnError(ServiceUtil
0803:                                .getErrorMessage(serviceResult));
0804:                    }
0805:                    if (billingAccountId == null) {
0806:                        // create new BillingAccount w/ 0 balance
0807:                        Map results = createBillingAccountFromReturn(
0808:                                returnHeader, returnItems, dctx, context);
0809:                        if (ServiceUtil.isError(results)) {
0810:                            Debug.logError("Error creating BillingAccount: "
0811:                                    + results.get(ModelService.ERROR_MESSAGE),
0812:                                    module);
0813:                            return ServiceUtil
0814:                                    .returnError(UtilProperties
0815:                                            .getMessage(
0816:                                                    resource_error,
0817:                                                    "OrderErrorWithCreateBillingAccount",
0818:                                                    locale)
0819:                                            + results
0820:                                                    .get(ModelService.ERROR_MESSAGE));
0821:                        }
0822:                        billingAccountId = (String) results
0823:                                .get("billingAccountId");
0824:                    }
0825:
0826:                    // double check; make sure we have a billingAccount
0827:                    if (billingAccountId == null) {
0828:                        Debug
0829:                                .logError(
0830:                                        "No available billing account, none was created",
0831:                                        module);
0832:                        return ServiceUtil.returnError(UtilProperties
0833:                                .getMessage(resource_error,
0834:                                        "OrderNoAvailableBillingAccount",
0835:                                        locale));
0836:                    }
0837:
0838:                    // now; to be used for all timestamps
0839:                    Timestamp now = UtilDateTime.nowTimestamp();
0840:
0841:                    // first, compute the total credit from the return items
0842:                    BigDecimal creditTotal = ZERO;
0843:                    for (Iterator itemsIter = returnItems.iterator(); itemsIter
0844:                            .hasNext();) {
0845:                        GenericValue item = (GenericValue) itemsIter.next();
0846:                        BigDecimal quantity = item
0847:                                .getBigDecimal("returnQuantity");
0848:                        BigDecimal price = item.getBigDecimal("returnPrice");
0849:                        if (quantity == null)
0850:                            quantity = ZERO;
0851:                        if (price == null)
0852:                            price = ZERO;
0853:                        creditTotal = creditTotal.add(price.multiply(quantity)
0854:                                .setScale(decimals, rounding));
0855:                    }
0856:
0857:                    // add the adjustments to the total
0858:                    BigDecimal adjustments = new BigDecimal(
0859:                            getReturnAdjustmentTotal(delegator, UtilMisc.toMap(
0860:                                    "returnId", returnId)));
0861:                    creditTotal = creditTotal.add(adjustments.setScale(
0862:                            decimals, rounding));
0863:
0864:                    // create a Payment record for this credit; will look just like a normal payment
0865:                    // However, since this payment is not a DISBURSEMENT or RECEIPT but really a matter of internal record
0866:                    // it is of type "Other (Non-posting)"
0867:                    String paymentId = delegator.getNextSeqId("Payment");
0868:                    GenericValue payment = delegator.makeValue("Payment",
0869:                            UtilMisc.toMap("paymentId", paymentId));
0870:                    payment.set("paymentTypeId", "CUSTOMER_REFUND");
0871:                    payment.set("paymentMethodTypeId", "EXT_BILLACT");
0872:                    payment.set("partyIdFrom", toPartyId); // if you receive a return FROM someone, then you'd have to give a return TO that person
0873:                    payment.set("partyIdTo", fromPartyId);
0874:                    payment.set("effectiveDate", now);
0875:                    payment.set("amount", creditTotal);
0876:                    payment.set("comments", "Return Credit");
0877:                    payment.set("statusId", "PMNT_CONFIRMED"); // set the status to confirmed so nothing else can happen to the payment
0878:                    try {
0879:                        delegator.create(payment);
0880:                    } catch (GenericEntityException e) {
0881:                        Debug.logError(e, "Problem creating Payment record",
0882:                                module);
0883:                        return ServiceUtil.returnError(UtilProperties
0884:                                .getMessage(resource_error,
0885:                                        "OrderProblemCreatingPaymentRecord",
0886:                                        locale));
0887:                    }
0888:
0889:                    // create a return item response 
0890:                    Map itemResponse = UtilMisc.toMap("paymentId", paymentId);
0891:                    itemResponse.put("billingAccountId", billingAccountId);
0892:                    itemResponse.put("responseAmount", new Double(creditTotal
0893:                            .doubleValue()));
0894:                    itemResponse.put("responseDate", now);
0895:                    itemResponse.put("userLogin", userLogin);
0896:                    Map serviceResults = null;
0897:                    try {
0898:                        serviceResults = dispatcher.runSync(
0899:                                "createReturnItemResponse", itemResponse);
0900:                        if (ServiceUtil.isError(serviceResults)) {
0901:                            return ServiceUtil
0902:                                    .returnError(
0903:                                            "Could not create ReturnItemResponse record",
0904:                                            null, null, serviceResults);
0905:                        }
0906:                    } catch (GenericServiceException e) {
0907:                        Debug.logError(e,
0908:                                "Problem creating ReturnItemResponse record",
0909:                                module);
0910:                        return ServiceUtil
0911:                                .returnError(UtilProperties
0912:                                        .getMessage(
0913:                                                resource_error,
0914:                                                "OrderProblemCreatingReturnItemResponseRecord",
0915:                                                locale));
0916:                    }
0917:
0918:                    // the resulting response ID will be associated with the return items
0919:                    String itemResponseId = (String) serviceResults
0920:                            .get("returnItemResponseId");
0921:
0922:                    // loop through the items again to update them and store a status change history
0923:                    List toBeStored = new ArrayList();
0924:                    for (Iterator itemsIter = returnItems.iterator(); itemsIter
0925:                            .hasNext();) {
0926:                        GenericValue item = (GenericValue) itemsIter.next();
0927:
0928:                        // set the response on the item and flag the item to be stored
0929:                        item.set("returnItemResponseId", itemResponseId);
0930:                        item.set("statusId", "RETURN_COMPLETED");
0931:                        toBeStored.add(item);
0932:
0933:                        // create the status change history and set it to be stored
0934:                        String returnStatusId = delegator
0935:                                .getNextSeqId("ReturnStatus");
0936:                        GenericValue returnStatus = delegator.makeValue(
0937:                                "ReturnStatus", UtilMisc.toMap(
0938:                                        "returnStatusId", returnStatusId));
0939:                        returnStatus.set("statusId", item.get("statusId"));
0940:                        returnStatus.set("returnId", item.get("returnId"));
0941:                        returnStatus.set("returnItemSeqId", item
0942:                                .get("returnItemSeqId"));
0943:                        returnStatus.set("statusDatetime", now);
0944:                        toBeStored.add(returnStatus);
0945:                    }
0946:
0947:                    // store the item changes (attached responseId)
0948:                    try {
0949:                        delegator.storeAll(toBeStored);
0950:                    } catch (GenericEntityException e) {
0951:                        Debug.logError(e, "Problem storing ReturnItem updates",
0952:                                module);
0953:                        return ServiceUtil.returnError(UtilProperties
0954:                                .getMessage(resource_error,
0955:                                        "OrderProblemStoringReturnItemUpdates",
0956:                                        locale));
0957:                    }
0958:
0959:                    // create the PaymentApplication for the billing account
0960:                    String paId = delegator.getNextSeqId("PaymentApplication");
0961:                    GenericValue pa = delegator.makeValue("PaymentApplication",
0962:                            UtilMisc.toMap("paymentApplicationId", paId));
0963:                    pa.set("paymentId", paymentId);
0964:                    pa.set("billingAccountId", billingAccountId);
0965:                    pa.set("amountApplied", creditTotal);
0966:                    try {
0967:                        delegator.create(pa);
0968:                    } catch (GenericEntityException e) {
0969:                        Debug
0970:                                .logError(
0971:                                        e,
0972:                                        "Problem creating PaymentApplication record for billing account",
0973:                                        module);
0974:                        return ServiceUtil
0975:                                .returnError(UtilProperties
0976:                                        .getMessage(
0977:                                                resource_error,
0978:                                                "OrderProblemCreatingPaymentApplicationRecord",
0979:                                                locale));
0980:                    }
0981:
0982:                    // create the payment applications for the return invoice
0983:                    try {
0984:                        serviceResults = dispatcher
0985:                                .runSync(
0986:                                        "createPaymentApplicationsFromReturnItemResponse",
0987:                                        UtilMisc.toMap("returnItemResponseId",
0988:                                                itemResponseId, "userLogin",
0989:                                                userLogin));
0990:                        if (ServiceUtil.isError(serviceResults)) {
0991:                            return ServiceUtil
0992:                                    .returnError(
0993:                                            UtilProperties
0994:                                                    .getMessage(
0995:                                                            resource_error,
0996:                                                            "OrderProblemCreatingPaymentApplicationRecord",
0997:                                                            locale), null,
0998:                                            null, serviceResults);
0999:                        }
1000:                    } catch (GenericServiceException e) {
1001:                        Debug
1002:                                .logError(
1003:                                        e,
1004:                                        "Problem creating PaymentApplication records for return invoice",
1005:                                        module);
1006:                        return ServiceUtil
1007:                                .returnError(UtilProperties
1008:                                        .getMessage(
1009:                                                resource_error,
1010:                                                "OrderProblemCreatingPaymentApplicationRecord",
1011:                                                locale));
1012:                    }
1013:                }
1014:
1015:                return ServiceUtil.returnSuccess();
1016:            }
1017:
1018:            /**
1019:             * Helper method to generate a BillingAccount (store credit) from a return 
1020:             * header.  This method takes care of all business logic relating to
1021:             * the initialization of a Billing Account from the Return data.
1022:             *
1023:             * The BillingAccount.thruDate will be set to (now + 
1024:             * ProductStore.storeCreditValidDays + end of day).  The product stores 
1025:             * are obtained via the return orders, and the minimum storeCreditValidDays
1026:             * will be used.  The default is to set thruDate to null, which implies no 
1027:             * expiration.
1028:             *
1029:             * Note that we set BillingAccount.accountLimit to 0.0 for store credits.
1030:             * This is because the available balance of BillingAccounts is 
1031:             * calculated as accountLimit + sum of Payments - sum of Invoices.
1032:             */
1033:            private static Map createBillingAccountFromReturn(
1034:                    GenericValue returnHeader, List returnItems,
1035:                    DispatchContext dctx, Map context) {
1036:                LocalDispatcher dispatcher = dctx.getDispatcher();
1037:                GenericValue userLogin = (GenericValue) context
1038:                        .get("userLogin");
1039:                Locale locale = (Locale) context.get("locale");
1040:
1041:                try {
1042:                    // get the related product stores via the orders related to this return
1043:                    List orders = EntityUtil.getRelated("OrderHeader",
1044:                            returnItems);
1045:                    List productStores = EntityUtil.getRelated("ProductStore",
1046:                            orders);
1047:
1048:                    // find the minimum storeCreditValidDays of all the ProductStores associated with all the Orders on the Return, skipping null ones
1049:                    Long storeCreditValidDays = null;
1050:                    for (Iterator iter = productStores.iterator(); iter
1051:                            .hasNext();) {
1052:                        GenericValue productStore = (GenericValue) iter.next();
1053:                        Long this StoreValidDays = productStore
1054:                                .getLong("storeCreditValidDays");
1055:                        if (this StoreValidDays == null)
1056:                            continue;
1057:
1058:                        if (storeCreditValidDays == null) {
1059:                            storeCreditValidDays = this StoreValidDays;
1060:                        } else if (this StoreValidDays
1061:                                .compareTo(storeCreditValidDays) < 0) {
1062:                            // if this store's days < store credit valid days, use this store's days
1063:                            storeCreditValidDays = this StoreValidDays;
1064:                        }
1065:                    }
1066:
1067:                    // if there is a storeCreditValidDays, set the thruDate to (nowTimestamp + storeCreditValidDays + end of day)
1068:                    Timestamp thruDate = null;
1069:                    if (storeCreditValidDays != null)
1070:                        thruDate = UtilDateTime.getDayEnd(UtilDateTime
1071:                                .nowTimestamp(), storeCreditValidDays
1072:                                .intValue());
1073:
1074:                    // create the billing account
1075:                    Map input = UtilMisc.toMap("accountLimit",
1076:                            new Double(0.00), "description",
1077:                            "Credit Account for Return #"
1078:                                    + returnHeader.get("returnId"),
1079:                            "userLogin", userLogin);
1080:                    input.put("accountCurrencyUomId", returnHeader
1081:                            .get("currencyUomId"));
1082:                    input.put("thruDate", thruDate);
1083:                    Map results = dispatcher.runSync("createBillingAccount",
1084:                            input);
1085:                    if (ServiceUtil.isError(results))
1086:                        return results;
1087:                    String billingAccountId = (String) results
1088:                            .get("billingAccountId");
1089:
1090:                    // set the role on the account
1091:                    input = UtilMisc.toMap("billingAccountId",
1092:                            billingAccountId, "partyId", returnHeader
1093:                                    .get("fromPartyId"), "roleTypeId",
1094:                            "BILL_TO_CUSTOMER", "userLogin", userLogin);
1095:                    Map roleResults = dispatcher.runSync(
1096:                            "createBillingAccountRole", input);
1097:                    if (ServiceUtil.isError(roleResults)) {
1098:                        Debug.logError("Error with createBillingAccountRole: "
1099:                                + roleResults.get(ModelService.ERROR_MESSAGE),
1100:                                module);
1101:                        return ServiceUtil
1102:                                .returnError(UtilProperties
1103:                                        .getMessage(
1104:                                                resource_error,
1105:                                                "OrderErrorWithCreateBillingAccountRole",
1106:                                                locale)
1107:                                        + roleResults
1108:                                                .get(ModelService.ERROR_MESSAGE));
1109:                    }
1110:
1111:                    return results;
1112:                } catch (GenericEntityException e) {
1113:                    Debug.logError(e,
1114:                            "Entity error when creating BillingAccount: "
1115:                                    + e.getMessage(), module);
1116:                    return ServiceUtil.returnError(UtilProperties.getMessage(
1117:                            resource_error,
1118:                            "OrderProblemsCreatingBillingAccount", locale));
1119:                } catch (GenericServiceException e) {
1120:                    Debug.logError(e,
1121:                            "Service error when creating BillingAccount: "
1122:                                    + e.getMessage(), module);
1123:                    return ServiceUtil.returnError(UtilProperties.getMessage(
1124:                            resource_error,
1125:                            "OrderProblemsCreatingBillingAccount", locale));
1126:                }
1127:            }
1128:
1129:            // refund (cash/charge) return
1130:            //TODO add adjustment total
1131:            public static Map processRefundReturn(DispatchContext dctx,
1132:                    Map context) {
1133:                GenericDelegator delegator = dctx.getDelegator();
1134:                LocalDispatcher dispatcher = dctx.getDispatcher();
1135:                String returnId = (String) context.get("returnId");
1136:                GenericValue userLogin = (GenericValue) context
1137:                        .get("userLogin");
1138:                Locale locale = (Locale) context.get("locale");
1139:
1140:                GenericValue returnHeader = null;
1141:                List returnItems = null;
1142:                try {
1143:                    returnHeader = delegator.findByPrimaryKey("ReturnHeader",
1144:                            UtilMisc.toMap("returnId", returnId));
1145:                    if (returnHeader != null) {
1146:                        returnItems = returnHeader.getRelatedByAnd(
1147:                                "ReturnItem", UtilMisc.toMap("returnTypeId",
1148:                                        "RTN_REFUND"));
1149:                    }
1150:                } catch (GenericEntityException e) {
1151:                    Debug.logError(e, "Problems looking up return information",
1152:                            module);
1153:                    return ServiceUtil.returnError(UtilProperties.getMessage(
1154:                            resource_error,
1155:                            "OrderErrorGettingReturnHeaderItemInformation",
1156:                            locale));
1157:                }
1158:
1159:                if (returnHeader != null && returnItems != null
1160:                        && returnItems.size() > 0) {
1161:                    Map itemsByOrder = new HashMap();
1162:                    Map totalByOrder = new HashMap();
1163:
1164:                    // make sure total refunds on a return don't exceed amount of returned orders
1165:                    Map serviceResult = null;
1166:                    try {
1167:                        serviceResult = dispatcher.runSync(
1168:                                "checkPaymentAmountForRefund", UtilMisc.toMap(
1169:                                        "returnId", returnId));
1170:                    } catch (GenericServiceException e) {
1171:                        Debug
1172:                                .logError(
1173:                                        e,
1174:                                        "Problem running the checkPaymentAmountForRefund service",
1175:                                        module);
1176:                        return ServiceUtil
1177:                                .returnError(UtilProperties
1178:                                        .getMessage(
1179:                                                resource_error,
1180:                                                "OrderProblemsWithCheckPaymentAmountForRefund",
1181:                                                locale));
1182:                    }
1183:                    if (ServiceUtil.isError(serviceResult)) {
1184:                        return ServiceUtil.returnError(ServiceUtil
1185:                                .getErrorMessage(serviceResult));
1186:                    }
1187:
1188:                    groupReturnItemsByOrder(returnItems, itemsByOrder,
1189:                            totalByOrder, delegator, returnId);
1190:
1191:                    // process each one by order
1192:                    Set itemSet = itemsByOrder.entrySet();
1193:                    Iterator itemByOrderIt = itemSet.iterator();
1194:                    while (itemByOrderIt.hasNext()) {
1195:                        Map.Entry entry = (Map.Entry) itemByOrderIt.next();
1196:                        String orderId = (String) entry.getKey();
1197:                        List items = (List) entry.getValue();
1198:                        Double orderTotal = (Double) totalByOrder.get(orderId);
1199:
1200:                        // get order header & payment prefs
1201:                        GenericValue orderHeader = null;
1202:                        List orderPayPrefs = null;
1203:                        try {
1204:                            orderHeader = delegator.findByPrimaryKey(
1205:                                    "OrderHeader", UtilMisc.toMap("orderId",
1206:                                            orderId));
1207:                            // sort these desending by maxAmount
1208:                            orderPayPrefs = orderHeader.getRelated(
1209:                                    "OrderPaymentPreference", UtilMisc.toMap(
1210:                                            "statusId", "PAYMENT_SETTLED"),
1211:                                    UtilMisc.toList("-maxAmount"));
1212:                        } catch (GenericEntityException e) {
1213:                            Debug.logError(e, "Cannot get Order details for #"
1214:                                    + orderId, module);
1215:                            continue;
1216:                        }
1217:                        OrderReadHelper orderReadHelper = new OrderReadHelper(
1218:                                delegator, orderId);
1219:
1220:                        // now; for all timestamps
1221:                        Timestamp now = UtilDateTime.nowTimestamp();
1222:
1223:                        // Assemble a map of orderPaymentPreferenceId -> list of maps of ( OPP and availableAmountForRefunding )
1224:                        //     where availableAmountForRefunding = receivedAmount - alreadyRefundedAmount
1225:                        // We break the OPPs down this way because we need to process the refunds to payment methods in a particular order
1226:                        Map receivedPaymentTotalsByPaymentMethod = orderReadHelper
1227:                                .getReceivedPaymentTotalsByPaymentMethod();
1228:                        Map refundedTotalsByPaymentMethod = orderReadHelper
1229:                                .getReturnedTotalsByPaymentMethod();
1230:
1231:                        /*
1232:                         * Go through the OrderPaymentPreferences and determine how much remains to be refunded for each.
1233:                         * Then group these refund amounts and orderPaymentPreferences by paymentMethodTypeId.  That is,
1234:                         * the intent is to get the refundable amounts per orderPaymentPreference, grouped by payment method type.
1235:                         */
1236:                        Map prefSplitMap = new HashMap();
1237:                        Iterator oppit = orderPayPrefs.iterator();
1238:                        while (oppit.hasNext()) {
1239:                            GenericValue orderPayPref = (GenericValue) oppit
1240:                                    .next();
1241:                            String paymentMethodTypeId = orderPayPref
1242:                                    .getString("paymentMethodTypeId");
1243:                            String orderPayPrefKey = orderPayPref
1244:                                    .getString("paymentMethodId") != null ? orderPayPref
1245:                                    .getString("paymentMethodId")
1246:                                    : orderPayPref
1247:                                            .getString("paymentMethodTypeId");
1248:
1249:                            // See how much we can refund to the payment method
1250:                            BigDecimal orderPayPrefReceivedTotal = ZERO;
1251:                            if (receivedPaymentTotalsByPaymentMethod
1252:                                    .containsKey(orderPayPrefKey)) {
1253:                                orderPayPrefReceivedTotal = orderPayPrefReceivedTotal
1254:                                        .add(new BigDecimal(
1255:                                                ((Double) receivedPaymentTotalsByPaymentMethod
1256:                                                        .get(orderPayPrefKey))
1257:                                                        .doubleValue())
1258:                                                .setScale(decimals, rounding));
1259:                            }
1260:                            BigDecimal orderPayPrefRefundedTotal = ZERO;
1261:                            if (refundedTotalsByPaymentMethod
1262:                                    .containsKey(orderPayPrefKey)) {
1263:                                orderPayPrefRefundedTotal = orderPayPrefRefundedTotal
1264:                                        .add(new BigDecimal(
1265:                                                ((Double) refundedTotalsByPaymentMethod
1266:                                                        .get(orderPayPrefKey))
1267:                                                        .doubleValue())
1268:                                                .setScale(decimals, rounding));
1269:                            }
1270:                            BigDecimal orderPayPrefAvailableTotal = orderPayPrefReceivedTotal
1271:                                    .subtract(orderPayPrefRefundedTotal);
1272:
1273:                            // add the refundable amount and orderPaymentPreference to the paymentMethodTypeId map
1274:                            if (orderPayPrefAvailableTotal.compareTo(ZERO) == 1) {
1275:                                Map orderPayPrefDetails = new HashMap();
1276:                                orderPayPrefDetails.put(
1277:                                        "orderPaymentPreference", orderPayPref);
1278:                                orderPayPrefDetails.put("availableTotal",
1279:                                        orderPayPrefAvailableTotal);
1280:                                if (prefSplitMap
1281:                                        .containsKey(paymentMethodTypeId)) {
1282:                                    ((List) prefSplitMap
1283:                                            .get(paymentMethodTypeId))
1284:                                            .add(orderPayPrefDetails);
1285:                                } else {
1286:                                    prefSplitMap
1287:                                            .put(
1288:                                                    paymentMethodTypeId,
1289:                                                    UtilMisc
1290:                                                            .toList(orderPayPrefDetails));
1291:                                }
1292:                            }
1293:                        }
1294:
1295:                        // Keep a decreasing total of the amount remaining to refund
1296:                        BigDecimal amountLeftToRefund = new BigDecimal(
1297:                                orderTotal.doubleValue()).setScale(decimals,
1298:                                rounding);
1299:
1300:                        // This can be extended to support additional electronic types
1301:                        List electronicTypes = UtilMisc.toList("CREDIT_CARD",
1302:                                "EFT_ACCOUNT", "GIFT_CARD");
1303:
1304:                        // This defines the ordered part of the sequence of refund processing
1305:                        List orderedRefundPaymentMethodTypes = new ArrayList();
1306:                        orderedRefundPaymentMethodTypes.add("EXT_BILLACT");
1307:                        orderedRefundPaymentMethodTypes.add("GIFT_CARD");
1308:                        orderedRefundPaymentMethodTypes.add("CREDIT_CARD");
1309:
1310:                        // Add all the other paymentMethodTypes, in no particular order
1311:                        EntityConditionList pmtConditionList = new EntityConditionList(
1312:                                UtilMisc.toList(new EntityExpr(
1313:                                        "paymentMethodTypeId",
1314:                                        EntityOperator.NOT_IN,
1315:                                        orderedRefundPaymentMethodTypes)),
1316:                                EntityOperator.AND);
1317:                        List otherPaymentMethodTypes = new ArrayList();
1318:                        try {
1319:                            otherPaymentMethodTypes = delegator
1320:                                    .findByConditionCache("PaymentMethodType",
1321:                                            pmtConditionList, null, null);
1322:                        } catch (GenericEntityException e) {
1323:                            Debug.logError(e, "Cannot get PaymentMethodTypes",
1324:                                    module);
1325:                            return ServiceUtil
1326:                                    .returnError("Problems getting PaymentMethodTypes: "
1327:                                            + e.toString());
1328:                        }
1329:                        orderedRefundPaymentMethodTypes.addAll(EntityUtil
1330:                                .getFieldListFromEntityList(
1331:                                        otherPaymentMethodTypes,
1332:                                        "paymentMethodTypeId", true));
1333:
1334:                        // Iterate through the specified sequence of paymentMethodTypes, refunding to the correct OrderPaymentPreferences
1335:                        //    as long as there's a positive amount remaining to refund
1336:                        Iterator orpmtit = orderedRefundPaymentMethodTypes
1337:                                .iterator();
1338:                        while (orpmtit.hasNext()
1339:                                && amountLeftToRefund.compareTo(ZERO) == 1) {
1340:                            String paymentMethodTypeId = (String) orpmtit
1341:                                    .next();
1342:                            if (prefSplitMap.containsKey(paymentMethodTypeId)) {
1343:                                List paymentMethodDetails = (List) prefSplitMap
1344:                                        .get(paymentMethodTypeId);
1345:
1346:                                // Iterate through the OrderPaymentPreferences of this type
1347:                                Iterator pmtppit = paymentMethodDetails
1348:                                        .iterator();
1349:                                while (pmtppit.hasNext()
1350:                                        && amountLeftToRefund.compareTo(ZERO) == 1) {
1351:                                    Map orderPaymentPrefDetails = (Map) pmtppit
1352:                                            .next();
1353:                                    GenericValue orderPaymentPreference = (GenericValue) orderPaymentPrefDetails
1354:                                            .get("orderPaymentPreference");
1355:                                    BigDecimal orderPaymentPreferenceAvailable = (BigDecimal) orderPaymentPrefDetails
1356:                                            .get("availableTotal");
1357:
1358:                                    // Refund up to the maxAmount for the paymentPref, or whatever is left to refund if that's less than the maxAmount
1359:                                    BigDecimal amountToRefund = orderPaymentPreferenceAvailable
1360:                                            .min(amountLeftToRefund);
1361:
1362:                                    String paymentId = null;
1363:
1364:                                    // Call the refund service to refund the payment
1365:                                    if (electronicTypes
1366:                                            .contains(paymentMethodTypeId)) {
1367:                                        try {
1368:                                            // for electronic types such as CREDIT_CARD and EFT_ACCOUNT, use refundPayment service
1369:                                            serviceResult = dispatcher
1370:                                                    .runSync(
1371:                                                            "refundPayment",
1372:                                                            UtilMisc
1373:                                                                    .toMap(
1374:                                                                            "orderPaymentPreference",
1375:                                                                            orderPaymentPreference,
1376:                                                                            "refundAmount",
1377:                                                                            new Double(
1378:                                                                                    amountToRefund
1379:                                                                                            .setScale(
1380:                                                                                                    decimals,
1381:                                                                                                    rounding)
1382:                                                                                            .doubleValue()),
1383:                                                                            "userLogin",
1384:                                                                            userLogin));
1385:                                            if (ServiceUtil
1386:                                                    .isError(serviceResult)
1387:                                                    || ServiceUtil
1388:                                                            .isFailure(serviceResult)) {
1389:                                                Debug
1390:                                                        .logError(
1391:                                                                "Error in refund payment: "
1392:                                                                        + ServiceUtil
1393:                                                                                .getErrorMessage(serviceResult),
1394:                                                                module);
1395:                                                continue;
1396:                                            }
1397:                                            paymentId = (String) serviceResult
1398:                                                    .get("paymentId");
1399:                                        } catch (GenericServiceException e) {
1400:                                            Debug
1401:                                                    .logError(
1402:                                                            e,
1403:                                                            "Problem running the refundPayment service",
1404:                                                            module);
1405:                                            return ServiceUtil
1406:                                                    .returnError(UtilProperties
1407:                                                            .getMessage(
1408:                                                                    resource_error,
1409:                                                                    "OrderProblemsWithTheRefundSeeLogs",
1410:                                                                    locale));
1411:                                        }
1412:                                    } else if (paymentMethodTypeId
1413:                                            .equals("EXT_BILLACT")) {
1414:                                        try {
1415:                                            // for Billing Account refunds
1416:                                            serviceResult = dispatcher
1417:                                                    .runSync(
1418:                                                            "refundBillingAccountPayment",
1419:                                                            UtilMisc
1420:                                                                    .toMap(
1421:                                                                            "orderPaymentPreference",
1422:                                                                            orderPaymentPreference,
1423:                                                                            "refundAmount",
1424:                                                                            new Double(
1425:                                                                                    amountToRefund
1426:                                                                                            .setScale(
1427:                                                                                                    decimals,
1428:                                                                                                    rounding)
1429:                                                                                            .doubleValue()),
1430:                                                                            "userLogin",
1431:                                                                            userLogin));
1432:                                            if (ServiceUtil
1433:                                                    .isError(serviceResult)
1434:                                                    || ServiceUtil
1435:                                                            .isFailure(serviceResult)) {
1436:                                                Debug
1437:                                                        .logError(
1438:                                                                "Error in refund payment: "
1439:                                                                        + ServiceUtil
1440:                                                                                .getErrorMessage(serviceResult),
1441:                                                                module);
1442:                                                continue;
1443:                                            }
1444:                                            paymentId = (String) serviceResult
1445:                                                    .get("paymentId");
1446:                                        } catch (GenericServiceException e) {
1447:                                            Debug
1448:                                                    .logError(
1449:                                                            e,
1450:                                                            "Problem running the refundPayment service",
1451:                                                            module);
1452:                                            return ServiceUtil
1453:                                                    .returnError(UtilProperties
1454:                                                            .getMessage(
1455:                                                                    resource_error,
1456:                                                                    "OrderProblemsWithTheRefundSeeLogs",
1457:                                                                    locale));
1458:                                        }
1459:                                    } else {
1460:                                        // TODO: handle manual refunds (accounts payable)
1461:                                    }
1462:
1463:                                    // Fill out the data for the new ReturnItemResponse
1464:                                    Map response = FastMap.newInstance();
1465:                                    response
1466:                                            .put(
1467:                                                    "orderPaymentPreferenceId",
1468:                                                    orderPaymentPreference
1469:                                                            .getString("orderPaymentPreferenceId"));
1470:                                    response.put("responseAmount", new Double(
1471:                                            amountToRefund.setScale(decimals,
1472:                                                    rounding).doubleValue()));
1473:                                    response.put("responseDate", now);
1474:                                    response.put("userLogin", userLogin);
1475:                                    if (paymentId != null) {
1476:                                        // A null payment ID means no electronic refund was available; manual refund needed
1477:                                        response.put("paymentId", paymentId);
1478:                                    }
1479:                                    if (paymentMethodTypeId
1480:                                            .equals("EXT_BILLACT")) {
1481:                                        response
1482:                                                .put(
1483:                                                        "billingAccountId",
1484:                                                        orderReadHelper
1485:                                                                .getBillingAccount()
1486:                                                                .getString(
1487:                                                                        "billingAccountId"));
1488:                                    }
1489:                                    Map serviceResults = null;
1490:                                    try {
1491:                                        serviceResults = dispatcher.runSync(
1492:                                                "createReturnItemResponse",
1493:                                                response);
1494:                                        if (ServiceUtil.isError(serviceResults)) {
1495:                                            return ServiceUtil
1496:                                                    .returnError(
1497:                                                            UtilProperties
1498:                                                                    .getMessage(
1499:                                                                            resource_error,
1500:                                                                            "OrderProblemsCreatingReturnItemResponseEntity",
1501:                                                                            locale),
1502:                                                            null, null,
1503:                                                            serviceResults);
1504:                                        }
1505:                                    } catch (GenericServiceException e) {
1506:                                        Debug
1507:                                                .logError(
1508:                                                        e,
1509:                                                        "Problems creating new ReturnItemResponse entity",
1510:                                                        module);
1511:                                        return ServiceUtil
1512:                                                .returnError(UtilProperties
1513:                                                        .getMessage(
1514:                                                                resource_error,
1515:                                                                "OrderProblemsCreatingReturnItemResponseEntity",
1516:                                                                locale));
1517:                                    }
1518:                                    String responseId = (String) serviceResults
1519:                                            .get("returnItemResponseId");
1520:
1521:                                    // Set the response on each item
1522:                                    Iterator itemsIter = items.iterator();
1523:                                    while (itemsIter.hasNext()) {
1524:                                        GenericValue item = (GenericValue) itemsIter
1525:                                                .next();
1526:                                        item.set("returnItemResponseId",
1527:                                                responseId);
1528:                                        item
1529:                                                .set("statusId",
1530:                                                        "RETURN_COMPLETED");
1531:
1532:                                        // Create the status history
1533:                                        String returnStatusId = delegator
1534:                                                .getNextSeqId("ReturnStatus");
1535:                                        GenericValue returnStatus = delegator
1536:                                                .makeValue(
1537:                                                        "ReturnStatus",
1538:                                                        UtilMisc
1539:                                                                .toMap(
1540:                                                                        "returnStatusId",
1541:                                                                        returnStatusId));
1542:                                        returnStatus.set("statusId", item
1543:                                                .get("statusId"));
1544:                                        returnStatus.set("returnId", item
1545:                                                .get("returnId"));
1546:                                        returnStatus.set("returnItemSeqId",
1547:                                                item.get("returnItemSeqId"));
1548:                                        returnStatus.set("statusDatetime", now);
1549:
1550:                                        //Debug.log("Updating item status", module);
1551:                                        try {
1552:                                            item.store();
1553:                                            delegator.create(returnStatus);
1554:                                        } catch (GenericEntityException e) {
1555:                                            Debug
1556:                                                    .logError(
1557:                                                            "Problem updating the ReturnItem entity",
1558:                                                            module);
1559:                                            return ServiceUtil
1560:                                                    .returnError(UtilProperties
1561:                                                            .getMessage(
1562:                                                                    resource_error,
1563:                                                                    "OrderProblemUpdatingReturnItemReturnItemResponseId",
1564:                                                                    locale));
1565:                                        }
1566:
1567:                                        //Debug.log("Item status and return status history created", module);
1568:                                    }
1569:
1570:                                    // Create the payment applications for the return invoice
1571:                                    try {
1572:                                        serviceResults = dispatcher
1573:                                                .runSync(
1574:                                                        "createPaymentApplicationsFromReturnItemResponse",
1575:                                                        UtilMisc
1576:                                                                .toMap(
1577:                                                                        "returnItemResponseId",
1578:                                                                        responseId,
1579:                                                                        "userLogin",
1580:                                                                        userLogin));
1581:                                        if (ServiceUtil.isError(serviceResults)) {
1582:                                            return ServiceUtil
1583:                                                    .returnError(
1584:                                                            UtilProperties
1585:                                                                    .getMessage(
1586:                                                                            resource_error,
1587:                                                                            "OrderProblemUpdatingReturnItemReturnItemResponseId",
1588:                                                                            locale),
1589:                                                            null, null,
1590:                                                            serviceResults);
1591:                                        }
1592:                                    } catch (GenericServiceException e) {
1593:                                        Debug
1594:                                                .logError(
1595:                                                        e,
1596:                                                        "Problem creating PaymentApplication records for return invoice",
1597:                                                        module);
1598:                                        return ServiceUtil
1599:                                                .returnError(UtilProperties
1600:                                                        .getMessage(
1601:                                                                resource_error,
1602:                                                                "OrderProblemUpdatingReturnItemReturnItemResponseId",
1603:                                                                locale));
1604:                                    }
1605:
1606:                                    // Update the amount necessary to refund
1607:                                    amountLeftToRefund = amountLeftToRefund
1608:                                            .subtract(amountToRefund);
1609:                                }
1610:                            }
1611:                        }
1612:
1613:                        // OFBIZ-459:  Create a "filler" payment and return item response by hand for the remaining amount, note that this won't be applied to the invoice
1614:                        if (amountLeftToRefund.compareTo(ZERO) == 1) {
1615:                            try {
1616:                                Map input = UtilMisc.toMap("userLogin",
1617:                                        userLogin, "amount", new Double(
1618:                                                amountLeftToRefund
1619:                                                        .doubleValue()),
1620:                                        "statusId", "PMNT_NOT_PAID");
1621:                                input.put("partyIdTo", returnHeader
1622:                                        .get("fromPartyId"));
1623:                                input.put("partyIdFrom", returnHeader
1624:                                        .get("toPartyId"));
1625:                                input.put("paymentTypeId", "CUSTOMER_REFUND");
1626:                                Map results = dispatcher.runSync(
1627:                                        "createPayment", input);
1628:                                if (ServiceUtil.isError(results))
1629:                                    return results;
1630:
1631:                                input = UtilMisc.toMap("userLogin", userLogin,
1632:                                        "paymentId", results.get("paymentId"),
1633:                                        "responseAmount", new Double(
1634:                                                amountLeftToRefund
1635:                                                        .doubleValue()));
1636:                                results = dispatcher.runSync(
1637:                                        "createReturnItemResponse", input);
1638:                                if (ServiceUtil.isError(results))
1639:                                    return results;
1640:                            } catch (GenericServiceException e) {
1641:                                return ServiceUtil.returnError(e.getMessage());
1642:                            }
1643:                        }
1644:                    }
1645:                }
1646:
1647:                return ServiceUtil.returnSuccess();
1648:            }
1649:
1650:            public static Map refundBillingAccountPayment(DispatchContext dctx,
1651:                    Map context) {
1652:                GenericDelegator delegator = dctx.getDelegator();
1653:                LocalDispatcher dispatcher = dctx.getDispatcher();
1654:                GenericValue userLogin = (GenericValue) context
1655:                        .get("userLogin");
1656:
1657:                GenericValue paymentPref = (GenericValue) context
1658:                        .get("orderPaymentPreference");
1659:                Double refundAmount = (Double) context.get("refundAmount");
1660:
1661:                GenericValue orderHeader = null;
1662:                try {
1663:                    orderHeader = paymentPref.getRelatedOne("OrderHeader");
1664:                } catch (GenericEntityException e) {
1665:                    Debug
1666:                            .logError(
1667:                                    e,
1668:                                    "Cannot get OrderHeader from OrderPaymentPreference",
1669:                                    module);
1670:                    return ServiceUtil
1671:                            .returnError("Problems getting OrderHeader from OrderPaymentPreference: "
1672:                                    + e.toString());
1673:                }
1674:
1675:                OrderReadHelper orh = new OrderReadHelper(orderHeader);
1676:
1677:                String payFromPartyId = orh.getBillFromParty().getString(
1678:                        "partyId");
1679:                String payToPartyId = orh.getBillToParty().getString("partyId");
1680:
1681:                // Create the PaymentGatewayResponse record
1682:                String responseId = delegator
1683:                        .getNextSeqId("PaymentGatewayResponse");
1684:                GenericValue response = delegator.makeValue(
1685:                        "PaymentGatewayResponse", null);
1686:                response.set("paymentGatewayResponseId", responseId);
1687:                response.set("paymentServiceTypeEnumId", "PRDS_PAY_REFUND");
1688:                response.set("orderPaymentPreferenceId", paymentPref
1689:                        .get("orderPaymentPreferenceId"));
1690:                response.set("paymentMethodTypeId", paymentPref
1691:                        .get("paymentMethodTypeId"));
1692:                response.set("transCodeEnumId", "PGT_REFUND");
1693:                response.set("amount", refundAmount);
1694:                response.set("transactionDate", UtilDateTime.nowTimestamp());
1695:                response.set("currencyUomId", orh.getCurrency());
1696:                try {
1697:                    delegator.create(response);
1698:                } catch (GenericEntityException e) {
1699:                    Debug.logError(e, module);
1700:                    return ServiceUtil
1701:                            .returnError("Unable to create PaymentGatewayResponse record");
1702:                }
1703:
1704:                // Create the Payment record (parties reversed)
1705:                Map paymentCtx = UtilMisc.toMap("paymentTypeId",
1706:                        "CUSTOMER_REFUND");
1707:                paymentCtx.put("paymentMethodTypeId", paymentPref
1708:                        .get("paymentMethodTypeId"));
1709:                paymentCtx.put("paymentGatewayResponseId", responseId);
1710:                paymentCtx.put("partyIdTo", payToPartyId);
1711:                paymentCtx.put("partyIdFrom", payFromPartyId);
1712:                paymentCtx.put("statusId", "PMNT_CONFIRMED");
1713:                paymentCtx.put("paymentPreferenceId", paymentPref
1714:                        .get("orderPaymentPreferenceId"));
1715:                paymentCtx.put("currencyUomId", orh.getCurrency());
1716:                paymentCtx.put("amount", refundAmount);
1717:                paymentCtx.put("userLogin", userLogin);
1718:                paymentCtx.put("comments", "Refund");
1719:
1720:                String paymentId = null;
1721:                try {
1722:                    Map paymentCreationResult = dispatcher.runSync(
1723:                            "createPayment", paymentCtx);
1724:                    if (ServiceUtil.isError(paymentCreationResult)) {
1725:                        return paymentCreationResult;
1726:                    } else {
1727:                        paymentId = (String) paymentCreationResult
1728:                                .get("paymentId");
1729:                    }
1730:                } catch (GenericServiceException e) {
1731:                    return ServiceUtil.returnError("Problem creating Payment "
1732:                            + e.getMessage());
1733:                }
1734:
1735:                if (paymentId == null) {
1736:                    return ServiceUtil.returnError("Create payment failed");
1737:                }
1738:
1739:                // if the original order was paid with a billing account, then go find the billing account from the order and associate this refund with that billing account
1740:                // thus returning value to the billing account 
1741:                if ("EXT_BILLACT".equals(paymentPref
1742:                        .getString("paymentMethodTypeId"))) {
1743:                    GenericValue billingAccount = orh.getBillingAccount();
1744:                    if (UtilValidate.isNotEmpty(billingAccount
1745:                            .getString("billingAccountId"))) {
1746:                        try {
1747:                            Map paymentApplResult = dispatcher
1748:                                    .runSync(
1749:                                            "createPaymentApplication",
1750:                                            UtilMisc
1751:                                                    .toMap(
1752:                                                            "paymentId",
1753:                                                            paymentId,
1754:                                                            "billingAccountId",
1755:                                                            billingAccount
1756:                                                                    .getString("billingAccountId"),
1757:                                                            "amountApplied",
1758:                                                            refundAmount,
1759:                                                            "userLogin",
1760:                                                            userLogin));
1761:                            if (ServiceUtil.isError(paymentApplResult)) {
1762:                                return paymentApplResult;
1763:                            }
1764:                        } catch (GenericServiceException e) {
1765:                            return ServiceUtil
1766:                                    .returnError("Problem creating PaymentApplication: "
1767:                                            + e.getMessage());
1768:                        }
1769:                    }
1770:                }
1771:
1772:                Map result = ServiceUtil.returnSuccess();
1773:                result.put("paymentId", paymentId);
1774:                return result;
1775:            }
1776:
1777:            public static Map createPaymentApplicationsFromReturnItemResponse(
1778:                    DispatchContext dctx, Map context) {
1779:                LocalDispatcher dispatcher = dctx.getDispatcher();
1780:                GenericDelegator delegator = dctx.getDelegator();
1781:                GenericValue userLogin = (GenericValue) context
1782:                        .get("userLogin");
1783:
1784:                // the strategy for this service is to get a list of return invoices via the return items -> return item billing relationships
1785:                // then split up the responseAmount among the invoices evenly
1786:                String responseId = (String) context
1787:                        .get("returnItemResponseId");
1788:                String errorMsg = "Failed to create payment applications for return item response ["
1789:                        + responseId + "]. ";
1790:                try {
1791:                    GenericValue response = delegator.findByPrimaryKey(
1792:                            "ReturnItemResponse", UtilMisc.toMap(
1793:                                    "returnItemResponseId", responseId));
1794:                    if (response == null) {
1795:                        return ServiceUtil.returnError(errorMsg
1796:                                + "Return Item Response not found with ID ["
1797:                                + responseId + "].");
1798:                    }
1799:                    BigDecimal responseAmount = response.getBigDecimal(
1800:                            "responseAmount").setScale(decimals, rounding);
1801:                    String paymentId = response.getString("paymentId");
1802:
1803:                    // for each return item in the response, get the list of return item billings and then a list of invoices
1804:                    Map returnInvoices = FastMap.newInstance(); // key is invoiceId, value is Invoice GenericValue
1805:                    List items = response.getRelated("ReturnItem");
1806:                    for (Iterator itemIter = items.iterator(); itemIter
1807:                            .hasNext();) {
1808:                        GenericValue item = (GenericValue) itemIter.next();
1809:                        List billings = item.getRelated("ReturnItemBilling");
1810:                        for (Iterator billIter = billings.iterator(); billIter
1811:                                .hasNext();) {
1812:                            GenericValue billing = (GenericValue) billIter
1813:                                    .next();
1814:                            GenericValue invoice = billing
1815:                                    .getRelatedOne("Invoice");
1816:
1817:                            // 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)
1818:                            if (returnInvoices.get(invoice
1819:                                    .getString("invoiceId")) == null) {
1820:                                returnInvoices.put(invoice
1821:                                        .getString("invoiceId"), invoice);
1822:                            }
1823:                        }
1824:                    }
1825:
1826:                    // for each return invoice found, sum up the related billings
1827:                    Map invoiceTotals = FastMap.newInstance(); // key is invoiceId, value is the sum of all billings for that invoice
1828:                    BigDecimal grandTotal = ZERO; // The sum of all return invoice totals
1829:                    for (Iterator iter = returnInvoices.values().iterator(); iter
1830:                            .hasNext();) {
1831:                        GenericValue invoice = (GenericValue) iter.next();
1832:
1833:                        List billings = invoice.getRelated("ReturnItemBilling");
1834:                        BigDecimal runningTotal = ZERO;
1835:                        for (Iterator billIter = billings.iterator(); billIter
1836:                                .hasNext();) {
1837:                            GenericValue billing = (GenericValue) billIter
1838:                                    .next();
1839:                            runningTotal = runningTotal.add(billing
1840:                                    .getBigDecimal("amount").multiply(
1841:                                            billing.getBigDecimal("quantity"))
1842:                                    .setScale(decimals, rounding));
1843:                        }
1844:
1845:                        invoiceTotals.put(invoice.getString("invoiceId"),
1846:                                runningTotal);
1847:                        grandTotal = grandTotal.add(runningTotal);
1848:                    }
1849:
1850:                    // now allocate responseAmount * invoiceTotal / grandTotal to each invoice
1851:                    for (Iterator iter = returnInvoices.values().iterator(); iter
1852:                            .hasNext();) {
1853:                        GenericValue invoice = (GenericValue) iter.next();
1854:                        String invoiceId = invoice.getString("invoiceId");
1855:                        BigDecimal invoiceTotal = (BigDecimal) invoiceTotals
1856:                                .get(invoiceId);
1857:
1858:                        BigDecimal amountApplied = responseAmount.multiply(
1859:                                invoiceTotal).divide(grandTotal, decimals,
1860:                                rounding).setScale(decimals, rounding);
1861:
1862:                        if (paymentId != null) {
1863:                            // create a payment application for the invoice
1864:                            Map input = UtilMisc
1865:                                    .toMap("paymentId", paymentId, "invoiceId",
1866:                                            invoice.getString("invoiceId"));
1867:                            input.put("amountApplied", new Double(amountApplied
1868:                                    .doubleValue()));
1869:                            input.put("userLogin", userLogin);
1870:                            if (response.get("billingAccountId") != null) {
1871:                                GenericValue billingAccount = response
1872:                                        .getRelatedOne("BillingAccount");
1873:                                if (billingAccount != null) {
1874:                                    input.put("billingAccountId", response
1875:                                            .get("billingAccountId"));
1876:                                }
1877:                            }
1878:                            Map serviceResults = dispatcher.runSync(
1879:                                    "createPaymentApplication", input);
1880:                            if (ServiceUtil.isError(serviceResults)) {
1881:                                return ServiceUtil.returnError(errorMsg, null,
1882:                                        null, serviceResults);
1883:                            }
1884:                            if (Debug.verboseOn()) {
1885:                                Debug.logInfo(
1886:                                        "Created PaymentApplication for response with amountApplied "
1887:                                                + amountApplied.toString(),
1888:                                        module);
1889:                            }
1890:                        }
1891:                    }
1892:                } catch (GenericServiceException e) {
1893:                    Debug.logError(e, errorMsg + e.getMessage(), module);
1894:                    return ServiceUtil.returnError(errorMsg + e.getMessage());
1895:                } catch (GenericEntityException e) {
1896:                    Debug.logError(e, errorMsg + e.getMessage(), module);
1897:                    return ServiceUtil.returnError(errorMsg + e.getMessage());
1898:                }
1899:                return ServiceUtil.returnSuccess();
1900:            }
1901:
1902:            // replacement return (create new order adjusted to be at no charge)
1903:            public static Map processReplacementReturn(DispatchContext dctx,
1904:                    Map context) {
1905:                LocalDispatcher dispatcher = dctx.getDispatcher();
1906:                GenericDelegator delegator = dctx.getDelegator();
1907:                String returnId = (String) context.get("returnId");
1908:                GenericValue userLogin = (GenericValue) context
1909:                        .get("userLogin");
1910:                Locale locale = (Locale) context.get("locale");
1911:
1912:                GenericValue returnHeader = null;
1913:                List returnItems = null;
1914:                try {
1915:                    returnHeader = delegator.findByPrimaryKey("ReturnHeader",
1916:                            UtilMisc.toMap("returnId", returnId));
1917:                    if (returnHeader != null) {
1918:                        returnItems = returnHeader.getRelatedByAnd(
1919:                                "ReturnItem", UtilMisc.toMap("returnTypeId",
1920:                                        "RTN_REPLACE"));
1921:                    }
1922:                } catch (GenericEntityException e) {
1923:                    Debug.logError(e, "Problems looking up return information",
1924:                            module);
1925:                    return ServiceUtil.returnError(UtilProperties.getMessage(
1926:                            resource_error,
1927:                            "OrderErrorGettingReturnHeaderItemInformation",
1928:                            locale));
1929:                }
1930:
1931:                List createdOrderIds = new ArrayList();
1932:                if (returnHeader != null && returnItems != null
1933:                        && returnItems.size() > 0) {
1934:                    Map itemsByOrder = new HashMap();
1935:                    Map totalByOrder = new HashMap();
1936:                    groupReturnItemsByOrder(returnItems, itemsByOrder,
1937:                            totalByOrder, delegator, returnId);
1938:
1939:                    // process each one by order
1940:                    Set itemSet = itemsByOrder.entrySet();
1941:                    Iterator itemByOrderIt = itemSet.iterator();
1942:                    while (itemByOrderIt.hasNext()) {
1943:                        Map.Entry entry = (Map.Entry) itemByOrderIt.next();
1944:                        String orderId = (String) entry.getKey();
1945:                        List items = (List) entry.getValue();
1946:
1947:                        // get order header & payment prefs
1948:                        GenericValue orderHeader = null;
1949:                        try {
1950:                            orderHeader = delegator.findByPrimaryKey(
1951:                                    "OrderHeader", UtilMisc.toMap("orderId",
1952:                                            orderId));
1953:                        } catch (GenericEntityException e) {
1954:                            Debug.logError(e, "Cannot get Order details for #"
1955:                                    + orderId, module);
1956:                            continue;
1957:                        }
1958:
1959:                        OrderReadHelper orh = new OrderReadHelper(orderHeader);
1960:
1961:                        // create the replacement order
1962:                        Map orderMap = UtilMisc.toMap("userLogin", userLogin);
1963:                        GenericValue placingParty = orh.getPlacingParty();
1964:                        String placingPartyId = null;
1965:                        if (placingParty != null) {
1966:                            placingPartyId = placingParty.getString("partyId");
1967:                        }
1968:
1969:                        orderMap.put("orderTypeId", "SALES_ORDER");
1970:                        orderMap.put("partyId", placingPartyId);
1971:                        orderMap.put("productStoreId", orderHeader
1972:                                .get("productStoreId"));
1973:                        orderMap.put("webSiteId", orderHeader.get("webSiteId"));
1974:                        orderMap.put("visitId", orderHeader.get("visitId"));
1975:                        orderMap.put("currencyUom", orderHeader
1976:                                .get("currencyUom"));
1977:                        orderMap.put("grandTotal", new Double(0.00));
1978:
1979:                        // make the contact mechs
1980:                        List contactMechs = new ArrayList();
1981:                        List orderCm = null;
1982:                        try {
1983:                            orderCm = orderHeader
1984:                                    .getRelated("OrderContactMech");
1985:                        } catch (GenericEntityException e) {
1986:                            Debug.logError(e, module);
1987:                        }
1988:                        if (orderCm != null) {
1989:                            Iterator orderCmi = orderCm.iterator();
1990:                            while (orderCmi.hasNext()) {
1991:                                GenericValue v = (GenericValue) orderCmi.next();
1992:                                contactMechs.add(GenericValue.create(v));
1993:                            }
1994:                            orderMap.put("orderContactMechs", contactMechs);
1995:                        }
1996:
1997:                        // make the shipment prefs
1998:                        List shipmentPrefs = new ArrayList();
1999:                        List orderSp = null;
2000:                        try {
2001:                            orderSp = orderHeader
2002:                                    .getRelated("OrderShipmentPreference");
2003:                        } catch (GenericEntityException e) {
2004:                            Debug.logError(e, module);
2005:                        }
2006:                        if (orderSp != null) {
2007:                            Iterator orderSpi = orderSp.iterator();
2008:                            while (orderSpi.hasNext()) {
2009:                                GenericValue v = (GenericValue) orderSpi.next();
2010:                                shipmentPrefs.add(GenericValue.create(v));
2011:                            }
2012:                            orderMap.put("orderShipmentPreferences",
2013:                                    shipmentPrefs);
2014:                        }
2015:
2016:                        // make the order items
2017:                        double itemTotal = 0.00;
2018:                        List orderItems = new ArrayList();
2019:                        List orderItemShipGroupInfo = new ArrayList();
2020:                        List orderItemShipGroupIds = new ArrayList(); // this is used to store the ship group ids of the groups already added to the orderItemShipGroupInfo list
2021:                        List orderItemAssocs = new ArrayList();
2022:                        if (items != null) {
2023:                            Iterator ri = items.iterator();
2024:                            int itemCount = 1;
2025:                            while (ri.hasNext()) {
2026:                                GenericValue returnItem = (GenericValue) ri
2027:                                        .next();
2028:                                GenericValue orderItem = null;
2029:                                try {
2030:                                    orderItem = returnItem
2031:                                            .getRelatedOne("OrderItem");
2032:                                } catch (GenericEntityException e) {
2033:                                    Debug.logError(e, module);
2034:                                    continue;
2035:                                }
2036:                                if (orderItem != null) {
2037:                                    Double quantity = returnItem
2038:                                            .getDouble("returnQuantity");
2039:                                    Double unitPrice = returnItem
2040:                                            .getDouble("returnPrice");
2041:                                    if (quantity != null && unitPrice != null) {
2042:                                        itemTotal = (quantity.doubleValue() * unitPrice
2043:                                                .doubleValue());
2044:                                        GenericValue newItem = delegator
2045:                                                .makeValue(
2046:                                                        "OrderItem",
2047:                                                        UtilMisc
2048:                                                                .toMap(
2049:                                                                        "orderItemSeqId",
2050:                                                                        UtilFormatOut
2051:                                                                                .formatPaddedNumber(
2052:                                                                                        itemCount,
2053:                                                                                        5)));
2054:
2055:                                        newItem
2056:                                                .set(
2057:                                                        "orderItemTypeId",
2058:                                                        orderItem
2059:                                                                .get("orderItemTypeId"));
2060:                                        newItem.set("productId", orderItem
2061:                                                .get("productId"));
2062:                                        newItem
2063:                                                .set(
2064:                                                        "productFeatureId",
2065:                                                        orderItem
2066:                                                                .get("productFeatureId"));
2067:                                        newItem.set("prodCatalogId", orderItem
2068:                                                .get("prodCatalogId"));
2069:                                        newItem
2070:                                                .set(
2071:                                                        "productCategoryId",
2072:                                                        orderItem
2073:                                                                .get("productCategoryId"));
2074:                                        newItem.set("quantity", quantity);
2075:                                        newItem.set("unitPrice", unitPrice);
2076:                                        newItem.set("unitListPrice", orderItem
2077:                                                .get("unitListPrice"));
2078:                                        newItem
2079:                                                .set(
2080:                                                        "itemDescription",
2081:                                                        orderItem
2082:                                                                .get("itemDescription"));
2083:                                        newItem.set("comments", orderItem
2084:                                                .get("comments"));
2085:                                        newItem
2086:                                                .set(
2087:                                                        "correspondingPoId",
2088:                                                        orderItem
2089:                                                                .get("correspondingPoId"));
2090:                                        newItem.set("statusId", "ITEM_CREATED");
2091:                                        orderItems.add(newItem);
2092:
2093:                                        // Set the order item ship group information
2094:                                        // TODO: only the first ship group associated to the item 
2095:                                        //       of the original order is considered and cloned,
2096:                                        //       anIs there a better way to handle this?d the returned units are assigned to it.
2097:                                        //
2098:
2099:                                        try {
2100:                                            GenericValue orderItemShipGroupAssoc = EntityUtil
2101:                                                    .getFirst(orderItem
2102:                                                            .getRelated("OrderItemShipGroupAssoc"));
2103:                                            if (orderItemShipGroupAssoc != null) {
2104:                                                if (!orderItemShipGroupIds
2105:                                                        .contains(orderItemShipGroupAssoc
2106:                                                                .getString("shipGroupSeqId"))) {
2107:                                                    GenericValue orderItemShipGroup = orderItemShipGroupAssoc
2108:                                                            .getRelatedOne("OrderItemShipGroup");
2109:                                                    GenericValue newOrderItemShipGroup = (GenericValue) orderItemShipGroup
2110:                                                            .clone();
2111:                                                    newOrderItemShipGroup.set(
2112:                                                            "orderId", null);
2113:                                                    orderItemShipGroupInfo
2114:                                                            .add(newOrderItemShipGroup);
2115:                                                    orderItemShipGroupIds
2116:                                                            .add(orderItemShipGroupAssoc
2117:                                                                    .getString("shipGroupSeqId"));
2118:                                                }
2119:                                                GenericValue newOrderItemShipGroupAssoc = delegator
2120:                                                        .makeValue(
2121:                                                                "OrderItemShipGroupAssoc",
2122:                                                                UtilMisc
2123:                                                                        .toMap(
2124:                                                                                "orderItemSeqId",
2125:                                                                                newItem
2126:                                                                                        .getString("orderItemSeqId"),
2127:                                                                                "shipGroupSeqId",
2128:                                                                                orderItemShipGroupAssoc
2129:                                                                                        .getString("shipGroupSeqId"),
2130:                                                                                "quantity",
2131:                                                                                quantity));
2132:                                                orderItemShipGroupInfo
2133:                                                        .add(newOrderItemShipGroupAssoc);
2134:                                            }
2135:                                        } catch (GenericEntityException gee) {
2136:                                            Debug.logError(gee, module);
2137:                                        }
2138:                                        // Create an association between the replacement order item and the order item of the original order
2139:                                        GenericValue newOrderItemAssoc = delegator
2140:                                                .makeValue(
2141:                                                        "OrderItemAssoc",
2142:                                                        UtilMisc
2143:                                                                .toMap(
2144:                                                                        "orderId",
2145:                                                                        orderHeader
2146:                                                                                .getString("orderId"),
2147:                                                                        "orderItemSeqId",
2148:                                                                        orderItem
2149:                                                                                .getString("orderItemSeqId"),
2150:                                                                        "shipGroupSeqId",
2151:                                                                        "_NA_",
2152:                                                                        "toOrderItemSeqId",
2153:                                                                        newItem
2154:                                                                                .getString("orderItemSeqId"),
2155:                                                                        "toShipGroupSeqId",
2156:                                                                        "_NA_",
2157:                                                                        "orderItemAssocTypeId",
2158:                                                                        "REPLACEMENT"));
2159:                                        orderItemAssocs.add(newOrderItemAssoc);
2160:                                    }
2161:                                }
2162:                            }
2163:                            orderMap.put("orderItems", orderItems);
2164:                            if (orderItemShipGroupInfo.size() > 0) {
2165:                                orderMap.put("orderItemShipGroupInfo",
2166:                                        orderItemShipGroupInfo);
2167:                            }
2168:                            if (orderItemAssocs.size() > 0) {
2169:                                orderMap.put("orderItemAssociations",
2170:                                        orderItemAssocs);
2171:                            }
2172:                        } else {
2173:                            Debug.logError("No return items found??", module);
2174:                            continue;
2175:                        }
2176:
2177:                        // create the replacement adjustment
2178:                        GenericValue adj = delegator.makeValue(
2179:                                "OrderAdjustment", new HashMap());
2180:                        adj.set("orderAdjustmentTypeId", "REPLACE_ADJUSTMENT");
2181:                        adj.set("amount", new Double(itemTotal * -1));
2182:                        adj.set("comments", "Replacement Item Return #"
2183:                                + returnId);
2184:                        adj.set("createdDate", UtilDateTime.nowTimestamp());
2185:                        adj.set("createdByUserLogin", userLogin
2186:                                .getString("userLoginId"));
2187:                        orderMap.put("orderAdjustments", UtilMisc.toList(adj));
2188:
2189:                        // we'll assume new order is under same terms as original.  note orderTerms is a required parameter of storeOrder
2190:                        try {
2191:                            orderMap.put("orderTerms", orderHeader
2192:                                    .getRelated("OrderTerm"));
2193:                        } catch (GenericEntityException e) {
2194:                            Debug
2195:                                    .logError(
2196:                                            e,
2197:                                            "Cannot create replacement order because order terms for original order are not available",
2198:                                            module);
2199:                        }
2200:                        // we'll assume the new order has the same order roles of the original one
2201:                        try {
2202:                            List orderRoles = orderHeader
2203:                                    .getRelated("OrderRole");
2204:                            Map orderRolesMap = FastMap.newInstance();
2205:                            if (orderRoles != null) {
2206:                                Iterator orderRolesIt = orderRoles.iterator();
2207:                                while (orderRolesIt.hasNext()) {
2208:                                    GenericValue orderRole = (GenericValue) orderRolesIt
2209:                                            .next();
2210:                                    List parties = (List) orderRolesMap
2211:                                            .get(orderRole
2212:                                                    .getString("roleTypeId"));
2213:                                    if (parties == null) {
2214:                                        parties = FastList.newInstance();
2215:                                        orderRolesMap.put(orderRole
2216:                                                .getString("roleTypeId"),
2217:                                                parties);
2218:                                    }
2219:                                    parties.add(orderRole.getString("partyId"));
2220:                                }
2221:                            }
2222:                            if (orderRolesMap.size() > 0) {
2223:                                orderMap.put("orderAdditionalPartyRoleMap",
2224:                                        orderRolesMap);
2225:                            }
2226:                        } catch (GenericEntityException e) {
2227:                            Debug
2228:                                    .logError(
2229:                                            e,
2230:                                            "Cannot create replacement order because order roles for original order are not available",
2231:                                            module);
2232:                        }
2233:
2234:                        // create the order
2235:                        String createdOrderId = null;
2236:                        Map orderResult = null;
2237:                        try {
2238:                            orderResult = dispatcher.runSync("storeOrder",
2239:                                    orderMap);
2240:                        } catch (GenericServiceException e) {
2241:                            Debug.logInfo(e, "Problem creating the order!",
2242:                                    module);
2243:                        }
2244:                        if (orderResult != null) {
2245:                            createdOrderId = (String) orderResult
2246:                                    .get("orderId");
2247:                            createdOrderIds.add(createdOrderId);
2248:                        }
2249:
2250:                        // since there is no payments required; order is ready for processing/shipment
2251:                        if (createdOrderId != null) {
2252:                            OrderChangeHelper.approveOrder(dispatcher,
2253:                                    userLogin, createdOrderId);
2254:                        }
2255:                    }
2256:                }
2257:
2258:                StringBuffer successMessage = new StringBuffer();
2259:                if (createdOrderIds.size() > 0) {
2260:                    successMessage
2261:                            .append("The following new orders have been created : ");
2262:                    Iterator i = createdOrderIds.iterator();
2263:                    while (i.hasNext()) {
2264:                        successMessage.append(i.next());
2265:                        if (i.hasNext()) {
2266:                            successMessage.append(", ");
2267:                        }
2268:                    }
2269:                } else {
2270:                    successMessage.append("No orders were created.");
2271:                }
2272:
2273:                return ServiceUtil.returnSuccess(successMessage.toString());
2274:            }
2275:
2276:            /**
2277:             * Takes a List of returnItems and returns a Map of orderId -> items and a Map of orderId -> orderTotal 
2278:             * @param returnItems
2279:             * @param itemsByOrder
2280:             * @param totalByOrder
2281:             * @param delegator
2282:             * @param returnId
2283:             */
2284:            public static void groupReturnItemsByOrder(List returnItems,
2285:                    Map itemsByOrder, Map totalByOrder,
2286:                    GenericDelegator delegator, String returnId) {
2287:                Iterator itemIt = returnItems.iterator();
2288:                while (itemIt.hasNext()) {
2289:                    GenericValue item = (GenericValue) itemIt.next();
2290:                    String orderId = item.getString("orderId");
2291:                    if (orderId != null) {
2292:                        if (itemsByOrder != null) {
2293:                            List orderList = (List) itemsByOrder.get(orderId);
2294:                            Double totalForOrder = null;
2295:                            if (totalByOrder != null) {
2296:                                totalForOrder = (Double) totalByOrder
2297:                                        .get(orderId);
2298:                            }
2299:                            if (orderList == null) {
2300:                                orderList = new ArrayList();
2301:                            }
2302:                            if (totalForOrder == null) {
2303:                                totalForOrder = new Double(0.00);
2304:                            }
2305:
2306:                            // add to the items list
2307:                            orderList.add(item);
2308:                            itemsByOrder.put(orderId, orderList);
2309:
2310:                            if (totalByOrder != null) {
2311:                                // add on the total for this line
2312:                                Double quantity = item
2313:                                        .getDouble("returnQuantity");
2314:                                Double amount = item.getDouble("returnPrice");
2315:                                if (quantity == null) {
2316:                                    quantity = new Double(0);
2317:                                }
2318:                                if (amount == null) {
2319:                                    amount = new Double(0.00);
2320:                                }
2321:                                double this Total = amount.doubleValue()
2322:                                        * quantity.doubleValue();
2323:                                double existingTotal = totalForOrder
2324:                                        .doubleValue();
2325:                                Map condition = UtilMisc.toMap("returnId", item
2326:                                        .get("returnId"), "returnItemSeqId",
2327:                                        item.get("returnItemSeqId"));
2328:                                Double newTotal = new Double(existingTotal
2329:                                        + this Total
2330:                                        + getReturnAdjustmentTotal(delegator,
2331:                                                condition));
2332:                                totalByOrder.put(orderId, newTotal);
2333:                            }
2334:                        }
2335:                    }
2336:                }
2337:
2338:                // We may also have some order-level adjustments, so we need to go through each order again and add those as well
2339:                if ((totalByOrder != null) && (totalByOrder.keySet() != null)) {
2340:                    Iterator orderIterator = totalByOrder.keySet().iterator();
2341:                    while (orderIterator.hasNext()) {
2342:                        String orderId = (String) orderIterator.next();
2343:                        // find returnAdjustment for returnHeader
2344:                        Map condition = UtilMisc.toMap("returnId", returnId,
2345:                                "returnItemSeqId",
2346:                                org.ofbiz.common.DataModelConstants.SEQ_ID_NA);
2347:                        double existingTotal = ((Double) totalByOrder
2348:                                .get(orderId)).doubleValue()
2349:                                + getReturnAdjustmentTotal(delegator, condition);
2350:                        totalByOrder.put(orderId, new Double(existingTotal));
2351:                    }
2352:                }
2353:            }
2354:
2355:            public static Map getReturnAmountByOrder(DispatchContext dctx,
2356:                    Map context) {
2357:                GenericDelegator delegator = dctx.getDelegator();
2358:                String returnId = (String) context.get("returnId");
2359:                Locale locale = (Locale) context.get("locale");
2360:                List returnItems = null;
2361:                Map returnAmountByOrder = new HashMap();
2362:                try {
2363:                    returnItems = delegator.findByAnd("ReturnItem", UtilMisc
2364:                            .toMap("returnId", returnId));
2365:
2366:                } catch (GenericEntityException e) {
2367:                    Debug.logError(e, "Problems looking up return information",
2368:                            module);
2369:                    return ServiceUtil.returnError(UtilProperties.getMessage(
2370:                            resource_error,
2371:                            "OrderErrorGettingReturnHeaderItemInformation",
2372:                            locale));
2373:                }
2374:                if ((returnItems != null) && (returnItems.size() > 0)) {
2375:                    Iterator returnItemIterator = returnItems.iterator();
2376:                    GenericValue returnItem = null;
2377:                    GenericValue returnItemResponse = null;
2378:                    GenericValue payment = null;
2379:                    String orderId;
2380:                    List paymentList = new ArrayList();
2381:                    while (returnItemIterator.hasNext()) {
2382:                        returnItem = (GenericValue) returnItemIterator.next();
2383:                        orderId = returnItem.getString("orderId");
2384:                        try {
2385:                            returnItemResponse = returnItem
2386:                                    .getRelatedOne("ReturnItemResponse");
2387:                            if ((returnItemResponse != null)
2388:                                    && (orderId != null)) {
2389:                                // TODO should we filter on payment's status (PMNT_SENT,PMNT_RECEIVED)
2390:                                payment = returnItemResponse
2391:                                        .getRelatedOne("Payment");
2392:                                if ((payment != null)
2393:                                        && (payment.getBigDecimal("amount") != null)
2394:                                        && !paymentList.contains(payment
2395:                                                .get("paymentId"))) {
2396:                                    UtilMisc.addToBigDecimalInMap(
2397:                                            returnAmountByOrder, orderId,
2398:                                            payment.getBigDecimal("amount"));
2399:                                    paymentList.add(payment.get("paymentId")); // make sure we don't add duplicated payment amount
2400:                                }
2401:                            }
2402:                        } catch (GenericEntityException e) {
2403:                            Debug
2404:                                    .logError(
2405:                                            e,
2406:                                            "Problems looking up return item related information",
2407:                                            module);
2408:                            return ServiceUtil
2409:                                    .returnError(UtilProperties
2410:                                            .getMessage(
2411:                                                    resource_error,
2412:                                                    "OrderErrorGettingReturnHeaderItemInformation",
2413:                                                    locale));
2414:                        }
2415:                    }
2416:                }
2417:                return UtilMisc.toMap("orderReturnAmountMap",
2418:                        returnAmountByOrder);
2419:            }
2420:
2421:            public static Map checkPaymentAmountForRefund(DispatchContext dctx,
2422:                    Map context) {
2423:                LocalDispatcher dispatcher = dctx.getDispatcher();
2424:                GenericDelegator delegator = dctx.getDelegator();
2425:                String returnId = (String) context.get("returnId");
2426:                Locale locale = (Locale) context.get("locale");
2427:                Map returnAmountByOrder = null;
2428:                Map serviceResult = null;
2429:                //GenericValue orderHeader = null;
2430:                try {
2431:                    serviceResult = dispatcher.runSync(
2432:                            "getReturnAmountByOrder",
2433:                            org.ofbiz.base.util.UtilMisc.toMap("returnId",
2434:                                    returnId));
2435:                } catch (GenericServiceException e) {
2436:                    Debug
2437:                            .logError(
2438:                                    e,
2439:                                    "Problem running the getReturnAmountByOrder service",
2440:                                    module);
2441:                    return ServiceUtil.returnError(UtilProperties.getMessage(
2442:                            resource_error,
2443:                            "OrderProblemsWithGetReturnAmountByOrder", locale));
2444:                }
2445:                if (ServiceUtil.isError(serviceResult)) {
2446:                    return ServiceUtil.returnError((String) serviceResult
2447:                            .get(ModelService.ERROR_MESSAGE));
2448:                } else {
2449:                    returnAmountByOrder = (Map) serviceResult
2450:                            .get("orderReturnAmountMap");
2451:                }
2452:
2453:                if ((returnAmountByOrder != null)
2454:                        && (returnAmountByOrder.keySet() != null)) {
2455:                    Iterator orderIterator = returnAmountByOrder.keySet()
2456:                            .iterator();
2457:                    while (orderIterator.hasNext()) {
2458:                        String orderId = (String) orderIterator.next();
2459:                        BigDecimal returnAmount = (BigDecimal) returnAmountByOrder
2460:                                .get(orderId);
2461:                        if (returnAmount.abs().compareTo(
2462:                                new BigDecimal("0.000001")) < 0) {
2463:                            Debug.logError("Order [" + orderId
2464:                                    + "] refund amount[ " + returnAmount
2465:                                    + "] less than zero", module);
2466:                            return ServiceUtil
2467:                                    .returnError(UtilProperties
2468:                                            .getMessage(
2469:                                                    resource_error,
2470:                                                    "OrderReturnTotalCannotLessThanZero",
2471:                                                    locale));
2472:                        }
2473:                        OrderReadHelper helper = new OrderReadHelper(
2474:                                OrderReadHelper.getOrderHeader(delegator,
2475:                                        orderId));
2476:                        BigDecimal grandTotal = helper.getOrderGrandTotalBd();
2477:                        if (returnAmount == null) {
2478:                            Debug.logInfo("No returnAmount found for order:"
2479:                                    + orderId, module);
2480:                        } else {
2481:                            if (returnAmount.subtract(grandTotal).compareTo(
2482:                                    new BigDecimal("0.01")) > 0) {
2483:                                Debug.logError("Order [" + orderId
2484:                                        + "] refund amount[ " + returnAmount
2485:                                        + "] exceeds order total ["
2486:                                        + grandTotal + "]", module);
2487:                                return ServiceUtil
2488:                                        .returnError(UtilProperties
2489:                                                .getMessage(
2490:                                                        resource_error,
2491:                                                        "OrderRefundAmountExceedsOrderTotal",
2492:                                                        locale));
2493:                            }
2494:                        }
2495:                    }
2496:                }
2497:                return ServiceUtil.returnSuccess();
2498:            }
2499:
2500:            public static Map createReturnAdjustment(DispatchContext dctx,
2501:                    Map context) {
2502:                GenericDelegator delegator = dctx.getDelegator();
2503:                String orderAdjustmentId = (String) context
2504:                        .get("orderAdjustmentId");
2505:                String returnAdjustmentTypeId = (String) context
2506:                        .get("returnAdjustmentTypeId");
2507:                String returnId = (String) context.get("returnId");
2508:                String returnItemSeqId = (String) context
2509:                        .get("returnItemSeqId");
2510:                String description = (String) context.get("description");
2511:
2512:                GenericValue returnItemTypeMap = null;
2513:                GenericValue orderAdjustment = null;
2514:                GenericValue returnAdjustmentType = null;
2515:                GenericValue orderItem = null;
2516:                GenericValue returnItem = null;
2517:                GenericValue returnHeader = null;
2518:
2519:                Double amount;
2520:
2521:                // if orderAdjustment is not empty, then copy most return adjustment information from orderAdjustment's
2522:                if (orderAdjustmentId != null) {
2523:                    try {
2524:                        orderAdjustment = delegator
2525:                                .findByPrimaryKey("OrderAdjustment", UtilMisc
2526:                                        .toMap("orderAdjustmentId",
2527:                                                orderAdjustmentId));
2528:
2529:                        // get returnHeaderTypeId from ReturnHeader and then use it to figure out return item type mapping
2530:                        returnHeader = delegator.findByPrimaryKey(
2531:                                "ReturnHeader", UtilMisc.toMap("returnId",
2532:                                        returnId));
2533:                        String returnHeaderTypeId = ((returnHeader != null) && (returnHeader
2534:                                .getString("returnHeaderTypeId") != null)) ? returnHeader
2535:                                .getString("returnHeaderTypeId")
2536:                                : "CUSTOMER_RETURN";
2537:                        returnItemTypeMap = delegator.findByPrimaryKey(
2538:                                "ReturnItemTypeMap", UtilMisc.toMap(
2539:                                        "returnHeaderTypeId",
2540:                                        returnHeaderTypeId, "returnItemMapKey",
2541:                                        orderAdjustment
2542:                                                .get("orderAdjustmentTypeId")));
2543:                        returnAdjustmentType = returnItemTypeMap
2544:                                .getRelatedOne("ReturnAdjustmentType");
2545:                        if (returnAdjustmentType != null
2546:                                && UtilValidate.isEmpty(description)) {
2547:                            description = returnAdjustmentType
2548:                                    .getString("description");
2549:                        }
2550:                        if ((returnItemSeqId != null)
2551:                                && !("_NA_".equals(returnItemSeqId))) {
2552:                            returnItem = delegator.findByPrimaryKey(
2553:                                    "ReturnItem", UtilMisc.toMap("returnId",
2554:                                            returnId, "returnItemSeqId",
2555:                                            returnItemSeqId));
2556:                            Debug.log("returnId:" + returnId
2557:                                    + ",returnItemSeqId:" + returnItemSeqId);
2558:                            orderItem = returnItem.getRelatedOne("OrderItem");
2559:                        }
2560:                    } catch (GenericEntityException e) {
2561:                        Debug.logError(e, module);
2562:                        throw new GeneralRuntimeException(e.getMessage());
2563:                    }
2564:                    context.putAll(orderAdjustment.getAllFields());
2565:                }
2566:
2567:                // if orderAdjustmentTypeId is empty, ie not found from orderAdjustmentId, then try to get returnAdjustmentTypeId from returnItemTypeMap, 
2568:                // if still empty, use default RET_MAN_ADJ
2569:                if (returnAdjustmentTypeId == null) {
2570:                    String mappingTypeId = returnItemTypeMap != null ? returnItemTypeMap
2571:                            .get("returnItemTypeId").toString()
2572:                            : null;
2573:                    returnAdjustmentTypeId = mappingTypeId != null ? mappingTypeId
2574:                            : "RET_MAN_ADJ";
2575:                }
2576:                // calculate the returnAdjustment amount
2577:                if (returnItem != null) { // returnAdjustment for returnItem
2578:                    if (needRecalculate(returnAdjustmentTypeId)) {
2579:                        Debug.logInfo(
2580:                                "returnPrice:"
2581:                                        + returnItem.getDouble("returnPrice")
2582:                                        + ",returnQuantity:"
2583:                                        + returnItem
2584:                                                .getDouble("returnQuantity")
2585:                                        + ",sourcePercentage:"
2586:                                        + orderAdjustment
2587:                                                .getDouble("sourcePercentage"),
2588:                                module);
2589:                        if (orderAdjustment == null) {
2590:                            Debug
2591:                                    .logError(
2592:                                            "orderAdjustment ["
2593:                                                    + orderAdjustmentId
2594:                                                    + "] not found", module);
2595:                            return ServiceUtil.returnError("orderAdjustment ["
2596:                                    + orderAdjustmentId + "] not found");
2597:                        }
2598:                        BigDecimal returnTotal = returnItem.getBigDecimal(
2599:                                "returnPrice").multiply(
2600:                                returnItem.getBigDecimal("returnQuantity"));
2601:                        BigDecimal orderTotal = orderItem.getBigDecimal(
2602:                                "quantity").multiply(
2603:                                orderItem.getBigDecimal("unitPrice"));
2604:                        amount = getAdjustmentAmount("RET_SALES_TAX_ADJ"
2605:                                .equals(returnAdjustmentType), returnTotal,
2606:                                orderTotal, orderAdjustment
2607:                                        .getBigDecimal("amount"));
2608:                    } else {
2609:                        amount = (Double) context.get("amount");
2610:                    }
2611:                } else { // returnAdjustment for returnHeader
2612:                    amount = (Double) context.get("amount");
2613:                }
2614:
2615:                // store the return adjustment
2616:                String seqId = delegator.getNextSeqId("ReturnAdjustment");
2617:                GenericValue newReturnAdjustment = delegator.makeValue(
2618:                        "ReturnAdjustment", UtilMisc.toMap(
2619:                                "returnAdjustmentId", seqId));
2620:
2621:                try {
2622:                    newReturnAdjustment.setNonPKFields(context);
2623:                    if (orderAdjustment != null
2624:                            && orderAdjustment.get("taxAuthorityRateSeqId") != null) {
2625:                        newReturnAdjustment.set("taxAuthorityRateSeqId",
2626:                                orderAdjustment
2627:                                        .getString("taxAuthorityRateSeqId"));
2628:                    }
2629:                    newReturnAdjustment.set("amount", amount);
2630:                    newReturnAdjustment.set("returnAdjustmentTypeId",
2631:                            returnAdjustmentTypeId);
2632:                    newReturnAdjustment.set("description", description);
2633:                    newReturnAdjustment.set("returnItemSeqId", UtilValidate
2634:                            .isEmpty(returnItemSeqId) ? "_NA_"
2635:                            : returnItemSeqId);
2636:
2637:                    delegator.create(newReturnAdjustment);
2638:                    Map result = ServiceUtil
2639:                            .returnSuccess("Create ReturnAdjustment with Id:"
2640:                                    + seqId + " successfully.");
2641:                    result.put("returnAdjustmentId", seqId);
2642:                    return result;
2643:                } catch (GenericEntityException e) {
2644:                    Debug.logError(e, "Failed to store returnAdjustment",
2645:                            module);
2646:                    return ServiceUtil
2647:                            .returnError("Failed to store returnAdjustment");
2648:                }
2649:            }
2650:
2651:            public static Map updateReturnAdjustment(DispatchContext dctx,
2652:                    Map context) {
2653:                GenericDelegator delegator = dctx.getDelegator();
2654:
2655:                GenericValue returnItem = null;
2656:                GenericValue returnAdjustment = null;
2657:                String returnAdjustmentTypeId = null;
2658:                Double amount;
2659:
2660:                try {
2661:                    returnAdjustment = delegator.findByPrimaryKey(
2662:                            "ReturnAdjustment", UtilMisc.toMap(
2663:                                    "returnAdjustmentId", context
2664:                                            .get("returnAdjustmentId")));
2665:
2666:                    if (returnAdjustment != null) {
2667:                        returnItem = delegator
2668:                                .findByPrimaryKey("ReturnItem", UtilMisc.toMap(
2669:                                        "returnId", returnAdjustment
2670:                                                .get("returnId"),
2671:                                        "returnItemSeqId", returnAdjustment
2672:                                                .get("returnItemSeqId")));
2673:                        returnAdjustmentTypeId = returnAdjustment
2674:                                .getString("returnAdjustmentTypeId");
2675:                    }
2676:
2677:                    // calculate the returnAdjustment amount
2678:                    if (returnItem != null) { // returnAdjustment for returnItem
2679:                        double originalReturnPrice = (context
2680:                                .get("originalReturnPrice") != null) ? ((Double) context
2681:                                .get("originalReturnPrice")).doubleValue()
2682:                                : returnItem.getDouble("returnPrice")
2683:                                        .doubleValue();
2684:                        double originalReturnQuantity = (context
2685:                                .get("originalReturnQuantity") != null) ? ((Double) context
2686:                                .get("originalReturnQuantity")).doubleValue()
2687:                                : returnItem.getDouble("returnQuantity")
2688:                                        .doubleValue();
2689:
2690:                        if (needRecalculate(returnAdjustmentTypeId)) {
2691:                            BigDecimal returnTotal = returnItem.getBigDecimal(
2692:                                    "returnPrice").multiply(
2693:                                    returnItem.getBigDecimal("returnQuantity"));
2694:                            BigDecimal originalReturnTotal = new BigDecimal(
2695:                                    originalReturnPrice)
2696:                                    .multiply(new BigDecimal(
2697:                                            originalReturnQuantity));
2698:                            amount = getAdjustmentAmount("RET_SALES_TAX_ADJ"
2699:                                    .equals(returnAdjustmentTypeId),
2700:                                    returnTotal, originalReturnTotal,
2701:                                    returnAdjustment.getBigDecimal("amount"));
2702:                        } else {
2703:                            amount = (Double) context.get("amount");
2704:                        }
2705:                    } else { // returnAdjustment for returnHeader
2706:                        amount = (Double) context.get("amount");
2707:                    }
2708:
2709:                    returnAdjustment.setNonPKFields(context);
2710:                    returnAdjustment.set("amount", amount);
2711:                    delegator.store(returnAdjustment);
2712:                    Debug.logInfo("Update ReturnAdjustment with Id:"
2713:                            + context.get("returnAdjustmentId") + " to amount "
2714:                            + amount + " successfully.", module);
2715:                    Map result = ServiceUtil
2716:                            .returnSuccess("Update ReturnAdjustment with Id:"
2717:                                    + context.get("returnAdjustmentId")
2718:                                    + " to amount " + amount + " successfully.");
2719:                    return result;
2720:                } catch (GenericEntityException e) {
2721:                    Debug.logError(e, "Failed to store returnAdjustment",
2722:                            module);
2723:                    return ServiceUtil
2724:                            .returnError("Failed to store returnAdjustment");
2725:                }
2726:            }
2727:
2728:            //  used as a dispatch service, invoke different service based on the parameters passed in
2729:            public static Map createReturnItemOrAdjustment(
2730:                    DispatchContext dctx, Map context) {
2731:                Debug.logInfo("createReturnItemOrAdjustment's context:"
2732:                        + context, module);
2733:                String orderItemSeqId = (String) context.get("orderItemSeqId");
2734:                Debug.logInfo("orderItemSeqId:" + orderItemSeqId + "#", module);
2735:                LocalDispatcher dispatcher = dctx.getDispatcher();
2736:                //if the request is to create returnItem, orderItemSeqId should not be empty
2737:                String serviceName = UtilValidate.isNotEmpty(orderItemSeqId) ? "createReturnItem"
2738:                        : "createReturnAdjustment";
2739:                Debug.logInfo("serviceName:" + serviceName, module);
2740:                try {
2741:                    return dispatcher.runSync(serviceName,
2742:                            filterServiceContext(dctx, serviceName, context));
2743:                } catch (org.ofbiz.service.GenericServiceException e) {
2744:                    Debug.logError(e, module);
2745:                    return ServiceUtil.returnError(e.getMessage());
2746:                }
2747:            }
2748:
2749:            //  used as a dispatch service, invoke different service based on the parameters passed in
2750:            public static Map updateReturnItemOrAdjustment(
2751:                    DispatchContext dctx, Map context) {
2752:                Debug.logInfo("updateReturnItemOrAdjustment's context:"
2753:                        + context, module);
2754:                String returnAdjustmentId = (String) context
2755:                        .get("returnAdjustmentId");
2756:                Debug.logInfo("returnAdjustmentId:" + returnAdjustmentId + "#",
2757:                        module);
2758:                LocalDispatcher dispatcher = dctx.getDispatcher();
2759:                //if the request is to create returnItem, orderItemSeqId should not be empty
2760:                String serviceName = UtilValidate.isEmpty(returnAdjustmentId) ? "updateReturnItem"
2761:                        : "updateReturnAdjustment";
2762:                Debug.logInfo("serviceName:" + serviceName, module);
2763:                try {
2764:                    return dispatcher.runSync(serviceName,
2765:                            filterServiceContext(dctx, serviceName, context));
2766:                } catch (org.ofbiz.service.GenericServiceException e) {
2767:                    Debug.logError(e, module);
2768:                    return ServiceUtil.returnError(e.getMessage());
2769:                }
2770:            }
2771:
2772:            /**
2773:             * These return adjustment types need to be recalculated when the return item is updated
2774:             * @param returnAdjustmentTypeId
2775:             * @return
2776:             */
2777:            public static boolean needRecalculate(String returnAdjustmentTypeId) {
2778:                return "RET_PROMOTION_ADJ".equals(returnAdjustmentTypeId)
2779:                        || "RET_DISCOUNT_ADJ".equals(returnAdjustmentTypeId)
2780:                        || "RET_SALES_TAX_ADJ".equals(returnAdjustmentTypeId);
2781:
2782:            }
2783:
2784:            /**
2785:             * Get the total return adjustments for a set of key -> value condition pairs.  Done for code efficiency.
2786:             * @param delegator
2787:             * @param condition
2788:             * @return
2789:             */
2790:            public static double getReturnAdjustmentTotal(
2791:                    GenericDelegator delegator, Map condition) {
2792:                double total = 0.0;
2793:                List adjustments;
2794:                try {
2795:                    // TODO: find on a view-entity with a sum is probably more efficient
2796:                    adjustments = delegator.findByAnd("ReturnAdjustment",
2797:                            condition);
2798:                    if (adjustments != null) {
2799:                        Iterator adjustmentIterator = adjustments.iterator();
2800:                        while (adjustmentIterator.hasNext()) {
2801:                            GenericValue returnAdjustment = (GenericValue) adjustmentIterator
2802:                                    .next();
2803:                            if ((returnAdjustment != null)
2804:                                    && (returnAdjustment.get("amount") != null)) {
2805:                                total += returnAdjustment.getDouble("amount")
2806:                                        .doubleValue();
2807:                            }
2808:                        }
2809:                    }
2810:                } catch (org.ofbiz.entity.GenericEntityException e) {
2811:                    Debug.logError(e, module);
2812:                }
2813:                return total;
2814:            }
2815:
2816:            /**
2817:             *  Get rid of unnecessary parameters based on the given service name  
2818:             * @param dctx Service DispatchContext
2819:             * @param serviceName  
2820:             * @param context   context before clean up
2821:             * @return filtered context
2822:             * @throws GenericServiceException 
2823:             */
2824:            public static Map filterServiceContext(DispatchContext dctx,
2825:                    String serviceName, Map context)
2826:                    throws GenericServiceException {
2827:                ModelService modelService = dctx.getModelService(serviceName);
2828:
2829:                if (modelService == null) {
2830:                    throw new GenericServiceException(
2831:                            "Problems getting the service model");
2832:                }
2833:                Map serviceContext = FastMap.newInstance();
2834:                List modelParmInList = modelService.getInModelParamList();
2835:                Iterator modelParmInIter = modelParmInList.iterator();
2836:                while (modelParmInIter.hasNext()) {
2837:                    ModelParam modelParam = (ModelParam) modelParmInIter.next();
2838:                    String paramName = modelParam.name;
2839:
2840:                    Object value = context.get(paramName);
2841:                    if (value != null) {
2842:                        serviceContext.put(paramName, value);
2843:                    }
2844:                }
2845:                return serviceContext;
2846:            }
2847:
2848:            /**
2849:             * Calculate new returnAdjustment amount and set scale and rounding mode based on returnAdjustmentType: RET_SALES_TAX_ADJ use sales.tax._ and others use order._
2850:             * @param isSalesTax  if returnAdjustmentType is SaleTax  
2851:             * @param returnTotal
2852:             * @param originalTotal
2853:             * @param amount
2854:             * @return  new returnAdjustment amount
2855:             */
2856:            public static Double getAdjustmentAmount(boolean isSalesTax,
2857:                    BigDecimal returnTotal, BigDecimal originalTotal,
2858:                    BigDecimal amount) {
2859:                String settingPrefix = isSalesTax ? "salestax" : "order";
2860:                String decimalsPrefix = isSalesTax ? ".calc" : "";
2861:                int decimals = UtilNumber.getBigDecimalScale(settingPrefix
2862:                        + decimalsPrefix + ".decimals");
2863:                int rounding = UtilNumber
2864:                        .getBigDecimalRoundingMode(settingPrefix + ".rounding");
2865:                int finalDecimals = isSalesTax ? UtilNumber
2866:                        .getBigDecimalScale(settingPrefix + ".final.decimals")
2867:                        : decimals;
2868:                returnTotal = returnTotal.setScale(decimals, rounding);
2869:                originalTotal = originalTotal.setScale(decimals, rounding);
2870:                BigDecimal newAmount = returnTotal.divide(originalTotal,
2871:                        decimals, rounding).multiply(amount).setScale(
2872:                        finalDecimals, rounding);
2873:                return new Double(newAmount.doubleValue());
2874:            }
2875:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.