DirectedInsight
NEWEST
Different ways to show the user they're wrong.
Helpful
Some simple queries that can save you some research time
NEWER
Complete AJAX example.
COOL
Dynamic file upload fields

small DI oval 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.


small DI oval 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>
                

small DI oval 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

small DI oval