Write own usps library
This commit is contained in:
parent
7d0606143d
commit
4b31688c25
@ -56,7 +56,7 @@ def get_shipping_cost(total_weight, postal_code):
|
|||||||
str(total_weight.lb), container, str(postal_code)
|
str(total_weight.lb), container, str(postal_code)
|
||||||
)
|
)
|
||||||
|
|
||||||
usps = USPSApi(SiteSettings.load().usps_user_id, test=settings.DEBUG)
|
usps = USPSApi(SiteSettings.load().usps_user_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
validation = usps.get_rate(usps_rate_request)
|
validation = usps.get_rate(usps_rate_request)
|
||||||
|
|||||||
41
core/usps.py
41
core/usps.py
@ -1,41 +0,0 @@
|
|||||||
import json
|
|
||||||
import requests
|
|
||||||
import xmltodict
|
|
||||||
|
|
||||||
from lxml import etree
|
|
||||||
from usps import USPSApi as USPSApiBase
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from . import ShippingContainer
|
|
||||||
|
|
||||||
|
|
||||||
class USPSApi(USPSApiBase):
|
|
||||||
urls = {
|
|
||||||
'tracking': 'TrackV2{test}&XML={xml}',
|
|
||||||
'label': 'eVS{test}&XML={xml}',
|
|
||||||
'validate': 'Verify&XML={xml}',
|
|
||||||
'rate': 'RateV4&XML={xml}',
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_rate(self, *args, **kwargs):
|
|
||||||
return Rate(self, *args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
2
core/usps/__init__.py
Normal file
2
core/usps/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .address import Address
|
||||||
|
from .usps import USPSApi, USPSApiError
|
||||||
56
core/usps/address.py
Normal file
56
core/usps/address.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
from lxml import etree
|
||||||
|
|
||||||
|
|
||||||
|
class Address(object):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name,
|
||||||
|
address_1,
|
||||||
|
city,
|
||||||
|
state,
|
||||||
|
zipcode,
|
||||||
|
zipcode_ext='',
|
||||||
|
company='',
|
||||||
|
address_2='',
|
||||||
|
phone=''
|
||||||
|
):
|
||||||
|
self.name = name
|
||||||
|
self.company = company
|
||||||
|
self.address_1 = address_1
|
||||||
|
self.address_2 = address_2
|
||||||
|
self.city = city
|
||||||
|
self.state = state
|
||||||
|
self.zipcode = zipcode
|
||||||
|
self.zipcode_ext = zipcode_ext
|
||||||
|
self.phone = phone
|
||||||
|
|
||||||
|
def add_to_xml(self, root, prefix='To', validate=False):
|
||||||
|
if not validate:
|
||||||
|
name = etree.SubElement(root, prefix + 'Name')
|
||||||
|
name.text = self.name
|
||||||
|
|
||||||
|
company = etree.SubElement(root, prefix + 'Firm' + ('Name' if validate else ''))
|
||||||
|
company.text = self.company
|
||||||
|
|
||||||
|
address_1 = etree.SubElement(root, prefix + 'Address1')
|
||||||
|
address_1.text = self.address_1
|
||||||
|
|
||||||
|
address_2 = etree.SubElement(root, prefix + 'Address2')
|
||||||
|
address_2.text = self.address_2 or '-'
|
||||||
|
|
||||||
|
city = etree.SubElement(root, prefix + 'City')
|
||||||
|
city.text = self.city
|
||||||
|
|
||||||
|
state = etree.SubElement(root, prefix + 'State')
|
||||||
|
state.text = self.state
|
||||||
|
|
||||||
|
zipcode = etree.SubElement(root, prefix + 'Zip5')
|
||||||
|
zipcode.text = self.zipcode
|
||||||
|
|
||||||
|
zipcode_ext = etree.SubElement(root, prefix + 'Zip4')
|
||||||
|
zipcode_ext.text = self.zipcode_ext
|
||||||
|
|
||||||
|
if not validate:
|
||||||
|
phone = etree.SubElement(root, prefix + 'Phone')
|
||||||
|
phone.text = self.phone
|
||||||
80
core/usps/usps.py
Normal file
80
core/usps/usps.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
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)
|
||||||
1327
poetry.lock
generated
1327
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,6 @@ django-templated-email = "^3.0.1"
|
|||||||
paypal-checkout-serversdk = "^1.0.1"
|
paypal-checkout-serversdk = "^1.0.1"
|
||||||
pillow = "^9.4.0"
|
pillow = "^9.4.0"
|
||||||
redis = "^4.4.0"
|
redis = "^4.4.0"
|
||||||
usps-api = "^0.5"
|
|
||||||
psycopg2-binary = "^2.9.5"
|
psycopg2-binary = "^2.9.5"
|
||||||
gunicorn = "^20.1.0"
|
gunicorn = "^20.1.0"
|
||||||
sentry-sdk = "^1.12.1"
|
sentry-sdk = "^1.12.1"
|
||||||
@ -31,6 +30,8 @@ environs = "^9.5.0"
|
|||||||
python-dotenv = "^0.21.0"
|
python-dotenv = "^0.21.0"
|
||||||
py-moneyed = "^3.0"
|
py-moneyed = "^3.0"
|
||||||
django-simple-captcha = "^0.5.17"
|
django-simple-captcha = "^0.5.17"
|
||||||
|
lxml = "^4.9.3"
|
||||||
|
xmltodict = "^0.13.0"
|
||||||
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
|
|||||||
@ -265,7 +265,7 @@ class Cart:
|
|||||||
str(self.session.get('shipping_address')['postal_code'])
|
str(self.session.get('shipping_address')['postal_code'])
|
||||||
)
|
)
|
||||||
|
|
||||||
usps = USPSApi(self.site_settings.usps_user_id, test=settings.DEBUG)
|
usps = USPSApi(self.site_settings.usps_user_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
validation = usps.get_rate(usps_rate_request)
|
validation = usps.get_rate(usps_rate_request)
|
||||||
|
|||||||
@ -8,7 +8,7 @@ from django.conf import settings
|
|||||||
from django.core.mail import EmailMessage
|
from django.core.mail import EmailMessage
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from localflavor.us.us_states import USPS_CHOICES
|
from localflavor.us.us_states import USPS_CHOICES
|
||||||
from usps import USPSApi, Address
|
from core.usps import USPSApi, Address
|
||||||
from django_measurement.forms import MeasurementField
|
from django_measurement.forms import MeasurementField
|
||||||
|
|
||||||
from core.models import (
|
from core.models import (
|
||||||
@ -96,7 +96,7 @@ class AddressForm(forms.Form):
|
|||||||
state=quote(cleaned_data.get('state')),
|
state=quote(cleaned_data.get('state')),
|
||||||
zipcode=quote(cleaned_data.get('postal_code'))
|
zipcode=quote(cleaned_data.get('postal_code'))
|
||||||
)
|
)
|
||||||
usps = USPSApi(SiteSettings.load().usps_user_id, test=True)
|
usps = USPSApi(SiteSettings.load().usps_user_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
validation = usps.validate_address(address)
|
validation = usps.validate_address(address)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user