Skip to content

Commit d273847

Browse files
author
Greg Taylor
committed
Adding shipment validation on FedexProcessShipmentRequest objects via send_validation_request(). This is a good way to make sure you've got valid data before actually committing to creating a shipment with it. Works almost exactly like just sending the request. Also adding the beginnings of shipment deletion (not at all functional yet).
1 parent 88c0256 commit d273847

File tree

4 files changed

+137
-12
lines changed

4 files changed

+137
-12
lines changed

examples/create_shipment.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,18 @@
114114
# change.
115115
#print shipment.RequestedShipment
116116

117+
# If you want to make sure that all of your entered details are valid, you
118+
# can call this and parse it just like you would via send_request(). If
119+
# shipment.response.HighestSeverity == "SUCCESS", your shipment is valid.
120+
#shipment.send_validation_request()
121+
117122
# Fires off the request, sets the 'response' attribute on the object.
118123
shipment.send_request()
119124

120125
# This will show the reply to your shipment being sent. You can access the
121126
# attributes through the response attribute on the request object. This is
122127
# good to un-comment to see the variables returned by the Fedex reply.
123-
print shipment.response
128+
#print shipment.response
124129

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

fedex/base_service.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,13 +194,25 @@ def create_wsdl_object_of_type(self, type_name):
194194
"""
195195
return self.client.factory.create(type_name)
196196

197-
def send_request(self):
197+
def send_request(self, send_function=None):
198198
"""
199199
Sends the assembled request on the child object.
200+
@type send_function: L{function}
201+
@keyword send_function: A function reference (passed without the
202+
parenthesis) to a function that will send the request. This
203+
allows for overriding the default function in cases such as
204+
validation requests.
200205
"""
201206
# Send the request and get the response back.
202207
try:
203-
self.response = self._assemble_and_send_request()
208+
# If the user has overridden the send function, use theirs
209+
# instead of the default.
210+
if send_function:
211+
# Follow the overridden function.
212+
self.response = send_function()
213+
else:
214+
# Default scenario, business as usual.
215+
self.response = self._assemble_and_send_request()
204216
except suds.WebFault:
205217
# When this happens, throw an informative message reminding the
206218
# user to check all required variables, making sure they are
@@ -215,5 +227,5 @@ def send_request(self):
215227
self._check_response_for_request_errors()
216228

217229
# Debug output.
218-
self.logger.info("== FEDEX QUERY RESULT ==")
219-
self.logger.info(self.response)
230+
self.logger.debug("== FEDEX QUERY RESULT ==")
231+
self.logger.debug(self.response)

fedex/services/ship_service.py

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,30 @@ def __set_requested_shipment(self):
112112
# looks like.
113113
self.logger.info(self.RequestedShipment)
114114

115+
def send_validation_request(self):
116+
"""
117+
This is very similar to just sending the shipment via the typical
118+
send_request() function, but this doesn't create a shipment. It is
119+
used to make sure "good" values are given by the user or the
120+
application using the library.
121+
"""
122+
self.send_request(send_function=self._assemble_and_send_validation_request)
123+
124+
def _assemble_and_send_validation_request(self):
125+
"""
126+
Fires off the Fedex request.
127+
128+
@warning: NEVER CALL THIS METHOD DIRECTLY. CALL send_request(), WHICH RESIDES
129+
ON FedexBaseService AND IS INHERITED.
130+
"""
131+
# Fire off the query.
132+
response = self.client.service.processShipment(WebAuthenticationDetail=self.WebAuthenticationDetail,
133+
ClientDetail=self.ClientDetail,
134+
TransactionDetail=self.TransactionDetail,
135+
Version=self.VersionId,
136+
RequestedShipment=self.RequestedShipment)
137+
return response
138+
115139
def _assemble_and_send_request(self):
116140
"""
117141
Fires off the Fedex request.
@@ -140,4 +164,89 @@ def add_package(self, package_item):
140164
self.RequestedShipment.RequestedPackageLineItems.append(package_item)
141165
package_weight = package_item.Weight.Value
142166
self.RequestedShipment.TotalWeight.Value += package_weight
143-
self.RequestedShipment.PackageCount += 1
167+
self.RequestedShipment.PackageCount += 1
168+
169+
class FedexDeleteShipmentRequest(FedexBaseService):
170+
"""
171+
This class allows you to delete a shipment, given a tracking number.
172+
"""
173+
def __init__(self, config_obj, tracking_value,
174+
package_identifier='TRACKING_NUMBER_OR_DOORTAG',
175+
*args, **kwargs):
176+
"""
177+
Sends a shipment tracking request. The optional keyword args
178+
detailed on L{FedexBaseService} apply here as well.
179+
180+
@type config_obj: L{FedexConfig}
181+
@param config_obj: A valid FedexConfig object.
182+
@type tracking_value: L{str}
183+
@param tracking_value: Based on the value of package_identifier,
184+
this will be anything from a tracking number to a purchase order
185+
number.
186+
@type package_identifier: L{str}
187+
@keyword package_identifier: Determines what you are using to query for
188+
the shipment. The default assumes that tracking_value will be a Fedex
189+
tracking number.
190+
"""
191+
self._config_obj = config_obj
192+
193+
# Holds version info for the VersionId SOAP object.
194+
self._version_info = {'service_id': 'trck', 'major': '4',
195+
'intermediate': '0', 'minor': '0'}
196+
# Call the parent FedexBaseService class for basic setup work.
197+
super(FedexTrackRequest, self).__init__(self._config_obj,
198+
'TrackService_v4.wsdl',
199+
*args, **kwargs)
200+
201+
# Important request-specific instance variables.
202+
self.package_identifier = package_identifier
203+
"""@ivar: Determines what L{tracking_value} is, be it a tracking number,
204+
purchase order, or other things."""
205+
self.tracking_value = tracking_value
206+
"""@ivar: This is typically a Fedex tracking number, but setting
207+
L{package_identifier} to other values makes this change."""
208+
209+
def __set_track_package_identifier(self):
210+
"""
211+
This sets the package identifier information. This may be a tracking
212+
number or a few different things as per the Fedex spec.
213+
"""
214+
TrackPackageIdentifier = self.client.factory.create('TrackPackageIdentifier')
215+
TrackPackageIdentifier.Type = self.package_identifier
216+
TrackPackageIdentifier.Value = self.tracking_value
217+
self.logger.debug(TrackPackageIdentifier)
218+
self.TrackPackageIdentifier = TrackPackageIdentifier
219+
220+
def _check_response_for_request_errors(self):
221+
"""
222+
Checks the response to see if there were any errors specific to
223+
this WSDL.
224+
"""
225+
if self.response.HighestSeverity == "ERROR":
226+
for notification in self.response.Notifications:
227+
if notification.Severity == "ERROR":
228+
if "Invalid tracking number" in notification.Message:
229+
raise FedexInvalidTrackingNumber(notification.Code,
230+
notification.Message)
231+
else:
232+
raise FedexError(notification.Code,
233+
notification.Message)
234+
235+
def _assemble_and_send_request(self):
236+
"""
237+
Fires off the Fedex request.
238+
239+
@warning: NEVER CALL THIS METHOD DIRECTLY. CALL send_request(), WHICH RESIDES
240+
ON FedexBaseService AND IS INHERITED.
241+
"""
242+
self.__set_track_package_identifier()
243+
client = self.client
244+
# Fire off the query.
245+
response = client.service.track(WebAuthenticationDetail=self.WebAuthenticationDetail,
246+
ClientDetail=self.ClientDetail,
247+
TransactionDetail=self.TransactionDetail,
248+
Version=self.VersionId,
249+
CarrierCodeType=self.CarrierCodeType,
250+
PackageIdentifier=self.TrackPackageIdentifier)
251+
252+
return response

