Skip to content

Commit 4e42403

Browse files
committed
added avc service tests and examples
1 parent 2900950 commit 4e42403

File tree

3 files changed

+112
-140
lines changed

3 files changed

+112
-140
lines changed
Lines changed: 66 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,91 @@
11
#!/usr/bin/env python
22
"""
3-
This example shows how to use the FedEx RateRequest service.
4-
The variables populated below represents the minimum required values.
5-
You will need to fill all of these, or risk seeing a SchemaValidationError
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
67
exception thrown by suds.
7-
8-
TIP: Near the bottom of the module, see how to check the if the destination
9-
is Out of Delivery Area (ODA).
108
"""
119
import logging
10+
import datetime
1211
from example_config import CONFIG_OBJ
13-
from fedex.services.rate_service import FedexRateServiceRequest
12+
from fedex.services.availability_commitment_service import FedexAvailabilityCommitmentRequest
1413

1514
# Set this to the INFO level to see the response from Fedex printed in stdout.
1615
logging.basicConfig(level=logging.INFO)
1716

1817

19-
# This is the object that will be handling our tracking request.
18+
# This is the object that will be handling our service availability request.
2019
# We're using the FedexConfig object from example_config.py in this dir.
21-
customer_transaction_id = "*** RateService Request v18 using Python ***" # Optional transaction_id
22-
rate_request = FedexRateServiceRequest(CONFIG_OBJ, customer_transaction_id=customer_transaction_id)
23-
24-
# If you wish to have transit data returned with your request you
25-
# need to uncomment the following
26-
# rate_request.ReturnTransitAndCommit = True
27-
28-
# This is very generalized, top-level information.
29-
# REGULAR_PICKUP, REQUEST_COURIER, DROP_BOX, BUSINESS_SERVICE_CENTER or STATION
30-
rate_request.RequestedShipment.DropoffType = 'REGULAR_PICKUP'
20+
customer_transaction_id = "*** AvailabilityAndCommitment Request v4 using Python ***" # Optional transaction_id
21+
avc_request = FedexAvailabilityCommitmentRequest(CONFIG_OBJ, customer_transaction_id=customer_transaction_id)
3122

32-
# See page 355 in WS_ShipService.pdf for a full list. Here are the common ones:
33-
# STANDARD_OVERNIGHT, PRIORITY_OVERNIGHT, FEDEX_GROUND, FEDEX_EXPRESS_SAVER
34-
# To receive rates for multiple ServiceTypes set to None.
35-
rate_request.RequestedShipment.ServiceType = 'FEDEX_GROUND'
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'
3626

37-
# What kind of package this will be shipped in.
38-
# FEDEX_BOX, FEDEX_PAK, FEDEX_TUBE, YOUR_PACKAGING
39-
rate_request.RequestedShipment.PackagingType = 'YOUR_PACKAGING'
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'
4030

41-
# Shipper's address
42-
rate_request.RequestedShipment.Shipper.Address.PostalCode = '29631'
43-
rate_request.RequestedShipment.Shipper.Address.CountryCode = 'US'
44-
rate_request.RequestedShipment.Shipper.Address.Residential = False
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'
4533

46-
# Recipient address
47-
rate_request.RequestedShipment.Recipient.Address.PostalCode = '27577'
48-
rate_request.RequestedShipment.Recipient.Address.CountryCode = 'US'
49-
# This is needed to ensure an accurate rate quote with the response.
50-
#rate_request.RequestedShipment.Recipient.Address.Residential = True
51-
#include estimated duties and taxes in rate quote, can be ALL or NONE
52-
rate_request.RequestedShipment.EdtRequestType = 'NONE'
34+
# Can be set to the expected date. Defaults to today if not set.
35+
#avc_request.ShipDate = datetime.date.today().isoformat()
5336

54-
# Who pays for the rate_request?
55-
# RECIPIENT, SENDER or THIRD_PARTY
56-
rate_request.RequestedShipment.ShippingChargesPayment.PaymentType = 'SENDER'
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'
5739

58-
package1_weight = rate_request.create_wsdl_object_of_type('Weight')
59-
# Weight, in LB.
60-
package1_weight.Value = 1.0
61-
package1_weight.Units = "LB"
62-
63-
package1 = rate_request.create_wsdl_object_of_type('RequestedPackageLineItem')
64-
package1.Weight = package1_weight
65-
#can be other values this is probably the most common
66-
package1.PhysicalPackaging = 'BOX'
67-
# Required, but according to FedEx docs:
68-
# "Used only with PACKAGE_GROUPS, as a count of packages within a
69-
# group of identical packages". In practice you can use this to get rates
70-
# for a shipment with multiple packages of an identical package size/weight
71-
# on rate request without creating multiple RequestedPackageLineItem elements.
72-
# You can OPTIONALLY specify a package group:
73-
# package1.GroupNumber = 0 # default is 0
74-
# The result will be found in RatedPackageDetail, with specified GroupNumber.
75-
package1.GroupPackageCount = 1
76-
# Un-comment this to see the other variables you may set on a package.
77-
#print(package1)
78-
79-
# This adds the RequestedPackageLineItem WSDL object to the rate_request. It
80-
# increments the package count and total weight of the rate_request for you.
81-
rate_request.add_package(package1)
40+
# Fires off the request, sets the 'response' attribute on the object.
41+
avc_request.send_request()
8242

