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_file = p.normpath(p.join(p.abspath(p.dirname(__file__)), "./conf/env"))
env.load(env_file) env.load(env_file)
print(env_file)
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv) execute_from_command_line(sys.argv)

@ -71,7 +71,7 @@ django-redis==4.8.0
redis==2.10.5 redis==2.10.5
trans==2.1.0 trans==2.1.0
python-decouple==3.0 python-decouple==3.0
flake8==3.2.1 flake8==3.3.0
numpy==1.13.0 numpy==1.13.0
mock==2.0.0 mock==2.0.0
mockredispy==2.9.3 mockredispy==2.9.3
@ -82,3 +82,5 @@ django-test-plus==1.0.17
Faker==0.7.15 Faker==0.7.15
coverage==4.4.1 coverage==4.4.1
pytest-flake8==0.8.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) name = models.CharField(u'Имя клиента', max_length=100)
phone = models.CharField(u'Телефон или e-mail', max_length=50) phone = models.CharField(u'Телефон или e-mail', max_length=50)
message = models.TextField(u'Текст сообщения') 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 = models.PositiveSmallIntegerField(
status_changed = models.DateTimeField(u'Статус изменен', null=True, blank=True, editable=False) 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) created_at = models.DateTimeField(u'Дата заказа', auto_now_add=True)
updated_at = models.DateTimeField(u'Изменен', auto_now=True) updated_at = models.DateTimeField(u'Изменен', auto_now=True)

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf.urls import patterns, url from django.conf.urls import url
from callback.views import req_avail from callback.views import req_avail
urlpatterns = patterns('', urlpatterns = [
url(r'^send/$', req_avail, name='callback-send-message'), url(r'^send/$', req_avail, name='callback-send-message'),
url(r'^send/(?P<id>\d+)/$', req_avail, name='callback-request-item'), 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'Обязательное поле.'): def set_field_error(form, field, msg=u'Обязательное поле.'):
"""Добавить сообщение об ошибке поля и убрать это поле из списка успешно прошедших валидацию. """
Добавить сообщение об ошибке поля и убрать это поле из списка
успешно прошедших валидацию.
Полезно, если нужно инвалидировать поле из метода clean() и добавить ему ошибку. Полезно, если нужно инвалидировать поле из метода clean() и добавить ему ошибку.
В этом случае исключение forms.ValidationError() не подходит, т.к. оно добавит сообщение об ошибке в ошибки формы. В этом случае исключение forms.ValidationError() не подходит,
т.к. оно добавит сообщение об ошибке в ошибки формы.
""" """
form._errors[field] = form.error_class([msg]) form._errors[field] = form.error_class([msg])
if field in form.cleaned_data: if field in form.cleaned_data:
@ -16,18 +19,22 @@ def set_field_error(form, field, msg=u'Обязательное поле.'):
class _MySuperForm(object): class _MySuperForm(object):
"""Базовая форма. Добавляет всякого полезного функционала к форме.""" """Базовая форма. Добавляет всякого полезного функционала к форме."""
# Список условно-обязательных полей, у которых нужно установить атрибут required=False. # Список условно-обязательных полей, у которых нужно установить
# Полезно, когда какие-то поля становятся обязательны к заполнению в зависимости от значения других полей. # атрибут required=False.
# Полезно, когда какие-то поля становятся обязательны к заполнению
# в зависимости от значения других полей.
# TODO мигрировать на unset_required # TODO мигрировать на unset_required
conditional_fields = [] conditional_fields = []
# Список полей, у которых нужно сбросить признак обязательности: required=False. # Список полей, у которых нужно сбросить признак обязательности: required=False.
# Полезно, когда в базовой форме определяются какие-то поля, которые в одних унаследованных формах обязательны, # Полезно, когда в базовой форме определяются какие-то поля, которые в одних
# унаследованных формах обязательны,
# а в других нет. # а в других нет.
unset_required = [] unset_required = []
# Словарь полей, у которых нужно заменить атрибут label. # Словарь полей, у которых нужно заменить атрибут label.
# Полезно, когда нужно дать разные метки полям в админке и в форме, с которой работает пользователь. # Полезно, когда нужно дать разные метки полям в админке и в форме,
# с которой работает пользователь.
change_labels = {} change_labels = {}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

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

@ -254,7 +254,7 @@ class UserProfile(models.Model):
def check_main_reqs_not_filled(self): def check_main_reqs_not_filled(self):
result = self.check_name_not_filled() or self.inn == '' or self.address == '' or \ 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: if result:
return True return True
@ -524,7 +524,8 @@ class UserProfileFilters(models.Model):
show_name = models.BooleanField(u'Краткое название организации', default=True) show_name = models.BooleanField(u'Краткое название организации', default=True)
show_full_name = models.BooleanField(u'Полное название организации', default=True) show_full_name = models.BooleanField(u'Полное название организации', default=True)
show_kpp = 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) show_na_osnovanii = models.BooleanField(u'Действует на основании', default=True)
objects = managers.UserProfileFiltersManager() objects = managers.UserProfileFiltersManager()

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

