From 1927e0047b07a3e0000fa08f24946a14faf16435 Mon Sep 17 00:00:00 2001 From: Gena Date: Fri, 12 Jun 2015 01:40:11 +0600 Subject: [PATCH] no message --- accounts/admin.py | 68 +++++- accounts/forms.py | 4 + accounts/migrations/0001_initial.py | 33 +++ .../migrations/0002_auto_20150611_2306.py | 24 +++ accounts/models.py | 67 +++++- accounts/urls.py | 10 + accounts/views.py | 6 +- api/views.py | 2 + batiskaf/jinja2.py | 9 + batiskaf/settings.py | 31 ++- .../templates/jinja2/accounts/login.jinja | 4 + .../jinja2/bootstrapform/field.jinja | 82 ++++++++ .../templates/jinja2/bootstrapform/form.jinja | 16 ++ .../jinja2/bootstrapform/formset.jinja | 13 ++ batiskaf/templates/jinja2/cart_detail.jinja | 53 ++++- batiskaf/templates/jinja2/order_ok.jinja | 12 ++ batiskaf/templates/jinja2/order_print.jinja | 36 ++++ batiskaf/templates/jinja2/product.jinja | 1 - batiskaf/urls.py | 8 + static/js/_.js | 193 ++++++++++-------- static/less/_.css | 6 + static/less/_.less | 7 + store/alemtat.py | 69 +++++++ store/cart.py | 7 +- store/forms.py | 9 + store/migrations/0013_auto_20150611_2306.py | 31 +++ store/migrations/0014_auto_20150612_0050.py | 24 +++ store/migrations/0015_orderdata_items.py | 19 ++ store/models.py | 22 ++ store/urls.py | 1 + store/views.py | 43 +++- 31 files changed, 810 insertions(+), 100 deletions(-) create mode 100644 accounts/forms.py create mode 100644 accounts/migrations/0001_initial.py create mode 100644 accounts/migrations/0002_auto_20150611_2306.py create mode 100644 accounts/urls.py create mode 100644 batiskaf/templates/jinja2/accounts/login.jinja create mode 100644 batiskaf/templates/jinja2/bootstrapform/field.jinja create mode 100644 batiskaf/templates/jinja2/bootstrapform/form.jinja create mode 100644 batiskaf/templates/jinja2/bootstrapform/formset.jinja create mode 100644 batiskaf/templates/jinja2/order_ok.jinja create mode 100644 batiskaf/templates/jinja2/order_print.jinja create mode 100644 store/alemtat.py create mode 100644 store/forms.py create mode 100644 store/migrations/0013_auto_20150611_2306.py create mode 100644 store/migrations/0014_auto_20150612_0050.py create mode 100644 store/migrations/0015_orderdata_items.py diff --git a/accounts/admin.py b/accounts/admin.py index 8c38f3f..0d0327a 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -1,3 +1,69 @@ from django.contrib import admin +from django import forms +from django.contrib import admin +from django.contrib.auth.models import Group +from django.contrib.auth.admin import UserAdmin +from django.contrib.auth.forms import ReadOnlyPasswordHashField + +from .models import Profile + + +class ProfileCreationForm(forms.ModelForm): + password1 = forms.CharField(label='Пароль', widget=forms.PasswordInput) + password2 = forms.CharField(label='Подтверждение', widget=forms.PasswordInput) + + class Meta: + model = Profile + fields = ('phone', 'email') + + def clean_password2(self): + password1 = self.cleaned_data.get("password1") + password2 = self.cleaned_data.get("password2") + if password1 and password2 and password1 != password2: + raise forms.ValidationError("Пароли не совпадают") + return password2 + + def save(self, commit=True): + user = super(ProfileCreationForm, self).save(commit=False) + user.set_password(self.cleaned_data["password1"]) + if commit: + user.save() + return user + + +class ProfileChangeForm(forms.ModelForm): + password = ReadOnlyPasswordHashField() + + class Meta: + model = Profile + fields = ('phone', 'email', 'password', 'is_active', 'is_superuser') + + def clean_password(self): + return self.initial["password"] + + +class ProfileAdmin(UserAdmin): + form = ProfileChangeForm + add_form = ProfileCreationForm + + list_display = ('phone', 'first_name', 'last_name', 'email', 'is_superuser', 'date_joined') + list_filter = ('is_superuser',) + fieldsets = ( + (None, {'fields': ( + 'phone', 'email', 'password', 'first_name', 'last_name' + )}), + ('Инфо', {'fields': ('date_joined',)}), + ('Доступ', {'fields': ('is_superuser', 'is_active')}), + ) + add_fieldsets = ( + (None, { + 'classes': ('wide',), + 'fields': ('phone', 'email', 'first_name', 'last_name', 'password1', 'password2')} + ), + ) + search_fields = ('phone', 'email',) + ordering = ('phone', 'email',) + filter_horizontal = () -# Register your models here. +admin.site.register(Profile, ProfileAdmin) +admin.site.unregister(Group) diff --git a/accounts/forms.py b/accounts/forms.py new file mode 100644 index 0000000..6f59cf3 --- /dev/null +++ b/accounts/forms.py @@ -0,0 +1,4 @@ +from django import forms + +class LoginForm(forms.Form): + phone = forms.CharField(label='Телефон', max_length=15) \ No newline at end of file diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py new file mode 100644 index 0000000..06190d9 --- /dev/null +++ b/accounts/migrations/0001_initial.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import datetime + + +class Migration(migrations.Migration): + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.AutoField(verbose_name='ID', serialize=False, primary_key=True, auto_created=True)), + ('password', models.CharField(verbose_name='password', max_length=128)), + ('last_login', models.DateTimeField(verbose_name='last login', blank=True, null=True)), + ('phone', models.CharField(verbose_name='Телефон', db_index=True, max_length=15, unique=True)), + ('email', models.EmailField(verbose_name='Email', db_index=True, default=None, max_length=254, unique=True)), + ('first_name', models.CharField(verbose_name='first name', blank=True, max_length=30)), + ('last_name', models.CharField(verbose_name='last name', blank=True, max_length=30)), + ('date_joined', models.DateTimeField(verbose_name='Регистрация', default=datetime.datetime.now)), + ('is_superuser', models.BooleanField(verbose_name='Админ', default=False)), + ('is_active', models.BooleanField(verbose_name='Активный', db_index=True, default=True)), + ], + options={ + 'verbose_name': 'пользователь', + 'verbose_name_plural': 'пользователи', + }, + ), + ] diff --git a/accounts/migrations/0002_auto_20150611_2306.py b/accounts/migrations/0002_auto_20150611_2306.py new file mode 100644 index 0000000..6b71e6c --- /dev/null +++ b/accounts/migrations/0002_auto_20150611_2306.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='first_name', + field=models.CharField(max_length=30, blank=True, verbose_name='Имя'), + ), + migrations.AlterField( + model_name='profile', + name='last_name', + field=models.CharField(max_length=30, blank=True, verbose_name='Фамилия'), + ), + ] diff --git a/accounts/models.py b/accounts/models.py index 71a8362..b3688fa 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,3 +1,68 @@ +from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, AbstractUser, User +from django.core.mail import send_mail from django.db import models +from datetime import datetime -# Create your models here. +class ProfileManager(BaseUserManager): + def _create_user(self, phone, email, password, + is_superuser, **extra_fields): + now = datetime.now() + if not phone: + raise ValueError('Телефон не может быть пустым') + email = self.normalize_email(email) + user = self.model(phone=phone, email=email, + is_active=True, + is_superuser=is_superuser, last_login=now, + date_joined=now, **extra_fields) + user.set_password(password) + user.save() + return user + + def create_user(self, phone, email=None, password=None, **extra_fields): + return self._create_user(phone, email, password, False, + **extra_fields) + + def create_superuser(self, phone, email, password, **extra_fields): + return self._create_user(phone, email, password, True, + **extra_fields) + + +class Profile(AbstractBaseUser): + phone = models.CharField('Телефон', max_length=15, unique=True, db_index=True) + email = models.EmailField('Email', blank=False, null=False, default=None, unique=True, db_index=True) + first_name = models.CharField('Имя', max_length=30, blank=True) + last_name = models.CharField('Фамилия', max_length=30, blank=True) + date_joined = models.DateTimeField('Регистрация', default=datetime.now) + is_superuser = models.BooleanField('Админ', default=False) + is_active = models.BooleanField('Активный', default=True, db_index=True) + + USERNAME_FIELD = 'phone' + REQUIRED_FIELDS = ['email'] + + objects = ProfileManager() + + class Meta: + verbose_name = 'пользователь' + verbose_name_plural = 'пользователи' + + def __str__(self): + return self.phone + + def get_full_name(self): + return '{} {}'.format(self.first_name, self.last_name) + + def get_short_name(self): + return self.first_name + + def has_perm(self, perm, obj=None): + return True + + def has_module_perms(self, app_label): + return True + + @property + def is_staff(self): + return self.is_superuser + + def email_user(self, subject, message, from_email=None, **kwargs): + send_mail(subject, message, from_email, [self.email], **kwargs) \ No newline at end of file diff --git a/accounts/urls.py b/accounts/urls.py new file mode 100644 index 0000000..bb114ab --- /dev/null +++ b/accounts/urls.py @@ -0,0 +1,10 @@ +from django.conf.urls import patterns, url +from django.views.generic import RedirectView +from .views import * + +urlpatterns = patterns('', + url(r'^$', RedirectView.as_view( + url='/', permanent=True), name='store_index'), + url(r'^login/$', LoginView.as_view(), + name='store_cart_detail'), + ) diff --git a/accounts/views.py b/accounts/views.py index 91ea44a..b1a284d 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,3 +1,7 @@ from django.shortcuts import render +from django.views.generic import FormView +from .forms import * -# Create your views here. +class LoginView(FormView): + form_class = LoginForm + template_name = 'accounts/login.jinja' \ No newline at end of file diff --git a/api/views.py b/api/views.py index f66c6da..01448a7 100644 --- a/api/views.py +++ b/api/views.py @@ -8,3 +8,5 @@ class CartSerializer(serializers.Serializer): class CartViewSet(viewsets.ViewSet): serializer_class = CartSerializer + + diff --git a/batiskaf/jinja2.py b/batiskaf/jinja2.py index bf04c63..392c4f1 100644 --- a/batiskaf/jinja2.py +++ b/batiskaf/jinja2.py @@ -1,3 +1,4 @@ +from bootstrapform_jinja.templatetags.bootstrap import * from django.contrib.staticfiles.storage import staticfiles_storage from django.core.urlresolvers import reverse from batiskaf.jinja2_ext.thumbnails import thumbnail @@ -17,4 +18,12 @@ def environment(**options): env.filters['linebreaks'] = linebreaks env.filters['thumbnail'] = thumbnail env.filters['cart'] = cart + env.filters['bootstrap'] = bootstrap + env.filters['bootstrap_inline'] = bootstrap_inline + env.filters['bootstrap_horizontal'] = bootstrap_horizontal + env.filters['bootstrap_classes'] = bootstrap_classes + env.filters['is_checkbox'] = is_checkbox + env.filters['is_multiple_checkbox'] = is_multiple_checkbox + env.filters['is_radio'] = is_radio + env.filters['is_file'] = is_file return env diff --git a/batiskaf/settings.py b/batiskaf/settings.py index dab9ff7..2adae5c 100644 --- a/batiskaf/settings.py +++ b/batiskaf/settings.py @@ -40,7 +40,11 @@ MESSAGE_TAGS = { messages.SUCCESS: 'success', } -# Application definition +AUTH_USER_MODEL = 'accounts.Profile' + +LOGIN_URL = '/account/login/' + +LOGOUT_URL = '/account/logout/' INSTALLED_APPS = ( 'django.contrib.admin', @@ -53,9 +57,10 @@ INSTALLED_APPS = ( 'django_extensions', 'rest_framework', 'easy_thumbnails', - 'bootstrap3', + 'bootstrapform_jinja', 'batiskaf', 'main', + 'accounts', 'store', ) @@ -116,13 +121,13 @@ SERVER_EMAIL = "admin@batiskaf.kz" LANGUAGE_CODE = 'ru' -TIME_ZONE = 'UTC' +TIME_ZONE = 'Asia/Almaty' USE_I18N = True USE_L10N = True -USE_TZ = True +USE_TZ = False # Static files (CSS, JavaScript, Images) @@ -143,6 +148,16 @@ STATICFILES_DIRS = [ ] TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.jinja2.Jinja2', + 'DIRS': [ + os.path.join(BASE_DIR, "batiskaf/templates/jinja2"), + #os.path.join(BASE_DIR, "batiskaf/templates/jinja2/bootstrapform"), + ], + 'OPTIONS': { + 'environment': 'batiskaf.jinja2.environment', + } + }, { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, "batiskaf/templates"), ], @@ -160,13 +175,7 @@ TEMPLATES = [ ) }, }, - { - 'BACKEND': 'django.template.backends.jinja2.Jinja2', - 'DIRS': [os.path.join(BASE_DIR, "batiskaf/templates/jinja2"), ], - 'OPTIONS': { - 'environment': 'batiskaf.jinja2.environment', - } - }, + ] BOOTSTRAP3 = { diff --git a/batiskaf/templates/jinja2/accounts/login.jinja b/batiskaf/templates/jinja2/accounts/login.jinja new file mode 100644 index 0000000..f51e4ed --- /dev/null +++ b/batiskaf/templates/jinja2/accounts/login.jinja @@ -0,0 +1,4 @@ +{% extends 'base.jinja' %} +{% block content %} +{{ form }} +{% endblock %} diff --git a/batiskaf/templates/jinja2/bootstrapform/field.jinja b/batiskaf/templates/jinja2/bootstrapform/field.jinja new file mode 100644 index 0000000..4b6366b --- /dev/null +++ b/batiskaf/templates/jinja2/bootstrapform/field.jinja @@ -0,0 +1,82 @@ +{% macro render_field_checkbox(form, field, classes) -%} +
+
+ {% if field.auto_id %} + + {% endif %} + {% for error in field.errors %} + {{ error }} + {% endfor %} + + {% if field.help_text %} +

