Skip to content

Commit 034b747

Browse files
author
Greg Taylor
committed
Got the track, create shipment, and delete shipment requests in what should be their final forms. Shipment creation is very verbose now, which is good or bad depending on how you like your code to look. It should very closely follow the Fedex API now, though. Shipment deletion is now in usable state. The examples directory has been improved as a whole.
1 parent d273847 commit 034b747

File tree

7 files changed

+166
-206
lines changed

7 files changed

+166
-206
lines changed

examples/create_shipment.py

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,15 @@
99
"""
1010
import logging
1111
import binascii
12+
from example_config import CONFIG_OBJ
1213
from fedex.services.ship_service import FedexProcessShipmentRequest
13-
from fedex.config import FedexConfig
1414

1515
# Set this to the INFO level to see the response from Fedex printed in stdout.
16-
logging.basicConfig(level=logging.ERROR)
17-
18-
# FedexConfig objects should generally only be instantiated once and re-used
19-
# amongst different queries. They hold static data like account number.
20-
config_obj = FedexConfig(key='ZyNQQFdcxUATOx9L',
21-
password='GtngmKzs4Dk4RYmrlAjrLykwi',
22-
account_number='510087780',
23-
meter_number='118501898',
24-
use_test_server=True)
16+
logging.basicConfig(level=logging.INFO)
2517

2618
# This is the object that will be handling our tracking request.
27-
shipment = FedexProcessShipmentRequest(config_obj)
19+
# We're using the FedexConfig object from example_config.py in this dir.
20+
shipment = FedexProcessShipmentRequest(CONFIG_OBJ)
2821

2922
# This is very generalized, top-level information.
3023
# REGULAR_PICKUP, REQUEST_COURIER, DROP_BOX, BUSINESS_SERVICE_CENTER or STATION
@@ -43,53 +36,53 @@
4336
shipment.RequestedShipment.PackageDetail = 'INDIVIDUAL_PACKAGES'
4437

4538
# Shipper contact info.
46-
shipment.ShipperContact.PersonName = 'Sender Name'
47-
shipment.ShipperContact.CompanyName = 'Some Company'
48-
shipment.ShipperContact.PhoneNumber = '9012638716'
39+
shipment.RequestedShipment.Shipper.Contact.PersonName = 'Sender Name'
40+
shipment.RequestedShipment.Shipper.Contact.CompanyName = 'Some Company'
41+
shipment.RequestedShipment.Shipper.Contact.PhoneNumber = '9012638716'
4942

5043
# Shipper address.
51-
shipment.ShipperAddress.StreetLines = ['Address Line 1']
52-
shipment.ShipperAddress.City = 'Herndon'
53-
shipment.ShipperAddress.StateOrProvinceCode = 'VA'
54-
shipment.ShipperAddress.PostalCode = '20171'
55-
shipment.ShipperAddress.CountryCode = 'US'
56-
shipment.ShipperAddress.Residential = True
44+
shipment.RequestedShipment.Shipper.Address.StreetLines = ['Address Line 1']
45+
shipment.RequestedShipment.Shipper.Address.City = 'Herndon'
46+
shipment.RequestedShipment.Shipper.Address.StateOrProvinceCode = 'VA'
47+
shipment.RequestedShipment.Shipper.Address.PostalCode = '20171'
48+
shipment.RequestedShipment.Shipper.Address.CountryCode = 'US'
49+
shipment.RequestedShipment.Shipper.Address.Residential = True
5750

5851
# Recipient contact info.
59-
shipment.RecipientContact.PersonName = 'Recipient Name'
60-
shipment.RecipientContact.CompanyName = 'Recipient Company'
61-
shipment.RecipientContact.PhoneNumber = '9012637906'
52+
shipment.RequestedShipment.Recipient.Contact.PersonName = 'Recipient Name'
53+
shipment.RequestedShipment.Recipient.Contact.CompanyName = 'Recipient Company'
54+
shipment.RequestedShipment.Recipient.Contact.PhoneNumber = '9012637906'
6255

6356
# Recipient address
64-
shipment.RecipientAddress.StreetLines = ['Address Line 1']
65-
shipment.RecipientAddress.City = 'Herndon'
66-
shipment.RecipientAddress.StateOrProvinceCode = 'VA'
67-
shipment.RecipientAddress.PostalCode = '20171'
68-
shipment.RecipientAddress.CountryCode = 'US'
57+
shipment.RequestedShipment.Recipient.Address.StreetLines = ['Address Line 1']
58+
shipment.RequestedShipment.Recipient.Address.City = 'Herndon'
59+
shipment.RequestedShipment.Recipient.Address.StateOrProvinceCode = 'VA'
60+
shipment.RequestedShipment.Recipient.Address.PostalCode = '20171'
61+
shipment.RequestedShipment.Recipient.Address.CountryCode = 'US'
6962
# This is needed to ensure an accurate rate quote with the response.
70-
shipment.RecipientAddress.Residential = True
63+
shipment.RequestedShipment.Recipient.Address.Residential = True
7164

7265
# Who pays for the shipment?
7366
# RECIPIENT, SENDER or THIRD_PARTY
74-
shipment.ShippingChargesPayment.PaymentType = 'SENDER'
67+
shipment.RequestedShipment.ShippingChargesPayment.PaymentType = 'SENDER'
7568

7669
# Specifies the label type to be returned.
7770
# LABEL_DATA_ONLY or COMMON2D
78-
shipment.LabelSpecification.LabelFormatType = 'COMMON2D'
71+
shipment.RequestedShipment.LabelSpecification.LabelFormatType = 'COMMON2D'
7972

8073
# Specifies which format the label file will be sent to you in.
8174
# DPL, EPL2, PDF, PNG, ZPLII
82-
shipment.LabelSpecification.ImageType = 'PNG'
75+
shipment.RequestedShipment.LabelSpecification.ImageType = 'PNG'
8376

8477
# To use doctab stocks, you must change ImageType above to one of the
8578
# label printer formats (ZPLII, EPL2, DPL).
8679
# See documentation for paper types, there quite a few.
87-
shipment.LabelSpecification.LabelStockType = 'PAPER_4X6'
80+
shipment.RequestedShipment.LabelSpecification.LabelStockType = 'PAPER_4X6'
8881

8982
# This indicates if the top or bottom of the label comes out of the
9083
# printer first.
9184
# BOTTOM_EDGE_OF_TEXT_FIRST or TOP_EDGE_OF_TEXT_FIRST
92-
shipment.LabelSpecification.LabelPrintingOrientation = 'BOTTOM_EDGE_OF_TEXT_FIRST'
85+
shipment.RequestedShipment.LabelSpecification.LabelPrintingOrientation = 'BOTTOM_EDGE_OF_TEXT_FIRST'
9386

9487
package1_weight = shipment.create_wsdl_object_of_type('Weight')
9588
# Weight, in pounds.
@@ -125,7 +118,7 @@
125118
# This will show the reply to your shipment being sent. You can access the
126119
# attributes through the response attribute on the request object. This is
127120
# good to un-comment to see the variables returned by the Fedex reply.
128-
#print shipment.response
121+
print shipment.response
129122

130123
# Here is the overall end result of the query.
131124
print "HighestSeverity:", shipment.response.HighestSeverity

examples/delete_shipment.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env python
2+
"""
3+
This example shows how to delete existing shipments.
4+
"""
5+
import logging
6+
from example_config import CONFIG_OBJ
7+
from fedex.services.ship_service import FedexDeleteShipmentRequest
8+
9+
# Set this to the INFO level to see the response from Fedex printed in stdout.
10+
logging.basicConfig(level=logging.INFO)
11+
12+
# This is the object that will be handling our tracking request.
13+
# We're using the FedexConfig object from example_config.py in this dir.
14+
del_request = FedexDeleteShipmentRequest(CONFIG_OBJ)
15+
16+
# Either delete all packages in a shipment, or delete an individual package.
17+
# DELETE_ALL_PACKAGES, DELETE_ONE_PACKAGE
18+
del_request.DeletionControlType = "DELETE_ALL_PACKAGES"
19+
20+
# The tracking number of the shipment to delete.
21+
del_request.TrackingId.TrackingNumber = '794798682968'
22+
23+
# What kind of shipment the tracking number used.
24+
# EXPRESS, GROUND, or USPS
25+
del_request.TrackingId.TrackingIdType = 'EXPRESS'
26+
27+
# Fires off the request, sets the 'response' attribute on the object.
28+
del_request.send_request()
29+
30+
# See the response printed out.
31+
print del_request.response

examples/example_config.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""
2+
This file holds various configuration options used for all of the examples.
3+
"""
4+
import os
5+
import sys
6+
# Use the fedex directory included in the downloaded package instead of
7+
# any globally installed versions.
8+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
9+
from fedex.config import FedexConfig
10+
11+
CONFIG_OBJ = FedexConfig(key='ZyNQQFdcxUATOx9L',
12+
password='GtngmKzs4Dk4RYmrlAjrLykwi',
13+
account_number='510087780',
14+
meter_number='118501898',
15+
use_test_server=True)

