svn commit: r799511 - in /ofbiz/trunk/applications/product: servicedef/services_shipment_usps.xml src/org/ofbiz/shipment/thirdparty/usps/UspsServices.java

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r799511 - in /ofbiz/trunk/applications/product: servicedef/services_shipment_usps.xml src/org/ofbiz/shipment/thirdparty/usps/UspsServices.java

lektran
Author: lektran
Date: Fri Jul 31 03:44:46 2009
New Revision: 799511

URL: http://svn.apache.org/viewvc?rev=799511&view=rev
Log:
Added support for international USPS rate estimates, completely untested at this stage

Modified:
    ofbiz/trunk/applications/product/servicedef/services_shipment_usps.xml
    ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/usps/UspsServices.java

Modified: ofbiz/trunk/applications/product/servicedef/services_shipment_usps.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/servicedef/services_shipment_usps.xml?rev=799511&r1=799510&r2=799511&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/servicedef/services_shipment_usps.xml (original)
+++ ofbiz/trunk/applications/product/servicedef/services_shipment_usps.xml Fri Jul 31 03:44:46 2009
@@ -29,6 +29,10 @@
             location="org.ofbiz.shipment.thirdparty.usps.UspsServices" invoke="uspsRateInquire" auth="false">
         <implements service="calcShipmentEstimateInterface"/>
     </service>
+    <service name="uspsInternationalRateInquire" engine="java"
+            location="org.ofbiz.shipment.thirdparty.usps.UspsServices" invoke="uspsInternationalRateInquire" auth="false">
+        <implements service="calcShipmentEstimateInterface"/>
+    </service>
 
     <service name="uspsTrackConfirm" engine="java"
             location="org.ofbiz.shipment.thirdparty.usps.UspsServices" invoke="uspsTrackConfirm">

Modified: ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/usps/UspsServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/usps/UspsServices.java?rev=799511&r1=799510&r2=799511&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/usps/UspsServices.java (original)
+++ ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/usps/UspsServices.java Fri Jul 31 03:44:46 2009
@@ -139,7 +139,7 @@
         }
 
         // create the request document
-        Document requestDocument = createUspsRequestDocument("RateV2Request");
+        Document requestDocument = createUspsRequestDocument("RateV2Request", true);
 
         // TODO: 70 lb max is valid for Express, Priority and Parcel only - handle other methods
         BigDecimal maxWeight = new BigDecimal("70");
@@ -177,10 +177,11 @@
                 weightPounds = BigDecimal.ONE;
                 packageWeight = BigDecimal.ZERO;
             }
-            BigDecimal weightOunces = packageWeight.multiply(new BigDecimal("16")).remainder(new BigDecimal("16")).setScale(0, BigDecimal.ROUND_CEILING);
-            DecimalFormat df = new DecimalFormat("#");  // USPS only accepts whole numbers like 1 and not 1.0
-            UtilXml.addChildElementValue(packageElement, "Pounds", df.format(weightPounds), requestDocument);
-            UtilXml.addChildElementValue(packageElement, "Ounces", df.format(weightOunces), requestDocument);
+            // (packageWeight % 1) * 16 (Rounded up to 0 dp)
+            BigDecimal weightOunces = packageWeight.remainder(BigDecimal.ONE).multiply(new BigDecimal("16")).setScale(0, BigDecimal.ROUND_CEILING);
+
+            UtilXml.addChildElementValue(packageElement, "Pounds", weightPounds.toPlainString(), requestDocument);
+            UtilXml.addChildElementValue(packageElement, "Ounces", weightOunces.toPlainString(), requestDocument);
 
             // TODO: handle other container types, package sizes, and machinable packages
             // IMPORTANT: Express or Priority Mail will fail if you supply a Container tag: you will get a message like
@@ -230,8 +231,151 @@
         return result;
     }
 
