|
|
|
|
@ -5,6 +5,7 @@ from django.db.models import Count, Min, Sum |
|
|
|
|
from accounts.models import Profile |
|
|
|
|
from main.models import STARS_CHOICES |
|
|
|
|
from store.alemtat import alemtat_get_cities_tuple, alemtat_get_services_tuple |
|
|
|
|
from store.queryset import ProductQuerySet |
|
|
|
|
|
|
|
|
|
FIELD_TYPE_CHAR = 'char' |
|
|
|
|
FIELD_TYPE_INT = 'int' |
|
|
|
|
@ -24,6 +25,7 @@ def photo_filename(instance, filename): |
|
|
|
|
|
|
|
|
|
return 'photo_uploads/' + slugify_filename(filename) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CartModel(models.Model): |
|
|
|
|
cart_id = models.CharField('Сессия', max_length=256, default='') |
|
|
|
|
profile = models.ForeignKey(Profile, default=None, null=True, blank=False, |
|
|
|
|
@ -32,6 +34,7 @@ class CartModel(models.Model): |
|
|
|
|
weight = models.CharField('Вес', max_length=20, default='0') |
|
|
|
|
total = models.CharField('Итого тенге', max_length=20, default='0') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Category(models.Model): |
|
|
|
|
title = models.CharField('Наименование', max_length=256, default='') |
|
|
|
|
h1 = models.CharField('Заголовок h1', max_length=256, default='', null=True, blank=True) |
|
|
|
|
@ -40,14 +43,14 @@ class Category(models.Model): |
|
|
|
|
meta_text = models.TextField('Мета текст', default='', null=True, blank=True) |
|
|
|
|
slug = models.SlugField('Ссылка', max_length=256, default='') |
|
|
|
|
description = models.TextField( |
|
|
|
|
'Описание', default='', null=True, blank=True) |
|
|
|
|
'Описание', default='', null=True, blank=True) |
|
|
|
|
parent = models.ForeignKey( |
|
|
|
|
'self', default=None, null=True, blank=True, related_name='childs', |
|
|
|
|
verbose_name='Родительская категория') |
|
|
|
|
'self', default=None, null=True, blank=True, related_name='childs', |
|
|
|
|
verbose_name='Родительская категория') |
|
|
|
|
hide_products = models.BooleanField('Показывать дочерние категории вместо товаров', default=False) |
|
|
|
|
image = models.ImageField('Картинка', upload_to=photo_filename, default=None, null=True, blank=True) |
|
|
|
|
attributes = models.ManyToManyField( |
|
|
|
|
'Attribute', through='AttributeForCategory') |
|
|
|
|
'Attribute', through='AttributeForCategory') |
|
|
|
|
priority = models.IntegerField('Приоритет', default=0) |
|
|
|
|
|
|
|
|
|
class Meta: |
|
|
|
|
@ -91,13 +94,18 @@ class Category(models.Model): |
|
|
|
|
|
|
|
|
|
def brands(self): |
|
|
|
|
brand_qs = self.get_all_products().values( |
|
|
|
|
'brand').annotate(count_brands=Count('brand')) |
|
|
|
|
'brand').annotate(count_brands=Count('brand')) |
|
|
|
|
brand_pks = [v['brand'] for v in brand_qs] |
|
|
|
|
return Brand.objects.filter(pk__in=brand_pks).order_by('title') |
|
|
|
|
|
|
|
|
|
def get_childs_ordered_by_count(self): |
|
|
|
|
return self.childs.annotate(Count('childs')).order_by('priority') # , '-childs__count') |
|
|
|
|
|
|
|
|
|
def get_all_products_in_stock_order_by(self, field): |
|
|
|
|
queryset = Product.objects.filter(categories__in=self.get_all_childs()).sorted_in_stock_by_field(field) |
|
|
|
|
|
|
|
|
|
return queryset |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Attribute(models.Model): |
|
|
|
|
title = models.CharField('Наименование', max_length=256, default='') |
|
|
|
|
@ -113,15 +121,15 @@ class Attribute(models.Model): |
|
|
|
|
|
|
|
|
|
class AttributeForCategory(models.Model): |
|
|
|
|
category = models.ForeignKey( |
|
|
|
|
Category, verbose_name='Категория', related_name='attr_cat') |
|
|
|
|
Category, verbose_name='Категория', related_name='attr_cat') |
|
|
|
|
attribute = models.ForeignKey( |
|
|
|
|
Attribute, verbose_name='Атрибут в категории', |
|
|
|
|
related_name='for_category') |
|
|
|
|
Attribute, verbose_name='Атрибут в категории', |
|
|
|
|
related_name='for_category') |
|
|
|
|
field_type = models.CharField( |
|
|
|
|
'Тип атрибута', choices=FIELD_TYPE_CHOICES, |
|
|
|
|
default='char', max_length=10) |
|
|
|
|
'Тип атрибута', choices=FIELD_TYPE_CHOICES, |
|
|
|
|
default='char', max_length=10) |
|
|
|
|
choises_array = ArrayField( |
|
|
|
|
models.CharField(max_length=50), blank=True, default=[]) |
|
|
|
|
models.CharField(max_length=50), blank=True, default=[]) |
|
|
|
|
priority = models.IntegerField('Приоритет', default=0) |
|
|
|
|
|
|
|
|
|
class Meta: |
|
|
|
|
@ -131,12 +139,12 @@ class AttributeForCategory(models.Model): |
|
|
|
|
def __str__(self): |
|
|
|
|
if self.field_type == FIELD_TYPE_SELECT: |
|
|
|
|
return '{}: {} ({}: {})'.format( |
|
|
|
|
self.category.title, self.attribute.title, |
|
|
|
|
self.get_field_type_display(), self.choises_array) |
|
|
|
|
self.category.title, self.attribute.title, |
|
|
|
|
self.get_field_type_display(), self.choises_array) |
|
|
|
|
else: |
|
|
|
|
return '{}: {} ({})'.format( |
|
|
|
|
self.category.title, self.attribute.title, |
|
|
|
|
self.get_field_type_display()) |
|
|
|
|
self.category.title, self.attribute.title, |
|
|
|
|
self.get_field_type_display()) |
|
|
|
|
|
|
|
|
|
def get_posible_values(self): |
|
|
|
|
retval = [] |
|
|
|
|
@ -176,17 +184,19 @@ class Product(models.Model): |
|
|
|
|
title = models.CharField('Наименование', max_length=256, default='') |
|
|
|
|
slug = models.SlugField('Ссылка', max_length=256, default='') |
|
|
|
|
categories = models.ManyToManyField( |
|
|
|
|
Category, verbose_name='Категории', related_name='products') |
|
|
|
|
Category, verbose_name='Категории', related_name='products') |
|
|
|
|
description = models.TextField( |
|
|
|
|
'Описание', default='', null=True, blank=True) |
|
|
|
|
'Описание', default='', null=True, blank=True) |
|
|
|
|
brand = models.ForeignKey(Brand, verbose_name='Брэнд') |
|
|
|
|
video = models.CharField('Код Youtube', max_length=256, default='', null=True, blank=True) |
|
|
|
|
attirbutes = models.ManyToManyField( |
|
|
|
|
AttributeForCategory, through='AttributesInProduct') |
|
|
|
|
AttributeForCategory, through='AttributesInProduct') |
|
|
|
|
is_leader = models.BooleanField('Лидер продаж', default=False) |
|
|
|
|
on_main = models.BooleanField('На главной', default=False) |
|
|
|
|
priority = models.IntegerField('Приоритет для главной', default=0) |
|
|
|
|
|
|
|
|
|
objects = ProductQuerySet.as_manager() |
|
|
|
|
|
|
|
|
|
class Meta: |
|
|
|
|
verbose_name = 'товар' |
|
|
|
|
verbose_name_plural = 'товары' |
|
|
|
|
@ -254,14 +264,14 @@ class Product(models.Model): |
|
|
|
|
|
|
|
|
|
class ProductVariation(models.Model): |
|
|
|
|
product = models.ForeignKey( |
|
|
|
|
Product, verbose_name='Товар', related_name='variations') |
|
|
|
|
Product, verbose_name='Товар', related_name='variations') |
|
|
|
|
variation = models.CharField('Вариация', max_length=512, default='') |
|
|
|
|
price = models.IntegerField( |
|
|
|
|
'Цена (тенге)', default=0, null=False, blank=False) |
|
|
|
|
'Цена (тенге)', default=0, null=False, blank=False) |
|
|
|
|
in_stock = models.IntegerField( |
|
|
|
|
'В наличии (шт.)', default=1, null=False, blank=False) |
|
|
|
|
'В наличии (шт.)', default=1, null=False, blank=False) |
|
|
|
|
article = models.CharField( |
|
|
|
|
'Артикул', max_length=32, null=True, blank=True, default='') |
|
|
|
|
'Артикул', max_length=32, null=True, blank=True, default='') |
|
|
|
|
weight = models.FloatField('Вес (кг)', default=0.1, null=False, blank=False) |
|
|
|
|
discount = models.IntegerField('Скидка %', default=0, blank=False, null=False) |
|
|
|
|
delivery_date = models.CharField('Дата доставки', default=None, blank=True, null=True, max_length=20) |
|
|
|
|
@ -274,10 +284,11 @@ class ProductVariation(models.Model): |
|
|
|
|
return self.variation |
|
|
|
|
|
|
|
|
|
def get_price(self, profile=None): |
|
|
|
|
#import pdb; pdb.set_trace() |
|
|
|
|
#from django.core.mail import mail_admins |
|
|
|
|
#mail_admins('auth', '{} {}'.format(profile, self.product.brand.slug)) |
|
|
|
|
if profile and profile.is_authenticated() and self.product.brand.slug in ['beuchat', 'scorpena'] and profile.sale: |
|
|
|
|
# import pdb; pdb.set_trace() |
|
|
|
|
# from django.core.mail import mail_admins |
|
|
|
|
# mail_admins('auth', '{} {}'.format(profile, self.product.brand.slug)) |
|
|
|
|
if profile and profile.is_authenticated() and self.product.brand.slug in ['beuchat', |
|
|
|
|
'scorpena'] and profile.sale: |
|
|
|
|
return int(self.price - (self.price / Decimal(100) * Decimal(profile.sale))) |
|
|
|
|
else: |
|
|
|
|
if self.discount: |
|
|
|
|
@ -291,12 +302,12 @@ class ProductVariation(models.Model): |
|
|
|
|
|
|
|
|
|
class AttributesInProduct(models.Model): |
|
|
|
|
attribute = models.ForeignKey( |
|
|
|
|
AttributeForCategory, verbose_name='Атрибут в категории', |
|
|
|
|
related_name='in_product') |
|
|
|
|
AttributeForCategory, verbose_name='Атрибут в категории', |
|
|
|
|
related_name='in_product') |
|
|
|
|
product = models.ForeignKey( |
|
|
|
|
Product, verbose_name='Товар', related_name='product_attributes') |
|
|
|
|
Product, verbose_name='Товар', related_name='product_attributes') |
|
|
|
|
value = models.CharField( |
|
|
|
|
'Значение', max_length=64, default=None, blank=True, null=True) |
|
|
|
|
'Значение', max_length=64, default=None, blank=True, null=True) |
|
|
|
|
|
|
|
|
|
class Meta: |
|
|
|
|
verbose_name = 'атрибут в товаре' |
|
|
|
|
@ -310,7 +321,7 @@ class SlugImageField(models.ImageField): |
|
|
|
|
class ImageInProduct(models.Model): |
|
|
|
|
image = models.ImageField('Картинка', upload_to=photo_filename) |
|
|
|
|
product = models.ForeignKey( |
|
|
|
|
Product, verbose_name='Товар', related_name='images') |
|
|
|
|
Product, verbose_name='Товар', related_name='images') |
|
|
|
|
is_main = models.BooleanField('Главная', default=False) |
|
|
|
|
|
|
|
|
|
class Meta: |
|
|
|
|
@ -331,22 +342,22 @@ STATUS_CHOICES = ( |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
KAZPOST_CITIES = ( |
|
|
|
|
(1, "Астана"), |
|
|
|
|
(2, "Актобе"), |
|
|
|
|
(3, "Актау"), |
|
|
|
|
(4, "Алматы"), |
|
|
|
|
(5, "Атырау"), |
|
|
|
|
(6, "Караганда"), |
|
|
|
|
(7, "Кызылорда"), |
|
|
|
|
(8, "Кокшетау"), |
|
|
|
|
(9, "Костанай"), |
|
|
|
|
(10, "Павлодар"), |
|
|
|
|
(11, "Петропавловск"), |
|
|
|
|
(12, "Тараз"), |
|
|
|
|
(13, "Усть-Каменогорск"), |
|
|
|
|
(14, "Уральск"), |
|
|
|
|
(15, "Шымкент"), |
|
|
|
|
(16, "Талдыкорган") |
|
|
|
|
(1, "Астана"), |
|
|
|
|
(2, "Актобе"), |
|
|
|
|
(3, "Актау"), |
|
|
|
|
(4, "Алматы"), |
|
|
|
|
(5, "Атырау"), |
|
|
|
|
(6, "Караганда"), |
|
|
|
|
(7, "Кызылорда"), |
|
|
|
|
(8, "Кокшетау"), |
|
|
|
|
(9, "Костанай"), |
|
|
|
|
(10, "Павлодар"), |
|
|
|
|
(11, "Петропавловск"), |
|
|
|
|
(12, "Тараз"), |
|
|
|
|
(13, "Усть-Каменогорск"), |
|
|
|
|
(14, "Уральск"), |
|
|
|
|
(15, "Шымкент"), |
|
|
|
|
(16, "Талдыкорган") |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -356,28 +367,28 @@ class OrderData(models.Model): |
|
|
|
|
profile = models.ForeignKey(Profile, default=None, null=True, blank=False, |
|
|
|
|
related_name='orders') |
|
|
|
|
first_name = models.CharField( |
|
|
|
|
'Имя', max_length=64, blank=False, null=False) |
|
|
|
|
'Имя', max_length=64, blank=False, null=False) |
|
|
|
|
last_name = models.CharField( |
|
|
|
|
'Фамилия', max_length=64, blank=False, null=False) |
|
|
|
|
'Фамилия', max_length=64, blank=False, null=False) |
|
|
|
|
phone = models.CharField( |
|
|
|
|
'Номер мобильного телефона', max_length=15, blank=False, null=False) |
|
|
|
|
'Номер мобильного телефона', max_length=15, blank=False, null=False) |
|
|
|
|
email = models.EmailField( |
|
|
|
|
'Email', blank=False, null=False) |
|
|
|
|
'Email', blank=False, null=False) |
|
|
|
|
city = models.CharField( |
|
|
|
|
'Город Алемтат', max_length=20, blank=True, null=True, choices=alemtat_get_cities_tuple()) |
|
|
|
|
'Город Алемтат', max_length=20, blank=True, null=True, choices=alemtat_get_cities_tuple()) |
|
|
|
|
deliv_service = models.CharField( |
|
|
|
|
'Почтовая служба', max_length=20, blank=True, null=True, default='alemtat') |
|
|
|
|
'Почтовая служба', max_length=20, blank=True, null=True, default='alemtat') |
|
|
|
|
kazpost_city = models.IntegerField( |
|
|
|
|
'Город Казпочта', blank=True, null=True, choices=KAZPOST_CITIES) |
|
|
|
|
'Город Казпочта', blank=True, null=True, choices=KAZPOST_CITIES) |
|
|
|
|
address = models.CharField( |
|
|
|
|
'Адрес', max_length=100, blank=False, null=False) |
|
|
|
|
'Адрес', max_length=100, blank=False, null=False) |
|
|
|
|
deliv_type = models.CharField( |
|
|
|
|
'Способ Алемтат', max_length=2, blank=True, null=True, default='', |
|
|
|
|
choices=alemtat_get_services_tuple()) |
|
|
|
|
'Способ Алемтат', max_length=2, blank=True, null=True, default='', |
|
|
|
|
choices=alemtat_get_services_tuple()) |
|
|
|
|
items = models.CharField( |
|
|
|
|
'Товары', max_length=256, blank=False, null=False, default='') |
|
|
|
|
'Товары', max_length=256, blank=False, null=False, default='') |
|
|
|
|
amount = models.FloatField( |
|
|
|
|
'Сумма', blank=False, null=False, default=0.0) |
|
|
|
|
'Сумма', blank=False, null=False, default=0.0) |
|
|
|
|
status = models.IntegerField('Статус', default=0, null=False, blank=False, |
|
|
|
|
choices=STATUS_CHOICES) |
|
|
|
|
|
|
|
|
|
@ -387,9 +398,9 @@ class OrderData(models.Model): |
|
|
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
|
return '{} {}: {}'.format( |
|
|
|
|
self.first_name, |
|
|
|
|
self.last_name, |
|
|
|
|
self.amount |
|
|
|
|
self.first_name, |
|
|
|
|
self.last_name, |
|
|
|
|
self.amount |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
def get_status(self): |
|
|
|
|
|