pep 8 tests fix

prod
Dmitriy Shesterkin 9 years ago
parent d381e491de
commit a3cf8dab08
  1. 2
      manage.py
  2. 4
      requirements/base.txt
  3. 20
      src/callback/models.py
  4. 11
      src/callback/urls.py
  5. 19
      src/commons/forms.py
  6. 2
      src/customer/managers.py
  7. 5
      src/customer/models.py
  8. 143
      src/customer/urls.py
  9. 2
      src/customer/views/bank_accounts.py
  10. 39
      src/customer/views/bank_accounts_ajax.py
  11. 66
      src/customer/views/license.py
  12. 66
      src/customer/views/profile.py
  13. 21
      src/customer/views/profile_ajax.py
  14. 28
      src/docs/admin.py
  15. 1
      src/docs/apps.py
  16. 2
      src/docs/as_xls/__init__.py
  17. 156
      src/docs/as_xls/render_to_xls.py
  18. 4
      src/docs/autocomplete_light_registry.py
  19. 130
      src/docs/consts.py
  20. 216
      src/docs/filters.py
  21. 21
      src/docs/forms/__init__.py
  22. 21
      src/docs/forms/aktsverki.py
  23. 21
      src/docs/forms/dover.py
  24. 36
      src/docs/forms/email.py
  25. 3
      src/docs/forms/invoice.py
  26. 3
      src/docs/forms/nakladn.py
  27. 44
      src/docs/forms/platejka.py
  28. 16
      src/docs/models/__init__.py
  29. 69
      src/docs/models/aktsverki.py
  30. 85
      src/docs/models/base_models.py
  31. 39
      src/docs/models/dover.py
  32. 46
      src/docs/models/faktura.py
  33. 22
      src/docs/models/invoice.py
  34. 4
      src/docs/models/linked_docs_mixin.py
  35. 21
      src/docs/models/mixins.py
  36. 12
      src/docs/models/nakladn.py
  37. 97
      src/docs/models/platejka.py
  38. 16
      src/docs/tests.py
  39. 83
      src/docs/urls.py
  40. 4
      src/docs/utils.py
  41. 19
      src/docs/views/__init__.py
  42. 54
      src/docs/views/base_views.py
  43. 5
      src/docs/views/dover.py
  44. 29
      src/docs/views/invoice.py
  45. 30
      src/docs/views/nakladn.py
  46. 37
      src/docs/views/platejka.py
  47. 2
      src/dokumentor/__init__.py
  48. 2
      src/dokumentor/celery.py
  49. 3
      src/dokumentor/settings/common.py
  50. 1
      src/dokumentor/settings/local.py
  51. 3
      src/dokumentor/settings/production.py
  52. 3
      src/dokumentor/settings/stage.py
  53. 2
      src/dokumentor/settings/testing.py
  54. 21
      src/dokumentor/urls.py
  55. 2
      src/dokumentor/wsgi.py
  56. 3
      src/myauth/admin.py
  57. 2
      src/myauth/apps.py
  58. 130
      src/myauth/forms.py
  59. 14
      src/myauth/managers.py
  60. 27
      src/myauth/models.py
  61. 5
      src/myauth/tasks.py
  62. 6
      src/myauth/urls.py
  63. 15
      src/myauth/views.py
  64. 3
      src/pages/models.py
  65. 16
      src/pages/tests.py
  66. 1
      src/pages/views.py
  67. 2
      src/yandex_money/apps.py
  68. 4
      src/yandex_money/forms.py
  69. 6
      src/yandex_money/urls.py
  70. 4
      tox.ini

@ -9,8 +9,6 @@ if __name__ == "__main__":
env_file = p.normpath(p.join(p.abspath(p.dirname(__file__)), "./conf/env"))
env.load(env_file)
print(env_file)
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

@ -71,7 +71,7 @@ django-redis==4.8.0
redis==2.10.5
trans==2.1.0
python-decouple==3.0
flake8==3.2.1
flake8==3.3.0
numpy==1.13.0
mock==2.0.0
mockredispy==2.9.3
@ -82,3 +82,5 @@ django-test-plus==1.0.17
Faker==0.7.15
coverage==4.4.1
pytest-flake8==0.8.1
pycodestyle==2.3.1
pyflakes==1.5.0

@ -16,10 +16,24 @@ class ReqAvail(models.Model):
name = models.CharField(u'Имя клиента', max_length=100)
phone = models.CharField(u'Телефон или e-mail', max_length=50)
message = models.TextField(u'Текст сообщения')
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='messages', null=True, blank=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='messages',
null=True,
blank=True
)
status = models.PositiveSmallIntegerField(u'Статус', choices=STATUS_CHOICES, default=NEW_STATUS)
status_changed = models.DateTimeField(u'Статус изменен', null=True, blank=True, editable=False)
status = models.PositiveSmallIntegerField(
u'Статус',
choices=STATUS_CHOICES,
default=NEW_STATUS
)
status_changed = models.DateTimeField(
u'Статус изменен',
null=True,
blank=True,
editable=False
)
created_at = models.DateTimeField(u'Дата заказа', auto_now_add=True)
updated_at = models.DateTimeField(u'Изменен', auto_now=True)

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
from django.conf.urls import url
from callback.views import req_avail
urlpatterns = patterns('',
url(r'^send/$', req_avail, name='callback-send-message'),
url(r'^send/(?P<id>\d+)/$', req_avail, name='callback-request-item'),
)
urlpatterns = [
url(r'^send/$', req_avail, name='callback-send-message'),
url(r'^send/(?P<id>\d+)/$', req_avail, name='callback-request-item'),
]

@ -4,9 +4,12 @@ import autocomplete_light
def set_field_error(form, field, msg=u'Обязательное поле.'):
"""Добавить сообщение об ошибке поля и убрать это поле из списка успешно прошедших валидацию.
"""
Добавить сообщение об ошибке поля и убрать это поле из списка
успешно прошедших валидацию.
Полезно, если нужно инвалидировать поле из метода clean() и добавить ему ошибку.
В этом случае исключение forms.ValidationError() не подходит, т.к. оно добавит сообщение об ошибке в ошибки формы.
В этом случае исключение forms.ValidationError() не подходит,
т.к. оно добавит сообщение об ошибке в ошибки формы.
"""
form._errors[field] = form.error_class([msg])
if field in form.cleaned_data:
@ -16,18 +19,22 @@ def set_field_error(form, field, msg=u'Обязательное поле.'):
class _MySuperForm(object):
"""Базовая форма. Добавляет всякого полезного функционала к форме."""
# Список условно-обязательных полей, у которых нужно установить атрибут required=False.
# Полезно, когда какие-то поля становятся обязательны к заполнению в зависимости от значения других полей.
# Список условно-обязательных полей, у которых нужно установить
# атрибут required=False.
# Полезно, когда какие-то поля становятся обязательны к заполнению
# в зависимости от значения других полей.
# TODO мигрировать на unset_required
conditional_fields = []
# Список полей, у которых нужно сбросить признак обязательности: required=False.
# Полезно, когда в базовой форме определяются какие-то поля, которые в одних унаследованных формах обязательны,
# Полезно, когда в базовой форме определяются какие-то поля, которые в одних
# унаследованных формах обязательны,
# а в других нет.
unset_required = []
# Словарь полей, у которых нужно заменить атрибут label.
# Полезно, когда нужно дать разные метки полям в админке и в форме, с которой работает пользователь.
# Полезно, когда нужно дать разные метки полям в админке и в форме,
# с которой работает пользователь.
change_labels = {}
def __init__(self, *args, **kwargs):

@ -64,7 +64,7 @@ class BankAccountManager(models.Manager):
if not self.have_main(company=company):
try:
accounts = self.get_all(company=company)[0]
accounts.is_main=True
accounts.is_main = True
accounts.save()
except IndexError:
pass

@ -254,7 +254,7 @@ class UserProfile(models.Model):
def check_main_reqs_not_filled(self):
result = self.check_name_not_filled() or self.inn == '' or self.address == '' or \
self.get_boss_fio() == '' or self.get_main_bank_account() == ''
self.get_boss_fio() == '' or self.get_main_bank_account() == '' # noqa
if result:
return True
@ -524,7 +524,8 @@ class UserProfileFilters(models.Model):
show_name = models.BooleanField(u'Краткое название организации', default=True)
show_full_name = models.BooleanField(u'Полное название организации', default=True)
show_kpp = models.BooleanField(u'КПП', default=True)
show_org_boss_title_and_fio = models.BooleanField(u'Руководитель (Должность, ФИО)', default=True)
show_org_boss_title_and_fio = models.BooleanField(
u'Руководитель (Должность, ФИО)', default=True)
show_na_osnovanii = models.BooleanField(u'Действует на основании', default=True)
objects = managers.UserProfileFiltersManager()

@ -1,86 +1,85 @@
# -*- coding: utf-8 -*-
from django.conf.urls import *
from django.conf.urls import url
from customer import views
from customer.views import profile, profile_ajax, license, documents
from customer.views import bank_accounts, bank_accounts_ajax
from customer.views import clients, clients_ajax
urlpatterns = \
patterns('',
# личный кабинет
url(r'^$', views.customer_index, name='customer_index'),
urlpatterns = [
# личный кабинет
url(r'^$', views.customer_index, name='customer_index'),
# --- профиль
url(r'^profile/$', profile.profile_view, name='customer_profile_view'),
url(r'^profile/edit/$', profile.profile_edit, name='customer_profile_edit'),
url(r'^profile/email/$', profile.profile_email, name='customer_profile_email'),
url(r'^license/$', license.order_license, name='customer_order_license'),
url(r'^delete_license/(?P<pk>\d+)/$', license.delete_license,
name='customer_delete_license'),
url(r'^get_doc/(?P<order_num>\d+)/$', documents.get_doc,
name='customer_license_get_doc'),
url(r'^payment/confirm/(?P<payment_id>\d+)$', license.yandex_pay,
name='yamoney_confirm'),
url(r'^payment/result/$', license.payment_result, name='yamoney_result'),
url(r'^payment/success/$', license.payment_success, name='yamoney_success'),
url(r'^payment/fail/$', license.payment_fail, name='yamoney_fail'),
url(r'^license_list/$', license.license_list, name='customer_license_list'),
url(r'^paid_list/$', license.paid_list, name='customer_paid_list'),
# --- профиль
url(r'^profile/$', profile.profile_view, name='customer_profile_view'),
url(r'^profile/edit/$', profile.profile_edit, name='customer_profile_edit'),
url(r'^profile/email/$', profile.profile_email, name='customer_profile_email'),
url(r'^license/$', license.order_license, name='customer_order_license'),
url(r'^delete_license/(?P<pk>\d+)/$', license.delete_license,
name='customer_delete_license'),
url(r'^get_doc/(?P<order_num>\d+)/$', documents.get_doc,
name='customer_license_get_doc'),
url(r'^payment/confirm/(?P<payment_id>\d+)$', license.yandex_pay,
name='yamoney_confirm'),
url(r'^payment/result/$', license.payment_result, name='yamoney_result'),
url(r'^payment/success/$', license.payment_success, name='yamoney_success'),
url(r'^payment/fail/$', license.payment_fail, name='yamoney_fail'),
url(r'^license_list/$', license.license_list, name='customer_license_list'),
url(r'^paid_list/$', license.paid_list, name='customer_paid_list'),
# --- профиль AJAX
url(r'^profile/filters/edit/ajax/$', profile_ajax.profile_filters_edit_ajax,
name='customer_profile_filters_edit_ajax'),
url(r'^profile/email/ajax/$', profile_ajax.profile_email_ajax,
name='customer_profile_email_ajax'),
# --- профиль AJAX
url(r'^profile/filters/edit/ajax/$', profile_ajax.profile_filters_edit_ajax,
name='customer_profile_filters_edit_ajax'),
url(r'^profile/email/ajax/$', profile_ajax.profile_email_ajax,
name='customer_profile_email_ajax'),
# --- расчетные счета
url(r'^bank-accounts/$', bank_accounts.bank_accounts_list,
name='customer_bank_accounts_list'),
url(r'^bank-accounts/page/(?P<page_num>[0-9]+)/$', bank_accounts.bank_accounts_list,
name='customer_bank_accounts_list'),
url(r'^bank-accounts/add/$', bank_accounts.bank_accounts_add,
name='customer_bank_accounts_add'),
url(r'^bank-accounts/(?P<id>\d+)/edit/$', bank_accounts.bank_accounts_edit,
name='customer_bank_accounts_edit'),
url(r'^bank-accounts/(?P<id>\d+)/delete/$', bank_accounts.bank_accounts_delete,
name='customer_bank_accounts_delete'),
# --- расчетные счета
url(r'^bank-accounts/$', bank_accounts.bank_accounts_list,
name='customer_bank_accounts_list'),
url(r'^bank-accounts/page/(?P<page_num>[0-9]+)/$', bank_accounts.bank_accounts_list,
name='customer_bank_accounts_list'),
url(r'^bank-accounts/add/$', bank_accounts.bank_accounts_add,
name='customer_bank_accounts_add'),
url(r'^bank-accounts/(?P<id>\d+)/edit/$', bank_accounts.bank_accounts_edit,
name='customer_bank_accounts_edit'),
url(r'^bank-accounts/(?P<id>\d+)/delete/$', bank_accounts.bank_accounts_delete,
name='customer_bank_accounts_delete'),
# --- расчетные счета AJAX
url(r'^bank-accounts/ajax/$', bank_accounts_ajax.bank_accounts_list_ajax,
name='customer_bank_accounts_list_ajax'),
url(r'^bank-accounts/(?P<id>\d+)/get/ajax/$',
bank_accounts_ajax.bank_accounts_get_ajax,
name='customer_bank_accounts_get_ajax'),
url(r'^bank-accounts/add/ajax/$', bank_accounts_ajax.bank_accounts_add_ajax,
name='customer_bank_accounts_add_ajax'),
url(r'^bank-accounts/(?P<id>\d+)/edit/ajax/$',
bank_accounts_ajax.bank_accounts_edit_ajax,
name='customer_bank_accounts_edit_ajax'),
url(r'^bank-accounts/(?P<id>\d+)/delete/ajax/$',
bank_accounts_ajax.bank_accounts_delete_ajax,
name='customer_bank_accounts_delete_ajax'),
# --- расчетные счета AJAX
url(r'^bank-accounts/ajax/$', bank_accounts_ajax.bank_accounts_list_ajax,
name='customer_bank_accounts_list_ajax'),
url(r'^bank-accounts/(?P<id>\d+)/get/ajax/$',
bank_accounts_ajax.bank_accounts_get_ajax,
name='customer_bank_accounts_get_ajax'),
url(r'^bank-accounts/add/ajax/$', bank_accounts_ajax.bank_accounts_add_ajax,
name='customer_bank_accounts_add_ajax'),
url(r'^bank-accounts/(?P<id>\d+)/edit/ajax/$',
bank_accounts_ajax.bank_accounts_edit_ajax,
name='customer_bank_accounts_edit_ajax'),
url(r'^bank-accounts/(?P<id>\d+)/delete/ajax/$',
bank_accounts_ajax.bank_accounts_delete_ajax,
name='customer_bank_accounts_delete_ajax'),
# --- контрагенты
url(r'^clients/$', clients.clients_list, name='customer_clients_list'),
url(r'^clients/page/(?P<page_num>[0-9]+)/$', clients.clients_list,
name='customer_clients_list'),
url(r'^clients/add/$', clients.clients_add, name='customer_clients_add'),
url(r'^clients/(?P<id>\d+)/edit/$', clients.clients_edit,
name='customer_clients_edit'),
url(r'^clients/(?P<id>\d+)/delete/$', clients.clients_delete,
name='customer_clients_delete'),
# --- контрагенты
url(r'^clients/$', clients.clients_list, name='customer_clients_list'),
url(r'^clients/page/(?P<page_num>[0-9]+)/$', clients.clients_list,
name='customer_clients_list'),
url(r'^clients/add/$', clients.clients_add, name='customer_clients_add'),
url(r'^clients/(?P<id>\d+)/edit/$', clients.clients_edit,
name='customer_clients_edit'),
url(r'^clients/(?P<id>\d+)/delete/$', clients.clients_delete,
name='customer_clients_delete'),
# --- контрагенты AJAX
url(r'^clients/(?P<id>\d+)/get/ajax/$', clients_ajax.clients_get_ajax,
name='customer_clients_get_ajax'),
url(r'^clients/add/ajax/$', clients_ajax.clients_add_ajax,
name='customer_clients_add_ajax'),
url(r'^clients/(?P<id>\d+)/edit/ajax/$', clients_ajax.clients_edit_ajax,
name='customer_clients_edit_ajax'),
url(r'^clients/(?P<id>\d+)/delete/ajax/$', clients_ajax.clients_delete_ajax,
name='customer_clients_delete_ajax'),
# --- контрагенты AJAX
url(r'^clients/(?P<id>\d+)/get/ajax/$', clients_ajax.clients_get_ajax,
name='customer_clients_get_ajax'),
url(r'^clients/add/ajax/$', clients_ajax.clients_add_ajax,
name='customer_clients_add_ajax'),
url(r'^clients/(?P<id>\d+)/edit/ajax/$', clients_ajax.clients_edit_ajax,
name='customer_clients_edit_ajax'),
url(r'^clients/(?P<id>\d+)/delete/ajax/$', clients_ajax.clients_delete_ajax,
name='customer_clients_delete_ajax'),
url(r'^tmp_upload/ajax/$', profile.tmp_upload, name='upload_tmp_file'),
url(r'^upload-image/ajax/$', profile.upload_image, name='upload-image'),
)
# url(r'^tmp_upload/ajax/$', profile.tmp_upload, name='upload_tmp_file'),
url(r'^upload-image/ajax/$', profile.upload_image, name='upload-image'),
]

@ -28,7 +28,7 @@ def bank_accounts_add(request):
"""Добавить расчетный счет."""
raise_if_no_profile(request)
template_name='customer/bank_accounts/add.html'
template_name = 'customer/bank_accounts/add.html'
form_class = forms.BankAccountForm
success_url = 'customer_bank_accounts_list'

@ -8,11 +8,10 @@ from django.views.decorators.csrf import csrf_protect
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from docs.models import Invoice, Faktura, AktRabot, AktSverki, Nakladn, Platejka, Dover
from docs.models import Invoice, Faktura, AktRabot, Nakladn, Platejka
from commons.utils import dthandler
from .. import models, forms
from ..decorators import license_required
from ..utils import raise_if_no_profile
@ -81,12 +80,14 @@ def bank_accounts_add_ajax(request):
non_field_errors = form.non_field_errors()
if not form.is_valid():
non_field_errors.append(u'Заполните/исправьте выделенные поля.')
non_field_errors.append('Заполните/исправьте выделенные поля.')
data = {
'success': form.is_valid(),
'field_errors': form.errors, # ошибки полей
'form_errors': non_field_errors, # ошибки формы
# ошибки полей
'field_errors': form.errors,
# ошибки формы
'form_errors': non_field_errors,
}
return HttpResponse(json.dumps(data), content_type='application/json')
@ -111,12 +112,14 @@ def bank_accounts_edit_ajax(request, id):
non_field_errors = form.non_field_errors()
if not form.is_valid():
non_field_errors.append(u'Заполните/исправьте выделенные поля.')
non_field_errors.append('Заполните/исправьте выделенные поля.')
data = {
'success': form.is_valid(),
'field_errors': form.errors, # ошибки полей
'form_errors': non_field_errors, # ошибки формы
# ошибки полей
'field_errors': form.errors,
# ошибки формы
'form_errors': non_field_errors,
}
return HttpResponse(json.dumps(data), content_type='application/json')
@ -136,27 +139,27 @@ def bank_accounts_delete_ajax(request, id):
account_docs = []
doc_list = [
(Invoice, u'счета'),
(Faktura, u'счета-фактуры'),
(Nakladn, u'накладные'),
(AktRabot, u'акты выполненных работ'),
(Platejka, u'платёжные поручения')
(Invoice, 'счета'),
(Faktura, 'счета-фактуры'),
(Nakladn, 'накладные'),
(AktRabot, 'акты выполненных работ'),
(Platejka, 'платёжные поручения')
]
for doc in doc_list:
docs = doc[0].objects.filter(bank_account=account)
print(docs)
if docs:
account_docs.append(doc[1])
if not account_docs:
account.delete()
success = True
message = {'title': u'Инфо',
'msg': u'Расчётный счёт удалён.'}
message = {'title': 'Инфо',
'msg': 'Расчётный счёт удалён.'}
del_id = id
else:
success = True
message = {'title': u'Инфо',
'msg': u'Расчтный счет не удалён. Есть выписанные документы: %s.' % ','.join(
message = {'title': 'Инфо',
'msg': 'Расчтный счет не удалён. Есть выписанные документы: %s.' % ','.join(
account_docs)}
del_id = None

@ -3,11 +3,9 @@ import json
import hashlib
from django.shortcuts import render, redirect
from django.http import Http404, HttpResponseRedirect, HttpResponseForbidden, HttpResponse, \
HttpResponseBadRequest
from django.http import (HttpResponseForbidden, HttpResponse, HttpResponseBadRequest)
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from django.utils.http import urlquote
from django.contrib.auth.decorators import login_required
from django.template.response import TemplateResponse
from django.core.urlresolvers import reverse
@ -16,7 +14,6 @@ from django.views.decorators.csrf import csrf_protect
from yandex_money.models import Payment
from customer.models import License, LicensePrice
from customer.consts import PAYFORMS
from customer.forms import LicenseForm, YaForm
from customer.utils import raise_if_no_profile
@ -41,29 +38,29 @@ def order_license(request):
raise_if_no_profile(request)
template_name = 'customer/profile/license.html'
form = LicenseForm(request.POST or None,
initial = {'term': LicensePrice.objects.all()[1], 'payform': 0})
dictionary = {
'form': form,
}
form = LicenseForm(
request.POST or None,
initial={'term': LicensePrice.objects.all()[1], 'payform': 0}
)
dictionary = {'form': form}
if form.is_valid():
new_license = License(company=request.user.profile,
term=form.cleaned_data['term'].term,
payform=form.cleaned_data['payform'],
pay_sum=form.cleaned_data['term'].price,
)
new_license = License(
company=request.user.profile,
term=form.cleaned_data['term'].term,
payform=form.cleaned_data['payform'],
pay_sum=form.cleaned_data['term'].price
)
new_license.save()
if form.cleaned_data['payform'] == '1':
payment, _ = Payment.objects.get_or_create(order_amount=form.cleaned_data['term'].
price,
payment_type=Payment.PAYMENT_TYPE.AC,
order_number=new_license.id,
)
payment.user=request.user
# payment.cps_email=request.user.email
payment.customer_number=request.user.email
# payment.customer_number=request.user.profile.get_company_name().strip()
payment, _ = Payment.objects.get_or_create(
order_amount=form.cleaned_data['term'].
price,
payment_type=Payment.PAYMENT_TYPE.AC,
order_number=new_license.id
)
payment.user = request.user
payment.customer_number = request.user.email
payment.save()
return redirect(reverse('yamoney_confirm', kwargs={'payment_id': payment.id}))
@ -71,6 +68,7 @@ def order_license(request):
return render(request, template_name, dictionary)
@login_required
def license_list(request):
"""Список счетов на лицензии
@ -80,9 +78,7 @@ def license_list(request):
template_name = 'customer/profile/license_list.html'
licenses = License.objects.filter(
company=request.user.profile, deleted=False, status__gt=-1).order_by('-id')
dictionary = {
'licenses': licenses,
}
dictionary = {'licenses': licenses}
return render(request, template_name, dictionary)
@ -93,16 +89,17 @@ def paid_list(request):
raise_if_no_profile(request)
template_name = 'customer/profile/paid_list.html'
licenses = License.objects.filter(company=request.user.profile,
status__in=[-1, 1, 2, 3, 4], deleted=False).order_by('-id')
dictionary = {
'licenses': licenses,
}
licenses = License.objects.filter(
company=request.user.profile,
status__in=[-1, 1, 2, 3, 4],
deleted=False).order_by('-id')
dictionary = {'licenses': licenses}
return render(request, template_name, dictionary)
@login_required
def delete_license(request, pk):
dictionary = {}
if not request.is_ajax():
return HttpResponseBadRequest()
@ -147,8 +144,7 @@ def payment_result(request):
@csrf_exempt
def payment_success(request):
nInvId = request.GET.get('orderNumber')
order = License.objects.get(pk=nInvId)
# order = License.objects.get(pk=nInvId)
context = {'success': True, 'order_num': nInvId}
return TemplateResponse(request, 'customer/profile/end_order.html', context)
@ -156,7 +152,7 @@ def payment_success(request):
@csrf_exempt
def payment_fail(request):
try:
nInvId = request.GET.get('')
# nInvId = request.GET.get('')
message = u"Возникла проблема. Ваш Заказ не оплачен. " \
u"Попробуйте оформить заявку снова, или позвоните по номеру."
@ -165,5 +161,5 @@ def payment_fail(request):
request,
'customer/profile/end_order.html',
{'message': message, 'success': False})
except Order.DoesNotExist:
except:
return HttpResponseForbidden()

