Skip to content

Commit daa958b

Browse files
committed
Merge pull request #59 from gtaylor/avc_v4
Avc v4
2 parents 9a69aa8 + 0ee1c28 commit daa958b

19 files changed

+1057
-59
lines changed

CHANGES.rst

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
11
Change Log
22
==========
33

4+
2.1.0
5+
-----
6+
7+
* Added Validation, Availability and Commitment (AVC) service. (radzhome)
8+
* Added [Validation]AvailabilityAndCommitmentService_v4.wsdl for AVC service. (radzhome)
9+
* Added examples and unit tests for AVC service.
10+
* Refactored examples and documentation. (radzhome)
11+
12+
413
2.0.0
514
-----
615

7-
* Bump ShipService WSDL to v17 for create and delete shipment. (radlws)
8-
* Bump AddressValidation WSDL to v4. (radlws)
9-
* Bump RateService WSDL to v18. (radlws)
10-
* Bump TrackService WSDL to v10. (radlws)
11-
* General improvements to base class. (radlws)
12-
* Refactoring and updates to examples. (radlws)
13-
* Added test classes. (radlws)
14-
* Remove old and unused WSDLs. (radlws)
15-
* Change dependency to suds-jurko to include python 3 support. (radlws)
16+
* Bump ShipService WSDL to v17 for create and delete shipment. (radzhome)
17+
* Bump AddressValidation WSDL to v4. (radzhome)
18+
* Bump RateService WSDL to v18. (radzhome)
19+
* Bump TrackService WSDL to v10. (radzhome)
20+
* General improvements to base class. (radzhome)
21+
* Refactoring and updates to examples. (radzhome)
22+
* Added test classes. (radzhome)
23+
* Remove old and unused WSDLs. (radzhome)
24+
* Change dependency to suds-jurko to include python 3 support. (radzhome)
1625

1726
1.1.1
1827
-----
@@ -24,7 +33,7 @@ Change Log
2433
-----
2534

2635
* A quick PEP8 pass on most of the codebase. Yucky. (gtaylor)
27-
* Changing recommended install method to use pip + PyPi. (radlws)
36+
* Changing recommended install method to use pip + PyPi. (radzhome)
2837
* Updated rate_request and freight_rate_request examples for WSDL v16
2938
compatibility. (foxxyz)
3039
* Updated rate service WSDL from v8 to v16. (foxxyz)

README.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ Python FedEx SOAP API Module
44
:Author: Greg Taylor
55
:License: BSD
66
:Status: Stable
7-
:Maintained: Quasi-maintained, looking for new maintainer
87

98
What is it?
109
-----------
@@ -49,8 +48,8 @@ Fedex Support and Documentation
4948
Fedex Support Email: websupport@fedex.com
5049
Developer Portal: http://www.fedex.com/us/developer/
5150

52-
Legal Mumbo Jumbo
53-
-----------------
51+
Legal
52+
-----
5453

5554
Copyright (C) 2015 Gregory Taylor
5655

examples/address_validation.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class can handle up to 100 addresses for validation.
1313
# Set this to the INFO level to see the response from Fedex printed in stdout.
1414
logging.basicConfig(level=logging.INFO)
1515

16-
# This is the object that will be handling our tracking request.
16+
# This is the object that will be handling our avs request.
1717
# We're using the FedexConfig object from example_config.py in this dir.
1818
customer_transaction_id = "*** AddressValidation Request v4 using Python ***" # Optional transaction_id
1919
# Optional locale & language client data
@@ -68,27 +68,35 @@ class can handle up to 100 addresses for validation.
6868
# Overall end result of the query
6969
for i in range(len(avs_request.response.AddressResults)):
7070

