81 lines
2.9 KiB
Python
81 lines
2.9 KiB
Python
import logging
|
|
import json
|
|
import requests
|
|
import xmltodict
|
|
|
|
from lxml import etree
|
|
from django.conf import settings
|
|
|
|
from core import ShippingContainer
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class USPSApiError(Exception):
|
|
pass
|
|
|
|
|
|
class USPSApi:
|
|
BASE_URL = 'https://secure.shippingapis.com/ShippingAPI.dll?API='
|
|
urls = {
|
|
'validate': 'Verify&XML={xml}',
|
|
'rate': 'RateV4&XML={xml}'
|
|
}
|
|
|
|
def __init__(self, api_user_id, test=False):
|
|
self.api_user_id = api_user_id
|
|
self.test = test
|
|
|
|
def get_url(self, action, xml):
|
|
return self.BASE_URL + self.urls[action].format(
|
|
**{'test': 'Certify' if self.test else '', 'xml': xml}
|
|
)
|
|
|
|
def send_request(self, action, xml):
|
|
# The USPS developer guide says "ISO-8859-1 encoding is the expected character set for the request."
|
|
# (see https://www.usps.com/business/web-tools-apis/general-api-developer-guide.htm)
|
|
xml = etree.tostring(xml, encoding='iso-8859-1', pretty_print=self.test).decode()
|
|
url = self.get_url(action, xml)
|
|
xml_response = requests.get(url).content
|
|
response = json.loads(json.dumps(xmltodict.parse(xml_response)))
|
|
if 'Error' in response:
|
|
raise USPSApiError(response['Error']['Description'])
|
|
return response
|
|
|
|
def validate_address(self, *args, **kwargs):
|
|
return AddressValidate(self, *args, **kwargs)
|
|
|
|
def get_rate(self, *args, **kwargs):
|
|
return Rate(self, *args, **kwargs)
|
|
|
|
|
|
|
|
class AddressValidate:
|
|
def __init__(self, usps, address):
|
|
xml = etree.Element('AddressValidateRequest', {'USERID': usps.api_user_id})
|
|
_address = etree.SubElement(xml, 'Address', {'ID': '0'})
|
|
address.add_to_xml(_address, prefix='', validate=True)
|
|
|
|
self.result = usps.send_request('validate', xml)
|
|
|
|
|
|
class Rate:
|
|
def __init__(self, usps, request, **kwargs):
|
|
xml = etree.Element('RateV4Request', {'USERID': usps.api_user_id})
|
|
etree.SubElement(xml, 'Revision').text = '2'
|
|
package = etree.SubElement(xml, 'Package', {'ID': '0'})
|
|
etree.SubElement(package, 'Service').text = request['service']
|
|
etree.SubElement(package, 'ZipOrigination').text = request['zip_origination']
|
|
etree.SubElement(package, 'ZipDestination').text = request['zip_destination']
|
|
etree.SubElement(package, 'Pounds').text = request['pounds']
|
|
etree.SubElement(package, 'Ounces').text = request['ounces']
|
|
etree.SubElement(package, 'Container').text = request['container']
|
|
etree.SubElement(package, 'Width').text = request['width']
|
|
etree.SubElement(package, 'Length').text = request['length']
|
|
etree.SubElement(package, 'Height').text = request['height']
|
|
etree.SubElement(package, 'Girth').text = request['girth']
|
|
etree.SubElement(package, 'Machinable').text = request['machinable']
|
|
|
|
self.result = usps.send_request('rate', xml)
|