@ -23,7 +23,7 @@ from django.utils.encoding import smart_str
from django.conf import settings
from django.http import HttpResponse
from easy_thumbnails.files import get_thumbnailer
# from easy_thumbnails.files import get_thumbnailer
from commons.pdf_tools import render_pdf_to_string, pdf_to_response
@ -146,32 +146,32 @@ def profile_edit(request):
return render(request, template_name, dictionary)
def tmp_upload(request):
key = ''
SIZES = {'id_boss_sign': (170, 65),
'id_glavbuh_sign': (170, 65),
'id_stamp': (170, 170),
'id_logo': (170, 170)}
elm_id = request.REQUEST['elm_id']
for k in request.FILES.keys():
key = k
file_ = request.FILES.get(key)
if not file_.content_type.startswith('image'):
return {'res': 'bad'}
if not os.path.exists(settings.MEDIA_ROOT + '/cache/imgs/'):
os.makedirs(settings.MEDIA_ROOT + '/cache/imgs/')
tmp_dir = tempfile.mkdtemp('img_tmp', settings.MEDIA_ROOT + '/cache/imgs/')
os.chmod(tmp_dir, 755)
open(tmp_dir + '/' + file_.name, "wb+").write(file_.read())
tmp_url_partial = os.path.basename(tmp_dir) + '/' + file_.name
thumbnailer = get_thumbnailer(tmp_dir + '/' + file_.name)
thumbnail_options = {'size': SIZES[elm_id]}
# Возвращает в url полный путь, поэтому придётся резать
im = thumbnailer.get_thumbnail(thumbnail_options)
im_url = os.path.join(settings.MEDIA_URL, os.path.relpath(im.url, settings.MEDIA_ROOT))
data = {'res': 'ok', 'pic': im_url, 'full_pic': tmp_url_partial}
data.update(request.REQUEST)
return HttpResponse(json.dumps(data), content_type='application/json')
# def tmp_upload(request):
# key = ''
# SIZES = {'id_boss_sign': (170, 65),
# 'id_glavbuh_sign': (170, 65),
# 'id_stamp': (170, 170),
# 'id_logo': (170, 170)}
# elm_id = request.REQUEST['elm_id']
# for k in request.FILES.keys():
# key = k
# file_ = request.FILES.get(key)
# if not file_.content_type.startswith('image'):
# return {'res': 'bad'}
# if not os.path.exists(settings.MEDIA_ROOT + '/cache/imgs/'):
# os.makedirs(settings.MEDIA_ROOT + '/cache/imgs/')
# tmp_dir = tempfile.mkdtemp('img_tmp', settings.MEDIA_ROOT + '/cache/imgs/')
# os.chmod(tmp_dir, 755)
# open(tmp_dir + '/' + file_.name, "wb+").write(file_.read())
# tmp_url_partial = os.path.basename(tmp_dir) + '/' + file_.name
# thumbnailer = get_thumbnailer(tmp_dir + '/' + file_.name)
# thumbnail_options = {'size': SIZES[elm_id]}
# # Возвращает в url полный путь, поэтому придётся резать
# im = thumbnailer.get_thumbnail(thumbnail_options)
# im_url = os.path.join(settings.MEDIA_URL, os.path.relpath(im.url, settings.MEDIA_ROOT))
# data = {'res': 'ok', 'pic': im_url, 'full_pic': tmp_url_partial}
# data.update(request.REQUEST)
# return HttpResponse(json.dumps(data), content_type='application/json')
def save_file(path, file):
@ -188,12 +188,12 @@ def clean_background(file):
# np.asarray(img) is read only. Wrap it in np.array to make it modifiable.
arr = np.array(np.asarray(img))
r, g, b, a = np.rollaxis(arr, axis=-1)
mask = ((r > threshold)
& (g > threshold)
& (b > threshold)
& (np.abs(r - g) < dist)
& (np.abs(r - b) < dist)
& (np.abs(g - b) < dist)
mask = ((r > threshold) &
(g > threshold) &
(b > threshold) &
(np.abs(r - g) < dist) &
(np.abs(r - b) < dist) &
(np.abs(g - b) < dist)
)
arr[mask, 3] = 0
img = Image.fromarray(arr, mode='RGBA')

@ -1,16 +1,14 @@
# -*- coding: utf-8 -*-
import simplejson as json
from django.shortcuts import get_object_or_404
from django.http import HttpResponseBadRequest, HttpResponse, Http404
from django.http import HttpResponseBadRequest, HttpResponse
from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_protect
from django.contrib.auth.decorators import login_required
from customer import models, forms
from customer.decorators import license_required
from customer.views.profile import _send_profile_email, _profile_get_pdf
from customer.views.profile import (_send_profile_email, _profile_get_pdf)
from customer.utils import raise_if_no_profile
@ -31,7 +29,12 @@ def profile_filters_edit_ajax(request):
filters_form_class = forms.get_profile_filters_form_class(profile.profile_type)
filters = models.UserProfileFilters.objects.get_or_create_filters(user=request.user)
form = filters_form_class(data=request.POST, instance=filters, profile=profile, accounts=accounts)
form = filters_form_class(
data=request.POST,
instance=filters,
profile=profile,
accounts=accounts
)
if form.is_valid():
form.save()
@ -66,10 +69,10 @@ def profile_email_ajax(request):
form = form_class(data=request.POST)
if form.is_valid():
_send_profile_email(
subject = u'Реквизиты %s' % profile.get_company_name(),
to = form.cleaned_data['to'],
body = form.cleaned_data['body'],
pdf_content = _profile_get_pdf(request, profile, filters.bank_account, filters)
subject=u'Реквизиты %s' % profile.get_company_name(),
to=form.cleaned_data['to'],
body=form.cleaned_data['body'],
pdf_content=_profile_get_pdf(request, profile, filters.bank_account, filters)
)
non_field_errors = form.non_field_errors()

@ -4,57 +4,39 @@ from django.contrib import admin
from docs import models
#class InvoiceItemInline(admin.TabularInline):
# model = models.InvoiceItem
# extra = 0
class InvoiceAdmin(admin.ModelAdmin):
list_display = ('doc_num', 'doc_date', 'company', 'client',)
list_filter = ('doc_date',)
search_fields = ('company__name', 'company__inn', 'company__email',
'client__name', 'client__inn', 'client__contact_email')
#inlines = (InvoiceItemInline,)
#class NakladnItemInline(admin.TabularInline):
# model = models.NakladnItem
# extra = 0
'client__name', 'client__inn', 'client__contact_email')
class NakladnAdmin(admin.ModelAdmin):
list_display = ('doc_num', 'doc_date', 'company', 'client',)
list_filter = ('doc_date',)
search_fields = ('company__name', 'company__inn', 'company__email',
'client__name', 'client__inn', 'client__contact_email')
#inlines = (NakladnItemInline,)
#class AktRabotItemInline(admin.TabularInline):
# model = models.AktRabotItem
# extra = 0
'client__name', 'client__inn', 'client__contact_email')
class AktRabotAdmin(admin.ModelAdmin):
list_display = ('doc_num', 'doc_date', 'company', 'client',)
list_filter = ('doc_date',)
search_fields = ('company__name', 'company__inn', 'company__email',
'client__name', 'client__inn', 'client__contact_email')
#inlines = (AktRabotItemInline,)
'client__name', 'client__inn', 'client__contact_email')
class FakturaAdmin(admin.ModelAdmin):
list_display = ('doc_num', 'doc_date', 'company', 'client',)
list_filter = ('doc_date',)
search_fields = ('company__name', 'company__inn', 'company__email',
'client__name', 'client__inn', 'client__contact_email')
'client__name', 'client__inn', 'client__contact_email')
class PlatejkaAdmin(admin.ModelAdmin):
list_display = ('doc_num', 'doc_date', 'company', 'client',)
list_filter = ('doc_date',)
search_fields = ('doc_info', 'company__name', 'company__inn', 'company__email',
'client__name', 'client__inn', 'client__contact_email')
'client__name', 'client__inn', 'client__contact_email')
class MeasureAdmin(admin.ModelAdmin):

@ -5,4 +5,3 @@ from django.apps import AppConfig
class DocConfig(AppConfig):
name = 'docs'
verbose_name = 'Документы'

@ -1 +1 @@
from .render_to_xls import render_xls_to_string
from .render_to_xls import render_xls_to_string # noqa