+    public static Map<String, Object> uspsInternationalRateInquire(DispatchContext dctx, Map<String, ? extends Object> context) {
+
+        GenericDelegator delegator = dctx.getDelegator();
+
+        // check for 0 weight
+        BigDecimal shippableWeight = (BigDecimal) context.get("shippableWeight");
+        if (shippableWeight.compareTo(BigDecimal.ZERO) == 0) {
+            return ServiceUtil.returnFailure("shippableWeight must be greater than 0");
+        }
+
+        // get the destination country
+        String destinationCountry = null;
+        String shippingContactMechId = (String) context.get("shippingContactMechId");
+        if (UtilValidate.isNotEmpty(shippingContactMechId)) {
+            try {
+                GenericValue shipToAddress = delegator.findByPrimaryKey("PostalAddress", UtilMisc.toMap("contactMechId", shippingContactMechId));
+                if ("USA".equals(shipToAddress.get("countryGeoId"))) {
+                    return ServiceUtil.returnError("The USPS International Rate Calculation service is not applicable to US destinations, use uspsRateInquire");
+                }
+                if (shipToAddress != null && UtilValidate.isNotEmpty(shipToAddress.getString("countryGeoId"))) {
+                    GenericValue countryGeo = shipToAddress.getRelatedOne("CountryGeo");
+                    // TODO: Test against all country geoNames against what USPS expects
+                    destinationCountry = countryGeo.getString("geoName");
+                }
+            } catch (GenericEntityException e) {
+                Debug.logError(e, module);
+            }
+        }
+        if (UtilValidate.isEmpty(destinationCountry)) {
+            return ServiceUtil.returnError("Unable to determine the destination country");
+        }
+
+        // get the service code
+        String serviceCode = null;
+        try {
+            GenericValue carrierShipmentMethod = delegator.findByPrimaryKey("CarrierShipmentMethod",
+                    UtilMisc.toMap("shipmentMethodTypeId", (String) context.get("shipmentMethodTypeId"),
+                            "partyId", (String) context.get("carrierPartyId"), "roleTypeId", (String) context.get("carrierRoleTypeId")));
+            if (carrierShipmentMethod != null) {
+                serviceCode = carrierShipmentMethod.getString("carrierServiceCode");
+            }
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+        if (UtilValidate.isEmpty(serviceCode)) {
+            return ServiceUtil.returnError("Unable to determine the service code");
+        }
+
+        BigDecimal maxWeight = new BigDecimal("70");
+        String maxWeightStr = UtilProperties.getPropertyValue((String) context.get("serviceConfigProps"),
+                "shipment.usps.max.estimate.weight", "70");
+        try {
+            maxWeight = new BigDecimal(maxWeightStr);
+        } catch (NumberFormatException e) {
+            Debug.logWarning("Error parsing max estimate weight string [" + maxWeightStr + "], using default instead", module);
+            maxWeight = new BigDecimal("70");
+        }
+
+        List<Map<String, Object>> shippableItemInfo = UtilGenerics.checkList(context.get("shippableItemInfo"));
+        List<Map<String, BigDecimal>> packages = getPackageSplit(dctx, shippableItemInfo, maxWeight);
+        boolean isOnePackage = packages.size() == 1; // use shippableWeight if there's only one package
+
+        // create the request document
+        Document requestDocument = createUspsRequestDocument("IntlRateRequest", false);
+        UtilXml.addChildElementValue(requestDocument.getDocumentElement(), "Country", destinationCountry, requestDocument);
+
+        // TODO: Up to 25 packages can be included per request - handle more than 25
+        for (ListIterator<Map<String, BigDecimal>> li = packages.listIterator(); li.hasNext();) {
+            Map<String, BigDecimal> packageMap = li.next();
+
+            BigDecimal packageWeight = isOnePackage ? shippableWeight : calcPackageWeight(dctx, packageMap, shippableItemInfo, BigDecimal.ZERO);
+            if (packageWeight.compareTo(BigDecimal.ZERO) == 0) {
+                continue;
+            }
+
+            Element packageElement = UtilXml.addChildElement(requestDocument.getDocumentElement(), "Package", requestDocument);
+            packageElement.setAttribute("ID", String.valueOf(li.nextIndex() - 1)); // use zero-based index (see examples)
+
+            UtilXml.addChildElementValue(packageElement, "MailType", "Package", requestDocument);
+
+            BigDecimal weightPounds = packageWeight.setScale(0, BigDecimal.ROUND_FLOOR);
+            // for Parcel post, the weight must be at least 1 lb
+            if ("PARCEL".equals(serviceCode.toUpperCase()) && (weightPounds.compareTo(BigDecimal.ONE) < 0)) {
+                weightPounds = BigDecimal.ONE;
+                packageWeight = BigDecimal.ZERO;
+            }
+            // (packageWeight % 1) * 16 (Rounded up to 1 dp)
+            BigDecimal weightOunces = packageWeight.remainder(BigDecimal.ONE).multiply(new BigDecimal("16")).setScale(1, BigDecimal.ROUND_CEILING);
+            UtilXml.addChildElementValue(packageElement, "Pounds", weightPounds.toPlainString(), requestDocument);
+            UtilXml.addChildElementValue(packageElement, "Ounces", weightOunces.toPlainString(), requestDocument);
+
+            UtilXml.addChildElementValue(packageElement, "Machinable", "False", requestDocument);
+            
+            // TODO: Add package value so that an insurance fee can be returned
+        }
+
+        // send the request
+        Document responseDocument = null;
+        try {
+            responseDocument = sendUspsRequest("IntlRate", requestDocument);
+        } catch (UspsRequestException e) {
+            Debug.log(e, module);
+            return ServiceUtil.returnError("Error sending request for USPS International Rate Calculation service: " + e.getMessage());
+        }
+
+        if (responseDocument == null) {
+            return ServiceUtil.returnError("No rate available at this time");
+        }
+
+        List<? extends Element> packageElements = UtilXml.childElementList(responseDocument.getDocumentElement(), "Package");
+        if (UtilValidate.isEmpty(packageElements)) {
+            return ServiceUtil.returnError("No rate available at this time");
+        }
+
+        BigDecimal estimateAmount = BigDecimal.ZERO;
+        for (Element packageElement: packageElements) {
+            Element errorElement = UtilXml.firstChildElement(packageElement, "Error");
+            if (errorElement != null) {
+                String errorDescription = UtilXml.childElementValue(errorElement, "Description");
+                Debug.log("USPS International Rate Calculation returned a package error: " + errorDescription);
+                return ServiceUtil.returnError("No rate available at this time");
+            }
+            List<? extends Element> serviceElements = UtilXml.childElementList(packageElement, "Service");
+            for (Element serviceElement : serviceElements) {
+                String respServiceCode = serviceElement.getAttribute("ID");
+                if (!serviceCode.equalsIgnoreCase(respServiceCode)) {
+                    continue;
+                }
+                try {
+                    BigDecimal packageAmount = new BigDecimal(UtilXml.childElementValue(serviceElement, "Postage"));
+                    estimateAmount = estimateAmount.add(packageAmount);
+                } catch (NumberFormatException e) {
+                    Debug.log("USPS International Rate Calculation returned an unparsable postage amount: " + UtilXml.childElementValue(serviceElement, "Postage"));
+                    return ServiceUtil.returnError("No rate available at this time");
+                }
+            }
+        }
+
+        Map<String, Object> result = ServiceUtil.returnSuccess();
+        result.put("shippingEstimateAmount", estimateAmount);
+        return result;
+    }
+
     private static List<Map<String, BigDecimal>> getPackageSplit(DispatchContext dctx, List<Map<String, Object>> shippableItemInfo, BigDecimal maxWeight) {
-        // create the package list w/ the first pacakge
+        // create the package list w/ the first package
         List<Map<String, BigDecimal>> packages = FastList.newInstance();
 
         if (shippableItemInfo != null) {
@@ -370,7 +514,7 @@
 
     public static Map<String, Object> uspsTrackConfirm(DispatchContext dctx, Map<String, ? extends Object> context) {
 
-        Document requestDocument = createUspsRequestDocument("TrackRequest");
+        Document requestDocument = createUspsRequestDocument("TrackRequest", true);
 
         Element trackingElement = UtilXml.addChildElement(requestDocument.getDocumentElement(), "TrackID", requestDocument);
         trackingElement.setAttribute("ID", (String) context.get("trackingId"));
@@ -450,7 +594,7 @@
             return ServiceUtil.returnError(errorMessage);
         }
 
-        Document requestDocument = createUspsRequestDocument("AddressValidateRequest");
+        Document requestDocument = createUspsRequestDocument("AddressValidateRequest", true);
 
         Element addressElement = UtilXml.addChildElement(requestDocument.getDocumentElement(), "Address", requestDocument);
         addressElement.setAttribute("ID", "0");
@@ -539,7 +683,7 @@
 
     public static Map<String, Object> uspsCityStateLookup(DispatchContext dctx, Map<String, ? extends Object> context) {
 
-        Document requestDocument = createUspsRequestDocument("CityStateLookupRequest");
+        Document requestDocument = createUspsRequestDocument("CityStateLookupRequest", true);
 
         Element zipCodeElement = UtilXml.addChildElement(requestDocument.getDocumentElement(), "ZipCode", requestDocument);
         zipCodeElement.setAttribute("ID", "0");
@@ -644,7 +788,7 @@
             return ServiceUtil.returnError("Unsupported service type: " + type);
         }
 
-        Document requestDocument = createUspsRequestDocument(type + "Request");
+        Document requestDocument = createUspsRequestDocument(type + "Request", true);
 
         UtilXml.addChildElementValue(requestDocument.getDocumentElement(), "OriginZip",
                 (String) context.get("originZip"), requestDocument);
@@ -721,7 +865,7 @@
 
     public static Map<String, Object> uspsDomesticRate(DispatchContext dctx, Map<String, ? extends Object> context) {
 
-        Document requestDocument = createUspsRequestDocument("RateRequest");
+        Document requestDocument = createUspsRequestDocument("RateRequest", true);
 
         Element packageElement = UtilXml.addChildElement(requestDocument.getDocumentElement(), "Package", requestDocument);
         packageElement.setAttribute("ID", "0");
@@ -889,7 +1033,7 @@
                 //        shipmentPackageRouteSeg.getString("shipmentPackageSeqId") + "," +
                 //        shipmentPackageRouteSeg.getString("shipmentRouteSegmentId") + "]";
 
-                Document requestDocument = createUspsRequestDocument("RateRequest");
+                Document requestDocument = createUspsRequestDocument("RateRequest", true);
 
                 Element packageElement = UtilXml.addChildElement(requestDocument.getDocumentElement(), "Package", requestDocument);
                 packageElement.setAttribute("ID", "0");
@@ -1148,7 +1292,7 @@
             }
 
             for (GenericValue shipmentPackageRouteSeg: shipmentPackageRouteSegList) {
-                Document requestDocument = createUspsRequestDocument("DeliveryConfirmationV2.0Request");
+                Document requestDocument = createUspsRequestDocument("DeliveryConfirmationV2.0Request", true);
                 Element requestElement = requestDocument.getDocumentElement();
 
                 UtilXml.addChildElementValue(requestElement, "Option", "3", requestDocument);
@@ -1307,15 +1451,17 @@
         return ServiceUtil.returnSuccess();
     }
 
-    private static Document createUspsRequestDocument(String rootElement) {
+    private static Document createUspsRequestDocument(String rootElement, boolean passwordRequired) {
 
         Document requestDocument = UtilXml.makeEmptyXmlDocument(rootElement);
 
         Element requestElement = requestDocument.getDocumentElement();
         requestElement.setAttribute("USERID",
                 UtilProperties.getPropertyValue("shipment.properties", "shipment.usps.access.userid"));
-        requestElement.setAttribute("PASSWORD",
-                UtilProperties.getPropertyValue("shipment.properties", "shipment.usps.access.password"));
+        if (passwordRequired) {
+            requestElement.setAttribute("PASSWORD",
+                    UtilProperties.getPropertyValue("shipment.properties", "shipment.usps.access.password"));
+        }
 
         return requestDocument;
     }