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
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')
|
|
|