71-
print("Details for Address", i + 1)
72-
print("The validated street is:", avs_request.response.AddressResults[i].EffectiveAddress.StreetLines)
73-
print("The validated city is:", avs_request.response.AddressResults[i].EffectiveAddress.City)
74-
print("The validated state code is:", avs_request.response.AddressResults[i].EffectiveAddress.StateOrProvinceCode)
75-
print("The validated postal code is:", avs_request.response.AddressResults[i].EffectiveAddress.PostalCode)
76-
print("The validated country code is:", avs_request.response.AddressResults[i].EffectiveAddress.CountryCode)
71+
print("Details for Address {}".format(i + 1))
72+
print("The validated street is: {}"
73+
"".format(avs_request.response.AddressResults[i].EffectiveAddress.StreetLines))
74+
print("The validated city is: {}"
75+
"".format(avs_request.response.AddressResults[i].EffectiveAddress.City))
76+
print("The validated state code is: {}"
77+
"".format(avs_request.response.AddressResults[i].EffectiveAddress.StateOrProvinceCode))
78+
print("The validated postal code is: {}"
79+
"".format(avs_request.response.AddressResults[i].EffectiveAddress.PostalCode))
80+
print("The validated country code is: {}"
81+
"".format(avs_request.response.AddressResults[i].EffectiveAddress.CountryCode))
7782

7883
# Can be used to determine the address classification to figure out if Residential fee should apply.
7984
# MIXED, RESIDENTIAL, UNKNOWN, BUSINESS
80-
print("The validated address is residential:", avs_request.response.AddressResults[i].Classification != 'BUSINESS')
85+
print("The validated address is residential: {}"
86+
"".format(avs_request.response.AddressResults[i].Classification != 'BUSINESS'))
8187

8288
# Getting the optional attributes if available
8389
for j in range(len(avs_request.response.AddressResults[i].Attributes)):
8490
cur_attribute = avs_request.response.AddressResults[i].Attributes[j]
8591
if cur_attribute.Name == "CountrySupported":
86-
print("Supported Country:", cur_attribute.Value == 'true')
92+
print("Supported Country: {}".format(cur_attribute.Value == 'true'))
8793
if cur_attribute.Name == "SuiteRequiredButMissing":
88-
print("Missing Suite:", cur_attribute.Value == 'true')
94+
print("Missing Suite: {}".format(cur_attribute.Value == 'true'))
8995
if cur_attribute.Name == "CountrySupported":
90-
print("Invalid Suite:", cur_attribute.Value == 'true')
96+
print("Invalid Suite: {}".format(cur_attribute.Value == 'true'))
9197
if cur_attribute.Name == "MultipleMatches":
92-
print("Multiple Matches:", cur_attribute.Value == 'true')
98+
print("Multiple Matches: {}".format(cur_attribute.Value == 'true'))
9399
if cur_attribute.Name == "POBox":
94-
print("Is POBox:", cur_attribute.Value == 'true')
100+
print("Is POBox: {}".format(cur_attribute.Value == 'true'))
101+
print("")
102+

examples/create_freight_shipment.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
# NOTE: A VALID 'freight_account_number' REQUIRED IN YOUR 'CONFIB_OBJ' FOR THIS SERVICE TO WORK.
2525
# OTHERWISE YOU WILL GET FEDEX FREIGHT OR ASSOCIATED ADDRESS IS REQUIRED, ERROR 3619.
2626

