1 23 package org.ofbiz.shipment.thirdparty.dhl; 24 25 import java.io.FileOutputStream ; 26 import java.io.IOException ; 27 import java.io.StringWriter ; 28 import java.util.ArrayList ; 29 import java.util.HashMap ; 30 import java.util.Iterator ; 31 import java.util.LinkedList ; 32 import java.util.List ; 33 import java.util.Locale ; 34 import java.util.Map ; 35 36 import javax.xml.parsers.ParserConfigurationException ; 37 38 import org.ofbiz.base.util.Base64; 39 import org.ofbiz.base.util.Debug; 40 import org.ofbiz.base.util.GeneralException; 41 import org.ofbiz.base.util.HttpClient; 42 import org.ofbiz.base.util.HttpClientException; 43 import org.ofbiz.base.util.StringUtil; 44 import org.ofbiz.base.util.UtilDateTime; 45 import org.ofbiz.base.util.UtilMisc; 46 import org.ofbiz.base.util.UtilProperties; 47 import org.ofbiz.base.util.UtilValidate; 48 import org.ofbiz.base.util.UtilXml; 49 import org.ofbiz.service.ModelService; 50 import org.ofbiz.content.content.ContentWorker; 51 import org.ofbiz.entity.GenericDelegator; 52 import org.ofbiz.entity.GenericEntityException; 53 import org.ofbiz.entity.GenericValue; 54 import org.ofbiz.service.DispatchContext; 55 import org.ofbiz.service.LocalDispatcher; 56 import org.ofbiz.service.ServiceUtil; 57 import org.ofbiz.service.GenericServiceException; 58 import org.w3c.dom.Document ; 59 import org.w3c.dom.Element ; 60 import org.xml.sax.SAXException ; 61 62 83 public class DhlServices { 84 85 public final static String module = DhlServices.class.getName(); 86 public final static String shipmentPropertiesFile = "shipment.properties"; 87 public final static String DHL_WEIGHT_UOM_ID = "WT_lb"; 89 99 public static String sendDhlRequest(String xmlString) 100 throws DhlConnectException { 101 String conStr = UtilProperties.getPropertyValue(shipmentPropertiesFile, 102 "shipment.dhl.connect.url"); 103 if (conStr == null) { 104 throw new DhlConnectException( 105 "Incomplete connection URL; check your DHL configuration"); 106 } 107 108 if (xmlString == null) { 111 throw new DhlConnectException("XML message cannot be null"); 112 } 113 114 conStr = conStr.trim(); 116 117 String timeOutStr = UtilProperties.getPropertyValue( 118 shipmentPropertiesFile, "shipment.dhl.connect.timeout", "60"); 119 int timeout = 60; 120 try { 121 timeout = Integer.parseInt(timeOutStr); 122 } catch (NumberFormatException e) { 123 Debug.logError(e, "Unable to set timeout to " + timeOutStr 124 + " using default " + timeout); 125 } 126 127 if (Debug.verboseOn()) { 128 Debug.logVerbose("DHL Connect URL : " + conStr, module); 129 Debug.logVerbose("DHL XML String : " + xmlString, module); 130 } 131 132 HttpClient http = new HttpClient(conStr); 133 http.setTimeout(timeout * 1000); 134 String response = null; 135 try { 136 response = http.post(xmlString); 137 } catch (HttpClientException e) { 138 Debug.logError(e, "Problem connecting with DHL server", module); 139 throw new DhlConnectException("URL Connection problem", e); 140 } 141 142 if (response == null) { 143 throw new DhlConnectException("Received a null response"); 144 } 145 if (Debug.verboseOn()) { 146 Debug.logVerbose("DHL Response : " + response, module); 147 } 148 149 return response; 150 } 151 152 153 157 public static Map dhlRateEstimate(DispatchContext dctx, Map context) { 158 GenericDelegator delegator = dctx.getDelegator(); 159 LocalDispatcher dispatcher = dctx.getDispatcher(); 160 Locale locale = (Locale ) context.get("locale"); 161 162 String upsRateInquireMode = (String ) context.get("upsRateInquireMode"); 164 String carrierRoleTypeId = (String ) context.get("carrierRoleTypeId"); 165 String carrierPartyId = (String ) context.get("carrierPartyId"); 166 String shipmentMethodTypeId = (String ) context.get("shipmentMethodTypeId"); 167 String shippingContactMechId = (String ) context.get("shippingContactMechId"); 168 List shippableItemInfo = (List ) context.get("shippableItemInfo"); 169 Double shippableTotal = (Double ) context.get("shippableTotal"); 170 Double shippableQuantity = (Double ) context.get("shippableQuantity"); 171 Double shippableWeight = (Double ) context.get("shippableWeight"); 172 173 if (shipmentMethodTypeId.equals("NO_SHIPPING")) { 174 Map result = ServiceUtil.returnSuccess(); 175 result.put("shippingEstimateAmount", null); 176 return result; 177 } 178 179 String dhlShipmentDetailCode = null; 181 try { 182 GenericValue carrierShipmentMethod = delegator.findByPrimaryKey("CarrierShipmentMethod", UtilMisc.toMap("shipmentMethodTypeId", shipmentMethodTypeId, 183 "partyId", carrierPartyId, "roleTypeId", "CARRIER")); 184 if (carrierShipmentMethod == null) { 185 return ServiceUtil.returnError("No CarrierShipmentMethod entry for carrier " + carrierPartyId + ", shipmentMethodTypeId " + shipmentMethodTypeId); 186 } 187 dhlShipmentDetailCode = carrierShipmentMethod.getString("carrierServiceCode"); 188 } catch (GenericEntityException e) { 189 Debug.logError(e, "Failed to get rate estimate: " + e.getMessage(), module); 190 } 191 192 String userid = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.dhl.access.userid"); 194 String password = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.dhl.access.password"); 195 String shippingKey = UtilProperties.getPropertyValue("shipment", "shipment.dhl.access.shippingKey"); 196 String accountNbr = UtilProperties.getPropertyValue("shipment", "shipment.dhl.access.accountNbr"); 197 if ((shippingKey == null) || (accountNbr == null) || (shippingKey.length() == 0) || (accountNbr.length() == 0)) { 198 return ServiceUtil.returnError("DHL Shipping Credentials are not configured. (check shipment.dhl.access)"); 199 } 200 201 GenericValue shipToAddress = null; 203 if (shippingContactMechId != null) { 204 try { 205 shipToAddress = delegator.findByPrimaryKey("PostalAddress", UtilMisc.toMap("contactMechId", shippingContactMechId)); 206 if (shipToAddress == null) { 207 return ServiceUtil.returnError("Unable to determine ship-to address"); 208 } 209 } 210 catch (GenericEntityException e) { 211 Debug.logError(e, module); 212 } 213 } 214 215 if ((shippableWeight == null) || (shippableWeight.doubleValue() <= 0.0)) { 216 String tmpValue = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.default.weight.value"); 217 if (tmpValue != null) { 218 try { 219 shippableWeight = new Double (tmpValue); 220 } catch (Exception e) { 221 return ServiceUtil.returnError("Cannot get DHL Estimate: Default shippable weight not configured (shipment.default.weight.value)"); 222 } 223 } 224 } 225 226 if (shippableWeight.doubleValue() < 1.0) { 228 Debug.logWarning("DHL Estimate: Weight is less than 1 lb, submitting DHL minimum of 1 lb for estimate.", module); 229 shippableWeight = new Double (1.0); 230 } 231 if ((dhlShipmentDetailCode.equals("G") && shippableWeight.doubleValue() > 999) || (shippableWeight.doubleValue() > 150)) { 232 return ServiceUtil.returnError("Cannot get DHL Estimate: Shippable weight cannot be greater than 999 lbs for ground or 150 lbs for all other services."); 233 } 234 String weight = (new Integer ((int) shippableWeight.longValue())).toString(); 235 236 String templateName = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.template.dhl.rate.estimate"); 238 if ((templateName == null) || (templateName.trim().length() == 0)) { 239 return ServiceUtil.returnError("Cannot get DHL Estimate: DHL Rate template not configured (shipment.template.dhl.rate.estimate"); 240 } 241 StringWriter outWriter = new StringWriter (); 242 Map inContext = new HashMap (); 243 inContext.put("action", "RateEstimate"); 244 inContext.put("userid", userid); 245 inContext.put("password", password); 246 inContext.put("accountNbr", accountNbr); 247 inContext.put("shippingKey", shippingKey); 248 inContext.put("shipDate", UtilDateTime.nowTimestamp()); 249 inContext.put("dhlShipmentDetailCode", dhlShipmentDetailCode); 250 inContext.put("weight", weight); 251 inContext.put("state", shipToAddress.getString("stateProvinceGeoId")); 252 inContext.put("postalCode", shipToAddress.getString("postalCode")); 253 try { 254 Map tmpResult = ContentWorker.renderContentAsText(delegator, templateName, outWriter, inContext, null, locale, "text/plain"); 255 } catch (Exception e) { 256 Debug.logError(e, "Cannot get DHL Estimate: Failed to render DHL XML Request.", module); 257 return ServiceUtil.returnError("Cannot get DHL Estimate: Failed to render DHL XML Request."); 258 } 259 String requestString = outWriter.toString(); 260 if (Debug.verboseOn()) { 261 Debug.logVerbose(requestString, module); 262 } 263 264 String rateResponseString = null; 266 try { 267 rateResponseString = sendDhlRequest(requestString); 268 if (Debug.verboseOn()) { 269 Debug.logVerbose(rateResponseString, module); 270 } 271 } 272 catch (DhlConnectException e) { 273 String uceErrMsg = "Error sending DHL request for DHL Service Rate: " + e.toString(); 274 Debug.logError(e, uceErrMsg, module); 275 return ServiceUtil.returnError(uceErrMsg); 276 } 277 278 Document rateResponseDocument = null; 279 try { 280 rateResponseDocument = UtilXml.readXmlDocument(rateResponseString, false); 281 return handleDhlRateResponse(rateResponseDocument); 282 } 283 catch (SAXException e2) { 284 String excErrMsg = "Error parsing the RatingServiceResponse: " + e2.toString(); 285 Debug.logError(e2, excErrMsg, module); 286 return ServiceUtil.returnError(excErrMsg); 287 } 288 catch (ParserConfigurationException e2) { 289 String excErrMsg = "Error parsing the RatingServiceResponse: " + e2.toString(); 290 Debug.logError(e2, excErrMsg, module); 291 return ServiceUtil.returnError(excErrMsg); 292 } 293 catch (IOException e2) { 294 String excErrMsg = "Error parsing the RatingServiceResponse: " + e2.toString(); 295 Debug.logError(e2, excErrMsg, module); 296 return ServiceUtil.returnError(excErrMsg); 297 } 298 } 299 300 303 public static Map handleDhlRateResponse(Document rateResponseDocument) { 304 List errorList = new LinkedList (); 305 Map dhlRateCodeMap = new HashMap (); 306 Element rateResponseElement = rateResponseDocument.getDocumentElement(); 308 DhlServices.handleErrors(rateResponseElement, errorList); 309 if (UtilValidate.isNotEmpty(errorList)) { 310 return ServiceUtil.returnError(errorList); 311 } 312 Element responseElement = UtilXml.firstChildElement( 314 rateResponseElement, "Shipment"); 315 Element responseResultElement = UtilXml.firstChildElement( 316 responseElement, "Result"); 317 Element responseEstimateDetailElement = UtilXml.firstChildElement( 318 responseElement, "EstimateDetail"); 319 320 DhlServices.handleErrors(responseElement, errorList); 321 if (UtilValidate.isNotEmpty(errorList)) { 322 return ServiceUtil.returnError(errorList); 323 } 324 String responseStatusCode = UtilXml.childElementValue( 325 responseResultElement, "Code"); 326 String responseStatusDescription = UtilXml.childElementValue( 327 responseResultElement, "Desc"); 328 329 String dateGenerated = UtilXml.childElementValue( 330 responseEstimateDetailElement, "DateGenerated"); 331 332 Element responseServiceLevelCommitmentElement = UtilXml 333 .firstChildElement(responseEstimateDetailElement, 334 "ServiceLevelCommitment"); 335 String responseServiceLevelCommitmentDescription = UtilXml 336 .childElementValue(responseServiceLevelCommitmentElement, 337 "Desc"); 338 339 Element responseRateEstimateElement = UtilXml.firstChildElement( 340 responseEstimateDetailElement, "RateEstimate"); 341 String responseTotalChargeEstimate = UtilXml.childElementValue( 342 responseRateEstimateElement, "TotalChargeEstimate"); 343 Element responseChargesElement = UtilXml.firstChildElement( 344 responseRateEstimateElement, "Charges"); 345 List chargeNodeList = UtilXml.childElementList(responseChargesElement, 346 "Charge"); 347 348 List chargeList = new ArrayList (); 349 if (chargeNodeList != null && chargeNodeList.size() > 0) { 350 for (int i = 0; chargeNodeList.size() > i; i++) { 351 Map charge = new HashMap (); 352 353 Element responseChargeElement = (Element ) chargeNodeList.get(i); 354 Element responseChargeTypeElement = UtilXml.firstChildElement( 355 responseChargeElement, "Type"); 356 357 String responseChargeTypeCode = UtilXml.childElementValue( 358 responseChargeTypeElement, "Code"); 359 String responseChargeTypeDesc = UtilXml.childElementValue( 360 responseChargeTypeElement, "Desc"); 361 String responseChargeValue = UtilXml.childElementValue( 362 responseChargeElement, "Value"); 363 364 charge.put("chargeTypeCode", responseChargeTypeCode); 365 charge.put("chargeTypeDesc", responseChargeTypeDesc); 366 charge.put("chargeValue", responseChargeValue); 367 chargeList.add(charge); 368 } 369 } 370 Double shippingEstimateAmount = new Double (responseTotalChargeEstimate); 371 dhlRateCodeMap.put("dateGenerated", dateGenerated); 372 dhlRateCodeMap.put("serviceLevelCommitment", 373 responseServiceLevelCommitmentDescription); 374 dhlRateCodeMap.put("totalChargeEstimate", responseTotalChargeEstimate); 375 dhlRateCodeMap.put("chargeList", chargeList); 376 377 Map result = ServiceUtil.returnSuccess(); 378 result.put("shippingEstimateAmount", shippingEstimateAmount); 379 result.put("dhlRateCodeMap", dhlRateCodeMap); 380 return result; 381 } 382 383 386 public static Map dhlRegisterInquire(DispatchContext dctx, Map context) { 387 388 Map result = new HashMap (); 389 String postalCode = (String ) context.get("postalCode"); 390 String accountNbr = UtilProperties.getPropertyValue("shipment", 391 "shipment.dhl.access.accountNbr"); 392 if (accountNbr == null) { 393 return ServiceUtil 394 .returnError("accountNbr not found for Register Account."); 395 } 396 Document requestDocument = createAccessRequestDocument(); 398 String requestString = null; 399 Element requesElement = requestDocument.getDocumentElement(); 400 401 Element registerRequestElement = UtilXml.addChildElement(requesElement, 402 "Register", requestDocument); 403 registerRequestElement.setAttribute("version", "1.0"); 404 registerRequestElement.setAttribute("action", "ShippingKey"); 405 UtilXml.addChildElementValue(registerRequestElement, "AccountNbr", 406 accountNbr, requestDocument); 407 UtilXml.addChildElementValue(registerRequestElement, "PostalCode", 408 postalCode, requestDocument); 409 410 try { 411 requestString = UtilXml.writeXmlDocument(requestDocument); 412 Debug.log("AccessRequest XML Document:" + requestString); 413 } catch (IOException e) { 414 String ioeErrMsg = "Error writing the AccessRequest XML Document to a String: " 415 + e.toString(); 416 Debug.logError(e, ioeErrMsg, module); 417 return ServiceUtil.returnError(ioeErrMsg); 418 } 419 String registerResponseString = null; 421 try { 422 registerResponseString = sendDhlRequest(requestString); 423 Debug.log("DHL request for DHL Register Account:" 424 + registerResponseString); 425 } catch (DhlConnectException e) { 426 String uceErrMsg = "Error sending DHL request for DHL Register Account: " 427 + e.toString(); 428 Debug.logError(e, uceErrMsg, module); 429 return ServiceUtil.returnError(uceErrMsg); 430 } 431 432 Document registerResponseDocument = null; 433 try { 434 registerResponseDocument = UtilXml.readXmlDocument( 435 registerResponseString, false); 436 result = handleDhlRegisterResponse(registerResponseDocument); 437 Debug.log("DHL response for DHL Register Account:" 438 + registerResponseString); 439 } catch (SAXException e2) { 440 String excErrMsg = "Error parsing the RegisterAccountServiceSelectionResponse: " 441 + e2.toString(); 442 Debug.logError(e2, excErrMsg, module); 443 return ServiceUtil.returnError(excErrMsg); 444 } catch (ParserConfigurationException e2) { 445 String excErrMsg = "Error parsing the RegisterAccountServiceSelectionResponse: " 446 + e2.toString(); 447 Debug.logError(e2, excErrMsg, module); 448 return ServiceUtil.returnError(excErrMsg); 449 } catch (IOException e2) { 450 String excErrMsg = "Error parsing the RegisterAccountServiceSelectionResponse: " 451 + e2.toString(); 452 Debug.logError(e2, excErrMsg, module); 453 return ServiceUtil.returnError(excErrMsg); 454 } 455 456 return result; 457 } 458 459 462 public static Map handleDhlRegisterResponse( 463 Document registerResponseDocument) { 464 List errorList = new LinkedList (); 465 Element registerResponseElement = registerResponseDocument 467 .getDocumentElement(); 468 DhlServices.handleErrors(registerResponseElement, errorList); 469 if (UtilValidate.isNotEmpty(errorList)) { 470 return ServiceUtil.returnError(errorList); 471 } 472 Element responseElement = UtilXml.firstChildElement( 474 registerResponseElement, "Register"); 475 Element responseResultElement = UtilXml.firstChildElement( 476 responseElement, "Result"); 477 478 DhlServices.handleErrors(responseElement, errorList); 479 if (UtilValidate.isNotEmpty(errorList)) { 480 return ServiceUtil.returnError(errorList); 481 } 482 String responseStatusCode = UtilXml.childElementValue( 483 responseResultElement, "Code"); 484 String responseStatusDescription = UtilXml.childElementValue( 485 responseResultElement, "Desc"); 486 487 String responseShippingKey = UtilXml.childElementValue(responseElement, 488 "ShippingKey"); 489 String responsePostalCode = UtilXml.childElementValue(responseElement, 490 "PostalCode"); 491 492 Map result = ServiceUtil.returnSuccess(); 493 result.put("shippingKey", responseShippingKey); 494 return result; 495 } 496 497 500 501 public static Map dhlShipmentConfirm(DispatchContext dctx, Map context) { 502 GenericDelegator delegator = dctx.getDelegator(); 503 LocalDispatcher dispatcher = dctx.getDispatcher(); 504 Locale locale = (Locale ) context.get("locale"); 505 506 String shipmentId = (String ) context.get("shipmentId"); 507 String shipmentRouteSegmentId = (String ) context.get("shipmentRouteSegmentId"); 508 Map result = new HashMap (); 509 String shipmentConfirmResponseString = null; 510 try { 511 GenericValue shipment = delegator.findByPrimaryKey("Shipment", UtilMisc.toMap("shipmentId", shipmentId)); 512 if (shipment == null) { 513 return ServiceUtil.returnError("Shipment not found with ID " + shipmentId); 514 } 515 GenericValue shipmentRouteSegment = delegator.findByPrimaryKey("ShipmentRouteSegment", UtilMisc.toMap("shipmentId", shipmentId, "shipmentRouteSegmentId", shipmentRouteSegmentId)); 516 if (shipmentRouteSegment == null) { 517 return ServiceUtil.returnError("ShipmentRouteSegment not found with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); 518 } 519 520 if (!"DHL".equals(shipmentRouteSegment.getString("carrierPartyId"))) { 521 return ServiceUtil.returnError("ERROR: The Carrier for ShipmentRouteSegment " + shipmentRouteSegmentId + " of Shipment " + shipmentId + ", is not DHL."); 522 } 523 524 if (UtilValidate.isNotEmpty(shipmentRouteSegment.getString("carrierServiceStatusId")) && !"SHRSCS_NOT_STARTED".equals(shipmentRouteSegment.getString("carrierServiceStatusId"))) { 526 return ServiceUtil.returnError("ERROR: The Carrier Service Status for ShipmentRouteSegment " + shipmentRouteSegmentId + " of Shipment " + shipmentId + ", is [" + shipmentRouteSegment.getString("carrierServiceStatusId") + "], but must be not-set or [SHRSCS_NOT_STARTED] to perform the DHL Shipment Confirm operation."); 527 } 528 529 GenericValue originPostalAddress = shipmentRouteSegment.getRelatedOne("OriginPostalAddress"); 531 if (originPostalAddress == null) { 532 return ServiceUtil.returnError("OriginPostalAddress not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); 533 } 534 GenericValue originTelecomNumber = shipmentRouteSegment.getRelatedOne("OriginTelecomNumber"); 535 if (originTelecomNumber == null) { 536 return ServiceUtil.returnError("OriginTelecomNumber not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); 537 } 538 String originPhoneNumber = originTelecomNumber.getString("areaCode") + originTelecomNumber.getString("contactNumber"); 539 if (UtilValidate.isNotEmpty(originTelecomNumber.getString("countryCode")) && !"001".equals(originTelecomNumber.getString("countryCode"))) { 541 originPhoneNumber = originTelecomNumber.getString("countryCode") + originPhoneNumber; 542 } 543 originPhoneNumber = StringUtil.replaceString(originPhoneNumber, "-", ""); 544 originPhoneNumber = StringUtil.replaceString(originPhoneNumber, " ", ""); 545 546 GenericValue originCountryGeo = originPostalAddress.getRelatedOne("CountryGeo"); 548 if (originCountryGeo == null) { 549 return ServiceUtil.returnError("OriginCountryGeo not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); 550 } 551 552 GenericValue destPostalAddress = shipmentRouteSegment.getRelatedOne("DestPostalAddress"); 554 if (destPostalAddress == null) { 555 return ServiceUtil.returnError("DestPostalAddress not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); 556 } 557 558 String destPhoneNumber = originPhoneNumber; 560 GenericValue destTelecomNumber = shipmentRouteSegment.getRelatedOne("DestTelecomNumber"); 561 if (destTelecomNumber != null) { 562 destPhoneNumber = destTelecomNumber.getString("areaCode") + destTelecomNumber.getString("contactNumber"); 563 if (UtilValidate.isNotEmpty(destTelecomNumber.getString("countryCode")) && !"001".equals(destTelecomNumber.getString("countryCode"))) { 565 destPhoneNumber = destTelecomNumber.getString("countryCode") + destPhoneNumber; 566 } 567 destPhoneNumber = StringUtil.replaceString(destPhoneNumber, "-", ""); 568 destPhoneNumber = StringUtil.replaceString(destPhoneNumber, " ", ""); 569 } 570 571 GenericValue destCountryGeo = destPostalAddress.getRelatedOne("CountryGeo"); 573 if (destCountryGeo == null) { 574 return ServiceUtil.returnError("DestCountryGeo not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); 575 } 576 577 List shipmentPackageRouteSegs = shipmentRouteSegment.getRelated("ShipmentPackageRouteSeg", null, UtilMisc.toList("+shipmentPackageSeqId")); 578 if (shipmentPackageRouteSegs == null || shipmentPackageRouteSegs.size() == 0) { 579 return ServiceUtil.returnError("No ShipmentPackageRouteSegs (ie No Packages) found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); 580 } 581 if (shipmentPackageRouteSegs.size() != 1) { 582 return ServiceUtil.returnError("Cannot confirm shipment: DHL ShipIT does not currently support more than one package per shipment."); 583 } 584 585 boolean hasBillingWeight = false; Double billingWeight = shipmentRouteSegment.getDouble("billingWeight"); 588 String billingWeightUomId = shipmentRouteSegment.getString("billingWeightUomId"); 589 if ((billingWeight != null) && (billingWeight.doubleValue() > 0)) { 590 hasBillingWeight = true; 591 if (billingWeightUomId == null) { 592 Debug.logWarning("Shipment Route Segment missing billingWeightUomId in shipmentId " + shipmentId, module); 593 billingWeightUomId = "WT_lb"; } 595 Map results = dispatcher.runSync("convertUom", UtilMisc.toMap("uomId", billingWeightUomId, "uomIdTo", DHL_WEIGHT_UOM_ID, "originalValue", billingWeight)); 597 if (ServiceUtil.isError(results) || (results.get("convertedValue") == null)) { 598 Debug.logWarning("Unable to convert billing weights for shipmentId " + shipmentId , module); 599 hasBillingWeight = false; 601 } else { 602 billingWeight = (Double ) results.get("convertedValue"); 603 } 604 } 605 606 String length = null; 608 String width = null; 609 String height = null; 610 Double packageWeight = null; 611 Iterator shipmentPackageRouteSegIter = shipmentPackageRouteSegs.iterator(); 612 while (shipmentPackageRouteSegIter.hasNext()) { 613 GenericValue shipmentPackageRouteSeg = (GenericValue) shipmentPackageRouteSegIter.next(); 614 GenericValue shipmentPackage = shipmentPackageRouteSeg.getRelatedOne("ShipmentPackage"); 615 GenericValue shipmentBoxType = shipmentPackage.getRelatedOne("ShipmentBoxType"); 616 List carrierShipmentBoxTypes = shipmentPackage.getRelated("CarrierShipmentBoxType", UtilMisc.toMap("partyId", "DHL"), null); 617 GenericValue carrierShipmentBoxType = null; 618 if (carrierShipmentBoxTypes.size() > 0) { 619 carrierShipmentBoxType = (GenericValue) carrierShipmentBoxTypes.get(0); 620 } 621 622 if (shipmentBoxType != null) { 624 GenericValue dimensionUom = shipmentBoxType.getRelatedOne("DimensionUom"); 625 length = shipmentBoxType.get("boxLength").toString(); 626 width = shipmentBoxType.get("boxWidth").toString(); 627 height = shipmentBoxType.get("boxHeight").toString(); 628 } 629 630 if (hasBillingWeight) continue; 632 633 if (shipmentPackage.getString("weight") != null) { 635 packageWeight = Double.valueOf(shipmentPackage.getString("weight")); 636 } else { 637 try { 639 packageWeight = Double.valueOf(UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.default.weight.value")); 640 } catch (NumberFormatException ne) { 641 Debug.logWarning("Default shippable weight not configured (shipment.default.weight.value)", module); 642 packageWeight = new Double (1.0); 643 } 644 } 645 String weightUomId = (String ) shipmentPackage.get("weightUomId"); 647 if (weightUomId == null) { 648 Debug.logWarning("Shipment Route Segment missing weightUomId in shipmentId " + shipmentId, module); 649 weightUomId = "WT_lb"; } 651 Map results = dispatcher.runSync("convertUom", UtilMisc.toMap("uomId", weightUomId, "uomIdTo", DHL_WEIGHT_UOM_ID, "originalValue", packageWeight)); 652 if ((results == null) || (results.get(ModelService.RESPONSE_MESSAGE).equals(ModelService.RESPOND_ERROR)) || (results.get("convertedValue") == null)) { 653 Debug.logWarning("Unable to convert weights for shipmentId " + shipmentId , module); 654 packageWeight = new Double (1.0); 655 } else { 656 packageWeight = (Double ) results.get("convertedValue"); 657 } 658 } 659 660 Double weight = null; 662 if (hasBillingWeight) { 663 weight = billingWeight; 664 } else { 665 weight = packageWeight; 666 } 667 String roundedWeight = "" + Math.round(weight.doubleValue()); 669 670 String shipmentMethodTypeId = shipmentRouteSegment.getString("shipmentMethodTypeId"); 672 String dhlShipmentDetailCode = null; 673 GenericValue carrierShipmentMethod = delegator.findByPrimaryKey("CarrierShipmentMethod", UtilMisc.toMap("shipmentMethodTypeId", shipmentMethodTypeId, 674 "partyId", "DHL", "roleTypeId", "CARRIER")); 675 if (carrierShipmentMethod == null) { 676 return ServiceUtil.returnError("No CarrierShipmentMethod entry for carrier DHL shipmentMethodTypeId " + shipmentMethodTypeId); 677 } 678 dhlShipmentDetailCode = carrierShipmentMethod.getString("carrierServiceCode"); 679 680 String userid = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.dhl.access.userid"); 682 String password = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.dhl.access.password"); 683 String shippingKey = UtilProperties.getPropertyValue("shipment", "shipment.dhl.access.shippingKey"); 684 String accountNbr = UtilProperties.getPropertyValue("shipment", "shipment.dhl.access.accountNbr"); 685 if ((shippingKey == null) || (accountNbr == null) || (shippingKey.length() == 0) || (accountNbr.length() == 0)) { 686 return ServiceUtil.returnError("DHL Shipping Credentials are not configured. (check shipment.dhl.access)"); 687 } 688 689 String labelImagePreference = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.dhl.label.image.format"); 691 if (labelImagePreference == null) { 692 Debug.logInfo("shipment.dhl.label.image.format not specified, assuming PNG", module); 693 labelImagePreference="PNG"; 694 } else if (!(labelImagePreference.equals("PNG") || labelImagePreference.equals("GIF"))) { 695 Debug.logError("Illegal shipment.dhl.label.image.format: " + labelImagePreference, module); 696 return ServiceUtil.returnError("Unknown DHL Label Image Format: " + labelImagePreference); 697 } 698 699 String templateName = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.template.dhl.rate.estimate"); 701 if ((templateName == null) || (templateName.trim().length() == 0)) { 702 return ServiceUtil.returnError("Cannot get DHL Estimate: DHL Rate template not configured (shipment.template.dhl.rate.estimate"); 703 } 704 StringWriter outWriter = new StringWriter (); 705 Map inContext = new HashMap (); 706 inContext.put("action", "GenerateLabel"); 707 inContext.put("userid", userid); 708 inContext.put("password", password); 709 inContext.put("accountNbr", accountNbr); 710 inContext.put("shippingKey", shippingKey); 711 inContext.put("shipDate", UtilDateTime.nowTimestamp()); 712 inContext.put("dhlShipmentDetailCode", dhlShipmentDetailCode); 713 inContext.put("weight", roundedWeight); 714 inContext.put("senderPhoneNbr", originPhoneNumber); 715 inContext.put("companyName", destPostalAddress.getString("toName")); 716 inContext.put("attnTo", destPostalAddress.getString("attnName")); 717 inContext.put("street", destPostalAddress.getString("address1")); 718 inContext.put("streetLine2", destPostalAddress.getString("address2")); 719 inContext.put("city", destPostalAddress.getString("city")); 720 inContext.put("state", destPostalAddress.getString("stateProvinceGeoId")); 721 inContext.put("postalCode", destPostalAddress.getString("postalCode")); 722 inContext.put("phoneNbr", destPhoneNumber); 723 inContext.put("labelImageType", labelImagePreference); 724 725 try { 726 Map tmpResult = ContentWorker.renderContentAsText(delegator, templateName, outWriter, inContext, null, locale, "text/plain"); 727 } catch (Exception e) { 728 Debug.logError(e, "Cannot confirm DHL shipment: Failed to render DHL XML Request.", module); 729 return ServiceUtil.returnError("Cannot confirm DHL shipment: Failed to render DHL XML Request."); 730 } 731 String requestString = outWriter.toString(); 732 if (Debug.verboseOn()) { 733 Debug.logVerbose(requestString, module); 734 } 735 736 String responseString = null; 738 try { 739 responseString = sendDhlRequest(requestString); 740 if (Debug.verboseOn()) { 741 Debug.logVerbose(responseString, module); 742 } 743 } catch (DhlConnectException e) { 744 String uceErrMsg = "Error sending DHL request for DHL Service Rate: " + e.toString(); 745 Debug.logError(e, uceErrMsg, module); 746 return ServiceUtil.returnError(uceErrMsg); 747 } 748 return handleDhlShipmentConfirmResponse(responseString, shipmentRouteSegment, shipmentPackageRouteSegs); 750 751 } catch (GenericEntityException e) { 752 Debug.logError(e, module); 753 if (shipmentConfirmResponseString != null) { 754 Debug.logError("Got XML ShipmentConfirmRespose: " + shipmentConfirmResponseString, module); 755 return ServiceUtil.returnError(UtilMisc.toList( 756 "Error reading or writing Shipment data for DHL Shipment Confirm: " + e.toString(), 757 "A ShipmentConfirmRespose was received: " + shipmentConfirmResponseString)); 758 } else { 759 return ServiceUtil.returnError("Error reading or writing Shipment data for DHL Shipment Confirm: " + e.toString()); 760 } 761 } catch (GenericServiceException e) { 762 Debug.logError(e, module); 763 return ServiceUtil.returnError("Error reading or writing Shipment data for DHL Shipment Confirm: " + e.toString()); 764 } 765 } 766 767 public static Map handleDhlShipmentConfirmResponse(String rateResponseString, GenericValue shipmentRouteSegment, 769 List shipmentPackageRouteSegs) throws GenericEntityException { 770 Map result = new HashMap (); 771 GenericValue shipmentPackageRouteSeg = (GenericValue) shipmentPackageRouteSegs.get(0); 772 773 Document rateResponseDocument = null; 776 try { 777 rateResponseDocument = UtilXml.readXmlDocument(rateResponseString, false); 778 } catch (SAXException e2) { 779 String excErrMsg = "Error parsing the RatingServiceSelectionResponse: " + e2.toString(); 780 Debug.logError(e2, excErrMsg, module); 781 } catch (ParserConfigurationException e2) { 783 String excErrMsg = "Error parsing the RatingServiceSelectionResponse: " + e2.toString(); 784 Debug.logError(e2, excErrMsg, module); 785 } catch (IOException e2) { 787 String excErrMsg = "Error parsing the RatingServiceSelectionResponse: " + e2.toString(); 788 Debug.logError(e2, excErrMsg, module); 789 } 791 792 Element rootElement = rateResponseDocument.getDocumentElement(); 794 Element shipmentElement = UtilXml.firstChildElement(rootElement, "Shipment"); 795 Element shipmentDetailElement = UtilXml.firstChildElement(shipmentElement, "ShipmentDetail"); 796 String trackingNumber = UtilXml.childElementValue(shipmentDetailElement, "AirbillNbr"); 797 798 Element labelElement = UtilXml.firstChildElement(shipmentElement, "Label"); 800 String encodedImageString = UtilXml.childElementValue(labelElement, "Image"); 801 if (encodedImageString == null) { 802 Debug.logError("Cannot find response DHL shipment label. Rate response document is: " + rateResponseString, module); 803 return ServiceUtil.returnError("Cannot get response DHL shipment label for shipment package route segment " + shipmentPackageRouteSeg + ". DHL response is: " + rateResponseString); 804 } 805 806 int size = encodedImageString.length(); 808 StringBuffer sb = new StringBuffer (); 809 for (int i = 0; i < size; i++) { 810 if (encodedImageString.charAt(i) == '\n') 811 continue; 812 sb.append(encodedImageString.charAt(i)); 813 } 814 byte[] labelBytes = Base64.base64Decode(sb.toString().getBytes()); 815 816 if (labelBytes != null) { 817 shipmentPackageRouteSeg.setBytes("labelImage", labelBytes); 819 } else { 820 Debug.log("Failed to either decode returned DHL label or no data found in eCommerce/Shipment/Label/Image."); 821 } 823 824 shipmentPackageRouteSeg.set("trackingCode", trackingNumber); 825 shipmentPackageRouteSeg.set("labelHtml", sb.toString()); 826 shipmentPackageRouteSeg.store(); 827 828 shipmentRouteSegment.set("trackingIdNumber", trackingNumber); 829 shipmentRouteSegment.put("carrierServiceStatusId", "SHRSCS_CONFIRMED"); 830 shipmentRouteSegment.store(); 831 832 return ServiceUtil.returnSuccess("DHL Shipment Confirmed."); 833 } 834 835 private static double getWeight(List shippableItemInfo) { 836 double totalWeight = 0; 837 if (shippableItemInfo != null) { 838 Iterator sii = shippableItemInfo.iterator(); 839 while (sii.hasNext()) { 840 Map itemInfo = (Map ) sii.next(); 841 double weight = ((Double ) itemInfo.get("weight")).doubleValue(); 842 totalWeight = totalWeight + weight; 843 } 844 } 845 return totalWeight; 846 } 847 848 public static Document createAccessRequestDocument() { 849 return createAccessRequestDocument(shipmentPropertiesFile); 850 } 851 852 public static Document createAccessRequestDocument(String props) { 853 Document eCommerceRequestDocument = UtilXml 854 .makeEmptyXmlDocument("eCommerce"); 855 Element eCommerceRequesElement = eCommerceRequestDocument 856 .getDocumentElement(); 857 eCommerceRequesElement.setAttribute("version", UtilProperties 858 .getPropertyValue(props, "shipment.dhl.head.version")); 859 eCommerceRequesElement.setAttribute("action", UtilProperties 860 .getPropertyValue(props, "shipment.dhl.head.action")); 861 Element requestorRequestElement = UtilXml.addChildElement( 862 eCommerceRequesElement, "Requestor", eCommerceRequestDocument); 863 UtilXml 864 .addChildElementValue(requestorRequestElement, "ID", 865 UtilProperties.getPropertyValue(props, 866 "shipment.dhl.access.userid"), 867 eCommerceRequestDocument); 868 UtilXml.addChildElementValue(requestorRequestElement, "Password", 869 UtilProperties.getPropertyValue(props, 870 "shipment.dhl.access.password"), 871 eCommerceRequestDocument); 872 873 return eCommerceRequestDocument; 874 } 875 876 public static void handleErrors(Element responseElement, List errorList) { 877 Element faultsElement = UtilXml.firstChildElement(responseElement, 878 "Faults"); 879 List faultElements = UtilXml.childElementList(faultsElement, "Fault"); 880 if (UtilValidate.isNotEmpty(faultElements)) { 881 Iterator errorElementIter = faultElements.iterator(); 882 while (errorElementIter.hasNext()) { 883 StringBuffer errorMessageBuf = new StringBuffer (); 884 Element errorElement = (Element ) errorElementIter.next(); 885 886 String errorCode = UtilXml.childElementValue(errorElement, 887 "Code"); 888 String errorDescription = UtilXml.childElementValue( 889 errorElement, "Desc"); 890 String errorSource = UtilXml.childElementValue(errorElement, 891 "Source"); 892 if (UtilValidate.isEmpty(errorSource)) { 893 errorSource = UtilXml.childElementValue(errorElement, 894 "Context"); 895 } 896 errorMessageBuf.append("An error occurred [code:"); 897 errorMessageBuf.append(errorCode); 898 errorMessageBuf.append("] "); 899 errorMessageBuf.append(" [Description:"); 900 errorMessageBuf.append(errorDescription); 901 errorMessageBuf.append("] "); 902 errorMessageBuf.append(". "); 903 if (UtilValidate.isNotEmpty(errorSource)) { 904 errorMessageBuf.append("The error was at Element ["); 905 errorMessageBuf.append(errorSource); 906 errorMessageBuf.append("]"); 907 } 908 errorList.add(errorMessageBuf.toString()); 909 } 910 } 911 } 912 } 913 914 915 class DhlConnectException extends GeneralException { 916 DhlConnectException() { 917 super(); 918 } 919 920 DhlConnectException(String msg) { 921 super(msg); 922 } 923 924 DhlConnectException(Throwable t) { 925 super(t); 926 } 927 928 DhlConnectException(String msg, Throwable t) { 929 super(msg, t); 930 } 931 } 932 | Popular Tags |