remotes/origin/artem
Gena 11 years ago
parent 66b134174a
commit 1927e0047b
  1. 68
      accounts/admin.py
  2. 4
      accounts/forms.py
  3. 33
      accounts/migrations/0001_initial.py
  4. 24
      accounts/migrations/0002_auto_20150611_2306.py
  5. 67
      accounts/models.py
  6. 10
      accounts/urls.py
  7. 6
      accounts/views.py
  8. 2
      api/views.py
  9. 9
      batiskaf/jinja2.py
  10. 31
      batiskaf/settings.py
  11. 4
      batiskaf/templates/jinja2/accounts/login.jinja
  12. 82
      batiskaf/templates/jinja2/bootstrapform/field.jinja
  13. 16
      batiskaf/templates/jinja2/bootstrapform/form.jinja
  14. 13
      batiskaf/templates/jinja2/bootstrapform/formset.jinja
  15. 53
      batiskaf/templates/jinja2/cart_detail.jinja
  16. 12
      batiskaf/templates/jinja2/order_ok.jinja
  17. 36
      batiskaf/templates/jinja2/order_print.jinja
  18. 1
      batiskaf/templates/jinja2/product.jinja
  19. 8
      batiskaf/urls.py
  20. 193
      static/js/_.js
  21. 6
      static/less/_.css
  22. 7
      static/less/_.less
  23. 69
      store/alemtat.py
  24. 7
      store/cart.py
  25. 9
      store/forms.py
  26. 31
      store/migrations/0013_auto_20150611_2306.py
  27. 24
      store/migrations/0014_auto_20150612_0050.py
  28. 19
      store/migrations/0015_orderdata_items.py
  29. 22
      store/models.py
  30. 1
      store/urls.py
  31. 43
      store/views.py

@ -1,3 +1,69 @@
from django.contrib import admin 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)

@ -0,0 +1,4 @@
from django import forms
class LoginForm(forms.Form):
phone = forms.CharField(label='Телефон', max_length=15)

@ -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': 'пользователи',
},
),
]

@ -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='Фамилия'),
),
]

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

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

@ -1,3 +1,7 @@
from django.shortcuts import render 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'

@ -8,3 +8,5 @@ class CartSerializer(serializers.Serializer):
class CartViewSet(viewsets.ViewSet): class CartViewSet(viewsets.ViewSet):
serializer_class = CartSerializer serializer_class = CartSerializer

@ -1,3 +1,4 @@
from bootstrapform_jinja.templatetags.bootstrap import *
from django.contrib.staticfiles.storage import staticfiles_storage from django.contrib.staticfiles.storage import staticfiles_storage
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from batiskaf.jinja2_ext.thumbnails import thumbnail from batiskaf.jinja2_ext.thumbnails import thumbnail
@ -17,4 +18,12 @@ def environment(**options):
env.filters['linebreaks'] = linebreaks env.filters['linebreaks'] = linebreaks
env.filters['thumbnail'] = thumbnail env.filters['thumbnail'] = thumbnail
env.filters['cart'] = cart 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 return env

