remotes/origin/artem
Gena 11 years ago
parent 5c1bf22146
commit 39c36eb223
  1. 2
      accounts/admin.py
  2. 36
      accounts/forms.py
  3. 24
      accounts/migrations/0003_auto_20150616_2302.py
  4. 4
      accounts/models.py
  5. 13
      accounts/urls.py
  6. 7
      accounts/utils.py
  7. 58
      accounts/views.py
  8. 2
      batiskaf/settings.py
  9. 52
      batiskaf/templates/jinja2/accounts/index.jinja
  10. 34
      batiskaf/templates/jinja2/accounts/login.jinja
  11. 37
      batiskaf/templates/jinja2/accounts/login_sms.jinja
  12. 55
      batiskaf/templates/jinja2/accounts/order_detail.jinja
  13. 23
      batiskaf/templates/jinja2/base.jinja
  14. 22
      batiskaf/templates/jinja2/cart_detail.jinja
  15. 21
      store/migrations/0019_orderdata_profile.py
  16. 25
      store/migrations/0020_auto_20150616_2302.py
  17. 19
      store/migrations/0021_orderdata_status.py
  18. 25
      store/models.py
  19. 39
      store/views.py

@ -58,7 +58,7 @@ class ProfileAdmin(UserAdmin):
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('phone', 'email', 'first_name', 'last_name', 'password1', 'password2')}
'fields': ('phone', 'email', 'first_name', 'last_name', 'password1', 'password2', 'temp_password')}
),
)
search_fields = ('phone', 'email',)

@ -1,4 +1,38 @@
from django import forms
from accounts.models import Profile
from random import randint
from accounts.utils import normalize_phone
class LoginForm(forms.Form):
phone = forms.CharField(label='Телефон', max_length=15)
phone = forms.CharField(label='Номер мобильного телефона', max_length=45, required=True)
def clean_phone(self):
data = normalize_phone(self.cleaned_data['phone'])
try:
profile = Profile.objects.get(phone=data)
profile.temp_password = randint(1000000, 9999999)
self.temp_password = profile.temp_password
profile.save()
except Profile.DoesNotExist:
raise forms.ValidationError("Вы еще не совершали покупки в нашем магазине")
return data
class LoginSmsForm(forms.Form):
sms = forms.IntegerField(label='Одноразовый пароль', required=True)
def clean_sms(self):
data = self.cleaned_data['sms']
phone = normalize_phone(self.phone)
try:
profile = Profile.objects.get(phone=phone, temp_password=data)
self.profile = profile
#profile.temp_password = randint(1000000, 9999999)
#self.temp_password = profile.temp_password
#profile.save()
except Profile.DoesNotExist:
raise forms.ValidationError("Неверный одноразовый пароль")
return data

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('accounts', '0002_auto_20150611_2306'),
]
operations = [
migrations.AddField(
model_name='profile',
name='temp_password',
field=models.IntegerField(blank=True, null=True, verbose_name='Одноразовый пароль', default=None),
),
migrations.AlterField(
model_name='profile',
name='phone',
field=models.CharField(verbose_name='Номер мобильного телефона', max_length=15, unique=True, db_index=True),
),
]

@ -28,13 +28,15 @@ class ProfileManager(BaseUserManager):
class Profile(AbstractBaseUser):
phone = models.CharField('Телефон', max_length=15, unique=True, db_index=True)
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)
temp_password = models.IntegerField('Одноразовый пароль', default=None, blank=True, null=True)
USERNAME_FIELD = 'phone'
REQUIRED_FIELDS = ['email']

@ -3,8 +3,13 @@ from django.views.generic import RedirectView
from .views import *
urlpatterns = patterns('',
url(r'^$', RedirectView.as_view(
url='/', permanent=True), name='accounts_index'),
url(r'^login/$', LoginView.as_view(),
url(r'^$', account_index, name='accounts_index'),
url(r'^order/(?P<pk>\d+)/$', order_detail, name='account_order_detail'),
url(r'^login/$', login_view,
name='accounts_login'),
)
url(r'^login/sms/$', login_sms_view,
name='accounts_login_sms'),
url(r'^logout/$', account_logout,
name='accounts_logout'),
)

@ -0,0 +1,7 @@
import re
def normalize_phone(phone):
retval = re.sub("\D", "", phone)
if len(retval) > 10:
retval = retval[len(retval)-10:]
return retval

