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)