27-
# This is the object that will be handling our tracking request.
27+
# This is the object that will be handling our freight shipment request.
2828
# We're using the FedexConfig object from example_config.py in this dir.
2929
shipment = FedexProcessShipmentRequest(CONFIG_OBJ)
3030
shipment.RequestedShipment.DropoffType = 'REGULAR_PICKUP'
@@ -148,12 +148,17 @@
148148
# attributes through the response attribute on the request object. This is
149149
# good to un-comment to see the variables returned by the Fedex reply.
150150
print(shipment.response)
151+
151152
# Here is the overall end result of the query.
152-
# print("HighestSeverity:", shipment.response.HighestSeverity)
153-
# # Getting the tracking number from the new shipment.
154-
# print("Tracking #:", shipment.response.CompletedShipmentDetail.CompletedPackageDetails[0].TrackingIds[0].TrackingNumber)
155-
# # Net shipping costs.
156-
# print("Net Shipping Cost (US$):", shipment.response.CompletedShipmentDetail.CompletedPackageDetails[0].PackageRating.PackageRateDetails[0].NetCharge.Amount)
153+
print("HighestSeverity: {}".format(shipment.response.HighestSeverity))
154+
155+
# Getting the tracking number from the new shipment.
156+
print("Tracking #: {}"
157+
"".format(shipment.response.CompletedShipmentDetail.MasterTrackingId.TrackingNumber))
158+
159+
# Net shipping costs.
160+
amount = shipment.response.CompletedShipmentDetail.ShipmentRating.ShipmentRateDetails[0].TotalNetCharge.Amount
161+
print("Net Shipping Cost (US$): {}".format(amount))
157162

158163

159164
# # Get the label image in ASCII format from the reply. Note the list indices
@@ -170,7 +175,7 @@
170175
"""
171176
# This will be the file we write the label out to.
172177
out_path = 'example_freight_shipment_label.%s' % GENERATE_IMAGE_TYPE.lower()
173-
print("Writing to file", out_path)
178+
print("Writing to file {}".format(out_path))
174179
out_file = open(out_path, 'wb')
175180
out_file.write(label_binary_data)
176181
out_file.close()

examples/create_shipment.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
# Set this to the INFO level to see the response from Fedex printed in stdout.
2323
logging.basicConfig(level=logging.INFO)
2424

25-
# This is the object that will be handling our tracking request.
25+
# This is the object that will be handling our shipment request.
2626
# We're using the FedexConfig object from example_config.py in this dir.
2727
customer_transaction_id = "*** ShipService Request v17 using Python ***" # Optional transaction_id
2828
shipment = FedexProcessShipmentRequest(CONFIG_OBJ, customer_transaction_id=customer_transaction_id)
@@ -143,17 +143,19 @@
143143
print(shipment.response)
144144

145145
# Here is the overall end result of the query.
146-
print("HighestSeverity:", shipment.response.HighestSeverity)
146+
print("HighestSeverity: {}".format(shipment.response.HighestSeverity))
147147

148148
# Getting the tracking number from the new shipment.
149-
print("Tracking #:", shipment.response.CompletedShipmentDetail.CompletedPackageDetails[0].TrackingIds[0].TrackingNumber)
149+
print("Tracking #: {}"
150+
"".format(shipment.response.CompletedShipmentDetail.CompletedPackageDetails[0].TrackingIds[0].TrackingNumber))
150151

151152
# Net shipping costs. Only show if available. Sometimes sandbox will not include this in the response.
152153
CompletedPackageDetails = shipment.response.CompletedShipmentDetail.CompletedPackageDetails[0]
153154
if hasattr(CompletedPackageDetails, 'PackageRating'):
154-
print("Net Shipping Cost (US$):", CompletedPackageDetails.PackageRating.PackageRateDetails[0].NetCharge.Amount)
155+
print("Net Shipping Cost (US$): {}"
156+
"".format(CompletedPackageDetails.PackageRating.PackageRateDetails[0].NetCharge.Amount))
155157
else:
156-
print('WARNING: Unable to get rate.')
158+
print('WARNING: Unable to get shipping rate.')
157159

158160
# Get the label image in ASCII format from the reply. Note the list indices
159161
# we're using. You'll need to adjust or iterate through these if your shipment
@@ -169,7 +171,7 @@
169171
"""
170172
# This will be the file we write the label out to.
171173
out_path = 'example_shipment_label.%s' % GENERATE_IMAGE_TYPE.lower()
172-
print("Writing to file", out_path)
174+
print("Writing to file {}".format(out_path))
173175
out_file = open(out_path, 'wb')
174176
out_file.write(label_binary_data)
175177
out_file.close()

examples/delete_shipment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# Set this to the INFO level to see the response from Fedex printed in stdout.
1010
logging.basicConfig(level=logging.INFO)
1111