@ -8,11 +8,11 @@ import xlwt
from django.conf import settings
from django.template import Template, RequestContext
from django.template.base import BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END
from commons.xls import (get_xlwt_style_list, copy_cells, width_cols, horz_page_break, mm_to_twips,
sum_src_heights, sum_dst_heights)
from django.template.base import BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, \
VARIABLE_TAG_END
from commons.xls import (get_xlwt_style_list, copy_cells, width_cols,
horz_page_break, mm_to_twips, sum_src_heights, sum_dst_heights)
TAG_RE = re.compile('(%s.*?%s|%s.*?%s)' % (
re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
@ -35,7 +35,7 @@ def render_xls_to_string(request, xls_template, dictionary=None):
try:
# откуда
src_book = xlrd.open_workbook(src_xls, encoding_override='cp1251',
on_demand=True, formatting_info=True)
on_demand=True, formatting_info=True)
src_sheet = src_book.sheet_by_index(0)
# достать список стилей
@ -50,8 +50,7 @@ def render_xls_to_string(request, xls_template, dictionary=None):
apply_page_settings(dst_sheet, xls_settings)
# import ipdb;ipdb.set_trace()
# заполнить данными
fill_xls(request, dictionary, src_sheet, dst_sheet, style_list,
xls_settings)
fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings)
# закрыть исходную книгу и сохранить созданную
src_book.release_resources()
@ -73,8 +72,6 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
context = RequestContext(request, dictionary)
# -------------------------------------------------------------------------
def write(row, col, val, src_row=None, src_col=None, commands=None):
"""Записывает данные в ячейку с сохранением стилей."""
src_row = src_row or row
@ -92,18 +89,21 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
return template.render(context)
def parse_cells(row_from=0, row_to=None, col_from=0, col_to=None,
dst_row_shift=0, dst_col_shift=0, **kwargs):
"""Ищет шаблонные теги и переменные в ячейках заданного диапазона. Если находит, то передает содержимое ячейки
целиком на обработку в process_template. После чего записывает полученный результат обратно в ячейку.
dst_row_shift=0, dst_col_shift=0, **kwargs):
"""
Ищет шаблонные теги и переменные в ячейках заданного диапазона.
Если находит, то передает содержимое ячейки
целиком на обработку в process_template. После чего записывает
полученный результат обратно в ячейку.
Также ищет спец. токены и выполняет соответствующие действия.
"""
row_to = row_to or src_sheet.nrows-1
col_to = col_to or src_sheet.ncols-1
row_to = row_to or src_sheet.nrows - 1
col_to = col_to or src_sheet.ncols - 1
for row in range(row_from, row_to+1):
for row in range(row_from, row_to + 1):
cmd_fix_height = []
for col in range(col_from, col_to+1):
for col in range(col_from, col_to + 1):
cell = src_sheet.cell(row, col)
cell_value = new_value = cell.value
@ -121,7 +121,6 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
new_value = process_template(new_value, **kwargs)
# пофиксить переводы строки
#new_value = new_value.strip().replace('\r\n', '\n')
new_value = new_value.strip().replace('\r\n', ' ')
# команда 'конвертировать во float'
@ -162,8 +161,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
try:
dst_sheet.insert_bitmap(
new_value,
row = row + dst_row_shift,
col = col + dst_col_shift,
row=row + dst_row_shift,
col=col + dst_col_shift,
)
new_value = ''
except:
@ -173,28 +172,26 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
# print "Error inserting image from file '%s'" % new_value
raise
write(
row = row + dst_row_shift,
col = col + dst_col_shift,
val = new_value,
src_row = row,
src_col = col,
commands = {'draw_thin_bottom_border': cmd_draw_thin_bottom_border,
}
row=row + dst_row_shift,
col=col + dst_col_shift,
val=new_value,
src_row=row,
src_col=col,
commands={'draw_thin_bottom_border': cmd_draw_thin_bottom_border}
)
# --- конец цикла по ячейкам в строке
# подобрать высоту строки в ячейках
dst_row = row + dst_row_shift # строка назначения
row_height = dst_sheet.row(dst_row).height # текущая высота
dst_row = row + dst_row_shift # строка назначения
row_height = dst_sheet.row(dst_row).height # текущая высота
max_height = 0
for fh in cmd_fix_height:
#print '---FIX_HEIGHT:', 'dst_row=', dst_row, 'col=', fh['col']
# print '---FIX_HEIGHT:', 'dst_row=', dst_row, 'col=', fh['col']
# взять ширину ячейки
width = 0
# учитываем только объединенные ячейки
for r1,r2,c1,c2 in src_sheet.merged_cells:
for r1, r2, c1, c2 in src_sheet.merged_cells:
if r1 != row or c1 != fh['col']:
continue
for colx in range(c1, c2):
@ -208,7 +205,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
width_in_pixels = width / 36.5
width_in_chars = width_in_pixels / 5.8
# может быть 0, если команда @@FIX_HEIGHT@@ задана в простой (не объединенной) ячейке
# может быть 0, если команда @@FIX_HEIGHT@@ задана в простой
# (не объединенной) ячейке
if width_in_chars == 0:
# print ('WARNING. xls generation, cmd @@FIX_HEIGHT@@. '
# 'variable `width_in_chars` = %s. skip this command.' % width_in_chars)
@ -219,14 +217,15 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
min_rows = 1
need_rows = math.ceil(len(value) / width_in_chars)
need_rows = int(max(min_rows, need_rows))
#print 'need_rows=', need_rows
# print 'need_rows=', need_rows
new_height = row_height * need_rows
# не фиксить высоту, если новая высота данной ячейки меньше либо равна текущей высоте
# не фиксить высоту, если новая высота данной ячейки меньше либо
# равна текущей высоте
if new_height > max_height:
max_height = new_height
else:
#print 'SKIP,', new_height, '<=', max_height
# print 'SKIP,', new_height, '<=', max_height
continue
dst_sheet.row(dst_row).height = new_height
@ -253,12 +252,12 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
# --- !!! ------ вывести начало документа включительно по шапку табл. части
copy_cells(src_sheet, dst_sheet, style_list, row_from=0, row_to=p.TBL_BODY_ROW-1)
copy_cells(src_sheet, dst_sheet, style_list, row_from=0, row_to=p.TBL_BODY_ROW - 1)
parse_cells(row_to=p.TBL_BODY_ROW-1)
parse_cells(row_to=p.TBL_BODY_ROW - 1)
# для отладки - выйти здесь
#return
# return
# --- !!! ------------ вывести таблицу с учетом переходов на новую страницу
@ -273,24 +272,24 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
row = 0
row_shift = 0
#print '---table:'
# print '---table:'
def write_tbl_body_row():
"""Хелпер для отрисовки строки таблицы.
Зависит от внешних переменных row_shift, row и item!
"""
#print '---table body row, dst_row_shift =', row_shift
# print '---table body row, dst_row_shift =', row_shift
copy_cells(
src_sheet, dst_sheet, style_list,
row_from = p.TBL_BODY_ROW, row_to = p.TBL_BODY_ROW,
dst_row_shift = row_shift
row_from=p.TBL_BODY_ROW, row_to=p.TBL_BODY_ROW,
dst_row_shift=row_shift
)
parse_cells(
row_from = p.TBL_BODY_ROW,
row_to = p.TBL_BODY_ROW,
dst_row_shift = row_shift,
item = item,
item_npp = row+1
row_from=p.TBL_BODY_ROW,
row_to=p.TBL_BODY_ROW,
dst_row_shift=row_shift,
item=item,
item_npp=row + 1
)
def write_tbl_page_footer():
@ -298,19 +297,19 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
Зависит от внешних переменных row_shift, last_page_item_idx и row!
"""
dst_row_shift = row_shift - (p.TBL_PAGE_FOOTER_FROM - p.TBL_BODY_ROW)
#print '---table page footer, dst_row_shift =', dst_row_shift, \
# print '---table page footer, dst_row_shift =', dst_row_shift, \
# 'items_start =', last_page_item_idx, 'items_stop =', row
copy_cells(
src_sheet, dst_sheet, style_list,
row_from = p.TBL_PAGE_FOOTER_FROM, row_to = p.TBL_PAGE_FOOTER_TO,
dst_row_shift = dst_row_shift
row_from=p.TBL_PAGE_FOOTER_FROM, row_to=p.TBL_PAGE_FOOTER_TO,
dst_row_shift=dst_row_shift
)
parse_cells(
row_from = p.TBL_PAGE_FOOTER_FROM,
row_to = p.TBL_PAGE_FOOTER_TO,
dst_row_shift = dst_row_shift,
items_start = last_page_item_idx,
items_stop = row
row_from=p.TBL_PAGE_FOOTER_FROM,
row_to=p.TBL_PAGE_FOOTER_TO,
dst_row_shift=dst_row_shift,
items_start=last_page_item_idx,
items_stop=row
)
def write_tbl_header():
@ -318,17 +317,17 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
Зависит от внешних переменных row и add_offset!
"""
dst_row_shift = p.TBL_HEADER_ROWS + row + add_offset
#print '---table header, dst_row_shift =', dst_row_shift
# print '---table header, dst_row_shift =', dst_row_shift
copy_cells(
src_sheet, dst_sheet, style_list,
row_from = p.TBL_HEADER_FROM, row_to = p.TBL_HEADER_TO,
dst_row_shift = dst_row_shift
row_from=p.TBL_HEADER_FROM, row_to=p.TBL_HEADER_TO,
dst_row_shift=dst_row_shift
)
# цикл по табличной части документа
for row, item in enumerate(obj_items):
row_shift = row + add_offset
#print 'row = %s, add_offset = %s' % (row, add_offset)
# print 'row = %s, add_offset = %s' % (row, add_offset)
write_tbl_body_row()
row_height = dst_sheet.row(p.TBL_BODY_ROW + row_shift).height
@ -340,13 +339,13 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
if curr_height + p.TBL_PAGE_FOOTER_HEIGHT + p.TBL_FOOTER_HEIGHT > p.WORK_HEIGHT:
# если это первая строка, то:
if row == 0:
#print '---table new page, row =', row
# print '---table new page, row =', row
# 1. добавить разрыв страницы перед первой шапкой
horz_page_break(dst_sheet, p.TBL_HEADER_FROM)
curr_height = p.TBL_HEADER_HEIGHT + row_height
# если это не последняя строка, то:
elif row < len(obj_items)-1:
#print '---table new page, row =', row
elif row < len(obj_items) - 1:
# print '---table new page, row =', row
# 1. вместо строки вывести подитог
if p.TBL_PAGE_FOOTER_ROWS > 0:
write_tbl_page_footer()
@ -355,7 +354,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
add_offset += p.TBL_PAGE_FOOTER_ROWS
row_shift += add_offset
# 2. добавить разрыв страницы
horz_page_break(dst_sheet, (p.TBL_HEADER_FROM + p.TBL_HEADER_ROWS + row + add_offset))
horz_page_break(dst_sheet,
(p.TBL_HEADER_FROM + p.TBL_HEADER_ROWS + row + add_offset))
# 3. вывести шапку
write_tbl_header()
add_offset += p.TBL_HEADER_ROWS
@ -365,28 +365,28 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
write_tbl_body_row()
curr_height += row_height
else: # for ... else
else: # for ... else
# вывести подитог, если только что не выводили его в цикле
if p.TBL_PAGE_FOOTER_ROWS > 0 and not just_wrote_page_footer:
#print '---tbl last page, row =', row
row += 1 # чтоб захватить в подитог и последнюю запись тоже
# print '---tbl last page, row =', row
row += 1 # чтоб захватить в подитог и последнюю запись тоже
row_shift = row + add_offset
write_tbl_page_footer()
curr_height += p.TBL_PAGE_FOOTER_HEIGHT
add_offset += row - p.TBL_PAGE_FOOTER_ROWS
#print '---end table'
# print '---end table'
# для отладки - выйти здесь
#return
# return
# --- !!! --------------------------------------- вывести остаток документа
copy_cells(
src_sheet, dst_sheet, style_list,
row_from = p.TBL_FOOTER_FROM,
dst_row_shift = add_offset
row_from=p.TBL_FOOTER_FROM,
dst_row_shift=add_offset
)
# добавить разрыв страницы, если остаток документа не уместится целиком
@ -426,13 +426,14 @@ def get_settings(src_book, sheet_name=u'settings'):
def apply_page_settings(dst_sheet, settings):
"""Применить параметры страницы."""
def setparam(attr, key):
if key in settings:
setattr(dst_sheet, attr, settings[key])
def setparam_as_inch(attr, key):
if key in settings:
setattr(dst_sheet, attr, settings[key]/25.4)
setattr(dst_sheet, attr, settings[key] / 25.4)
setparam('portrait', 'PAGE_PORTRAIT')
setparam('header_str', 'PAGE_HEADER_STR')
@ -448,12 +449,16 @@ def apply_page_settings(dst_sheet, settings):
def get_all_these_boring_params(src_sheet, xls_settings):
"""Достает нужные настройки из словаря и проверят, некоторые вычисляет -
и всё это складывает в класс, который потом и возвращает.
Если какие-то обязательные настройки не заданы, сообщает об этом в консоль и возвращает None.
"""
Достает нужные настройки из словаря и проверят, некоторые вычисляет -
и всё это складывает в класс, который потом и возвращает.
Если какие-то обязательные настройки не заданы, сообщает
об этом в консоль и возвращает None.
"""
class Params(object):
pass
p = Params()
# строка контента таблицы - обязательно
@ -507,7 +512,8 @@ def get_all_these_boring_params(src_sheet, xls_settings):
# высота в строках
p.TBL_PAGE_FOOTER_ROWS = int(p.TBL_PAGE_FOOTER_TO - p.TBL_PAGE_FOOTER_FROM + 1)
# высота в twips
p.TBL_PAGE_FOOTER_HEIGHT = sum_src_heights(src_sheet, p.TBL_PAGE_FOOTER_FROM, p.TBL_PAGE_FOOTER_TO)
p.TBL_PAGE_FOOTER_HEIGHT = sum_src_heights(src_sheet, p.TBL_PAGE_FOOTER_FROM,
p.TBL_PAGE_FOOTER_TO)
else:
p.TBL_PAGE_FOOTER_ROWS = 0
p.TBL_PAGE_FOOTER_HEIGHT = 0

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
# import autocomplete_light
import autocomplete_light
from django.db.models import Q
@ -30,8 +29,7 @@ class AutocompleteClient(autocomplete_light.AutocompleteModelBase):
exclude = self.request.GET.getlist('exclude', [])
choices = self.choices.filter(company=user_.profile).\
filter(Q(name__icontains=q) | Q(inn=q) | Q(okpo=q)).\
exclude(pk__in=exclude)
filter(Q(name__icontains=q) | Q(inn=q) | Q(okpo=q)).exclude(pk__in=exclude)
return self.order_choices(choices)[0:self.limit_choices]