+ {{ field.help_text|safe }} +

+ {% endif %} +
+
+{%- endmacro %} + +{% macro render_field_radio(form, field, classes) -%} + {% if field.auto_id %} + + {% endif %} +
+ {% for choice in field %} +
+ +
+ {% endfor %} + + {% for error in field.errors %} + {{ error }} + {% endfor %} + + {% if field.help_text %} +

+ {{ field.help_text|safe }} +

+ {% endif %} +
+{%- endmacro %} + +{% macro render_field_standard(form, field, classes) -%} + {% if field.auto_id %} + + {% endif %} + +
+ {{ field|safe }} + + {% for error in field.errors %} + {{ error }} + {% endfor %} + + {% if field.help_text %} +

+ {{ field.help_text|safe }} +

+ {% endif %} +
+{%- endmacro %} + +
+ {% if field|is_checkbox %} + + {{ render_field_checkbox(form, field, classes) }} + + {% elif field|is_radio %} + + {{ render_field_radio(form, field, classes) }} + + {% else %} + + {{ render_field_standard(form, field, classes) }} + + {% endif %} +
\ No newline at end of file diff --git a/batiskaf/templates/jinja2/bootstrapform/form.jinja b/batiskaf/templates/jinja2/bootstrapform/form.jinja new file mode 100644 index 0000000..102438a --- /dev/null +++ b/batiskaf/templates/jinja2/bootstrapform/form.jinja @@ -0,0 +1,16 @@ +{% if form.non_field_errors() %} +
+ × + {% for non_field_error in form.non_field_errors() %} + {{ non_field_error }} + {% endfor %} +
+{% endif %} + +{% for field in form.hidden_fields() %} + {{ field|safe }} +{% endfor %} + +{% for field in form.visible_fields() %} + {% include 'bootstrapform/field.jinja' %} +{% endfor %} diff --git a/batiskaf/templates/jinja2/bootstrapform/formset.jinja b/batiskaf/templates/jinja2/bootstrapform/formset.jinja new file mode 100644 index 0000000..31c8bf0 --- /dev/null +++ b/batiskaf/templates/jinja2/bootstrapform/formset.jinja @@ -0,0 +1,13 @@ +{{ formset.management_form }} + +{% for form in formset %} + + {% if classes.label == 'sr-only' %} +
+ {% endif %} + {% include 'bootstrapform/form.jinja' %} + {% if classes.label == 'sr-only' %} +
+ {% endif %} + +{% endfor %} diff --git a/batiskaf/templates/jinja2/cart_detail.jinja b/batiskaf/templates/jinja2/cart_detail.jinja index f6221de..5277dde 100644 --- a/batiskaf/templates/jinja2/cart_detail.jinja +++ b/batiskaf/templates/jinja2/cart_detail.jinja @@ -57,16 +57,67 @@ ← Продолжить покупки - Итого: {{ cart.total }} ₸ + Итого: {{ cart.total }} + +
+