12-
# This is the object that will be handling our tracking request.
12+
# This is the object that will be handling our request.
1313
# We're using the FedexConfig object from example_config.py in this dir.
1414
del_request = FedexDeleteShipmentRequest(CONFIG_OBJ)
1515

examples/freight_rate_request.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# Set this to the INFO level to see the response from Fedex printed in stdout.
1616
logging.basicConfig(level=logging.INFO)
1717

18-
# This is the object that will be handling our tracking request.
18+
# This is the object that will be handling our request.
1919
# We're using the FedexConfig object from example_config.py in this dir.
2020
rate_request = FedexRateServiceRequest(CONFIG_OBJ)
2121

examples/rate_request.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
logging.basicConfig(level=logging.INFO)
1717

1818

19-
# This is the object that will be handling our tracking request.
19+
# This is the object that will be handling our request.
2020
# We're using the FedexConfig object from example_config.py in this dir.
2121
customer_transaction_id = "*** RateService Request v18 using Python ***" # Optional transaction_id
2222
rate_request = FedexRateServiceRequest(CONFIG_OBJ, customer_transaction_id=customer_transaction_id)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#!/usr/bin/env python
2+
"""
3+
This example shows how to use the FedEx Service Validation,
4+
Availability and Commitment Service.
5+
The variables populated below represents common values.
6+
You will need to fill out the required values or risk seeing a SchemaValidationError
7+
exception thrown by suds.
8+
"""
9+
import logging
10+
import datetime
11+
from example_config import CONFIG_OBJ
12+
from fedex.services.availability_commitment_service import FedexAvailabilityCommitmentRequest
13+
14+
# Set this to the INFO level to see the response from Fedex printed in stdout.
15+
logging.basicConfig(level=logging.INFO)
16+
17+
18+
# This is the object that will be handling our service availability request.
19+
# We're using the FedexConfig object from example_config.py in this dir.
20+
customer_transaction_id = "*** AvailabilityAndCommitment Request v4 using Python ***" # Optional transaction_id
21+
avc_request = FedexAvailabilityCommitmentRequest(CONFIG_OBJ, customer_transaction_id=customer_transaction_id)
22+
23+
# Specify the origin postal code and country code. These fields are required.
24+
avc_request.Origin.PostalCode = '29631'
25+
avc_request.Origin.CountryCode = 'US'
26+
27+
# Specify the destination postal code and country code. These fields are required.
28+
avc_request.Destination.PostalCode = '27577'
29+
avc_request.Destination.CountryCode = 'US'
30+
31+
# Can be set to FEDEX_TUBE, YOUR_PACKAGING, FEDEX_BOX etc.. Defaults to YOUR_PACKAGING if not set.
32+
#avc_request.Packaging = 'FEDEX_ENVELOPE'
33+
34+
# Can be set to the expected date. Defaults to today if not set.
35+
#avc_request.ShipDate = datetime.date.today().isoformat()
36+
37+
# Can be set to PRIORITY_OVERNIGHT, FEDEX_2_DAY, STANDARD_OVERNIGHT etc.. Defaults to showing all options if not set.
38+
#avc_request.Service = 'FEDEX_2_DAY'
39+
40+
# Fires off the request, sets the 'response' attribute on the object.
41+
avc_request.send_request()
42+
43+
# If you'd like to see some documentation on the ship service WSDL, un-comment this line.
44+
print(avc_request.client)
45+
46+
# Un-comment this to see your complete, ready-to-send request as it stands
47+
# before it is actually sent. This is useful for seeing what values you can change.
48+
#print(avc_request.Origin)
49+
#print(avc_request.Destination)
50+
#print(avc_request.ShipDate)
51+
#print(avc_request.CarrierCode)
52+
#print(avc_request.Service)
53+
#print(avc_request.Packaging)
54+
55+
# This will show the reply to your avc_request being sent. You can access the
56+
# attributes through the response attribute on the request object. This is
57+
# good to un-comment to see the variables returned by the FedEx reply.
58+
print(avc_request.response)
59+
60+
# Here is the overall end result of the query.
61+
print("HighestSeverity: {}".format(avc_request.response.HighestSeverity))
62+
print("")
63+
64+
# Cycle through all the Notifications
65+
for notification in avc_request.response.Notifications:
66+
print("Notification:")
67+
print("Severity {} Source {}".format(notification.Severity, notification.Source))
68+
if hasattr(notification, 'Code'):
69+
print("Code {}".format(notification.Code))
70+
if hasattr(notification, 'Message'):
71+
print("Message {}".format(notification.Message))
72+
if hasattr(notification, 'LocalizedMessage'):
73+
print("LocalizedMessage {}".format(notification.LocalizedMessage))
74+
print("")
75+
76+
# Cycle through all the shipping options
77+
for option in avc_request.response.Options:
78+
print("Ship Option:")
79+
if hasattr(option, 'Service'):
80+
print("Service {}".format(option.Service))
81+
if hasattr(option, 'DeliveryDate'):
82+
print("DeliveryDate {}".format(option.DeliveryDate))
83+
if hasattr(option, 'DeliveryDay'):
84+
print("DeliveryDay {}".format(option.DeliveryDay))
85+
if hasattr(option, 'DestinationStationId'):
86+
print("DestinationStationId {}".format(option.DestinationStationId))
87+
if hasattr(option, 'DestinationAirportId'):
88+
print("DestinationAirportId {}".format(option.DestinationAirportId))
89+
if hasattr(option, 'TransitTime'):
90+
print("TransitTime {}".format(option.TransitTime))
91+
print("")