fedex/services/track_service.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,17 @@ def __init__(self, config_obj, tracking_value,
5858
self.tracking_value = tracking_value
5959
"""@ivar: This is typically a Fedex tracking number, but setting
6060
L{package_identifier} to other values makes this change."""
61+
# Get the object ready for manipulation.
62+
self.__set_track_package_identifier()
6163

6264
def __set_track_package_identifier(self):
6365
"""
6466
This sets the package identifier information. This may be a tracking
6567
number or a few different things as per the Fedex spec.
6668
"""
67-
TrackPackageIdentifier = self.client.factory.create('TrackPackageIdentifier')
68-
TrackPackageIdentifier.Type = self.package_identifier
69-
TrackPackageIdentifier.Value = self.tracking_value
70-
self.logger.debug(TrackPackageIdentifier)
71-
self.TrackPackageIdentifier = TrackPackageIdentifier
69+
self.TrackPackageIdentifier = self.client.factory.create('TrackPackageIdentifier')
70+
self.TrackPackageIdentifier.Type = self.package_identifier
71+
self.TrackPackageIdentifier.Value = self.tracking_value
7272

7373
def _check_response_for_request_errors(self):
7474
"""
@@ -92,7 +92,6 @@ def _assemble_and_send_request(self):
9292
@warning: NEVER CALL THIS METHOD DIRECTLY. CALL send_request(), WHICH RESIDES
9393
ON FedexBaseService AND IS INHERITED.
9494
"""
95-
self.__set_track_package_identifier()
9695
client = self.client
9796
# Fire off the query.
9897
response = client.service.track(WebAuthenticationDetail=self.WebAuthenticationDetail,

0 commit comments

Comments
 (0)