@ -1,7 +1,61 @@
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import FormView
from .forms import *
from store.models import OrderData
from django.contrib.auth import logout, authenticate, login
from .utils import normalize_phone
from random import randint
import requests
from django.conf import settings
class LoginView(FormView):
form_class = LoginForm
template_name = 'accounts/login.jinja'
template_name = 'accounts/login.jinja'
def login_view(request):
form = LoginForm(request.POST or None)
if form.is_valid():
phone = form.cleaned_data['phone']
params = dict(
login='Jango.kz',
psw='AcEMXtLGz042Fc1ZJUSl',
phones='7{}'.format(phone),
mes='Batiskaf.kz odnorazoviy parol: {}'.format(form.temp_password)
)
requests.get('http://smsc.ru/sys/send.php', params=params)
return redirect('/account/login/sms/?phone='+phone)
c = dict(form=form)
return render(request, 'accounts/login.jinja', c)
def login_sms_view(request):
form = LoginSmsForm(request.POST or None)
phone = request.GET.get('phone', None)
form.phone = phone
if form.is_valid():
profile = form.profile
profile.set_password(settings.PROFILE_TEMP_PASSWORD)
profile.save()
user = authenticate(username=profile.phone, password=settings.PROFILE_TEMP_PASSWORD)
if user.is_active:
login(request, user)
return redirect('/account/')
c = dict(form=form)
return render(request, 'accounts/login_sms.jinja', c)
@login_required
def account_index(request):
return render(request, 'accounts/index.jinja')
@login_required
def account_logout(request):
logout(request)
return redirect('/')
@login_required
def order_detail(request, pk):
order = get_object_or_404(OrderData, pk=pk, profile=request.user)
c = dict(order=order)
return render(request, 'accounts/order_detail.jinja', c)

@ -255,3 +255,5 @@ THUMBNAIL_PROCESSORS = (
'easy_thumbnails.processors.scale_and_crop',
'easy_thumbnails.processors.background',
)
PROFILE_TEMP_PASSWORD = 'dE6Hyo9heWck5yiM2dIs'