examples/track_shipment.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,28 @@
33
This example shows how to track shipments.
44
"""
55
import logging
6+
from example_config import CONFIG_OBJ
67
from fedex.services.track_service import FedexTrackRequest
7-
from fedex.config import FedexConfig
88

99
# Set this to the INFO level to see the response from Fedex printed in stdout.
1010
logging.basicConfig(level=logging.INFO)
1111

12-
# FedexConfig objects should generally only be instantiated once and re-used
13-
# amongst different queries. They hold static data like account number.
14-
config_obj = FedexConfig(key='ZyNQQFdcxUATOx9L',
15-
password='GtngmKzs4Dk4RYmrlAjrLykwi',
16-
account_number='510087780',
17-
meter_number='118501898',
18-
use_test_server=True)
12+
# NOTE: TRACKING IS VERY ERRATIC ON THE TEST SERVERS. YOU MAY NEED TO USE
13+
# PRODUCTION KEYS/PASSWORDS/ACCOUNT #.
14+
# We're using the FedexConfig object from example_config.py in this dir.
15+
track = FedexTrackRequest(CONFIG_OBJ)
16+
track.TrackPackageIdentifier.Type = 'TRACKING_NUMBER_OR_DOORTAG'
17+
track.TrackPackageIdentifier.Value = '798114182456'
1918

20-
# This is the object that will be handling our tracking request.
21-
track = FedexTrackRequest(config_obj, '798114182456')
2219
# Fires off the request, sets the 'response' attribute on the object.
2320
track.send_request()
2421

22+
# See the response printed out.
23+
print track.response
24+
2525
# Look through the matches (there should only be one for a tracking number
2626
# query), and show a few details about each shipment.
27+
print "== Results =="
2728
for match in track.response.TrackDetails:
28-
print "TRACKING #:", match.TrackingNumber
29-
print "STATUS:", match.StatusDescription
29+
print "Tracking #:", match.TrackingNumber
30+
print "Status:", match.StatusDescription

fedex/base_service.py

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -63,41 +63,43 @@ def __init__(self, config_obj, wsdl_name, *args, **kwargs):
6363
@keyword customer_transaction_id: A user-specified identifier to
6464
differentiate this transaction from others. This value will be
6565
returned with the response from Fedex.
66-
@type carrier_code: L{str}
67-
@keyword carrier_code: The carrier code to use for this query. In most
68-
cases, this will be FDXE (Fedex Express). Must be one of the
69-
following four-letter codes:
70-
- FDXC (Fedex Cargo)
71-
- FDXE (Fedex Express)
72-
- FDXG (Fedex Ground)
73-
- FXCC (Fedex Custom Critical)
74-
- FXFR (Fedex Freight)
75-
- FXSP (Fedex Smartpost)
7666
"""
67+
self.logger = logging.getLogger('fedex')
68+
"""@ivar: Python logger instance with name 'fedex'."""
7769
self.config_obj = config_obj
70+
"""@ivar: The FedexConfig object to pull auth info from."""
7871