examples/track_shipment.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,31 @@
4343
# Fires off the request, sets the 'response' attribute on the object.
4444
track.send_request()
4545

46-
# See the response printed out.
46+
# This will show the reply to your track request being sent. You can access the
47+
# attributes through the response attribute on the request object. This is
48+
# good to un-comment to see the variables returned by the FedEx reply.
4749
print(track.response)
4850

4951
# Look through the matches (there should only be one for a tracking number
5052
# query), and show a few details about each shipment.
5153
print("== Results ==")
52-
#print(track.response)
5354
for match in track.response.CompletedTrackDetails[0].TrackDetails:
54-
print("Tracking #:", match.TrackingNumber)
55-
print("Tracking # UniqueID:", match.TrackingNumberUniqueIdentifier)
56-
print("Status:", match.StatusDetail.Description)
57-
print("Status AncillaryDetails Reason:", match.StatusDetail.AncillaryDetails[-1].Reason)
58-
print("Status AncillaryDetails Description:", match.StatusDetail.AncillaryDetails[-1].ReasonDescription)
59-
print("Commit Message:", match.ServiceCommitMessage)
55+
print("Tracking #: {}".format(match.TrackingNumber))
56+
print("Tracking # UniqueID: {}".format(match.TrackingNumberUniqueIdentifier))
57+
print("Status: {}".format(match.StatusDetail.Description))
58+
print("Status AncillaryDetails Reason: {}".format(match.StatusDetail.AncillaryDetails[-1].Reason))
59+
print("Status AncillaryDetails Description:{}".format(match.StatusDetail.AncillaryDetails[-1].ReasonDescription))
60+
print("Commit Message:{}".format(match.ServiceCommitMessage))
61+
print("")
62+
63+
event_details = []
64+
if hasattr(match, 'Events'):
65+
for j in range(len(match.Events)):
66+
event_match = match.Events[j]
67+
event_details.append({'created': event_match.Timestamp, 'type': event_match.EventType,
68+
'description': event_match.EventDescription})
69+
70+
if hasattr(event_match, 'StatusExceptionDescription'):
71+
event_details[j]['exception_description'] = event_match.StatusExceptionDescription
72+
73+
print("Event {}: {}".format(j+1, event_details[j]))

0 commit comments

Comments
 (0)