+

Оформление заказа

+
+
+
+
+
+

Данные доставки

+
+
+
+ {{ form|bootstrap }} +
+
+ Итого: {{ cart.total }} ₸ +
+
+
+ +
+
+
+
+ +
+ + {#
#} + {#
#} + {#
#} + {#

Доставка

#} + {#
#} + {#
#} + {# #} + {#
#} + {#
#} + {#
#} +
+ {#
#} + {#
#} + {#
#} + {#
#} + {#

Способ оплаты

#} + {#
#} + {#
#} + {# Банковский платеж#} + {#
#} + {#
#} + {#
#} + {#
#}
{% else %} diff --git a/batiskaf/templates/jinja2/order_ok.jinja b/batiskaf/templates/jinja2/order_ok.jinja new file mode 100644 index 0000000..c6c8180 --- /dev/null +++ b/batiskaf/templates/jinja2/order_ok.jinja @@ -0,0 +1,12 @@ +{% extends 'base.jinja' %} +{% block content %} + +
+ +

Спасибо!

+

Ваш заказ успешно принят и поступит в обработку сразу после оплаты.

+

Распечатать квитанцию для оплаты

+
+ +{% endblock %} + diff --git a/batiskaf/templates/jinja2/order_print.jinja b/batiskaf/templates/jinja2/order_print.jinja new file mode 100644 index 0000000..fe1d93f --- /dev/null +++ b/batiskaf/templates/jinja2/order_print.jinja @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ date.strftime('%d.%m.%Y') }} {{ order.pk }}
Поступ. в банк плат.Списано со сч. плат.
ПЛАТЕЖНОЕ ПОРУЧЕНИЕ №201508
Сумма
прописью
Двести тысяч рублей 00 копеек
ИИН 7708654321КПП 770801001
\ No newline at end of file diff --git a/batiskaf/templates/jinja2/product.jinja b/batiskaf/templates/jinja2/product.jinja index 08ea307..dff9b05 100644 --- a/batiskaf/templates/jinja2/product.jinja +++ b/batiskaf/templates/jinja2/product.jinja @@ -73,7 +73,6 @@ Добавить в корзину - diff --git a/batiskaf/urls.py b/batiskaf/urls.py index 32959c9..f3445e1 100644 --- a/batiskaf/urls.py +++ b/batiskaf/urls.py @@ -1,5 +1,6 @@ from django.conf.urls import patterns, include, url from django.contrib import admin +from store.views import order_view, order_print admin.site.site_header = 'Админка Batiskaf.kz' admin.site.site_title = 'Админка Batiskaf.kz' @@ -9,6 +10,13 @@ urlpatterns = patterns( '', url(r'^$', 'main.views.index', name='index'), + url(r'^get_order_amount/$', 'store.views.get_order_amount'), + url(r'^order/(?P.+)/print/$', order_print, + name='store_order_print'), + + url(r'^order/(?P.+)/$', order_view, + name='store_order_view'), url(r'^store/', include('store.urls')), + url(r'^account/', include('accounts.urls')), url(r'^admin2517_garpun/', include(admin.site.urls)), ) diff --git a/static/js/_.js b/static/js/_.js index 6b17872..e6c7d63 100644 --- a/static/js/_.js +++ b/static/js/_.js @@ -66,110 +66,143 @@ $(document).ready(function () { }); -$('.product-min-thumbnails a').each(function(){ - var link = $(this); - link.on('click', function(){ - $('.product-big-thumbnail img').prop('src', link.prop('href')); - $('#product-big-img').attr('data-zoom-image', link.attr("data-big-url")); - $('.zoomContainer').remove(); - $('#product-big-img').removeData('elevateZoom'); - $('#product-big-img').removeData('zoomImage'); - $('#product-big-img').elevateZoom({ - zoomType: "inner", - cursor: "crosshair", - lensFadeIn: 500, - lensFadeOut: 500, - easing : true - }); + $('.product-min-thumbnails a').each(function () { + var link = $(this); + link.on('click', function () { + $('.product-big-thumbnail img').prop('src', link.prop('href')); + $('#product-big-img').attr('data-zoom-image', link.attr("data-big-url")); + $('.zoomContainer').remove(); + $('#product-big-img').removeData('elevateZoom'); + $('#product-big-img').removeData('zoomImage'); + $('#product-big-img').elevateZoom({ + zoomType: "inner", + cursor: "crosshair", + lensFadeIn: 500, + lensFadeOut: 500, + easing: true + }); - // $('.product-big-thumbnail-container').trigger('zoom.destroy'); - // $('.product-big-thumbnail-container').zoom({url: link.attr("data-big-url")}); + // $('.product-big-thumbnail-container').trigger('zoom.destroy'); + // $('.product-big-thumbnail-container').zoom({url: link.attr("data-big-url")}); //$('a#product-big-image-url').prop('href', link.attr('data-big-url')) return false; }) -}); -$('#product-big-img').elevateZoom({ - zoomType: "inner", - cursor: "crosshair", - lensFadeIn: 500, - lensFadeOut: 500, - easing : true -}); + }); + $('#product-big-img').elevateZoom({ + zoomType: "inner", + cursor: "crosshair", + lensFadeIn: 500, + lensFadeOut: 500, + easing: true + }); //$('.product-big-thumbnail-container').zoom({url: $('#product-big-image-url').prop("href")}); -function create_cart_add_link(product_pk, count){ - return $.param.querystring('/store/cart/add/', 'pk=' + product_pk + '&count=' + count + '&next=' + window.location.pathname); -} - -function selectVariation(value, index){ - var price = $('.product-variations-selecter option[value=' + value + ']').attr('data-price'); - var in_stock = $('.product-variations-selecter option[value=' + value + ']').attr('data-count'); - $('.product-detail-price-span').html(price); - if (in_stock > 0){ - $(".product-count-selecter").selecter('destroy'); - $('.product-in-stock').show(); - $('.product-not-in-stock').hide(); - $('.product-count-selecter').html(''); - for (i=0; i'); - option.attr({ 'value': i+1 }).text((i+1) + ' шт.'); - $('.product-count-selecter').append(option); + function create_cart_add_link(product_pk, count) { + return $.param.querystring('/store/cart/add/', 'pk=' + product_pk + '&count=' + count + '&next=' + window.location.pathname); + } + + function selectVariation(value, index) { + var price = $('.product-variations-selecter option[value=' + value + ']').attr('data-price'); + var in_stock = $('.product-variations-selecter option[value=' + value + ']').attr('data-count'); + $('.product-detail-price-span').html(price); + if (in_stock > 0) { + $(".product-count-selecter").selecter('destroy'); + $('.product-in-stock').show(); + $('.product-not-in-stock').hide(); + $('.product-count-selecter').html(''); + for (i = 0; i < in_stock; i++) { + var option = $('