UPS Online Tools
UPS offers suite of tools that can be used by companys to access a variety of services through their Online tools. In creating these tools, UPS chose not use one of the more common methods of accessing data via the internet (web services, SOAP, JavaBeans) and, instead, created their own custom solution. They offer both an HTML and an XML based way to do this. The XML version is a very robust method that the individual company can implement in any manner that they choose and can customize the inputs so long as they conform to the required format. The response from UPS is an XML document that the receiver can parse to extract the required data and format that data in any way that they choose. It is this method that is shown here.
Submitting a request to UPS requires two XML documents to be concatenated and sent in the same request. The first doc contains the access information for the company, user name, password, and an access key supplied by UPS. The second document is the actual service request and the data required by UPS to provide a response. The example below demonstates a rate request.
Access XML document
The access XML document should be a static document that can be used for all of the various service requests. As such it is kept as a separate file in the same directory as the function(s) that will make use of it so if the access information changes it only needs to be changed in one place for all using functions. The file is shown below.
<?xml version="1.0"?>
<AccessRequest xml:lang="en-US">
<AccessLicenseNumber>LicenseNumberFromUPS</AccessLicenseNumber>
<UserId>userID</UserId>
<Password>password</Password>
</AccessRequest>
Main Function
Here is the function that makes the actual request and parses the response. This function was created to only retrieve basic rate information from the tool. There is a large number of other elements that can be added to the XML doc sent to UPS that will retrieve a much larger variety of data. These elements and their usage are described in the references provided with the tools.
function getUPSRate(accessXMLFile, shipMethod, shipperZip, fromZip, toZip, packageWeightArr)
returnVal = 0
packages = ""
errorCode = 0
totalCharges = 0
Dim chargeNode
' split out the package weights and create the XML elements for them all
for each packageWeight in packageWeightArr
packages = packages & "<Package><PackagingType><Code>02</Code></PackagingType><PackageWeight><UnitOfMeasurement>"
packages = packages & "<Code>LBS</Code></UnitOfMeasurement><Weight>" & packageWeight & "</Weight></PackageWeight></Package>"
next
if packages = "" then errorCode = 1
if shipMethod = "" then errorCode = 2
if shipperZip = "" then errorCode = 3
if fromZip = "" then errorCode = 4
if toZip = "" then errorCode = 5
if errorCode = 0 then
requestXML = "<?xml version=""1.0""?><RatingServiceSelectionRequest xml:lang=""en-US"">"
requestXML = requestXML & "<Request><TransactionReference><CustomerContext>Company Name</CustomerContext>"
requestXML = requestXML & "<XpciVersion>1.0001</XpciVersion></TransactionReference><RequestAction>Rate</RequestAction>"
requestXML = requestXML & "<RequestOption>Rate</RequestOption></Request><PickupType><Code>01</Code></PickupType>"
requestXML = requestXML & "<Shipment><Shipper><Address><PostalCode>" & shipperZip & "</PostalCode><CountryCode>US</CountryCode></Address>"
requestXML = requestXML & "</Shipper><ShipTo><Address><PostalCode>" & toZip & "</PostalCode><CountryCode>US</CountryCode>"
requestXML = requestXML & "</Address></ShipTo><ShipFrom><Address><PostalCode>" & fromZip & "</PostalCode><CountryCode>US</CountryCode>"
requestXML = requestXML & "</Address></ShipFrom><Service><Code>" & shipMethod & "</Code></Service>" & packages & "</Shipment></RatingServiceSelectionRequest>"
if accessXMLFile = "" then accessXMLFile = "pathToFile\xmlAccess.xml"
Set xmlAccessReq = Server.CreateObject("Microsoft.XMLDOM")
xmlAccessReq.validateOnParse = true
Set xmlRateRequest = Server.CreateObject("Microsoft.XMLDOM")
xmlRateRequest.validateOnParse = true
xmlAccessReq.load(accessXMLFile)
if xmlAccessReq.parseError.errorcode <> 0 then
errorCode = 6
end if
if errorCode = 0 then
xmlRateRequest.loadXML(requestXML)
if xmlRateRequest.parseError.errorcode <> 0 then
errorCode = 7
end if
end if ' end if no errors yet
if errorCode = 0 then
Set xmlUPSResponse = Server.CreateObject("Microsoft.XMLDOM")
xmlUPSResponse.validateOnParse = true
xmlUPSResponse.Async = false ' wait until done loading to move on
xmlUPSResponse.setProperty "SelectionLanguage", "XPath"
' send the request.
set xmlHttp = Server.CreateObject("Msxml2.ServerXMLHTTP.3.0")
xmlHttp.open "POST", "https://wwwcie.ups.com/ups.app/xml/Rate", false
xmlHttp.setRequestHeader "Content-Length", len(xmlAccessReq.xml) + len(xmlRateRequest.xml)
xmlHttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
xmlHttp.send xmlAccessReq.xml & xmlRateRequest.xml
xmlUPSResponse.loadXML(xmlHttp.responseXML.xml)
set xmlHttp = nothing
' check for errors in the UPS response
if xmlUPSResponse.parseError.errorcode <> 0 then
errorCode = 8
else
pathToCharges = "*/RatedShipment/TotalCharges/MonetaryValue"
set chargeNode = xmlUPSResponse.selectSingleNode(pathToCharges)
if not isNull(chargeNode) or chargeNode is nothing then
totalCharges = FormatCurrency(chargeNode.text)
end if
end if
if totalCharges = 0 then
errorCode = 9
end if
end if ' end if ok to send to UPS
end if ' end if has error
if errorCode > 0 then
returnVal = errorCode
else
returnVal = totalCharges
end if
getUPSRate = returnVal
end function
The inputs to the function above are:
accessXMLFile - the file path of the access file - defaults to xmlAccess.xml.
shipMethod - The UPS service option (see the UPS tools reference)
shipperZip - The zip code of the shipper
fromZip - The zip code the package is shipping from
toZip - The zip code the package is shipping to
packageWeightArr - An array of package weights in pounds
The function will return either an integer value that represents one of the error codes described below, or the total charges returned from the tool formatted as currency in US Dollars.
Error Codes:
1 - no or improperly formatted package weights array
2 - no or improperly formatted shipMethod
3 - no or improperly formatted shipperZip
4 - no or improperly formatted fromZip
5 - no or improperly formatted toZip
6 - the accessXML file had a parse error
7 - the constructed requestXML string had a parse error
8 - the returned XML from UPS had a parse error
9 - could not find the total charges returned from UPS
A sample call to this function could look like this:
dim weightsArr(1)
weightsArr(0 ) = 10
weightsArr(1) = 23
testVal = getUPSRate("", "03", "44102", "44054", "44107", weightsArr)
There are a variety of things that can be done to make the code more robust from better error reporting to using a different version of the MSXML. Not to mention what could be done in a different programming language.
If you have a question, comment, bug fix, or addition let us know.
We'll add it to the demo with the proper credit. comments@directedinsight.com