83-
# If you'd like to see some documentation on the ship service WSDL, un-comment
84-
# this line. (Spammy).
85-
#print(rate_request.client)
43+
# If you'd like to see some documentation on the ship service WSDL, un-comment this line.
44+
print(avc_request.client)
8645

8746
# Un-comment this to see your complete, ready-to-send request as it stands
88-
# before it is actually sent. This is useful for seeing what values you can
89-
# change.
90-
#print(rate_request.RequestedShipment)
91-
92-
# Fires off the request, sets the 'response' attribute on the object.
93-
rate_request.send_request()
94-
95-
# This will show the reply to your rate_request being sent. You can access the
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
9656
# attributes through the response attribute on the request object. This is
9757
# good to un-comment to see the variables returned by the FedEx reply.
98-
#print(rate_request.response)
58+
#print(avc_request.response)
9959

10060
# Here is the overall end result of the query.
101-
print("HighestSeverity:", rate_request.response.HighestSeverity)
102-
103-
# RateReplyDetails can contain rates for multiple ServiceTypes if ServiceType was set to None
104-
for service in rate_request.response.RateReplyDetails:
105-
for detail in service.RatedShipmentDetails:
106-
for surcharge in detail.ShipmentRateDetail.Surcharges:
107-
if surcharge.SurchargeType == 'OUT_OF_DELIVERY_AREA':
108-
print("%s: ODA rate_request charge %s" % (service.ServiceType, surcharge.Amount.Amount))
109-
110-
for rate_detail in service.RatedShipmentDetails:
111-
print("%s: Net FedEx Charge %s %s" % (service.ServiceType,
112-
rate_detail.ShipmentRateDetail.TotalNetFedExCharge.Currency,
113-
rate_detail.ShipmentRateDetail.TotalNetFedExCharge.Amount))
114-
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("")
Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
"""
2-
Address Validation Service Module
2+
Service Availability and Commitment Module
33
=================================
44
This package contains the shipping methods defined by Fedex's
5-
AddressValidationService WSDL file. Each is encapsulated in a class for
5+
ValidationAvailabilityAndCommitmentService WSDL file. Each is encapsulated in a class for
66
easy access. For more details on each, refer to the respective class's
77
documentation.
88
"""
99

10-
from datetime import datetime
10+
import datetime
1111
from .. base_service import FedexBaseService
1212

1313

14-
class FedexAddressValidationRequest(FedexBaseService):
14+
class FedexAvailabilityCommitmentRequest(FedexBaseService):
1515
"""
16-
This class allows you validate anywhere from one to a hundred addresses
17-
in one go. Create AddressToValidate WSDL objects and add them to each
18-
instance of this request using add_address().
16+
This class allows you validate service availability
1917
"""
2018

2119
def __init__(self, config_obj, *args, **kwargs):
@@ -27,26 +25,41 @@ def __init__(self, config_obj, *args, **kwargs):
2725
self._config_obj = config_obj
2826
# Holds version info for the VersionId SOAP object.
2927
self._version_info = {
30-
'service_id': 'aval',
28+
'service_id': 'vacs',
3129
'major': '4',
3230
'intermediate': '0',
3331
'minor': '0'
3432
}
35-
36-
# self.AddressValidationOptions = None
37-
"""@ivar: Holds the AddressValidationOptions WSDL object."""
38-
self.AddressesToValidate = []
39-
"""@ivar: Holds the AddressToValidate WSDL object."""
33+
34+
"""ivar: Carrier Code Default to Fedex (FDXE), or can bbe FDXG."""
35+
self.CarrierCode = None
36+
37+
"""@ivar: Holds Addresses and Ship Date objects."""
38+
self.Origin = self.Destination = None
39+
self.ShipDate = None
40+
41+
"""@ivar: Holds the ValidationAvailabilityAndCommitmentService WSDL object."""
4042
# Call the parent FedexBaseService class for basic setup work.
41-
super(FedexAddressValidationRequest, self).__init__(
42-
self._config_obj, 'AddressValidationService_v4.wsdl', *args, **kwargs)
43+
# Shortened the name of the wsdl, otherwise suds did not load it properly.
44+
# Suds throws the following error when using the long file name from FedEx:
45+
#
46+
# File "/Library/Python/2.7/site-packages/suds/wsdl.py", line 878, in resolve
47+
# raise Exception("binding '%s', not-found" % p.binding)
48+
# Exception: binding 'ns:ValidationAvailabilityAndCommitmentServiceSoapBinding', not-found
49+
50+
super(FedexAvailabilityCommitmentRequest, self).__init__(
51+
self._config_obj, 'AvailabilityAndCommitmentService_v4.wsdl', *args, **kwargs)
4352

