Source Code Cross Referenced for FedexServices.java in  » ERP-CRM-Financial » ofbiz » org » ofbiz » shipment » thirdparty » fedex » 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.shipment.thirdparty.fedex 
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.shipment.thirdparty.fedex;
0019:
0020:        import org.ofbiz.base.util.*;
0021:        import org.ofbiz.base.util.template.FreeMarkerWorker;
0022:        import org.ofbiz.service.DispatchContext;
0023:        import org.ofbiz.service.ServiceUtil;
0024:        import org.ofbiz.service.LocalDispatcher;
0025:        import org.ofbiz.service.GenericServiceException;
0026:        import org.ofbiz.entity.GenericValue;
0027:        import org.ofbiz.entity.GenericDelegator;
0028:        import org.ofbiz.entity.GenericEntityException;
0029:        import org.ofbiz.entity.condition.EntityExpr;
0030:        import org.ofbiz.entity.condition.EntityOperator;
0031:        import org.ofbiz.entity.condition.EntityConditionList;
0032:        import org.ofbiz.entity.util.EntityUtil;
0033:        import org.ofbiz.party.party.PartyHelper;
0034:        import org.w3c.dom.Document;
0035:        import org.w3c.dom.Element;
0036:        import org.xml.sax.SAXException;
0037:
0038:        import javax.xml.parsers.ParserConfigurationException;
0039:        import java.util.*;
0040:        import java.io.IOException;
0041:        import java.io.StringWriter;
0042:        import java.math.BigDecimal;
0043:        import java.sql.Timestamp;
0044:
0045:        /**
0046:         * Fedex Shipment Services
0047:         * 
0048:         * Implementation of Fedex shipment interface using Ship Manager Direct API
0049:         * 
0050:         * TODO: FDXShipDeleteRequest/Reply (on error and via service call)
0051:         * TODO: FDXCloseRequest/Reply
0052:         * TODO: FDXRateRequest/Reply
0053:         * TODO: FDXTrackRequest/Reply
0054:         * TODO: International shipments
0055:         * TODO: Multi-piece shipments
0056:         * TODO: Freight shipments
0057:         */
0058:        public class FedexServices {
0059:
0060:            public final static String module = FedexServices.class.getName();
0061:            public final static String shipmentPropertiesFile = "shipment.properties";
0062:
0063:            /**
0064:             * Opens a URL to Fedex and makes a request.
0065:             * 
0066:             * @param xmlString XML message to send
0067:             * @return XML string response from FedEx
0068:             * @throws FedexConnectException
0069:             */
0070:            public static String sendFedexRequest(String xmlString)
0071:                    throws FedexConnectException {
0072:                String url = UtilProperties.getPropertyValue(
0073:                        shipmentPropertiesFile, "shipment.fedex.connect.url");
0074:                if (url == null) {
0075:                    throw new FedexConnectException(
0076:                            "Incomplete connection URL; check your Fedex configuration");
0077:                }
0078:
0079:                // xmlString should contain the auth document at the beginning
0080:                // all documents require an <?xml version="1.0" encoding="UTF-8" ?> header
0081:                if (!xmlString
0082:                        .matches("^(?s)<\\?xml\\s+version=\"1\\.0\"\\s+encoding=\"UTF-8\"\\s*\\?>.*")) {
0083:                    throw new FedexConnectException("XML header is malformed");
0084:                }
0085:
0086:                // prepare the connect string
0087:                url = url.trim();
0088:
0089:                String timeOutStr = UtilProperties.getPropertyValue(
0090:                        shipmentPropertiesFile,
0091:                        "shipment.fedex.connect.timeout", "60");
0092:                int timeout = 60;
0093:                try {
0094:                    timeout = Integer.parseInt(timeOutStr);
0095:                } catch (NumberFormatException e) {
0096:                    Debug.logError(e, "Unable to set timeout to " + timeOutStr
0097:                            + " using default " + timeout);
0098:                }
0099:
0100:                if (Debug.verboseOn()) {
0101:                    Debug.logVerbose("Fedex Connect URL : " + url, module);
0102:                    Debug.logVerbose("Fedex XML String : " + xmlString, module);
0103:                }
0104:
0105:                HttpClient http = new HttpClient(url);
0106:                http.setTimeout(timeout * 1000);
0107:                String response = null;
0108:                try {
0109:                    response = http.post(xmlString);
0110:                } catch (HttpClientException e) {
0111:                    Debug.logError(e, "Problem connecting to Fedex server",
0112:                            module);
0113:                    throw new FedexConnectException("URL Connection problem", e);
0114:                }
0115:
0116:                if (response == null) {
0117:                    throw new FedexConnectException("Received a null response");
0118:                }
0119:                if (Debug.verboseOn()) {
0120:                    Debug.logVerbose("Fedex Response : " + response, module);
0121:                }
0122:
0123:                return response;
0124:            }
0125:
0126:            /*
0127:             * Register a Fedex account for shipping by obtaining the meter number
0128:             */
0129:            public static Map fedexSubscriptionRequest(DispatchContext dctx,
0130:                    Map context) {
0131:                GenericDelegator delegator = dctx.getDelegator();
0132:                List errorList = new ArrayList();
0133:
0134:                Boolean replaceMeterNumber = (Boolean) context
0135:                        .get("replaceMeterNumber");
0136:
0137:                if (!replaceMeterNumber.booleanValue()) {
0138:                    String meterNumber = UtilProperties.getPropertyValue(
0139:                            shipmentPropertiesFile,
0140:                            "shipment.fedex.access.meterNumber");
0141:                    if (UtilValidate.isNotEmpty(meterNumber)) {
0142:                        return ServiceUtil
0143:                                .returnError("MeterNumber already exists: "
0144:                                        + shipmentPropertiesFile
0145:                                        + ":shipment.fedex.access.meterNumber="
0146:                                        + meterNumber);
0147:                    }
0148:                }
0149:
0150:                String companyPartyId = (String) context.get("companyPartyId");
0151:                String contactPartyName = (String) context
0152:                        .get("contactPartyName");
0153:
0154:                Map result = new HashMap();
0155:
0156:                String accountNumber = UtilProperties.getPropertyValue(
0157:                        shipmentPropertiesFile,
0158:                        "shipment.fedex.access.accountNbr");
0159:                if (UtilValidate.isEmpty(accountNumber)) {
0160:                    return ServiceUtil
0161:                            .returnError("accountNbr not found for Fedex subscription request.");
0162:                }
0163:
0164:                if (UtilValidate.isEmpty(contactPartyName)) {
0165:                    return ServiceUtil
0166:                            .returnError("Contact name can't be empty.");
0167:                }
0168:
0169:                String companyName = null;
0170:                GenericValue postalAddress = null;
0171:                String phoneNumber = null;
0172:                String faxNumber = null;
0173:                String emailAddress = null;
0174:                try {
0175:
0176:                    // Make sure the company exists
0177:                    GenericValue companyParty = delegator
0178:                            .findByPrimaryKeyCache("Party", UtilMisc.toMap(
0179:                                    "partyId", companyPartyId));
0180:                    if (companyParty == null) {
0181:                        String errorMessage = "Party with partyId "
0182:                                + companyPartyId + " does not exist";
0183:                        Debug.logError(errorMessage, module);
0184:                        return ServiceUtil.returnError(errorMessage);
0185:                    }
0186:
0187:                    // Get the company name (required by Fedex)
0188:                    companyName = PartyHelper.getPartyName(companyParty);
0189:                    if (UtilValidate.isEmpty(companyName)) {
0190:                        String errorMessage = "Party with partyId "
0191:                                + companyPartyId + " has no name";
0192:                        Debug.logError(errorMessage, module);
0193:                        return ServiceUtil.returnError(errorMessage);
0194:                    }
0195:
0196:                    // Get the contact information for the company
0197:                    List partyContactDetails = delegator.findByAnd(
0198:                            "PartyContactDetailByPurpose", UtilMisc.toMap(
0199:                                    "partyId", companyPartyId));
0200:                    partyContactDetails = EntityUtil
0201:                            .filterByDate(partyContactDetails);
0202:                    partyContactDetails = EntityUtil.filterByDate(
0203:                            partyContactDetails, UtilDateTime.nowTimestamp(),
0204:                            "purposeFromDate", "purposeThruDate", true);
0205:
0206:                    // Get the first valid postal address (address1, city, postalCode and countryGeoId are required by Fedex)
0207:                    List postalAddressConditions = new ArrayList();
0208:                    postalAddressConditions.add(new EntityExpr(
0209:                            "contactMechTypeId", EntityOperator.EQUALS,
0210:                            "POSTAL_ADDRESS"));
0211:                    postalAddressConditions.add(new EntityExpr("address1",
0212:                            EntityOperator.NOT_EQUAL, null));
0213:                    postalAddressConditions.add(new EntityExpr("address1",
0214:                            EntityOperator.NOT_EQUAL, ""));
0215:                    postalAddressConditions.add(new EntityExpr("city",
0216:                            EntityOperator.NOT_EQUAL, null));
0217:                    postalAddressConditions.add(new EntityExpr("city",
0218:                            EntityOperator.NOT_EQUAL, ""));
0219:                    postalAddressConditions.add(new EntityExpr("postalCode",
0220:                            EntityOperator.NOT_EQUAL, null));
0221:                    postalAddressConditions.add(new EntityExpr("postalCode",
0222:                            EntityOperator.NOT_EQUAL, ""));
0223:                    postalAddressConditions.add(new EntityExpr("countryGeoId",
0224:                            EntityOperator.NOT_EQUAL, null));
0225:                    postalAddressConditions.add(new EntityExpr("countryGeoId",
0226:                            EntityOperator.NOT_EQUAL, ""));
0227:                    List postalAddresses = EntityUtil.filterByCondition(
0228:                            partyContactDetails,
0229:                            new EntityConditionList(postalAddressConditions,
0230:                                    EntityOperator.AND));
0231:
0232:                    // Fedex requires USA or Canada addresses to have a state/province ID, so filter out the ones without
0233:                    postalAddressConditions.clear();
0234:                    postalAddressConditions.add(new EntityExpr("countryGeoId",
0235:                            EntityOperator.IN, UtilMisc.toList("CAN", "USA")));
0236:                    postalAddressConditions.add(new EntityExpr(
0237:                            "stateProvinceGeoId", EntityOperator.EQUALS, null));
0238:                    postalAddresses = EntityUtil.filterOutByCondition(
0239:                            postalAddresses,
0240:                            new EntityConditionList(postalAddressConditions,
0241:                                    EntityOperator.AND));
0242:                    postalAddressConditions.clear();
0243:                    postalAddressConditions.add(new EntityExpr("countryGeoId",
0244:                            EntityOperator.IN, UtilMisc.toList("CAN", "USA")));
0245:                    postalAddressConditions.add(new EntityExpr(
0246:                            "stateProvinceGeoId", EntityOperator.EQUALS, ""));
0247:                    postalAddresses = EntityUtil.filterOutByCondition(
0248:                            postalAddresses,
0249:                            new EntityConditionList(postalAddressConditions,
0250:                                    EntityOperator.AND));
0251:
0252:                    postalAddress = EntityUtil.getFirst(postalAddresses);
0253:                    if (UtilValidate.isEmpty(postalAddress)) {
0254:                        String errorMessage = "Party with partyId "
0255:                                + companyPartyId
0256:                                + " does not have a current, fully populated postal address";
0257:                        Debug.logError(errorMessage, module);
0258:                        return ServiceUtil.returnError(errorMessage);
0259:                    }
0260:                    GenericValue countryGeo = delegator.findByPrimaryKeyCache(
0261:                            "Geo", UtilMisc.toMap("geoId", postalAddress
0262:                                    .getString("countryGeoId")));
0263:                    String countryCode = countryGeo.getString("geoCode");
0264:                    String stateOrProvinceCode = null;
0265:                    // Only add the StateOrProvinceCode element if the address is in USA or Canada
0266:                    if (countryCode.equals("CA") || countryCode.equals("US")) {
0267:                        GenericValue stateProvinceGeo = delegator
0268:                                .findByPrimaryKeyCache(
0269:                                        "Geo",
0270:                                        UtilMisc
0271:                                                .toMap(
0272:                                                        "geoId",
0273:                                                        postalAddress
0274:                                                                .getString("stateProvinceGeoId")));
0275:                        stateOrProvinceCode = stateProvinceGeo
0276:                                .getString("geoCode");
0277:                    }
0278:
0279:                    // Get the first valid primary phone number (required by Fedex)
0280:                    List phoneNumberConditions = new ArrayList();
0281:                    phoneNumberConditions.add(new EntityExpr(
0282:                            "contactMechTypeId", EntityOperator.EQUALS,
0283:                            "TELECOM_NUMBER"));
0284:                    phoneNumberConditions.add(new EntityExpr(
0285:                            "contactMechPurposeTypeId", EntityOperator.EQUALS,
0286:                            "PRIMARY_PHONE"));
0287:                    phoneNumberConditions.add(new EntityExpr("areaCode",
0288:                            EntityOperator.NOT_EQUAL, null));
0289:                    phoneNumberConditions.add(new EntityExpr("areaCode",
0290:                            EntityOperator.NOT_EQUAL, ""));
0291:                    phoneNumberConditions.add(new EntityExpr("contactNumber",
0292:                            EntityOperator.NOT_EQUAL, null));
0293:                    phoneNumberConditions.add(new EntityExpr("contactNumber",
0294:                            EntityOperator.NOT_EQUAL, ""));
0295:                    List phoneNumbers = EntityUtil.filterByCondition(
0296:                            partyContactDetails, new EntityConditionList(
0297:                                    phoneNumberConditions, EntityOperator.AND));
0298:                    GenericValue phoneNumberValue = EntityUtil
0299:                            .getFirst(phoneNumbers);
0300:                    if (UtilValidate.isEmpty(phoneNumberValue)) {
0301:                        String errorMessage = "Party with partyId "
0302:                                + companyPartyId
0303:                                + " does not have a current, fully populated primary phone number";
0304:                        Debug.logError(errorMessage, module);
0305:                        return ServiceUtil.returnError(errorMessage);
0306:                    }
0307:                    phoneNumber = phoneNumberValue.getString("areaCode")
0308:                            + phoneNumberValue.getString("contactNumber");
0309:                    // Fedex doesn't want the North American country code
0310:                    if (UtilValidate.isNotEmpty(phoneNumberValue
0311:                            .getString("countryCode"))
0312:                            && !(countryCode.equals("CA") || countryCode
0313:                                    .equals("US"))) {
0314:                        phoneNumber = phoneNumberValue.getString("countryCode")
0315:                                + phoneNumber;
0316:                    }
0317:                    phoneNumber = phoneNumber.replaceAll("[^+\\d]", "");
0318:
0319:                    // Get the first valid fax number
0320:                    List faxNumberConditions = new ArrayList();
0321:                    faxNumberConditions.add(new EntityExpr("contactMechTypeId",
0322:                            EntityOperator.EQUALS, "TELECOM_NUMBER"));
0323:                    faxNumberConditions.add(new EntityExpr(
0324:                            "contactMechPurposeTypeId", EntityOperator.EQUALS,
0325:                            "FAX_NUMBER"));
0326:                    faxNumberConditions.add(new EntityExpr("areaCode",
0327:                            EntityOperator.NOT_EQUAL, null));
0328:                    faxNumberConditions.add(new EntityExpr("areaCode",
0329:                            EntityOperator.NOT_EQUAL, ""));
0330:                    faxNumberConditions.add(new EntityExpr("contactNumber",
0331:                            EntityOperator.NOT_EQUAL, null));
0332:                    faxNumberConditions.add(new EntityExpr("contactNumber",
0333:                            EntityOperator.NOT_EQUAL, ""));
0334:                    List faxNumbers = EntityUtil.filterByCondition(
0335:                            partyContactDetails, new EntityConditionList(
0336:                                    faxNumberConditions, EntityOperator.AND));
0337:                    GenericValue faxNumberValue = EntityUtil
0338:                            .getFirst(faxNumbers);
0339:                    if (!UtilValidate.isEmpty(faxNumberValue)) {
0340:                        faxNumber = faxNumberValue.getString("areaCode")
0341:                                + faxNumberValue.getString("contactNumber");
0342:                        // Fedex doesn't want the North American country code
0343:                        if (UtilValidate.isNotEmpty(faxNumberValue
0344:                                .getString("countryCode"))
0345:                                && !(countryCode.equals("CA") || countryCode
0346:                                        .equals("US"))) {
0347:                            faxNumber = faxNumberValue.getString("countryCode")
0348:                                    + faxNumber;
0349:                        }
0350:                        faxNumber = faxNumber.replaceAll("[^+\\d]", "");
0351:                    }
0352:
0353:                    // Get the first valid email address
0354:                    List emailConditions = new ArrayList();
0355:                    emailConditions.add(new EntityExpr("contactMechTypeId",
0356:                            EntityOperator.EQUALS, "EMAIL_ADDRESS"));
0357:                    emailConditions.add(new EntityExpr("infoString",
0358:                            EntityOperator.NOT_EQUAL, null));
0359:                    emailConditions.add(new EntityExpr("infoString",
0360:                            EntityOperator.NOT_EQUAL, ""));
0361:                    List emailAddresses = EntityUtil.filterByCondition(
0362:                            partyContactDetails, new EntityConditionList(
0363:                                    emailConditions, EntityOperator.AND));
0364:                    GenericValue emailAddressValue = EntityUtil
0365:                            .getFirst(emailAddresses);
0366:                    if (!UtilValidate.isEmpty(emailAddressValue)) {
0367:                        emailAddress = emailAddressValue
0368:                                .getString("infoString");
0369:                    }
0370:
0371:                    // Get the location of the Freemarker (XML) template for the FDXSubscriptionRequest
0372:                    String templateLocation = UtilProperties.getPropertyValue(
0373:                            shipmentPropertiesFile,
0374:                            "shipment.template.fedex.subscription.location");
0375:                    if (UtilValidate.isEmpty(templateLocation)) {
0376:                        return ServiceUtil
0377:                                .returnError("Can't find location for FDXSubscriptionRequest template - should be in "
0378:                                        + shipmentPropertiesFile
0379:                                        + ":shipment.template.fedex.subscription.location");
0380:                    }
0381:
0382:                    // Populate the Freemarker context
0383:                    Map subscriptionRequestContext = new HashMap();
0384:                    subscriptionRequestContext.put("AccountNumber",
0385:                            accountNumber);
0386:                    subscriptionRequestContext.put("PersonName",
0387:                            contactPartyName);
0388:                    subscriptionRequestContext.put("CompanyName", companyName);
0389:                    subscriptionRequestContext.put("PhoneNumber", phoneNumber);
0390:                    if (UtilValidate.isNotEmpty(faxNumber)) {
0391:                        subscriptionRequestContext.put("FaxNumber", faxNumber);
0392:                    }
0393:                    if (UtilValidate.isNotEmpty(emailAddress)) {
0394:                        subscriptionRequestContext.put("EMailAddress",
0395:                                emailAddress);
0396:                    }
0397:                    subscriptionRequestContext.put("Line1", postalAddress
0398:                            .getString("address1"));
0399:                    if (UtilValidate.isNotEmpty(postalAddress
0400:                            .getString("address2"))) {
0401:                        subscriptionRequestContext.put("Line2", postalAddress
0402:                                .getString("address2"));
0403:                    }
0404:                    subscriptionRequestContext.put("City", postalAddress
0405:                            .getString("city"));
0406:                    if (UtilValidate.isNotEmpty(stateOrProvinceCode)) {
0407:                        subscriptionRequestContext.put("StateOrProvinceCode",
0408:                                stateOrProvinceCode);
0409:                    }
0410:                    subscriptionRequestContext.put("PostalCode", postalAddress
0411:                            .getString("postalCode"));
0412:                    subscriptionRequestContext.put("CountryCode", countryCode);
0413:
0414:                    StringWriter outWriter = new StringWriter();
0415:                    try {
0416:                        FreeMarkerWorker.renderTemplateAtLocation(
0417:                                templateLocation, subscriptionRequestContext,
0418:                                outWriter);
0419:                    } catch (Exception e) {
0420:                        String errorMessage = "Cannot send Fedex subscription request: Failed to render Fedex XML Subscription Request Template ["
0421:                                + templateLocation + "].";
0422:                        Debug.logError(e, errorMessage, module);
0423:                        return ServiceUtil.returnError(errorMessage + ": "
0424:                                + e.getMessage());
0425:                    }
0426:                    String fDXSubscriptionRequestString = outWriter.toString();
0427:
0428:                    // Send the request
0429:                    String fDXSubscriptionReplyString = null;
0430:                    try {
0431:                        fDXSubscriptionReplyString = sendFedexRequest(fDXSubscriptionRequestString);
0432:                        Debug.log("Fedex response for FDXSubscriptionRequest:"
0433:                                + fDXSubscriptionReplyString);
0434:                    } catch (FedexConnectException e) {
0435:                        String errorMessage = "Error sending Fedex request for FDXSubscriptionRequest: "
0436:                                + e.toString();
0437:                        Debug.logError(e, errorMessage, module);
0438:                        return ServiceUtil.returnError(errorMessage);
0439:                    }
0440:
0441:                    Document fDXSubscriptionReplyDocument = null;
0442:                    try {
0443:                        fDXSubscriptionReplyDocument = UtilXml.readXmlDocument(
0444:                                fDXSubscriptionReplyString, false);
0445:                        Debug.log("Fedex response for FDXSubscriptionRequest:"
0446:                                + fDXSubscriptionReplyString);
0447:                    } catch (SAXException se) {
0448:                        String errorMessage = "Error parsing the FDXSubscriptionRequest response: "
0449:                                + se.toString();
0450:                        Debug.logError(se, errorMessage, module);
0451:                        return ServiceUtil.returnError(errorMessage);
0452:                    } catch (ParserConfigurationException pce) {
0453:                        String errorMessage = "Error parsing the FDXSubscriptionRequest response: "
0454:                                + pce.toString();
0455:                        Debug.logError(pce, errorMessage, module);
0456:                        return ServiceUtil.returnError(errorMessage);
0457:                    } catch (IOException ioe) {
0458:                        String errorMessage = "Error parsing the FDXSubscriptionRequest response: "
0459:                                + ioe.toString();
0460:                        Debug.logError(ioe, errorMessage, module);
0461:                        return ServiceUtil.returnError(errorMessage);
0462:                    }
0463:
0464:                    Element fedexSubscriptionReplyElement = fDXSubscriptionReplyDocument
0465:                            .getDocumentElement();
0466:                    handleErrors(fedexSubscriptionReplyElement, errorList);
0467:
0468:                    if (UtilValidate.isNotEmpty(errorList)) {
0469:                        return ServiceUtil.returnError(errorList);
0470:                    }
0471:
0472:                    String meterNumber = UtilXml.childElementValue(
0473:                            fedexSubscriptionReplyElement, "MeterNumber");
0474:
0475:                    result.put("meterNumber", meterNumber);
0476:
0477:                } catch (GenericEntityException e) {
0478:                    Debug.logError(e, module);
0479:                    return ServiceUtil.returnError(e.getMessage());
0480:                }
0481:
0482:                return result;
0483:            }
0484:
0485:            /**
0486:             * 
0487:             * Send a FDXShipRequest via the Ship Manager Direct API
0488:             */
0489:            public static Map fedexShipRequest(DispatchContext dctx, Map context) {
0490:                GenericDelegator delegator = dctx.getDelegator();
0491:                LocalDispatcher dispatcher = dctx.getDispatcher();
0492:                GenericValue userLogin = (GenericValue) context
0493:                        .get("userLogin");
0494:                Locale locale = (Locale) context.get("locale");
0495:                Map result = ServiceUtil.returnSuccess();
0496:
0497:                String shipmentId = (String) context.get("shipmentId");
0498:                String shipmentRouteSegmentId = (String) context
0499:                        .get("shipmentRouteSegmentId");
0500:
0501:                // Get the location of the Freemarker (XML) template for the FDXShipRequest
0502:                String templateLocation = UtilProperties.getPropertyValue(
0503:                        shipmentPropertiesFile,
0504:                        "shipment.template.fedex.ship.location");
0505:                if (UtilValidate.isEmpty(templateLocation)) {
0506:                    return ServiceUtil
0507:                            .returnError("Can't find location for FDXShipRequest template - should be in "
0508:                                    + shipmentPropertiesFile
0509:                                    + ":shipment.template.fedex.ship.location");
0510:                }
0511:
0512:                // Get the Fedex account number
0513:                String accountNumber = UtilProperties.getPropertyValue(
0514:                        shipmentPropertiesFile,
0515:                        "shipment.fedex.access.accountNbr");
0516:                if (UtilValidate.isEmpty(accountNumber)) {
0517:                    return ServiceUtil
0518:                            .returnError("accountNbr not found for Fedex ship request.");
0519:                }
0520:
0521:                // Get the Fedex meter number
0522:                String meterNumber = UtilProperties.getPropertyValue(
0523:                        shipmentPropertiesFile,
0524:                        "shipment.fedex.access.meterNumber");
0525:                if (UtilValidate.isEmpty(meterNumber)) {
0526:                    return ServiceUtil
0527:                            .returnError("Meter number not found for Fedex ship request - should be in "
0528:                                    + shipmentPropertiesFile
0529:                                    + ":shipment.fedex.access.meterNumber (run the fedexSubscriptionRequest service).");
0530:                }
0531:
0532:                // Get the weight units to be used in the request
0533:                String weightUomId = UtilProperties.getPropertyValue(
0534:                        shipmentPropertiesFile, "shipment.default.weight.uom");
0535:                if (UtilValidate.isEmpty(weightUomId)) {
0536:                    return ServiceUtil
0537:                            .returnError("Default weightUomId not found for Fedex ship request - should be in "
0538:                                    + shipmentPropertiesFile
0539:                                    + ":shipment.default.weight.uom.");
0540:                } else if (!("WT_lb".equals(weightUomId) || "WT_kg"
0541:                        .equals(weightUomId))) {
0542:                    return ServiceUtil
0543:                            .returnError("WeightUomId in "
0544:                                    + shipmentPropertiesFile
0545:                                    + ":shipment.default.weight.uom must be either WT_lb or WT_kg.");
0546:                }
0547:
0548:                // Get the dimension units to be used in the request
0549:                String dimensionsUomId = UtilProperties.getPropertyValue(
0550:                        shipmentPropertiesFile,
0551:                        "shipment.default.dimension.uom");
0552:                if (UtilValidate.isEmpty(dimensionsUomId)) {
0553:                    return ServiceUtil
0554:                            .returnError("Default dimensionUomId not found for Fedex ship request - should be in "
0555:                                    + shipmentPropertiesFile
0556:                                    + ":shipment.default.dimension.uom.");
0557:                } else if (!("LEN_in".equals(dimensionsUomId) || "LEN_cm"
0558:                        .equals(dimensionsUomId))) {
0559:                    return ServiceUtil
0560:                            .returnError("WeightUomId in "
0561:                                    + shipmentPropertiesFile
0562:                                    + ":shipment.default.dimension.uom must be either LEN_in or LEN_cm.");
0563:                }
0564:
0565:                // Get the label image type to be returned
0566:                String labelImageType = UtilProperties
0567:                        .getPropertyValue(shipmentPropertiesFile,
0568:                                "shipment.fedex.labelImageType");
0569:                if (UtilValidate.isEmpty(labelImageType)) {
0570:                    return ServiceUtil
0571:                            .returnError("LabelImageType not found for Fedex ship request - should be in "
0572:                                    + shipmentPropertiesFile
0573:                                    + ":shipment.fedex.labelImageType.");
0574:                } else if (!("PDF".equals(labelImageType) || "PNG"
0575:                        .equals(labelImageType))) {
0576:                    return ServiceUtil
0577:                            .returnError("LabelImageType in "
0578:                                    + shipmentPropertiesFile
0579:                                    + ":shipment.fedex.labelImageType must be either PDF or PNG.");
0580:                }
0581:
0582:                // Get the default dropoff type
0583:                String dropoffType = UtilProperties.getPropertyValue(
0584:                        shipmentPropertiesFile,
0585:                        "shipment.fedex.default.dropoffType");
0586:                if (UtilValidate.isEmpty(dropoffType)) {
0587:                    return ServiceUtil
0588:                            .returnError("Default dropoff type not found for Fedex ship request - should be in "
0589:                                    + shipmentPropertiesFile
0590:                                    + ":shipment.fedex.default.dropoffType.");
0591:                }
0592:
0593:                try {
0594:
0595:                    Map shipRequestContext = new HashMap();
0596:
0597:                    // Get the shipment and the shipmentRouteSegment
0598:                    GenericValue shipment = delegator.findByPrimaryKey(
0599:                            "Shipment", UtilMisc
0600:                                    .toMap("shipmentId", shipmentId));
0601:                    if (UtilValidate.isEmpty(shipment)) {
0602:                        return ServiceUtil
0603:                                .returnError("Shipment not found with ID "
0604:                                        + shipmentId);
0605:                    }
0606:                    GenericValue shipmentRouteSegment = delegator
0607:                            .findByPrimaryKey("ShipmentRouteSegment", UtilMisc
0608:                                    .toMap("shipmentId", shipmentId,
0609:                                            "shipmentRouteSegmentId",
0610:                                            shipmentRouteSegmentId));
0611:                    if (UtilValidate.isEmpty(shipmentRouteSegment)) {
0612:                        return ServiceUtil
0613:                                .returnError("ShipmentRouteSegment not found with shipmentId "
0614:                                        + shipmentId
0615:                                        + " and shipmentRouteSegmentId "
0616:                                        + shipmentRouteSegmentId);
0617:                    }
0618:
0619:                    // Determine the Fedex carrier
0620:                    String carrierPartyId = shipmentRouteSegment
0621:                            .getString("carrierPartyId");
0622:                    if (!"FEDEX".equals(carrierPartyId)) {
0623:                        return ServiceUtil
0624:                                .returnError("ERROR: The Carrier for ShipmentRouteSegment "
0625:                                        + shipmentRouteSegmentId
0626:                                        + " of Shipment "
0627:                                        + shipmentId
0628:                                        + ", is not Fedex.");
0629:                    }
0630:
0631:                    // Check the shipmentRouteSegment's carrier status
0632:                    if (UtilValidate.isNotEmpty(shipmentRouteSegment
0633:                            .getString("carrierServiceStatusId"))
0634:                            && !"SHRSCS_NOT_STARTED"
0635:                                    .equals(shipmentRouteSegment
0636:                                            .getString("carrierServiceStatusId"))) {
0637:                        return ServiceUtil
0638:                                .returnError("ERROR: The Carrier Service Status for ShipmentRouteSegment "
0639:                                        + shipmentRouteSegmentId
0640:                                        + " of Shipment "
0641:                                        + shipmentId
0642:                                        + ", is ["
0643:                                        + shipmentRouteSegment
0644:                                                .getString("carrierServiceStatusId")
0645:                                        + "], but must be not-set or [SHRSCS_NOT_STARTED] to perform the Fedex Shipment Confirm operation.");
0646:                    }
0647:
0648:                    // Translate shipmentMethodTypeId to Fedex service code and carrier code
0649:                    String shipmentMethodTypeId = shipmentRouteSegment
0650:                            .getString("shipmentMethodTypeId");
0651:                    GenericValue carrierShipmentMethod = delegator
0652:                            .findByPrimaryKey("CarrierShipmentMethod", UtilMisc
0653:                                    .toMap("shipmentMethodTypeId",
0654:                                            shipmentMethodTypeId, "partyId",
0655:                                            "FEDEX", "roleTypeId", "CARRIER"));
0656:                    if (UtilValidate.isEmpty(carrierShipmentMethod)) {
0657:                        return ServiceUtil
0658:                                .returnError("No CarrierShipmentMethod entry for carrier Fedex shipmentMethodTypeId "
0659:                                        + shipmentMethodTypeId);
0660:                    }
0661:                    if (UtilValidate.isEmpty(carrierShipmentMethod
0662:                            .getString("carrierServiceCode"))) {
0663:                        return ServiceUtil
0664:                                .returnError("No Carrier service code for carrier Fedex shipmentMethodTypeId "
0665:                                        + shipmentMethodTypeId);
0666:                    }
0667:                    String service = carrierShipmentMethod
0668:                            .getString("carrierServiceCode");
0669:
0670:                    // CarrierCode is FDXG only for FEDEXGROUND and GROUNDHOMEDELIVERY services.
0671:                    boolean isGroundService = service.equals("FEDEXGROUND")
0672:                            || service.equals("GROUNDHOMEDELIVERY");
0673:                    String carrierCode = isGroundService ? "FDXG" : "FDXE";
0674:
0675:                    // Determine the currency by trying the shipmentRouteSegment, then the Shipment, then the framework's default currency, and finally default to USD
0676:                    String currencyCode = null;
0677:                    if (UtilValidate.isNotEmpty(shipmentRouteSegment
0678:                            .getString("currencyUomId"))) {
0679:                        currencyCode = shipmentRouteSegment
0680:                                .getString("currencyUomId");
0681:                    } else if (UtilValidate.isNotEmpty(shipmentRouteSegment
0682:                            .getString("currencyUomId"))) {
0683:                        currencyCode = shipment.getString("currencyUomId");
0684:                    } else {
0685:                        currencyCode = UtilProperties.getPropertyValue(
0686:                                "general.properties",
0687:                                "currency.uom.id.default", "USD");
0688:                    }
0689:
0690:                    // Get and validate origin postal address
0691:                    GenericValue originPostalAddress = shipmentRouteSegment
0692:                            .getRelatedOne("OriginPostalAddress");
0693:                    if (UtilValidate.isEmpty(originPostalAddress)) {
0694:                        return ServiceUtil
0695:                                .returnError("OriginPostalAddress not found for ShipmentRouteSegment with shipmentId "
0696:                                        + shipmentId
0697:                                        + " and shipmentRouteSegmentId "
0698:                                        + shipmentRouteSegmentId);
0699:                    } else if (UtilValidate.isEmpty(originPostalAddress
0700:                            .getString("address1"))
0701:                            || UtilValidate.isEmpty(originPostalAddress
0702:                                    .getString("city"))
0703:                            || UtilValidate.isEmpty(originPostalAddress
0704:                                    .getString("postalCode"))
0705:                            || UtilValidate.isEmpty(originPostalAddress
0706:                                    .getString("countryGeoId"))) {
0707:                        return ServiceUtil
0708:                                .returnError("OriginPostalAddress not complete for ShipmentRouteSegment with shipmentId "
0709:                                        + shipmentId
0710:                                        + " and shipmentRouteSegmentId "
0711:                                        + shipmentRouteSegmentId
0712:                                        + " (missing address1, city, postalCode and/or countryGeoId).");
0713:                    }
0714:                    GenericValue originCountryGeo = originPostalAddress
0715:                            .getRelatedOne("CountryGeo");
0716:                    if (UtilValidate.isEmpty(originCountryGeo)) {
0717:                        return ServiceUtil
0718:                                .returnError("OriginCountryGeo not found for ShipmentRouteSegment with shipmentId "
0719:                                        + shipmentId
0720:                                        + " and shipmentRouteSegmentId "
0721:                                        + shipmentRouteSegmentId);
0722:                    }
0723:                    String originAddressCountryCode = originCountryGeo
0724:                            .getString("geoCode");
0725:                    String originAddressStateOrProvinceCode = null;
0726:
0727:                    // Only add the StateOrProvinceCode element if the address is in USA or Canada
0728:                    if (originAddressCountryCode.equals("CA")
0729:                            || originAddressCountryCode.equals("US")) {
0730:                        if (UtilValidate.isEmpty(originPostalAddress
0731:                                .getString("stateProvinceGeoId"))) {
0732:                            return ServiceUtil
0733:                                    .returnError("OriginStateProvinceGeoId required in contactMechId "
0734:                                            + originPostalAddress
0735:                                                    .getString("contactMechId")
0736:                                            + " for ShipmentRouteSegment with shipmentId "
0737:                                            + shipmentId
0738:                                            + " and shipmentRouteSegmentId "
0739:                                            + shipmentRouteSegmentId);
0740:                        }
0741:                        GenericValue stateProvinceGeo = delegator
0742:                                .findByPrimaryKeyCache(
0743:                                        "Geo",
0744:                                        UtilMisc
0745:                                                .toMap(
0746:                                                        "geoId",
0747:                                                        originPostalAddress
0748:                                                                .getString("stateProvinceGeoId")));
0749:                        originAddressStateOrProvinceCode = stateProvinceGeo
0750:                                .getString("geoCode");
0751:                    }
0752:
0753:                    // Get and validate origin telecom number
0754:                    GenericValue originTelecomNumber = shipmentRouteSegment
0755:                            .getRelatedOne("OriginTelecomNumber");
0756:                    if (UtilValidate.isEmpty(originTelecomNumber)) {
0757:                        return ServiceUtil
0758:                                .returnError("OriginTelecomNumber not found for ShipmentRouteSegment with shipmentId "
0759:                                        + shipmentId
0760:                                        + " and shipmentRouteSegmentId "
0761:                                        + shipmentRouteSegmentId);
0762:                    }
0763:                    String originContactPhoneNumber = originTelecomNumber
0764:                            .getString("areaCode")
0765:                            + originTelecomNumber.getString("contactNumber");
0766:
0767:                    // Fedex doesn't want the North American country code
0768:                    if (UtilValidate.isNotEmpty(originTelecomNumber
0769:                            .getString("countryCode"))
0770:                            && !(originAddressCountryCode.equals("CA") || originAddressCountryCode
0771:                                    .equals("US"))) {
0772:                        originContactPhoneNumber = originTelecomNumber
0773:                                .getString("countryCode")
0774:                                + originContactPhoneNumber;
0775:                    }
0776:                    originContactPhoneNumber = originContactPhoneNumber
0777:                            .replaceAll("[^+\\d]", "");
0778:
0779:                    // Get the origin contact name from the owner of the origin facility
0780:                    GenericValue partyFrom = null;
0781:                    GenericValue originFacility = shipment
0782:                            .getRelatedOne("OriginFacility");
0783:                    if (UtilValidate.isEmpty(originFacility)) {
0784:                        return ServiceUtil
0785:                                .returnError("Shipment.originFacilityId is required for Fedex shipments: shipmentId "
0786:                                        + shipmentId
0787:                                        + ", shipmentRouteSegmentId "
0788:                                        + shipmentRouteSegmentId);
0789:                    } else {
0790:                        partyFrom = originFacility.getRelatedOne("OwnerParty");
0791:                        if (UtilValidate.isEmpty(partyFrom)) {
0792:                            return ServiceUtil
0793:                                    .returnError("Facility.ownerPartyId is required for Fedex shipments: shipmentId "
0794:                                            + shipmentId
0795:                                            + ", shipmentRouteSegmentId "
0796:                                            + shipmentRouteSegmentId
0797:                                            + ", facilityId "
0798:                                            + originFacility
0799:                                                    .getString("facilityId"));
0800:                        }
0801:                    }
0802:
0803:                    String originContactKey = "PERSON".equals(partyFrom
0804:                            .getString("partyTypeId")) ? "OriginContactPersonName"
0805:                            : "OriginContactCompanyName";
0806:                    String originContactName = PartyHelper.getPartyName(
0807:                            partyFrom, false);
0808:                    if (UtilValidate.isEmpty(originContactName)) {
0809:                        return ServiceUtil
0810:                                .returnError("partyIdFrom for shipmentId "
0811:                                        + shipmentId
0812:                                        + ", shipmentRouteSegmentId "
0813:                                        + shipmentRouteSegmentId
0814:                                        + " has no name (required for Fedex shipments)");
0815:                    }
0816:
0817:                    // Get and validate destination postal address
0818:                    GenericValue destinationPostalAddress = shipmentRouteSegment
0819:                            .getRelatedOne("DestPostalAddress");
0820:                    if (UtilValidate.isEmpty(destinationPostalAddress)) {
0821:                        return ServiceUtil
0822:                                .returnError("destinationPostalAddress not found for ShipmentRouteSegment with shipmentId "
0823:                                        + shipmentId
0824:                                        + " and shipmentRouteSegmentId "
0825:                                        + shipmentRouteSegmentId);
0826:                    } else if (UtilValidate.isEmpty(destinationPostalAddress
0827:                            .getString("address1"))
0828:                            || UtilValidate.isEmpty(destinationPostalAddress
0829:                                    .getString("city"))
0830:                            || UtilValidate.isEmpty(destinationPostalAddress
0831:                                    .getString("postalCode"))
0832:                            || UtilValidate.isEmpty(destinationPostalAddress
0833:                                    .getString("countryGeoId"))) {
0834:                        return ServiceUtil
0835:                                .returnError("destinationPostalAddress not complete for ShipmentRouteSegment with shipmentId "
0836:                                        + shipmentId
0837:                                        + " and shipmentRouteSegmentId "
0838:                                        + shipmentRouteSegmentId
0839:                                        + " (missing address1, city, postalCode and/or countryGeoId).");
0840:                    }
0841:                    GenericValue destinationCountryGeo = destinationPostalAddress
0842:                            .getRelatedOne("CountryGeo");
0843:                    if (UtilValidate.isEmpty(destinationCountryGeo)) {
0844:                        return ServiceUtil
0845:                                .returnError("destinationCountryGeo not found for ShipmentRouteSegment with shipmentId "
0846:                                        + shipmentId
0847:                                        + " and shipmentRouteSegmentId "
0848:                                        + shipmentRouteSegmentId);
0849:                    }
0850:                    String destinationAddressCountryCode = destinationCountryGeo
0851:                            .getString("geoCode");
0852:                    String destinationAddressStateOrProvinceCode = null;
0853:
0854:                    // Only add the StateOrProvinceCode element if the address is in USA or Canada
0855:                    if (destinationAddressCountryCode.equals("CA")
0856:                            || destinationAddressCountryCode.equals("US")) {
0857:                        if (UtilValidate.isEmpty(destinationPostalAddress
0858:                                .getString("stateProvinceGeoId"))) {
0859:                            return ServiceUtil
0860:                                    .returnError("destinationStateProvinceGeoId required in contactMechId "
0861:                                            + destinationPostalAddress
0862:                                                    .getString("contactMechId")
0863:                                            + " for ShipmentRouteSegment with shipmentId "
0864:                                            + shipmentId
0865:                                            + " and shipmentRouteSegmentId "
0866:                                            + shipmentRouteSegmentId);
0867:                        }
0868:                        GenericValue stateProvinceGeo = delegator
0869:                                .findByPrimaryKeyCache(
0870:                                        "Geo",
0871:                                        UtilMisc
0872:                                                .toMap(
0873:                                                        "geoId",
0874:                                                        destinationPostalAddress
0875:                                                                .getString("stateProvinceGeoId")));
0876:                        destinationAddressStateOrProvinceCode = stateProvinceGeo
0877:                                .getString("geoCode");
0878:                    }
0879:
0880:                    // Get and validate destination telecom number
0881:                    GenericValue destinationTelecomNumber = shipmentRouteSegment
0882:                            .getRelatedOne("DestTelecomNumber");
0883:                    if (UtilValidate.isEmpty(destinationTelecomNumber)) {
0884:                        return ServiceUtil
0885:                                .returnError("destinationTelecomNumber not found for ShipmentRouteSegment with shipmentId "
0886:                                        + shipmentId
0887:                                        + " and shipmentRouteSegmentId "
0888:                                        + shipmentRouteSegmentId);
0889:                    }
0890:                    String destinationContactPhoneNumber = destinationTelecomNumber
0891:                            .getString("areaCode")
0892:                            + destinationTelecomNumber
0893:                                    .getString("contactNumber");
0894:
0895:                    // Fedex doesn't want the North American country code
0896:                    if (UtilValidate.isNotEmpty(destinationTelecomNumber
0897:                            .getString("countryCode"))
0898:                            && !(destinationAddressCountryCode.equals("CA") || destinationAddressCountryCode
0899:                                    .equals("US"))) {
0900:                        destinationContactPhoneNumber = destinationTelecomNumber
0901:                                .getString("countryCode")
0902:                                + destinationContactPhoneNumber;
0903:                    }
0904:                    destinationContactPhoneNumber = destinationContactPhoneNumber
0905:                            .replaceAll("[^+\\d]", "");
0906:
0907:                    // Get the destination contact name
0908:                    String destinationPartyId = shipment.getString("partyIdTo");
0909:                    if (UtilValidate.isEmpty(destinationPartyId)) {
0910:                        return ServiceUtil
0911:                                .returnError("Shipment.partyIdTo is required for Fedex shipments: shipmentId "
0912:                                        + shipmentId
0913:                                        + ", shipmentRouteSegmentId "
0914:                                        + shipmentRouteSegmentId);
0915:                    }
0916:                    GenericValue partyTo = delegator.findByPrimaryKey("Party",
0917:                            UtilMisc.toMap("partyId", destinationPartyId));
0918:                    String destinationContactKey = "PERSON".equals(partyTo
0919:                            .getString("partyTypeId")) ? "DestinationContactPersonName"
0920:                            : "DestinationContactCompanyName";
0921:                    String destinationContactName = PartyHelper.getPartyName(
0922:                            partyTo, false);
0923:                    if (UtilValidate.isEmpty(destinationContactName)) {
0924:                        return ServiceUtil
0925:                                .returnError("partyTo for shipmentId "
0926:                                        + shipmentId
0927:                                        + ", shipmentRouteSegmentId "
0928:                                        + shipmentRouteSegmentId
0929:                                        + " has no name (required for Fedex shipments)");
0930:                    }
0931:
0932:                    String homeDeliveryType = null;
0933:                    Timestamp homeDeliveryDate = null;
0934:                    if ("GROUNDHOMEDELIVERY".equals(service)) {
0935:
0936:                        // Determine the home-delivery instructions
0937:                        homeDeliveryType = shipmentRouteSegment
0938:                                .getString("homeDeliveryType");
0939:                        if (UtilValidate.isNotEmpty(homeDeliveryType)) {
0940:                            if (!(homeDeliveryType.equals("DATECERTAIN")
0941:                                    || homeDeliveryType.equals("EVENING") || homeDeliveryType
0942:                                    .equals("APPOINTMENT"))) {
0943:                                return ServiceUtil
0944:                                        .returnError("Invalid homeDeliveryType for ShipmentRouteSegment with shipmentId "
0945:                                                + shipmentId
0946:                                                + " and shipmentRouteSegmentId "
0947:                                                + shipmentRouteSegmentId);
0948:                            }
0949:                        }
0950:                        homeDeliveryDate = shipmentRouteSegment
0951:                                .getTimestamp("homeDeliveryDate");
0952:                        if (UtilValidate.isEmpty(homeDeliveryDate)) {
0953:                            return ServiceUtil
0954:                                    .returnError("homeDeliveryDate required for home deliveryType shipments - ShipmentRouteSegment with shipmentId "
0955:                                            + shipmentId
0956:                                            + " and shipmentRouteSegmentId "
0957:                                            + shipmentRouteSegmentId);
0958:                        } else if (homeDeliveryDate.before(UtilDateTime
0959:                                .nowTimestamp())) {
0960:                            return ServiceUtil
0961:                                    .returnError("homeDeliveryDate is before the current time for ShipmentRouteSegment with shipmentId "
0962:                                            + shipmentId
0963:                                            + " and shipmentRouteSegmentId "
0964:                                            + shipmentRouteSegmentId);
0965:                        }
0966:                    }
0967:
0968:                    List shipmentPackageRouteSegs = shipmentRouteSegment
0969:                            .getRelated("ShipmentPackageRouteSeg", UtilMisc
0970:                                    .toList("+shipmentPackageSeqId"));
0971:                    if (UtilValidate.isEmpty(shipmentPackageRouteSegs)) {
0972:                        return ServiceUtil
0973:                                .returnError("No ShipmentPackageRouteSegs (ie No Packages) found for ShipmentRouteSegment with shipmentId "
0974:                                        + shipmentId
0975:                                        + " and shipmentRouteSegmentId "
0976:                                        + shipmentRouteSegmentId);
0977:                    }
0978:                    if (shipmentPackageRouteSegs.size() != 1) {
0979:                        return ServiceUtil
0980:                                .returnError("Cannot confirm shipment: fedexShipRequest service does not currently support more than one package per shipment.");
0981:                    }
0982:
0983:                    // TODO: Multi-piece shipments, including logic to cancel packages 1-n if FDXShipRequest n+1 fails
0984:
0985:                    // Populate the Freemarker context with the non-package-related information
0986:                    shipRequestContext.put("AccountNumber", accountNumber);
0987:                    shipRequestContext.put("MeterNumber", meterNumber);
0988:                    shipRequestContext.put("CarrierCode", carrierCode);
0989:                    shipRequestContext.put("ShipDate", UtilDateTime
0990:                            .nowTimestamp());
0991:                    shipRequestContext.put("ShipTime", UtilDateTime
0992:                            .nowTimestamp());
0993:                    shipRequestContext.put("DropoffType", dropoffType);
0994:                    shipRequestContext.put("Service", service);
0995:                    shipRequestContext.put("WeightUnits", weightUomId
0996:                            .equals("WT_kg") ? "KGS" : "LBS");
0997:                    shipRequestContext.put("CurrencyCode", currencyCode);
0998:                    shipRequestContext.put("PayorType", "SENDER");
0999:                    shipRequestContext.put(originContactKey, originContactName);
1000:                    shipRequestContext.put("OriginContactPhoneNumber",
1001:                            originContactPhoneNumber);
1002:                    shipRequestContext.put("OriginAddressLine1",
1003:                            originPostalAddress.getString("address1"));
1004:                    if (UtilValidate.isNotEmpty(originPostalAddress
1005:                            .getString("address2"))) {
1006:                        shipRequestContext.put("OriginAddressLine2",
1007:                                originPostalAddress.getString("address2"));
1008:                    }
1009:                    shipRequestContext.put("OriginAddressCity",
1010:                            originPostalAddress.getString("city"));
1011:                    if (UtilValidate
1012:                            .isNotEmpty(originAddressStateOrProvinceCode)) {
1013:                        shipRequestContext.put(
1014:                                "OriginAddressStateOrProvinceCode",
1015:                                originAddressStateOrProvinceCode);
1016:                    }
1017:                    shipRequestContext.put("OriginAddressPostalCode",
1018:                            originPostalAddress.getString("postalCode"));
1019:                    shipRequestContext.put("OriginAddressCountryCode",
1020:                            originAddressCountryCode);
1021:                    shipRequestContext.put(destinationContactKey,
1022:                            destinationContactName);
1023:                    shipRequestContext.put("DestinationContactPhoneNumber",
1024:                            destinationContactPhoneNumber);
1025:                    shipRequestContext.put("DestinationAddressLine1",
1026:                            destinationPostalAddress.getString("address1"));
1027:                    if (UtilValidate.isNotEmpty(destinationPostalAddress
1028:                            .getString("address2"))) {
1029:                        shipRequestContext.put("DestinationAddressLine2",
1030:                                destinationPostalAddress.getString("address2"));
1031:                    }
1032:                    shipRequestContext.put("DestinationAddressCity",
1033:                            destinationPostalAddress.getString("city"));
1034:                    if (UtilValidate
1035:                            .isNotEmpty(destinationAddressStateOrProvinceCode)) {
1036:                        shipRequestContext.put(
1037:                                "DestinationAddressStateOrProvinceCode",
1038:                                destinationAddressStateOrProvinceCode);
1039:                    }
1040:                    shipRequestContext.put("DestinationAddressPostalCode",
1041:                            destinationPostalAddress.getString("postalCode"));
1042:                    shipRequestContext.put("DestinationAddressCountryCode",
1043:                            destinationAddressCountryCode);
1044:                    shipRequestContext.put("LabelType", "2DCOMMON"); // Required type for FDXShipRequest. Not directly in the FTL because it shouldn't be changed.
1045:                    shipRequestContext.put("LabelImageType", labelImageType);
1046:                    if (UtilValidate.isNotEmpty(homeDeliveryType)) {
1047:                        shipRequestContext.put("HomeDeliveryType",
1048:                                homeDeliveryType);
1049:                    }
1050:                    if (homeDeliveryDate != null) {
1051:                        shipRequestContext.put("HomeDeliveryDate",
1052:                                homeDeliveryDate);
1053:                    }
1054:
1055:                    // Get the weight from the ShipmentRouteSegment first, which overrides all later weight computations
1056:                    boolean hasBillingWeight = false;
1057:                    Double billingWeight = shipmentRouteSegment
1058:                            .getDouble("billingWeight");
1059:                    String billingWeightUomId = shipmentRouteSegment
1060:                            .getString("billingWeightUomId");
1061:                    if ((billingWeight != null)
1062:                            && (billingWeight.doubleValue() > 0)) {
1063:                        hasBillingWeight = true;
1064:                        if (billingWeightUomId == null) {
1065:                            Debug
1066:                                    .logWarning(
1067:                                            "Shipment Route Segment missing billingWeightUomId in shipmentId "
1068:                                                    + shipmentId
1069:                                                    + ", assuming default shipment.fedex.weightUomId of "
1070:                                                    + weightUomId + " from "
1071:                                                    + shipmentPropertiesFile,
1072:                                            module);
1073:                            billingWeightUomId = weightUomId;
1074:                        }
1075:
1076:                        // Convert the weight if necessary
1077:                        if (!billingWeightUomId.equals(weightUomId)) {
1078:                            Map results = dispatcher.runSync("convertUom",
1079:                                    UtilMisc.toMap("uomId", billingWeightUomId,
1080:                                            "uomIdTo", weightUomId,
1081:                                            "originalValue", billingWeight));
1082:                            if (ServiceUtil.isError(results)
1083:                                    || (results.get("convertedValue") == null)) {
1084:                                Debug.logWarning(
1085:                                        "Unable to convert billing weights for shipmentId "
1086:                                                + shipmentId, module);
1087:
1088:                                // Try getting the weight from package instead
1089:                                hasBillingWeight = false;
1090:                            } else {
1091:                                billingWeight = (Double) results
1092:                                        .get("convertedValue");
1093:                            }
1094:                        }
1095:                    }
1096:
1097:                    // Loop through Shipment segments (NOTE: only one supported, loop is here for future refactoring reference)
1098:                    Iterator shipmentPackageRouteSegIter = shipmentPackageRouteSegs
1099:                            .iterator();
1100:                    while (shipmentPackageRouteSegIter.hasNext()) {
1101:
1102:                        GenericValue shipmentPackageRouteSeg = (GenericValue) shipmentPackageRouteSegIter
1103:                                .next();
1104:                        GenericValue shipmentPackage = shipmentPackageRouteSeg
1105:                                .getRelatedOne("ShipmentPackage");
1106:                        GenericValue shipmentBoxType = shipmentPackage
1107:                                .getRelatedOne("ShipmentBoxType");
1108:
1109:                        // FedEx requires the packaging type
1110:                        String packaging = null;
1111:                        if (UtilValidate.isEmpty(shipmentBoxType)) {
1112:                            Debug
1113:                                    .logWarning(
1114:                                            "Package "
1115:                                                    + shipmentPackage
1116:                                                            .getString("shipmentPackageSeqId")
1117:                                                    + " of shipment "
1118:                                                    + shipmentId
1119:                                                    + " has no packaging type set - defaulting to "
1120:                                                    + shipmentPropertiesFile
1121:                                                    + ":shipment.fedex.default.packagingType",
1122:                                            module);
1123:
1124:                            // Try to get the default packaging type
1125:                            packaging = UtilProperties.getPropertyValue(
1126:                                    shipmentPropertiesFile,
1127:                                    "shipment.fedex.default.packagingType");
1128:                            if (UtilValidate.isEmpty(packaging)) {
1129:                                return ServiceUtil
1130:                                        .returnError("Cannot confirm shipment: Package "
1131:                                                + shipmentPackage
1132:                                                        .getString("shipmentPackageSeqId")
1133:                                                + " of shipment "
1134:                                                + shipmentId
1135:                                                + " has no packaging type set, and "
1136:                                                + shipmentPropertiesFile
1137:                                                + ":shipment.fedex.default.packagingType is not configured");
1138:                            }
1139:                        } else {
1140:                            packaging = shipmentBoxType
1141:                                    .getString("shipmentBoxTypeId");
1142:                        }
1143:
1144:                        // Make sure that the packaging type is valid for FedEx
1145:                        GenericValue carrierShipmentBoxType = delegator
1146:                                .findByPrimaryKey("CarrierShipmentBoxType",
1147:                                        UtilMisc.toMap("partyId", "FEDEX",
1148:                                                "shipmentBoxTypeId", packaging));
1149:                        if (UtilValidate.isEmpty(carrierShipmentBoxType)) {
1150:                            return ServiceUtil
1151:                                    .returnError("Cannot confirm shipment: Package "
1152:                                            + shipmentPackage
1153:                                                    .getString("shipmentPackageSeqId")
1154:                                            + " of shipment "
1155:                                            + shipmentId
1156:                                            + " has an invalid packaging type for FedEx.");
1157:                        } else if (UtilValidate.isEmpty(carrierShipmentBoxType
1158:                                .getString("packagingTypeCode"))) {
1159:                            return ServiceUtil
1160:                                    .returnError("Cannot confirm shipment: Package type for package "
1161:                                            + shipmentPackage
1162:                                                    .getString("shipmentPackageSeqId")
1163:                                            + " of shipment "
1164:                                            + shipmentId
1165:                                            + " is missing packagingTypeCode.");
1166:                        }
1167:                        packaging = carrierShipmentBoxType
1168:                                .getString("packagingTypeCode");
1169:
1170:                        // Determine the dimensions of the package
1171:                        Double dimensionsLength = null;
1172:                        Double dimensionsWidth = null;
1173:                        Double dimensionsHeight = null;
1174:                        if (shipmentBoxType != null) {
1175:                            dimensionsLength = shipmentBoxType
1176:                                    .getDouble("boxLength");
1177:                            dimensionsWidth = shipmentBoxType
1178:                                    .getDouble("boxWidth");
1179:                            dimensionsHeight = shipmentBoxType
1180:                                    .getDouble("boxHeight");
1181:
1182:                            String boxDimensionsUomId = null;
1183:                            GenericValue boxDimensionsUom = shipmentBoxType
1184:                                    .getRelatedOne("DimensionUom");
1185:                            if (!UtilValidate.isEmpty(boxDimensionsUom)) {
1186:                                boxDimensionsUomId = boxDimensionsUom
1187:                                        .getString("uomId");
1188:                            } else {
1189:                                Debug
1190:                                        .logWarning(
1191:                                                "Packaging type for package "
1192:                                                        + shipmentPackage
1193:                                                                .getString("shipmentPackageSeqId")
1194:                                                        + " of shipmentRouteSegment "
1195:                                                        + shipmentRouteSegmentId
1196:                                                        + " of shipment "
1197:                                                        + shipmentId
1198:                                                        + " is missing dimensionUomId, assuming default shipment.default.dimension.uom of "
1199:                                                        + dimensionsUomId
1200:                                                        + " from "
1201:                                                        + shipmentPropertiesFile,
1202:                                                module);
1203:                                boxDimensionsUomId = dimensionsUomId;
1204:                            }
1205:                            if (dimensionsLength != null
1206:                                    && dimensionsLength.doubleValue() > 0) {
1207:                                if (!boxDimensionsUomId.equals(dimensionsUomId)) {
1208:                                    Map results = dispatcher.runSync(
1209:                                            "convertUom", UtilMisc.toMap(
1210:                                                    "uomId",
1211:                                                    boxDimensionsUomId,
1212:                                                    "uomIdTo", dimensionsUomId,
1213:                                                    "originalValue",
1214:                                                    dimensionsLength));
1215:                                    if (ServiceUtil.isError(results)
1216:                                            || (results.get("convertedValue") == null)) {
1217:                                        Debug
1218:                                                .logWarning(
1219:                                                        "Unable to convert length for package "
1220:                                                                + shipmentPackage
1221:                                                                        .getString("shipmentPackageSeqId")
1222:                                                                + " of shipmentRouteSegment "
1223:                                                                + shipmentRouteSegmentId
1224:                                                                + " of shipment "
1225:                                                                + shipmentId,
1226:                                                        module);
1227:                                        dimensionsLength = null;
1228:                                    } else {
1229:                                        dimensionsLength = (Double) results
1230:                                                .get("convertedValue");
1231:                                    }
1232:                                }
1233:
1234:                            }
1235:                            if (dimensionsWidth != null
1236:                                    && dimensionsWidth.doubleValue() > 0) {
1237:                                if (!boxDimensionsUomId.equals(dimensionsUomId)) {
1238:                                    Map results = dispatcher.runSync(
1239:                                            "convertUom", UtilMisc.toMap(
1240:                                                    "uomId",
1241:                                                    boxDimensionsUomId,
1242:                                                    "uomIdTo", dimensionsUomId,
1243:                                                    "originalValue",
1244:                                                    dimensionsWidth));
1245:                                    if (ServiceUtil.isError(results)
1246:                                            || (results.get("convertedValue") == null)) {
1247:                                        Debug
1248:                                                .logWarning(
1249:                                                        "Unable to convert width for package "
1250:                                                                + shipmentPackage
1251:                                                                        .getString("shipmentPackageSeqId")
1252:                                                                + " of shipmentRouteSegment "
1253:                                                                + shipmentRouteSegmentId
1254:                                                                + " of shipment "
1255:                                                                + shipmentId,
1256:                                                        module);
1257:                                        dimensionsWidth = null;
1258:                                    } else {
1259:                                        dimensionsWidth = (Double) results
1260:                                                .get("convertedValue");
1261:                                    }
1262:                                }
1263:
1264:                            }
1265:                            if (dimensionsHeight != null
1266:                                    && dimensionsHeight.doubleValue() > 0) {
1267:                                if (!boxDimensionsUomId.equals(dimensionsUomId)) {
1268:                                    Map results = dispatcher.runSync(
1269:                                            "convertUom", UtilMisc.toMap(
1270:                                                    "uomId",
1271:                                                    boxDimensionsUomId,
1272:                                                    "uomIdTo", dimensionsUomId,
1273:                                                    "originalValue",
1274:                                                    dimensionsHeight));
1275:                                    if (ServiceUtil.isError(results)
1276:                                            || (results.get("convertedValue") == null)) {
1277:                                        Debug
1278:                                                .logWarning(
1279:                                                        "Unable to convert height for package "
1280:                                                                + shipmentPackage
1281:                                                                        .getString("shipmentPackageSeqId")
1282:                                                                + " of shipmentRouteSegment "
1283:                                                                + shipmentRouteSegmentId
1284:                                                                + " of shipment "
1285:                                                                + shipmentId,
1286:                                                        module);
1287:                                        dimensionsHeight = null;
1288:                                    } else {
1289:                                        dimensionsHeight = (Double) results
1290:                                                .get("convertedValue");
1291:                                    }
1292:                                }
1293:
1294:                            }
1295:                        }
1296:
1297:                        // Determine the package weight (possibly overriden by route segment billing weight)
1298:                        Double packageWeight = null;
1299:                        if (!hasBillingWeight) {
1300:                            if (UtilValidate.isNotEmpty(shipmentPackage
1301:                                    .getString("weight"))) {
1302:                                packageWeight = shipmentPackage
1303:                                        .getDouble("weight");
1304:                            } else {
1305:
1306:                                // Use default weight if available
1307:                                try {
1308:                                    packageWeight = Double
1309:                                            .valueOf(UtilProperties
1310:                                                    .getPropertyValue(
1311:                                                            shipmentPropertiesFile,
1312:                                                            "shipment.default.weight.value"));
1313:                                } catch (NumberFormatException ne) {
1314:                                    Debug
1315:                                            .logWarning(
1316:                                                    "Default shippable weight not configured (shipment.default.weight.value), assuming 1.0"
1317:                                                            + weightUomId,
1318:                                                    module);
1319:                                    packageWeight = new Double(1.0);
1320:                                }
1321:                            }
1322:
1323:                            // Convert weight if necessary
1324:                            String packageWeightUomId = shipmentPackage
1325:                                    .getString("weightUomId");
1326:                            if (UtilValidate.isEmpty(packageWeightUomId)) {
1327:                                Debug
1328:                                        .logWarning(
1329:                                                "Shipment Route Segment missing weightUomId in shipmentId "
1330:                                                        + shipmentId
1331:                                                        + ", assuming shipment.default.weight.uom of "
1332:                                                        + weightUomId
1333:                                                        + " from "
1334:                                                        + shipmentPropertiesFile,
1335:                                                module);
1336:                                packageWeightUomId = weightUomId;
1337:                            }
1338:                            if (!packageWeightUomId.equals(weightUomId)) {
1339:                                Map results = dispatcher.runSync("convertUom",
1340:                                        UtilMisc.toMap("uomId",
1341:                                                packageWeightUomId, "uomIdTo",
1342:                                                weightUomId, "originalValue",
1343:                                                packageWeight));
1344:                                if (ServiceUtil.isError(results)
1345:                                        || (results.get("convertedValue") == null)) {
1346:                                    ServiceUtil
1347:                                            .returnError("Unable to convert weight for package "
1348:                                                    + shipmentPackage
1349:                                                            .getString("shipmentPackageSeqId")
1350:                                                    + " of shipmentRouteSegment "
1351:                                                    + shipmentRouteSegmentId
1352:                                                    + " of shipment "
1353:                                                    + shipmentId);
1354:                                } else {
1355:                                    packageWeight = (Double) results
1356:                                            .get("convertedValue");
1357:                                }
1358:                            }
1359:                        }
1360:                        Double weight = hasBillingWeight ? billingWeight
1361:                                : packageWeight;
1362:                        if (weight == null || weight.doubleValue() < 0) {
1363:                            ServiceUtil
1364:                                    .returnError("Unable to determine weight for package "
1365:                                            + shipmentPackage
1366:                                                    .getString("shipmentPackageSeqId")
1367:                                            + " of shipmentRouteSegment "
1368:                                            + shipmentRouteSegmentId
1369:                                            + " of shipment " + shipmentId);
1370:                        }
1371:
1372:                        // Populate the Freemarker context with package-related information
1373:                        shipRequestContext.put("CustomerReference", shipmentId
1374:                                + ":"
1375:                                + shipmentRouteSegmentId
1376:                                + ":"
1377:                                + shipmentPackage
1378:                                        .getString("shipmentPackageSeqId"));
1379:                        shipRequestContext.put("DropoffType", dropoffType);
1380:                        shipRequestContext.put("Packaging", packaging);
1381:                        if (UtilValidate.isNotEmpty(dimensionsUomId)
1382:                                && dimensionsLength != null
1383:                                && Math.round(dimensionsLength.doubleValue()) > 0
1384:                                && dimensionsWidth != null
1385:                                && Math.round(dimensionsWidth.doubleValue()) > 0
1386:                                && dimensionsHeight != null
1387:                                && Math.round(dimensionsHeight.doubleValue()) > 0) {
1388:                            shipRequestContext.put("DimensionsUnits",
1389:                                    dimensionsUomId.equals("LEN_in") ? "IN"
1390:                                            : "CM");
1391:                            shipRequestContext.put("DimensionsLength", ""
1392:                                    + Math
1393:                                            .round(dimensionsLength
1394:                                                    .doubleValue()));
1395:                            shipRequestContext
1396:                                    .put("DimensionsWidth", ""
1397:                                            + Math.round(dimensionsWidth
1398:                                                    .doubleValue()));
1399:                            shipRequestContext.put("DimensionsHeight", ""
1400:                                    + Math
1401:                                            .round(dimensionsHeight
1402:                                                    .doubleValue()));
1403:                        }
1404:                        shipRequestContext.put("Weight", new BigDecimal(weight
1405:                                .doubleValue())
1406:                                .setScale(1, BigDecimal.ROUND_UP).toString());
1407:                    }
1408:
1409:                    StringWriter outWriter = new StringWriter();
1410:                    try {
1411:                        FreeMarkerWorker
1412:                                .renderTemplateAtLocation(templateLocation,
1413:                                        shipRequestContext, outWriter);
1414:                    } catch (Exception e) {
1415:                        String errorMessage = "Cannot confirm Fedex shipment: Failed to render Fedex XML Ship Request Template ["
1416:                                + templateLocation + "].";
1417:                        Debug.logError(e, errorMessage, module);
1418:                        return ServiceUtil.returnError(errorMessage + ": "
1419:                                + e.getMessage());
1420:                    }
1421:
1422:                    // Pass the request string to the sending method
1423:                    String fDXShipRequestString = outWriter.toString();
1424:                    String fDXShipReplyString = null;
1425:                    try {
1426:                        fDXShipReplyString = sendFedexRequest(fDXShipRequestString);
1427:                        if (Debug.verboseOn()) {
1428:                            Debug.logVerbose(fDXShipReplyString, module);
1429:                        }
1430:                    } catch (FedexConnectException e) {
1431:                        String errorMessage = "Error sending Fedex request for FDXShipRequest: ";
1432:                        Debug.logError(e, errorMessage, module);
1433:                        return ServiceUtil.returnError(errorMessage
1434:                                + e.toString());
1435:                    }
1436:
1437:                    // Pass the reply to the handler method
1438:                    return handleFedexShipReply(fDXShipReplyString,
1439:                            shipmentRouteSegment, shipmentPackageRouteSegs);
1440:
1441:                } catch (GenericEntityException e) {
1442:                    Debug.logError(e, module);
1443:                    return ServiceUtil
1444:                            .returnError("Error in fedexShipRequest service: "
1445:                                    + e.toString());
1446:                } catch (GenericServiceException se) {
1447:                    Debug.logError(se, module);
1448:                    return ServiceUtil
1449:                            .returnError("Error in fedexShipRequest service: "
1450:                                    + se.toString());
1451:                }
1452:            }
1453:
1454:            /**
1455:             * Extract the tracking number and shipping label from the FDXShipReply XML string
1456:             * @param fDXShipReplyString
1457:             * @param shipmentRouteSegment
1458:             * @param shipmentPackageRouteSegs
1459:             * @throws GenericEntityException
1460:             */
1461:            public static Map handleFedexShipReply(String fDXShipReplyString,
1462:                    GenericValue shipmentRouteSegment,
1463:                    List shipmentPackageRouteSegs)
1464:                    throws GenericEntityException {
1465:                List errorList = new ArrayList();
1466:                GenericValue shipmentPackageRouteSeg = (GenericValue) shipmentPackageRouteSegs
1467:                        .get(0);
1468:
1469:                Document fdxShipReplyDocument = null;
1470:                try {
1471:                    fdxShipReplyDocument = UtilXml.readXmlDocument(
1472:                            fDXShipReplyString, false);
1473:                } catch (SAXException se) {
1474:                    String errorMessage = "Error parsing the FDXShipReply: "
1475:                            + se.toString();
1476:                    Debug.logError(se, errorMessage, module);
1477:                    // TODO: Cancel the package
1478:                } catch (ParserConfigurationException pe) {
1479:                    String errorMessage = "Error parsing the FDXShipReply: "
1480:                            + pe.toString();
1481:                    Debug.logError(pe, errorMessage, module);
1482:                    // TODO Cancel the package
1483:                } catch (IOException ioe) {
1484:                    String errorMessage = "Error parsing the FDXShipReply: "
1485:                            + ioe.toString();
1486:                    Debug.logError(ioe, errorMessage, module);
1487:                    // TODO Cancel the package
1488:                }
1489:
1490:                if (UtilValidate.isEmpty(fdxShipReplyDocument)) {
1491:                    return ServiceUtil
1492:                            .returnError("Error parsing the FDXShipReply.");
1493:                }
1494:
1495:                // Tracking number: Tracking/TrackingNumber
1496:                Element rootElement = fdxShipReplyDocument.getDocumentElement();
1497:
1498:                handleErrors(rootElement, errorList);
1499:
1500:                if (UtilValidate.isNotEmpty(errorList)) {
1501:                    return ServiceUtil.returnError(errorList);
1502:                }
1503:
1504:                Element trackingElement = UtilXml.firstChildElement(
1505:                        rootElement, "Tracking");
1506:                String trackingNumber = UtilXml.childElementValue(
1507:                        trackingElement, "TrackingNumber");
1508:
1509:                // Label: Labels/OutboundLabel
1510:                Element labelElement = UtilXml.firstChildElement(rootElement,
1511:                        "Labels");
1512:                String encodedImageString = UtilXml.childElementValue(
1513:                        labelElement, "OutboundLabel");
1514:                if (UtilValidate.isEmpty(encodedImageString)) {
1515:                    Debug.logError(
1516:                            "Cannot find FDXShipReply label. FDXShipReply document is: "
1517:                                    + fDXShipReplyString, module);
1518:                    return ServiceUtil
1519:                            .returnError("Cannot get FDXShipReply label for shipment package route segment "
1520:                                    + shipmentPackageRouteSeg
1521:                                    + ".  FedEx response is: "
1522:                                    + fDXShipReplyString);
1523:                }
1524:
1525:                byte[] labelBytes = Base64.base64Decode(encodedImageString
1526:                        .getBytes());
1527:
1528:                if (labelBytes != null) {
1529:
1530:                    // Store in db blob
1531:                    shipmentPackageRouteSeg.setBytes("labelImage", labelBytes);
1532:                } else {
1533:                    Debug
1534:                            .log("Failed to either decode returned FedEx label or no data found in Labels/OutboundLabel.");
1535:                    // TODO: Cancel the package
1536:                }
1537:
1538:                shipmentPackageRouteSeg.set("trackingCode", trackingNumber);
1539:                shipmentPackageRouteSeg.set("labelHtml", encodedImageString);
1540:                shipmentPackageRouteSeg.store();
1541:
1542:                shipmentRouteSegment.set("trackingIdNumber", trackingNumber);
1543:                shipmentRouteSegment.put("carrierServiceStatusId",
1544:                        "SHRSCS_CONFIRMED");
1545:                shipmentRouteSegment.store();
1546:
1547:                return ServiceUtil.returnSuccess("FedEx Shipment Confirmed.");
1548:
1549:            }
1550:
1551:            public static void handleErrors(Element rootElement, List errorList) {
1552:                Element errorElement = null;
1553:                if ("Error".equalsIgnoreCase(rootElement.getNodeName())) {
1554:                    errorElement = rootElement;
1555:                } else {
1556:                    errorElement = UtilXml.firstChildElement(rootElement,
1557:                            "Error");
1558:                }
1559:                if (errorElement != null) {
1560:                    Element errorCodeElement = UtilXml.firstChildElement(
1561:                            errorElement, "Code");
1562:                    Element errorMessageElement = UtilXml.firstChildElement(
1563:                            errorElement, "Message");
1564:                    if (errorCodeElement != null || errorMessageElement != null) {
1565:                        String errorCode = UtilXml.childElementValue(
1566:                                errorElement, "Code");
1567:                        String errorMessage = UtilXml.childElementValue(
1568:                                errorElement, "Message");
1569:                        if (UtilValidate.isNotEmpty(errorCode)
1570:                                || UtilValidate.isNotEmpty(errorMessage)) {
1571:                            String errMsg = "An error occurred [code: "
1572:                                    + errorCode + " [Description: "
1573:                                    + errorMessage + "].";
1574:                            errorList.add(errMsg);
1575:                        }
1576:                    }
1577:                }
1578:            }
1579:
1580:        }
1581:
1582:        class FedexConnectException extends GeneralException {
1583:            FedexConnectException() {
1584:                super ();
1585:            }
1586:
1587:            FedexConnectException(String msg) {
1588:                super (msg);
1589:            }
1590:
1591:            FedexConnectException(Throwable t) {
1592:                super (t);
1593:            }
1594:
1595:            FedexConnectException(String msg, Throwable t) {
1596:                super(msg, t);
1597:            }
1598:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.