Nathan Chapman adb3b73d5f Remove self
2022-05-14 07:32:59 -06:00

449 lines
15 KiB
Python

import logging
import requests
import json
from django.conf import settings
from django.utils import timezone
from django.shortcuts import render, reverse, redirect, get_object_or_404
from django.urls import reverse_lazy
from django.core.mail import EmailMessage
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
from django.http import JsonResponse, HttpResponseRedirect
from django.views.generic.base import RedirectView, TemplateView
from django.views.generic.edit import (
FormView, CreateView, UpdateView, DeleteView, FormMixin
)
from django.views.generic.detail import DetailView, SingleObjectMixin
from django.views.generic.list import ListView
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib import messages
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.forms.models import model_to_dict
from paypalcheckoutsdk.orders import OrdersCreateRequest, OrdersCaptureRequest
from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment
from accounts.models import User, Address
from accounts.utils import get_or_create_customer
from accounts.forms import (
AddressForm as AccountAddressForm, CustomerUpdateForm
)
from core.models import Product, Order, Transaction, OrderLine, Coupon
from core.forms import ShippingMethodForm
from core import OrderStatus
from .forms import (
AddToCartForm, UpdateCartItemForm, OrderCreateForm,
AddressForm, CouponApplyForm, ContactForm
)
from .cart import Cart
from .payments import CaptureOrder
logger = logging.getLogger(__name__)
class CartView(TemplateView):
template_name = 'storefront/cart_detail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
cart = Cart(self.request)
for item in cart:
for variation in item['variations'].values():
variation['update_quantity_form'] = UpdateCartItemForm(
initial={
'quantity': variation['quantity']
}
)
context['cart'] = cart
context['coupon_apply_form'] = CouponApplyForm()
return context
class CartAddProductView(SingleObjectMixin, FormView):
model = Product
form_class = AddToCartForm
def get_success_url(self):
return reverse('storefront:cart-detail')
def post(self, request, *args, **kwargs):
cart = Cart(request)
form = self.get_form()
if form.is_valid():
cart.add(
request=request,
product=self.get_object(),
grind=form.cleaned_data['grind'],
quantity=form.cleaned_data['quantity']
)
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
return super().form_valid(form)
class CartUpdateProductView(SingleObjectMixin, FormView):
model = Product
form_class = UpdateCartItemForm
def get_success_url(self):
return reverse('storefront:cart-detail')
def post(self, request, *args, **kwargs):
cart = Cart(request)
form = self.get_form()
if form.is_valid():
cart.add(
request=request,
product=self.get_object(),
grind=kwargs['grind'],
quantity=form.cleaned_data['quantity'],
update_quantity=form.cleaned_data['update']
)
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
return super().form_valid(form)
def cart_remove_product_view(request, pk, grind):
cart = Cart(request)
product = get_object_or_404(Product, id=pk)
cart.remove(product, grind)
return redirect('storefront:cart-detail')
class CouponApplyView(FormView):
template_name = 'contact.html'
form_class = CouponApplyForm
success_url = reverse_lazy('storefront:cart-detail')
def form_valid(self, form):
today = timezone.localtime(timezone.now()).date()
code = form.cleaned_data['code'].upper()
try:
coupon = Coupon.objects.get(
code__iexact=code,
valid_from__date__lte=today,
valid_to__date__gte=today
)
if coupon.is_valid:
self.request.session['coupon_code'] = coupon.code
except ObjectDoesNotExist:
self.request.session['coupon_code'] = None
return super().form_valid(form)
class ProductListView(FormMixin, ListView):
model = Product
template_name = 'storefront/product_list.html'
form_class = AddToCartForm
ordering = 'sorting'
queryset = Product.objects.filter(
visible_in_listings=True
)
class ProductDetailView(FormMixin, DetailView):
model = Product
template_name = 'storefront/product_detail.html'
form_class = AddToCartForm
class CheckoutAddressView(FormView):
template_name = 'storefront/checkout_address.html'
form_class = AddressForm
success_url = reverse_lazy('storefront:order-create')
def get_initial(self):
user = self.request.user
initial = None
if user.is_authenticated and user.default_shipping_address:
address = user.default_shipping_address
initial = {
'full_name': address.first_name+' '+address.last_name,
'email': user.email,
'street_address_1': address.street_address_1,
'street_address_2': address.street_address_2,
'city': address.city,
'state': address.state,
'postal_code': address.postal_code
}
elif self.request.session.get('shipping_address'):
address = self.request.session.get('shipping_address')
initial = {
'full_name': address['first_name']+' '+address['last_name'],
'email': address['email'],
'street_address_1': address['street_address_1'],
'street_address_2': address['street_address_2'],
'city': address['city'],
'state': address['state'],
'postal_code': address['postal_code']
}
return initial
def form_valid(self, form):
# save address data to session
cleaned_data = form.cleaned_data
first_name, last_name = form.process_full_name(
cleaned_data.get('full_name')
)
address = {
'first_name': first_name,
'last_name': last_name,
'email': cleaned_data['email'],
'street_address_1': cleaned_data['street_address_1'],
'street_address_2': cleaned_data['street_address_2'],
'city': cleaned_data['city'],
'state': cleaned_data['state'],
'postal_code': cleaned_data['postal_code']
}
self.request.session['shipping_address'] = address
return super().form_valid(form)
class OrderCreateView(CreateView):
model = Order
template_name = 'storefront/order_form.html'
form_class = OrderCreateForm
success_url = reverse_lazy('storefront:payment-done')
def get(self, request, *args, **kwargs):
if not self.request.session.get("shipping_address"):
messages.warning(request, 'Please add a shipping address.')
return HttpResponseRedirect(
reverse('storefront:checkout-address')
)
elif self.request.session.get('coupon_code'):
address = self.request.session.get("shipping_address")
coupon = Coupon.objects.get(
code=self.request.session.get('coupon_code')
)
try:
user = User.objects.get(email=address['email'])
except ObjectDoesNotExist:
user = None
if user in coupon.users.all():
del self.request.session['coupon_code']
messages.warning(request, 'Coupon already used.')
return super().get(request, *args, **kwargs)
def get_initial(self):
cart = Cart(self.request)
try:
shipping_cost = cart.get_shipping_cost()
except Exception as e:
raise e('Could not get shipping information')
shipping_cost = Decimal('0.00')
initial = {
'total_net_amount': cart.get_total_price(),
'shipping_total': shipping_cost
}
if self.request.session.get('shipping_address'):
a = self.request.session.get('shipping_address')
user_info = {
'email': a['email'],
'first_name': a['first_name'],
'last_name': a['last_name']
}
initial |= user_info
return initial
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['shipping_address'] = self.request.session.get('shipping_address')
context['PAYPAL_CLIENT_ID'] = settings.PAYPAL_CLIENT_ID
return context
def form_valid(self, form):
cart = Cart(self.request)
shipping_address = self.request.session.get('shipping_address')
form.instance.customer, form.instance.shipping_address = get_or_create_customer(self.request, form, shipping_address)
form.instance.status = OrderStatus.DRAFT
self.object = form.save()
bulk_list = cart.build_bulk_list(self.object)
objs = OrderLine.objects.bulk_create(bulk_list)
response = cart.create_order()
data = response.result.__dict__['_dict']
self.request.session['order_id'] = self.object.pk
return JsonResponse(data)
@csrf_exempt
@require_POST
def paypal_order_transaction_capture(request, transaction_id):
if request.method == "POST":
data = CaptureOrder().capture_order(transaction_id)
cart = Cart(request)
order = Order.objects.get(pk=request.session.get('order_id'))
order.status = OrderStatus.UNFULFILLED
try:
coupon = Coupon.objects.get(
code=request.session.get('coupon_code')
)
except ObjectDoesNotExist:
coupon = None
if coupon:
form.instance.coupon = coupon
coupon.users.add(form.instance.customer)
order.save()
transaction = Transaction.objects.get(order=order)
transaction.paypal_id = data['purchase_units'][0]['payments']['captures'][0]['id']
transaction.status = data['status']
transaction.save()
cart.clear()
logger.debug(f'\nPayPal Response data: {data}\n')
return JsonResponse(data)
else:
return JsonResponse({'details': 'invalid request'})
@csrf_exempt
@require_POST
def paypal_webhook_endpoint(request):
data = json.loads(request.body)
logger.info(data)
return JsonResponse(data)
class PaymentDoneView(TemplateView):
template_name = 'storefront/payment_done.html'
class PaymentCanceledView(TemplateView):
template_name = 'storefront/payment_canceled.html'
class CustomerDetailView(UserPassesTestMixin, LoginRequiredMixin, DetailView):
model = User
template_name = 'storefront/customer_detail.html'
context_object_name = 'customer'
permission_denied_message = 'Not authorized.'
raise_exception = True
def test_func(self):
return self.request.user.pk == self.get_object().pk
class CustomerUpdateView(UserPassesTestMixin, LoginRequiredMixin, UpdateView):
model = User
template_name = 'storefront/customer_form.html'
context_object_name = 'customer'
form_class = CustomerUpdateForm
permission_denied_message = 'Not authorized.'
raise_exception = True
def test_func(self):
return self.request.user.pk == self.get_object().pk
def get_success_url(self):
return reverse(
'storefront:customer-detail', kwargs={'pk': self.object.pk}
)
class OrderDetailView(UserPassesTestMixin, LoginRequiredMixin, DetailView):
model = Order
template_name = 'storefront/order_detail.html'
pk_url_kwarg = 'order_pk'
permission_denied_message = 'Not authorized.'
raise_exception = True
def test_func(self):
return self.request.user.pk == self.get_object().customer.pk
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['customer'] = User.objects.get(pk=self.kwargs['pk'])
return context
class CustomerAddressCreateView(
UserPassesTestMixin, LoginRequiredMixin, CreateView
):
model = Address
template_name = 'storefront/address_create_form.html'
form_class = AccountAddressForm
permission_denied_message = 'Not authorized.'
raise_exception = True
def test_func(self):
return self.request.user.pk == self.kwargs['pk']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['customer'] = User.objects.get(pk=self.kwargs['pk'])
return context
def form_valid(self, form):
customer = User.objects.get(pk=self.kwargs['pk'])
self.object = form.save()
customer.addresses.add(self.object)
return super().form_valid(form)
def get_success_url(self):
return reverse(
'storefront:customer-detail', kwargs={'pk': self.kwargs['pk']}
)
class CustomerAddressUpdateView(
UserPassesTestMixin, LoginRequiredMixin, UpdateView
):
model = Address
pk_url_kwarg = 'address_pk'
template_name = 'storefront/address_form.html'
form_class = AccountAddressForm
permission_denied_message = 'Not authorized.'
raise_exception = True
def test_func(self):
return self.request.user.pk == self.get_object().customer.pk
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['customer'] = User.objects.get(pk=self.kwargs['pk'])
return context
def get_success_url(self):
return reverse('storefront:customer-detail', kwargs={'pk': self.kwargs['pk']})
class AboutView(TemplateView):
template_name = 'storefront/about.html'
class FairTradeView(TemplateView):
template_name = 'storefront/fairtrade.html'
class ReviewListView(TemplateView):
template_name = 'storefront/reviews.html'
class ContactFormView(FormView, SuccessMessageMixin):
template_name = 'storefront/contact_form.html'
form_class = ContactForm
success_url = reverse_lazy('storefront:product-list')
def form_valid(self, form):
form.send_email()
return super().form_valid(form)