Skip to content

Commit fe08bf3

Browse files
author
Greg Taylor
committed
Bringing the source code in.
1 parent 1022a80 commit fe08bf3

12 files changed

+8889
-0
lines changed

example.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import logging
2+
from fedex.services.ship_service import FedexTrackRequest
3+
from fedex.config import FedexConfig
4+
5+
# Set this to the INFO level to see the response from Fedex printed in stdout.
6+
logging.basicConfig(level=logging.INFO)
7+
8+
# FedexConfig objects should generally only be instantiated once and re-used
9+
# amongst different queries. They hold static data like account number.
10+
config_obj = FedexConfig(key='ZyNQQFdcxUATOx9L',
11+
password='GtngmKzs4Dk4RYmrlAjrLykwi',
12+
account_number='510087780',
13+
meter_number='118501898')
14+
15+
# This is the object that will be handling our tracking request.
16+
track = FedexTrackRequest(config_obj, '1777768882')
17+
# Fires off the request, sets the 'response' attribute on the object.
18+
track.send_request()
19+
20+
# Look through the matches (there should only be one for a tracking number
21+
# query), and show a few details about each shipment.
22+
for match in track.response.TrackDetails:
23+
print "TRACKING #:", match.TrackingNumber
24+
print "STATUS:", match.StatusDescription

fedex/__init__.py

Whitespace-only changes.

fedex/base_service.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import os
2+
import logging
3+
from suds.client import Client
4+
5+
class FedexBaseService(object):
6+
def __init__(self, config_obj, wsdl_name, *args, **kwargs):
7+
self.config_obj = config_obj
8+
self.wsdl_path = os.path.join(config_obj.wsdl_path, wsdl_name)
9+
self.client = Client('file://%s' % self.wsdl_path)
10+
self.logger = logging.getLogger('fedex')
11+
12+
self.logger.debug(self.client)
13+
self.set_web_authentication_detail()
14+
self.set_client_detail()
15+
self.set_version_id()
16+
self.set_carrier_code_type(*args, **kwargs)
17+
self.set_transaction_detail(*args, **kwargs)
18+
19+
def set_web_authentication_detail(self):
20+
"""
21+
Sets up the WebAuthenticationDetail node. This is required for all
22+
requests.
23+
"""
24+
# Start of the authentication stuff.
25+
WebAuthenticationCredential = self.client.factory.create('WebAuthenticationCredential')
26+
WebAuthenticationCredential.Key = self.config_obj.key
27+
WebAuthenticationCredential.Password = self.config_obj.password
28+
29+
# Encapsulates the auth credentials.
30+
WebAuthenticationDetail = self.client.factory.create('WebAuthenticationDetail')
31+
WebAuthenticationDetail.UserCredential = WebAuthenticationCredential
32+
self.logger.debug(WebAuthenticationDetail)
33+
self.WebAuthenticationDetail = WebAuthenticationDetail
34+
35+
def set_client_detail(self):
36+
"""
37+
Sets up the ClientDetail node, which is required for all shipping
38+
related requests.
39+
"""
40+
ClientDetail = self.client.factory.create('ClientDetail')
41+
ClientDetail.AccountNumber = self.config_obj.account_number
42+
ClientDetail.MeterNumber = self.config_obj.meter_number
43+
ClientDetail.IntegratorId = self.config_obj.integrator_id
44+
self.logger.debug(ClientDetail)
45+
self.ClientDetail = ClientDetail
46+
47+
def set_transaction_detail(self, *args, **kwargs):
48+
"""
49+
Checks kwargs for 'customer_transaction_id' and sets it if present.
50+
"""
51+
customer_transaction_id = kwargs.get('customer_transaction_id', False)
52+
if customer_transaction_id:
53+
TransactionDetail = client.factory.create('TransactionDetail')
54+
TransactionDetail.CustomerTransactionId = customer_transaction_id
55+
self.logger.debug(TransactionDetail)
56+
self.TransactionDetail = TransactionDetail
57+
else:
58+
self.TransactionDetail = None
59+
60+
def set_carrier_code_type(self, *args, **kwargs):
61+
"""
62+
Checks kwargs for 'carrier_code' and sets it if present.
63+
"""
64+
carrier_code = kwargs.get('carrier_code', False)
65+
if carrier_code:
66+
CarrierCodeType = self.client.factory.create('CarrierCodeType')
67+
CarrierCodeType.Type = carrier_code
68+
self.logger.debug(CarrierCodeType)
69+
self.CarrierCodeType = CarrierCodeType
70+
else:
71+
self.CarrierCodeType = None
72+
73+
def set_version_id(self):
74+
"""
75+
Pulles the versioning info for the request from the child request.
76+
"""
77+
VersionId = self.client.factory.create('VersionId')
78+
VersionId.ServiceId = self.version_info['service_id']
79+
VersionId.Major = self.version_info['major']
80+
VersionId.Intermediate = self.version_info['intermediate']
81+
VersionId.Minor = self.version_info['minor']
82+
self.logger.debug(VersionId)
83+
self.VersionId = VersionId
84+
85+
def send_request(self):
86+
"""
87+
Sends the assembled request on the child object.
88+
"""
89+
self.response = self.assemble_and_send_request()
90+
self.logger.info("== FEDEX QUERY RESULT ==")
91+
self.logger.info(self.response)

