251 lines
7.5 KiB
Python
251 lines
7.5 KiB
Python
import logging
|
|
import json
|
|
import stripe
|
|
from requests import ConnectionError
|
|
from urllib.parse import quote
|
|
from django import forms
|
|
from django.conf import settings
|
|
from django.core.mail import EmailMessage
|
|
from django.core.exceptions import ValidationError
|
|
from localflavor.us.us_states import USPS_CHOICES
|
|
from core.usps import USPSApi, Address
|
|
from django_measurement.forms import MeasurementField
|
|
|
|
from core.models import (
|
|
Order, ProductVariant, Subscription, SiteSettings, WholesaleOrder
|
|
)
|
|
from core import CoffeeGrind, ShippingContainer
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
class SplitWidget(forms.MultiWidget):
|
|
def decompress(self, value):
|
|
if value:
|
|
return [value[0], value[1]]
|
|
return [0, 0]
|
|
|
|
def value_from_datadict(self, data, files, name):
|
|
sixteen, five = super().value_from_datadict(data, files, name)
|
|
return [sixteen, five]
|
|
|
|
|
|
|
|
class VariantChoiceField(forms.ModelChoiceField):
|
|
def label_from_instance(self, obj):
|
|
return f'{obj.name} | ${obj.price}'
|
|
|
|
|
|
class AddToCartForm(forms.Form):
|
|
quantity = forms.IntegerField(min_value=1, max_value=20, initial=1)
|
|
|
|
def __init__(self, variants, options, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.fields['variant'] = VariantChoiceField(
|
|
queryset=variants,
|
|
widget=forms.RadioSelect,
|
|
label=''
|
|
)
|
|
|
|
for option in options:
|
|
self.fields[option.name] = forms.ChoiceField(
|
|
choices=[(opt, opt) for opt in option.options]
|
|
)
|
|
|
|
|
|
class CartItemUpdateForm(forms.Form):
|
|
item_index = forms.IntegerField(widget=forms.HiddenInput())
|
|
quantity = forms.IntegerField(min_value=1, max_value=20, initial=1)
|
|
|
|
|
|
class AddressForm(forms.Form):
|
|
full_name = forms.CharField()
|
|
email = forms.EmailField()
|
|
street_address_1 = forms.CharField()
|
|
street_address_2 = forms.CharField(required=False)
|
|
city = forms.CharField()
|
|
state = forms.ChoiceField(
|
|
choices=USPS_CHOICES
|
|
)
|
|
postal_code = forms.CharField()
|
|
|
|
def process_full_name(self, full_name):
|
|
name = full_name.split()
|
|
|
|
if len(name) > 2:
|
|
last_name = ''.join(name.pop(-1))
|
|
first_name = ' '.join(name)
|
|
elif len(name) > 1:
|
|
first_name = name[0]
|
|
last_name = name[1]
|
|
else:
|
|
first_name = name[0]
|
|
last_name = ''
|
|
|
|
return first_name, last_name
|
|
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
address = Address(
|
|
name=quote(cleaned_data.get('full_name')),
|
|
address_1=quote(cleaned_data.get('street_address_1')),
|
|
address_2=quote(cleaned_data.get('street_address_2')),
|
|
city=quote(cleaned_data.get('city')),
|
|
state=quote(cleaned_data.get('state')),
|
|
zipcode=quote(cleaned_data.get('postal_code'))
|
|
)
|
|
usps = USPSApi(SiteSettings.load().usps_user_id)
|
|
|
|
try:
|
|
validation = usps.validate_address(address)
|
|
except ConnectionError:
|
|
raise ValidationError(
|
|
'Could not connect to USPS, try again.'
|
|
)
|
|
|
|
if 'Error' in validation.result['AddressValidateResponse']['Address']:
|
|
error = validation.result['AddressValidateResponse']['Address']['Error']['Description']
|
|
raise ValidationError(
|
|
"USPS: " + error
|
|
)
|
|
|
|
try:
|
|
cleaned_data['postal_code'] = validation.result['AddressValidateResponse']['Address']['Zip5']
|
|
except KeyError:
|
|
raise ValidationError(
|
|
'Could not find Zip5'
|
|
)
|
|
|
|
|
|
class CheckoutShippingForm(forms.Form):
|
|
def __init__(self, containers, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.fields['shipping_method'] = forms.ChoiceField(
|
|
label='',
|
|
widget=forms.RadioSelect,
|
|
choices=[(container.pk, f'{container.name} ${container.s_cost}') for container in containers]
|
|
)
|
|
|
|
|
|
class OrderCreateForm(forms.ModelForm):
|
|
class Meta:
|
|
model = Order
|
|
fields = []
|
|
|
|
|
|
class CouponApplyForm(forms.Form):
|
|
code = forms.CharField(label='Coupon code')
|
|
|
|
|
|
class SubscriptionForm(forms.Form):
|
|
GRIND_CHOICES = [
|
|
('Whole Beans', 'Whole Beans'),
|
|
('Espresso', 'Espresso'),
|
|
('Cone Drip', 'Cone Drip'),
|
|
('Basket Drip', 'Basket Drip'),
|
|
('French Press', 'French Press'),
|
|
('Stovetop Espresso (Moka Pot)', 'Stovetop Espresso (Moka Pot)'),
|
|
('AeroPress', 'AeroPress'),
|
|
('Percolator', 'Percolator'),
|
|
('BLTC cafe pour over', 'BLTC cafe pour over')
|
|
]
|
|
grind = forms.ChoiceField(choices=GRIND_CHOICES, label='')
|
|
products_and_quantities = forms.CharField(widget=forms.HiddenInput())
|
|
stripe_price_id = forms.CharField(widget=forms.HiddenInput())
|
|
total_quantity = forms.IntegerField(widget=forms.HiddenInput())
|
|
total_weight = forms.CharField(widget=forms.HiddenInput())
|
|
|
|
|
|
class WholesaleOrderCreateForm(forms.ModelForm):
|
|
class Meta:
|
|
model = WholesaleOrder
|
|
fields = [
|
|
"brazil",
|
|
"dantes_tornado",
|
|
"decaf",
|
|
"ethiopia",
|
|
"loop_d_loop",
|
|
"moka_java",
|
|
"nicaragua",
|
|
"pantomime",
|
|
"sumatra",
|
|
]
|
|
widgets = {
|
|
"brazil": SplitWidget(widgets={
|
|
"16": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
"5": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
}),
|
|
"dantes_tornado": SplitWidget(widgets={
|
|
"16": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
"5": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
}),
|
|
"decaf": SplitWidget(widgets={
|
|
"16": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
"5": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
}),
|
|
"ethiopia": SplitWidget(widgets={
|
|
"16": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
"5": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
}),
|
|
"loop_d_loop": SplitWidget(widgets={
|
|
"16": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
"5": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
}),
|
|
"moka_java": SplitWidget(widgets={
|
|
"16": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
"5": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
}),
|
|
"nicaragua": SplitWidget(widgets={
|
|
"16": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
"5": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
}),
|
|
"pantomime": SplitWidget(widgets={
|
|
"16": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
"5": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
}),
|
|
"sumatra": SplitWidget(widgets={
|
|
"16": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
"5": forms.NumberInput(attrs={
|
|
"size": 5
|
|
}),
|
|
}),
|
|
}
|
|
|