7972
# If the config object is set to use the test server, point
8073
# suds at the test server WSDL directory.
8174
if config_obj.use_test_server:
75+
self.logger.info("Using test server.")
8276
self.wsdl_path = os.path.join(config_obj.wsdl_path,
8377
'test_server_wsdl', wsdl_name)
8478
else:
79+
self.logger.info("Using production server.")
8580
self.wsdl_path = os.path.join(config_obj.wsdl_path, wsdl_name)
8681

8782
self.client = Client('file://%s' % self.wsdl_path)
88-
self.logger = logging.getLogger('fedex')
83+
84+
self.VersionId = None
85+
"""@ivar: Holds details on the version numbers of the WSDL."""
86+
self.WebAuthenticationDetail = None
87+
"""@ivar: WSDL object that holds authentication info."""
88+
self.ClientDetail = None
89+
"""@ivar: WSDL object that holds client account details."""
8990
self.response = None
9091
"""@ivar: The response from Fedex. You will want to pick what you
9192
want out here here. This object does have a __str__() method,
9293
you'll want to print or log it to see what possible values
9394
you can pull."""
95+
self.TransactionDetail = None
96+
"""@ivar: Holds customer-specified transaction IDs."""
9497

95-
self.logger.debug(self.client)
9698
self.__set_web_authentication_detail()
9799
self.__set_client_detail()
98100
self.__set_version_id()
99-
self.__set_carrier_code_type(*args, **kwargs)
100101
self.__set_transaction_detail(*args, **kwargs)
102+
self._prepare_wsdl_objects()
101103