@ -28,7 +28,7 @@ def bank_accounts_add(request):
"""Добавить расчетный счет.""" """Добавить расчетный счет."""
raise_if_no_profile(request) raise_if_no_profile(request)
template_name='customer/bank_accounts/add.html' template_name = 'customer/bank_accounts/add.html'
form_class = forms.BankAccountForm form_class = forms.BankAccountForm
success_url = 'customer_bank_accounts_list' 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.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse 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 commons.utils import dthandler
from .. import models, forms from .. import models, forms
from ..decorators import license_required
from ..utils import raise_if_no_profile from ..utils import raise_if_no_profile
@ -81,12 +80,14 @@ def bank_accounts_add_ajax(request):
non_field_errors = form.non_field_errors() non_field_errors = form.non_field_errors()
if not form.is_valid(): if not form.is_valid():
non_field_errors.append(u'Заполните/исправьте выделенные поля.') non_field_errors.append('Заполните/исправьте выделенные поля.')
data = { data = {
'success': form.is_valid(), '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') 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() non_field_errors = form.non_field_errors()
if not form.is_valid(): if not form.is_valid():
non_field_errors.append(u'Заполните/исправьте выделенные поля.') non_field_errors.append('Заполните/исправьте выделенные поля.')
data = { data = {
'success': form.is_valid(), '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') return HttpResponse(json.dumps(data), content_type='application/json')
@ -136,27 +139,27 @@ def bank_accounts_delete_ajax(request, id):
account_docs = [] account_docs = []
doc_list = [ doc_list = [
(Invoice, u'счета'), (Invoice, 'счета'),
(Faktura, u'счета-фактуры'), (Faktura, 'счета-фактуры'),
(Nakladn, u'накладные'), (Nakladn, 'накладные'),
(AktRabot, u'акты выполненных работ'), (AktRabot, 'акты выполненных работ'),
(Platejka, u'платёжные поручения') (Platejka, 'платёжные поручения')
] ]
for doc in doc_list: for doc in doc_list:
docs = doc[0].objects.filter(bank_account=account) docs = doc[0].objects.filter(bank_account=account)
print(docs)
if docs: if docs:
account_docs.append(doc[1]) account_docs.append(doc[1])
if not account_docs: if not account_docs:
account.delete() account.delete()
success = True success = True
message = {'title': u'Инфо', message = {'title': 'Инфо',
'msg': u'Расчётный счёт удалён.'} 'msg': 'Расчётный счёт удалён.'}
del_id = id del_id = id
else: else:
success = True success = True
message = {'title': u'Инфо', message = {'title': 'Инфо',
'msg': u'Расчтный счет не удалён. Есть выписанные документы: %s.' % ','.join( 'msg': 'Расчтный счет не удалён. Есть выписанные документы: %s.' % ','.join(
account_docs)} account_docs)}
del_id = None del_id = None

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

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

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

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

@ -5,4 +5,3 @@ from django.apps import AppConfig
class DocConfig(AppConfig): class DocConfig(AppConfig):
name = 'docs' name = 'docs'
verbose_name = 'Документы' 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.conf import settings
from django.template import Template, RequestContext from django.template import Template, RequestContext
from django.template.base import BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END 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 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)' % ( TAG_RE = re.compile('(%s.*?%s|%s.*?%s)' % (
re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), 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: try:
# откуда # откуда
src_book = xlrd.open_workbook(src_xls, encoding_override='cp1251', 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) 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) apply_page_settings(dst_sheet, xls_settings)
# import ipdb;ipdb.set_trace() # import ipdb;ipdb.set_trace()
# заполнить данными # заполнить данными
fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings)
xls_settings)
# закрыть исходную книгу и сохранить созданную # закрыть исходную книгу и сохранить созданную
src_book.release_resources() 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) context = RequestContext(request, dictionary)
# -------------------------------------------------------------------------
def write(row, col, val, src_row=None, src_col=None, commands=None): def write(row, col, val, src_row=None, src_col=None, commands=None):
"""Записывает данные в ячейку с сохранением стилей.""" """Записывает данные в ячейку с сохранением стилей."""
src_row = src_row or row 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) return template.render(context)
def parse_cells(row_from=0, row_to=None, col_from=0, col_to=None, def parse_cells(row_from=0, row_to=None, col_from=0, col_to=None,
dst_row_shift=0, dst_col_shift=0, **kwargs): dst_row_shift=0, dst_col_shift=0, **kwargs):
"""Ищет шаблонные теги и переменные в ячейках заданного диапазона. Если находит, то передает содержимое ячейки """
целиком на обработку в process_template. После чего записывает полученный результат обратно в ячейку. Ищет шаблонные теги и переменные в ячейках заданного диапазона.
Если находит, то передает содержимое ячейки
целиком на обработку в process_template. После чего записывает
полученный результат обратно в ячейку.
Также ищет спец. токены и выполняет соответствующие действия. Также ищет спец. токены и выполняет соответствующие действия.
""" """
row_to = row_to or src_sheet.nrows-1 row_to = row_to or src_sheet.nrows - 1
col_to = col_to or src_sheet.ncols-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 = [] 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 = src_sheet.cell(row, col)
cell_value = new_value = cell.value 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 = process_template(new_value, **kwargs)
# пофиксить переводы строки # пофиксить переводы строки
#new_value = new_value.strip().replace('\r\n', '\n')
new_value = new_value.strip().replace('\r\n', ' ') new_value = new_value.strip().replace('\r\n', ' ')
# команда 'конвертировать во float' # команда 'конвертировать во float'
@ -162,8 +161,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
try: try:
dst_sheet.insert_bitmap( dst_sheet.insert_bitmap(
new_value, new_value,
row = row + dst_row_shift, row=row + dst_row_shift,
col = col + dst_col_shift, col=col + dst_col_shift,
) )
new_value = '' new_value = ''
except: 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 # print "Error inserting image from file '%s'" % new_value
raise raise
write( write(
row = row + dst_row_shift, row=row + dst_row_shift,
col = col + dst_col_shift, col=col + dst_col_shift,
val = new_value, val=new_value,
src_row = row, src_row=row,
src_col = col, src_col=col,
commands = {'draw_thin_bottom_border': cmd_draw_thin_bottom_border, commands={'draw_thin_bottom_border': cmd_draw_thin_bottom_border}
}
) )
# --- конец цикла по ячейкам в строке # --- конец цикла по ячейкам в строке
# подобрать высоту строки в ячейках # подобрать высоту строки в ячейках
dst_row = row + dst_row_shift # строка назначения dst_row = row + dst_row_shift # строка назначения
row_height = dst_sheet.row(dst_row).height # текущая высота row_height = dst_sheet.row(dst_row).height # текущая высота
max_height = 0 max_height = 0
for fh in cmd_fix_height: 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 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']: if r1 != row or c1 != fh['col']:
continue continue
for colx in range(c1, c2): 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_pixels = width / 36.5
width_in_chars = width_in_pixels / 5.8 width_in_chars = width_in_pixels / 5.8
# может быть 0, если команда @@FIX_HEIGHT@@ задана в простой (не объединенной) ячейке # может быть 0, если команда @@FIX_HEIGHT@@ задана в простой
# (не объединенной) ячейке
if width_in_chars == 0: if width_in_chars == 0:
# print ('WARNING. xls generation, cmd @@FIX_HEIGHT@@. ' # print ('WARNING. xls generation, cmd @@FIX_HEIGHT@@. '
# 'variable `width_in_chars` = %s. skip this command.' % width_in_chars) # '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 min_rows = 1
need_rows = math.ceil(len(value) / width_in_chars) need_rows = math.ceil(len(value) / width_in_chars)
need_rows = int(max(min_rows, need_rows)) need_rows = int(max(min_rows, need_rows))
#print 'need_rows=', need_rows # print 'need_rows=', need_rows
new_height = row_height * need_rows new_height = row_height * need_rows
# не фиксить высоту, если новая высота данной ячейки меньше либо равна текущей высоте # не фиксить высоту, если новая высота данной ячейки меньше либо
# равна текущей высоте
if new_height > max_height: if new_height > max_height:
max_height = new_height max_height = new_height
else: else:
#print 'SKIP,', new_height, '<=', max_height # print 'SKIP,', new_height, '<=', max_height
continue continue
dst_sheet.row(dst_row).height = new_height 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 = 0
row_shift = 0 row_shift = 0
#print '---table:' # print '---table:'
def write_tbl_body_row(): def write_tbl_body_row():
"""Хелпер для отрисовки строки таблицы. """Хелпер для отрисовки строки таблицы.
Зависит от внешних переменных row_shift, row и item! Зависит от внешних переменных row_shift, row и item!
""" """
#print '---table body row, dst_row_shift =', row_shift # print '---table body row, dst_row_shift =', row_shift
copy_cells( copy_cells(
src_sheet, dst_sheet, style_list, src_sheet, dst_sheet, style_list,
row_from = p.TBL_BODY_ROW, row_to = p.TBL_BODY_ROW, row_from=p.TBL_BODY_ROW, row_to=p.TBL_BODY_ROW,
dst_row_shift = row_shift dst_row_shift=row_shift
) )
parse_cells( parse_cells(
row_from = p.TBL_BODY_ROW, row_from=p.TBL_BODY_ROW,
row_to = p.TBL_BODY_ROW, row_to=p.TBL_BODY_ROW,
dst_row_shift = row_shift, dst_row_shift=row_shift,
item = item, item=item,
item_npp = row+1 item_npp=row + 1
) )
def write_tbl_page_footer(): 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! Зависит от внешних переменных row_shift, last_page_item_idx и row!
""" """
dst_row_shift = row_shift - (p.TBL_PAGE_FOOTER_FROM - p.TBL_BODY_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 # 'items_start =', last_page_item_idx, 'items_stop =', row
copy_cells( copy_cells(
src_sheet, dst_sheet, style_list, src_sheet, dst_sheet, style_list,
row_from = p.TBL_PAGE_FOOTER_FROM, row_to = p.TBL_PAGE_FOOTER_TO, row_from=p.TBL_PAGE_FOOTER_FROM, row_to=p.TBL_PAGE_FOOTER_TO,
dst_row_shift = dst_row_shift dst_row_shift=dst_row_shift
) )
parse_cells( parse_cells(
row_from = p.TBL_PAGE_FOOTER_FROM, row_from=p.TBL_PAGE_FOOTER_FROM,
row_to = p.TBL_PAGE_FOOTER_TO, row_to=p.TBL_PAGE_FOOTER_TO,
dst_row_shift = dst_row_shift, dst_row_shift=dst_row_shift,
items_start = last_page_item_idx, items_start=last_page_item_idx,
items_stop = row items_stop=row
) )
def write_tbl_header(): def write_tbl_header():
@ -318,17 +317,17 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings
Зависит от внешних переменных row и add_offset! Зависит от внешних переменных row и add_offset!
""" """
dst_row_shift = p.TBL_HEADER_ROWS + 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( copy_cells(
src_sheet, dst_sheet, style_list, src_sheet, dst_sheet, style_list,
row_from = p.TBL_HEADER_FROM, row_to = p.TBL_HEADER_TO, row_from=p.TBL_HEADER_FROM, row_to=p.TBL_HEADER_TO,
dst_row_shift = dst_row_shift dst_row_shift=dst_row_shift
) )
# цикл по табличной части документа # цикл по табличной части документа
for row, item in enumerate(obj_items): for row, item in enumerate(obj_items):
row_shift = row + add_offset 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() write_tbl_body_row()
row_height = dst_sheet.row(p.TBL_BODY_ROW + row_shift).height 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 curr_height + p.TBL_PAGE_FOOTER_HEIGHT + p.TBL_FOOTER_HEIGHT > p.WORK_HEIGHT:
# если это первая строка, то: # если это первая строка, то:
if row == 0: if row == 0:
#print '---table new page, row =', row # print '---table new page, row =', row
# 1. добавить разрыв страницы перед первой шапкой # 1. добавить разрыв страницы перед первой шапкой
horz_page_break(dst_sheet, p.TBL_HEADER_FROM) horz_page_break(dst_sheet, p.TBL_HEADER_FROM)
curr_height = p.TBL_HEADER_HEIGHT + row_height curr_height = p.TBL_HEADER_HEIGHT + row_height
# если это не последняя строка, то: # если это не последняя строка, то:
elif row < len(obj_items)-1: elif row < len(obj_items) - 1:
#print '---table new page, row =', row # print '---table new page, row =', row
# 1. вместо строки вывести подитог # 1. вместо строки вывести подитог
if p.TBL_PAGE_FOOTER_ROWS > 0: if p.TBL_PAGE_FOOTER_ROWS > 0:
write_tbl_page_footer() 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 add_offset += p.TBL_PAGE_FOOTER_ROWS
row_shift += add_offset row_shift += add_offset
# 2. добавить разрыв страницы # 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. вывести шапку # 3. вывести шапку
write_tbl_header() write_tbl_header()
add_offset += p.TBL_HEADER_ROWS 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() write_tbl_body_row()
curr_height += row_height curr_height += row_height
else: # for ... else else: # for ... else
# вывести подитог, если только что не выводили его в цикле # вывести подитог, если только что не выводили его в цикле
if p.TBL_PAGE_FOOTER_ROWS > 0 and not just_wrote_page_footer: if p.TBL_PAGE_FOOTER_ROWS > 0 and not just_wrote_page_footer:
#print '---tbl last page, row =', row # print '---tbl last page, row =', row
row += 1 # чтоб захватить в подитог и последнюю запись тоже row += 1 # чтоб захватить в подитог и последнюю запись тоже
row_shift = row + add_offset row_shift = row + add_offset
write_tbl_page_footer() write_tbl_page_footer()
curr_height += p.TBL_PAGE_FOOTER_HEIGHT curr_height += p.TBL_PAGE_FOOTER_HEIGHT
add_offset += row - p.TBL_PAGE_FOOTER_ROWS add_offset += row - p.TBL_PAGE_FOOTER_ROWS
#print '---end table' # print '---end table'
# для отладки - выйти здесь # для отладки - выйти здесь
#return # return
# --- !!! --------------------------------------- вывести остаток документа # --- !!! --------------------------------------- вывести остаток документа
copy_cells( copy_cells(
src_sheet, dst_sheet, style_list, src_sheet, dst_sheet, style_list,
row_from = p.TBL_FOOTER_FROM, row_from=p.TBL_FOOTER_FROM,
dst_row_shift = add_offset 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 apply_page_settings(dst_sheet, settings):
"""Применить параметры страницы.""" """Применить параметры страницы."""
def setparam(attr, key): def setparam(attr, key):
if key in settings: if key in settings:
setattr(dst_sheet, attr, settings[key]) setattr(dst_sheet, attr, settings[key])
def setparam_as_inch(attr, key): def setparam_as_inch(attr, key):
if key in settings: 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('portrait', 'PAGE_PORTRAIT')
setparam('header_str', 'PAGE_HEADER_STR') 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): def get_all_these_boring_params(src_sheet, xls_settings):
"""Достает нужные настройки из словаря и проверят, некоторые вычисляет -
и всё это складывает в класс, который потом и возвращает.
Если какие-то обязательные настройки не заданы, сообщает об этом в консоль и возвращает None.
""" """
Достает нужные настройки из словаря и проверят, некоторые вычисляет -
и всё это складывает в класс, который потом и возвращает.
Если какие-то обязательные настройки не заданы, сообщает
об этом в консоль и возвращает None.
"""
class Params(object): class Params(object):
pass pass
p = Params() 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) p.TBL_PAGE_FOOTER_ROWS = int(p.TBL_PAGE_FOOTER_TO - p.TBL_PAGE_FOOTER_FROM + 1)
# высота в twips # высота в 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: else:
p.TBL_PAGE_FOOTER_ROWS = 0 p.TBL_PAGE_FOOTER_ROWS = 0
p.TBL_PAGE_FOOTER_HEIGHT = 0 p.TBL_PAGE_FOOTER_HEIGHT = 0

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

@ -1,10 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from decimal import Decimal from decimal import Decimal
BOOL_CHOICES = ( BOOL_CHOICES = (
(True, u'Да'), (True, 'Да'),
(False, u'Нет'), (False, 'Нет'),
) )
# виды НДС # виды НДС
@ -13,9 +12,9 @@ NDS_TYPE_IN = 2
NDS_TYPE_OUT = 3 NDS_TYPE_OUT = 3
NDS_TYPE_CHOICES = ( NDS_TYPE_CHOICES = (
(NDS_TYPE_NO, u'Не учитывать'), (NDS_TYPE_NO, 'Не учитывать'),
(NDS_TYPE_IN, u'В сумме'), (NDS_TYPE_IN, 'В сумме'),
(NDS_TYPE_OUT, u'Сверх суммы'), (NDS_TYPE_OUT, 'Сверх суммы'),
) )
# ставка НДС # ставка НДС
@ -24,9 +23,9 @@ NDS_VALUE_10 = 10
NDS_VALUE_18 = 18 NDS_VALUE_18 = 18
NDS_VALUE_CHOICES = ( NDS_VALUE_CHOICES = (
(NDS_VALUE_0, u'Без НДС'), (NDS_VALUE_0, 'Без НДС'),
(NDS_VALUE_10, u'10%'), (NDS_VALUE_10, '10%'),
(NDS_VALUE_18, u'18%'), (NDS_VALUE_18, '18%'),
) )
# ставка НДС - число в формате Decimal (для расчетов) # ставка НДС - число в формате Decimal (для расчетов)
@ -39,7 +38,6 @@ NDS_VALUE_NUMERIC = {
NDS_IN_AMOUNT = 0 NDS_IN_AMOUNT = 0
NDS_OTHER_AMOUNT = 1 NDS_OTHER_AMOUNT = 1
NDS_METHOD_CHOICES = ( NDS_METHOD_CHOICES = (
(NDS_IN_AMOUNT, 'В сумме'), (NDS_IN_AMOUNT, 'В сумме'),
(NDS_OTHER_AMOUNT, 'Сверх суммы'), (NDS_OTHER_AMOUNT, 'Сверх суммы'),
@ -54,10 +52,10 @@ CURR_EUR = 3
CURR_OTHER = 4 CURR_OTHER = 4
CURRENCY_CHOICES = ( CURRENCY_CHOICES = (
(CURR_RUB, u'Руб.'), (CURR_RUB, 'Руб.'),
(CURR_USD, u'USD'), (CURR_USD, 'USD'),
(CURR_EUR, u'EUR'), (CURR_EUR, 'EUR'),
(CURR_OTHER, u'Другое'), (CURR_OTHER, 'Другое'),
) )
CURRENCY_CHOICES_DICT = dict(CURRENCY_CHOICES) CURRENCY_CHOICES_DICT = dict(CURRENCY_CHOICES)
@ -68,9 +66,9 @@ CONSIGNOR_TYPE_OTHER = 2
CONSIGNOR_TYPE_NO = 3 CONSIGNOR_TYPE_NO = 3
CONSIGNOR_CHOICES = ( CONSIGNOR_CHOICES = (
(CONSIGNOR_TYPE_SELF, u'Подставить мои данные'), # из профиля через поле user (CONSIGNOR_TYPE_SELF, 'Подставить мои данные'), # из профиля через поле user
(CONSIGNOR_TYPE_OTHER, u'Стороннее лицо'), # из справочника контрагенты (CONSIGNOR_TYPE_OTHER, 'Стороннее лицо'), # из справочника контрагенты
(CONSIGNOR_TYPE_NO, u'Не указывать'), (CONSIGNOR_TYPE_NO, 'Не указывать'),
) )
# варианты для поля грузополучатель # варианты для поля грузополучатель
@ -79,9 +77,9 @@ RECEIVER_TYPE_OTHER = 2
RECEIVER_TYPE_NO = 3 RECEIVER_TYPE_NO = 3
RECEIVER_CHOICES = ( RECEIVER_CHOICES = (
(RECEIVER_TYPE_BUYER, u'То же лицо'), # что и покупатель (RECEIVER_TYPE_BUYER, 'То же лицо'), # что и покупатель
(RECEIVER_TYPE_OTHER, u'Стороннее лицо'), # из справочника контрагенты (RECEIVER_TYPE_OTHER, 'Стороннее лицо'), # из справочника контрагенты
(RECEIVER_TYPE_NO, u'Не указывать'), (RECEIVER_TYPE_NO, 'Не указывать'),
) )
# ----------------------------------------------------- для платежных поручений # ----------------------------------------------------- для платежных поручений
@ -91,66 +89,66 @@ PLATEJ_TYPE_COMMERCE = 1
PLATEJ_TYPE_TAX = 2 PLATEJ_TYPE_TAX = 2
PLATEJ_TYPE_CHOICES = ( PLATEJ_TYPE_CHOICES = (
(PLATEJ_TYPE_COMMERCE, u'Коммерческое'), (PLATEJ_TYPE_COMMERCE, 'Коммерческое'),
(PLATEJ_TYPE_TAX, u'Налоговое'), (PLATEJ_TYPE_TAX, 'Налоговое'),
) )
# вид платежа # вид платежа
PAYMENT_TYPE_CHOICES = ( PAYMENT_TYPE_CHOICES = (
(1, u'Не указывать'), (1, 'Не указывать'),
(2, u'Срочно'), (2, 'Срочно'),
(3, u'Электронно'), (3, 'Электронно'),
(4, u'Почтой'), (4, 'Почтой'),
(5, u'Телеграфом'), (5, 'Телеграфом'),
) )
# статус составителя # статус составителя
TAX_STATUS_CHOICES = ( TAX_STATUS_CHOICES = (
(u'01', u'01 - налогоплательщик (плательщик сборов) - юридическое лицо'), ('01', '01 - налогоплательщик (плательщик сборов) - юридическое лицо'),
(u'02', u'02 - налоговый агент'), ('02', '02 - налоговый агент'),
(u'03', u'03 - сборщик налогов и сборов'), ('03', '03 - сборщик налогов и сборов'),
(u'04', u'04 - налоговый орган'), ('04', '04 - налоговый орган'),
(u'05', u'05 - служба судебных приставов'), ('05', '05 - служба судебных приставов'),
(u'06', u'06 - участник внешнеэкономической деятельности'), ('06', '06 - участник внешнеэкономической деятельности'),
(u'07', u'07 - таможенный орган'), ('07', '07 - таможенный орган'),
(u'08', u'08 - плательщик иных обязательных платежей'), ('08', '08 - плательщик иных обязательных платежей'),
(u'09', u'09 - налогоплательщик (плательщик сборов) - ИП'), ('09', '09 - налогоплательщик (плательщик сборов) - ИП'),
(u'10', u'10 - налогоплательщик (плательщик сборов) - частный нотариус'), ('10', '10 - налогоплательщик (плательщик сборов) - частный нотариус'),
(u'11', u'11 - налогоплательщик (плательщик сборов) - адвокат'), ('11', '11 - налогоплательщик (плательщик сборов) - адвокат'),
(u'12', u'12 - налогоплательщик (плательщик сборов) - глава КФХ'), ('12', '12 - налогоплательщик (плательщик сборов) - глава КФХ'),
(u'13', u'13 - налогоплательщик (плательщик сборов) - иное физическое лицо'), ('13', '13 - налогоплательщик (плательщик сборов) - иное физическое лицо'),
(u'14', u'14 - налогоплательщик, производящий выплаты физическим лицам'), ('14', '14 - налогоплательщик, производящий выплаты физическим лицам'),
(u'15', u'15 - кредитная организация'), ('15', '15 - кредитная организация'),
) )
# основание налогового платежа # основание налогового платежа
TAX_BASE = ( 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 = ( 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): class CustomChoiceFilter(django_filters.ChoiceFilter):
def __init__(self, *args, **kwargs): 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()] kwargs['choices'] = [(key, value[0]) for key, value in self.options.items()]
super(CustomChoiceFilter, self).__init__(*args, **kwargs) 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) return datetime.date(year, 4, 1), datetime.date(year, 6, 30)
elif q == 3: elif q == 3:
return datetime.date(year, 7, 1), datetime.date(year, 9, 30) 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 datetime.date(year, 10, 1), datetime.date(year, 12, 31)
return None, None return None, None
def current_quarter(today): def current_quarter(today):
"""Возвращает даты начала/окончания текущего квартала.""" """Возвращает даты начала/окончания текущего квартала."""
q = (today.month-1)//3+1 q = (today.month - 1) // 3 + 1
return _quarter_dates(q, today.year) return _quarter_dates(q, today.year)
def last_quarter(today): def last_quarter(today):
"""Возвращает даты начала/окончания прошлого квартала.""" """Возвращает даты начала/окончания прошлого квартала."""
q = (today.month-1)//3+1 q = (today.month - 1) // 3 + 1
q -= 1 q -= 1
year = today.year year = today.year
if q < 1: # прошлый год if q < 1: # прошлый год
q = 4 q = 4
year -= 1 year -= 1
return _quarter_dates(q, year) return _quarter_dates(q, year)
@ -73,64 +73,64 @@ last_quarter_start, last_quarter_end = last_quarter(today)
# --- варианты фильтрации для разных полей # --- варианты фильтрации для разных полей
doc_date_choices = { doc_date_choices = {
'': (u'Всё время', lambda qs, name: qs.all()), '': ('Всё время', lambda qs, name: qs.all()),
1: (u'Этот месяц', lambda qs, name: qs.filter(**{ 1: ('Этот месяц', lambda qs, name: qs.filter(**{
'%s__year' % name: datetime.datetime.now().year, '%s__year' % name: datetime.datetime.now().year,
'%s__month' % name: datetime.datetime.now().month '%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__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__gte' % name: current_quarter_start,
'%s__lte' % name: current_quarter_end, '%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__gte' % name: last_quarter_start,
'%s__lte' % name: last_quarter_end, '%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, '%s__year' % name: datetime.datetime.now().year,
})), })),
6: (u'Прошлый год', lambda qs, name: qs.filter(**{ 6: ('Прошлый год', lambda qs, name: qs.filter(**{
'%s__year' % name: datetime.datetime.now().year-1, '%s__year' % name: datetime.datetime.now().year - 1,
})), })),
} }
closed_status_choices = ( closed_status_choices = (
('', u'Все счета'), ('', 'Все счета'),
(1, u'Закрытые актом выполненных работ'), (1, 'Закрытые актом выполненных работ'),
(0, u'Не закрытые актом выполненных работ'), (0, 'Не закрытые актом выполненных работ'),
) )
paid_status_choices = ( paid_status_choices = (
('', u'Все счета'), ('', 'Все счета'),
(Invoice.PAID, u'Оплаченные'), (Invoice.PAID, 'Оплаченные'),
(Invoice.PARTLY_PAID, u'Частично оплаченные'), (Invoice.PARTLY_PAID, 'Частично оплаченные'),
(Invoice.UNPAID, u'Неоплаченные'), (Invoice.UNPAID, 'Неоплаченные'),
) )
signed_status_choices = ( signed_status_choices = (
('', u'Все документы'), ('', 'Все документы'),
('1', u'Подписанные'), ('1', 'Подписанные'),
('0', u'Не подписанные'), ('0', 'Не подписанные'),
) )
total_saldo_choices = { total_saldo_choices = {
'': (u'Любое', lambda qs, name: qs.all()), '': ('Любое', lambda qs, name: qs.all()),
1: (u'Положительное', lambda qs, name: qs.filter(**{ 1: ('Положительное', lambda qs, name: qs.filter(**{
'%s__gt' % name: 0, '%s__gt' % name: 0,
})), })),
2: (u'Отрицательное', lambda qs, name: qs.filter(**{ 2: ('Отрицательное', lambda qs, name: qs.filter(**{
'%s__lt' % name: 0, '%s__lt' % name: 0,
})), })),
} }
platej_type_choices = ( platej_type_choices = (
('', u'Все плат. поручения'), ('', 'Все плат. поручения'),
(consts.PLATEJ_TYPE_COMMERCE, u'Коммерческие'), (consts.PLATEJ_TYPE_COMMERCE, 'Коммерческие'),
(consts.PLATEJ_TYPE_TAX, u'Налоговые'), (consts.PLATEJ_TYPE_TAX, 'Налоговые'),
) )
@ -145,10 +145,12 @@ class BaseDocsFilterSet(django_filters.FilterSet):
self.request = request self.request = request
if 'client' in self.filters: 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: 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 # сбросить у полей формы атрибут help_text
for field in self.form.fields.values(): for field in self.form.fields.values():
@ -156,46 +158,146 @@ class BaseDocsFilterSet(django_filters.FilterSet):
class InvoiceFilterSet(BaseDocsFilterSet): class InvoiceFilterSet(BaseDocsFilterSet):
paid_status = django_filters.ChoiceFilter(label=u'По оплате', choices=paid_status_choices, widget=django_filters.widgets.LinkWidget) paid_status = django_filters.ChoiceFilter(
closed_status = django_filters.ChoiceFilter(label=u'По закрывающим документам', choices=closed_status_choices, widget=django_filters.widgets.LinkWidget) label='По оплате',
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') choices=paid_status_choices,
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) 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): class AktRabotFilterSet(BaseDocsFilterSet):
signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) signed_status = django_filters.ChoiceFilter(
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') label='По приёмке',
invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета') choices=signed_status_choices,
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) 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): class NakladnFilterSet(BaseDocsFilterSet):
signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) signed_status = django_filters.ChoiceFilter(
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') label='По приёмке',
invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета') choices=signed_status_choices,
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) 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): class FakturaFilterSet(BaseDocsFilterSet):
signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) signed_status = django_filters.ChoiceFilter(
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') label='По приёмке',
invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета') choices=signed_status_choices,
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) 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): class AktSverkiFilterSet(BaseDocsFilterSet):
signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) signed_status = django_filters.ChoiceFilter(
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') label='По приёмке',
total_saldo = CustomChoiceFilter(label=u'По сальдо', options=total_saldo_choices, widget=django_filters.widgets.LinkWidget) choices=signed_status_choices,
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) 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): class DoverFilterSet(BaseDocsFilterSet):
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') client = django_filters.ModelChoiceFilter(
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) label='По контрагенту',
queryset=None,
empty_label='все контрагенты'
)
doc_date = CustomDateRangeFilter(
label='По времени создания',
options=doc_date_choices,
widget=django_filters.widgets.LinkWidget
)
class PlatejkaFilterSet(BaseDocsFilterSet): class PlatejkaFilterSet(BaseDocsFilterSet):
platej_type = django_filters.ChoiceFilter(label=u'По типу', choices=platej_type_choices, widget=django_filters.widgets.LinkWidget) platej_type = django_filters.ChoiceFilter(
client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') label='По типу',
doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) 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.invoice import (InvoiceForm, InvoiceAdminForm, # noqa
from docs.forms.aktrabot import AktRabotForm, AktRabotAdminForm, AktRabotItemForm, AktRabotItemAdminForm InvoiceItemForm, InvoiceItemAdminForm, InvoicesListForm) # noqa
from docs.forms.aktsverki import AktSverkiForm, AktSverkiAdminForm, AktSverkiItemForm, AktSverkiItemAdminForm from docs.forms.aktrabot import (AktRabotForm, AktRabotAdminForm, # noqa
from docs.forms.dover import DoverForm, DoverAdminForm, DoverItemForm, DoverItemAdminForm AktRabotItemForm, AktRabotItemAdminForm) # noqa
from docs.forms.platejka import PlatejkaForm, PlatejkaAdminForm from docs.forms.aktsverki import (AktSverkiForm, AktSverkiAdminForm, # noqa
from docs.forms.nakladn import NakladnForm, NakladnAdminForm, NakladnItemForm, NakladnItemAdminForm AktSverkiItemForm, AktSverkiItemAdminForm) # noqa
from docs.forms.faktura import FakturaForm, FakturaAdminForm, FakturaItemForm, FakturaItemAdminForm 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 -*- # -*- coding: utf-8 -*-
from django import forms
from commons.forms import MyBaseModelForm from commons.forms import MyBaseModelForm
from .base_forms import BaseModelForm from .base_forms import BaseModelForm
@ -18,13 +16,13 @@ class AktSverkiForm(BaseModelForm):
class Meta: class Meta:
model = AktSverki model = AktSverki
fields = ('doc_num', 'doc_date', fields = ('doc_num', 'doc_date',
'doc_mesto', 'doc_mesto',
'client', 'client',
# период # период
'start_date', 'end_date', 'start_date', 'end_date',
# входящее сальдо # входящее сальдо
'saldo_debit', 'saldo_credit', 'saldo_debit', 'saldo_credit',
) )
def __init__(self, user, *args, **kwargs): def __init__(self, user, *args, **kwargs):
super(AktSverkiForm, self).__init__(user, *args, **kwargs) super(AktSverkiForm, self).__init__(user, *args, **kwargs)
@ -44,12 +42,14 @@ class AktSverkiAdminForm(AktSverkiForm):
exclude = () exclude = ()
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
# обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки ! # обязательно нужно вызывать родительский __init__ и передавать ему None
# вместо user - иначе глюки !
super(AktSverkiAdminForm, self).__init__(None, *args, **kwargs) super(AktSverkiAdminForm, self).__init__(None, *args, **kwargs)
class AktSverkiItemForm(MyBaseModelForm): class AktSverkiItemForm(MyBaseModelForm):
"""Форма редактирования табличной части акта сверки.""" """Форма редактирования табличной части акта сверки."""
class Meta: class Meta:
model = AktSverkiItem model = AktSverkiItem
exclude = ['parent'] exclude = ['parent']
@ -58,5 +58,6 @@ class AktSverkiItemForm(MyBaseModelForm):
class AktSverkiItemAdminForm(AktSverkiItemForm): class AktSverkiItemAdminForm(AktSverkiItemForm):
"""Форма редактирования табличной части акта сверки - для админки.""" """Форма редактирования табличной части акта сверки - для админки."""
class Meta(AktSverkiItemForm.Meta): class Meta(AktSverkiItemForm.Meta):
exclude = None exclude = None

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