@ -40,7 +40,11 @@ MESSAGE_TAGS = {
messages.SUCCESS: 'success', messages.SUCCESS: 'success',
} }
# Application definition AUTH_USER_MODEL = 'accounts.Profile'
LOGIN_URL = '/account/login/'
LOGOUT_URL = '/account/logout/'
INSTALLED_APPS = ( INSTALLED_APPS = (
'django.contrib.admin', 'django.contrib.admin',
@ -53,9 +57,10 @@ INSTALLED_APPS = (
'django_extensions', 'django_extensions',
'rest_framework', 'rest_framework',
'easy_thumbnails', 'easy_thumbnails',
'bootstrap3', 'bootstrapform_jinja',
'batiskaf', 'batiskaf',
'main', 'main',
'accounts',
'store', 'store',
) )
@ -116,13 +121,13 @@ SERVER_EMAIL = "admin@batiskaf.kz"
LANGUAGE_CODE = 'ru' LANGUAGE_CODE = 'ru'
TIME_ZONE = 'UTC' TIME_ZONE = 'Asia/Almaty'
USE_I18N = True USE_I18N = True
USE_L10N = True USE_L10N = True
USE_TZ = True USE_TZ = False
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
@ -143,6 +148,16 @@ STATICFILES_DIRS = [
] ]
TEMPLATES = [ 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', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "batiskaf/templates"), ], '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 = { BOOTSTRAP3 = {

@ -0,0 +1,4 @@
{% extends 'base.jinja' %}
{% block content %}
{{ form }}
{% endblock %}

@ -0,0 +1,82 @@
{% macro render_field_checkbox(form, field, classes) -%}
<div class="{{ classes.single_value }}">
<div class="checkbox">
{% if field.auto_id %}
<label {% if field.field.required and form.required_css_class %}class="{{ form.required_css_class }}"{% endif %}>
{{ field|safe }} <span>{{ field.label }}</span>
</label>
{% endif %}
{% for error in field.errors %}
<span class="help-block {{ form.error_css_class }}">{{ error }}</span>
{% endfor %}
{% if field.help_text %}
<p class="help-block">
{{ field.help_text|safe }}
</p>
{% endif %}
</div>
</div>
{%- endmacro %}
{% macro render_field_radio(form, field, classes) -%}
{% if field.auto_id %}
<label class="control-label {{ classes.label }} {% if field.field.required %}{{ form.required_css_class }}{% endif %}">{{ field.label }}</label>
{% endif %}
<div class="{{ classes.value }}">
{% for choice in field %}
<div class="radio">
<label>
{{ choice.tag()|safe }}
{{ choice.choice_label }}
</label>
</div>
{% endfor %}
{% for error in field.errors %}
<span class="help-block {{ form.error_css_class }}">{{ error }}</span>
{% endfor %}
{% if field.help_text %}
<p class="help-block">
{{ field.help_text|safe }}
</p>
{% endif %}
</div>
{%- endmacro %}
{% macro render_field_standard(form, field, classes) -%}
{% if field.auto_id %}
<label class="control-label {{ classes.label }} {% if field.field.required %}{{ form.required_css_class }}{% endif %}" for="{{ field.auto_id }}">{{ field.label }}</label>
{% endif %}
<div class="{{ classes.value }} {% if field|is_multiple_checkbox %}multiple-checkbox{% endif %}">
{{ field|safe }}
{% for error in field.errors %}
<span class="help-block {{ form.error_css_class }}">{{ error }}</span>
{% endfor %}
{% if field.help_text %}
<p class="help-block">
{{ field.help_text|safe }}
</p>
{% endif %}
</div>
{%- endmacro %}
<div class="form-group{% if field.errors %} has-error{% endif %}">
{% 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 %}
</div>

@ -0,0 +1,16 @@
{% if form.non_field_errors() %}
<div class="alert alert-danger">
<a class="close" data-dismiss="alert">&times;</a>
{% for non_field_error in form.non_field_errors() %}
{{ non_field_error }}
{% endfor %}
</div>
{% endif %}
{% for field in form.hidden_fields() %}
{{ field|safe }}
{% endfor %}
{% for field in form.visible_fields() %}
{% include 'bootstrapform/field.jinja' %}
{% endfor %}

@ -0,0 +1,13 @@
{{ formset.management_form }}
{% for form in formset %}
{% if classes.label == 'sr-only' %}
<div class="form-inline">
{% endif %}
{% include 'bootstrapform/form.jinja' %}
{% if classes.label == 'sr-only' %}
</div>
{% endif %}
{% endfor %}

@ -57,16 +57,67 @@
<tr> <tr>
<th colspan="2" class="text-left"><a href="javascript:history.back()" class=""> <th colspan="2" class="text-left"><a href="javascript:history.back()" class="">
&larr; Продолжить покупки</a></th> &larr; Продолжить покупки</a></th>
<th colspan="3" class="text-right table-cart-itogo">Итого: {{ cart.total }} ₸</th> <th colspan="3" class="text-right table-cart-itogo">Итого: <span id="cart-itogo">{{ cart.total }}</span> ₸</th>
<th class="text-center"> <th class="text-center">
<button type="submit" class="btn btn-primary"><span <button type="submit" class="btn btn-primary"><span
class="glyphicon glyphicon-repeat"></span> Пересчитать class="glyphicon glyphicon-repeat"></span> Пересчитать
</button> </button>
</th> </th>
</tr> </tr>
</tfoot> </tfoot>
</table> </table>
</form> </form>
</div><br/>
<hr class="dashed"/><br/>
<h4>Оформление заказа</h4>
<div class="order-data">
<div class="row">
<div class="col-xs-6 col-xs-offset-3">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Данные доставки</h3>
</div>
<div class="panel-body">
<form action="" class="" method="post"><input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
{{ form|bootstrap }}
<br/>
<div class="order-itogo text-right">
Итого: <span id="order-itogo-amount">{{ cart.total }}</span> ₸
</div>
<br/>
<div class="form-group text-center">
<button type="submit" name="order_next" class="btn btn-success">Продолжить</button>
</div>
</form>
</div>
</div>
</div>
{# <div class="col-xs-6">#}
{# <div class="panel panel-default">#}
{# <div class="panel-heading">#}
{# <h3 class="panel-title">Доставка</h3>#}
{# </div>#}
{# <div class="panel-body">#}
{# #}
{# </div>#}
{# </div>#}
{# </div>#}
</div>
{# <div class="row">#}
{# <div class="col-xs-12">#}
{# <div class="panel panel-default">#}
{# <div class="panel-heading">#}
{# <h3 class="panel-title">Способ оплаты</h3>#}
{# </div>#}
{# <div class="panel-body">#}
{# Банковский платеж#}
{# </div>#}
{# </div>#}
{# </div>#}
{# </div>#}
</div> </div>
{% else %} {% else %}

@ -0,0 +1,12 @@
{% extends 'base.jinja' %}
{% block content %}
<div class="alert alert-success alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<h4>Спасибо!</h4>
<p>Ваш заказ успешно принят и поступит в обработку сразу после оплаты.</p>
<p><a class="btn btn-success" href="/order/{{ order.pk }}/print/">Распечатать квитанцию для оплаты</a></p>
</div>
{% endblock %}

@ -0,0 +1,36 @@
<table>
<tr>
<td colspan="2" style="border-bottom: 1px black solid">{{ date.strftime('%d.%m.%Y') }}</td>
<td colspan="2" style="border-bottom: 1px black solid"> </td>
<td></td>
<td></td>
<td></td>
<td style="border: 1px black solid">{{ order.pk }}</td>
</tr>
<tr>
<td>Поступ. в банк плат.</td>
<td>Списано со сч. плат.</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan="3">ПЛАТЕЖНОЕ ПОРУЧЕНИЕ №2015</td>
<td colspan="2" style="border-bottom: 1px black solid"></td>
<td colspan="2" style="border-bottom: 1px black solid"></td>
<td style="border: 1px black solid">08</td>
</tr>
<tr>
<td style="border-right: 1px black solid; border-bottom: 1px black solid; ">Сумма <br/>прописью</td>
<td colspan="3" style="border-bottom: 1px black solid">Двести тысяч рублей 00 копеек</td>
<td colspan="4" style="border-bottom: 1px black solid"></td>
</tr>
<tr>
<td colspan="2" style="border-right: 1px black solid; border-bottom: 1px black solid; ">ИИН 7708654321</td>
<td colspan="2" style="border-right: 1px black solid; border-bottom: 1px black solid; ">КПП 770801001</td>
<td colspan="4" style="border-bottom: 1px black solid"></td>
</tr>
</table>

@ -73,7 +73,6 @@
<a href="/store/cart/add/?pk={{ variant.pk }}&count=1&next={{ product.get_absolute_url() }}" <a href="/store/cart/add/?pk={{ variant.pk }}&count=1&next={{ product.get_absolute_url() }}"
class="btn btn-warning btn-block" id="product-add-to-cart-link"><span class="btn btn-warning btn-block" id="product-add-to-cart-link"><span
class="glyphicon glyphicon-shopping-cart" aria-hidden="true"></span> Добавить в корзину</a> class="glyphicon glyphicon-shopping-cart" aria-hidden="true"></span> Добавить в корзину</a>
</div> </div>
</div> </div>
</div> </div>

@ -1,5 +1,6 @@
from django.conf.urls import patterns, include, url from django.conf.urls import patterns, include, url
from django.contrib import admin from django.contrib import admin
from store.views import order_view, order_print
admin.site.site_header = 'Админка Batiskaf.kz' admin.site.site_header = 'Админка Batiskaf.kz'
admin.site.site_title = 'Админка Batiskaf.kz' admin.site.site_title = 'Админка Batiskaf.kz'
@ -9,6 +10,13 @@ urlpatterns = patterns(
'', '',
url(r'^$', 'main.views.index', url(r'^$', 'main.views.index',
name='index'), name='index'),
url(r'^get_order_amount/$', 'store.views.get_order_amount'),
url(r'^order/(?P<order>.+)/print/$', order_print,
name='store_order_print'),
url(r'^order/(?P<order>.+)/$', order_view,
name='store_order_view'),
url(r'^store/', include('store.urls')), url(r'^store/', include('store.urls')),
url(r'^account/', include('accounts.urls')),
url(r'^admin2517_garpun/', include(admin.site.urls)), url(r'^admin2517_garpun/', include(admin.site.urls)),
) )

@ -66,110 +66,143 @@ $(document).ready(function () {
}); });
$('.product-min-thumbnails a').each(function(){ $('.product-min-thumbnails a').each(function () {
var link = $(this); var link = $(this);
link.on('click', function(){ link.on('click', function () {
$('.product-big-thumbnail img').prop('src', link.prop('href')); $('.product-big-thumbnail img').prop('src', link.prop('href'));
$('#product-big-img').attr('data-zoom-image', link.attr("data-big-url")); $('#product-big-img').attr('data-zoom-image', link.attr("data-big-url"));
$('.zoomContainer').remove(); $('.zoomContainer').remove();
$('#product-big-img').removeData('elevateZoom'); $('#product-big-img').removeData('elevateZoom');
$('#product-big-img').removeData('zoomImage'); $('#product-big-img').removeData('zoomImage');
$('#product-big-img').elevateZoom({ $('#product-big-img').elevateZoom({
zoomType: "inner", zoomType: "inner",
cursor: "crosshair", cursor: "crosshair",
lensFadeIn: 500, lensFadeIn: 500,
lensFadeOut: 500, lensFadeOut: 500,
easing : true easing: true
}); });
// $('.product-big-thumbnail-container').trigger('zoom.destroy'); // $('.product-big-thumbnail-container').trigger('zoom.destroy');
// $('.product-big-thumbnail-container').zoom({url: link.attr("data-big-url")}); // $('.product-big-thumbnail-container').zoom({url: link.attr("data-big-url")});
//$('a#product-big-image-url').prop('href', link.attr('data-big-url')) //$('a#product-big-image-url').prop('href', link.attr('data-big-url'))
return false; return false;
}) })
}); });
$('#product-big-img').elevateZoom({ $('#product-big-img').elevateZoom({
zoomType: "inner", zoomType: "inner",
cursor: "crosshair", cursor: "crosshair",
lensFadeIn: 500, lensFadeIn: 500,
lensFadeOut: 500, lensFadeOut: 500,
easing : true easing: true
}); });
//$('.product-big-thumbnail-container').zoom({url: $('#product-big-image-url').prop("href")}); //$('.product-big-thumbnail-container').zoom({url: $('#product-big-image-url').prop("href")});
function create_cart_add_link(product_pk, count){ function create_cart_add_link(product_pk, count) {
return $.param.querystring('/store/cart/add/', 'pk=' + product_pk + '&count=' + count + '&next=' + window.location.pathname); return $.param.querystring('/store/cart/add/', 'pk=' + product_pk + '&count=' + count + '&next=' + window.location.pathname);
} }
function selectVariation(value, index){ function selectVariation(value, index) {
var price = $('.product-variations-selecter option[value=' + value + ']').attr('data-price'); var price = $('.product-variations-selecter option[value=' + value + ']').attr('data-price');
var in_stock = $('.product-variations-selecter option[value=' + value + ']').attr('data-count'); var in_stock = $('.product-variations-selecter option[value=' + value + ']').attr('data-count');
$('.product-detail-price-span').html(price); $('.product-detail-price-span').html(price);
if (in_stock > 0){ if (in_stock > 0) {
$(".product-count-selecter").selecter('destroy'); $(".product-count-selecter").selecter('destroy');
$('.product-in-stock').show(); $('.product-in-stock').show();
$('.product-not-in-stock').hide(); $('.product-not-in-stock').hide();
$('.product-count-selecter').html(''); $('.product-count-selecter').html('');
for (i=0; i<in_stock; i++){ for (i = 0; i < in_stock; i++) {
var option = $('<option/>'); var option = $('<option/>');
option.attr({ 'value': i+1 }).text((i+1) + ' шт.'); option.attr({'value': i + 1}).text((i + 1) + ' шт.');
$('.product-count-selecter').append(option); $('.product-count-selecter').append(option);
}
$(".product-count-selecter").selecter({
callback: selectCount
});
selectCount(1, index);
$('#product-add-to-cart-link').prop('href',
create_cart_add_link($('.product-variations-selecter').val(),
$('.product-count-selecter').val()));
} else {
$('.product-count-selecter').selecter('destroy');
$('.product-in-stock').hide();
$('.product-not-in-stock').show();
} }
$(".product-count-selecter").selecter({
callback: selectCount }
});
selectCount(1, index); $(".product-variations-selecter").selecter({
callback: selectVariation
});
function selectCount(value, index) {
var price = parseInt($('.product-detail-price-span').html());
$('.itogo-span').html(price * value);
$('#product-add-to-cart-link').prop('href', $('#product-add-to-cart-link').prop('href',
create_cart_add_link($('.product-variations-selecter').val(), create_cart_add_link($('.product-variations-selecter').val(),
$('.product-count-selecter').val())); $('.product-count-selecter').val()));
}else{
$('.product-count-selecter').selecter('destroy');
$('.product-in-stock').hide();
$('.product-not-in-stock').show();
} }
} $(".product-count-selecter").selecter({
callback: selectCount
});
$(".product-variations-selecter").selecter({
callback: selectVariation
});
function selectCount(value, index){ if ($('.product-count-selecter option').size() < 1) {
var price = parseInt($('.product-detail-price-span').html()); $('.product-in-stock').hide();
$('.itogo-span').html(price*value); $('.product-not-in-stock').show();
$('#product-add-to-cart-link').prop('href',
create_cart_add_link($('.product-variations-selecter').val(),
$('.product-count-selecter').val()));
}
$(".product-count-selecter").selecter({ } else {
callback: selectCount $(".product-count-selecter").selecter();
}); }
$('ul.messages li').each(function () {
var li = $(this);
var messageType = li.attr('data-type');
swal({
html: true,
type: messageType,
title: "OK!",
text: li.html()
});
});
if ($('.product-count-selecter option').size() < 1){ function selectCity(value, index) {
$('.product-in-stock').hide(); var city = $('#id_city').val();
$('.product-not-in-stock').show(); var deliv = $('#id_deliv_type').val();
var cart_itogo = $('#cart-itogo').html();
var order_itogo = $('#order-itogo-amount');
}else{ if (city && deliv) {
$(".product-count-selecter").selecter(); $.ajax({
} method: "GET",
url: "/get_order_amount/",
data: {
city: city,
deliv: deliv,
$('ul.messages li').each(function(){ }
var li = $(this); })
var messageType = li.attr('data-type'); .done(function (msg) {
swal({ order_itogo.html(
html: true, parseFloat(msg.AmountPlusFSAmount) + parseFloat(cart_itogo)
type: messageType, );
title: "OK!", });
text: li.html()
} else {
order_itogo.html(cart_itogo);
}
}
});
});
$('#id_city').selecter({
callback: selectCity
});
$('#id_deliv_type').selecter({
callback: selectCity
});
}); });

@ -949,3 +949,9 @@ ul.messages {
padding-top: 20px; padding-top: 20px;
border-top: 1px #ddd solid; border-top: 1px #ddd solid;
} }
.order-data .radio {
margin-left: 15px;
}
#order-itogo-amount {
font-size: 20px;
}

@ -790,4 +790,11 @@ ul.messages {
margin-top: 40px; margin-top: 40px;
padding-top: 20px; padding-top: 20px;
border-top: 1px #ddd solid; border-top: 1px #ddd solid;
}
.order-data .radio{
margin-left: 15px;
}
#order-itogo-amount{
font-size: 20px;
} }

@ -0,0 +1,69 @@
import requests
class AlemTat(object):
COUNTRY_CODE = '0001'
CITY_CODE = '000003'
API_KEY = '677a8773-c647-4b8f-8968-32a67d55e0d3'
CONTRACT = '05828/ИМ'
def _build_url(self, url):
# url = url.replace('\{ext\}', API_KEY)
retval = url
if '?' in url:
retval = url + '&ApiKey={}'.format(self.API_KEY)
else:
retval = url + '?ApiKey={}'.format(self.API_KEY)
return retval
def get_cities(self):
url = self._build_url(
'http://api.alemtat.kz/web/{ext}/Catalog/getCitiesByCountry?CountryLocalCode={}'.format(self.COUNTRY_CODE, ext=self.API_KEY))
r = requests.get(url)
return r.json()
def get_cities_tuple(self):
retval = map(lambda cities: (cities['LocalCode'], '{} - {}'.format(cities['LocalityName'].title(), cities[
'Region'].capitalize())), self.get_cities())
return tuple(retval)
def get_services(self):
url = self._build_url(
'http://api.alemtat.kz/web/{ext}/Catalog/getServices'.format(ext=self.API_KEY))
r = requests.get(url)
return r.json()
def get_services_tuple(self):
retval = map(lambda services: (services['LocalCode'], services['Name'],), self.get_services())
return tuple(retval)
# def get_services_tuple(self):
# retval = map(lambda cities: (cities['LocalCode'], '{} - {}'.format(cities['LocalityName'].title(), cities[
# 'Region'].capitalize())), self.get_cities())
# return tuple(retval)
def get_amount(self, to, places, weight, service):
url = self._build_url(
'http://api.alemtat.kz/web/{ext}/Calc/getAmount'.format(ext=self.API_KEY))
post_data = dict(
FromCountryCode=self.COUNTRY_CODE,
FromLocalCode=self.CITY_CODE,
ToCountryCode=self.COUNTRY_CODE,
ToLocalCode=to,
ServiceLocalCode=service,
Places=places,
Weight=weight,
Contract=self.CONTRACT,
)
r = requests.post(url, data=post_data)
return r.json()
def alemtat_get_cities_tuple():
a = AlemTat()
return a.get_cities_tuple()
def alemtat_get_services_tuple():
a = AlemTat()
return a.get_services_tuple()

@ -21,6 +21,7 @@ class Cart(object):
items = [] items = []
json_items = [] json_items = []
total = 0 total = 0
weight = 0.1
items_format = {'items': [], 'total': 0} items_format = {'items': [], 'total': 0}
def __init__(self, request): def __init__(self, request):
@ -37,11 +38,13 @@ class Cart(object):
def deserialize_items(self): def deserialize_items(self):
for j in self.json_items['items']: for j in self.json_items['items']:
variation = ProductVariation.objects.get(
pk=j['product'])
item = CartItem( item = CartItem(
ProductVariation.objects.get( variation, j['count'], j['id'])
pk=j['product']), j['count'], j['id'])
self.items.append(item) self.items.append(item)
self.total += int(item.subtotal) self.total += int(item.subtotal)
self.weight += variation.weight
return self return self
def serialize_items(self): def serialize_items(self):

@ -0,0 +1,9 @@
from django import forms
from store.alemtat import alemtat_get_services_tuple
from store.models import OrderData
class OrderForm(forms.ModelForm):
class Meta:
model = OrderData
fields = ['first_name', 'last_name', 'phone', 'email', 'city', 'address', 'deliv_type']

File diff suppressed because one or more lines are too long

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('store', '0013_auto_20150611_2306'),
]
operations = [
migrations.AddField(
model_name='orderdata',
name='deliv_type',
field=models.CharField(verbose_name='Способ доставки', choices=[('E', 'Экспресс-отправления по РК'), ('T', 'Не срочные отправления по РК'), ('A', 'Автоконсолидация по РК'), ('C', 'Доставка по городу')], max_length=2, default=''),
),
migrations.AlterField(
model_name='orderdata',
name='address',
field=models.CharField(verbose_name='Адрес', max_length=100),
),
]

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('store', '0014_auto_20150612_0050'),
]
operations = [
migrations.AddField(
model_name='orderdata',
name='items',
field=models.CharField(default='', verbose_name='Товары', max_length=256),
),
]

@ -2,6 +2,7 @@ from django.db import models
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from decimal import * from decimal import *
from django.db.models import Count, Min from django.db.models import Count, Min
from store.alemtat import alemtat_get_cities_tuple, alemtat_get_services_tuple
FIELD_TYPE_CHAR = 'char' FIELD_TYPE_CHAR = 'char'
FIELD_TYPE_INT = 'int' FIELD_TYPE_INT = 'int'
@ -202,6 +203,8 @@ class ProductVariation(models.Model):
'В наличии (шт.)', default=1, null=False, blank=False) 'В наличии (шт.)', default=1, null=False, blank=False)
article = models.CharField( 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)
#weight = models.FloatField('Вес (кг)', default=0.1, null=False, blank=False)
class Meta: class Meta:
verbose_name = 'разновидность товара' verbose_name = 'разновидность товара'
@ -244,3 +247,22 @@ class ImageInProduct(models.Model):
class Meta: class Meta:
verbose_name = 'фото товара' verbose_name = 'фото товара'
verbose_name_plural = 'фото товаров' verbose_name_plural = 'фото товаров'
class OrderData(models.Model):
first_name = models.CharField(
'Имя', max_length=64, blank=False, null=False)
last_name = models.CharField(
'Фамилия', max_length=64, blank=False, null=False)
phone = models.CharField(
'Телефон', max_length=15, blank=False, null=False)
email = models.EmailField(
'Email', blank=False, null=False)
city = models.CharField(
'Город', max_length=20, blank=False, null=False, choices=alemtat_get_cities_tuple())
address = models.CharField(
'Адрес', max_length=100, blank=False, null=False)
deliv_type = models.CharField(
'Способ доставки', max_length=2, blank=False, null=False, default='', choices=alemtat_get_services_tuple())
items = models.CharField(
'Товары', max_length=256, blank=False, null=False, default='')

@ -7,6 +7,7 @@ urlpatterns = patterns('',
url='/', permanent=True), name='store_index'), url='/', permanent=True), name='store_index'),
url(r'^cart/$', CartDetailView.as_view(), url(r'^cart/$', CartDetailView.as_view(),
name='store_cart_detail'), name='store_cart_detail'),
url(r'^cart/add/$', CartAddView.as_view( url(r'^cart/add/$', CartAddView.as_view(
permanent=False), name='store_cart_add'), permanent=False), name='store_cart_add'),
url(r'^cart/remove/$', CartRemoveView.as_view( url(r'^cart/remove/$', CartRemoveView.as_view(

@ -1,11 +1,14 @@
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect, render
from django.views.generic import * from django.views.generic import *
from batiskaf.jinja2_ext.html_filters import escape from batiskaf.jinja2_ext.html_filters import escape
from .models import * from .models import *
from store.alemtat import AlemTat
from store.cart import Cart, CartItem from store.cart import Cart, CartItem
from django.contrib import messages from django.contrib import messages
from store.forms import OrderForm
from django.http import JsonResponse
from datetime import datetime
class CategoryBaseView(object): class CategoryBaseView(object):
category = None category = None
@ -165,9 +168,45 @@ class CartDetailView(TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
retval = super(CartDetailView, self).get_context_data() retval = super(CartDetailView, self).get_context_data()
retval['cart'] = Cart(self.request) retval['cart'] = Cart(self.request)
retval['form'] = OrderForm(self.request.POST or None)
#retval['form_delivs'] = DelivsForm()
return retval return retval
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
cart = Cart(self.request) cart = Cart(self.request)
cart.update_items() cart.update_items()
if 'order_next' in self.request.POST:
form = OrderForm(self.request.POST)
if form.is_valid():
order = form.save()
json_items = map(lambda items: {items.item.pk: items.count}, cart.items)
order.items = str(list(json_items))
order.save()
else:
return self.render_to_response(self.get_context_data())
return redirect(self.request.path) return redirect(self.request.path)
def get_order_amount(request):
retval = None
a = AlemTat()
cart = Cart(request)
retval = dict(a.get_amount(
request.GET['city'],
len(cart.items),
cart.weight,
request.GET['deliv'],
))
return JsonResponse(retval)
def order_view(request, order):
order = get_object_or_404(OrderData, pk=order)
c = dict(order=order)
return render(request, 'order_ok.jinja', c)
def order_print(request, order):
order = get_object_or_404(OrderData, pk=order)
c = dict(order=order, date=datetime.now())
return render(request, 'order_print.jinja', c)
Loading…
Cancel
Save