2022-04-05 10:04:24 -06:00

303 lines
10 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
from django.http import JsonResponse
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.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
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 .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:
item['update_quantity_form'] = UpdateCartItemForm(
initial={
'quantity': item['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(
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(
product=self.get_object(),
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):
cart = Cart(request)
product = get_object_or_404(Product, id=pk)
cart.remove(product)
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']
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 = {
'first_name': address.first_name,
'last_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
}
return initial
def form_valid(self, form):
# save address data to session
self.request.session['shipping_address'] = form.cleaned_data
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_initial(self):
cart = Cart(self.request)
initial = {
'coupon': cart.coupon,
'total_net_amount': cart.get_total_price()
}
if self.request.user.is_authenticated:
user_info = {
'email': self.request.user.email,
'first_name': self.request.user.first_name,
'last_name': self.request.user.last_name,
}
initial |= user_info
else:
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')
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)
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']
cart.clear()
self.request.session['order_id'] = self.object.pk
return JsonResponse(data)
def paypal_order_transaction_capture(request, transaction_id):
if request.method =="POST":
data = CaptureOrder().capture_order(transaction_id)
transaction = Transaction.objects.get(order__pk=request.session.get('order_id'))
transaction.paypal_id = data['purchase_units'][0]['payments']['captures'][0]['id']
transaction.status = data['status']
transaction.save()
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(LoginRequiredMixin, DetailView):
model = User
template_name = 'storefront/customer_detail.html'
context_object_name = 'customer'
class CustomerUpdateView(LoginRequiredMixin, UpdateView):
model = User
template_name = 'storefront/customer_form.html'
context_object_name = 'customer'
form_class = CustomerUpdateForm
def get_success_url(self):
return reverse('storefront:customer-detail', kwargs={'pk': self.object.pk})
class OrderDetailView(LoginRequiredMixin, DetailView):
model = Order
template_name = 'storefront/order_detail.html'
pk_url_kwarg = 'order_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 AddressUpdateView(LoginRequiredMixin, UpdateView):
model = Address
pk_url_kwarg = 'address_pk'
template_name = 'storefront/address_form.html'
form_class = AccountAddressForm
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 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)