@ -3,19 +3,33 @@ from django import forms
DOC_FORMATS = ( DOC_FORMATS = (
(u'pdf', u'PDF'), ('pdf', 'PDF'),
(u'xls', u'Excel'), ('xls', 'Excel'),
) )
class EmailForm(forms.Form): class EmailForm(forms.Form):
"""Форма отправки документа по email.""" """Форма отправки документа по email."""
to = forms.EmailField(label=u'E-mail получателя') to = forms.EmailField(label='E-mail получателя')
body = forms.CharField(label=u'Текст сообщения', max_length=1000, required=False, body = forms.CharField(
widget=forms.Textarea(attrs={'cols': 80, 'rows': 3})) label='Текст сообщения',
doc_format = forms.ChoiceField(label=u'Отправить как', choices=DOC_FORMATS, initial=DOC_FORMATS[0][0], max_length=1000,
widget=forms.RadioSelect()) required=False,
insert_sign = forms.BooleanField(label=u'Вставить печать и подпись', initial=False, widget=forms.Textarea(attrs={'cols': 80, 'rows': 3})
required=False) )
save_client_email = forms.BooleanField(label=u'Сохранить этот e-mail в анкете контрагента', initial=False, doc_format = forms.ChoiceField(
required=False) 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): def __init__(self, *args, **kwargs):
# обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки ! # обязательно нужно вызывать родительский __init__ и передавать ему None
# вместо user - иначе глюки !
super(InvoiceAdminForm, self).__init__(None, *args, **kwargs) super(InvoiceAdminForm, self).__init__(None, *args, **kwargs)

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

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

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

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

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

