You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

256 lines
8.6 KiB

import datetime
import logging
import uuid
from functools import reduce
from decimal import Decimal
from django.conf import settings
from django.db import transaction
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from django.views.generic import ListView
from django.contrib import messages
from cart.models import Buying, Discount, Offer
from core.models import City
from core.views import ProtectedListView, ProtectedTemplateView, ProtectedView, ProtectedFormView, ProtectedBaseFormView
from .forms import (
CartRemoveBuyingForm,
DiscountForm,
CartAddInlineForm, CartCheckoutForm,
CartCheckoutBuyingForm)
logger = logging.getLogger(__name__)
class CartAddView(ProtectedBaseFormView):
http_method_names = ('post',)
form_class = CartAddInlineForm
def get_success_url(self):
return self.request.META.get('HTTP_REFERRER', reverse_lazy('products:product_list'))
def form_valid(self, form):
self.request.cart.add(offer_id=form.cleaned_data['offer'].product_id, quantity=form.cleaned_data['amount'])
return super().form_valid(form)
def form_invalid(self, form):
if form.errors:
for error in form.errors:
messages.error(self.request, error)
return HttpResponseRedirect(self.get_success_url())
class CartRemoveView(ProtectedBaseFormView):
http_method_names = ('post',)
model = Offer
form_class = CartRemoveBuyingForm
def get_success_url(self):
return self.request.META.get('HTTP_REFERRER', reverse_lazy('products:product_list'))
def form_valid(self, form):
self.request.cart.remove(form.cleaned_data['offer'].product_id)
return super().form_valid(form)
class CartView(ProtectedListView):
model = Offer
paginate_by = settings.DEFAULT_PAGE_AMOUNT
context_object_name = 'offer_items'
template_name = 'cart/cart.html'
ordering = '-create_at'
title = _('Корзина')
def get_queryset(self):
qs = super().get_queryset()
return qs.filter(product__id__in=self.request.cart.keys())
def get_total_price(self, object_list):
return reduce(
lambda initial, offer: initial + offer.price * Decimal(self.request.cart[offer.product_id]['quantity']),
object_list,
Decimal(0)
)
def get_total_cashback(self, object_list):
return reduce(
lambda initial, offer: initial + offer.cashback * Decimal(self.request.cart[offer.product_id]['quantity']),
object_list,
Decimal(0)
)
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=object_list, **kwargs)
context['title'] = self.title
context['total_price'] = self.get_total_price(self.object_list)
context['total_price_currency'] = context[
'total_cashback_currency'] = self.object_list.first().currency.sign if self.object_list.first() else ''
context['total_cashback'] = self.get_total_cashback(self.object_list)
return context
class CartCheckoutView(ProtectedFormView):
http_method_names = ('get', 'post',)
template_name = 'cart/checkout.html'
form_class = CartCheckoutForm
title = _('Оформление заказа')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['initial'] = {
'customer_name': self.request.user.profile.full_name,
'customer_email': self.request.user.email,
'phone': self.request.user.profile.phone,
'customer_address': self.request.user.profile.address,
'city': City.objects.filter(name=self.request.user.profile.city).first()
}
return kwargs
class CartConfirmView(ProtectedFormView):
http_method_names = ('post',)
template_name = 'cart/confirm.html'
form_class = CartCheckoutForm
title = _('Подтверждение заказа')
def get_total_price(self, offers):
return reduce(
lambda initial, offer: initial + offer.price * Decimal(self.request.cart[offer.product_id]['quantity']),
offers,
Decimal(0)
)
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
data = kwargs['data'].copy()
data.update({
'total_price': self.get_total_price(Offer.active.filter(product_id__in=self.request.cart.keys()))
})
kwargs['data'] = data
return kwargs
def form_valid(self, form):
if form.is_valid():
try:
with transaction.atomic():
form.save(self.request.user)
for item in self.request.cart:
buying_form = CartCheckoutBuyingForm(data={
'offer': Offer.active.get(pk=item),
'order': form.instance,
'bonus_points': 0, #@TODO: ADD BONUS PRODUCTS FOR AN ENTIRE PURCHASE
'amount': self.request.cart[item]['quantity']
})
buying_form.save(self.request.user)
form.send_order_invoice(self.request)
form.send_order_request(self.request)
self.request.cart.clear()
return self.render_to_response(self.get_context_data())
except Exception as e:
logger.critical(e)
return self.form_invalid(form)
def form_invalid(self, form):
for error in form.errors:
messages.error(self.request, error)
return HttpResponseRedirect(self.request.META['HTTP_REFERER'])
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = self.title
return context
class BuyingsHistory(ProtectedListView):
model = Buying
paginate_by = settings.DEFAULT_PAGE_AMOUNT
context_object_name = 'bought_item_list'
ordering = '-create_at'
template_name = 'cart/bought_history.html'
title = _('История покупок')
def get_queryset(self):
qs = super().get_queryset()
return qs.filter(user=self.request.user)
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=object_list, **kwargs)
context['title'] = self.title
return context
class DiscountListView(ListView):
template_name = 'cart/discount_list.html'
model = Discount
title = _('Акции / Cashback')
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=object_list, **kwargs)
context['title'] = self.title
return context
# Discount views # @TODO: TEST FOR PRODUCTION
class PointsApply(ProtectedTemplateView):
http_method_names = ('post',)
def dispatch(self, request, *args, **kwargs):
super().dispatch(request, *args, **kwargs)
self.request.session['points'] = True
return redirect('cart:buyings')
class PointsRevoke(ProtectedView):
http_method_names = ('post',)
def dispatch(self, request, *args, **kwargs):
super().dispatch(request, *args, **kwargs)
self.request.session.pop('points', None)
return redirect('cart:buyings')
class DiscountApply(ProtectedFormView):
http_method_names = ('post',)
form_class = DiscountForm
def form_valid(self, form):
now = datetime.now()
code = form.cleaned_data['code']
try:
discount = Discount.objects.get(code__iexact=code,
valid_from__lte=now,
valid_to__gte=now,
active=True)
self.request.session['discount_id'] = discount.id
except Discount.DoesNotExist:
self.request.session['discount_id'] = None
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('cart:buyings')
class CreateDiscount(ProtectedFormView):
http_method_names = ('post',)
form_class = DiscountForm
def form_valid(self, form):
now = datetime.now()
Discount.objects.update_or_create(
user=self.request.user,
defaults={'code': str(uuid.uuid4()),
'valid_from': now,
'valid_to': now + datetime.timedelta(days=7),
'active': True}
)
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('cabinet:index')