@ -0,0 +1,52 @@
{% extends 'base.jinja' %}
{% block title %}
Личный кабинет
{% endblock %}
{% block content %}
<div class=" breadcrumbs">
<ol class="breadcrumb breadcrumb-arrow">
<li><a href="/">Главная</a></li>
<li class="active"><span>Личный кабинет</span></li>
</ol>
</div>
<h2>Ваши заказы, {{ request.user.first_name }}:</h2>
<br/>
<div class="row">
<div class="col-xs-12">
<div class="panel">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>Номер заказа</th>
<th>Дата</th>
<th>Кому/Куда</th>
<th>Способ доставки</th>
<th>Сумма</th>
<th>Статус</th>
</tr>
</thead>
<tbody>
{% for order in request.user.orders.all() %}
<tr>
<td>{{ order.pk }}</td>
<td>{{ order.created.strftime('%d.%m.%Y') }}</td>
<td><a href="/account/order/{{ order.pk }}/"><b>{{ order.first_name }} {{ order.last_name }}</b><br/>
г. {{ order.get_city_display() }}<br/>
{{ order.address }}</a></td>
<td>{{ order.get_deliv_type_display() }}</td>
<td>{{ order.amount }}</td>
<td>{{ order.get_status_display() }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

@ -1,4 +1,36 @@
{% extends 'base.jinja' %}
{% block title %}
Вход в личный кабинет
{% endblock %}
{% block content %}
{{ form }}
<div class=" breadcrumbs">
<ol class="breadcrumb breadcrumb-arrow">
<li><a href="/">Главная</a></li>
<li class="active"><span>Вход в личный кабинет</span></li>
</ol>
</div>
<h2>Вход в личный кабинет</h2><br/>
<div class="well well-large">
<div class="alert alert-info alert-dismissable">
<h4>Введите номер телефона</h4>
<p>Если вы уже совершали покупки в нашем интернет-магазине, на ваш номер телефона будет отправлено SMS-сообщение с одноразовым паролем для входа.</p>
</div>
<div class="row">
<div class="login-form col-xs-6 col-xs-offset-3">
<form action="" class="form" method="post"><input type="hidden" name="csrfmiddlewaretoken"
value="{{ csrf_token }}">
{{ form|bootstrap }}
<div class="form-group text-left">
<button type="submit" name="login-send" class="btn btn-primary">Далее
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

@ -0,0 +1,37 @@
{% extends 'base.jinja' %}
{% block title %}
Ввод одноразового пароля
{% endblock %}
{% block content %}
<div class=" breadcrumbs">
<ol class="breadcrumb breadcrumb-arrow">
<li><a href="/">Главная</a></li>
<li><a href="/account/login/">Вход в личный кабинет</a></li>
<li class="active"><span>Ввод одноразового пароля</span></li>
</ol>
</div>
<h2>Ввод одноразового пароля</h2><br/>
<div class="well well-large">
<div class="alert alert-info alert-dismissable">
<h4>Проверьте телефон</h4>
<p>На Ваш номер было отправлено SMS-сообщение с одноразовым паролем для входа. Введите его в поле ниже.</p>
</div>
<div class="row">
<div class="sms-form col-xs-6 col-xs-offset-3">
<form action="" class="form" method="post"><input type="hidden" name="csrfmiddlewaretoken"
value="{{ csrf_token }}">
{{ form|bootstrap }}
<div class="form-group text-left">
<button type="submit" name="sms-send" class="btn btn-primary">Войти
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

@ -0,0 +1,55 @@
{% extends 'base.jinja' %}
{% block title %}
Заказ номер {{ order.pk }}
{% endblock %}
{% block content %}
<div class=" breadcrumbs">
<ol class="breadcrumb breadcrumb-arrow">
<li><a href="/">Главная</a></li>
<li><a href="/account/">Личный кабинет</a></li>
<li class="active"><span>Заказ номер {{ order.pk }}</span></li>
</ol>
</div>
<h2>Заказ №{{ order.pk }}</h2>
<br/>
<div class="row">
<div class="panel ">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>Фото</th>
<th>Товар</th>
<th>Стоимость</th>
<th>Количество</th>
</tr>
</thead>
<tbody>
{% for item, count in order.get_items() %}
<tr>
<td class="text-center table-cart-image">
{% set im = item.product.main_image()|thumbnail("80x80") %}
<a href="{{ item.product.get_absolute_url() }}"><img src="/static/{{ im.url }}"
alt="{{ item.product.title }}"
title="{{ item.product.title }}"
class="img-thumbnail"/></a>
</td>
<td>
<a href="{{ item.product.get_absolute_url() }}">{{ item.product.title }}</a><br/>
<em>{{ item.variation }}</em>
</td>
<td class="text-right info">{{ item.get_price() }} ₸</td>
<td class="text-right">{{ count }} шт.
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}

@ -4,7 +4,8 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>{% block title %}Интернет-Магазин Батискаф-Казахстан{% endblock %} | Батискаф-Казахстан, Батискаф, Снаряжение для дайвинга, Снаряжение для подводной охоты, Интернет-Магазин снаряжения для дайвинга и подводной охоты</title>
<title>{% block title %}Интернет-Магазин Батискаф-Казахстан{% endblock %} | Батискаф-Казахстан, Батискаф, Снаряжение
для дайвинга, Снаряжение для подводной охоты, Интернет-Магазин снаряжения для дайвинга и подводной охоты</title>
<meta name="description" content="{% block meta_description %}{% endblock %}">
<meta name="author" content="Sitio.kz">
<link href='/static/favicon.ico?v=1' type='image/x-icon' rel='shortcut icon'/>
@ -82,7 +83,7 @@
<a href="mailto:admin@batiskaf-kz.kz"><span class="glyphicon glyphicon-envelope"
aria-hidden="true"></span> Написать нам</a> | <a
href="skype:batiskaf_kz?chat"><img
src="/static/img/skype.png" alt="Написать в Skype" title="Написать в Skype" width="20" height="20"/></a>
src="/static/img/skype.png" alt="Написать в Skype" title="Написать в Skype" width="20" height="20"/></a>
</div>
@ -92,7 +93,8 @@
<div class="container-fluid header-middle">
<div class="container">
<div class="logo-container">
<a href="/"><img src="/static/img/logo.png" alt="Батискаф-Казахстан" title="Батискаф-Казахстан" width="457" height="104"/></a>
<a href="/"><img src="/static/img/logo.png" alt="Батискаф-Казахстан" title="Батискаф-Казахстан" width="457"
height="104"/></a>
</div>
<div class="quick-access-container">
@ -102,10 +104,19 @@
</form>
<p class="small-welcome">Добро пожаловать в интернет-магазин Батискаф!</p>
<p class="quick-links"><a href="#">Мой аккаунт</a> | <a href="/news/">Новости</a> | <a href="/store/cart/">Моя
<p class="quick-links"><a href="/account/">Мой аккаунт</a> | <a href="/news/">Новости</a> | <a
href="/store/cart/">Моя
корзина {% if (request|cart).items|length > 0 %}
<span class="label label-success">{{ (request|cart).items|length }}</span>{% endif %}</a> | <a
href="#">Войти</a></p>
<span class="label label-success">{{ (request|cart).items|length }}</span>{% endif %}</a>
{% if request.user.is_authenticated() %}
| <a href="/account/logout/">Выйти</a>
{% else %}
| <a href="/account/login/">Войти</a>
{% endif %}
</p>
</div>
</div>
</div>

