parent
66b134174a
commit
1927e0047b
31 changed files with 810 additions and 100 deletions
@ -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) |
||||
|
||||
@ -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 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.views.generic import FormView |
||||
from .forms import * |
||||
|
||||
# Create your views here. |
||||
class LoginView(FormView): |
||||
form_class = LoginForm |
||||
template_name = 'accounts/login.jinja' |
||||
@ -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">×</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 %} |
||||
@ -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> |
||||
@ -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() |
||||
|
||||
@ -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), |
||||
), |
||||
] |
||||
Loading…
Reference in new issue