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; } |
Free forum by Nabble | Edit this page |