@ -1,6 +1,6 @@
{% extends 'base.jinja' %}
{% block title %}
Корзина товаров
Корзина товаров
{% endblock %}
{% block content %}
<div class=" breadcrumbs">
@ -35,7 +35,8 @@
<td class="text-center table-cart-image">
{% set im = item.item.product.main_image()|thumbnail("80x80") %}
<a href="{{ item.item.product.get_absolute_url() }}"><img src="/static/{{ im.url }}"
alt="{{ item.item.product.title }}" title="{{ item.item.product.title }}"
alt="{{ item.item.product.title }}"
title="{{ item.item.product.title }}"
class="img-thumbnail"/></a>
</td>
<td>
@ -59,15 +60,16 @@
<tfoot>
<tr>
<th colspan="5" class="text-left"><p class="text-right price-subtotal">
Стоимость товара: <span id="cart-itogo">{{ cart.total }}</span> ₸ <br/>
Стоимость доставки: <span id="order-itogo-delivery-up">0</span> ₸
<br/>
Итого к оплате: <span id="order-itogo-amount-up">{{ cart.total }}</span> ₸
</p>
<p>
<a href="javascript:history.back()" class="">
&larr; Продолжить покупки</a>
Стоимость товара: <span id="cart-itogo">{{ cart.total }}</span> ₸ <br/>
Стоимость доставки: <span id="order-itogo-delivery-up">0</span> ₸
<br/>
Итого к оплате: <span id="order-itogo-amount-up">{{ cart.total }}</span> ₸
</p>
<p>
<a href="javascript:history.back()" class="">
&larr; Продолжить покупки</a>
</p>
</th>
<th class="text-center">
<button type="submit" class="btn btn-primary"><span

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('store', '0018_auto_20150615_1130'),
]
operations = [
migrations.AddField(
model_name='orderdata',
name='profile',
field=models.ForeignKey(null=True, default=None, to=settings.AUTH_USER_MODEL),
),
]

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
('store', '0019_orderdata_profile'),
]
operations = [
migrations.AlterField(
model_name='orderdata',
name='phone',
field=models.CharField(verbose_name='Номер мобильного телефона', max_length=15),
),
migrations.AlterField(
model_name='orderdata',
name='profile',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, related_name='orders', null=True, default=None),
),
]

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('store', '0020_auto_20150616_2302'),
]
operations = [
migrations.AddField(
model_name='orderdata',
name='status',
field=models.IntegerField(verbose_name='Статус', choices=[(0, 'Ожидает оплаты'), (1, 'Формирование посылки'), (2, 'Ожидает отправки'), (3, 'Отправлено')], default=0),
),
]