@ -6,37 +6,40 @@ from docs.models.base_models import BaseModel, VeryBaseModel
class Dover(BaseModel): class Dover(BaseModel):
"""Доверенность на получение ТМЦ.""" """Доверенность на получение ТМЦ."""
doc_expire_date = models.DateField(u'Срок действия') doc_expire_date = models.DateField('Срок действия')
# на получение мат.ценностей по документу # на получение мат.ценностей по документу
dover_doc = models.CharField(u'По документу №', max_length=256) dover_doc = models.CharField('По документу №', max_length=256)
dover_doc_date = models.DateField(u'Дата документа') dover_doc_date = models.DateField('Дата документа')
# кому выдана и его документы # кому выдана и его документы
dover_name = models.CharField(u'Должность, ФИО', max_length=256, help_text=u'Полностью в дат. падеже.') dover_name = models.CharField(
dover_passport_ser = models.CharField(u'Серия', max_length=10) 'Должность, ФИО',
dover_passport_num = models.CharField(u'Номер', max_length=10) max_length=256,
dover_passport_org = models.CharField(u'Кем выдан', max_length=256) help_text='Полностью в дат. падеже.'
dover_passport_date = models.DateField(u'Дата выдачи') )
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): class Meta(BaseModel.Meta):
verbose_name = u'Доверенность на получ. ТМЦ' verbose_name = 'Доверенность на получ. ТМЦ'
verbose_name_plural = u'Доверенности на получ. ТМЦ' verbose_name_plural = 'Доверенности на получ. ТМЦ'
class DoverItem(VeryBaseModel): class DoverItem(VeryBaseModel):
"""Табличная часть доверенности на получение ТМЦ.""" """Табличная часть доверенности на получение ТМЦ."""
parent = models.ForeignKey(Dover, related_name='dover_items') parent = models.ForeignKey(Dover, related_name='dover_items')
name = models.CharField(u'Наименование', max_length=256) name = models.CharField('Наименование', max_length=256)
qty = models.PositiveIntegerField(u'Количество') qty = models.PositiveIntegerField('Количество')
units = models.CharField(u'Ед. измерения', max_length=20) units = models.CharField('Ед. измерения', max_length=20)
class Meta(VeryBaseModel.Meta): class Meta(VeryBaseModel.Meta):
verbose_name = u'Табл. часть доверенности' verbose_name = 'Табл. часть доверенности'
verbose_name_plural = u'Табл. части доверенностей' verbose_name_plural = 'Табл. части доверенностей'
#app_label = 'docs'
ordering = ('created_at',) ordering = ('created_at',)
def __unicode__(self): def __str__(self):
return u'%s, %s %s' % (self.name[:30], self.qty, self.units) 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): class Faktura(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, LinkedDocsMixin):
"""Счёт-фактура""" """Счёт-фактура"""
doc_reason = models.CharField(u'Основание', max_length=256, blank=True, default='') doc_reason = models.CharField('Основание', max_length=256, blank=True, default='')
fixes = models.BooleanField(u'Изменения', default=False) fixes = models.BooleanField('Изменения', default=False)
avance = models.BooleanField(u'аванс', default=False) avance = models.BooleanField('аванс', default=False)
currency = models.ForeignKey(Currency, verbose_name=u'валюта', null=True) currency = models.ForeignKey(Currency, verbose_name='валюта', null=True)
user_is_sender = models.BooleanField(u'пользователь - отправитель', default=False) user_is_sender = models.BooleanField('пользователь - отправитель', default=False)
sender = models.ForeignKey( sender = models.ForeignKey(
Client, Client,
related_name='sender_fakturas', related_name='sender_fakturas',
blank=True, blank=True,
null=True, null=True,
verbose_name=u'Отправитель' verbose_name='Отправитель'
) )
receiver = models.ForeignKey( receiver = models.ForeignKey(
Client, Client,
related_name='receiver_fakturas', related_name='receiver_fakturas',
blank=True, blank=True,
null=True, null=True,
verbose_name=u'Получатель' verbose_name='Получатель'
) )
plat_doc_num = models.CharField( plat_doc_num = models.CharField(
'Номер платёжного документа', 'Номер платёжного документа',
@ -36,7 +36,7 @@ class Faktura(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, Linke
default='' default=''
) )
plat_doc_date = models.DateField('Дата платёжного документа', blank=True, null=True) 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) fix_doc_date = models.DateField('Дата исправления', blank=True, null=True)
def get_consignor_and_address(self): def get_consignor_and_address(self):
@ -44,24 +44,24 @@ class Faktura(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, Linke
""" """
if self.user_is_sender: 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: elif self.sender:
return '%s, %s' % (self.sender.name, self.sender.address) return f'{self.sender.name}, {self.sender.address}'
else: else:
return u'' return ''
def get_receiver_and_address(self): def get_receiver_and_address(self):
"""Получатель и адрес """Получатель и адрес
""" """
if self.receiver: if self.receiver:
return '%s, %s' % (self.receiver.name, self.receiver.address) return f'{self.receiver.name}, {self.receiver.address}'
else: else:
return u'' return ''
class Meta(BaseInvoiceModel.Meta): class Meta(BaseInvoiceModel.Meta):
verbose_name = u'Счёт-фактура' verbose_name = 'Счёт-фактура'
verbose_name_plural = u'Счета-фактуры' verbose_name_plural = 'Счета-фактуры'
app_label="docs" app_label = "docs"
class FakturaItem(BaseItemInvoiceModel): class FakturaItem(BaseItemInvoiceModel):
@ -70,20 +70,20 @@ class FakturaItem(BaseItemInvoiceModel):
'Код единицы измерения', 'Код единицы измерения',
max_length=10, max_length=10,
blank=True, blank=True,
default=u'-' default='-'
) )
parent = models.ForeignKey(Faktura, related_name='faktura_items') parent = models.ForeignKey(Faktura, related_name='faktura_items')
country_code = models.CharField(u'Код страны', max_length=10, blank=True, default=u'-') country_code = models.CharField('Код страны', max_length=10, blank=True, default='-')
country_name = models.CharField(u'Название страны', max_length=256) country_name = models.CharField('Название страны', max_length=256)
gtd = models.CharField(u'Основание', max_length=256, blank=True, default='') gtd = models.CharField('Основание', max_length=256, blank=True, default='')
ntd = models.CharField( ntd = models.CharField(
u'Номер транспортной декларации', 'Номер транспортной декларации',
max_length=256, max_length=256,
blank=True, blank=True,
default='' default=''
) )
class Meta(BaseItemInvoiceModel.Meta): class Meta(BaseItemInvoiceModel.Meta):
verbose_name = u'Табл. часть фактуры' verbose_name = 'Табл. часть фактуры'
verbose_name_plural = u'Табл. части фактур' verbose_name_plural = 'Табл. части фактур'
app_label = "docs" app_label = "docs"

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

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