102104
def __set_web_authentication_detail(self):
103105
"""
@@ -112,7 +114,6 @@ def __set_web_authentication_detail(self):
112114
# Encapsulates the auth credentials.
113115
WebAuthenticationDetail = self.client.factory.create('WebAuthenticationDetail')
114116
WebAuthenticationDetail.UserCredential = WebAuthenticationCredential
115-
self.logger.debug(WebAuthenticationDetail)
116117
self.WebAuthenticationDetail = WebAuthenticationDetail
117118

118119
def __set_client_detail(self):
@@ -124,7 +125,6 @@ def __set_client_detail(self):
124125
ClientDetail.AccountNumber = self.config_obj.account_number
125126
ClientDetail.MeterNumber = self.config_obj.meter_number
126127
ClientDetail.IntegratorId = self.config_obj.integrator_id
127-
self.logger.debug(ClientDetail)
128128
self.ClientDetail = ClientDetail
129129

130130
def __set_transaction_detail(self, *args, **kwargs):
@@ -133,25 +133,10 @@ def __set_transaction_detail(self, *args, **kwargs):
133133
"""
134134
customer_transaction_id = kwargs.get('customer_transaction_id', False)
135135
if customer_transaction_id:
136-
TransactionDetail = client.factory.create('TransactionDetail')
136+
TransactionDetail = self.client.factory.create('TransactionDetail')
137137
TransactionDetail.CustomerTransactionId = customer_transaction_id
138138
self.logger.debug(TransactionDetail)
139139
self.TransactionDetail = TransactionDetail
140-
else:
141-
self.TransactionDetail = None
142-
143-
def __set_carrier_code_type(self, *args, **kwargs):
144-
"""
145-
Checks kwargs for 'carrier_code' and sets it if present.
146-
"""
147-
carrier_code = kwargs.get('carrier_code', False)
148-
if carrier_code:
149-
CarrierCodeType = self.client.factory.create('CarrierCodeType')
150-
CarrierCodeType.Type = carrier_code
151-
self.logger.debug(CarrierCodeType)
152-
self.CarrierCodeType = CarrierCodeType
153-
else:
154-
self.CarrierCodeType = None
155140

156141
def __set_version_id(self):
157142
"""
@@ -165,6 +150,14 @@ def __set_version_id(self):
165150
self.logger.debug(VersionId)
166151
self.VersionId = VersionId
167152

153+
def __prepare_wsdl_objects(self):
154+
"""
155+
This method should be over-ridden on each sub-class. It instantiates
156+
any of the required WSDL objects so the user can just print their
157+
__str__() methods and see what they need to fill in.
158+
"""
159+
pass
160+
168161
def __check_response_for_fedex_error(self):
169162
"""
170163
This checks the response for general Fedex errors that aren't related

0 commit comments

Comments
 (0)