@ -2,6 +2,7 @@ from django.db import models
from django.contrib.postgres.fields import ArrayField
from decimal import *
from django.db.models import Count, Min
from accounts.models import Profile
from store.alemtat import alemtat_get_cities_tuple, alemtat_get_services_tuple
FIELD_TYPE_CHAR = 'char'
@ -208,7 +209,7 @@ class ProductVariation(models.Model):
article = models.CharField(
'Артикул', 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)
# weight = models.FloatField('Вес (кг)', default=0.1, null=False, blank=False)
class Meta:
verbose_name = 'разновидность товара'
@ -262,15 +263,23 @@ class ImageInProduct(models.Model):
return '{}: {}'.format(self.pk, self.product.title)
STATUS_CHOICES = (
(0, 'Ожидает оплаты'),
(1, 'Формирование посылки'),
(2, 'Ожидает отправки'),
(3, 'Отправлено'),
)
class OrderData(models.Model):
created = models.DateTimeField('Дата и время', auto_now_add=True, editable=False)
edited = models.DateTimeField('Изменено', auto_now=True, editable=False)
profile = models.ForeignKey(Profile, default=None, null=True, blank=False, related_name='orders')
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)
'Номер мобильного телефона', max_length=15, blank=False, null=False)
email = models.EmailField(
'Email', blank=False, null=False)
city = models.CharField(
@ -283,6 +292,7 @@ class OrderData(models.Model):
'Товары', max_length=256, blank=False, null=False, default='')
amount = models.FloatField(
'Сумма', blank=False, null=False, default=0.0)
status = models.IntegerField('Статус', default=0, null=False, blank=False, choices=STATUS_CHOICES)
class Meta:
verbose_name = 'заказ'
@ -295,3 +305,14 @@ class OrderData(models.Model):
self.amount
)
def get_status(self):
return 'Ожидает оплаты'
def get_items(self):
retval = ()
for item in eval(self.items):
variation_id = list(item.keys())[0]
variation_count = list(item.values())[0]
variation = ProductVariation.objects.get(pk=variation_id)
retval += ((variation, variation_count),)
return retval

@ -1,6 +1,9 @@
from django.contrib.auth import authenticate, login
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import get_object_or_404, redirect, render
from django.views.generic import *
from accounts.models import Profile
from accounts.utils import normalize_phone
from batiskaf.jinja2_ext.html_filters import escape
from .models import *
from store.alemtat import AlemTat
@ -9,6 +12,8 @@ from django.contrib import messages
from store.forms import OrderForm
from django.http import JsonResponse
from datetime import datetime
from django.conf import settings
class CategoryBaseView(object):
category = None
@ -126,7 +131,6 @@ class CategoryView(CategoryBaseView, TemplateView):
return retval
class ProductView(CategoryBaseView, DetailView):
model = Product
template_name = 'product.jinja'
@ -143,7 +147,6 @@ class ProductView(CategoryBaseView, DetailView):
class CartAddView(RedirectView):
def dispatch(self, request, *args, **kwargs):
retval = super(CartAddView, self).dispatch(request, args, kwargs)
cart = Cart(self.request)
@ -160,11 +163,11 @@ class CartAddView(RedirectView):
def get_redirect_url(self, *args, **kwargs):
from django.core.urlresolvers import reverse
return reverse('store_cart_detail')
class CartRemoveView(RedirectView):
def dispatch(self, request, *args, **kwargs):
retval = super(CartRemoveView, self).dispatch(request, args, kwargs)
cart = Cart(self.request)
@ -183,7 +186,7 @@ class CartDetailView(TemplateView):
retval = super(CartDetailView, self).get_context_data()
retval['cart'] = Cart(self.request)
retval['form'] = OrderForm(self.request.POST or None)
#retval['form_delivs'] = DelivsForm()
# retval['form_delivs'] = DelivsForm()
return retval
def post(self, request, *args, **kwargs):
@ -204,14 +207,38 @@ class CartDetailView(TemplateView):
cart.weight,
order.deliv_type,
))
order.phone = normalize_phone(order.phone)
order.amount = order_amount['AmountPlusFSAmount'] + cart.total
profile = None
try:
profile = Profile.objects.get(phone=normalize_phone(order.phone))
profile.set_password(settings.PROFILE_TEMP_PASSWORD)
profile.save()
except:
profile = Profile.objects.create(
phone=normalize_phone(order.phone),
email=order.email,
first_name=order.first_name,
last_name=order.last_name,
)
profile.set_password(settings.PROFILE_TEMP_PASSWORD)
profile.save()
user = authenticate(username=profile.phone, password=settings.PROFILE_TEMP_PASSWORD)
if user.is_active:
login(request, user)
order.profile = profile
order.save()
return redirect('/order/{}/'.format(order.pk))
else:
return self.render_to_response(self.get_context_data())
return redirect(self.request.path)
def get_order_amount(request):
retval = None
a = AlemTat()
@ -225,12 +252,14 @@ def get_order_amount(request):
return JsonResponse(retval)
def order_view(request, order):
order = get_object_or_404(OrderData, pk=order)
c = dict(order=order, date=datetime.now())
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)
return render(request, 'order_print.jinja', c)

Loading…
Cancel
Save