4453
def _prepare_wsdl_objects(self):
4554
"""
4655
Create the data structure and get it ready for the WSDL request.
4756
"""
48-
pass
49-
57+
self.CarrierCode = 'FDXE'
58+
self.Origin = self.Destination = self.client.factory.create('Address')
59+
self.ShipDate = datetime.date.today().isoformat()
60+
self.Service = None
61+
self.Packaging = 'YOUR_PACKAGING'
62+
5063
def _assemble_and_send_request(self):
5164
"""
5265
Fires off the Fedex request.
@@ -64,23 +77,14 @@ def _assemble_and_send_request(self):
6477
self.logger.debug(self.TransactionDetail)
6578
self.logger.debug(self.VersionId)
6679
# Fire off the query.
67-
return self.client.service.addressValidation(
80+
return self.client.service.serviceAvailability(
6881
WebAuthenticationDetail=self.WebAuthenticationDetail,
6982
ClientDetail=self.ClientDetail,
7083
TransactionDetail=self.TransactionDetail,
7184
Version=self.VersionId,
72-
InEffectAsOfTimestamp=datetime.now(),
73-
AddressesToValidate=self.AddressesToValidate)
74-
75-
def add_address(self, address_item):
76-
"""
77-
Adds an address to self.AddressesToValidate.
78-
79-
@type address_item: WSDL object, type of AddressToValidate WSDL object.
80-
@keyword address_item: A AddressToValidate, created by
81-
calling create_wsdl_object_of_type('AddressToValidate') on
82-
this FedexAddressValidationRequest object.
83-
See examples/create_shipment.py for more details.
84-
"""
85-
86-
self.AddressesToValidate.append(address_item)
85+
Origin=self.Origin,
86+
Destination=self.Destination,
87+
ShipDate=self.ShipDate,
88+
CarrierCode=self.CarrierCode,
89+
Service=self.Service,
90+
Packaging=self.Packaging)

tests/test_availability_commitment_service.py

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,32 @@
66

77
import sys
88
sys.path.insert(0, '..')
9-
from fedex.services.track_service import FedexTrackRequest
9+
from fedex.services.availability_commitment_service import FedexAvailabilityCommitmentRequest
1010

1111
# Common global config object for testing.
1212
from common import get_test_config
1313
CONFIG_OBJ = get_test_config()
1414

1515

16-
class TrackServiceTests(unittest.TestCase):
16+
class AvailabilityCommitmentServiceTests(unittest.TestCase):
1717
"""
1818
These tests verify that the shipping service WSDL is in good shape.
1919
"""
2020
def test_track(self):
2121
# Test shipment tracking. Query for a tracking number and make sure the
2222
# first (and hopefully only) result matches up.
2323

24-
tracking_num = '781820562774'
24+
avc_request = FedexAvailabilityCommitmentRequest(CONFIG_OBJ)
2525

26-
track = FedexTrackRequest(CONFIG_OBJ)
26+
avc_request.Origin.PostalCode = 'M5V 3A4'
27+
avc_request.Origin.CountryCode = 'CA'
2728

28-
# Track by Tracking Number
29-
track.SelectionDetails.PackageIdentifier.Type = 'TRACKING_NUMBER_OR_DOORTAG'
30-
track.SelectionDetails.PackageIdentifier.Value = tracking_num
29+
avc_request.Origin.PostalCode = '27577' # 29631
30+
avc_request.Origin.CountryCode = 'US'
3131

32-
# FedEx operating company or delete
33-
del track.SelectionDetails.OperatingCompany
32+
avc_request.send_request()
33+
assert avc_request.response
3434

35-
track.send_request()
36-
37-
assert track.response
38-
39-
# Uncomment below if testing in production with a valid tracking number
40-
# for match in track.response.CompletedTrackDetails[0].TrackDetails:
41-
# # This should be the same tracking number on the response that we
42-
# # asked for in the request.
43-
# assert match.TrackingNumber == tracking_num
4435

4536

4637
if __name__ == "__main__":

0 commit comments

Comments
 (0)