From 80011eebb8aa8b60c1effa844f4a48af21e2efcc Mon Sep 17 00:00:00 2001 From: Max Yakovenko Date: Thu, 26 Jul 2018 00:44:01 +0300 Subject: [PATCH] add cart app and its templates --- cart/__init__.py | 0 cart/admin.py | 3 ++ cart/apps.py | 5 ++ cart/cart.py | 87 ++++++++++++++++++++++++++++++ cart/context_processors.py | 6 +++ cart/forms.py | 21 ++++++++ cart/models.py | 59 ++++++++++++++++++++ cart/tests.py | 3 ++ cart/urls.py | 12 +++++ cart/views.py | 60 +++++++++++++++++++++ templates/cart/buying_history.html | 4 ++ 11 files changed, 260 insertions(+) create mode 100644 cart/__init__.py create mode 100644 cart/admin.py create mode 100644 cart/apps.py create mode 100644 cart/cart.py create mode 100644 cart/context_processors.py create mode 100644 cart/forms.py create mode 100644 cart/models.py create mode 100644 cart/tests.py create mode 100644 cart/urls.py create mode 100644 cart/views.py create mode 100644 templates/cart/buying_history.html diff --git a/cart/__init__.py b/cart/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cart/admin.py b/cart/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/cart/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/cart/apps.py b/cart/apps.py new file mode 100644 index 0000000..7cc6ec1 --- /dev/null +++ b/cart/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CartConfig(AppConfig): + name = 'cart' diff --git a/cart/cart.py b/cart/cart.py new file mode 100644 index 0000000..bfb83fe --- /dev/null +++ b/cart/cart.py @@ -0,0 +1,87 @@ +from decimal import Decimal +from django.conf import settings +from django.contrib import auth +from products.models import Product +# from discount.models import Discount + +class Cart(object): + def __init__(self, request): + self.session = request.session + # self.discount_id = self.session.get('discount_id') + if request.user.is_authenticated(): + # self.points = self.session.get('points') + self.points_quant = auth.get_user(request).profile.user_points + cart = self.session.get(settings.CART_SESSION_ID) + if not cart: + request.session['points'] = False + cart = self.session[settings.CART_SESSION_ID] = {} + self.cart = cart + + def add(self, offer, price_per_itom, quantity=1, update_quantity=False): + offer_slug = offer.slug + if offer_slug not in self.cart: + self.cart[offer_slug] = {'quantity': 0, + 'price': str(price_per_itom)} + if update_quantity: + self.cart[offer_slug]['quantity'] = int(quantity) + else: + self.cart[offer_slug]['quantity'] += int(quantity) + self.save() + + def save(self): + self.session[settings.CART_SESSION_ID] = self.cart + self.session.modified = True + + def remove(self, offer_slug): + # product_id = str(products.id) + if offer_slug in self.cart: + del self.cart[offer_slug] + self.save() + + def __iter__(self): + offers_ids = self.cart.keys() + offers = Offer.objects.filter(slug__in=offers_ids) + + for offer in offers: + self.cart[str(offer.slug)]['offer'] = offer + + for item in self.cart.values(): + item['price'] = Decimal(item['price']) + item['total_price'] = item['price'] * item['quantity'] + yield item + + def __len__(self): + return sum(item['quantity'] for item in self.cart.values()) + + def get_total_price(self): + return sum(Decimal(item['price']) * item['quantity'] for item in self.cart.values()) + + def get_max(self): + return min(self.points_quant, self.get_total_price() - 1) + + def clear(self): + del self.session[settings.CART_SESSION_ID] + self.session.modified = True + + # @property + # def discount(self): + # if self.discount_id: + # return Discount.objects.get(id=self.discount_id) + # return None + + # def get_discount(self): + # if self.discount: + # return (self.discount.discount / Decimal('100')) * self.get_total_price() + # return Decimal('0') + + # def get_total_price_after_discount(self): + # return self.get_total_price() - self.get_discount() + + def get_total_deduct_points(self): + total_price = self.get_total_price() + if total_price <= self.points_quant: + # self.points_quant = self.points_quant - total_price + 1 + # self.save() + return 1 + return total_price - self.points_quant + diff --git a/cart/context_processors.py b/cart/context_processors.py new file mode 100644 index 0000000..c6dba27 --- /dev/null +++ b/cart/context_processors.py @@ -0,0 +1,6 @@ +from .cart import Cart + + +def cart(request): + return {'cart': Cart(request)} + diff --git a/cart/forms.py b/cart/forms.py new file mode 100644 index 0000000..f510932 --- /dev/null +++ b/cart/forms.py @@ -0,0 +1,21 @@ +from django import forms + +class CartAddProductForm(forms.Form): + quantity = forms.CharField(widget=forms.TextInput(attrs={ + 'id': 'quantity', + 'name': 'quantity', + 'type': 'number', + 'min': '1', + 'max': '1000', + 'value': '1', + 'onchange': 'calculate()'})) + product_slug = forms.CharField(widget=forms.TextInput(attrs={ + 'id': 'product_slug', + 'name': 'product_slug', + 'type': 'hidden'})) + price_per_itom = forms.IntegerField(widget=forms.TextInput(attrs={ + 'id': 'price_per_itom', + 'name': 'price_per_itom', + 'type': 'hidden'})) + update = forms.BooleanField(required=False, initial=False, widget=forms.HiddenInput) + diff --git a/cart/models.py b/cart/models.py new file mode 100644 index 0000000..f070cc4 --- /dev/null +++ b/cart/models.py @@ -0,0 +1,59 @@ +from django.db import models +from django.contrib.auth import get_user_model +from django.contrib.postgres.fields import HStoreField +from django.utils.translation import ugettext_lazy as _ + +from autoslug import AutoSlugField + +# Create your models here. +from core.models import AbstractStatusModel +from products.models import Product + +OFFER_STATUS_ACTIVE = 25 +OFFER_STATUS_INACTIVE = 50 + +OFFER_STATUS_CHOICES = ( + (OFFER_STATUS_ACTIVE, _('Активный')), + (OFFER_STATUS_INACTIVE, _('Неактивный')) +) + +OFFER_DEFAULT_CHOICE = OFFER_STATUS_INACTIVE + + +class Offer(AbstractStatusModel): + name = models.CharField(max_length=64, blank=True, null=True, default=None) + slug = AutoSlugField(populate_from='name') + price = models.DecimalField(max_digits=8, decimal_places=2, null=True, default=0.00) + product = models.ForeignKey(Product, on_delete=models.CASCADE, blank=True, null=True, default=None, + related_name='variants') + attributes = HStoreField(blank=True, null=True, default={}) + + status = models.SmallIntegerField(_('статус'), default=OFFER_DEFAULT_CHOICE, choices=OFFER_STATUS_CHOICES) + + def __str__(self): + return self.name + + class Meta: + verbose_name = _('Позиция') + verbose_name_plural = _('Позиции') + + +# ------------------------------------------ Buying status --------------------------------------------------- # +BUYING_STATUS_IN_CART = 25 +BUYING_STATUS_BOUGHT = 50 +BUYING_STATUS_CHOICES = ( + (BUYING_STATUS_IN_CART, _('В корзине')), + (BUYING_STATUS_BOUGHT, _('Куплен')) +) + +BUYING_DEFAULT_CHOICE = BUYING_STATUS_IN_CART + + +class Buying(AbstractStatusModel): + user = models.ForeignKey(get_user_model(),verbose_name=_('Пользователь'), on_delete=models.CASCADE, ) + offer = models.ForeignKey(Offer, verbose_name=_('Позиция'), on_delete=models.CASCADE) + status = models.SmallIntegerField(_('статус'), default=BUYING_DEFAULT_CHOICE, choices=BUYING_STATUS_CHOICES) + + class Meta: + verbose_name = _('Покупка') + verbose_name_plural = _('Покупки') diff --git a/cart/tests.py b/cart/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/cart/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/cart/urls.py b/cart/urls.py new file mode 100644 index 0000000..e7e8dd2 --- /dev/null +++ b/cart/urls.py @@ -0,0 +1,12 @@ +from django.conf.urls import url +from django.urls import re_path + +from . import views + +urlpatterns = [ + # url(r'^$', views.CartDetail, name='CartDetail'), + # url(r'^remove/(?P[-\w]+)/$', views.CartRemove, name='CartRemove'), + # url(r'^add/$', views.CartAdd, name='CartAdd'), + re_path(r'^buyings/history/', views.BuyingsHistory.as_view(), name='buyings_history') + +] diff --git a/cart/views.py b/cart/views.py new file mode 100644 index 0000000..19db9b8 --- /dev/null +++ b/cart/views.py @@ -0,0 +1,60 @@ +from django.shortcuts import render, redirect, get_object_or_404 +from django.views.decorators.http import require_POST +from django.views.decorators.csrf import csrf_exempt +from django.contrib.auth.decorators import login_required +from django.contrib import auth +from django.views.generic import ListView + +from cart.models import Buying +from core.views import ProtectedView + +from .cart import Cart +from .forms import CartAddProductForm +# from discount.layout import DiscountApllyForm + +# @csrf_exempt +# @require_POST +# @login_required(login_url='accounts_ext:accounts_ext') +# def CartAdd(request): +# cart = Cart(request) +# form = CartAddProductForm(request.POST) +# if form.is_valid(): +# cd = form.cleaned_data +# if int(cd['quantity']) < 1 or int(cd['quantity']) > 1000: +# return redirect(request.META.get('HTTP_REFERER')) +# offer = get_object_or_404(Offer, slug=cd['product_slug']) +# cart.add(offer=offer, price_per_itom=cd['price_per_itom'], quantity=cd['quantity'], +# update_quantity=cd['update']) +# request.session.pop('points', None) +# return redirect('cart:CartDetail') +# +# @csrf_exempt +# @login_required(login_url='accounts_ext:accounts_ext') +# def CartRemove(request, offer_slug): +# cart = Cart(request) +# # offer = get_object_or_404(Offer, slug=offer_slug) +# cart.remove(offer_slug) +# request.session.pop('points', None) +# return redirect('cart:CartDetail') +# +# @csrf_exempt +# @login_required(login_url='accounts_ext:accounts_ext') +# def CartDetail(request): +# user = auth.get_user(request) +# cart = Cart(request) +# for item in cart: +# item['update_quantity_form'] = CartAddProductForm( +# initial={ +# 'quantity': item['quantity'], +# 'product_slug': item['offer'].slug, +# 'price_per_itom': item['price'], +# 'update': True +# }) +# # discount_apply_form = DiscountApllyForm() +# return render(request, 'cart/detail.html', {'username': user.username}) +# # 'discount_apply_form': discount_apply_form}) + + +class BuyingsHistory(ProtectedView,ListView): + model = Buying + template_name = 'cart/buying_history.html' diff --git a/templates/cart/buying_history.html b/templates/cart/buying_history.html new file mode 100644 index 0000000..4e78f8b --- /dev/null +++ b/templates/cart/buying_history.html @@ -0,0 +1,4 @@ +{% extends 'base.html' %} +{% block content %} + Missing buying history +{% endblock %}