@ -6,8 +6,14 @@ from docs import consts
class SignedStatusFieldMixin(models.Model): 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: class Meta:
abstract = True abstract = True
@ -15,8 +21,15 @@ class SignedStatusFieldMixin(models.Model):
class InvoiceFieldMixin(models.Model): class InvoiceFieldMixin(models.Model):
"""Mixin: добавляет FK поле `Создать по счёту`""" """Mixin: добавляет FK поле `Создать по счёту`"""
invoice = models.ForeignKey(Invoice, related_name='+', verbose_name=u'Создать по счёту', blank=True, null=True, invoice = models.ForeignKey(
default=None, on_delete=models.SET_NULL) Invoice,
related_name='+',
verbose_name='Создать по счёту',
blank=True,
null=True,
default=None,
on_delete=models.SET_NULL
)
class Meta: class Meta:
abstract = True abstract = True

@ -8,19 +8,19 @@ from docs.models.linked_docs_mixin import LinkedDocsMixin
class Nakladn(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, LinkedDocsMixin): class Nakladn(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, LinkedDocsMixin):
"""Накладная торг12.""" """Накладная торг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): class Meta(BaseInvoiceModel.Meta):
verbose_name = u'Накладная' verbose_name = 'Накладная'
verbose_name_plural = u'Накладные' verbose_name_plural = 'Накладные'
class NakladnItem(BaseItemInvoiceModel): class NakladnItem(BaseItemInvoiceModel):
"""Табличная часть накладной торг12.""" """Табличная часть накладной торг12."""
parent = models.ForeignKey(Nakladn, related_name='nakladn_items') 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): class Meta(BaseItemInvoiceModel.Meta):
verbose_name = u'Табл. часть накладной' verbose_name = 'Табл. часть накладной'
verbose_name_plural = u'Табл. части накладных' verbose_name_plural = 'Табл. части накладных'

@ -9,45 +9,68 @@ from docs import consts
class Platejka(BaseModel): class Platejka(BaseModel):
"""Платёжное поручение.""" """Платёжное поручение."""
platej_type = models.PositiveSmallIntegerField(u'Тип платёжного поручения', choices=consts.PLATEJ_TYPE_CHOICES, platej_type = models.PositiveSmallIntegerField(
default=consts.PLATEJ_TYPE_COMMERCE) 'Тип платёжного поручения',
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) doc_total = models.DecimalField('Сумма', max_digits=10, decimal_places=2)
payment_type = models.PositiveSmallIntegerField(u'Вид платежа', choices=consts.PAYMENT_TYPE_CHOICES, payment_type = models.PositiveSmallIntegerField(
default=consts.PAYMENT_TYPE_CHOICES[0][0]) 'Вид платежа',
payment_order = models.CharField(u'Очерёдность платежа', max_length=10) choices=consts.PAYMENT_TYPE_CHOICES,
doc_info = models.TextField(u'Назначение платежа', max_length=1000) 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, tax_status = models.CharField(
default=consts.TAX_STATUS_CHOICES[0][0]) 'Статус составителя',
tax_base = models.CharField(u'Основание налогового платежа', max_length=10, choices=consts.TAX_BASE, max_length=10,
default=consts.TAX_BASE[0][0]) choices=consts.TAX_STATUS_CHOICES,
tax_type = models.CharField(u'Тип налогового платежа', max_length=10, choices=consts.TAX_TYPE, default=consts.TAX_STATUS_CHOICES[0][0]
default=consts.TAX_TYPE[0][0]) )
tax_num = models.CharField(u'Номер документа основания', max_length=50, blank=True, default='') tax_base = models.CharField(
tax_date = models.DateField(u'Дата документа основания', blank=True, null=True) 'Основание налогового платежа',
tax_bk = models.CharField(u'Код БК доходов РФ', max_length=256) max_length=10,
tax_okato = models.CharField(u'Код ОКАТО сборщика платежей', max_length=256) choices=consts.TAX_BASE,
tax_period = models.CharField(u'Период, за который начисляется налог', max_length=256, default=consts.TAX_BASE[0][0]
help_text = (u'Формат ввода периода платежей:<br />' )
u'Месячный платёж - "МС.00.0000"<br />' tax_type = models.CharField(
u'Квартальный платёж - "КВ.00.0000"<br />' 'Тип налогового платежа',
u'Полугодовой платёж - "ПЛ.00.0000"<br />' max_length=10,
u'Годовой платёж - "ГД.00.0000"<br />' choices=consts.TAX_TYPE,
u'Платёж по дате - "дд.мм.гггг"') 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): class Meta(BaseModel.Meta):
verbose_name = u'Платёжное поручение' verbose_name = 'Платёжное поручение'
verbose_name_plural = u'Платёжные поручения' verbose_name_plural = 'Платёжные поручения'
# хелперы, чтоб не оборачивать в шаблонах каждое обращение к определенным полям в проверку типа платежа # хелперы, чтоб не оборачивать в шаблонах каждое обращение к
# определенным полям в проверку типа платежа
def is_commerce(self): def is_commerce(self):
return self.platej_type == consts.PLATEJ_TYPE_COMMERCE 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: if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_status:
return self.tax_status return self.tax_status
return u'' return ''
def get_tax_base_kod(self): def get_tax_base_kod(self):
"""Налоги. Основание налогового платежа, КОД.""" """Налоги. Основание налогового платежа, КОД."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_base: if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_base:
return self.tax_base return self.tax_base
return u'' return ''
def get_tax_type_kod(self): def get_tax_type_kod(self):
"""Налоги. Тип налогового платежа, КОД.""" """Налоги. Тип налогового платежа, КОД."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_type: if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_type:
return self.tax_type return self.tax_type
return u'' return ''
def get_tax_num(self): def get_tax_num(self):
"""Налоги. Номер документа основания.""" """Налоги. Номер документа основания."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_num: if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_num:
return self.tax_num return self.tax_num
return u'' return ''
def get_tax_date(self): def get_tax_date(self):
"""Налоги. Дата документа основания.""" """Налоги. Дата документа основания."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_date: if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_date:
return self.tax_date return self.tax_date
return u'' return ''
def get_tax_bk(self): def get_tax_bk(self):
"""Налоги. Код БК доходов РФ.""" """Налоги. Код БК доходов РФ."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_bk: if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_bk:
return self.tax_bk return self.tax_bk
return u'' return ''
def get_tax_okato(self): def get_tax_okato(self):
"""Налоги. Код ОКАТО сборщика платежей.""" """Налоги. Код ОКАТО сборщика платежей."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_okato: if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_okato:
return self.tax_okato return self.tax_okato
return u'' return ''
def get_tax_period(self): def get_tax_period(self):
"""Налоги. Период, за который начисляется налог.""" """Налоги. Период, за который начисляется налог."""
if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_period: if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_period:
return 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 -*- # -*- 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 (InvoiceViews, AktRabotViews, AktSverkiViews,
from docs.views import getview, index, get_invoices, get_tbl_items, get_client_by_invoice, toggle_doc_status DoverViews, PlatejkaViews, NakladnViews, FakturaViews)
from docs.views import (getview, index, get_invoices, get_tbl_items,
get_client_by_invoice, toggle_doc_status)
urlpatterns = [
urlpatterns = patterns('docs.views', # страница со ссылками на бух. формы
url(r'^$', index, name='docs_index'), # страница со ссылками на бух. формы url(r'^$', index, name='docs_index'),
) ]
klasses = [ klasses = [
('invoice', InvoiceViews), ('invoice', InvoiceViews),
@ -20,62 +22,83 @@ klasses = [
] ]
for name, klass in 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), 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), 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), 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), name='docs_%s_delete' % name),
# сохранить в pdf # сохранить в 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), 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), name='docs_%s_img' % name),
# сохранить в excel # сохранить в 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), name='docs_%s_xls' % name),
# отправить pdf/xls на email # отправить 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), name='docs_%s_email' % name),
# поля документа - AJAX # поля документа - 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), name='docs_%s_get_ajax' % name),
# отправить pdf/xls на email - AJAX # отправить 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), name='docs_%s_email_ajax' % name),
url(r'^ajax_get_invoices/$', get_invoices, name='ajax_get_invoices'), 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_invoices/(?P<client_id>\d+)/$', get_invoices,
url(r'^ajax_get_tbl_items/(?P<invoice_id>\d+)/$', get_tbl_items, name='ajax_get_tbl_items'), name='ajax_get_invoices'),
url(r'^ajax_get_client_by_invoice/(?P<invoice_id>\d+)/$', get_client_by_invoice, name='ajax_get_client_by_invoice'), url(r'^ajax_get_tbl_items/(?P<invoice_id>\d+)/$', get_tbl_items,
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'), 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, 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, 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'), name='docs_%s_add_by_invoice' % 'faktura'),
) ]

@ -28,7 +28,7 @@ def calc_clean_total_price(obj):
def calc_total_nds(obj): def calc_total_nds(obj):
"""Считает сумму налога.""" """Считает сумму налога."""
total_price = obj.price * obj.qty 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 total_nds = total_price * nds_rate
return total_nds return total_nds
@ -52,7 +52,7 @@ def get_total_nds(obj):
"""Считает сумму налога.""" """Считает сумму налога."""
total_price = obj.price * obj.qty total_price = obj.price * obj.qty
if obj.parent.nds_method: 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 total_nds = total_price * nds_rate
else: else:
nds_rate = get_nds(obj.parent.nds_value) / (100 + get_nds(obj.parent.nds_value)) 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.shortcuts import render
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from docs.views.invoice import InvoiceViews from docs.views.invoice import InvoiceViews # noqa
from docs.views.aktrabot import AktRabotViews from docs.views.aktrabot import AktRabotViews # noqa
from docs.views.aktsverki import AktSverkiViews from docs.views.aktsverki import AktSverkiViews # noqa
from docs.views.dover import DoverViews from docs.views.dover import DoverViews # noqa
from docs.views.platejka import PlatejkaViews from docs.views.platejka import PlatejkaViews # noqa
from docs.views.nakladn import NakladnViews from docs.views.nakladn import NakladnViews # noqa
from docs.views.faktura import FakturaViews from docs.views.faktura import FakturaViews # noqa
from docs.views.ajax import get_invoices, get_tbl_items, get_client_by_invoice, toggle_doc_status from docs.views.ajax import (get_invoices, get_tbl_items, # noqa
get_client_by_invoice, toggle_doc_status) # noqa
@login_required # важно!!! @login_required # важно!!!
@ -22,8 +23,6 @@ def getview(request, *args, **kwargs):
return handler(request, *args, **kwargs) return handler(request, *args, **kwargs)
# -----------------------------------------------------------------------------
@login_required @login_required
def index(request): def index(request):
"""Страница со ссылками на все бух.формы.""" """Страница со ссылками на все бух.формы."""

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

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

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

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

@ -11,13 +11,13 @@ from .base_views import BaseViews
class PlatejkaViews(BaseViews): class PlatejkaViews(BaseViews):
"""Views для платежных поручений.""" """Views для платежных поручений."""
MODEL = Platejka # модель документа MODEL = Platejka # модель документа
FORM_CLASS = PlatejkaForm # форма документа FORM_CLASS = PlatejkaForm # форма документа
# поля, по которым можно сортировать список документов # поля, по которым можно сортировать список документов
ORDER_FIELDS = ('doc_date', 'doc_num', 'doc_info', 'doc_total',) ORDER_FIELDS = ('doc_date', 'doc_num', 'doc_info', 'doc_total',)
FILTERSET_CLASS = PlatejkaFilterSet # фильтры FILTERSET_CLASS = PlatejkaFilterSet # фильтры
# префикс именованных урлов этого типа документов, для передачи в шаблон # префикс именованных урлов этого типа документов, для передачи в шаблон
URL_PREFIX = 'docs_platejka_' URL_PREFIX = 'docs_platejka_'
@ -34,27 +34,30 @@ class PlatejkaViews(BaseViews):
# для генерации pdf/xls # для генерации pdf/xls
PDF_TEMPLATE = 'docs/platejka/as_pdf.html' PDF_TEMPLATE = 'docs/platejka/as_pdf.html'
XLS_TEMPLATE = 'platejka.xls' XLS_TEMPLATE = 'platejka.xls'
FILENAME = u'Платежное поручение № %s, %s' # без расширения FILENAME = u'Платежное поручение № %s, %s' # без расширения
# --- грамматика для вывода наименований в шаблонах # --- грамматика для вывода наименований в шаблонах
PADEJI = { PADEJI = {
'imenit': u'платёжное поручение', # кто? что? 'imenit': u'платёжное поручение', # кто? что?
'rodit': u'платёжного поручения', # кого? чего? 'rodit': u'платёжного поручения', # кого? чего?
'dateln': u'платёжному поручению', # кому? чему? 'dateln': u'платёжному поручению', # кому? чему?
'vinit': u'платёжное поручение', # кого? что? 'vinit': u'платёжное поручение', # кого? что?
'tvorit': u'платёжным поручением', # кем? чем? 'tvorit': u'платёжным поручением', # кем? чем?
'predlojn': u'платёжном поручении', # о ком? о чём? 'predlojn': u'платёжном поручении', # о ком? о чём?
} }
PADEJI_MNOJ = { PADEJI_MNOJ = {
'imenit': u'платёжные поручения', # кто? что? 'imenit': u'платёжные поручения', # кто? что?
'rodit': u'платёжных поручений', # кого? чего? 'rodit': u'платёжных поручений', # кого? чего?
'dateln': u'платёжным поручениям', # кому? чему? 'dateln': u'платёжным поручениям', # кому? чему?
'vinit': u'платёжные поручения', # кого? что? 'vinit': u'платёжные поручения', # кого? что?
'tvorit': u'платёжными поручениями', # кем? чем? 'tvorit': u'платёжными поручениями', # кем? чем?
'predlojn': u'платёжных поручениях', # о ком? о чём? 'predlojn': u'платёжных поручениях', # о ком? о чём?
} }
def update_list_dict(self, dictionary): def update_list_dict(self, dictionary):
"""Здесь можно изменить словарь параметров перед передачей его в шаблон вывода списка документов.""" """
Здесь можно изменить словарь параметров перед передачей
его в шаблон вывода списка документов.
"""
dictionary['dadata_api_key'] = settings.DADATA_API_KEY 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 # This will make sure the app is always imported when
# Django starts so that shared_task will use this app. # Django starts so that shared_task will use this app.
try: try:
from .celery import app as celery_app from .celery import app as celery_app # noqa
except ImportError as e: except ImportError as e:
warnings.warn('Celery import error, is it installed?') warnings.warn('Celery import error, is it installed?')

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

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

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

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

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

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

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

@ -1,6 +1,6 @@
import os import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dokumentor.settings") 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() application = get_wsgi_application()

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

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

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

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

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

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf.urls import * from django.conf.urls import url
from django.views.generic import TemplateView from django.views.generic import TemplateView
from myauth import views from myauth import views
urlpatterns = patterns('', urlpatterns = [
url(r'^register/$', views.register, name='myauth_register'), url(r'^register/$', views.register, name='myauth_register'),
url(r'^login/$', views.login, name='myauth_login'), url(r'^login/$', views.login, name='myauth_login'),
@ -43,4 +43,4 @@ urlpatterns = patterns('',
views.confirm_rm_profile, views.confirm_rm_profile,
name='auth_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 from myauth import forms, models, emails
REGISTRATION_OPEN = getattr(settings, 'REGISTRATION_OPEN', True) REGISTRATION_OPEN = getattr(settings, 'REGISTRATION_OPEN', True)
@ -76,14 +75,14 @@ def register(request):
form = form_class(data=request.POST, prefix=form_prefix) form = form_class(data=request.POST, prefix=form_prefix)
if form.is_valid(): if form.is_valid():
new_user = _create_user(request, **form.cleaned_data) 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) emails.send_registration_email.delay(new_user.email, confirm_url)
messages.add_message(request, messages.INFO, success_msg) messages.add_message(request, messages.INFO, success_msg)
return redirect(success_url) return redirect(success_url)
else: else:
form = form_class(prefix=form_prefix) form = form_class(prefix=form_prefix)
return render(request, template_name, {'form': form,}) return render(request, template_name, {'form': form, })
@sensitive_variables() @sensitive_variables()
@ -120,7 +119,7 @@ def confirm_registered_email(request, key):
def reset(request): def reset(request):
"""Запросить ключ восстановления пароля.""" """Запросить ключ восстановления пароля."""
form_class = forms.ResetPasswordForm form_class = forms.ResetPasswordForm
form_prefix='reset' form_prefix = 'reset'
template_name = 'myauth/reset.html' template_name = 'myauth/reset.html'
success_url = 'myauth_reset_key_ready' success_url = 'myauth_reset_key_ready'
@ -129,13 +128,13 @@ def reset(request):
if form.is_valid(): if form.is_valid():
user = form.get_user() user = form.get_user()
key = models.ResetKey.objects.create_key(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) emails.send_reset_password_email.delay(user.email, confirm_url)
return redirect(success_url) return redirect(success_url)
else: else:
form = form_class(prefix=form_prefix) form = form_class(prefix=form_prefix)
return render(request, template_name, {'form': form,}) return render(request, template_name, {'form': form, })
@sensitive_variables() @sensitive_variables()
@ -230,7 +229,7 @@ def login(request):
form = form_class(data=request.POST, prefix=form_prefix) form = form_class(data=request.POST, prefix=form_prefix)
if form.is_valid(): if form.is_valid():
auth.login(request, form.get_user()) 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.user_session_key = request.session.session_key
request.user.profile.save() request.user.profile.save()
del request.session['login_count'] del request.session['login_count']
@ -244,7 +243,7 @@ def login(request):
else: else:
form = form_class(prefix=form_prefix) form = form_class(prefix=form_prefix)
return render(request, template_name, {'form': form,}) return render(request, template_name, {'form': form, })
def logout(request): 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 django.shortcuts import redirect
from cms.views import details from cms.views import details
from cms.models.pagemodel import Page
def site_index(request): def site_index(request):

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

@ -102,7 +102,7 @@ class BasePaymentForm(forms.Form):
scid = self.cleaned_data['scid'] scid = self.cleaned_data['scid']
if ( if (
scid != settings.YANDEX_MONEY_SCID and 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]) raise forms.ValidationError(self.error_messages[self.ERROR_MESSAGE_CODES.BAD_SCID])
return scid return scid
@ -111,7 +111,7 @@ class BasePaymentForm(forms.Form):
shop_id = self.cleaned_data['shopId'] shop_id = self.cleaned_data['shopId']
if ( if (
shop_id != settings.YANDEX_MONEY_SHOP_ID and 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]) raise forms.ValidationError(self.error_messages[self.ERROR_MESSAGE_CODES.BAD_SHOP_ID])
return shop_id return shop_id

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