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;
}