fedex/config.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import os
2+
import sys
3+
4+
class FedexConfig(object):
5+
"""
6+
Base configuration class that is used for the different Fedex SOAP calls.
7+
"""
8+
def __init__(self, key, password, account_number=None, meter_number=None,
9+
integrator_id=None, wsdl_path=None):
10+
self.key = key
11+
self.password = password
12+
self.account_number = account_number
13+
self.meter_number = meter_number
14+
self.integrator_id = integrator_id
15+
16+
# Allow overriding of the WDSL path.
17+
if wsdl_path == None:
18+
self.wsdl_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
19+
'wsdl')
20+
else:
21+
self.wsdl_path = wsdl_path

fedex/services/__init__.py

Whitespace-only changes.

fedex/services/ship_service.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from .. base_service import FedexBaseService
2+
3+
class FedexTrackRequest(FedexBaseService):
4+
def __init__(self, config_obj, tracking_value,
5+
package_identifier='TRACKING_NUMBER_OR_DOORTAG',
6+
*args, **kwargs):
7+
"""
8+
Sends a shipment tracking request.
9+
10+
package_identifier: (str) Determines what you are using to query for
11+
the shipment. The default assumes that
12+
tracking_value will be a Fedex tracking #.
13+
tracking_value: (str) Based on the value of package_identifier, this
14+
will be anything from a tracking number to
15+
a purchase order number.
16+
"""
17+
self.config_obj = config_obj
18+
# Holds version info for the VersionId SOAP object.
19+
self.version_info = {'service_id': 'trck', 'major': '4',
20+
'intermediate': '0', 'minor': '0'}
21+
# Call the parent FedexBaseService class for basic setup work.
22+
super(FedexTrackRequest, self).__init__(config_obj,
23+
'TrackService_v4.wsdl',
24+
*args, **kwargs)
25+
# Start preparing the Fedex-specific things.
26+
self.tracking_value = tracking_value
27+
self.package_identifier = package_identifier
28+
self.set_track_package_identifier()
29+
30+
def set_track_package_identifier(self):
31+
"""
32+
This sets the package identifier information. This may be a tracking
33+
number or a few different things as per the Fedex spec.
34+
"""
35+
TrackPackageIdentifier = self.client.factory.create('TrackPackageIdentifier')
36+
TrackPackageIdentifier.Type = self.package_identifier
37+
TrackPackageIdentifier.Value = self.tracking_value
38+
self.logger.debug(TrackPackageIdentifier)
39+
self.TrackPackageIdentifier = TrackPackageIdentifier
40+
41+
def assemble_and_send_request(self):
42+
"""
43+
Fires off the Fedex request.
44+
NEVER CALL THIS METHOD DIRECTLY. CALL SEND_REQUEST(), WHICH RESIDES
45+
ON FedexBaseService AND IS INHERITED.
46+
"""
47+
client = self.client
48+
# Fire off the query.
49+
response = client.service.track(WebAuthenticationDetail=self.WebAuthenticationDetail,
50+
ClientDetail=self.ClientDetail,
51+
TransactionDetail=self.TransactionDetail,
52+
Version=self.VersionId,
53+
CarrierCodeType=self.CarrierCodeType,
54+
PackageIdentifier=self.TrackPackageIdentifier)
55+
return response

0 commit comments

Comments
 (0)