@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
from decimal import Decimal
BOOL_CHOICES = (
(True, u'Да'),
(False, u'Нет'),
(True, 'Да'),
(False, 'Нет'),
)
# виды НДС
@ -13,9 +12,9 @@ NDS_TYPE_IN = 2
NDS_TYPE_OUT = 3
NDS_TYPE_CHOICES = (
(NDS_TYPE_NO, u'Не учитывать'),
(NDS_TYPE_IN, u'В сумме'),
(NDS_TYPE_OUT, u'Сверх суммы'),
(NDS_TYPE_NO, 'Не учитывать'),
(NDS_TYPE_IN, 'В сумме'),
(NDS_TYPE_OUT, 'Сверх суммы'),
)
# ставка НДС
@ -24,9 +23,9 @@ NDS_VALUE_10 = 10
NDS_VALUE_18 = 18
NDS_VALUE_CHOICES = (
(NDS_VALUE_0, u'Без НДС'),
(NDS_VALUE_10, u'10%'),
(NDS_VALUE_18, u'18%'),
(NDS_VALUE_0, 'Без НДС'),
(NDS_VALUE_10, '10%'),
(NDS_VALUE_18, '18%'),
)
# ставка НДС - число в формате Decimal (для расчетов)
@ -39,7 +38,6 @@ NDS_VALUE_NUMERIC = {
NDS_IN_AMOUNT = 0
NDS_OTHER_AMOUNT = 1
NDS_METHOD_CHOICES = (
(NDS_IN_AMOUNT, 'В сумме'),
(NDS_OTHER_AMOUNT, 'Сверх суммы'),
@ -54,10 +52,10 @@ CURR_EUR = 3
CURR_OTHER = 4
CURRENCY_CHOICES = (
(CURR_RUB, u'Руб.'),
(CURR_USD, u'USD'),
(CURR_EUR, u'EUR'),
(CURR_OTHER, u'Другое'),
(CURR_RUB, 'Руб.'),
(CURR_USD, 'USD'),
(CURR_EUR, 'EUR'),
(CURR_OTHER, 'Другое'),
)
CURRENCY_CHOICES_DICT = dict(CURRENCY_CHOICES)
@ -68,9 +66,9 @@ CONSIGNOR_TYPE_OTHER = 2
CONSIGNOR_TYPE_NO = 3
CONSIGNOR_CHOICES = (
(CONSIGNOR_TYPE_SELF, u'Подставить мои данные'), # из профиля через поле user
(CONSIGNOR_TYPE_OTHER, u'Стороннее лицо'), # из справочника контрагенты
(CONSIGNOR_TYPE_NO, u'Не указывать'),
(CONSIGNOR_TYPE_SELF, 'Подставить мои данные'), # из профиля через поле user
(CONSIGNOR_TYPE_OTHER, 'Стороннее лицо'), # из справочника контрагенты
(CONSIGNOR_TYPE_NO, 'Не указывать'),
)
# варианты для поля грузополучатель
@ -79,9 +77,9 @@ RECEIVER_TYPE_OTHER = 2
RECEIVER_TYPE_NO = 3
RECEIVER_CHOICES = (
(RECEIVER_TYPE_BUYER, u'То же лицо'), # что и покупатель
(RECEIVER_TYPE_OTHER, u'Стороннее лицо'), # из справочника контрагенты
(RECEIVER_TYPE_NO, u'Не указывать'),
(RECEIVER_TYPE_BUYER, 'То же лицо'), # что и покупатель
(RECEIVER_TYPE_OTHER, 'Стороннее лицо'), # из справочника контрагенты
(RECEIVER_TYPE_NO, 'Не указывать'),
)
# ----------------------------------------------------- для платежных поручений
@ -91,66 +89,66 @@ PLATEJ_TYPE_COMMERCE = 1
PLATEJ_TYPE_TAX = 2
PLATEJ_TYPE_CHOICES = (
(PLATEJ_TYPE_COMMERCE, u'Коммерческое'),
(PLATEJ_TYPE_TAX, u'Налоговое'),
(PLATEJ_TYPE_COMMERCE, 'Коммерческое'),
(PLATEJ_TYPE_TAX, 'Налоговое'),
)
# вид платежа
PAYMENT_TYPE_CHOICES = (
(1, u'Не указывать'),
(2, u'Срочно'),
(3, u'Электронно'),
(4, u'Почтой'),
(5, u'Телеграфом'),
(1, 'Не указывать'),
(2, 'Срочно'),
(3, 'Электронно'),
(4, 'Почтой'),
(5, 'Телеграфом'),
)
# статус составителя
TAX_STATUS_CHOICES = (
(u'01', u'01 - налогоплательщик (плательщик сборов) - юридическое лицо'),
(u'02', u'02 - налоговый агент'),
(u'03', u'03 - сборщик налогов и сборов'),
(u'04', u'04 - налоговый орган'),
(u'05', u'05 - служба судебных приставов'),
(u'06', u'06 - участник внешнеэкономической деятельности'),
(u'07', u'07 - таможенный орган'),
(u'08', u'08 - плательщик иных обязательных платежей'),
(u'09', u'09 - налогоплательщик (плательщик сборов) - ИП'),
(u'10', u'10 - налогоплательщик (плательщик сборов) - частный нотариус'),
(u'11', u'11 - налогоплательщик (плательщик сборов) - адвокат'),
(u'12', u'12 - налогоплательщик (плательщик сборов) - глава КФХ'),
(u'13', u'13 - налогоплательщик (плательщик сборов) - иное физическое лицо'),
(u'14', u'14 - налогоплательщик, производящий выплаты физическим лицам'),
(u'15', u'15 - кредитная организация'),
('01', '01 - налогоплательщик (плательщик сборов) - юридическое лицо'),
('02', '02 - налоговый агент'),
('03', '03 - сборщик налогов и сборов'),
('04', '04 - налоговый орган'),
('05', '05 - служба судебных приставов'),
('06', '06 - участник внешнеэкономической деятельности'),
('07', '07 - таможенный орган'),
('08', '08 - плательщик иных обязательных платежей'),
('09', '09 - налогоплательщик (плательщик сборов) - ИП'),
('10', '10 - налогоплательщик (плательщик сборов) - частный нотариус'),
('11', '11 - налогоплательщик (плательщик сборов) - адвокат'),
('12', '12 - налогоплательщик (плательщик сборов) - глава КФХ'),
('13', '13 - налогоплательщик (плательщик сборов) - иное физическое лицо'),
('14', '14 - налогоплательщик, производящий выплаты физическим лицам'),
('15', '15 - кредитная организация'),
)
# основание налогового платежа
TAX_BASE = (
(u'ТП', u'ТП - платежи текущего года'),
(u'ЗД', u'ЗД - добровольное погашение задолженности по истекшим налоговым периода'),
(u'БФ', u'БФ - текущие платежи физических лиц - клиентов банка (владельцев счета)'),
(u'ТР', u'ТР - погашение задолженности по требованию об уплате налогов (сборов) от налогового органа'),
(u'РС', u'РС - погашение рассроченной задолженности'),
(u'ОТ', u'ОТ - погашение отсроченной задолженности'),
(u'РТ', u'РТ - погашение реструктурируемой задолженности'),
(u'ВУ', u'ВУ - погашение отсроченной задолженности в связи с введением внешнего управления'),
(u'ПР', u'ПР - погашение задолженности, приостановленной к взысканию'),
(u'АП', u'АП - погашение задолженности по акту проверки'),
(u'АР', u'АР - погашение задолженности по исполнительному документу'),
( u'0', u'0 - Конкретное значение указать невозможно'),
('ТП', 'ТП - платежи текущего года'),
('ЗД', 'ЗД - добровольное погашение задолженности по истекшим налоговым периода'),
('БФ', 'БФ - текущие платежи физических лиц - клиентов банка (владельцев счета)'),
('ТР',
'ТР - погашение задолженности по требованию об уплате налогов (сборов) от налогового органа'),
('РС', 'РС - погашение рассроченной задолженности'),
('ОТ', 'ОТ - погашение отсроченной задолженности'),
('РТ', 'РТ - погашение реструктурируемой задолженности'),
('ВУ', 'ВУ - погашение отсроченной задолженности в связи с введением внешнего управления'),
('ПР', 'ПР - погашение задолженности, приостановленной к взысканию'),
('АП', 'АП - погашение задолженности по акту проверки'),
('АР', 'АР - погашение задолженности по исполнительному документу'),
('0', '0 - Конкретное значение указать невозможно'),
)
# тип налогового платежа
TAX_TYPE = (
(u'НС', u'НС - уплата налога или сбора'),
(u'ПЛ', u'ПЛ - уплата платежа'),
(u'ГП', u'ГП - уплата пошлины'),
(u'ВЗ', u'ВЗ - уплата взноса'),
(u'АВ', u'АВ - уплата аванса или предоплата (в том числе декадные платежи)'),
(u'ПЕ', u'ПЕ - уплата пени'),
(u'ПЦ', u'ПЦ - уплата процентов'),
(u'СА', u'СА - налоговые санкции, установленные Налоговым кодексом РФ'),
(u'АШ', u'АШ - административные штрафы'),
(u'ИШ', u'ИШ - иные штрафы, установленные соответствующими нормативными актами'),
( u'0', u'0 - Конкретное значение указать невозможно'),
('НС', 'НС - уплата налога или сбора'),
('ПЛ', 'ПЛ - уплата платежа'),
('ГП', 'ГП - уплата пошлины'),
('ВЗ', 'ВЗ - уплата взноса'),
('АВ', 'АВ - уплата аванса или предоплата (в том числе декадные платежи)'),
('ПЕ', 'ПЕ - уплата пени'),
('ПЦ', 'ПЦ - уплата процентов'),
('СА', 'СА - налоговые санкции, установленные Налоговым кодексом РФ'),
('АШ', 'АШ - административные штрафы'),
('ИШ', 'ИШ - иные штрафы, установленные соответствующими нормативными актами'),
('0', '0 - Конкретное значение указать невозможно'),
)

@ -22,7 +22,7 @@ class CustomDateRangeFilter(django_filters.DateRangeFilter):
class CustomChoiceFilter(django_filters.ChoiceFilter):
def __init__(self, *args, **kwargs):
self.options = kwargs.pop('options') # обязательный параметр!
self.options = kwargs.pop('options') # обязательный параметр!
kwargs['choices'] = [(key, value[0]) for key, value in self.options.items()]
super(CustomChoiceFilter, self).__init__(*args, **kwargs)
@ -44,23 +44,23 @@ def _quarter_dates(q, year):
return datetime.date(year, 4, 1), datetime.date(year, 6, 30)
elif q == 3:
return datetime.date(year, 7, 1), datetime.date(year, 9, 30)
elif q ==4:
elif q == 4:
return datetime.date(year, 10, 1), datetime.date(year, 12, 31)
return None, None
def current_quarter(today):
"""Возвращает даты начала/окончания текущего квартала."""
q = (today.month-1)//3+1
q = (today.month - 1) // 3 + 1
return _quarter_dates(q, today.year)
def last_quarter(today):
"""Возвращает даты начала/окончания прошлого квартала."""
q = (today.month-1)//3+1
q = (today.month - 1) // 3 + 1
q -= 1
year = today.year
if q < 1: # прошлый год
if q < 1: # прошлый год
q = 4
year -= 1
return _quarter_dates(q, year)
@ -73,64 +73,64 @@ last_quarter_start, last_quarter_end = last_quarter(today)
# --- варианты фильтрации для разных полей
doc_date_choices = {
'': (u'Всё время', lambda qs, name: qs.all()),
1: (u'Этот месяц', lambda qs, name: qs.filter(**{
'': ('Всё время', lambda qs, name: qs.all()),
1: ('Этот месяц', lambda qs, name: qs.filter(**{
'%s__year' % name: datetime.datetime.now().year,
'%s__month' % name: datetime.datetime.now().month
})),
2: (u'Прошлый месяц', lambda qs, name: qs.filter(**{
2: ('Прошлый месяц', lambda qs, name: qs.filter(**{
'%s__year' % name: datetime.datetime.now().year,
'%s__month' % name: datetime.datetime.now().month-1
'%s__month' % name: datetime.datetime.now().month - 1
})),
3: (u'Этот квартал', lambda qs, name: qs.filter(**{
3: ('Этот квартал', lambda qs, name: qs.filter(**{
'%s__gte' % name: current_quarter_start,
'%s__lte' % name: current_quarter_end,
})),
4: (u'Прошлый квартал', lambda qs, name: qs.filter(**{
4: ('Прошлый квартал', lambda qs, name: qs.filter(**{
'%s__gte' % name: last_quarter_start,
'%s__lte' % name: last_quarter_end,
})),
5: (u'Этот год', lambda qs, name: qs.filter(**{
5: ('Этот год', lambda qs, name: qs.filter(**{
'%s__year' % name: datetime.datetime.now().year,
})),
6: (u'Прошлый год', lambda qs, name: qs.filter(**{
'%s__year' % name: datetime.datetime.now().year-1,
6: ('Прошлый год', lambda qs, name: qs.filter(**{
'%s__year' % name: datetime.datetime.now().year - 1,
})),
}
closed_status_choices = (
('', u'Все счета'),
(1, u'Закрытые актом выполненных работ'),
(0, u'Не закрытые актом выполненных работ'),
('', 'Все счета'),
(1, 'Закрытые актом выполненных работ'),
(0, 'Не закрытые актом выполненных работ'),
)
paid_status_choices = (
('', u'Все счета'),
(Invoice.PAID, u'Оплаченные'),
(Invoice.PARTLY_PAID, u'Частично оплаченные'),
(Invoice.UNPAID, u'Неоплаченные'),
('', 'Все счета'),
(Invoice.PAID, 'Оплаченные'),
(Invoice.PARTLY_PAID, 'Частично оплаченные'),
(Invoice.UNPAID, 'Неоплаченные'),
)
signed_status_choices = (
('', u'Все документы'),
('1', u'Подписанные'),
('0', u'Не подписанные'),
('', 'Все документы'),
('1', 'Подписанные'),
('0', 'Не подписанные'),
)
total_saldo_choices = {
'': (u'Любое', lambda qs, name: qs.all()),
1: (u'Положительное', lambda qs, name: qs.filter(**{
'': ('Любое', lambda qs, name: qs.all()),
1: ('Положительное', lambda qs, name: qs.filter(**{
'%s__gt' % name: 0,
})),
2: (u'Отрицательное', lambda qs, name: qs.filter(**{
2: ('Отрицательное', lambda qs, name: qs.filter(**{
'%s__lt' % name: 0,
})),
}
platej_type_choices = (
('', u'Все плат. поручения'),
(consts.PLATEJ_TYPE_COMMERCE, u'Коммерческие'),
(consts.PLATEJ_TYPE_TAX, u'Налоговые'),
('', 'Все плат. поручения'),
(consts.PLATEJ_TYPE_COMMERCE, 'Коммерческие'),
(consts.PLATEJ_TYPE_TAX, 'Налоговые'),
)
@ -145,10 +145,12 @@ class BaseDocsFilterSet(django_filters.FilterSet):
self.request = request
if 'client' in self.filters:
self.filters['client'].extra['queryset'] = Client.objects.get_all(self.request.user.profile)
self.filters['client'].extra['queryset'] = \
Client.objects.get_all(self.request.user.profile)
if 'invoice' in self.filters:
self.filters['invoice'].extra['queryset'] = Invoice.objects.get_all(self.request.user.profile)
self.filters['invoice'].extra['queryset'] = \
Invoice.objects.get_all(self.request.user.profile)
# сбросить у полей формы атрибут help_text
for field in self.form.fields.values():
@ -156,46 +158,146 @@ class BaseDocsFilterSet(django_filters.FilterSet):
class InvoiceFilterSet(BaseDocsFilterSet):
paid_status = django_filters.ChoiceFilter(label=u'По оплате', choices=paid_status_choices, widget=django_filters.widgets.LinkWidget)
closed_status = django_filters.ChoiceFilter(label=u'По закрывающим документам', choices=closed_status_choices, widget=django_filters.widgets.LinkWidget)
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты')
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget)
paid_status = django_filters.ChoiceFilter(
label='По оплате',
choices=paid_status_choices,
widget=django_filters.widgets.LinkWidget
)
closed_status = django_filters.ChoiceFilter(
label='По закрывающим документам',
choices=closed_status_choices,
widget=django_filters.widgets.LinkWidget
)
client = django_filters.ModelChoiceFilter(
label='По контрагенту',
queryset=None,
empty_label='все контрагенты'
)
doc_date = CustomDateRangeFilter(
label='По времени создания',
options=doc_date_choices,
widget=django_filters.widgets.LinkWidget
)
class AktRabotFilterSet(BaseDocsFilterSet):
signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget)
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты')
invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета')
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget)
signed_status = django_filters.ChoiceFilter(
label='По приёмке',
choices=signed_status_choices,
widget=django_filters.widgets.LinkWidget
)
client = django_filters.ModelChoiceFilter(
label='По контрагенту',
queryset=None,
empty_label='все контрагенты'
)
invoice = django_filters.ModelChoiceFilter(
label='По счёту',
queryset=None,
empty_label='все счета'
)
doc_date = CustomDateRangeFilter(
label='По времени создания',
options=doc_date_choices,
widget=django_filters.widgets.LinkWidget
)
class NakladnFilterSet(BaseDocsFilterSet):
signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget)
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты')
invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета')
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget)
signed_status = django_filters.ChoiceFilter(
label='По приёмке',
choices=signed_status_choices,
widget=django_filters.widgets.LinkWidget
)
client = django_filters.ModelChoiceFilter(
label='По контрагенту',
queryset=None,
empty_label='все контрагенты'
)
invoice = django_filters.ModelChoiceFilter(
label='По счёту',
queryset=None,
empty_label='все счета'
)
doc_date = CustomDateRangeFilter(
label='По времени создания',
options=doc_date_choices,
widget=django_filters.widgets.LinkWidget
)
class FakturaFilterSet(BaseDocsFilterSet):
signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget)
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты')
invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета')
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget)
signed_status = django_filters.ChoiceFilter(
label='По приёмке',
choices=signed_status_choices,
widget=django_filters.widgets.LinkWidget
)
client = django_filters.ModelChoiceFilter(
label='По контрагенту',
queryset=None,
empty_label='все контрагенты'
)
invoice = django_filters.ModelChoiceFilter(
label='По счёту',
queryset=None,
empty_label='все счета'
)
doc_date = CustomDateRangeFilter(
label='По времени создания',
options=doc_date_choices,
widget=django_filters.widgets.LinkWidget
)
class AktSverkiFilterSet(BaseDocsFilterSet):
signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget)
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты')
total_saldo = CustomChoiceFilter(label=u'По сальдо', options=total_saldo_choices, widget=django_filters.widgets.LinkWidget)
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget)
signed_status = django_filters.ChoiceFilter(
label='По приёмке',
choices=signed_status_choices,
widget=django_filters.widgets.LinkWidget
)
client = django_filters.ModelChoiceFilter(
label='По контрагенту',
queryset=None,
empty_label='все контрагенты'
)
total_saldo = CustomChoiceFilter(
label='По сальдо',
options=total_saldo_choices,
widget=django_filters.widgets.LinkWidget
)
doc_date = CustomDateRangeFilter(
label='По времени создания',
options=doc_date_choices,
widget=django_filters.widgets.LinkWidget
)
class DoverFilterSet(BaseDocsFilterSet):
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты')
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget)
client = django_filters.ModelChoiceFilter(
label='По контрагенту',
queryset=None,
empty_label='все контрагенты'
)
doc_date = CustomDateRangeFilter(
label='По времени создания',
options=doc_date_choices,
widget=django_filters.widgets.LinkWidget
)
class PlatejkaFilterSet(BaseDocsFilterSet):
platej_type = django_filters.ChoiceFilter(label=u'По типу', choices=platej_type_choices, widget=django_filters.widgets.LinkWidget)
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты')
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget)
platej_type = django_filters.ChoiceFilter(
label='По типу',
choices=platej_type_choices,
widget=django_filters.widgets.LinkWidget
)
client = django_filters.ModelChoiceFilter(
label='По контрагенту',
queryset=None,
empty_label='все контрагенты'
)
doc_date = CustomDateRangeFilter(
label='По времени создания',
options=doc_date_choices,
widget=django_filters.widgets.LinkWidget
)

@ -1,9 +1,14 @@
from docs.forms.email import EmailForm
from docs.forms.email import EmailForm # noqa
from docs.forms.invoice import InvoiceForm, InvoiceAdminForm, InvoiceItemForm, InvoiceItemAdminForm, InvoicesListForm
from docs.forms.aktrabot import AktRabotForm, AktRabotAdminForm, AktRabotItemForm, AktRabotItemAdminForm
from docs.forms.aktsverki import AktSverkiForm, AktSverkiAdminForm, AktSverkiItemForm, AktSverkiItemAdminForm
from docs.forms.dover import DoverForm, DoverAdminForm, DoverItemForm, DoverItemAdminForm
from docs.forms.platejka import PlatejkaForm, PlatejkaAdminForm
from docs.forms.nakladn import NakladnForm, NakladnAdminForm, NakladnItemForm, NakladnItemAdminForm
from docs.forms.faktura import FakturaForm, FakturaAdminForm, FakturaItemForm, FakturaItemAdminForm
from docs.forms.invoice import (InvoiceForm, InvoiceAdminForm, # noqa
InvoiceItemForm, InvoiceItemAdminForm, InvoicesListForm) # noqa
from docs.forms.aktrabot import (AktRabotForm, AktRabotAdminForm, # noqa
AktRabotItemForm, AktRabotItemAdminForm) # noqa
from docs.forms.aktsverki import (AktSverkiForm, AktSverkiAdminForm, # noqa
AktSverkiItemForm, AktSverkiItemAdminForm) # noqa
from docs.forms.dover import DoverForm, DoverAdminForm, DoverItemForm, DoverItemAdminForm # noqa
from docs.forms.platejka import PlatejkaForm, PlatejkaAdminForm # noqa
from docs.forms.nakladn import (NakladnForm, NakladnAdminForm, # noqa
NakladnItemForm, NakladnItemAdminForm) # noqa
from docs.forms.faktura import (FakturaForm, FakturaAdminForm, # noqa
FakturaItemForm, FakturaItemAdminForm) # noqa

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
from django import forms
from commons.forms import MyBaseModelForm
from .base_forms import BaseModelForm
@ -18,13 +16,13 @@ class AktSverkiForm(BaseModelForm):
class Meta:
model = AktSverki
fields = ('doc_num', 'doc_date',
'doc_mesto',
'client',
# период
'start_date', 'end_date',
# входящее сальдо
'saldo_debit', 'saldo_credit',
)
'doc_mesto',
'client',
# период
'start_date', 'end_date',
# входящее сальдо
'saldo_debit', 'saldo_credit',
)
def __init__(self, user, *args, **kwargs):
super(AktSverkiForm, self).__init__(user, *args, **kwargs)
@ -44,12 +42,14 @@ class AktSverkiAdminForm(AktSverkiForm):
exclude = ()
def __init__(self, *args, **kwargs):
# обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки !
# обязательно нужно вызывать родительский __init__ и передавать ему None
# вместо user - иначе глюки !
super(AktSverkiAdminForm, self).__init__(None, *args, **kwargs)
class AktSverkiItemForm(MyBaseModelForm):
"""Форма редактирования табличной части акта сверки."""
class Meta:
model = AktSverkiItem
exclude = ['parent']
@ -58,5 +58,6 @@ class AktSverkiItemForm(MyBaseModelForm):
class AktSverkiItemAdminForm(AktSverkiItemForm):
"""Форма редактирования табличной части акта сверки - для админки."""
class Meta(AktSverkiItemForm.Meta):
exclude = None

@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
from django import forms
from commons.forms import MyBaseModelForm
from .base_forms import BaseModelForm
@ -16,12 +14,13 @@ class DoverForm(BaseModelForm):
class Meta:
model = Dover
fields = ('doc_num', 'doc_date', 'doc_expire_date',
'client',
# на получение мат.ценностей по документу
'dover_doc', 'dover_doc_date',
# кому выдана и его документы
'dover_name', 'dover_passport_ser', 'dover_passport_num', 'dover_passport_org', 'dover_passport_date',
)
'client',
# на получение мат.ценностей по документу
'dover_doc', 'dover_doc_date',
# кому выдана и его документы
'dover_name', 'dover_passport_ser', 'dover_passport_num', 'dover_passport_org',
'dover_passport_date',
)
def __init__(self, user, *args, **kwargs):
super(DoverForm, self).__init__(user, *args, **kwargs)
@ -33,17 +32,20 @@ class DoverForm(BaseModelForm):
class DoverAdminForm(DoverForm):
"""Форма редактирования доверенности на получение ТМЦ - для админки."""
class Meta(DoverForm.Meta):
# fields = None
exclude = ()
def __init__(self, *args, **kwargs):
# обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки !
# обязательно нужно вызывать родительский __init__ и передавать ему None
# вместо user - иначе глюки !
super(DoverAdminForm, self).__init__(None, *args, **kwargs)
class DoverItemForm(MyBaseModelForm):
"""Форма редактирования табличной части доверенности на получение ТМЦ."""
class Meta:
model = DoverItem
exclude = ['parent']
@ -52,5 +54,6 @@ class DoverItemForm(MyBaseModelForm):
class DoverItemAdminForm(DoverItemForm):
"""Форма редактирования табличной части доверенности на получение ТМЦ - для админки."""
class Meta(DoverItemForm.Meta):
exclude = None

@ -3,19 +3,33 @@ from django import forms
DOC_FORMATS = (
(u'pdf', u'PDF'),
(u'xls', u'Excel'),
('pdf', 'PDF'),
('xls', 'Excel'),
)
class EmailForm(forms.Form):
"""Форма отправки документа по email."""
to = forms.EmailField(label=u'E-mail получателя')
body = forms.CharField(label=u'Текст сообщения', max_length=1000, required=False,
widget=forms.Textarea(attrs={'cols': 80, 'rows': 3}))
doc_format = forms.ChoiceField(label=u'Отправить как', choices=DOC_FORMATS, initial=DOC_FORMATS[0][0],
widget=forms.RadioSelect())
insert_sign = forms.BooleanField(label=u'Вставить печать и подпись', initial=False,
required=False)
save_client_email = forms.BooleanField(label=u'Сохранить этот e-mail в анкете контрагента', initial=False,
required=False)
to = forms.EmailField(label='E-mail получателя')
body = forms.CharField(
label='Текст сообщения',
max_length=1000,
required=False,
widget=forms.Textarea(attrs={'cols': 80, 'rows': 3})
)
doc_format = forms.ChoiceField(
label='Отправить как',
choices=DOC_FORMATS,
initial=DOC_FORMATS[0][0],
widget=forms.RadioSelect()
)
insert_sign = forms.BooleanField(
label='Вставить печать и подпись',
initial=False,
required=False
)
save_client_email = forms.BooleanField(
label='Сохранить этот e-mail в анкете контрагента',
initial=False,
required=False
)

@ -41,7 +41,8 @@ class InvoiceAdminForm(InvoiceForm):
}
def __init__(self, *args, **kwargs):
# обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки !
# обязательно нужно вызывать родительский __init__ и передавать ему None
# вместо user - иначе глюки !
super(InvoiceAdminForm, self).__init__(None, *args, **kwargs)

@ -41,7 +41,8 @@ class NakladnAdminForm(NakladnForm):
}
def __init__(self, *args, **kwargs):
# обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки !
# обязательно нужно вызывать родительский __init__ и
# передавать ему None вместо user - иначе глюки !
super(NakladnAdminForm, self).__init__(None, *args, **kwargs)

@ -11,22 +11,24 @@ from .. import consts
class PlatejkaForm(BaseModelForm):
"""Форма редактирования платежного поручения."""
conditional_fields = ['nds_value',
'tax_status', 'tax_base', 'tax_type', 'tax_bk', 'tax_okato', 'tax_period',]
'tax_status', 'tax_base', 'tax_type', 'tax_bk', 'tax_okato',
'tax_period', ]
class Meta:
model = Platejka
fields = ('platej_type', 'doc_num', 'doc_date',
'bank_account', 'client',
'nds_value', # поля только для перевода денег
# поля только для оплаты налогов
'tax_status', 'tax_base', 'tax_type', 'tax_num', 'tax_date', 'tax_bk', 'tax_okato', 'tax_period',
# опять общие поля
'doc_total', 'payment_type', 'payment_order', 'doc_info',
)
'bank_account', 'client',
'nds_value', # поля только для перевода денег
# поля только для оплаты налогов
'tax_status', 'tax_base', 'tax_type', 'tax_num', 'tax_date', 'tax_bk',
'tax_okato', 'tax_period',
# опять общие поля
'doc_total', 'payment_type', 'payment_order', 'doc_info',
)
_radioselect = forms.RadioSelect
_textarea = forms.Textarea(attrs={'cols': 80, 'rows': 5})
widgets = {
#'platej_type': _radioselect,
# 'platej_type': _radioselect,
'doc_info': _textarea,
}
@ -50,7 +52,7 @@ class PlatejkaForm(BaseModelForm):
#
# if not nds_value: set_field_error(self, 'nds_value')
elif platej_type == consts.PLATEJ_TYPE_TAX: # налоги
elif platej_type == consts.PLATEJ_TYPE_TAX: # налоги
tax_status = cleaned_data.get('tax_status')
tax_base = cleaned_data.get('tax_base')
tax_type = cleaned_data.get('tax_type')
@ -58,18 +60,25 @@ class PlatejkaForm(BaseModelForm):
tax_okato = cleaned_data.get('tax_okato')
tax_period = cleaned_data.get('tax_period')
if not tax_status: set_field_error(self, 'tax_status')
if not tax_base: set_field_error(self, 'tax_base')
if not tax_type: set_field_error(self, 'tax_type')
if not tax_bk: set_field_error(self, 'tax_bk')
if not tax_okato: set_field_error(self, 'tax_okato')
if not tax_period: set_field_error(self, 'tax_period')
if not tax_status:
set_field_error(self, 'tax_status')
if not tax_base:
set_field_error(self, 'tax_base')
if not tax_type:
set_field_error(self, 'tax_type')
if not tax_bk:
set_field_error(self, 'tax_bk')
if not tax_okato:
set_field_error(self, 'tax_okato')
if not tax_period:
set_field_error(self, 'tax_period')
return cleaned_data
class PlatejkaAdminForm(PlatejkaForm):
"""Форма редактирования платежного поручения - для админки."""
class Meta(PlatejkaForm.Meta):
# fields = None
exclude = ()
@ -78,5 +87,6 @@ class PlatejkaAdminForm(PlatejkaForm):
}
def __init__(self, *args, **kwargs):
# обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки !
# обязательно нужно вызывать родительский __init__ и передавать ему None
# вместо user - иначе глюки !
super(PlatejkaAdminForm, self).__init__(None, *args, **kwargs)

@ -1,8 +1,8 @@
from docs.models.refs import Currency, Country, Measure
from docs.models.invoice import Invoice, InvoiceItem
from docs.models.aktrabot import AktRabot, AktRabotItem
from docs.models.aktsverki import AktSverki, AktSverkiItem
from docs.models.dover import Dover, DoverItem
from docs.models.platejka import Platejka
from docs.models.nakladn import Nakladn, NakladnItem
from docs.models.faktura import Faktura, FakturaItem
from docs.models.refs import Currency, Country, Measure # noqa
from docs.models.invoice import Invoice, InvoiceItem # noqa
from docs.models.aktrabot import AktRabot, AktRabotItem # noqa
from docs.models.aktsverki import AktSverki, AktSverkiItem # noqa
from docs.models.dover import Dover, DoverItem # noqa
from docs.models.platejka import Platejka # noqa
from docs.models.nakladn import Nakladn, NakladnItem # noqa
from docs.models.faktura import Faktura, FakturaItem # noqa

@ -9,29 +9,60 @@ from docs.models.mixins import SignedStatusFieldMixin
class AktSverki(BaseModel, SignedStatusFieldMixin):
"""Акт сверки."""
doc_mesto = models.CharField(u'Место подписания', max_length=256, help_text=u'(Например, г. Москва)')
doc_mesto = models.CharField(
'Место подписания',
max_length=256,
help_text='(Например, г. Москва)'
)
# период
start_date = models.DateField('С')
end_date = models.DateField('По')
# входящее сальдо
saldo_debit = models.DecimalField(u'Дебетовое', max_digits=10, decimal_places=2, blank=True) # , default=Decimal('0.00'))
saldo_credit = models.DecimalField(u'Кредитовое', max_digits=10, decimal_places=2, blank=True) # , default=Decimal('0.00'))
saldo_debit = models.DecimalField(
'Дебетовое',
max_digits=10,
decimal_places=2,
blank=True
)
saldo_credit = models.DecimalField(
'Кредитовое',
max_digits=10,
decimal_places=2,
blank=True
)
# вычисляемые поля - обновляются при сохранении записей табличной части
total_debit = models.DecimalField(u'Общее дебетовое сальдо', max_digits=10, decimal_places=2, blank=True,
default=Decimal('0.00'))
total_credit = models.DecimalField(u'Общее кредитовое сальдо', max_digits=10, decimal_places=2, blank=True,
default=Decimal('0.00'))
total_saldo = models.DecimalField(u'Итоговое сальдо', max_digits=10, decimal_places=2, blank=True,
default=Decimal('0.00'))
total_debit = models.DecimalField(
'Общее дебетовое сальдо',
max_digits=10,
decimal_places=2,
blank=True,
default=Decimal('0.00')
)
total_credit = models.DecimalField(
'Общее кредитовое сальдо',
max_digits=10,
decimal_places=2,
blank=True,
default=Decimal('0.00')
)
total_saldo = models.DecimalField(
'Итоговое сальдо',
max_digits=10,
decimal_places=2,
blank=True,
default=Decimal('0.00')
)
class Meta(BaseModel.Meta):
verbose_name = u'Акт сверки'
verbose_name_plural = u'Акты сверки'
def save(self, *args, **kwargs):
if not self.saldo_debit: self.saldo_debit = 0
if not self.saldo_credit: self.saldo_credit = 0
if not self.saldo_debit:
self.saldo_debit = 0
if not self.saldo_credit:
self.saldo_credit = 0
super(AktSverki, self).save(*args, **kwargs)
@ -39,16 +70,18 @@ class AktSverkiItem(VeryBaseModel):
"""Табличная часть акта сверки."""
parent = models.ForeignKey(AktSverki, related_name='aktsverki_items')
name = models.CharField(u'Наименование операции, документы', max_length=256)
debit = models.DecimalField(u'Дебет', max_digits=10, decimal_places=2, blank=True)
credit = models.DecimalField(u'Кредит', max_digits=10, decimal_places=2, blank=True)
name = models.CharField('Наименование операции, документы', max_length=256)
debit = models.DecimalField('Дебет', max_digits=10, decimal_places=2, blank=True)
credit = models.DecimalField('Кредит', max_digits=10, decimal_places=2, blank=True)
class Meta(VeryBaseModel.Meta):
verbose_name = u'Табл. часть акта сверки'
verbose_name_plural = u'Табл. части актов сверки'
verbose_name = 'Табл. часть акта сверки'
verbose_name_plural = 'Табл. части актов сверки'
ordering = ('created_at',)
def save(self, *args, **kwargs):
if not self.debit: self.debit = 0
if not self.credit: self.credit = 0
if not self.debit:
self.debit = 0
if not self.credit:
self.credit = 0
super(AktSverkiItem, self).save(*args, **kwargs)

@ -10,9 +10,11 @@ from docs import consts
class VeryBaseModel(models.Model):
"""Очень базовая абстрактная модель."""
created_at = models.DateTimeField(u'Создан', auto_now_add=True)
updated_at = models.DateTimeField(u'Изменен', auto_now=True)
"""
Очень базовая абстрактная модель.
"""
created_at = models.DateTimeField('Создан', auto_now_add=True)
updated_at = models.DateTimeField('Изменен', auto_now=True)
class Meta:
abstract = True
@ -20,18 +22,22 @@ class VeryBaseModel(models.Model):
ordering = ('-created_at',)
get_latest_by = 'created_at'
# -----------------------------------------------------------------------------
class BaseModel(VeryBaseModel):
"""Абстрактная модель бух.формы."""
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+', verbose_name=u'Пользователь')
company = models.ForeignKey(UserProfile, verbose_name=u'Компания', null=True)
doc_num = models.PositiveIntegerField(u'Номер')
"""
Абстрактная модель бух.формы.
"""
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name='+',
verbose_name='Пользователь'
)
company = models.ForeignKey(UserProfile, verbose_name='Компания', null=True)
doc_num = models.PositiveIntegerField('Номер')
doc_date = models.DateField('Дата создания')
client = models.ForeignKey(Client, related_name='+', verbose_name=u'Контрагент')
client = models.ForeignKey(Client, related_name='+', verbose_name='Контрагент')
objects = managers.BaseModelManager()
@ -39,18 +45,15 @@ class BaseModel(VeryBaseModel):
abstract = True
ordering = ('-doc_date',)
def __unicode__(self):
return u'%s%s от %s' % (self._meta.verbose_name or '', self.doc_num, self.doc_date)
def __str__(self):
return u'%s%s от %s' % (self._meta.verbose_name or '', self.doc_num, self.doc_date)
return f'{self._meta.verbose_name}{self.doc_num} от {self.doc_date}'
class BaseNdsModel(BaseModel):
"""Расширение абстрактной модели бух.формы - НДС.
Доп. поля под тип и ставку НДС.
"""
nds_value = models.PositiveSmallIntegerField(u'Ставка НДС',
nds_value = models.PositiveSmallIntegerField('Ставка НДС',
choices=consts.NDS_VALUE_CHOICES,
default=consts.NDS_VALUE_0)
nds_method = models.PositiveSmallIntegerField('Метод расчета НДС',
@ -66,54 +69,56 @@ class BaseNdsModel(BaseModel):
class BaseInvoiceModel(BaseNdsModel):
"""Расширение абстрактной модели бух.формы - по типу счета.
Доп. поля под расчетный счет и дополнительные условия.
"""
bank_account = models.ForeignKey(BankAccount, related_name='+',
verbose_name=u'Расчётный счёт',
blank=True, null=True)
doc_text = models.TextField(u'Дополнительные условия', max_length=1000, blank=True, default='')
Расширение абстрактной модели бух.формы - по типу счета.
Доп. поля под расчетный счет и дополнительные условия.
"""
bank_account = models.ForeignKey(
BankAccount, related_name='+',
verbose_name='Расчётный счёт',
blank=True,
null=True
)
doc_text = models.TextField(
'Дополнительные условия',
max_length=1000,
blank=True,
default=''
)
class Meta(BaseNdsModel.Meta):
abstract = True
# -----------------------------------------------------------------------------
class BaseItemModel(VeryBaseModel):
"""Абстрактная модель табличной части бух.формы."""
name = models.CharField(u'Наименование', max_length=256)
qty = models.DecimalField(u'Кол-во', max_digits=10, decimal_places=3)
units = models.CharField(u'Ед. изм.', max_length=20)
name = models.CharField('Наименование', max_length=256)
qty = models.DecimalField('Кол-во', max_digits=10, decimal_places=3)
units = models.CharField('Ед. изм.', max_length=20)
class Meta(VeryBaseModel.Meta):
abstract = True
ordering = ('created_at',)
def __unicode__(self):
return u'%s, %s %s' % (self.name[:30], self.qty, self.units)
def __str__(self):
return u'%s, %s %s' % (self.name[:30], self.qty, self.units)
return f'{self.name[:30]}, {self.qty} {self.units}'
class BaseItemInvoiceModel(BaseItemModel):
"""Расширение абстрактной модели табл. части бух.формы - по типу счета.
Доп. поля под цену и сумму.
"""
price = models.DecimalField(u'Цена', max_digits=10, decimal_places=2)
total_price = models.DecimalField(u'Сумма', max_digits=10, decimal_places=2)
Расширение абстрактной модели табл. части бух.формы - по типу счета.
Доп. поля под цену и сумму.
"""
price = models.DecimalField('Цена', max_digits=10, decimal_places=2)
total_price = models.DecimalField('Сумма', max_digits=10, decimal_places=2)
class Meta(BaseItemModel.Meta):
abstract = True
def __unicode__(self):
curr = consts.CURRENCY_CHOICES_DICT.get(getattr(self, 'currency', consts.CURR_RUB))
return u'%s, %s %s * %s = %s %s' % (self.name[:30], self.qty, self.units, self.price, self.total_price, curr)
def __str__(self):
curr = consts.CURRENCY_CHOICES_DICT.get(getattr(self, 'currency', consts.CURR_RUB))
return u'%s, %s %s * %s = %s %s' % (self.name[:30], self.qty, self.units, self.price, self.total_price, curr)
return \
f'{self.name[:30]}, {self.qty} {self.units} * {self.price} = {self.total_price} {curr}'
def save(self, *args, **kwargs):
# пересчитать сумму

@ -6,37 +6,40 @@ from docs.models.base_models import BaseModel, VeryBaseModel
class Dover(BaseModel):
"""Доверенность на получение ТМЦ."""
doc_expire_date = models.DateField(u'Срок действия')
doc_expire_date = models.DateField('Срок действия')
# на получение мат.ценностей по документу
dover_doc = models.CharField(u'По документу №', max_length=256)
dover_doc_date = models.DateField(u'Дата документа')
dover_doc = models.CharField('По документу №', max_length=256)
dover_doc_date = models.DateField('Дата документа')
# кому выдана и его документы
dover_name = models.CharField(u'Должность, ФИО', max_length=256, help_text=u'Полностью в дат. падеже.')
dover_passport_ser = models.CharField(u'Серия', max_length=10)
dover_passport_num = models.CharField(u'Номер', max_length=10)
dover_passport_org = models.CharField(u'Кем выдан', max_length=256)
dover_passport_date = models.DateField(u'Дата выдачи')
dover_name = models.CharField(
'Должность, ФИО',
max_length=256,
help_text='Полностью в дат. падеже.'
)
dover_passport_ser = models.CharField('Серия', max_length=10)
dover_passport_num = models.CharField('Номер', max_length=10)
dover_passport_org = models.CharField('Кем выдан', max_length=256)
dover_passport_date = models.DateField('Дата выдачи')
class Meta(BaseModel.Meta):
verbose_name = u'Доверенность на получ. ТМЦ'
verbose_name_plural = u'Доверенности на получ. ТМЦ'
verbose_name = 'Доверенность на получ. ТМЦ'
verbose_name_plural = 'Доверенности на получ. ТМЦ'
class DoverItem(VeryBaseModel):
"""Табличная часть доверенности на получение ТМЦ."""
parent = models.ForeignKey(Dover, related_name='dover_items')
name = models.CharField(u'Наименование', max_length=256)
qty = models.PositiveIntegerField(u'Количество')
units = models.CharField(u'Ед. измерения', max_length=20)
name = models.CharField('Наименование', max_length=256)
qty = models.PositiveIntegerField('Количество')
units = models.CharField('Ед. измерения', max_length=20)
class Meta(VeryBaseModel.Meta):
verbose_name = u'Табл. часть доверенности'
verbose_name_plural = u'Табл. части доверенностей'
#app_label = 'docs'
verbose_name = 'Табл. часть доверенности'
verbose_name_plural = 'Табл. части доверенностей'
ordering = ('created_at',)
def __unicode__(self):
return u'%s, %s %s' % (self.name[:30], self.qty, self.units)
def __str__(self):
return f'{self.name[:30]}, {self.qty} {self.units}'

@ -10,24 +10,24 @@ from docs.models.linked_docs_mixin import LinkedDocsMixin
class Faktura(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, LinkedDocsMixin):
"""Счёт-фактура"""
doc_reason = models.CharField(u'Основание', max_length=256, blank=True, default='')
fixes = models.BooleanField(u'Изменения', default=False)
avance = models.BooleanField(u'аванс', default=False)
currency = models.ForeignKey(Currency, verbose_name=u'валюта', null=True)
user_is_sender = models.BooleanField(u'пользователь - отправитель', default=False)
doc_reason = models.CharField('Основание', max_length=256, blank=True, default='')
fixes = models.BooleanField('Изменения', default=False)
avance = models.BooleanField('аванс', default=False)
currency = models.ForeignKey(Currency, verbose_name='валюта', null=True)
user_is_sender = models.BooleanField('пользователь - отправитель', default=False)
sender = models.ForeignKey(
Client,
related_name='sender_fakturas',
blank=True,
null=True,
verbose_name=u'Отправитель'
verbose_name='Отправитель'
)
receiver = models.ForeignKey(
Client,
related_name='receiver_fakturas',
blank=True,
null=True,
verbose_name=u'Получатель'
verbose_name='Получатель'
)
plat_doc_num = models.CharField(
'Номер платёжного документа',
@ -36,7 +36,7 @@ class Faktura(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, Linke
default=''
)
plat_doc_date = models.DateField('Дата платёжного документа', blank=True, null=True)
fix_doc_num = models.PositiveIntegerField(u'Номер исправления', null=True, blank=True)
fix_doc_num = models.PositiveIntegerField('Номер исправления', null=True, blank=True)
fix_doc_date = models.DateField('Дата исправления', blank=True, null=True)
def get_consignor_and_address(self):
@ -44,24 +44,24 @@ class Faktura(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, Linke
"""
if self.user_is_sender:
return u'%s, %s' % (self.user.profile.get_company_name(), self.user.profile.address)
return f'{self.user.profile.get_company_name()}, {self.user.profile.address}'
elif self.sender:
return '%s, %s' % (self.sender.name, self.sender.address)
return f'{self.sender.name}, {self.sender.address}'
else:
return u''
return ''
def get_receiver_and_address(self):
"""Получатель и адрес
"""
if self.receiver:
return '%s, %s' % (self.receiver.name, self.receiver.address)
return f'{self.receiver.name}, {self.receiver.address}'
else:
return u''
return ''
class Meta(BaseInvoiceModel.Meta):
verbose_name = u'Счёт-фактура'
verbose_name_plural = u'Счета-фактуры'
app_label="docs"
verbose_name = 'Счёт-фактура'
verbose_name_plural = 'Счета-фактуры'
app_label = "docs"
class FakturaItem(BaseItemInvoiceModel):
@ -70,20 +70,20 @@ class FakturaItem(BaseItemInvoiceModel):
'Код единицы измерения',
max_length=10,
blank=True,
default=u'-'
default='-'
)
parent = models.ForeignKey(Faktura, related_name='faktura_items')
country_code = models.CharField(u'Код страны', max_length=10, blank=True, default=u'-')
country_name = models.CharField(u'Название страны', max_length=256)
gtd = models.CharField(u'Основание', max_length=256, blank=True, default='')
country_code = models.CharField('Код страны', max_length=10, blank=True, default='-')
country_name = models.CharField('Название страны', max_length=256)
gtd = models.CharField('Основание', max_length=256, blank=True, default='')
ntd = models.CharField(
u'Номер транспортной декларации',
'Номер транспортной декларации',
max_length=256,
blank=True,
default=''
)
class Meta(BaseItemInvoiceModel.Meta):
verbose_name = u'Табл. часть фактуры'
verbose_name_plural = u'Табл. части фактур'
verbose_name = 'Табл. часть фактуры'
verbose_name_plural = 'Табл. части фактур'
app_label = "docs"

@ -16,17 +16,21 @@ class Invoice(BaseInvoiceModel, LinkedDocsMixin):
PAID = 3
PAID_CHOICES = (
(UNPAID, u'Нет'),
(PARTLY_PAID, u'Частично'),
(PAID, u'Да'),
(UNPAID, 'Нет'),
(PARTLY_PAID, 'Частично'),
(PAID, 'Да'),
)
paid_status = models.PositiveSmallIntegerField(u'Оплачен?', choices=PAID_CHOICES, default=UNPAID)
closed_status = models.BooleanField(u'Закрыт?', choices=consts.BOOL_CHOICES, default=False)
paid_status = models.PositiveSmallIntegerField(
'Оплачен?',
choices=PAID_CHOICES,
default=UNPAID
)
closed_status = models.BooleanField('Закрыт?', choices=consts.BOOL_CHOICES, default=False)
class Meta(BaseInvoiceModel.Meta):
verbose_name = u'Счёт'
verbose_name_plural = u'Счета'
verbose_name = 'Счёт'
verbose_name_plural = 'Счета'
def to_string_for_json(self):
# Счёт №Х от ХХ.ХХ.ХХ, Х позиций, на сумму ХХ.
@ -53,5 +57,5 @@ class InvoiceItem(BaseItemInvoiceModel):
parent = models.ForeignKey(Invoice, related_name='invoice_items')
class Meta(BaseItemInvoiceModel.Meta):
verbose_name = u'Табл. часть счета'
verbose_name_plural = u'Табл. части счетов'
verbose_name = 'Табл. часть счета'
verbose_name_plural = 'Табл. части счетов'

@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.core.exceptions import FieldError
class LinkedDocsMixin(models.Model):
@ -14,7 +13,8 @@ class LinkedDocsMixin(models.Model):
if getattr(self, '_cache_linked_docs', None) is None:
self._cache_linked_docs = {}
model_name = self.__class__.__name__ # имя модели на инстансе которой вызвали метод linked_docs
# имя модели на инстансе которой вызвали метод linked_docs
model_name = self.__class__.__name__
if model_name == 'Invoice':
invoice_id = self.id

@ -6,8 +6,14 @@ from docs import consts
class SignedStatusFieldMixin(models.Model):
"""Mixin: добавляет поле `Подписан?`"""
signed_status = models.BooleanField(u'Подписан?', choices=consts.BOOL_CHOICES, default=False)
"""
Mixin: добавляет поле `Подписан?`
"""
signed_status = models.BooleanField(
'Подписан?',
choices=consts.BOOL_CHOICES,
default=False
)
class Meta:
abstract = True
@ -15,8 +21,15 @@ class SignedStatusFieldMixin(models.Model):
class InvoiceFieldMixin(models.Model):
"""Mixin: добавляет FK поле `Создать по счёту`"""
invoice = models.ForeignKey(Invoice, related_name='+', verbose_name=u'Создать по счёту', blank=True, null=True,
default=None, on_delete=models.SET_NULL)
invoice = models.ForeignKey(
Invoice,
related_name='+',
verbose_name='Создать по счёту',
blank=True,
null=True,
default=None,
on_delete=models.SET_NULL
)
class Meta:
abstract = True

@ -8,19 +8,19 @@ from docs.models.linked_docs_mixin import LinkedDocsMixin
class Nakladn(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, LinkedDocsMixin):
"""Накладная торг12."""
doc_reason = models.CharField(u'Основание', max_length=256, blank=True, default='')
doc_reason = models.CharField('Основание', max_length=256, blank=True, default='')
class Meta(BaseInvoiceModel.Meta):
verbose_name = u'Накладная'
verbose_name_plural = u'Накладные'
verbose_name = 'Накладная'
verbose_name_plural = 'Накладные'
class NakladnItem(BaseItemInvoiceModel):
"""Табличная часть накладной торг12."""
parent = models.ForeignKey(Nakladn, related_name='nakladn_items')
units_kod = models.CharField(u'Код единицы измерения', max_length=20, blank=True, default=u'-')
units_kod = models.CharField('Код единицы измерения', max_length=20, blank=True, default='-')
class Meta(BaseItemInvoiceModel.Meta):
verbose_name = u'Табл. часть накладной'
verbose_name_plural = u'Табл. части накладных'
verbose_name = 'Табл. часть накладной'
verbose_name_plural = 'Табл. части накладных'

@ -9,45 +9,68 @@ from docs import consts
class Platejka(BaseModel):
"""Платёжное поручение."""
platej_type = models.PositiveSmallIntegerField(u'Тип платёжного поручения', choices=consts.PLATEJ_TYPE_CHOICES,
default=consts.PLATEJ_TYPE_COMMERCE)
platej_type = models.PositiveSmallIntegerField(
'Тип платёжного поручения',
choices=consts.PLATEJ_TYPE_CHOICES,
default=consts.PLATEJ_TYPE_COMMERCE
)
bank_account = models.ForeignKey(BankAccount, related_name='+', verbose_name=u'Расчётный счёт')
bank_account = models.ForeignKey(BankAccount, related_name='+', verbose_name='Расчётный счёт')
doc_total = models.DecimalField(u'Сумма', max_digits=10, decimal_places=2)
payment_type = models.PositiveSmallIntegerField(u'Вид платежа', choices=consts.PAYMENT_TYPE_CHOICES,
default=consts.PAYMENT_TYPE_CHOICES[0][0])
payment_order = models.CharField(u'Очерёдность платежа', max_length=10)
doc_info = models.TextField(u'Назначение платежа', max_length=1000)
doc_total = models.DecimalField('Сумма', max_digits=10, decimal_places=2)
payment_type = models.PositiveSmallIntegerField(
'Вид платежа',
choices=consts.PAYMENT_TYPE_CHOICES,
default=consts.PAYMENT_TYPE_CHOICES[0][0]
)
payment_order = models.CharField('Очерёдность платежа', max_length=10)
doc_info = models.TextField('Назначение платежа', max_length=1000)
# поля только для перевода денег (коммерческое)
nds_value = models.PositiveSmallIntegerField(u'Ставка НДС', choices=consts.NDS_VALUE_CHOICES, default=consts.NDS_VALUE_0)
nds_value = models.PositiveSmallIntegerField(
'Ставка НДС',
choices=consts.NDS_VALUE_CHOICES,
default=consts.NDS_VALUE_0
)
# поля только для оплаты налогов (налоговое)
tax_status = models.CharField(u'Статус составителя', max_length=10, choices=consts.TAX_STATUS_CHOICES,
default=consts.TAX_STATUS_CHOICES[0][0])
tax_base = models.CharField(u'Основание налогового платежа', max_length=10, choices=consts.TAX_BASE,
default=consts.TAX_BASE[0][0])
tax_type = models.CharField(u'Тип налогового платежа', max_length=10, choices=consts.TAX_TYPE,
default=consts.TAX_TYPE[0][0])
tax_num = models.CharField(u'Номер документа основания', max_length=50, blank=True, default='')
tax_date = models.DateField(u'Дата документа основания', blank=True, null=True)
tax_bk = models.CharField(u'Код БК доходов РФ', max_length=256)
tax_okato = models.CharField(u'Код ОКАТО сборщика платежей', max_length=256)
tax_period = models.CharField(u'Период, за который начисляется налог', max_length=256,
help_text = (u'Формат ввода периода платежей:<br />'
u'Месячный платёж - "МС.00.0000"<br />'
u'Квартальный платёж - "КВ.00.0000"<br />'
u'Полугодовой платёж - "ПЛ.00.0000"<br />'
u'Годовой платёж - "ГД.00.0000"<br />'
u'Платёж по дате - "дд.мм.гггг"')
tax_status = models.CharField(
'Статус составителя',
max_length=10,
choices=consts.TAX_STATUS_CHOICES,
default=consts.TAX_STATUS_CHOICES[0][0]
)
tax_base = models.CharField(
'Основание налогового платежа',
max_length=10,
choices=consts.TAX_BASE,
default=consts.TAX_BASE[0][0]
)
tax_type = models.CharField(
'Тип налогового платежа',
max_length=10,
choices=consts.TAX_TYPE,
default=consts.TAX_TYPE[0][0]
)
tax_num = models.CharField('Номер документа основания', max_length=50, blank=True, default='')
tax_date = models.DateField('Дата документа основания', blank=True, null=True)
tax_bk = models.CharField('Код БК доходов РФ', max_length=256)
tax_okato = models.CharField('Код ОКАТО сборщика платежей', max_length=256)
tax_period = models.CharField('Период, за который начисляется налог', max_length=256,
help_text=('Формат ввода периода платежей:<br />'
'Месячный платёж - "МС.00.0000"<br />'
'Квартальный платёж - "КВ.00.0000"<br />'
'Полугодовой платёж - "ПЛ.00.0000"<br />'
'Годовой платёж - "ГД.00.0000"<br />'
'Платёж по дате - "дд.мм.гггг"')
)
class Meta(BaseModel.Meta):
verbose_name = u'Платёжное поручение'
verbose_name_plural = u'Платёжные поручения'
verbose_name = 'Платёжное поручение'
verbose_name_plural = 'Платёжные поручения'
# хелперы, чтоб не оборачивать в шаблонах каждое обращение к определенным полям в проверку типа платежа
# хелперы, чтоб не оборачивать в шаблонах каждое обращение к
# определенным полям в проверку типа платежа
def is_commerce(self):
return self.platej_type == consts.PLATEJ_TYPE_COMMERCE
@ -59,46 +82,46 @@ class Platejka(BaseModel):
"""Налоги. Статус составителя, КОД."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_status:
return self.tax_status
return u''
return ''
def get_tax_base_kod(self):
"""Налоги. Основание налогового платежа, КОД."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_base:
return self.tax_base
return u''
return ''
def get_tax_type_kod(self):
"""Налоги. Тип налогового платежа, КОД."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_type:
return self.tax_type
return u''
return ''
def get_tax_num(self):
"""Налоги. Номер документа основания."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_num:
return self.tax_num
return u''
return ''
def get_tax_date(self):
"""Налоги. Дата документа основания."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_date:
return self.tax_date
return u''
return ''
def get_tax_bk(self):
"""Налоги. Код БК доходов РФ."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_bk:
return self.tax_bk
return u''
return ''
def get_tax_okato(self):
"""Налоги. Код ОКАТО сборщика платежей."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_okato:
return self.tax_okato
return u''
return ''
def get_tax_period(self):
"""Налоги. Период, за который начисляется налог."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_period:
return self.tax_period
return u''
return ''

@ -1,16 +0,0 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

@ -1,13 +1,15 @@
# -*- coding: UTF-8 -*-
from django.conf.urls import *
from django.conf.urls import url
from docs.views import (InvoiceViews, AktRabotViews, AktSverkiViews, DoverViews, PlatejkaViews, NakladnViews, FakturaViews)
from docs.views import getview, index, get_invoices, get_tbl_items, get_client_by_invoice, toggle_doc_status
from docs.views import (InvoiceViews, AktRabotViews, AktSverkiViews,
DoverViews, PlatejkaViews, NakladnViews, FakturaViews)
from docs.views import (getview, index, get_invoices, get_tbl_items,
get_client_by_invoice, toggle_doc_status)
urlpatterns = patterns('docs.views',
url(r'^$', index, name='docs_index'), # страница со ссылками на бух. формы
)
urlpatterns = [
# страница со ссылками на бух. формы
url(r'^$', index, name='docs_index'),
]
klasses = [
('invoice', InvoiceViews),
@ -20,62 +22,83 @@ klasses = [
]
for name, klass in klasses:
urlpatterns += patterns('docs.views',
urlpatterns += [
# список
url(r'^%s/$' % name, getview, {'klass': klass, 'oper': 'list',}, name='docs_%s_list' % name),
url(r'^%s/$' % name, getview, {'klass': klass, 'oper': 'list', },
name='docs_%s_list' % name),
# список, пагинация
url(r'^%s/page/(?P<page_num>[0-9]+)/$' % name, getview, {'klass': klass, 'oper': 'list',},
url(r'^%s/page/(?P<page_num>[0-9]+)/$' % name, getview,
{'klass': klass, 'oper': 'list', },
name='docs_%s_list' % name),
# добавить
url(r'^%s/add/$' % name, getview, {'klass': klass, 'oper': 'add',}, name='docs_%s_add' % name),
url(r'^%s/add/$' % name, getview, {'klass': klass, 'oper': 'add', },
name='docs_%s_add' % name),
# редактировать
url(r'^%s/(?P<id>\d+)/edit/$' % name, getview, {'klass': klass, 'oper': 'edit',},
url(r'^%s/(?P<id>\d+)/edit/$' % name, getview,
{'klass': klass, 'oper': 'edit', },
name='docs_%s_edit' % name),
# создать копию
url(r'^%s/(?P<id>\d+)/copy/$' % name, getview, {'klass': klass, 'oper': 'copy',},
url(r'^%s/(?P<id>\d+)/copy/$' % name, getview,
{'klass': klass, 'oper': 'copy', },
name='docs_%s_copy' % name),
# удалить
url(r'^%s/(?P<id>\d+)/delete/$' % name, getview, {'klass': klass, 'oper': 'delete',},
url(r'^%s/(?P<id>\d+)/delete/$' % name, getview,
{'klass': klass, 'oper': 'delete', },
name='docs_%s_delete' % name),
# сохранить в pdf
url(r'^%s/(?P<id>\d+)/pdf/$' % name, getview, {'klass': klass, 'oper': 'as_pdf',},
url(r'^%s/(?P<id>\d+)/pdf/$' % name, getview,
{'klass': klass, 'oper': 'as_pdf', },
name='docs_%s_pdf' % name),
# показать картинку
url(r'^%s/(?P<id>\d+)/preview/$' % name, getview, {'klass': klass, 'oper': 'as_img',},
url(r'^%s/(?P<id>\d+)/preview/$' % name, getview,
{'klass': klass, 'oper': 'as_img', },
name='docs_%s_img' % name),
# сохранить в excel
url(r'^%s/(?P<id>\d+)/xls/$' % name, getview, {'klass': klass, 'oper': 'as_xls',},
url(r'^%s/(?P<id>\d+)/xls/$' % name, getview,
{'klass': klass, 'oper': 'as_xls', },
name='docs_%s_xls' % name),
# отправить pdf/xls на email
url(r'^%s/(?P<id>\d+)/email/$' % name, getview, {'klass': klass, 'oper': 'email',},
url(r'^%s/(?P<id>\d+)/email/$' % name, getview,
{'klass': klass, 'oper': 'email', },
name='docs_%s_email' % name),
# поля документа - AJAX
url(r'^%s/(?P<id>\d+)/get/ajax/$' % name, getview, {'klass': klass, 'oper': 'get_ajax',},
url(r'^%s/(?P<id>\d+)/get/ajax/$' % name, getview,
{'klass': klass, 'oper': 'get_ajax', },
name='docs_%s_get_ajax' % name),
# отправить pdf/xls на email - AJAX
url(r'^%s/(?P<id>\d+)/email/ajax/$' % name, getview, {'klass': klass, 'oper': 'email_ajax',},
url(r'^%s/(?P<id>\d+)/email/ajax/$' % name, getview,
{'klass': klass, 'oper': 'email_ajax', },
name='docs_%s_email_ajax' % name),
url(r'^ajax_get_invoices/$', get_invoices, name='ajax_get_invoices'),
url(r'^ajax_get_invoices/(?P<client_id>\d+)/$', get_invoices, name='ajax_get_invoices'),
url(r'^ajax_get_tbl_items/(?P<invoice_id>\d+)/$', get_tbl_items, name='ajax_get_tbl_items'),
url(r'^ajax_get_client_by_invoice/(?P<invoice_id>\d+)/$', get_client_by_invoice, name='ajax_get_client_by_invoice'),
url(r'^ajax_toggle_doc_status/(?P<doc_type>\w+)/(?P<doc_id>\d+)/(?P<doc_attr>\w+)/$', toggle_doc_status, name='ajax_get_client_by_invoice'),
)
url(r'^ajax_get_invoices/(?P<client_id>\d+)/$', get_invoices,
name='ajax_get_invoices'),
url(r'^ajax_get_tbl_items/(?P<invoice_id>\d+)/$', get_tbl_items,
name='ajax_get_tbl_items'),
url(r'^ajax_get_client_by_invoice/(?P<invoice_id>\d+)/$',
get_client_by_invoice, name='ajax_get_client_by_invoice'),
url(
r'^ajax_toggle_doc_status/(?P<doc_type>\w+)/(?P<doc_id>\d+)/(?P<doc_attr>\w+)/$',
toggle_doc_status, name='ajax_get_client_by_invoice'),
]
# доп. обработчики: создать Документ по Счету
urlpatterns += patterns('docs.views',
urlpatterns += [
# создать по Счету -> Акт вып. работ
url(r'^%s/add/by/invoice/(?P<invoice_id>\d+)/$' % 'aktrabot', getview,
{'klass': AktRabotViews, 'oper': 'add_by_invoice'}, name='docs_%s_add_by_invoice' % 'aktrabot'),
{'klass': AktRabotViews, 'oper': 'add_by_invoice'},
name='docs_%s_add_by_invoice' % 'aktrabot'),
# создать по Счету -> Накладную
url(r'^%s/add/by/invoice/(?P<invoice_id>\d+)/$' % 'nakladn', getview,
{'klass': NakladnViews, 'oper': 'add_by_invoice'}, name='docs_%s_add_by_invoice' % 'nakladn'),
{'klass': NakladnViews, 'oper': 'add_by_invoice'},
name='docs_%s_add_by_invoice' % 'nakladn'),
# создать по Счету -> Счёт-фактуру
url(r'^%s/add/by/invoice/(?P<invoice_id>\d+)/$' % 'faktura', getview, {'klass': FakturaViews, 'oper': 'add_by_invoice',},
url(r'^%s/add/by/invoice/(?P<invoice_id>\d+)/$' % 'faktura', getview,
{'klass': FakturaViews, 'oper': 'add_by_invoice', },
name='docs_%s_add_by_invoice' % 'faktura'),
)
]

@ -28,7 +28,7 @@ def calc_clean_total_price(obj):
def calc_total_nds(obj):
"""Считает сумму налога."""
total_price = obj.price * obj.qty
nds_rate = get_nds(obj.parent.nds_value)/100
nds_rate = get_nds(obj.parent.nds_value) / 100
total_nds = total_price * nds_rate
return total_nds
@ -52,7 +52,7 @@ def get_total_nds(obj):
"""Считает сумму налога."""
total_price = obj.price * obj.qty
if obj.parent.nds_method:
nds_rate = get_nds(obj.parent.nds_value)/100
nds_rate = get_nds(obj.parent.nds_value) / 100
total_nds = total_price * nds_rate
else:
nds_rate = get_nds(obj.parent.nds_value) / (100 + get_nds(obj.parent.nds_value))

@ -2,14 +2,15 @@
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from docs.views.invoice import InvoiceViews
from docs.views.aktrabot import AktRabotViews
from docs.views.aktsverki import AktSverkiViews
from docs.views.dover import DoverViews
from docs.views.platejka import PlatejkaViews
from docs.views.nakladn import NakladnViews
from docs.views.faktura import FakturaViews
from docs.views.ajax import get_invoices, get_tbl_items, get_client_by_invoice, toggle_doc_status
from docs.views.invoice import InvoiceViews # noqa
from docs.views.aktrabot import AktRabotViews # noqa
from docs.views.aktsverki import AktSverkiViews # noqa
from docs.views.dover import DoverViews # noqa
from docs.views.platejka import PlatejkaViews # noqa
from docs.views.nakladn import NakladnViews # noqa
from docs.views.faktura import FakturaViews # noqa
from docs.views.ajax import (get_invoices, get_tbl_items, # noqa
get_client_by_invoice, toggle_doc_status) # noqa
@login_required # важно!!!
@ -22,8 +23,6 @@ def getview(request, *args, **kwargs):
return handler(request, *args, **kwargs)
# -----------------------------------------------------------------------------
@login_required
def index(request):
"""Страница со ссылками на все бух.формы."""

@ -37,7 +37,6 @@ from customer.utils import raise_if_no_profile
from django.conf import settings
import traceback
DEBUG = getattr(settings, 'DEBUG', False)
SUPPORT_EMAIL = getattr(settings, 'SUPPORT_EMAIL', '')
MEDIA_ROOT = getattr(settings, 'MEDIA_ROOT', '')
@ -94,7 +93,7 @@ class BaseViews(object):
# для генерации pdf/xls
PDF_TEMPLATE = ''
XLS_TEMPLATE = ''
FILENAME = u'Документ № %s, %s' # без расширения
FILENAME = u'Документ № %s, %s' # без расширения
MAYBE_SIGNED = False
# --- константы для вывода наименований в шаблонах
@ -128,13 +127,13 @@ class BaseViews(object):
"""Проверить объект класса на типичные ошибки."""
assert self.request is not None, \
(u"%s.request can't be None!" % self.__class__.__name__)
assert self.MODEL is not None,\
assert self.MODEL is not None, \
(u"%s.MODEL can't be None!" % self.__class__.__name__)
assert self.FORM_CLASS is not None, \
(u"%s.FORM_CLASS can't be None!" % self.__class__.__name__)
assert self.EMAIL_FORM_CLASS is not None,\
assert self.EMAIL_FORM_CLASS is not None, \
(u"%s.EMAIL_FORM_CLASS can't be None!" % self.__class__.__name__)
assert (isinstance(self.ORDER_FIELDS, tuple) or isinstance(self.ORDER_FIELDS, list)),\
assert (isinstance(self.ORDER_FIELDS, tuple) or isinstance(self.ORDER_FIELDS, list)), \
(u"%s.ORDER_FIELDS should be of tuple or list type!" % self.__class__.__name__)
assert self.FILTERSET_CLASS is not None, \
(u"%s.FILTERSET_CLASS can't be None!" % self.__class__.__name__)
@ -149,7 +148,7 @@ class BaseViews(object):
def get_ordering(self):
"""Поле и порядок сортировки."""
order_field, order_type = 'doc_date', 'desc' # default
order_field, order_type = 'doc_date', 'desc' # default
params = dict(self.request.GET.items())
if params.get(ORDER_VAR) in self.ORDER_FIELDS:
order_field = params.get(ORDER_VAR)
@ -248,7 +247,7 @@ class BaseViews(object):
def init_form(self):
"""Начальные значения полей формы документа."""
initial = {'doc_date': datetime.now(),}
initial = {'doc_date': datetime.now(), }
# номер нового документа
doc_num = self.MODEL.objects.get_max_doc_num(self.request.user) or 0
initial['doc_num'] = doc_num + 1
@ -322,7 +321,7 @@ class BaseViews(object):
data=self.request.POST, instance=obj)
if form.is_valid():
new_obj = form.save()
form.save()
return redirect(self.REDIRECT_AFTER_EDIT)
else:
form = self.FORM_CLASS(self.request.user, instance=obj)
@ -381,7 +380,7 @@ class BaseViews(object):
c1 = time()
pdf = render_pdf_to_string(self.request, self.PDF_TEMPLATE, params)
if DEBUG:
print('%s generation time (seconds): %s' % (self.PDF_TEMPLATE, time()-c1,))
print('%s generation time (seconds): %s' % (self.PDF_TEMPLATE, time() - c1,))
return pdf
def get_xls(self, *args, **kwargs):
@ -399,7 +398,7 @@ class BaseViews(object):
c1 = time()
xls = render_xls_to_string(self.request, self.XLS_TEMPLATE, params)
if DEBUG:
print('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time()-c1,))
print('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time() - c1,))
return xls
def as_img(self, *args, **kwargs):
@ -454,15 +453,15 @@ class BaseViews(object):
imgs.sort()
email_form = self.EMAIL_FORM_CLASS()
dictionary = {
'obj': obj,
'images': imgs,
'padeji': self.PADEJI,
'padeji_mnoj': self.PADEJI_MNOJ,
'url_prefix': self.URL_PREFIX,
'template_create_docs': self.TEMPLATE_CREATE_DOCS,
'template_linked_docs_list': self.TEMPLATE_LINKED_DOCS_LIST,
'email_form': email_form,
'maybe_sign': self.MAYBE_SIGNED,
'obj': obj,
'images': imgs,
'padeji': self.PADEJI,
'padeji_mnoj': self.PADEJI_MNOJ,
'url_prefix': self.URL_PREFIX,
'template_create_docs': self.TEMPLATE_CREATE_DOCS,
'template_linked_docs_list': self.TEMPLATE_LINKED_DOCS_LIST,
'email_form': email_form,
'maybe_sign': self.MAYBE_SIGNED,
}
return render(self.request, self.TEMPLATE_IMG, dictionary)
except:
@ -500,7 +499,7 @@ class BaseViews(object):
def send_email(self, subject, to, body, files, sign_doc):
"""Отправка письма."""
dict_context = {'body': body, 'support_email': SUPPORT_EMAIL,}
dict_context = {'body': body, 'support_email': SUPPORT_EMAIL}
email_body = render_to_string(self.EMAIL_MSG_TEMPLATE, dict_context)
attachments = []
@ -595,8 +594,8 @@ class BaseViews(object):
data = {
'success': form.is_valid(),
'field_errors': form.errors, # ошибки полей
'form_errors': non_field_errors, # ошибки формы
'field_errors': form.errors, # ошибки полей
'form_errors': non_field_errors, # ошибки формы
}
if form.is_valid() and result:
data['message'] = {'title': 'Инфо', 'msg': 'Письмо отправлено.'}
@ -611,6 +610,7 @@ class BaseViews(object):
data = json.dumps(obj, default=dthandler())
return HttpResponse(data, content_type='application/json')
# -----------------------------------------------------------------------------
@ -639,9 +639,9 @@ class BaseItemsViews(BaseViews):
def set_item_formset_class(self, extra_count=2):
"""Класс FormSet-а для табличной части документа."""
self.ITEM_FORMSET_CLASS = inlineformset_factory(
parent_model = self.MODEL,
model = self.ITEM_MODEL,
form = self.ITEM_FORM_CLASS,
parent_model=self.MODEL,
model=self.ITEM_MODEL,
form=self.ITEM_FORM_CLASS,
extra=extra_count,
can_delete=True,
)
@ -863,7 +863,7 @@ class BaseItemsViews(BaseViews):
c1 = time()
pdf = render_pdf_to_string(self.request, self.PDF_TEMPLATE, params)
if DEBUG:
print('%s generation time (seconds): %s' % (self.PDF_TEMPLATE, time()-c1,))
print('%s generation time (seconds): %s' % (self.PDF_TEMPLATE, time() - c1,))
return pdf
def get_xls(self, *args, **kwargs):
@ -882,5 +882,5 @@ class BaseItemsViews(BaseViews):
c1 = time()
xls = render_xls_to_string(self.request, self.XLS_TEMPLATE, params)
if DEBUG:
print('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time()-c1,))
print('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time() - c1,))
return xls

@ -61,7 +61,10 @@ class DoverViews(BaseItemsViews):
}
def update_list_dict(self, dictionary):
"""Здесь можно изменить словарь параметров перед передачей его в шаблон вывода списка документов."""
"""
Здесь можно изменить словарь параметров перед передачей
его в шаблон вывода списка документов.
"""
dictionary['clients_form'] = ClientsListForm(self.request.user)
def init_form(self):

@ -22,7 +22,8 @@ class InvoiceViews(BaseItemsViews):
ITEM_FORM_CLASS = InvoiceItemForm # форма табличной части документа
ITEM_FORM_PREFIX = 'invoice_items' # префикс формы табличной части
ORDER_FIELDS = ('doc_date', 'doc_num', 'client__name', 'doc_sum', 'paid_status', 'closed_status')
ORDER_FIELDS = (
'doc_date', 'doc_num', 'client__name', 'doc_sum', 'paid_status', 'closed_status')
FILTERSET_CLASS = InvoiceFilterSet # фильтры
@ -45,26 +46,26 @@ class InvoiceViews(BaseItemsViews):
# для генерации pdf/xls
PDF_TEMPLATE = 'docs/invoice/as_pdf.html'
XLS_TEMPLATE = 'invoice.xls'
FILENAME = u'Счет № %s, %s' # без расширения
FILENAME = u'Счет № %s, %s' # без расширения
MAYBE_SIGNED = True
# --- грамматика для вывода наименований в шаблонах
PADEJI = {
'imenit': u'счёт', # кто? что?
'rodit': u'счёта', # кого? чего?
'dateln': u'счёту', # кому? чему?
'vinit': u'счёт', # кого? что?
'tvorit': u'счётом', # кем? чем?
'predlojn': u'счёте', # о ком? о чём?
'imenit': u'счёт', # кто? что?
'rodit': u'счёта', # кого? чего?
'dateln': u'счёту', # кому? чему?
'vinit': u'счёт', # кого? что?
'tvorit': u'счётом', # кем? чем?
'predlojn': u'счёте', # о ком? о чём?
}
PADEJI_MNOJ = {
'imenit': u'счета', # кто? что?
'rodit': u'счетов', # кого? чего?
'dateln': u'счетам', # кому? чему?
'vinit': u'счета', # кого? что?
'tvorit': u'счетами', # кем? чем?
'predlojn': u'счетах', # о ком? о чём?
'imenit': u'счета', # кто? что?
'rodit': u'счетов', # кого? чего?
'dateln': u'счетам', # кому? чему?
'vinit': u'счета', # кого? что?
'tvorit': u'счетами', # кем? чем?
'predlojn': u'счетах', # о ком? о чём?
}
def update_list_dict(self, dictionary):

@ -48,26 +48,26 @@ class NakladnViews(BaseItemsViews, AddByInvoiceMethodMixin):
# для генерации pdf/xls
PDF_TEMPLATE = 'docs/nakladn/as_pdf.html'
XLS_TEMPLATE = 'nakladn.xls'
FILENAME = u'Накладная № %s, %s' # без расширения
FILENAME = u'Накладная № %s, %s' # без расширения
MAYBE_SIGNED = True
# --- грамматика для вывода наименований в шаблонах
PADEJI = {
'imenit': u'накладная', # кто? что?
'rodit': u'накладной', # кого? чего?
'dateln': u'накладной', # кому? чему?
'vinit': u'накладную', # кого? что?
'tvorit': u'накладной', # кем? чем?
'predlojn': u'накладной', # о ком? о чём?
'imenit': u'накладная', # кто? что?
'rodit': u'накладной', # кого? чего?
'dateln': u'накладной', # кому? чему?
'vinit': u'накладную', # кого? что?
'tvorit': u'накладной', # кем? чем?
'predlojn': u'накладной', # о ком? о чём?
}
PADEJI_MNOJ = {
'imenit': u'накладные', # кто? что?
'rodit': u'накладных', # кого? чего?
'dateln': u'накладным', # кому? чему?
'vinit': u'накладные', # кого? что?
'tvorit': u'накладными', # кем? чем?
'predlojn': u'накладных', # о ком? о чём?
'imenit': u'накладные', # кто? что?
'rodit': u'накладных', # кого? чего?
'dateln': u'накладным', # кому? чему?
'vinit': u'накладные', # кого? что?
'tvorit': u'накладными', # кем? чем?
'predlojn': u'накладных', # о ком? о чём?
}
def prepare(self, obj, obj_items, export_to=None):
@ -132,12 +132,12 @@ class NakladnViews(BaseItemsViews, AddByInvoiceMethodMixin):
name_rows = max(1, len(name.split('\n'))) + 1
# строка, подитог и итог не помещаются на странице
if (curr_rows + name_rows + tbl_page_footer_rows +
tbl_footer_rows > page_rows):
tbl_footer_rows > page_rows):
if idx == 0:
item.pdf_pagebreak_before = True
prev_item = item
else:
prev_item = obj_items[idx-1]
prev_item = obj_items[idx - 1]
prev_item.pdf_pagebreak_after = True
prev_item.pdf_page_footer = True

@ -11,13 +11,13 @@ from .base_views import BaseViews
class PlatejkaViews(BaseViews):
"""Views для платежных поручений."""
MODEL = Platejka # модель документа
FORM_CLASS = PlatejkaForm # форма документа
MODEL = Platejka # модель документа
FORM_CLASS = PlatejkaForm # форма документа
# поля, по которым можно сортировать список документов
ORDER_FIELDS = ('doc_date', 'doc_num', 'doc_info', 'doc_total',)
FILTERSET_CLASS = PlatejkaFilterSet # фильтры
FILTERSET_CLASS = PlatejkaFilterSet # фильтры
# префикс именованных урлов этого типа документов, для передачи в шаблон
URL_PREFIX = 'docs_platejka_'
@ -34,27 +34,30 @@ class PlatejkaViews(BaseViews):
# для генерации pdf/xls
PDF_TEMPLATE = 'docs/platejka/as_pdf.html'
XLS_TEMPLATE = 'platejka.xls'
FILENAME = u'Платежное поручение № %s, %s' # без расширения
FILENAME = u'Платежное поручение № %s, %s' # без расширения
# --- грамматика для вывода наименований в шаблонах
PADEJI = {
'imenit': u'платёжное поручение', # кто? что?
'rodit': u'платёжного поручения', # кого? чего?
'dateln': u'платёжному поручению', # кому? чему?
'vinit': u'платёжное поручение', # кого? что?
'tvorit': u'платёжным поручением', # кем? чем?
'predlojn': u'платёжном поручении', # о ком? о чём?
'imenit': u'платёжное поручение', # кто? что?
'rodit': u'платёжного поручения', # кого? чего?
'dateln': u'платёжному поручению', # кому? чему?
'vinit': u'платёжное поручение', # кого? что?
'tvorit': u'платёжным поручением', # кем? чем?
'predlojn': u'платёжном поручении', # о ком? о чём?
}
PADEJI_MNOJ = {
'imenit': u'платёжные поручения', # кто? что?
'rodit': u'платёжных поручений', # кого? чего?
'dateln': u'платёжным поручениям', # кому? чему?
'vinit': u'платёжные поручения', # кого? что?
'tvorit': u'платёжными поручениями', # кем? чем?
'predlojn': u'платёжных поручениях', # о ком? о чём?
'imenit': u'платёжные поручения', # кто? что?
'rodit': u'платёжных поручений', # кого? чего?
'dateln': u'платёжным поручениям', # кому? чему?
'vinit': u'платёжные поручения', # кого? что?
'tvorit': u'платёжными поручениями', # кем? чем?
'predlojn': u'платёжных поручениях', # о ком? о чём?
}
def update_list_dict(self, dictionary):
"""Здесь можно изменить словарь параметров перед передачей его в шаблон вывода списка документов."""
"""
Здесь можно изменить словарь параметров перед передачей
его в шаблон вывода списка документов.
"""
dictionary['dadata_api_key'] = settings.DADATA_API_KEY

@ -12,6 +12,6 @@ env.load(env_file)
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
try:
from .celery import app as celery_app
from .celery import app as celery_app # noqa
except ImportError as e:
warnings.warn('Celery import error, is it installed?')

@ -1,7 +1,7 @@
# coding: utf-8
from celery import Celery
from django.conf import settings
from django.conf import settings # noqa
app = Celery('dokumentor')
app.config_from_object('django.conf:settings', namespace='CELERY')

@ -1,3 +1,4 @@
# flake8: noqa
# -*- coding: utf-8 -*-
import os
@ -150,7 +151,7 @@ INSTALLED_APPS = [
# 'cmsplugin_filer_folder',
# 'cmsplugin_filer_link',
# 'cmsplugin_filer_image',
# 'cmsplugin_filer_teaser' ,
# 'cmsplugin_filer_teaser',
# 'cmsplugin_filer_video',
'captcha',

@ -1,3 +1,4 @@
# flake8: noqa
# -*- coding: utf-8 -*-
import dj_database_url

@ -1,8 +1,9 @@
# flake8: noqa
# coding: utf-8
import dj_database_url
from src.dokumentor.settings.common import * # noqa
from src.dokumentor.settings.common import *
DEBUG = False
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG

@ -1,8 +1,9 @@
# flake8: noqa
# coding: utf-8
import dj_database_url
from src.dokumentor.settings.common import * # noqa
from src.dokumentor.settings.common import *
DEBUG = False
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG

@ -1,4 +1,6 @@
# flake8: noqa
# -*- coding: utf-8 -*-
import logging
import dj_database_url

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from django.conf import settings
from django.contrib import admin
from django.conf.urls import patterns, include, url
from django.conf.urls import include, url
import autocomplete_light
from django.conf.urls.static import static
@ -14,9 +13,7 @@ admin.site.site_header = 'Документор'
admin.site.index_title = 'Документор'
admin.site.site_title = 'Документор'
urlpatterns = patterns('',
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
urlpatterns = [
# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)),
url(r'autocomplete/', include('autocomplete_light.urls')),
@ -30,16 +27,10 @@ urlpatterns = patterns('',
url(r'^captcha/', include('captcha.urls')),
url(r'^yandex-money/', include('yandex_money.urls')),
url(r'^', include('cms.urls')),
)
]
if settings.DEBUG:
urlpatterns.extend(
static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) +
static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
)
import debug_toolbar
urlpatterns = [
url(r'^__debug__/', include(debug_toolbar.urls)),
] + urlpatterns
urlpatterns += [url(r'^__debug__/', include(debug_toolbar.urls))]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

@ -1,6 +1,6 @@
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dokumentor.settings")
from django.core.wsgi import get_wsgi_application
from django.core.wsgi import get_wsgi_application # noqa
application = get_wsgi_application()

@ -24,7 +24,7 @@ class CustomUserAdmin(UserAdmin):
(None, {
'classes': ('wide',),
'fields': ('username', 'email', 'password1', 'password2')}
),
),
)
form = CustomUserChangeForm
add_form = CustomUserCreationForm
@ -32,5 +32,6 @@ class CustomUserAdmin(UserAdmin):
search_fields = ('username', 'email', 'first_name', 'last_name')
ordering = ('email',)
admin.site.register(DokUser, CustomUserAdmin)
admin.site.register(ConfirmEmail)

@ -5,5 +5,3 @@ from django.apps import AppConfig
class MyAuthConfig(AppConfig):
name = 'myauth'
verbose_name = 'Авторизация'

@ -11,37 +11,47 @@ from customer import consts as customer_consts
from myauth.models import DokUser
PASSWORD_MIN_LEN = getattr(settings, 'PASSWORD_MIN_LEN ', 7)
PROFILE_CHOICES = (
(customer_consts.IP_PROFILE, u'Индивидуальный предприниматель (ИП)'),
(customer_consts.ORG_PROFILE, u'Организация (ООО, ЗАО, ОАО, НКО и т.п.)'),
(customer_consts.IP_PROFILE, 'Индивидуальный предприниматель (ИП)'),
(customer_consts.ORG_PROFILE, 'Организация (ООО, ЗАО, ОАО, НКО и т.п.)'),
)
class RegistrationForm(forms.Form):
"""Форма регистрации нового пользователя."""
email = forms.EmailField(label=u'Укажите e-mail', max_length=75, error_messages={'invalid': u'Неверный формат e-mail.',},
help_text=u'На него будет выслано письмо с подтверждением.')
password1 = forms.CharField(label=u'Введите пароль', min_length=PASSWORD_MIN_LEN, widget=forms.PasswordInput,
error_messages={'min_length': u'Не менее %s символов.' % PASSWORD_MIN_LEN,},
help_text=u'Не менее %s символов.' % PASSWORD_MIN_LEN)
password2 = forms.CharField(label=u'Повтор пароля', widget=forms.PasswordInput)
profile_type = forms.ChoiceField(label=u'Тип регистрации', choices=PROFILE_CHOICES, widget=forms.RadioSelect,
error_messages={'required': u'Нужно указать форму собственности вашего бизнеса.',})
email = forms.EmailField(
label='Укажите e-mail',
max_length=75,
error_messages={'invalid': 'Неверный формат e-mail.'},
help_text='На него будет выслано письмо с подтверждением.'
)
password1 = forms.CharField(
label='Введите пароль',
min_length=PASSWORD_MIN_LEN,
widget=forms.PasswordInput,
error_messages={'min_length': f'Не менее {PASSWORD_MIN_LEN} символов.'},
help_text=f'Не менее {PASSWORD_MIN_LEN} символов.'
)
password2 = forms.CharField(label='Повтор пароля', widget=forms.PasswordInput)
profile_type = forms.ChoiceField(
label='Тип регистрации',
choices=PROFILE_CHOICES,
widget=forms.RadioSelect,
error_messages={'required': 'Нужно указать форму собственности вашего бизнеса.'}
)
def clean_email(self):
"""Проверить не занят ли email."""
email = self.cleaned_data['email']
try:
DokUser.objects.get(email__iexact = email)
DokUser.objects.get(email__iexact=email)
except DokUser.DoesNotExist:
return email
raise forms.ValidationError(u'Такой e-mail уже зарегистрирован.')
raise forms.ValidationError('Такой e-mail уже зарегистрирован.')
def clean(self):
super(RegistrationForm, self).clean()
@ -50,36 +60,40 @@ class RegistrationForm(forms.Form):
# проверить чтобы оба пароля совпадали
if password1 and password2:
if password1 != password2:
set_field_error(self, 'password2', u'Пароли не совпадают.')
set_field_error(self, 'password2', 'Пароли не совпадают.')
return self.cleaned_data
class ResetPasswordForm(forms.Form):
"""Форма восстановления пароля."""
email = forms.EmailField(label=u'Ваш e-mail', max_length=75,
error_messages={'invalid': u'Неверный формат e-mail.', 'required': u'Введите свой e-mail.',})
email = forms.EmailField(
label='Ваш e-mail',
max_length=75,
error_messages={'invalid': 'Неверный формат e-mail.', 'required': 'Введите свой e-mail.'}
)
def __init__(self, *args, **kwargs):
super(ResetPasswordForm, self).__init__(*args, **kwargs)
self.user_cache = None # кешировать юзера в форме, чтобы повторно не ходить в базу из вьюхи
# кешировать юзера в форме, чтобы повторно не ходить в базу из вьюхи
self.user_cache = None
def clean_email(self):
"""Проверить зарегистрирован ли email."""
email = self.cleaned_data['email']
try:
DokUser.objects.get(email__iexact = email)
DokUser.objects.get(email__iexact=email)
return email
except DokUser.DoesNotExist:
raise forms.ValidationError(u'Такой e-mail не зарегистрирован.')
raise forms.ValidationError('Такой e-mail не зарегистрирован.')
def clean(self):
super(ResetPasswordForm, self).clean()
email = self.cleaned_data.get('email')
if email:
self.user_cache = DokUser.objects.get(email__iexact = email)
self.user_cache = DokUser.objects.get(email__iexact=email)
if self.user_cache:
if not self.user_cache.is_active:
raise forms.ValidationError(u'Пользователь заблокирован.')
raise forms.ValidationError('Пользователь заблокирован.')
return self.cleaned_data
def get_user(self):
@ -88,13 +102,17 @@ class ResetPasswordForm(forms.Form):
class ChangePasswordForm(forms.Form):
"""Форма изменения пароля."""
old_password = forms.CharField(label=u'Ваш пароль', widget=forms.PasswordInput)
old_password = forms.CharField(label='Ваш пароль', widget=forms.PasswordInput)
password1 = forms.CharField(label=u'Новый пароль', min_length=PASSWORD_MIN_LEN, widget=forms.PasswordInput,
error_messages={'min_length': u'Не менее %s символов.' % PASSWORD_MIN_LEN,},
help_text=u'Не менее %s символов.' % PASSWORD_MIN_LEN)
password1 = forms.CharField(
label='Новый пароль',
min_length=PASSWORD_MIN_LEN,
widget=forms.PasswordInput,
error_messages={'min_length': f'Не менее {PASSWORD_MIN_LEN} символов.'},
help_text=f'Не менее {PASSWORD_MIN_LEN} символов.'
)
password2 = forms.CharField(label=u'Повторите', widget=forms.PasswordInput)
password2 = forms.CharField(label='Повторите', widget=forms.PasswordInput)
def __init__(self, user, *args, **kwargs):
super(ChangePasswordForm, self).__init__(*args, **kwargs)
@ -104,7 +122,7 @@ class ChangePasswordForm(forms.Form):
"""Проверить старый пароль."""
old_password = self.cleaned_data.get('old_password')
if old_password and not self._user.check_password(old_password):
raise forms.ValidationError(u'Неверный пароль.')
raise forms.ValidationError('Неверный пароль.')
return old_password
def clean(self):
@ -114,16 +132,19 @@ class ChangePasswordForm(forms.Form):
# проверить чтобы оба новых пароля совпадали
if password1 and password2:
if password1 != password2:
set_field_error(self, 'password2', u'Пароли не совпадают.')
set_field_error(self, 'password2', 'Пароли не совпадают.')
return self.cleaned_data
class ChangeEmailForm(forms.Form):
"""Форма изменения e-mail."""
password = forms.CharField(label=u'Ваш пароль', widget=forms.PasswordInput)
password = forms.CharField(label='Ваш пароль', widget=forms.PasswordInput)
email = forms.EmailField(label=u'Новый e-mail', max_length=75,
error_messages={'invalid': u'Неверный формат e-mail.', 'required': u'Введите свой e-mail.',})
email = forms.EmailField(
label='Новый e-mail',
max_length=75,
error_messages={'invalid': 'Неверный формат e-mail.', 'required': 'Введите свой e-mail.'}
)
def __init__(self, user, *args, **kwargs):
super(ChangeEmailForm, self).__init__(*args, **kwargs)
@ -133,30 +154,31 @@ class ChangeEmailForm(forms.Form):
"""Проверить пароль."""
password = self.cleaned_data.get('password')
if password and not self._user.check_password(password):
raise forms.ValidationError(u'Неверный пароль.')
raise forms.ValidationError('Неверный пароль.')
return password
def clean_email(self):
"""Проверить не зарегистрирован ли email."""
email = self.cleaned_data['email']
try:
DokUser.objects.get(email__iexact = email)
raise forms.ValidationError(u'Такой e-mail уже зарегистрирован.')
DokUser.objects.get(email__iexact=email)
raise forms.ValidationError('Такой e-mail уже зарегистрирован.')
except DokUser.DoesNotExist:
return email
class LoginForm(forms.Form):
"""Форма логина."""
email = forms.EmailField(label=u'Укажите e-mail', max_length=75)
password = forms.CharField(label=u'Введите пароль', widget=forms.PasswordInput)
reset_old_login = forms.BooleanField(label=u'Сбросить старый вход', required=False)
email = forms.EmailField(label='Укажите e-mail', max_length=75)
password = forms.CharField(label='Введите пароль', widget=forms.PasswordInput)
reset_old_login = forms.BooleanField(label='Сбросить старый вход', required=False)
# TODO капча на случай если пароль не ввели правильно с первого раза
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.user_cache = None # кешировать юзера в форме, чтобы повторно не лазить в базу из вьюхи
# кешировать юзера в форме, чтобы повторно не лазить в базу из вьюхи
self.user_cache = None
def clean(self):
super(LoginForm, self).clean()
@ -165,19 +187,26 @@ class LoginForm(forms.Form):
reset_old_login = self.cleaned_data.get('reset_old_login')
if email and password:
try:
username = DokUser.objects.get(email__iexact = email).username
self.user_cache = authenticate(username = username, password = password)
username = DokUser.objects.get(email__iexact=email).username
self.user_cache = authenticate(username=username, password=password)
if self.user_cache:
if not self.user_cache.is_active:
set_field_error(self, 'email', u'Пользователь заблокирован.')
set_field_error(self, 'email', 'Пользователь заблокирован.')
if not self.user_cache.profile.confirmed:
set_field_error(self, 'email', u'Для подтверждения адреса электронной почты перейдите по адресу, указанному в письме. Если вы не получили письмо с активацией, попробуйте зарегистрироваться ещё раз или укажите другой адрес электронной почты.')
msg = "Для подтверждения адреса электронной почты перейдите по адресу," \
"указанному в письме. Если вы не получили письмо с активацией, " \
"попробуйте зарегистрироваться ещё раз или укажите другой " \
"адрес электронной почты."
set_field_error(self, 'email', msg)
if self.user_cache.profile.user_session_key and not reset_old_login:
set_field_error(self, 'email', u'Пользователь уже вошёл в систему. Установите флаг "Сбросить старый вход", чтобы войти.')
msg = "Пользователь уже вошёл в систему. Установите флаг " \
"'Сбросить старый вход', чтобы войти."
set_field_error(self, 'email', msg)
else:
set_field_error(self, 'password', u'Неверное сочетание e-mail / пароль.')
set_field_error(self, 'password', 'Неверное сочетание e-mail / пароль.')
except DokUser.DoesNotExist:
set_field_error(self, 'email', u'Такой e-mail не зарегистрирован.')
set_field_error(self, 'email', 'Такой e-mail не зарегистрирован.')
return self.cleaned_data
def get_user(self):
@ -185,7 +214,7 @@ class LoginForm(forms.Form):
class CaptchedLoginForm(LoginForm):
captcha = CaptchaField(label=u'Введите код с картинки')
captcha = CaptchaField(label='Введите код с картинки')
class CustomUserCreationForm(UserCreationForm):
@ -193,6 +222,7 @@ class CustomUserCreationForm(UserCreationForm):
A form that creates a user, with no privileges, from the given email and
password.
"""
def clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
@ -207,8 +237,8 @@ class CustomUserCreationForm(UserCreationForm):
model = DokUser
fields = ("username", "email",)
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = DokUser
fields = '__all__'

@ -29,21 +29,21 @@ class ResetKeyManager(models.Manager):
def create_key(self, user):
"""Создает или обновляет ключ восстановления пароля."""
key = hashlib.sha1('%s' % random()).hexdigest()
reset_key, created = self.get_or_create(user=user, defaults={'key': key,})
reset_key, created = self.get_or_create(user=user, defaults={'key': key})
if not created:
reset_key.key = key # обновить ключ
reset_key.key = key # обновить ключ
reset_key.save()
return reset_key
class CustomUserManager(BaseUserManager):
def _create_user(self, username, email, password,
is_staff, is_superuser, **extra_fields):
is_staff, is_superuser, **extra_fields):
"""
Creates and saves a User with the given email and password.
"""
now = timezone.now()
if not email :
if not email:
raise ValueError('The given email must be set')
email = self.normalize_email(email)
user = self.model(email=email,
@ -56,9 +56,7 @@ class CustomUserManager(BaseUserManager):
return user
def create_user(self, username, email, password=None, **extra_fields):
return self._create_user(username, email, password, False, False,
**extra_fields )
return self._create_user(username, email, password, False, False, **extra_fields)
def create_superuser(self, username, email, password, **extra_fields):
return self._create_user(username, email, password, True, True,
**extra_fields)
return self._create_user(username, email, password, True, True, **extra_fields)

@ -42,13 +42,13 @@ class DokUser(AbstractBaseUser, PermissionsMixin):
verbose_name_plural = _('users')
def get_absolute_url(self):
return "/users/%s/" % urlquote(self.email)
return f"/users/{urlquote(self.email)}/"
def get_full_name(self):
"""
Returns the first_name plus the last_name, with a space in between.
"""
full_name = '%s %s' % (self.first_name, self.last_name)
full_name = f'{self.first_name} {self.last_name}'
return full_name.strip()
def get_short_name(self):
@ -82,17 +82,11 @@ class ConfirmEmail(models.Model):
verbose_name_plural = u'запросы подтверждения email'
ordering = ['-created_at', ]
def __unicode__(self):
status = u'не подтвержден'
if self.is_confirmed:
status = u'подтвержден'
return u'%s, email %s' % (self.user.email, status,)
def __str__(self):
status = u'не подтвержден'
if self.is_confirmed:
status = u'подтвержден'
return u'%s, email %s' % (self.user.email, status,)
return f'{self.user.email}, email {status}'
class ResetKey(models.Model):
@ -110,24 +104,21 @@ class ResetKey(models.Model):
validators=[
RegexValidator(
regex='[0-9a-f]{40}',
message=u'Введите значение длиной 40 символов, состоящее из цифр 0-9 и букв a-f.'
message='Введите значение длиной 40 символов, состоящее из цифр 0-9 и букв a-f.'
),
MinLengthValidator(40),
]
)
created_at = models.DateTimeField(u'создан', auto_now_add=True)
updated_at = models.DateTimeField(u'изменен', auto_now=True)
created_at = models.DateTimeField('создан', auto_now_add=True)
updated_at = models.DateTimeField('изменен', auto_now=True)
objects = managers.ResetKeyManager()
class Meta:
verbose_name = u'ключ восстановления пароля'
verbose_name_plural = u'ключи восстановления паролей'
verbose_name = 'ключ восстановления пароля'
verbose_name_plural = 'ключи восстановления паролей'
ordering = ['-created_at', ]
def __unicode__(self):
return u'%s, %s' % (self.user.email, self.key,)
def __str__(self):
return u'%s, %s' % (self.user.email, self.key,)
return f'{self.user.email}, {self.key}'

@ -1,2 +1,3 @@
from myauth.emails import send_reset_password_email, \
send_registration_email, send_new_password_email
# flake8: noqa
from myauth.emails import (send_reset_password_email,
send_registration_email, send_new_password_email)

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
from django.conf.urls import *
from django.conf.urls import url
from django.views.generic import TemplateView
from myauth import views
urlpatterns = patterns('',
urlpatterns = [
url(r'^register/$', views.register, name='myauth_register'),
url(r'^login/$', views.login, name='myauth_login'),
@ -43,4 +43,4 @@ urlpatterns = patterns('',
views.confirm_rm_profile,
name='auth_confirm_rm_profile'
),
)
]

@ -18,7 +18,6 @@ from customer.models import UserProfile, UserProfileFilters, License
from myauth import forms, models, emails
REGISTRATION_OPEN = getattr(settings, 'REGISTRATION_OPEN', True)
@ -76,14 +75,14 @@ def register(request):
form = form_class(data=request.POST, prefix=form_prefix)
if form.is_valid():
new_user = _create_user(request, **form.cleaned_data)
confirm_url = reverse('myauth_confirm_email', args=[new_user.username,])
confirm_url = reverse('myauth_confirm_email', args=[new_user.username])
emails.send_registration_email.delay(new_user.email, confirm_url)
messages.add_message(request, messages.INFO, success_msg)
return redirect(success_url)
else:
form = form_class(prefix=form_prefix)
return render(request, template_name, {'form': form,})
return render(request, template_name, {'form': form, })
@sensitive_variables()
@ -120,7 +119,7 @@ def confirm_registered_email(request, key):
def reset(request):
"""Запросить ключ восстановления пароля."""
form_class = forms.ResetPasswordForm
form_prefix='reset'
form_prefix = 'reset'
template_name = 'myauth/reset.html'
success_url = 'myauth_reset_key_ready'
@ -129,13 +128,13 @@ def reset(request):
if form.is_valid():
user = form.get_user()
key = models.ResetKey.objects.create_key(user)
confirm_url = reverse('myauth_confirm_reset', args=[key.key,])
confirm_url = reverse('myauth_confirm_reset', args=[key.key, ])
emails.send_reset_password_email.delay(user.email, confirm_url)
return redirect(success_url)
else:
form = form_class(prefix=form_prefix)
return render(request, template_name, {'form': form,})
return render(request, template_name, {'form': form, })
@sensitive_variables()
@ -230,7 +229,7 @@ def login(request):
form = form_class(data=request.POST, prefix=form_prefix)
if form.is_valid():
auth.login(request, form.get_user())
old_session_key = request.user.profile.user_session_key
# old_session_key = request.user.profile.user_session_key
request.user.profile.user_session_key = request.session.session_key
request.user.profile.save()
del request.session['login_count']
@ -244,7 +243,7 @@ def login(request):
else:
form = form_class(prefix=form_prefix)
return render(request, template_name, {'form': form,})
return render(request, template_name, {'form': form, })
def logout(request):

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

@ -1,16 +0,0 @@
"""
This file demonstrates writing tests using the unittest module. These will pass
when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)

@ -2,7 +2,6 @@
from django.shortcuts import redirect
from cms.views import details
from cms.models.pagemodel import Page
def site_index(request):

@ -5,5 +5,3 @@ from django.apps import AppConfig
class YandexMoneyConfig(AppConfig):
name = 'yandex_money'
verbose_name = 'Яндекс.Деньги'

@ -102,7 +102,7 @@ class BasePaymentForm(forms.Form):
scid = self.cleaned_data['scid']
if (
scid != settings.YANDEX_MONEY_SCID and
not scid in Payment.get_used_scids()
scid not in Payment.get_used_scids()
):
raise forms.ValidationError(self.error_messages[self.ERROR_MESSAGE_CODES.BAD_SCID])
return scid
@ -111,7 +111,7 @@ class BasePaymentForm(forms.Form):
shop_id = self.cleaned_data['shopId']
if (
shop_id != settings.YANDEX_MONEY_SHOP_ID and
not shop_id in Payment.get_used_shop_ids()
shop_id not in Payment.get_used_shop_ids()
):
raise forms.ValidationError(self.error_messages[self.ERROR_MESSAGE_CODES.BAD_SHOP_ID])
return shop_id

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
from django.conf.urls import url
from .views import NoticeFormView
from .views import CheckOrderFormView
urlpatterns = patterns('',
urlpatterns = [
url(r'^check/$', CheckOrderFormView.as_view(), name='yandex_money_check'),
url(r'^aviso/$', NoticeFormView.as_view(), name='yandex_money_notice'),
)
]

@ -0,0 +1,4 @@
[flake8]
ignore = E731 F405
max-line-length = 99
exclude = ./venv/*, ./node_modules/*, **/conf/**, **/migrations/**, **/templates/**, static/*
Loading…
Cancel
Save