The Artima Developer Community
Sponsored Link

Weblogs Forum
A Fedex Rate Requester using xmlnode

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Bruce Eckel

Posts: 875
Nickname: beckel
Registered: Jun, 2003

A Fedex Rate Requester using xmlnode (View in Weblogs)
Posted: Jun 9, 2006 12:45 PM
Reply to this message Reply
Summary
As a followup to "Simplifying XML Manipulation", here is the Fedex Rate Requester that motivated me to make xmlnode in the first place. Because xmlnode got the XML-creation code noise out of the way, I was able to bash this together very quickly.
Advertisement

As people pointed out for that post, xmlnode does not handle XML namespaces. However, I have not had to deal with those yet; I've only needed to create XML and throw it at some application. If I run into a namespace problem, I'll either adapt xmlnode or move to some other system that handles them, like py.xml.

One thought occurred to me while I was building the rate requester: it's not uncommon that the documentation for the service you're using will give example XML showing what you should generate. It would be interesting to modify xmlnode so that it would parse existing XML and generate the code necessary to build that XML. This could speed up the development process and possibly eliminate mistakes.

Note that the FedexRateRequest class inherits Node, and inheritance (rather than composition) is useful here. Also, in the getRates() function, the copy.deepcopy() function is used to clone FedexRateRequest objects, eliminating duplicated effort.

Although I was able to put this code together quickly, I did depend on the code and information that I found at http://opensource.pseudocode.net/files/shipping.tgz , which definitely helped me bootstrap the process. Look at that package to find out how to get your own meter number.

import sys, urllib, copy
from xml.dom.minidom import parseString
from xmlnode import Node

class FedexRateRequest(Node):
    login = { "account" : "your account #", "meter" : "your meter #" }
    def __init__(self, service, packaging, weight, orginState, originZip, destState, destZip):
        self.Error = False
        if float(weight) > 1.0 and packaging == 'FEDEXENVELOPE': # Can't be more than 1 lb.
            packaging = 'FEDEXBOX'        
        Node.__init__(self, "FDXRateRequest")
        self.setAttribute("xmlns:api", "http://www.fedex.com/fsmapi")
        self.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
        self.setAttribute("xsi:noNamespaceSchemaLocation", "FDXRateRequest.xsd")
        
        self += Node("RequestHeader") + \
                Node("AccountNumber", FedexRateRequest.login["account"]) + \
                Node("MeterNumber", FedexRateRequest.login["meter"]) + \
                Node("CarrierCode", "FDXE")
        
        self += Node("Service", service)
        self += Node("Packaging", packaging)
        self += Node("WeightUnits", 'LBS')
        self += Node("Weight", weight)
        
        self += Node("OriginAddress") + Node("StateOrProvinceCode", orginState) + \
                Node("PostalCode", originZip) + Node("CountryCode", "US")
        
        self += Node("DestinationAddress") + Node("StateOrProvinceCode", destState) + \
                Node("PostalCode", destZip) + Node("CountryCode", "US")
        
        self += Node("Payment")
        
        self += Node("PackageCount", "1")
        
        self.result = None
    
    def requestRate(self):
        reqxml = '<?xml version="1.0" ?>' + self.rawxml().strip()
        result = urllib.urlopen("https://gateway.fedex.com/GatewayDC", reqxml).read()
        self.result = Node.create(parseString(result))
        if result.find("Error") != -1:
            self.Error = True
            return
        self.base = float(self.result["BaseCharge"].value)
        self.discount = float(self.result["TotalDiscount"].value)
        self.surcharge = float(self.result["TotalSurcharge"].value)
        self.netcharge = float(self.result["NetCharge"].value)
        
    def showResults(self):
        print self["Service"].value, self["Packaging"].value
        if self.Error:
            print "Error:", self.result["Message"].value
            return
        print "base:", self.base
        print "discount:", self.discount
        print "surcharge:", self.surcharge
        print "net charge:", self.netcharge
    
def getRates(packaging, weight, orginState, originZip, destState, destZip, homedelivery):
    priority = FedexRateRequest('PRIORITYOVERNIGHT', 
               packaging, weight, orginState, originZip,
               destState, destZip)
    standard = copy.deepcopy(priority)
    standard["Service"].value = 'STANDARDOVERNIGHT'
    twoday = copy.deepcopy(priority)
    twoday["Service"].value = 'FEDEX2DAY'
    ground = copy.deepcopy(priority)
    ground["CarrierCode"].value = 'FDXG'
    ground["Packaging"].value = 'YOURPACKAGING' # Ground must use YOURPACKAGING
    if homedelivery:
        ground["Service"].value = 'GROUNDHOMEDELIVERY'
    else:
        ground["Service"].value = 'FEDEXGROUND'
    priority.requestRate()
    standard.requestRate()
    twoday.requestRate()
    ground.requestRate()
    return (ground, twoday, standard, priority)

if __name__ == "__main__":
    for rate in getRates('1.6', "CA", "91941", "CO", "81224", homedelivery=False):
        rate.showResults()

Topic: A Fedex Rate Requester using xmlnode Previous Topic   Next Topic Topic: Are Long Work Hours Hazardous to Your Project?

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use