From a3cf8dab08469ba43084c1309772ff094880f703 Mon Sep 17 00:00:00 2001 From: Dmitriy Shesterkin Date: Mon, 26 Jun 2017 18:50:24 +0300 Subject: [PATCH] pep 8 tests fix --- manage.py | 2 - requirements/base.txt | 4 +- src/callback/models.py | 20 ++- src/callback/urls.py | 11 +- src/commons/forms.py | 19 +- src/customer/managers.py | 2 +- src/customer/models.py | 5 +- src/customer/urls.py | 143 ++++++++------- src/customer/views/bank_accounts.py | 2 +- src/customer/views/bank_accounts_ajax.py | 39 ++-- src/customer/views/license.py | 66 ++++--- src/customer/views/profile.py | 66 +++---- src/customer/views/profile_ajax.py | 21 ++- src/docs/admin.py | 28 +-- src/docs/apps.py | 1 - src/docs/as_xls/__init__.py | 2 +- src/docs/as_xls/render_to_xls.py | 156 ++++++++-------- src/docs/autocomplete_light_registry.py | 4 +- src/docs/consts.py | 130 +++++++------- src/docs/filters.py | 216 +++++++++++++++++------ src/docs/forms/__init__.py | 21 ++- src/docs/forms/aktsverki.py | 21 +-- src/docs/forms/dover.py | 21 ++- src/docs/forms/email.py | 36 ++-- src/docs/forms/invoice.py | 3 +- src/docs/forms/nakladn.py | 3 +- src/docs/forms/platejka.py | 44 +++-- src/docs/models/__init__.py | 16 +- src/docs/models/aktsverki.py | 69 ++++++-- src/docs/models/base_models.py | 85 ++++----- src/docs/models/dover.py | 39 ++-- src/docs/models/faktura.py | 46 ++--- src/docs/models/invoice.py | 22 ++- src/docs/models/linked_docs_mixin.py | 4 +- src/docs/models/mixins.py | 21 ++- src/docs/models/nakladn.py | 12 +- src/docs/models/platejka.py | 97 ++++++---- src/docs/tests.py | 16 -- src/docs/urls.py | 83 +++++---- src/docs/utils.py | 4 +- src/docs/views/__init__.py | 19 +- src/docs/views/base_views.py | 54 +++--- src/docs/views/dover.py | 5 +- src/docs/views/invoice.py | 29 +-- src/docs/views/nakladn.py | 30 ++-- src/docs/views/platejka.py | 37 ++-- src/dokumentor/__init__.py | 2 +- src/dokumentor/celery.py | 2 +- src/dokumentor/settings/common.py | 3 +- src/dokumentor/settings/local.py | 1 + src/dokumentor/settings/production.py | 3 +- src/dokumentor/settings/stage.py | 3 +- src/dokumentor/settings/testing.py | 2 + src/dokumentor/urls.py | 21 +-- src/dokumentor/wsgi.py | 2 +- src/myauth/admin.py | 3 +- src/myauth/apps.py | 2 - src/myauth/forms.py | 130 ++++++++------ src/myauth/managers.py | 14 +- src/myauth/models.py | 27 +-- src/myauth/tasks.py | 5 +- src/myauth/urls.py | 6 +- src/myauth/views.py | 15 +- src/pages/models.py | 3 - src/pages/tests.py | 16 -- src/pages/views.py | 1 - src/yandex_money/apps.py | 2 - src/yandex_money/forms.py | 4 +- src/yandex_money/urls.py | 6 +- tox.ini | 4 + 70 files changed, 1143 insertions(+), 908 deletions(-) delete mode 100644 src/docs/tests.py delete mode 100644 src/pages/models.py delete mode 100644 src/pages/tests.py create mode 100644 tox.ini diff --git a/manage.py b/manage.py index 4fc15af..fab7a95 100755 --- a/manage.py +++ b/manage.py @@ -9,8 +9,6 @@ if __name__ == "__main__": env_file = p.normpath(p.join(p.abspath(p.dirname(__file__)), "./conf/env")) env.load(env_file) - print(env_file) - from django.core.management import execute_from_command_line execute_from_command_line(sys.argv) diff --git a/requirements/base.txt b/requirements/base.txt index 02e86c9..717e9c5 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -71,7 +71,7 @@ django-redis==4.8.0 redis==2.10.5 trans==2.1.0 python-decouple==3.0 -flake8==3.2.1 +flake8==3.3.0 numpy==1.13.0 mock==2.0.0 mockredispy==2.9.3 @@ -82,3 +82,5 @@ django-test-plus==1.0.17 Faker==0.7.15 coverage==4.4.1 pytest-flake8==0.8.1 +pycodestyle==2.3.1 +pyflakes==1.5.0 diff --git a/src/callback/models.py b/src/callback/models.py index cabd2a5..b85bd1b 100644 --- a/src/callback/models.py +++ b/src/callback/models.py @@ -16,10 +16,24 @@ class ReqAvail(models.Model): name = models.CharField(u'Имя клиента', max_length=100) phone = models.CharField(u'Телефон или e-mail', max_length=50) message = models.TextField(u'Текст сообщения') - user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='messages', null=True, blank=True) + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + related_name='messages', + null=True, + blank=True + ) - status = models.PositiveSmallIntegerField(u'Статус', choices=STATUS_CHOICES, default=NEW_STATUS) - status_changed = models.DateTimeField(u'Статус изменен', null=True, blank=True, editable=False) + status = models.PositiveSmallIntegerField( + u'Статус', + choices=STATUS_CHOICES, + default=NEW_STATUS + ) + status_changed = models.DateTimeField( + u'Статус изменен', + null=True, + blank=True, + editable=False + ) created_at = models.DateTimeField(u'Дата заказа', auto_now_add=True) updated_at = models.DateTimeField(u'Изменен', auto_now=True) diff --git a/src/callback/urls.py b/src/callback/urls.py index fbae108..d163803 100644 --- a/src/callback/urls.py +++ b/src/callback/urls.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- -from django.conf.urls import patterns, url +from django.conf.urls import url + from callback.views import req_avail -urlpatterns = patterns('', - url(r'^send/$', req_avail, name='callback-send-message'), - url(r'^send/(?P\d+)/$', req_avail, name='callback-request-item'), - ) +urlpatterns = [ + url(r'^send/$', req_avail, name='callback-send-message'), + url(r'^send/(?P\d+)/$', req_avail, name='callback-request-item'), +] diff --git a/src/commons/forms.py b/src/commons/forms.py index 7c51287..1797aff 100644 --- a/src/commons/forms.py +++ b/src/commons/forms.py @@ -4,9 +4,12 @@ import autocomplete_light def set_field_error(form, field, msg=u'Обязательное поле.'): - """Добавить сообщение об ошибке поля и убрать это поле из списка успешно прошедших валидацию. + """ + Добавить сообщение об ошибке поля и убрать это поле из списка + успешно прошедших валидацию. Полезно, если нужно инвалидировать поле из метода clean() и добавить ему ошибку. - В этом случае исключение forms.ValidationError() не подходит, т.к. оно добавит сообщение об ошибке в ошибки формы. + В этом случае исключение forms.ValidationError() не подходит, + т.к. оно добавит сообщение об ошибке в ошибки формы. """ form._errors[field] = form.error_class([msg]) if field in form.cleaned_data: @@ -16,18 +19,22 @@ def set_field_error(form, field, msg=u'Обязательное поле.'): class _MySuperForm(object): """Базовая форма. Добавляет всякого полезного функционала к форме.""" - # Список условно-обязательных полей, у которых нужно установить атрибут required=False. - # Полезно, когда какие-то поля становятся обязательны к заполнению в зависимости от значения других полей. + # Список условно-обязательных полей, у которых нужно установить + # атрибут required=False. + # Полезно, когда какие-то поля становятся обязательны к заполнению + # в зависимости от значения других полей. # TODO мигрировать на unset_required conditional_fields = [] # Список полей, у которых нужно сбросить признак обязательности: required=False. - # Полезно, когда в базовой форме определяются какие-то поля, которые в одних унаследованных формах обязательны, + # Полезно, когда в базовой форме определяются какие-то поля, которые в одних + # унаследованных формах обязательны, # а в других нет. unset_required = [] # Словарь полей, у которых нужно заменить атрибут label. - # Полезно, когда нужно дать разные метки полям в админке и в форме, с которой работает пользователь. + # Полезно, когда нужно дать разные метки полям в админке и в форме, + # с которой работает пользователь. change_labels = {} def __init__(self, *args, **kwargs): diff --git a/src/customer/managers.py b/src/customer/managers.py index fe787eb..420c782 100644 --- a/src/customer/managers.py +++ b/src/customer/managers.py @@ -64,7 +64,7 @@ class BankAccountManager(models.Manager): if not self.have_main(company=company): try: accounts = self.get_all(company=company)[0] - accounts.is_main=True + accounts.is_main = True accounts.save() except IndexError: pass diff --git a/src/customer/models.py b/src/customer/models.py index 5256f50..26b1b61 100644 --- a/src/customer/models.py +++ b/src/customer/models.py @@ -254,7 +254,7 @@ class UserProfile(models.Model): def check_main_reqs_not_filled(self): result = self.check_name_not_filled() or self.inn == '' or self.address == '' or \ - self.get_boss_fio() == '' or self.get_main_bank_account() == '' + self.get_boss_fio() == '' or self.get_main_bank_account() == '' # noqa if result: return True @@ -524,7 +524,8 @@ class UserProfileFilters(models.Model): show_name = models.BooleanField(u'Краткое название организации', default=True) show_full_name = models.BooleanField(u'Полное название организации', default=True) show_kpp = models.BooleanField(u'КПП', default=True) - show_org_boss_title_and_fio = models.BooleanField(u'Руководитель (Должность, ФИО)', default=True) + show_org_boss_title_and_fio = models.BooleanField( + u'Руководитель (Должность, ФИО)', default=True) show_na_osnovanii = models.BooleanField(u'Действует на основании', default=True) objects = managers.UserProfileFiltersManager() diff --git a/src/customer/urls.py b/src/customer/urls.py index b650399..dd1aa30 100644 --- a/src/customer/urls.py +++ b/src/customer/urls.py @@ -1,86 +1,85 @@ # -*- coding: utf-8 -*- -from django.conf.urls import * +from django.conf.urls import url from customer import views from customer.views import profile, profile_ajax, license, documents from customer.views import bank_accounts, bank_accounts_ajax from customer.views import clients, clients_ajax -urlpatterns = \ - patterns('', - # личный кабинет - url(r'^$', views.customer_index, name='customer_index'), +urlpatterns = [ + # личный кабинет + url(r'^$', views.customer_index, name='customer_index'), - # --- профиль - url(r'^profile/$', profile.profile_view, name='customer_profile_view'), - url(r'^profile/edit/$', profile.profile_edit, name='customer_profile_edit'), - url(r'^profile/email/$', profile.profile_email, name='customer_profile_email'), - url(r'^license/$', license.order_license, name='customer_order_license'), - url(r'^delete_license/(?P\d+)/$', license.delete_license, - name='customer_delete_license'), - url(r'^get_doc/(?P\d+)/$', documents.get_doc, - name='customer_license_get_doc'), - url(r'^payment/confirm/(?P\d+)$', license.yandex_pay, - name='yamoney_confirm'), - url(r'^payment/result/$', license.payment_result, name='yamoney_result'), - url(r'^payment/success/$', license.payment_success, name='yamoney_success'), - url(r'^payment/fail/$', license.payment_fail, name='yamoney_fail'), - url(r'^license_list/$', license.license_list, name='customer_license_list'), - url(r'^paid_list/$', license.paid_list, name='customer_paid_list'), + # --- профиль + url(r'^profile/$', profile.profile_view, name='customer_profile_view'), + url(r'^profile/edit/$', profile.profile_edit, name='customer_profile_edit'), + url(r'^profile/email/$', profile.profile_email, name='customer_profile_email'), + url(r'^license/$', license.order_license, name='customer_order_license'), + url(r'^delete_license/(?P\d+)/$', license.delete_license, + name='customer_delete_license'), + url(r'^get_doc/(?P\d+)/$', documents.get_doc, + name='customer_license_get_doc'), + url(r'^payment/confirm/(?P\d+)$', license.yandex_pay, + name='yamoney_confirm'), + url(r'^payment/result/$', license.payment_result, name='yamoney_result'), + url(r'^payment/success/$', license.payment_success, name='yamoney_success'), + url(r'^payment/fail/$', license.payment_fail, name='yamoney_fail'), + url(r'^license_list/$', license.license_list, name='customer_license_list'), + url(r'^paid_list/$', license.paid_list, name='customer_paid_list'), - # --- профиль AJAX - url(r'^profile/filters/edit/ajax/$', profile_ajax.profile_filters_edit_ajax, - name='customer_profile_filters_edit_ajax'), - url(r'^profile/email/ajax/$', profile_ajax.profile_email_ajax, - name='customer_profile_email_ajax'), + # --- профиль AJAX + url(r'^profile/filters/edit/ajax/$', profile_ajax.profile_filters_edit_ajax, + name='customer_profile_filters_edit_ajax'), + url(r'^profile/email/ajax/$', profile_ajax.profile_email_ajax, + name='customer_profile_email_ajax'), - # --- расчетные счета - url(r'^bank-accounts/$', bank_accounts.bank_accounts_list, - name='customer_bank_accounts_list'), - url(r'^bank-accounts/page/(?P[0-9]+)/$', bank_accounts.bank_accounts_list, - name='customer_bank_accounts_list'), - url(r'^bank-accounts/add/$', bank_accounts.bank_accounts_add, - name='customer_bank_accounts_add'), - url(r'^bank-accounts/(?P\d+)/edit/$', bank_accounts.bank_accounts_edit, - name='customer_bank_accounts_edit'), - url(r'^bank-accounts/(?P\d+)/delete/$', bank_accounts.bank_accounts_delete, - name='customer_bank_accounts_delete'), + # --- расчетные счета + url(r'^bank-accounts/$', bank_accounts.bank_accounts_list, + name='customer_bank_accounts_list'), + url(r'^bank-accounts/page/(?P[0-9]+)/$', bank_accounts.bank_accounts_list, + name='customer_bank_accounts_list'), + url(r'^bank-accounts/add/$', bank_accounts.bank_accounts_add, + name='customer_bank_accounts_add'), + url(r'^bank-accounts/(?P\d+)/edit/$', bank_accounts.bank_accounts_edit, + name='customer_bank_accounts_edit'), + url(r'^bank-accounts/(?P\d+)/delete/$', bank_accounts.bank_accounts_delete, + name='customer_bank_accounts_delete'), - # --- расчетные счета AJAX - url(r'^bank-accounts/ajax/$', bank_accounts_ajax.bank_accounts_list_ajax, - name='customer_bank_accounts_list_ajax'), - url(r'^bank-accounts/(?P\d+)/get/ajax/$', - bank_accounts_ajax.bank_accounts_get_ajax, - name='customer_bank_accounts_get_ajax'), - url(r'^bank-accounts/add/ajax/$', bank_accounts_ajax.bank_accounts_add_ajax, - name='customer_bank_accounts_add_ajax'), - url(r'^bank-accounts/(?P\d+)/edit/ajax/$', - bank_accounts_ajax.bank_accounts_edit_ajax, - name='customer_bank_accounts_edit_ajax'), - url(r'^bank-accounts/(?P\d+)/delete/ajax/$', - bank_accounts_ajax.bank_accounts_delete_ajax, - name='customer_bank_accounts_delete_ajax'), + # --- расчетные счета AJAX + url(r'^bank-accounts/ajax/$', bank_accounts_ajax.bank_accounts_list_ajax, + name='customer_bank_accounts_list_ajax'), + url(r'^bank-accounts/(?P\d+)/get/ajax/$', + bank_accounts_ajax.bank_accounts_get_ajax, + name='customer_bank_accounts_get_ajax'), + url(r'^bank-accounts/add/ajax/$', bank_accounts_ajax.bank_accounts_add_ajax, + name='customer_bank_accounts_add_ajax'), + url(r'^bank-accounts/(?P\d+)/edit/ajax/$', + bank_accounts_ajax.bank_accounts_edit_ajax, + name='customer_bank_accounts_edit_ajax'), + url(r'^bank-accounts/(?P\d+)/delete/ajax/$', + bank_accounts_ajax.bank_accounts_delete_ajax, + name='customer_bank_accounts_delete_ajax'), - # --- контрагенты - url(r'^clients/$', clients.clients_list, name='customer_clients_list'), - url(r'^clients/page/(?P[0-9]+)/$', clients.clients_list, - name='customer_clients_list'), - url(r'^clients/add/$', clients.clients_add, name='customer_clients_add'), - url(r'^clients/(?P\d+)/edit/$', clients.clients_edit, - name='customer_clients_edit'), - url(r'^clients/(?P\d+)/delete/$', clients.clients_delete, - name='customer_clients_delete'), + # --- контрагенты + url(r'^clients/$', clients.clients_list, name='customer_clients_list'), + url(r'^clients/page/(?P[0-9]+)/$', clients.clients_list, + name='customer_clients_list'), + url(r'^clients/add/$', clients.clients_add, name='customer_clients_add'), + url(r'^clients/(?P\d+)/edit/$', clients.clients_edit, + name='customer_clients_edit'), + url(r'^clients/(?P\d+)/delete/$', clients.clients_delete, + name='customer_clients_delete'), - # --- контрагенты AJAX - url(r'^clients/(?P\d+)/get/ajax/$', clients_ajax.clients_get_ajax, - name='customer_clients_get_ajax'), - url(r'^clients/add/ajax/$', clients_ajax.clients_add_ajax, - name='customer_clients_add_ajax'), - url(r'^clients/(?P\d+)/edit/ajax/$', clients_ajax.clients_edit_ajax, - name='customer_clients_edit_ajax'), - url(r'^clients/(?P\d+)/delete/ajax/$', clients_ajax.clients_delete_ajax, - name='customer_clients_delete_ajax'), + # --- контрагенты AJAX + url(r'^clients/(?P\d+)/get/ajax/$', clients_ajax.clients_get_ajax, + name='customer_clients_get_ajax'), + url(r'^clients/add/ajax/$', clients_ajax.clients_add_ajax, + name='customer_clients_add_ajax'), + url(r'^clients/(?P\d+)/edit/ajax/$', clients_ajax.clients_edit_ajax, + name='customer_clients_edit_ajax'), + url(r'^clients/(?P\d+)/delete/ajax/$', clients_ajax.clients_delete_ajax, + name='customer_clients_delete_ajax'), - url(r'^tmp_upload/ajax/$', profile.tmp_upload, name='upload_tmp_file'), - url(r'^upload-image/ajax/$', profile.upload_image, name='upload-image'), - ) + # url(r'^tmp_upload/ajax/$', profile.tmp_upload, name='upload_tmp_file'), + url(r'^upload-image/ajax/$', profile.upload_image, name='upload-image'), +] diff --git a/src/customer/views/bank_accounts.py b/src/customer/views/bank_accounts.py index 76f3673..19ed0a3 100644 --- a/src/customer/views/bank_accounts.py +++ b/src/customer/views/bank_accounts.py @@ -28,7 +28,7 @@ def bank_accounts_add(request): """Добавить расчетный счет.""" raise_if_no_profile(request) - template_name='customer/bank_accounts/add.html' + template_name = 'customer/bank_accounts/add.html' form_class = forms.BankAccountForm success_url = 'customer_bank_accounts_list' diff --git a/src/customer/views/bank_accounts_ajax.py b/src/customer/views/bank_accounts_ajax.py index 52d50dd..cb39707 100644 --- a/src/customer/views/bank_accounts_ajax.py +++ b/src/customer/views/bank_accounts_ajax.py @@ -8,11 +8,10 @@ from django.views.decorators.csrf import csrf_protect from django.contrib.auth.decorators import login_required from django.core.urlresolvers import reverse -from docs.models import Invoice, Faktura, AktRabot, AktSverki, Nakladn, Platejka, Dover +from docs.models import Invoice, Faktura, AktRabot, Nakladn, Platejka from commons.utils import dthandler from .. import models, forms -from ..decorators import license_required from ..utils import raise_if_no_profile @@ -81,12 +80,14 @@ def bank_accounts_add_ajax(request): non_field_errors = form.non_field_errors() if not form.is_valid(): - non_field_errors.append(u'Заполните/исправьте выделенные поля.') + non_field_errors.append('Заполните/исправьте выделенные поля.') data = { 'success': form.is_valid(), - 'field_errors': form.errors, # ошибки полей - 'form_errors': non_field_errors, # ошибки формы + # ошибки полей + 'field_errors': form.errors, + # ошибки формы + 'form_errors': non_field_errors, } return HttpResponse(json.dumps(data), content_type='application/json') @@ -111,12 +112,14 @@ def bank_accounts_edit_ajax(request, id): non_field_errors = form.non_field_errors() if not form.is_valid(): - non_field_errors.append(u'Заполните/исправьте выделенные поля.') + non_field_errors.append('Заполните/исправьте выделенные поля.') data = { 'success': form.is_valid(), - 'field_errors': form.errors, # ошибки полей - 'form_errors': non_field_errors, # ошибки формы + # ошибки полей + 'field_errors': form.errors, + # ошибки формы + 'form_errors': non_field_errors, } return HttpResponse(json.dumps(data), content_type='application/json') @@ -136,27 +139,27 @@ def bank_accounts_delete_ajax(request, id): account_docs = [] doc_list = [ - (Invoice, u'счета'), - (Faktura, u'счета-фактуры'), - (Nakladn, u'накладные'), - (AktRabot, u'акты выполненных работ'), - (Platejka, u'платёжные поручения') + (Invoice, 'счета'), + (Faktura, 'счета-фактуры'), + (Nakladn, 'накладные'), + (AktRabot, 'акты выполненных работ'), + (Platejka, 'платёжные поручения') ] for doc in doc_list: docs = doc[0].objects.filter(bank_account=account) - print(docs) + if docs: account_docs.append(doc[1]) if not account_docs: account.delete() success = True - message = {'title': u'Инфо', - 'msg': u'Расчётный счёт удалён.'} + message = {'title': 'Инфо', + 'msg': 'Расчётный счёт удалён.'} del_id = id else: success = True - message = {'title': u'Инфо', - 'msg': u'Расчтный счет не удалён. Есть выписанные документы: %s.' % ','.join( + message = {'title': 'Инфо', + 'msg': 'Расчтный счет не удалён. Есть выписанные документы: %s.' % ','.join( account_docs)} del_id = None diff --git a/src/customer/views/license.py b/src/customer/views/license.py index 06ab32c..d462eaf 100644 --- a/src/customer/views/license.py +++ b/src/customer/views/license.py @@ -3,11 +3,9 @@ import json import hashlib from django.shortcuts import render, redirect -from django.http import Http404, HttpResponseRedirect, HttpResponseForbidden, HttpResponse, \ - HttpResponseBadRequest +from django.http import (HttpResponseForbidden, HttpResponse, HttpResponseBadRequest) from django.conf import settings from django.views.decorators.csrf import csrf_exempt -from django.utils.http import urlquote from django.contrib.auth.decorators import login_required from django.template.response import TemplateResponse from django.core.urlresolvers import reverse @@ -16,7 +14,6 @@ from django.views.decorators.csrf import csrf_protect from yandex_money.models import Payment from customer.models import License, LicensePrice -from customer.consts import PAYFORMS from customer.forms import LicenseForm, YaForm from customer.utils import raise_if_no_profile @@ -41,29 +38,29 @@ def order_license(request): raise_if_no_profile(request) template_name = 'customer/profile/license.html' - form = LicenseForm(request.POST or None, - initial = {'term': LicensePrice.objects.all()[1], 'payform': 0}) - dictionary = { - 'form': form, - } + form = LicenseForm( + request.POST or None, + initial={'term': LicensePrice.objects.all()[1], 'payform': 0} + ) + dictionary = {'form': form} if form.is_valid(): - new_license = License(company=request.user.profile, - term=form.cleaned_data['term'].term, - payform=form.cleaned_data['payform'], - pay_sum=form.cleaned_data['term'].price, - ) + new_license = License( + company=request.user.profile, + term=form.cleaned_data['term'].term, + payform=form.cleaned_data['payform'], + pay_sum=form.cleaned_data['term'].price + ) new_license.save() if form.cleaned_data['payform'] == '1': - payment, _ = Payment.objects.get_or_create(order_amount=form.cleaned_data['term']. - price, - payment_type=Payment.PAYMENT_TYPE.AC, - order_number=new_license.id, - ) - payment.user=request.user - # payment.cps_email=request.user.email - payment.customer_number=request.user.email - # payment.customer_number=request.user.profile.get_company_name().strip() + payment, _ = Payment.objects.get_or_create( + order_amount=form.cleaned_data['term']. + price, + payment_type=Payment.PAYMENT_TYPE.AC, + order_number=new_license.id + ) + payment.user = request.user + payment.customer_number = request.user.email payment.save() return redirect(reverse('yamoney_confirm', kwargs={'payment_id': payment.id})) @@ -71,6 +68,7 @@ def order_license(request): return render(request, template_name, dictionary) + @login_required def license_list(request): """Список счетов на лицензии @@ -80,9 +78,7 @@ def license_list(request): template_name = 'customer/profile/license_list.html' licenses = License.objects.filter( company=request.user.profile, deleted=False, status__gt=-1).order_by('-id') - dictionary = { - 'licenses': licenses, - } + dictionary = {'licenses': licenses} return render(request, template_name, dictionary) @@ -93,16 +89,17 @@ def paid_list(request): raise_if_no_profile(request) template_name = 'customer/profile/paid_list.html' - licenses = License.objects.filter(company=request.user.profile, - status__in=[-1, 1, 2, 3, 4], deleted=False).order_by('-id') - dictionary = { - 'licenses': licenses, - } + licenses = License.objects.filter( + company=request.user.profile, + status__in=[-1, 1, 2, 3, 4], + deleted=False).order_by('-id') + dictionary = {'licenses': licenses} return render(request, template_name, dictionary) @login_required def delete_license(request, pk): + dictionary = {} if not request.is_ajax(): return HttpResponseBadRequest() @@ -147,8 +144,7 @@ def payment_result(request): @csrf_exempt def payment_success(request): nInvId = request.GET.get('orderNumber') - order = License.objects.get(pk=nInvId) - + # order = License.objects.get(pk=nInvId) context = {'success': True, 'order_num': nInvId} return TemplateResponse(request, 'customer/profile/end_order.html', context) @@ -156,7 +152,7 @@ def payment_success(request): @csrf_exempt def payment_fail(request): try: - nInvId = request.GET.get('') + # nInvId = request.GET.get('') message = u"Возникла проблема. Ваш Заказ не оплачен. " \ u"Попробуйте оформить заявку снова, или позвоните по номеру." @@ -165,5 +161,5 @@ def payment_fail(request): request, 'customer/profile/end_order.html', {'message': message, 'success': False}) - except Order.DoesNotExist: + except: return HttpResponseForbidden() diff --git a/src/customer/views/profile.py b/src/customer/views/profile.py index e4ef8f8..bda9d61 100644 --- a/src/customer/views/profile.py +++ b/src/customer/views/profile.py @@ -23,7 +23,7 @@ from django.utils.encoding import smart_str from django.conf import settings from django.http import HttpResponse -from easy_thumbnails.files import get_thumbnailer +# from easy_thumbnails.files import get_thumbnailer from commons.pdf_tools import render_pdf_to_string, pdf_to_response @@ -146,32 +146,32 @@ def profile_edit(request): return render(request, template_name, dictionary) -def tmp_upload(request): - key = '' - SIZES = {'id_boss_sign': (170, 65), - 'id_glavbuh_sign': (170, 65), - 'id_stamp': (170, 170), - 'id_logo': (170, 170)} - elm_id = request.REQUEST['elm_id'] - for k in request.FILES.keys(): - key = k - file_ = request.FILES.get(key) - if not file_.content_type.startswith('image'): - return {'res': 'bad'} - if not os.path.exists(settings.MEDIA_ROOT + '/cache/imgs/'): - os.makedirs(settings.MEDIA_ROOT + '/cache/imgs/') - tmp_dir = tempfile.mkdtemp('img_tmp', settings.MEDIA_ROOT + '/cache/imgs/') - os.chmod(tmp_dir, 755) - open(tmp_dir + '/' + file_.name, "wb+").write(file_.read()) - tmp_url_partial = os.path.basename(tmp_dir) + '/' + file_.name - thumbnailer = get_thumbnailer(tmp_dir + '/' + file_.name) - thumbnail_options = {'size': SIZES[elm_id]} - # Возвращает в url полный путь, поэтому придётся резать - im = thumbnailer.get_thumbnail(thumbnail_options) - im_url = os.path.join(settings.MEDIA_URL, os.path.relpath(im.url, settings.MEDIA_ROOT)) - data = {'res': 'ok', 'pic': im_url, 'full_pic': tmp_url_partial} - data.update(request.REQUEST) - return HttpResponse(json.dumps(data), content_type='application/json') +# def tmp_upload(request): +# key = '' +# SIZES = {'id_boss_sign': (170, 65), +# 'id_glavbuh_sign': (170, 65), +# 'id_stamp': (170, 170), +# 'id_logo': (170, 170)} +# elm_id = request.REQUEST['elm_id'] +# for k in request.FILES.keys(): +# key = k +# file_ = request.FILES.get(key) +# if not file_.content_type.startswith('image'): +# return {'res': 'bad'} +# if not os.path.exists(settings.MEDIA_ROOT + '/cache/imgs/'): +# os.makedirs(settings.MEDIA_ROOT + '/cache/imgs/') +# tmp_dir = tempfile.mkdtemp('img_tmp', settings.MEDIA_ROOT + '/cache/imgs/') +# os.chmod(tmp_dir, 755) +# open(tmp_dir + '/' + file_.name, "wb+").write(file_.read()) +# tmp_url_partial = os.path.basename(tmp_dir) + '/' + file_.name +# thumbnailer = get_thumbnailer(tmp_dir + '/' + file_.name) +# thumbnail_options = {'size': SIZES[elm_id]} +# # Возвращает в url полный путь, поэтому придётся резать +# im = thumbnailer.get_thumbnail(thumbnail_options) +# im_url = os.path.join(settings.MEDIA_URL, os.path.relpath(im.url, settings.MEDIA_ROOT)) +# data = {'res': 'ok', 'pic': im_url, 'full_pic': tmp_url_partial} +# data.update(request.REQUEST) +# return HttpResponse(json.dumps(data), content_type='application/json') def save_file(path, file): @@ -188,12 +188,12 @@ def clean_background(file): # np.asarray(img) is read only. Wrap it in np.array to make it modifiable. arr = np.array(np.asarray(img)) r, g, b, a = np.rollaxis(arr, axis=-1) - mask = ((r > threshold) - & (g > threshold) - & (b > threshold) - & (np.abs(r - g) < dist) - & (np.abs(r - b) < dist) - & (np.abs(g - b) < dist) + mask = ((r > threshold) & + (g > threshold) & + (b > threshold) & + (np.abs(r - g) < dist) & + (np.abs(r - b) < dist) & + (np.abs(g - b) < dist) ) arr[mask, 3] = 0 img = Image.fromarray(arr, mode='RGBA') diff --git a/src/customer/views/profile_ajax.py b/src/customer/views/profile_ajax.py index 0a9ba29..198093f 100644 --- a/src/customer/views/profile_ajax.py +++ b/src/customer/views/profile_ajax.py @@ -1,16 +1,14 @@ # -*- coding: utf-8 -*- import simplejson as json -from django.shortcuts import get_object_or_404 -from django.http import HttpResponseBadRequest, HttpResponse, Http404 +from django.http import HttpResponseBadRequest, HttpResponse from django.views.decorators.http import require_POST from django.views.decorators.csrf import csrf_protect from django.contrib.auth.decorators import login_required from customer import models, forms -from customer.decorators import license_required -from customer.views.profile import _send_profile_email, _profile_get_pdf +from customer.views.profile import (_send_profile_email, _profile_get_pdf) from customer.utils import raise_if_no_profile @@ -31,7 +29,12 @@ def profile_filters_edit_ajax(request): filters_form_class = forms.get_profile_filters_form_class(profile.profile_type) filters = models.UserProfileFilters.objects.get_or_create_filters(user=request.user) - form = filters_form_class(data=request.POST, instance=filters, profile=profile, accounts=accounts) + form = filters_form_class( + data=request.POST, + instance=filters, + profile=profile, + accounts=accounts + ) if form.is_valid(): form.save() @@ -66,10 +69,10 @@ def profile_email_ajax(request): form = form_class(data=request.POST) if form.is_valid(): _send_profile_email( - subject = u'Реквизиты %s' % profile.get_company_name(), - to = form.cleaned_data['to'], - body = form.cleaned_data['body'], - pdf_content = _profile_get_pdf(request, profile, filters.bank_account, filters) + subject=u'Реквизиты %s' % profile.get_company_name(), + to=form.cleaned_data['to'], + body=form.cleaned_data['body'], + pdf_content=_profile_get_pdf(request, profile, filters.bank_account, filters) ) non_field_errors = form.non_field_errors() diff --git a/src/docs/admin.py b/src/docs/admin.py index e2a738b..8f04b8a 100644 --- a/src/docs/admin.py +++ b/src/docs/admin.py @@ -4,57 +4,39 @@ from django.contrib import admin from docs import models -#class InvoiceItemInline(admin.TabularInline): -# model = models.InvoiceItem -# extra = 0 - - class InvoiceAdmin(admin.ModelAdmin): list_display = ('doc_num', 'doc_date', 'company', 'client',) list_filter = ('doc_date',) search_fields = ('company__name', 'company__inn', 'company__email', - 'client__name', 'client__inn', 'client__contact_email') - #inlines = (InvoiceItemInline,) - - -#class NakladnItemInline(admin.TabularInline): -# model = models.NakladnItem -# extra = 0 + 'client__name', 'client__inn', 'client__contact_email') class NakladnAdmin(admin.ModelAdmin): list_display = ('doc_num', 'doc_date', 'company', 'client',) list_filter = ('doc_date',) search_fields = ('company__name', 'company__inn', 'company__email', - 'client__name', 'client__inn', 'client__contact_email') - #inlines = (NakladnItemInline,) - - -#class AktRabotItemInline(admin.TabularInline): -# model = models.AktRabotItem -# extra = 0 + 'client__name', 'client__inn', 'client__contact_email') class AktRabotAdmin(admin.ModelAdmin): list_display = ('doc_num', 'doc_date', 'company', 'client',) list_filter = ('doc_date',) search_fields = ('company__name', 'company__inn', 'company__email', - 'client__name', 'client__inn', 'client__contact_email') - #inlines = (AktRabotItemInline,) + 'client__name', 'client__inn', 'client__contact_email') class FakturaAdmin(admin.ModelAdmin): list_display = ('doc_num', 'doc_date', 'company', 'client',) list_filter = ('doc_date',) search_fields = ('company__name', 'company__inn', 'company__email', - 'client__name', 'client__inn', 'client__contact_email') + 'client__name', 'client__inn', 'client__contact_email') class PlatejkaAdmin(admin.ModelAdmin): list_display = ('doc_num', 'doc_date', 'company', 'client',) list_filter = ('doc_date',) search_fields = ('doc_info', 'company__name', 'company__inn', 'company__email', - 'client__name', 'client__inn', 'client__contact_email') + 'client__name', 'client__inn', 'client__contact_email') class MeasureAdmin(admin.ModelAdmin): diff --git a/src/docs/apps.py b/src/docs/apps.py index ee54d3e..ff1c55a 100644 --- a/src/docs/apps.py +++ b/src/docs/apps.py @@ -5,4 +5,3 @@ from django.apps import AppConfig class DocConfig(AppConfig): name = 'docs' verbose_name = 'Документы' - diff --git a/src/docs/as_xls/__init__.py b/src/docs/as_xls/__init__.py index 8cb5cdc..6c3320c 100644 --- a/src/docs/as_xls/__init__.py +++ b/src/docs/as_xls/__init__.py @@ -1 +1 @@ -from .render_to_xls import render_xls_to_string +from .render_to_xls import render_xls_to_string # noqa diff --git a/src/docs/as_xls/render_to_xls.py b/src/docs/as_xls/render_to_xls.py index b05c790..4bec789 100644 --- a/src/docs/as_xls/render_to_xls.py +++ b/src/docs/as_xls/render_to_xls.py @@ -8,11 +8,11 @@ import xlwt from django.conf import settings from django.template import Template, RequestContext -from django.template.base import BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END - -from commons.xls import (get_xlwt_style_list, copy_cells, width_cols, horz_page_break, mm_to_twips, - sum_src_heights, sum_dst_heights) +from django.template.base import BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, \ + VARIABLE_TAG_END +from commons.xls import (get_xlwt_style_list, copy_cells, width_cols, + horz_page_break, mm_to_twips, sum_src_heights, sum_dst_heights) TAG_RE = re.compile('(%s.*?%s|%s.*?%s)' % ( re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END), @@ -35,7 +35,7 @@ def render_xls_to_string(request, xls_template, dictionary=None): try: # откуда src_book = xlrd.open_workbook(src_xls, encoding_override='cp1251', - on_demand=True, formatting_info=True) + on_demand=True, formatting_info=True) src_sheet = src_book.sheet_by_index(0) # достать список стилей @@ -50,8 +50,7 @@ def render_xls_to_string(request, xls_template, dictionary=None): apply_page_settings(dst_sheet, xls_settings) # import ipdb;ipdb.set_trace() # заполнить данными - fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, - xls_settings) + fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings) # закрыть исходную книгу и сохранить созданную src_book.release_resources() @@ -73,8 +72,6 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings context = RequestContext(request, dictionary) - # ------------------------------------------------------------------------- - def write(row, col, val, src_row=None, src_col=None, commands=None): """Записывает данные в ячейку с сохранением стилей.""" src_row = src_row or row @@ -92,18 +89,21 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings return template.render(context) def parse_cells(row_from=0, row_to=None, col_from=0, col_to=None, - dst_row_shift=0, dst_col_shift=0, **kwargs): - """Ищет шаблонные теги и переменные в ячейках заданного диапазона. Если находит, то передает содержимое ячейки - целиком на обработку в process_template. После чего записывает полученный результат обратно в ячейку. + dst_row_shift=0, dst_col_shift=0, **kwargs): + """ + Ищет шаблонные теги и переменные в ячейках заданного диапазона. + Если находит, то передает содержимое ячейки + целиком на обработку в process_template. После чего записывает + полученный результат обратно в ячейку. Также ищет спец. токены и выполняет соответствующие действия. """ - row_to = row_to or src_sheet.nrows-1 - col_to = col_to or src_sheet.ncols-1 + row_to = row_to or src_sheet.nrows - 1 + col_to = col_to or src_sheet.ncols - 1 - for row in range(row_from, row_to+1): + for row in range(row_from, row_to + 1): cmd_fix_height = [] - for col in range(col_from, col_to+1): + for col in range(col_from, col_to + 1): cell = src_sheet.cell(row, col) cell_value = new_value = cell.value @@ -121,7 +121,6 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings new_value = process_template(new_value, **kwargs) # пофиксить переводы строки - #new_value = new_value.strip().replace('\r\n', '\n') new_value = new_value.strip().replace('\r\n', ' ') # команда 'конвертировать во float' @@ -162,8 +161,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings try: dst_sheet.insert_bitmap( new_value, - row = row + dst_row_shift, - col = col + dst_col_shift, + row=row + dst_row_shift, + col=col + dst_col_shift, ) new_value = '' except: @@ -173,28 +172,26 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings # print "Error inserting image from file '%s'" % new_value raise write( - row = row + dst_row_shift, - col = col + dst_col_shift, - val = new_value, - src_row = row, - src_col = col, - commands = {'draw_thin_bottom_border': cmd_draw_thin_bottom_border, - } + row=row + dst_row_shift, + col=col + dst_col_shift, + val=new_value, + src_row=row, + src_col=col, + commands={'draw_thin_bottom_border': cmd_draw_thin_bottom_border} ) - # --- конец цикла по ячейкам в строке # подобрать высоту строки в ячейках - dst_row = row + dst_row_shift # строка назначения - row_height = dst_sheet.row(dst_row).height # текущая высота + dst_row = row + dst_row_shift # строка назначения + row_height = dst_sheet.row(dst_row).height # текущая высота max_height = 0 for fh in cmd_fix_height: - #print '---FIX_HEIGHT:', 'dst_row=', dst_row, 'col=', fh['col'] + # print '---FIX_HEIGHT:', 'dst_row=', dst_row, 'col=', fh['col'] # взять ширину ячейки width = 0 # учитываем только объединенные ячейки - for r1,r2,c1,c2 in src_sheet.merged_cells: + for r1, r2, c1, c2 in src_sheet.merged_cells: if r1 != row or c1 != fh['col']: continue for colx in range(c1, c2): @@ -208,7 +205,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings width_in_pixels = width / 36.5 width_in_chars = width_in_pixels / 5.8 - # может быть 0, если команда @@FIX_HEIGHT@@ задана в простой (не объединенной) ячейке + # может быть 0, если команда @@FIX_HEIGHT@@ задана в простой + # (не объединенной) ячейке if width_in_chars == 0: # print ('WARNING. xls generation, cmd @@FIX_HEIGHT@@. ' # 'variable `width_in_chars` = %s. skip this command.' % width_in_chars) @@ -219,14 +217,15 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings min_rows = 1 need_rows = math.ceil(len(value) / width_in_chars) need_rows = int(max(min_rows, need_rows)) - #print 'need_rows=', need_rows + # print 'need_rows=', need_rows new_height = row_height * need_rows - # не фиксить высоту, если новая высота данной ячейки меньше либо равна текущей высоте + # не фиксить высоту, если новая высота данной ячейки меньше либо + # равна текущей высоте if new_height > max_height: max_height = new_height else: - #print 'SKIP,', new_height, '<=', max_height + # print 'SKIP,', new_height, '<=', max_height continue dst_sheet.row(dst_row).height = new_height @@ -253,12 +252,12 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings # --- !!! ------ вывести начало документа включительно по шапку табл. части - copy_cells(src_sheet, dst_sheet, style_list, row_from=0, row_to=p.TBL_BODY_ROW-1) + copy_cells(src_sheet, dst_sheet, style_list, row_from=0, row_to=p.TBL_BODY_ROW - 1) - parse_cells(row_to=p.TBL_BODY_ROW-1) + parse_cells(row_to=p.TBL_BODY_ROW - 1) # для отладки - выйти здесь - #return + # return # --- !!! ------------ вывести таблицу с учетом переходов на новую страницу @@ -273,24 +272,24 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings row = 0 row_shift = 0 - #print '---table:' + # print '---table:' def write_tbl_body_row(): """Хелпер для отрисовки строки таблицы. Зависит от внешних переменных row_shift, row и item! """ - #print '---table body row, dst_row_shift =', row_shift + # print '---table body row, dst_row_shift =', row_shift copy_cells( src_sheet, dst_sheet, style_list, - row_from = p.TBL_BODY_ROW, row_to = p.TBL_BODY_ROW, - dst_row_shift = row_shift + row_from=p.TBL_BODY_ROW, row_to=p.TBL_BODY_ROW, + dst_row_shift=row_shift ) parse_cells( - row_from = p.TBL_BODY_ROW, - row_to = p.TBL_BODY_ROW, - dst_row_shift = row_shift, - item = item, - item_npp = row+1 + row_from=p.TBL_BODY_ROW, + row_to=p.TBL_BODY_ROW, + dst_row_shift=row_shift, + item=item, + item_npp=row + 1 ) def write_tbl_page_footer(): @@ -298,19 +297,19 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings Зависит от внешних переменных row_shift, last_page_item_idx и row! """ dst_row_shift = row_shift - (p.TBL_PAGE_FOOTER_FROM - p.TBL_BODY_ROW) - #print '---table page footer, dst_row_shift =', dst_row_shift, \ + # print '---table page footer, dst_row_shift =', dst_row_shift, \ # 'items_start =', last_page_item_idx, 'items_stop =', row copy_cells( src_sheet, dst_sheet, style_list, - row_from = p.TBL_PAGE_FOOTER_FROM, row_to = p.TBL_PAGE_FOOTER_TO, - dst_row_shift = dst_row_shift + row_from=p.TBL_PAGE_FOOTER_FROM, row_to=p.TBL_PAGE_FOOTER_TO, + dst_row_shift=dst_row_shift ) parse_cells( - row_from = p.TBL_PAGE_FOOTER_FROM, - row_to = p.TBL_PAGE_FOOTER_TO, - dst_row_shift = dst_row_shift, - items_start = last_page_item_idx, - items_stop = row + row_from=p.TBL_PAGE_FOOTER_FROM, + row_to=p.TBL_PAGE_FOOTER_TO, + dst_row_shift=dst_row_shift, + items_start=last_page_item_idx, + items_stop=row ) def write_tbl_header(): @@ -318,17 +317,17 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings Зависит от внешних переменных row и add_offset! """ dst_row_shift = p.TBL_HEADER_ROWS + row + add_offset - #print '---table header, dst_row_shift =', dst_row_shift + # print '---table header, dst_row_shift =', dst_row_shift copy_cells( src_sheet, dst_sheet, style_list, - row_from = p.TBL_HEADER_FROM, row_to = p.TBL_HEADER_TO, - dst_row_shift = dst_row_shift + row_from=p.TBL_HEADER_FROM, row_to=p.TBL_HEADER_TO, + dst_row_shift=dst_row_shift ) # цикл по табличной части документа for row, item in enumerate(obj_items): row_shift = row + add_offset - #print 'row = %s, add_offset = %s' % (row, add_offset) + # print 'row = %s, add_offset = %s' % (row, add_offset) write_tbl_body_row() row_height = dst_sheet.row(p.TBL_BODY_ROW + row_shift).height @@ -340,13 +339,13 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings if curr_height + p.TBL_PAGE_FOOTER_HEIGHT + p.TBL_FOOTER_HEIGHT > p.WORK_HEIGHT: # если это первая строка, то: if row == 0: - #print '---table new page, row =', row + # print '---table new page, row =', row # 1. добавить разрыв страницы перед первой шапкой horz_page_break(dst_sheet, p.TBL_HEADER_FROM) curr_height = p.TBL_HEADER_HEIGHT + row_height # если это не последняя строка, то: - elif row < len(obj_items)-1: - #print '---table new page, row =', row + elif row < len(obj_items) - 1: + # print '---table new page, row =', row # 1. вместо строки вывести подитог if p.TBL_PAGE_FOOTER_ROWS > 0: write_tbl_page_footer() @@ -355,7 +354,8 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings add_offset += p.TBL_PAGE_FOOTER_ROWS row_shift += add_offset # 2. добавить разрыв страницы - horz_page_break(dst_sheet, (p.TBL_HEADER_FROM + p.TBL_HEADER_ROWS + row + add_offset)) + horz_page_break(dst_sheet, + (p.TBL_HEADER_FROM + p.TBL_HEADER_ROWS + row + add_offset)) # 3. вывести шапку write_tbl_header() add_offset += p.TBL_HEADER_ROWS @@ -365,28 +365,28 @@ def fill_xls(request, dictionary, src_sheet, dst_sheet, style_list, xls_settings write_tbl_body_row() curr_height += row_height - else: # for ... else + else: # for ... else # вывести подитог, если только что не выводили его в цикле if p.TBL_PAGE_FOOTER_ROWS > 0 and not just_wrote_page_footer: - #print '---tbl last page, row =', row - row += 1 # чтоб захватить в подитог и последнюю запись тоже + # print '---tbl last page, row =', row + row += 1 # чтоб захватить в подитог и последнюю запись тоже row_shift = row + add_offset write_tbl_page_footer() curr_height += p.TBL_PAGE_FOOTER_HEIGHT add_offset += row - p.TBL_PAGE_FOOTER_ROWS - #print '---end table' + # print '---end table' # для отладки - выйти здесь - #return + # return # --- !!! --------------------------------------- вывести остаток документа copy_cells( src_sheet, dst_sheet, style_list, - row_from = p.TBL_FOOTER_FROM, - dst_row_shift = add_offset + row_from=p.TBL_FOOTER_FROM, + dst_row_shift=add_offset ) # добавить разрыв страницы, если остаток документа не уместится целиком @@ -426,13 +426,14 @@ def get_settings(src_book, sheet_name=u'settings'): def apply_page_settings(dst_sheet, settings): """Применить параметры страницы.""" + def setparam(attr, key): if key in settings: setattr(dst_sheet, attr, settings[key]) def setparam_as_inch(attr, key): if key in settings: - setattr(dst_sheet, attr, settings[key]/25.4) + setattr(dst_sheet, attr, settings[key] / 25.4) setparam('portrait', 'PAGE_PORTRAIT') setparam('header_str', 'PAGE_HEADER_STR') @@ -448,12 +449,16 @@ def apply_page_settings(dst_sheet, settings): def get_all_these_boring_params(src_sheet, xls_settings): - """Достает нужные настройки из словаря и проверят, некоторые вычисляет - - и всё это складывает в класс, который потом и возвращает. - Если какие-то обязательные настройки не заданы, сообщает об этом в консоль и возвращает None. """ + Достает нужные настройки из словаря и проверят, некоторые вычисляет - + и всё это складывает в класс, который потом и возвращает. + Если какие-то обязательные настройки не заданы, сообщает + об этом в консоль и возвращает None. + """ + class Params(object): pass + p = Params() # строка контента таблицы - обязательно @@ -507,7 +512,8 @@ def get_all_these_boring_params(src_sheet, xls_settings): # высота в строках p.TBL_PAGE_FOOTER_ROWS = int(p.TBL_PAGE_FOOTER_TO - p.TBL_PAGE_FOOTER_FROM + 1) # высота в twips - p.TBL_PAGE_FOOTER_HEIGHT = sum_src_heights(src_sheet, p.TBL_PAGE_FOOTER_FROM, p.TBL_PAGE_FOOTER_TO) + p.TBL_PAGE_FOOTER_HEIGHT = sum_src_heights(src_sheet, p.TBL_PAGE_FOOTER_FROM, + p.TBL_PAGE_FOOTER_TO) else: p.TBL_PAGE_FOOTER_ROWS = 0 p.TBL_PAGE_FOOTER_HEIGHT = 0 diff --git a/src/docs/autocomplete_light_registry.py b/src/docs/autocomplete_light_registry.py index 89b5111..f923427 100644 --- a/src/docs/autocomplete_light_registry.py +++ b/src/docs/autocomplete_light_registry.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -# import autocomplete_light import autocomplete_light from django.db.models import Q @@ -30,8 +29,7 @@ class AutocompleteClient(autocomplete_light.AutocompleteModelBase): exclude = self.request.GET.getlist('exclude', []) choices = self.choices.filter(company=user_.profile).\ - filter(Q(name__icontains=q) | Q(inn=q) | Q(okpo=q)).\ - exclude(pk__in=exclude) + filter(Q(name__icontains=q) | Q(inn=q) | Q(okpo=q)).exclude(pk__in=exclude) return self.order_choices(choices)[0:self.limit_choices] diff --git a/src/docs/consts.py b/src/docs/consts.py index 9a5e13d..e31b975 100644 --- a/src/docs/consts.py +++ b/src/docs/consts.py @@ -1,10 +1,9 @@ # -*- coding: utf-8 -*- from decimal import Decimal - BOOL_CHOICES = ( - (True, u'Да'), - (False, u'Нет'), + (True, 'Да'), + (False, 'Нет'), ) # виды НДС @@ -13,9 +12,9 @@ NDS_TYPE_IN = 2 NDS_TYPE_OUT = 3 NDS_TYPE_CHOICES = ( - (NDS_TYPE_NO, u'Не учитывать'), - (NDS_TYPE_IN, u'В сумме'), - (NDS_TYPE_OUT, u'Сверх суммы'), + (NDS_TYPE_NO, 'Не учитывать'), + (NDS_TYPE_IN, 'В сумме'), + (NDS_TYPE_OUT, 'Сверх суммы'), ) # ставка НДС @@ -24,9 +23,9 @@ NDS_VALUE_10 = 10 NDS_VALUE_18 = 18 NDS_VALUE_CHOICES = ( - (NDS_VALUE_0, u'Без НДС'), - (NDS_VALUE_10, u'10%'), - (NDS_VALUE_18, u'18%'), + (NDS_VALUE_0, 'Без НДС'), + (NDS_VALUE_10, '10%'), + (NDS_VALUE_18, '18%'), ) # ставка НДС - число в формате Decimal (для расчетов) @@ -39,7 +38,6 @@ NDS_VALUE_NUMERIC = { NDS_IN_AMOUNT = 0 NDS_OTHER_AMOUNT = 1 - NDS_METHOD_CHOICES = ( (NDS_IN_AMOUNT, 'В сумме'), (NDS_OTHER_AMOUNT, 'Сверх суммы'), @@ -54,10 +52,10 @@ CURR_EUR = 3 CURR_OTHER = 4 CURRENCY_CHOICES = ( - (CURR_RUB, u'Руб.'), - (CURR_USD, u'USD'), - (CURR_EUR, u'EUR'), - (CURR_OTHER, u'Другое'), + (CURR_RUB, 'Руб.'), + (CURR_USD, 'USD'), + (CURR_EUR, 'EUR'), + (CURR_OTHER, 'Другое'), ) CURRENCY_CHOICES_DICT = dict(CURRENCY_CHOICES) @@ -68,9 +66,9 @@ CONSIGNOR_TYPE_OTHER = 2 CONSIGNOR_TYPE_NO = 3 CONSIGNOR_CHOICES = ( - (CONSIGNOR_TYPE_SELF, u'Подставить мои данные'), # из профиля через поле user - (CONSIGNOR_TYPE_OTHER, u'Стороннее лицо'), # из справочника контрагенты - (CONSIGNOR_TYPE_NO, u'Не указывать'), + (CONSIGNOR_TYPE_SELF, 'Подставить мои данные'), # из профиля через поле user + (CONSIGNOR_TYPE_OTHER, 'Стороннее лицо'), # из справочника контрагенты + (CONSIGNOR_TYPE_NO, 'Не указывать'), ) # варианты для поля грузополучатель @@ -79,9 +77,9 @@ RECEIVER_TYPE_OTHER = 2 RECEIVER_TYPE_NO = 3 RECEIVER_CHOICES = ( - (RECEIVER_TYPE_BUYER, u'То же лицо'), # что и покупатель - (RECEIVER_TYPE_OTHER, u'Стороннее лицо'), # из справочника контрагенты - (RECEIVER_TYPE_NO, u'Не указывать'), + (RECEIVER_TYPE_BUYER, 'То же лицо'), # что и покупатель + (RECEIVER_TYPE_OTHER, 'Стороннее лицо'), # из справочника контрагенты + (RECEIVER_TYPE_NO, 'Не указывать'), ) # ----------------------------------------------------- для платежных поручений @@ -91,66 +89,66 @@ PLATEJ_TYPE_COMMERCE = 1 PLATEJ_TYPE_TAX = 2 PLATEJ_TYPE_CHOICES = ( - (PLATEJ_TYPE_COMMERCE, u'Коммерческое'), - (PLATEJ_TYPE_TAX, u'Налоговое'), + (PLATEJ_TYPE_COMMERCE, 'Коммерческое'), + (PLATEJ_TYPE_TAX, 'Налоговое'), ) # вид платежа PAYMENT_TYPE_CHOICES = ( - (1, u'Не указывать'), - (2, u'Срочно'), - (3, u'Электронно'), - (4, u'Почтой'), - (5, u'Телеграфом'), + (1, 'Не указывать'), + (2, 'Срочно'), + (3, 'Электронно'), + (4, 'Почтой'), + (5, 'Телеграфом'), ) # статус составителя TAX_STATUS_CHOICES = ( - (u'01', u'01 - налогоплательщик (плательщик сборов) - юридическое лицо'), - (u'02', u'02 - налоговый агент'), - (u'03', u'03 - сборщик налогов и сборов'), - (u'04', u'04 - налоговый орган'), - (u'05', u'05 - служба судебных приставов'), - (u'06', u'06 - участник внешнеэкономической деятельности'), - (u'07', u'07 - таможенный орган'), - (u'08', u'08 - плательщик иных обязательных платежей'), - (u'09', u'09 - налогоплательщик (плательщик сборов) - ИП'), - (u'10', u'10 - налогоплательщик (плательщик сборов) - частный нотариус'), - (u'11', u'11 - налогоплательщик (плательщик сборов) - адвокат'), - (u'12', u'12 - налогоплательщик (плательщик сборов) - глава КФХ'), - (u'13', u'13 - налогоплательщик (плательщик сборов) - иное физическое лицо'), - (u'14', u'14 - налогоплательщик, производящий выплаты физическим лицам'), - (u'15', u'15 - кредитная организация'), + ('01', '01 - налогоплательщик (плательщик сборов) - юридическое лицо'), + ('02', '02 - налоговый агент'), + ('03', '03 - сборщик налогов и сборов'), + ('04', '04 - налоговый орган'), + ('05', '05 - служба судебных приставов'), + ('06', '06 - участник внешнеэкономической деятельности'), + ('07', '07 - таможенный орган'), + ('08', '08 - плательщик иных обязательных платежей'), + ('09', '09 - налогоплательщик (плательщик сборов) - ИП'), + ('10', '10 - налогоплательщик (плательщик сборов) - частный нотариус'), + ('11', '11 - налогоплательщик (плательщик сборов) - адвокат'), + ('12', '12 - налогоплательщик (плательщик сборов) - глава КФХ'), + ('13', '13 - налогоплательщик (плательщик сборов) - иное физическое лицо'), + ('14', '14 - налогоплательщик, производящий выплаты физическим лицам'), + ('15', '15 - кредитная организация'), ) # основание налогового платежа TAX_BASE = ( - (u'ТП', u'ТП - платежи текущего года'), - (u'ЗД', u'ЗД - добровольное погашение задолженности по истекшим налоговым периода'), - (u'БФ', u'БФ - текущие платежи физических лиц - клиентов банка (владельцев счета)'), - (u'ТР', u'ТР - погашение задолженности по требованию об уплате налогов (сборов) от налогового органа'), - (u'РС', u'РС - погашение рассроченной задолженности'), - (u'ОТ', u'ОТ - погашение отсроченной задолженности'), - (u'РТ', u'РТ - погашение реструктурируемой задолженности'), - (u'ВУ', u'ВУ - погашение отсроченной задолженности в связи с введением внешнего управления'), - (u'ПР', u'ПР - погашение задолженности, приостановленной к взысканию'), - (u'АП', u'АП - погашение задолженности по акту проверки'), - (u'АР', u'АР - погашение задолженности по исполнительному документу'), - ( u'0', u'0 - Конкретное значение указать невозможно'), + ('ТП', 'ТП - платежи текущего года'), + ('ЗД', 'ЗД - добровольное погашение задолженности по истекшим налоговым периода'), + ('БФ', 'БФ - текущие платежи физических лиц - клиентов банка (владельцев счета)'), + ('ТР', + 'ТР - погашение задолженности по требованию об уплате налогов (сборов) от налогового органа'), + ('РС', 'РС - погашение рассроченной задолженности'), + ('ОТ', 'ОТ - погашение отсроченной задолженности'), + ('РТ', 'РТ - погашение реструктурируемой задолженности'), + ('ВУ', 'ВУ - погашение отсроченной задолженности в связи с введением внешнего управления'), + ('ПР', 'ПР - погашение задолженности, приостановленной к взысканию'), + ('АП', 'АП - погашение задолженности по акту проверки'), + ('АР', 'АР - погашение задолженности по исполнительному документу'), + ('0', '0 - Конкретное значение указать невозможно'), ) # тип налогового платежа TAX_TYPE = ( - (u'НС', u'НС - уплата налога или сбора'), - (u'ПЛ', u'ПЛ - уплата платежа'), - (u'ГП', u'ГП - уплата пошлины'), - (u'ВЗ', u'ВЗ - уплата взноса'), - (u'АВ', u'АВ - уплата аванса или предоплата (в том числе декадные платежи)'), - (u'ПЕ', u'ПЕ - уплата пени'), - (u'ПЦ', u'ПЦ - уплата процентов'), - (u'СА', u'СА - налоговые санкции, установленные Налоговым кодексом РФ'), - (u'АШ', u'АШ - административные штрафы'), - (u'ИШ', u'ИШ - иные штрафы, установленные соответствующими нормативными актами'), - ( u'0', u'0 - Конкретное значение указать невозможно'), + ('НС', 'НС - уплата налога или сбора'), + ('ПЛ', 'ПЛ - уплата платежа'), + ('ГП', 'ГП - уплата пошлины'), + ('ВЗ', 'ВЗ - уплата взноса'), + ('АВ', 'АВ - уплата аванса или предоплата (в том числе декадные платежи)'), + ('ПЕ', 'ПЕ - уплата пени'), + ('ПЦ', 'ПЦ - уплата процентов'), + ('СА', 'СА - налоговые санкции, установленные Налоговым кодексом РФ'), + ('АШ', 'АШ - административные штрафы'), + ('ИШ', 'ИШ - иные штрафы, установленные соответствующими нормативными актами'), + ('0', '0 - Конкретное значение указать невозможно'), ) - diff --git a/src/docs/filters.py b/src/docs/filters.py index 8ae1405..ee7099f 100644 --- a/src/docs/filters.py +++ b/src/docs/filters.py @@ -22,7 +22,7 @@ class CustomDateRangeFilter(django_filters.DateRangeFilter): class CustomChoiceFilter(django_filters.ChoiceFilter): def __init__(self, *args, **kwargs): - self.options = kwargs.pop('options') # обязательный параметр! + self.options = kwargs.pop('options') # обязательный параметр! kwargs['choices'] = [(key, value[0]) for key, value in self.options.items()] super(CustomChoiceFilter, self).__init__(*args, **kwargs) @@ -44,23 +44,23 @@ def _quarter_dates(q, year): return datetime.date(year, 4, 1), datetime.date(year, 6, 30) elif q == 3: return datetime.date(year, 7, 1), datetime.date(year, 9, 30) - elif q ==4: + elif q == 4: return datetime.date(year, 10, 1), datetime.date(year, 12, 31) return None, None def current_quarter(today): """Возвращает даты начала/окончания текущего квартала.""" - q = (today.month-1)//3+1 + q = (today.month - 1) // 3 + 1 return _quarter_dates(q, today.year) def last_quarter(today): """Возвращает даты начала/окончания прошлого квартала.""" - q = (today.month-1)//3+1 + q = (today.month - 1) // 3 + 1 q -= 1 year = today.year - if q < 1: # прошлый год + if q < 1: # прошлый год q = 4 year -= 1 return _quarter_dates(q, year) @@ -73,64 +73,64 @@ last_quarter_start, last_quarter_end = last_quarter(today) # --- варианты фильтрации для разных полей doc_date_choices = { - '': (u'Всё время', lambda qs, name: qs.all()), - 1: (u'Этот месяц', lambda qs, name: qs.filter(**{ + '': ('Всё время', lambda qs, name: qs.all()), + 1: ('Этот месяц', lambda qs, name: qs.filter(**{ '%s__year' % name: datetime.datetime.now().year, '%s__month' % name: datetime.datetime.now().month })), - 2: (u'Прошлый месяц', lambda qs, name: qs.filter(**{ + 2: ('Прошлый месяц', lambda qs, name: qs.filter(**{ '%s__year' % name: datetime.datetime.now().year, - '%s__month' % name: datetime.datetime.now().month-1 + '%s__month' % name: datetime.datetime.now().month - 1 })), - 3: (u'Этот квартал', lambda qs, name: qs.filter(**{ + 3: ('Этот квартал', lambda qs, name: qs.filter(**{ '%s__gte' % name: current_quarter_start, '%s__lte' % name: current_quarter_end, })), - 4: (u'Прошлый квартал', lambda qs, name: qs.filter(**{ + 4: ('Прошлый квартал', lambda qs, name: qs.filter(**{ '%s__gte' % name: last_quarter_start, '%s__lte' % name: last_quarter_end, })), - 5: (u'Этот год', lambda qs, name: qs.filter(**{ + 5: ('Этот год', lambda qs, name: qs.filter(**{ '%s__year' % name: datetime.datetime.now().year, })), - 6: (u'Прошлый год', lambda qs, name: qs.filter(**{ - '%s__year' % name: datetime.datetime.now().year-1, + 6: ('Прошлый год', lambda qs, name: qs.filter(**{ + '%s__year' % name: datetime.datetime.now().year - 1, })), } closed_status_choices = ( - ('', u'Все счета'), - (1, u'Закрытые актом выполненных работ'), - (0, u'Не закрытые актом выполненных работ'), + ('', 'Все счета'), + (1, 'Закрытые актом выполненных работ'), + (0, 'Не закрытые актом выполненных работ'), ) paid_status_choices = ( - ('', u'Все счета'), - (Invoice.PAID, u'Оплаченные'), - (Invoice.PARTLY_PAID, u'Частично оплаченные'), - (Invoice.UNPAID, u'Неоплаченные'), + ('', 'Все счета'), + (Invoice.PAID, 'Оплаченные'), + (Invoice.PARTLY_PAID, 'Частично оплаченные'), + (Invoice.UNPAID, 'Неоплаченные'), ) signed_status_choices = ( - ('', u'Все документы'), - ('1', u'Подписанные'), - ('0', u'Не подписанные'), + ('', 'Все документы'), + ('1', 'Подписанные'), + ('0', 'Не подписанные'), ) total_saldo_choices = { - '': (u'Любое', lambda qs, name: qs.all()), - 1: (u'Положительное', lambda qs, name: qs.filter(**{ + '': ('Любое', lambda qs, name: qs.all()), + 1: ('Положительное', lambda qs, name: qs.filter(**{ '%s__gt' % name: 0, })), - 2: (u'Отрицательное', lambda qs, name: qs.filter(**{ + 2: ('Отрицательное', lambda qs, name: qs.filter(**{ '%s__lt' % name: 0, })), } platej_type_choices = ( - ('', u'Все плат. поручения'), - (consts.PLATEJ_TYPE_COMMERCE, u'Коммерческие'), - (consts.PLATEJ_TYPE_TAX, u'Налоговые'), + ('', 'Все плат. поручения'), + (consts.PLATEJ_TYPE_COMMERCE, 'Коммерческие'), + (consts.PLATEJ_TYPE_TAX, 'Налоговые'), ) @@ -145,10 +145,12 @@ class BaseDocsFilterSet(django_filters.FilterSet): self.request = request if 'client' in self.filters: - self.filters['client'].extra['queryset'] = Client.objects.get_all(self.request.user.profile) + self.filters['client'].extra['queryset'] = \ + Client.objects.get_all(self.request.user.profile) if 'invoice' in self.filters: - self.filters['invoice'].extra['queryset'] = Invoice.objects.get_all(self.request.user.profile) + self.filters['invoice'].extra['queryset'] = \ + Invoice.objects.get_all(self.request.user.profile) # сбросить у полей формы атрибут help_text for field in self.form.fields.values(): @@ -156,46 +158,146 @@ class BaseDocsFilterSet(django_filters.FilterSet): class InvoiceFilterSet(BaseDocsFilterSet): - paid_status = django_filters.ChoiceFilter(label=u'По оплате', choices=paid_status_choices, widget=django_filters.widgets.LinkWidget) - closed_status = django_filters.ChoiceFilter(label=u'По закрывающим документам', choices=closed_status_choices, widget=django_filters.widgets.LinkWidget) - client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') - doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + paid_status = django_filters.ChoiceFilter( + label='По оплате', + choices=paid_status_choices, + widget=django_filters.widgets.LinkWidget + ) + closed_status = django_filters.ChoiceFilter( + label='По закрывающим документам', + choices=closed_status_choices, + widget=django_filters.widgets.LinkWidget + ) + client = django_filters.ModelChoiceFilter( + label='По контрагенту', + queryset=None, + empty_label='все контрагенты' + ) + doc_date = CustomDateRangeFilter( + label='По времени создания', + options=doc_date_choices, + widget=django_filters.widgets.LinkWidget + ) class AktRabotFilterSet(BaseDocsFilterSet): - signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) - client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') - invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета') - doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + signed_status = django_filters.ChoiceFilter( + label='По приёмке', + choices=signed_status_choices, + widget=django_filters.widgets.LinkWidget + ) + client = django_filters.ModelChoiceFilter( + label='По контрагенту', + queryset=None, + empty_label='все контрагенты' + ) + invoice = django_filters.ModelChoiceFilter( + label='По счёту', + queryset=None, + empty_label='все счета' + ) + doc_date = CustomDateRangeFilter( + label='По времени создания', + options=doc_date_choices, + widget=django_filters.widgets.LinkWidget + ) class NakladnFilterSet(BaseDocsFilterSet): - signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) - client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') - invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета') - doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + signed_status = django_filters.ChoiceFilter( + label='По приёмке', + choices=signed_status_choices, + widget=django_filters.widgets.LinkWidget + ) + client = django_filters.ModelChoiceFilter( + label='По контрагенту', + queryset=None, + empty_label='все контрагенты' + ) + invoice = django_filters.ModelChoiceFilter( + label='По счёту', + queryset=None, + empty_label='все счета' + ) + doc_date = CustomDateRangeFilter( + label='По времени создания', + options=doc_date_choices, + widget=django_filters.widgets.LinkWidget + ) class FakturaFilterSet(BaseDocsFilterSet): - signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) - client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') - invoice = django_filters.ModelChoiceFilter(label=u'По счёту', queryset=None, empty_label=u'все счета') - doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + signed_status = django_filters.ChoiceFilter( + label='По приёмке', + choices=signed_status_choices, + widget=django_filters.widgets.LinkWidget + ) + client = django_filters.ModelChoiceFilter( + label='По контрагенту', + queryset=None, + empty_label='все контрагенты' + ) + invoice = django_filters.ModelChoiceFilter( + label='По счёту', + queryset=None, + empty_label='все счета' + ) + doc_date = CustomDateRangeFilter( + label='По времени создания', + options=doc_date_choices, + widget=django_filters.widgets.LinkWidget + ) class AktSverkiFilterSet(BaseDocsFilterSet): - signed_status = django_filters.ChoiceFilter(label=u'По приёмке', choices=signed_status_choices, widget=django_filters.widgets.LinkWidget) - client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') - total_saldo = CustomChoiceFilter(label=u'По сальдо', options=total_saldo_choices, widget=django_filters.widgets.LinkWidget) - doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + signed_status = django_filters.ChoiceFilter( + label='По приёмке', + choices=signed_status_choices, + widget=django_filters.widgets.LinkWidget + ) + client = django_filters.ModelChoiceFilter( + label='По контрагенту', + queryset=None, + empty_label='все контрагенты' + ) + total_saldo = CustomChoiceFilter( + label='По сальдо', + options=total_saldo_choices, + widget=django_filters.widgets.LinkWidget + ) + doc_date = CustomDateRangeFilter( + label='По времени создания', + options=doc_date_choices, + widget=django_filters.widgets.LinkWidget + ) class DoverFilterSet(BaseDocsFilterSet): - client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') - doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + client = django_filters.ModelChoiceFilter( + label='По контрагенту', + queryset=None, + empty_label='все контрагенты' + ) + doc_date = CustomDateRangeFilter( + label='По времени создания', + options=doc_date_choices, + widget=django_filters.widgets.LinkWidget + ) class PlatejkaFilterSet(BaseDocsFilterSet): - platej_type = django_filters.ChoiceFilter(label=u'По типу', choices=platej_type_choices, widget=django_filters.widgets.LinkWidget) - client = django_filters.ModelChoiceFilter(label=u'По контрагенту', queryset=None, empty_label=u'все контрагенты') - doc_date = CustomDateRangeFilter(label=u'По времени создания', options=doc_date_choices, widget=django_filters.widgets.LinkWidget) + platej_type = django_filters.ChoiceFilter( + label='По типу', + choices=platej_type_choices, + widget=django_filters.widgets.LinkWidget + ) + client = django_filters.ModelChoiceFilter( + label='По контрагенту', + queryset=None, + empty_label='все контрагенты' + ) + doc_date = CustomDateRangeFilter( + label='По времени создания', + options=doc_date_choices, + widget=django_filters.widgets.LinkWidget + ) diff --git a/src/docs/forms/__init__.py b/src/docs/forms/__init__.py index 3e08697..a1e0438 100644 --- a/src/docs/forms/__init__.py +++ b/src/docs/forms/__init__.py @@ -1,9 +1,14 @@ -from docs.forms.email import EmailForm +from docs.forms.email import EmailForm # noqa -from docs.forms.invoice import InvoiceForm, InvoiceAdminForm, InvoiceItemForm, InvoiceItemAdminForm, InvoicesListForm -from docs.forms.aktrabot import AktRabotForm, AktRabotAdminForm, AktRabotItemForm, AktRabotItemAdminForm -from docs.forms.aktsverki import AktSverkiForm, AktSverkiAdminForm, AktSverkiItemForm, AktSverkiItemAdminForm -from docs.forms.dover import DoverForm, DoverAdminForm, DoverItemForm, DoverItemAdminForm -from docs.forms.platejka import PlatejkaForm, PlatejkaAdminForm -from docs.forms.nakladn import NakladnForm, NakladnAdminForm, NakladnItemForm, NakladnItemAdminForm -from docs.forms.faktura import FakturaForm, FakturaAdminForm, FakturaItemForm, FakturaItemAdminForm +from docs.forms.invoice import (InvoiceForm, InvoiceAdminForm, # noqa + InvoiceItemForm, InvoiceItemAdminForm, InvoicesListForm) # noqa +from docs.forms.aktrabot import (AktRabotForm, AktRabotAdminForm, # noqa + AktRabotItemForm, AktRabotItemAdminForm) # noqa +from docs.forms.aktsverki import (AktSverkiForm, AktSverkiAdminForm, # noqa + AktSverkiItemForm, AktSverkiItemAdminForm) # noqa +from docs.forms.dover import DoverForm, DoverAdminForm, DoverItemForm, DoverItemAdminForm # noqa +from docs.forms.platejka import PlatejkaForm, PlatejkaAdminForm # noqa +from docs.forms.nakladn import (NakladnForm, NakladnAdminForm, # noqa + NakladnItemForm, NakladnItemAdminForm) # noqa +from docs.forms.faktura import (FakturaForm, FakturaAdminForm, # noqa + FakturaItemForm, FakturaItemAdminForm) # noqa diff --git a/src/docs/forms/aktsverki.py b/src/docs/forms/aktsverki.py index 92776b9..d7b7cc9 100644 --- a/src/docs/forms/aktsverki.py +++ b/src/docs/forms/aktsverki.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -from django import forms - from commons.forms import MyBaseModelForm from .base_forms import BaseModelForm @@ -18,13 +16,13 @@ class AktSverkiForm(BaseModelForm): class Meta: model = AktSverki fields = ('doc_num', 'doc_date', - 'doc_mesto', - 'client', - # период - 'start_date', 'end_date', - # входящее сальдо - 'saldo_debit', 'saldo_credit', - ) + 'doc_mesto', + 'client', + # период + 'start_date', 'end_date', + # входящее сальдо + 'saldo_debit', 'saldo_credit', + ) def __init__(self, user, *args, **kwargs): super(AktSverkiForm, self).__init__(user, *args, **kwargs) @@ -44,12 +42,14 @@ class AktSverkiAdminForm(AktSverkiForm): exclude = () def __init__(self, *args, **kwargs): - # обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки ! + # обязательно нужно вызывать родительский __init__ и передавать ему None + # вместо user - иначе глюки ! super(AktSverkiAdminForm, self).__init__(None, *args, **kwargs) class AktSverkiItemForm(MyBaseModelForm): """Форма редактирования табличной части акта сверки.""" + class Meta: model = AktSverkiItem exclude = ['parent'] @@ -58,5 +58,6 @@ class AktSverkiItemForm(MyBaseModelForm): class AktSverkiItemAdminForm(AktSverkiItemForm): """Форма редактирования табличной части акта сверки - для админки.""" + class Meta(AktSverkiItemForm.Meta): exclude = None diff --git a/src/docs/forms/dover.py b/src/docs/forms/dover.py index a326333..89b46b2 100644 --- a/src/docs/forms/dover.py +++ b/src/docs/forms/dover.py @@ -1,6 +1,4 @@ # -*- coding: utf-8 -*- -from django import forms - from commons.forms import MyBaseModelForm from .base_forms import BaseModelForm @@ -16,12 +14,13 @@ class DoverForm(BaseModelForm): class Meta: model = Dover fields = ('doc_num', 'doc_date', 'doc_expire_date', - 'client', - # на получение мат.ценностей по документу - 'dover_doc', 'dover_doc_date', - # кому выдана и его документы - 'dover_name', 'dover_passport_ser', 'dover_passport_num', 'dover_passport_org', 'dover_passport_date', - ) + 'client', + # на получение мат.ценностей по документу + 'dover_doc', 'dover_doc_date', + # кому выдана и его документы + 'dover_name', 'dover_passport_ser', 'dover_passport_num', 'dover_passport_org', + 'dover_passport_date', + ) def __init__(self, user, *args, **kwargs): super(DoverForm, self).__init__(user, *args, **kwargs) @@ -33,17 +32,20 @@ class DoverForm(BaseModelForm): class DoverAdminForm(DoverForm): """Форма редактирования доверенности на получение ТМЦ - для админки.""" + class Meta(DoverForm.Meta): # fields = None exclude = () def __init__(self, *args, **kwargs): - # обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки ! + # обязательно нужно вызывать родительский __init__ и передавать ему None + # вместо user - иначе глюки ! super(DoverAdminForm, self).__init__(None, *args, **kwargs) class DoverItemForm(MyBaseModelForm): """Форма редактирования табличной части доверенности на получение ТМЦ.""" + class Meta: model = DoverItem exclude = ['parent'] @@ -52,5 +54,6 @@ class DoverItemForm(MyBaseModelForm): class DoverItemAdminForm(DoverItemForm): """Форма редактирования табличной части доверенности на получение ТМЦ - для админки.""" + class Meta(DoverItemForm.Meta): exclude = None diff --git a/src/docs/forms/email.py b/src/docs/forms/email.py index 22d0d5c..0a14ec8 100644 --- a/src/docs/forms/email.py +++ b/src/docs/forms/email.py @@ -3,19 +3,33 @@ from django import forms DOC_FORMATS = ( - (u'pdf', u'PDF'), - (u'xls', u'Excel'), + ('pdf', 'PDF'), + ('xls', 'Excel'), ) class EmailForm(forms.Form): """Форма отправки документа по email.""" - to = forms.EmailField(label=u'E-mail получателя') - body = forms.CharField(label=u'Текст сообщения', max_length=1000, required=False, - widget=forms.Textarea(attrs={'cols': 80, 'rows': 3})) - doc_format = forms.ChoiceField(label=u'Отправить как', choices=DOC_FORMATS, initial=DOC_FORMATS[0][0], - widget=forms.RadioSelect()) - insert_sign = forms.BooleanField(label=u'Вставить печать и подпись', initial=False, - required=False) - save_client_email = forms.BooleanField(label=u'Сохранить этот e-mail в анкете контрагента', initial=False, - required=False) + to = forms.EmailField(label='E-mail получателя') + body = forms.CharField( + label='Текст сообщения', + max_length=1000, + required=False, + widget=forms.Textarea(attrs={'cols': 80, 'rows': 3}) + ) + doc_format = forms.ChoiceField( + label='Отправить как', + choices=DOC_FORMATS, + initial=DOC_FORMATS[0][0], + widget=forms.RadioSelect() + ) + insert_sign = forms.BooleanField( + label='Вставить печать и подпись', + initial=False, + required=False + ) + save_client_email = forms.BooleanField( + label='Сохранить этот e-mail в анкете контрагента', + initial=False, + required=False + ) diff --git a/src/docs/forms/invoice.py b/src/docs/forms/invoice.py index 6c7c7b4..34703da 100644 --- a/src/docs/forms/invoice.py +++ b/src/docs/forms/invoice.py @@ -41,7 +41,8 @@ class InvoiceAdminForm(InvoiceForm): } def __init__(self, *args, **kwargs): - # обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки ! + # обязательно нужно вызывать родительский __init__ и передавать ему None + # вместо user - иначе глюки ! super(InvoiceAdminForm, self).__init__(None, *args, **kwargs) diff --git a/src/docs/forms/nakladn.py b/src/docs/forms/nakladn.py index ae8cda4..92bd982 100644 --- a/src/docs/forms/nakladn.py +++ b/src/docs/forms/nakladn.py @@ -41,7 +41,8 @@ class NakladnAdminForm(NakladnForm): } def __init__(self, *args, **kwargs): - # обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки ! + # обязательно нужно вызывать родительский __init__ и + # передавать ему None вместо user - иначе глюки ! super(NakladnAdminForm, self).__init__(None, *args, **kwargs) diff --git a/src/docs/forms/platejka.py b/src/docs/forms/platejka.py index 3c151da..b634ac9 100644 --- a/src/docs/forms/platejka.py +++ b/src/docs/forms/platejka.py @@ -11,22 +11,24 @@ from .. import consts class PlatejkaForm(BaseModelForm): """Форма редактирования платежного поручения.""" conditional_fields = ['nds_value', - 'tax_status', 'tax_base', 'tax_type', 'tax_bk', 'tax_okato', 'tax_period',] + 'tax_status', 'tax_base', 'tax_type', 'tax_bk', 'tax_okato', + 'tax_period', ] class Meta: model = Platejka fields = ('platej_type', 'doc_num', 'doc_date', - 'bank_account', 'client', - 'nds_value', # поля только для перевода денег - # поля только для оплаты налогов - 'tax_status', 'tax_base', 'tax_type', 'tax_num', 'tax_date', 'tax_bk', 'tax_okato', 'tax_period', - # опять общие поля - 'doc_total', 'payment_type', 'payment_order', 'doc_info', - ) + 'bank_account', 'client', + 'nds_value', # поля только для перевода денег + # поля только для оплаты налогов + 'tax_status', 'tax_base', 'tax_type', 'tax_num', 'tax_date', 'tax_bk', + 'tax_okato', 'tax_period', + # опять общие поля + 'doc_total', 'payment_type', 'payment_order', 'doc_info', + ) _radioselect = forms.RadioSelect _textarea = forms.Textarea(attrs={'cols': 80, 'rows': 5}) widgets = { - #'platej_type': _radioselect, + # 'platej_type': _radioselect, 'doc_info': _textarea, } @@ -50,7 +52,7 @@ class PlatejkaForm(BaseModelForm): # # if not nds_value: set_field_error(self, 'nds_value') - elif platej_type == consts.PLATEJ_TYPE_TAX: # налоги + elif platej_type == consts.PLATEJ_TYPE_TAX: # налоги tax_status = cleaned_data.get('tax_status') tax_base = cleaned_data.get('tax_base') tax_type = cleaned_data.get('tax_type') @@ -58,18 +60,25 @@ class PlatejkaForm(BaseModelForm): tax_okato = cleaned_data.get('tax_okato') tax_period = cleaned_data.get('tax_period') - if not tax_status: set_field_error(self, 'tax_status') - if not tax_base: set_field_error(self, 'tax_base') - if not tax_type: set_field_error(self, 'tax_type') - if not tax_bk: set_field_error(self, 'tax_bk') - if not tax_okato: set_field_error(self, 'tax_okato') - if not tax_period: set_field_error(self, 'tax_period') + if not tax_status: + set_field_error(self, 'tax_status') + if not tax_base: + set_field_error(self, 'tax_base') + if not tax_type: + set_field_error(self, 'tax_type') + if not tax_bk: + set_field_error(self, 'tax_bk') + if not tax_okato: + set_field_error(self, 'tax_okato') + if not tax_period: + set_field_error(self, 'tax_period') return cleaned_data class PlatejkaAdminForm(PlatejkaForm): """Форма редактирования платежного поручения - для админки.""" + class Meta(PlatejkaForm.Meta): # fields = None exclude = () @@ -78,5 +87,6 @@ class PlatejkaAdminForm(PlatejkaForm): } def __init__(self, *args, **kwargs): - # обязательно нужно вызывать родительский __init__ и передавать ему None вместо user - иначе глюки ! + # обязательно нужно вызывать родительский __init__ и передавать ему None + # вместо user - иначе глюки ! super(PlatejkaAdminForm, self).__init__(None, *args, **kwargs) diff --git a/src/docs/models/__init__.py b/src/docs/models/__init__.py index ee6bd8c..f7349ea 100644 --- a/src/docs/models/__init__.py +++ b/src/docs/models/__init__.py @@ -1,8 +1,8 @@ -from docs.models.refs import Currency, Country, Measure -from docs.models.invoice import Invoice, InvoiceItem -from docs.models.aktrabot import AktRabot, AktRabotItem -from docs.models.aktsverki import AktSverki, AktSverkiItem -from docs.models.dover import Dover, DoverItem -from docs.models.platejka import Platejka -from docs.models.nakladn import Nakladn, NakladnItem -from docs.models.faktura import Faktura, FakturaItem +from docs.models.refs import Currency, Country, Measure # noqa +from docs.models.invoice import Invoice, InvoiceItem # noqa +from docs.models.aktrabot import AktRabot, AktRabotItem # noqa +from docs.models.aktsverki import AktSverki, AktSverkiItem # noqa +from docs.models.dover import Dover, DoverItem # noqa +from docs.models.platejka import Platejka # noqa +from docs.models.nakladn import Nakladn, NakladnItem # noqa +from docs.models.faktura import Faktura, FakturaItem # noqa diff --git a/src/docs/models/aktsverki.py b/src/docs/models/aktsverki.py index e99cc0f..4ca4e3f 100644 --- a/src/docs/models/aktsverki.py +++ b/src/docs/models/aktsverki.py @@ -9,29 +9,60 @@ from docs.models.mixins import SignedStatusFieldMixin class AktSverki(BaseModel, SignedStatusFieldMixin): """Акт сверки.""" - doc_mesto = models.CharField(u'Место подписания', max_length=256, help_text=u'(Например, г. Москва)') + doc_mesto = models.CharField( + 'Место подписания', + max_length=256, + help_text='(Например, г. Москва)' + ) # период start_date = models.DateField('С') end_date = models.DateField('По') # входящее сальдо - saldo_debit = models.DecimalField(u'Дебетовое', max_digits=10, decimal_places=2, blank=True) # , default=Decimal('0.00')) - saldo_credit = models.DecimalField(u'Кредитовое', max_digits=10, decimal_places=2, blank=True) # , default=Decimal('0.00')) + saldo_debit = models.DecimalField( + 'Дебетовое', + max_digits=10, + decimal_places=2, + blank=True + ) + saldo_credit = models.DecimalField( + 'Кредитовое', + max_digits=10, + decimal_places=2, + blank=True + ) # вычисляемые поля - обновляются при сохранении записей табличной части - total_debit = models.DecimalField(u'Общее дебетовое сальдо', max_digits=10, decimal_places=2, blank=True, - default=Decimal('0.00')) - total_credit = models.DecimalField(u'Общее кредитовое сальдо', max_digits=10, decimal_places=2, blank=True, - default=Decimal('0.00')) - total_saldo = models.DecimalField(u'Итоговое сальдо', max_digits=10, decimal_places=2, blank=True, - default=Decimal('0.00')) + total_debit = models.DecimalField( + 'Общее дебетовое сальдо', + max_digits=10, + decimal_places=2, + blank=True, + default=Decimal('0.00') + ) + total_credit = models.DecimalField( + 'Общее кредитовое сальдо', + max_digits=10, + decimal_places=2, + blank=True, + default=Decimal('0.00') + ) + total_saldo = models.DecimalField( + 'Итоговое сальдо', + max_digits=10, + decimal_places=2, + blank=True, + default=Decimal('0.00') + ) class Meta(BaseModel.Meta): verbose_name = u'Акт сверки' verbose_name_plural = u'Акты сверки' def save(self, *args, **kwargs): - if not self.saldo_debit: self.saldo_debit = 0 - if not self.saldo_credit: self.saldo_credit = 0 + if not self.saldo_debit: + self.saldo_debit = 0 + if not self.saldo_credit: + self.saldo_credit = 0 super(AktSverki, self).save(*args, **kwargs) @@ -39,16 +70,18 @@ class AktSverkiItem(VeryBaseModel): """Табличная часть акта сверки.""" parent = models.ForeignKey(AktSverki, related_name='aktsverki_items') - name = models.CharField(u'Наименование операции, документы', max_length=256) - debit = models.DecimalField(u'Дебет', max_digits=10, decimal_places=2, blank=True) - credit = models.DecimalField(u'Кредит', max_digits=10, decimal_places=2, blank=True) + name = models.CharField('Наименование операции, документы', max_length=256) + debit = models.DecimalField('Дебет', max_digits=10, decimal_places=2, blank=True) + credit = models.DecimalField('Кредит', max_digits=10, decimal_places=2, blank=True) class Meta(VeryBaseModel.Meta): - verbose_name = u'Табл. часть акта сверки' - verbose_name_plural = u'Табл. части актов сверки' + verbose_name = 'Табл. часть акта сверки' + verbose_name_plural = 'Табл. части актов сверки' ordering = ('created_at',) def save(self, *args, **kwargs): - if not self.debit: self.debit = 0 - if not self.credit: self.credit = 0 + if not self.debit: + self.debit = 0 + if not self.credit: + self.credit = 0 super(AktSverkiItem, self).save(*args, **kwargs) diff --git a/src/docs/models/base_models.py b/src/docs/models/base_models.py index 56ccda6..e097446 100644 --- a/src/docs/models/base_models.py +++ b/src/docs/models/base_models.py @@ -10,9 +10,11 @@ from docs import consts class VeryBaseModel(models.Model): - """Очень базовая абстрактная модель.""" - created_at = models.DateTimeField(u'Создан', auto_now_add=True) - updated_at = models.DateTimeField(u'Изменен', auto_now=True) + """ + Очень базовая абстрактная модель. + """ + created_at = models.DateTimeField('Создан', auto_now_add=True) + updated_at = models.DateTimeField('Изменен', auto_now=True) class Meta: abstract = True @@ -20,18 +22,22 @@ class VeryBaseModel(models.Model): ordering = ('-created_at',) get_latest_by = 'created_at' -# ----------------------------------------------------------------------------- - class BaseModel(VeryBaseModel): - """Абстрактная модель бух.формы.""" - user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='+', verbose_name=u'Пользователь') - company = models.ForeignKey(UserProfile, verbose_name=u'Компания', null=True) - - doc_num = models.PositiveIntegerField(u'Номер') + """ + Абстрактная модель бух.формы. + """ + user = models.ForeignKey( + settings.AUTH_USER_MODEL, + related_name='+', + verbose_name='Пользователь' + ) + company = models.ForeignKey(UserProfile, verbose_name='Компания', null=True) + + doc_num = models.PositiveIntegerField('Номер') doc_date = models.DateField('Дата создания') - client = models.ForeignKey(Client, related_name='+', verbose_name=u'Контрагент') + client = models.ForeignKey(Client, related_name='+', verbose_name='Контрагент') objects = managers.BaseModelManager() @@ -39,18 +45,15 @@ class BaseModel(VeryBaseModel): abstract = True ordering = ('-doc_date',) - def __unicode__(self): - return u'%s № %s от %s' % (self._meta.verbose_name or '', self.doc_num, self.doc_date) - def __str__(self): - return u'%s № %s от %s' % (self._meta.verbose_name or '', self.doc_num, self.doc_date) + return f'{self._meta.verbose_name} № {self.doc_num} от {self.doc_date}' class BaseNdsModel(BaseModel): """Расширение абстрактной модели бух.формы - НДС. Доп. поля под тип и ставку НДС. """ - nds_value = models.PositiveSmallIntegerField(u'Ставка НДС', + nds_value = models.PositiveSmallIntegerField('Ставка НДС', choices=consts.NDS_VALUE_CHOICES, default=consts.NDS_VALUE_0) nds_method = models.PositiveSmallIntegerField('Метод расчета НДС', @@ -66,54 +69,56 @@ class BaseNdsModel(BaseModel): class BaseInvoiceModel(BaseNdsModel): - """Расширение абстрактной модели бух.формы - по типу счета. - Доп. поля под расчетный счет и дополнительные условия. """ - bank_account = models.ForeignKey(BankAccount, related_name='+', - verbose_name=u'Расчётный счёт', - blank=True, null=True) - doc_text = models.TextField(u'Дополнительные условия', max_length=1000, blank=True, default='') + Расширение абстрактной модели бух.формы - по типу счета. + Доп. поля под расчетный счет и дополнительные условия. + """ + bank_account = models.ForeignKey( + BankAccount, related_name='+', + verbose_name='Расчётный счёт', + blank=True, + null=True + ) + doc_text = models.TextField( + 'Дополнительные условия', + max_length=1000, + blank=True, + default='' + ) class Meta(BaseNdsModel.Meta): abstract = True -# ----------------------------------------------------------------------------- - class BaseItemModel(VeryBaseModel): """Абстрактная модель табличной части бух.формы.""" - name = models.CharField(u'Наименование', max_length=256) - qty = models.DecimalField(u'Кол-во', max_digits=10, decimal_places=3) - units = models.CharField(u'Ед. изм.', max_length=20) + name = models.CharField('Наименование', max_length=256) + qty = models.DecimalField('Кол-во', max_digits=10, decimal_places=3) + units = models.CharField('Ед. изм.', max_length=20) class Meta(VeryBaseModel.Meta): abstract = True ordering = ('created_at',) - def __unicode__(self): - return u'%s, %s %s' % (self.name[:30], self.qty, self.units) - def __str__(self): - return u'%s, %s %s' % (self.name[:30], self.qty, self.units) + return f'{self.name[:30]}, {self.qty} {self.units}' class BaseItemInvoiceModel(BaseItemModel): - """Расширение абстрактной модели табл. части бух.формы - по типу счета. - Доп. поля под цену и сумму. """ - price = models.DecimalField(u'Цена', max_digits=10, decimal_places=2) - total_price = models.DecimalField(u'Сумма', max_digits=10, decimal_places=2) + Расширение абстрактной модели табл. части бух.формы - по типу счета. + Доп. поля под цену и сумму. + """ + price = models.DecimalField('Цена', max_digits=10, decimal_places=2) + total_price = models.DecimalField('Сумма', max_digits=10, decimal_places=2) class Meta(BaseItemModel.Meta): abstract = True - def __unicode__(self): - curr = consts.CURRENCY_CHOICES_DICT.get(getattr(self, 'currency', consts.CURR_RUB)) - return u'%s, %s %s * %s = %s %s' % (self.name[:30], self.qty, self.units, self.price, self.total_price, curr) - def __str__(self): curr = consts.CURRENCY_CHOICES_DICT.get(getattr(self, 'currency', consts.CURR_RUB)) - return u'%s, %s %s * %s = %s %s' % (self.name[:30], self.qty, self.units, self.price, self.total_price, curr) + return \ + f'{self.name[:30]}, {self.qty} {self.units} * {self.price} = {self.total_price} {curr}' def save(self, *args, **kwargs): # пересчитать сумму diff --git a/src/docs/models/dover.py b/src/docs/models/dover.py index f2b7209..2aa79a5 100644 --- a/src/docs/models/dover.py +++ b/src/docs/models/dover.py @@ -6,37 +6,40 @@ from docs.models.base_models import BaseModel, VeryBaseModel class Dover(BaseModel): """Доверенность на получение ТМЦ.""" - doc_expire_date = models.DateField(u'Срок действия') + doc_expire_date = models.DateField('Срок действия') # на получение мат.ценностей по документу - dover_doc = models.CharField(u'По документу №', max_length=256) - dover_doc_date = models.DateField(u'Дата документа') + dover_doc = models.CharField('По документу №', max_length=256) + dover_doc_date = models.DateField('Дата документа') # кому выдана и его документы - dover_name = models.CharField(u'Должность, ФИО', max_length=256, help_text=u'Полностью в дат. падеже.') - dover_passport_ser = models.CharField(u'Серия', max_length=10) - dover_passport_num = models.CharField(u'Номер', max_length=10) - dover_passport_org = models.CharField(u'Кем выдан', max_length=256) - dover_passport_date = models.DateField(u'Дата выдачи') + dover_name = models.CharField( + 'Должность, ФИО', + max_length=256, + help_text='Полностью в дат. падеже.' + ) + dover_passport_ser = models.CharField('Серия', max_length=10) + dover_passport_num = models.CharField('Номер', max_length=10) + dover_passport_org = models.CharField('Кем выдан', max_length=256) + dover_passport_date = models.DateField('Дата выдачи') class Meta(BaseModel.Meta): - verbose_name = u'Доверенность на получ. ТМЦ' - verbose_name_plural = u'Доверенности на получ. ТМЦ' + verbose_name = 'Доверенность на получ. ТМЦ' + verbose_name_plural = 'Доверенности на получ. ТМЦ' class DoverItem(VeryBaseModel): """Табличная часть доверенности на получение ТМЦ.""" parent = models.ForeignKey(Dover, related_name='dover_items') - name = models.CharField(u'Наименование', max_length=256) - qty = models.PositiveIntegerField(u'Количество') - units = models.CharField(u'Ед. измерения', max_length=20) + name = models.CharField('Наименование', max_length=256) + qty = models.PositiveIntegerField('Количество') + units = models.CharField('Ед. измерения', max_length=20) class Meta(VeryBaseModel.Meta): - verbose_name = u'Табл. часть доверенности' - verbose_name_plural = u'Табл. части доверенностей' - #app_label = 'docs' + verbose_name = 'Табл. часть доверенности' + verbose_name_plural = 'Табл. части доверенностей' ordering = ('created_at',) - def __unicode__(self): - return u'%s, %s %s' % (self.name[:30], self.qty, self.units) + def __str__(self): + return f'{self.name[:30]}, {self.qty} {self.units}' diff --git a/src/docs/models/faktura.py b/src/docs/models/faktura.py index 93649a1..400cd93 100644 --- a/src/docs/models/faktura.py +++ b/src/docs/models/faktura.py @@ -10,24 +10,24 @@ from docs.models.linked_docs_mixin import LinkedDocsMixin class Faktura(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, LinkedDocsMixin): """Счёт-фактура""" - doc_reason = models.CharField(u'Основание', max_length=256, blank=True, default='') - fixes = models.BooleanField(u'Изменения', default=False) - avance = models.BooleanField(u'аванс', default=False) - currency = models.ForeignKey(Currency, verbose_name=u'валюта', null=True) - user_is_sender = models.BooleanField(u'пользователь - отправитель', default=False) + doc_reason = models.CharField('Основание', max_length=256, blank=True, default='') + fixes = models.BooleanField('Изменения', default=False) + avance = models.BooleanField('аванс', default=False) + currency = models.ForeignKey(Currency, verbose_name='валюта', null=True) + user_is_sender = models.BooleanField('пользователь - отправитель', default=False) sender = models.ForeignKey( Client, related_name='sender_fakturas', blank=True, null=True, - verbose_name=u'Отправитель' + verbose_name='Отправитель' ) receiver = models.ForeignKey( Client, related_name='receiver_fakturas', blank=True, null=True, - verbose_name=u'Получатель' + verbose_name='Получатель' ) plat_doc_num = models.CharField( 'Номер платёжного документа', @@ -36,7 +36,7 @@ class Faktura(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, Linke default='' ) plat_doc_date = models.DateField('Дата платёжного документа', blank=True, null=True) - fix_doc_num = models.PositiveIntegerField(u'Номер исправления', null=True, blank=True) + fix_doc_num = models.PositiveIntegerField('Номер исправления', null=True, blank=True) fix_doc_date = models.DateField('Дата исправления', blank=True, null=True) def get_consignor_and_address(self): @@ -44,24 +44,24 @@ class Faktura(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, Linke """ if self.user_is_sender: - return u'%s, %s' % (self.user.profile.get_company_name(), self.user.profile.address) + return f'{self.user.profile.get_company_name()}, {self.user.profile.address}' elif self.sender: - return '%s, %s' % (self.sender.name, self.sender.address) + return f'{self.sender.name}, {self.sender.address}' else: - return u'' + return '' def get_receiver_and_address(self): """Получатель и адрес """ if self.receiver: - return '%s, %s' % (self.receiver.name, self.receiver.address) + return f'{self.receiver.name}, {self.receiver.address}' else: - return u'' + return '' class Meta(BaseInvoiceModel.Meta): - verbose_name = u'Счёт-фактура' - verbose_name_plural = u'Счета-фактуры' - app_label="docs" + verbose_name = 'Счёт-фактура' + verbose_name_plural = 'Счета-фактуры' + app_label = "docs" class FakturaItem(BaseItemInvoiceModel): @@ -70,20 +70,20 @@ class FakturaItem(BaseItemInvoiceModel): 'Код единицы измерения', max_length=10, blank=True, - default=u'-' + default='-' ) parent = models.ForeignKey(Faktura, related_name='faktura_items') - country_code = models.CharField(u'Код страны', max_length=10, blank=True, default=u'-') - country_name = models.CharField(u'Название страны', max_length=256) - gtd = models.CharField(u'Основание', max_length=256, blank=True, default='') + country_code = models.CharField('Код страны', max_length=10, blank=True, default='-') + country_name = models.CharField('Название страны', max_length=256) + gtd = models.CharField('Основание', max_length=256, blank=True, default='') ntd = models.CharField( - u'Номер транспортной декларации', + 'Номер транспортной декларации', max_length=256, blank=True, default='' ) class Meta(BaseItemInvoiceModel.Meta): - verbose_name = u'Табл. часть фактуры' - verbose_name_plural = u'Табл. части фактур' + verbose_name = 'Табл. часть фактуры' + verbose_name_plural = 'Табл. части фактур' app_label = "docs" diff --git a/src/docs/models/invoice.py b/src/docs/models/invoice.py index fd8436a..d92edb8 100644 --- a/src/docs/models/invoice.py +++ b/src/docs/models/invoice.py @@ -16,17 +16,21 @@ class Invoice(BaseInvoiceModel, LinkedDocsMixin): PAID = 3 PAID_CHOICES = ( - (UNPAID, u'Нет'), - (PARTLY_PAID, u'Частично'), - (PAID, u'Да'), + (UNPAID, 'Нет'), + (PARTLY_PAID, 'Частично'), + (PAID, 'Да'), ) - paid_status = models.PositiveSmallIntegerField(u'Оплачен?', choices=PAID_CHOICES, default=UNPAID) - closed_status = models.BooleanField(u'Закрыт?', choices=consts.BOOL_CHOICES, default=False) + paid_status = models.PositiveSmallIntegerField( + 'Оплачен?', + choices=PAID_CHOICES, + default=UNPAID + ) + closed_status = models.BooleanField('Закрыт?', choices=consts.BOOL_CHOICES, default=False) class Meta(BaseInvoiceModel.Meta): - verbose_name = u'Счёт' - verbose_name_plural = u'Счета' + verbose_name = 'Счёт' + verbose_name_plural = 'Счета' def to_string_for_json(self): # Счёт №Х от ХХ.ХХ.ХХ, Х позиций, на сумму ХХ. @@ -53,5 +57,5 @@ class InvoiceItem(BaseItemInvoiceModel): parent = models.ForeignKey(Invoice, related_name='invoice_items') class Meta(BaseItemInvoiceModel.Meta): - verbose_name = u'Табл. часть счета' - verbose_name_plural = u'Табл. части счетов' + verbose_name = 'Табл. часть счета' + verbose_name_plural = 'Табл. части счетов' diff --git a/src/docs/models/linked_docs_mixin.py b/src/docs/models/linked_docs_mixin.py index 5023254..b356621 100644 --- a/src/docs/models/linked_docs_mixin.py +++ b/src/docs/models/linked_docs_mixin.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- from django.db import models -from django.core.exceptions import FieldError class LinkedDocsMixin(models.Model): @@ -14,7 +13,8 @@ class LinkedDocsMixin(models.Model): if getattr(self, '_cache_linked_docs', None) is None: self._cache_linked_docs = {} - model_name = self.__class__.__name__ # имя модели на инстансе которой вызвали метод linked_docs + # имя модели на инстансе которой вызвали метод linked_docs + model_name = self.__class__.__name__ if model_name == 'Invoice': invoice_id = self.id diff --git a/src/docs/models/mixins.py b/src/docs/models/mixins.py index fa332f2..681baea 100644 --- a/src/docs/models/mixins.py +++ b/src/docs/models/mixins.py @@ -6,8 +6,14 @@ from docs import consts class SignedStatusFieldMixin(models.Model): - """Mixin: добавляет поле `Подписан?`""" - signed_status = models.BooleanField(u'Подписан?', choices=consts.BOOL_CHOICES, default=False) + """ + Mixin: добавляет поле `Подписан?` + """ + signed_status = models.BooleanField( + 'Подписан?', + choices=consts.BOOL_CHOICES, + default=False + ) class Meta: abstract = True @@ -15,8 +21,15 @@ class SignedStatusFieldMixin(models.Model): class InvoiceFieldMixin(models.Model): """Mixin: добавляет FK поле `Создать по счёту`""" - invoice = models.ForeignKey(Invoice, related_name='+', verbose_name=u'Создать по счёту', blank=True, null=True, - default=None, on_delete=models.SET_NULL) + invoice = models.ForeignKey( + Invoice, + related_name='+', + verbose_name='Создать по счёту', + blank=True, + null=True, + default=None, + on_delete=models.SET_NULL + ) class Meta: abstract = True diff --git a/src/docs/models/nakladn.py b/src/docs/models/nakladn.py index cac670c..2cc21a2 100644 --- a/src/docs/models/nakladn.py +++ b/src/docs/models/nakladn.py @@ -8,19 +8,19 @@ from docs.models.linked_docs_mixin import LinkedDocsMixin class Nakladn(BaseInvoiceModel, SignedStatusFieldMixin, InvoiceFieldMixin, LinkedDocsMixin): """Накладная торг12.""" - doc_reason = models.CharField(u'Основание', max_length=256, blank=True, default='') + doc_reason = models.CharField('Основание', max_length=256, blank=True, default='') class Meta(BaseInvoiceModel.Meta): - verbose_name = u'Накладная' - verbose_name_plural = u'Накладные' + verbose_name = 'Накладная' + verbose_name_plural = 'Накладные' class NakladnItem(BaseItemInvoiceModel): """Табличная часть накладной торг12.""" parent = models.ForeignKey(Nakladn, related_name='nakladn_items') - units_kod = models.CharField(u'Код единицы измерения', max_length=20, blank=True, default=u'-') + units_kod = models.CharField('Код единицы измерения', max_length=20, blank=True, default='-') class Meta(BaseItemInvoiceModel.Meta): - verbose_name = u'Табл. часть накладной' - verbose_name_plural = u'Табл. части накладных' + verbose_name = 'Табл. часть накладной' + verbose_name_plural = 'Табл. части накладных' diff --git a/src/docs/models/platejka.py b/src/docs/models/platejka.py index 45ebfa8..173d64a 100644 --- a/src/docs/models/platejka.py +++ b/src/docs/models/platejka.py @@ -9,45 +9,68 @@ from docs import consts class Platejka(BaseModel): """Платёжное поручение.""" - platej_type = models.PositiveSmallIntegerField(u'Тип платёжного поручения', choices=consts.PLATEJ_TYPE_CHOICES, - default=consts.PLATEJ_TYPE_COMMERCE) + platej_type = models.PositiveSmallIntegerField( + 'Тип платёжного поручения', + choices=consts.PLATEJ_TYPE_CHOICES, + default=consts.PLATEJ_TYPE_COMMERCE + ) - bank_account = models.ForeignKey(BankAccount, related_name='+', verbose_name=u'Расчётный счёт') + bank_account = models.ForeignKey(BankAccount, related_name='+', verbose_name='Расчётный счёт') - doc_total = models.DecimalField(u'Сумма', max_digits=10, decimal_places=2) - payment_type = models.PositiveSmallIntegerField(u'Вид платежа', choices=consts.PAYMENT_TYPE_CHOICES, - default=consts.PAYMENT_TYPE_CHOICES[0][0]) - payment_order = models.CharField(u'Очерёдность платежа', max_length=10) - doc_info = models.TextField(u'Назначение платежа', max_length=1000) + doc_total = models.DecimalField('Сумма', max_digits=10, decimal_places=2) + payment_type = models.PositiveSmallIntegerField( + 'Вид платежа', + choices=consts.PAYMENT_TYPE_CHOICES, + default=consts.PAYMENT_TYPE_CHOICES[0][0] + ) + payment_order = models.CharField('Очерёдность платежа', max_length=10) + doc_info = models.TextField('Назначение платежа', max_length=1000) # поля только для перевода денег (коммерческое) - nds_value = models.PositiveSmallIntegerField(u'Ставка НДС', choices=consts.NDS_VALUE_CHOICES, default=consts.NDS_VALUE_0) + nds_value = models.PositiveSmallIntegerField( + 'Ставка НДС', + choices=consts.NDS_VALUE_CHOICES, + default=consts.NDS_VALUE_0 + ) # поля только для оплаты налогов (налоговое) - tax_status = models.CharField(u'Статус составителя', max_length=10, choices=consts.TAX_STATUS_CHOICES, - default=consts.TAX_STATUS_CHOICES[0][0]) - tax_base = models.CharField(u'Основание налогового платежа', max_length=10, choices=consts.TAX_BASE, - default=consts.TAX_BASE[0][0]) - tax_type = models.CharField(u'Тип налогового платежа', max_length=10, choices=consts.TAX_TYPE, - default=consts.TAX_TYPE[0][0]) - tax_num = models.CharField(u'Номер документа основания', max_length=50, blank=True, default='') - tax_date = models.DateField(u'Дата документа основания', blank=True, null=True) - tax_bk = models.CharField(u'Код БК доходов РФ', max_length=256) - tax_okato = models.CharField(u'Код ОКАТО сборщика платежей', max_length=256) - tax_period = models.CharField(u'Период, за который начисляется налог', max_length=256, - help_text = (u'Формат ввода периода платежей:
' - u'Месячный платёж - "МС.00.0000"
' - u'Квартальный платёж - "КВ.00.0000"
' - u'Полугодовой платёж - "ПЛ.00.0000"
' - u'Годовой платёж - "ГД.00.0000"
' - u'Платёж по дате - "дд.мм.гггг"') + tax_status = models.CharField( + 'Статус составителя', + max_length=10, + choices=consts.TAX_STATUS_CHOICES, + default=consts.TAX_STATUS_CHOICES[0][0] + ) + tax_base = models.CharField( + 'Основание налогового платежа', + max_length=10, + choices=consts.TAX_BASE, + default=consts.TAX_BASE[0][0] + ) + tax_type = models.CharField( + 'Тип налогового платежа', + max_length=10, + choices=consts.TAX_TYPE, + default=consts.TAX_TYPE[0][0] ) + tax_num = models.CharField('Номер документа основания', max_length=50, blank=True, default='') + tax_date = models.DateField('Дата документа основания', blank=True, null=True) + tax_bk = models.CharField('Код БК доходов РФ', max_length=256) + tax_okato = models.CharField('Код ОКАТО сборщика платежей', max_length=256) + tax_period = models.CharField('Период, за который начисляется налог', max_length=256, + help_text=('Формат ввода периода платежей:
' + 'Месячный платёж - "МС.00.0000"
' + 'Квартальный платёж - "КВ.00.0000"
' + 'Полугодовой платёж - "ПЛ.00.0000"
' + 'Годовой платёж - "ГД.00.0000"
' + 'Платёж по дате - "дд.мм.гггг"') + ) class Meta(BaseModel.Meta): - verbose_name = u'Платёжное поручение' - verbose_name_plural = u'Платёжные поручения' + verbose_name = 'Платёжное поручение' + verbose_name_plural = 'Платёжные поручения' - # хелперы, чтоб не оборачивать в шаблонах каждое обращение к определенным полям в проверку типа платежа + # хелперы, чтоб не оборачивать в шаблонах каждое обращение к + # определенным полям в проверку типа платежа def is_commerce(self): return self.platej_type == consts.PLATEJ_TYPE_COMMERCE @@ -59,46 +82,46 @@ class Platejka(BaseModel): """Налоги. Статус составителя, КОД.""" if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_status: return self.tax_status - return u'' + return '' def get_tax_base_kod(self): """Налоги. Основание налогового платежа, КОД.""" if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_base: return self.tax_base - return u'' + return '' def get_tax_type_kod(self): """Налоги. Тип налогового платежа, КОД.""" if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_type: return self.tax_type - return u'' + return '' def get_tax_num(self): """Налоги. Номер документа основания.""" if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_num: return self.tax_num - return u'' + return '' def get_tax_date(self): """Налоги. Дата документа основания.""" if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_date: return self.tax_date - return u'' + return '' def get_tax_bk(self): """Налоги. Код БК доходов РФ.""" if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_bk: return self.tax_bk - return u'' + return '' def get_tax_okato(self): """Налоги. Код ОКАТО сборщика платежей.""" if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_okato: return self.tax_okato - return u'' + return '' def get_tax_period(self): """Налоги. Период, за который начисляется налог.""" if self.platej_type == consts.PLATEJ_TYPE_TAX and self.tax_period: return self.tax_period - return u'' + return '' diff --git a/src/docs/tests.py b/src/docs/tests.py deleted file mode 100644 index 501deb7..0000000 --- a/src/docs/tests.py +++ /dev/null @@ -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) diff --git a/src/docs/urls.py b/src/docs/urls.py index 2a08638..d6e9147 100644 --- a/src/docs/urls.py +++ b/src/docs/urls.py @@ -1,13 +1,15 @@ # -*- coding: UTF-8 -*- -from django.conf.urls import * +from django.conf.urls import url -from docs.views import (InvoiceViews, AktRabotViews, AktSverkiViews, DoverViews, PlatejkaViews, NakladnViews, FakturaViews) -from docs.views import getview, index, get_invoices, get_tbl_items, get_client_by_invoice, toggle_doc_status +from docs.views import (InvoiceViews, AktRabotViews, AktSverkiViews, + DoverViews, PlatejkaViews, NakladnViews, FakturaViews) +from docs.views import (getview, index, get_invoices, get_tbl_items, + get_client_by_invoice, toggle_doc_status) - -urlpatterns = patterns('docs.views', - url(r'^$', index, name='docs_index'), # страница со ссылками на бух. формы -) +urlpatterns = [ + # страница со ссылками на бух. формы + url(r'^$', index, name='docs_index'), +] klasses = [ ('invoice', InvoiceViews), @@ -20,62 +22,83 @@ klasses = [ ] for name, klass in klasses: - urlpatterns += patterns('docs.views', + urlpatterns += [ + # список - url(r'^%s/$' % name, getview, {'klass': klass, 'oper': 'list',}, name='docs_%s_list' % name), + url(r'^%s/$' % name, getview, {'klass': klass, 'oper': 'list', }, + name='docs_%s_list' % name), # список, пагинация - url(r'^%s/page/(?P[0-9]+)/$' % name, getview, {'klass': klass, 'oper': 'list',}, + url(r'^%s/page/(?P[0-9]+)/$' % name, getview, + {'klass': klass, 'oper': 'list', }, name='docs_%s_list' % name), # добавить - url(r'^%s/add/$' % name, getview, {'klass': klass, 'oper': 'add',}, name='docs_%s_add' % name), + url(r'^%s/add/$' % name, getview, {'klass': klass, 'oper': 'add', }, + name='docs_%s_add' % name), # редактировать - url(r'^%s/(?P\d+)/edit/$' % name, getview, {'klass': klass, 'oper': 'edit',}, + url(r'^%s/(?P\d+)/edit/$' % name, getview, + {'klass': klass, 'oper': 'edit', }, name='docs_%s_edit' % name), # создать копию - url(r'^%s/(?P\d+)/copy/$' % name, getview, {'klass': klass, 'oper': 'copy',}, + url(r'^%s/(?P\d+)/copy/$' % name, getview, + {'klass': klass, 'oper': 'copy', }, name='docs_%s_copy' % name), # удалить - url(r'^%s/(?P\d+)/delete/$' % name, getview, {'klass': klass, 'oper': 'delete',}, + url(r'^%s/(?P\d+)/delete/$' % name, getview, + {'klass': klass, 'oper': 'delete', }, name='docs_%s_delete' % name), # сохранить в pdf - url(r'^%s/(?P\d+)/pdf/$' % name, getview, {'klass': klass, 'oper': 'as_pdf',}, + url(r'^%s/(?P\d+)/pdf/$' % name, getview, + {'klass': klass, 'oper': 'as_pdf', }, name='docs_%s_pdf' % name), # показать картинку - url(r'^%s/(?P\d+)/preview/$' % name, getview, {'klass': klass, 'oper': 'as_img',}, + url(r'^%s/(?P\d+)/preview/$' % name, getview, + {'klass': klass, 'oper': 'as_img', }, name='docs_%s_img' % name), # сохранить в excel - url(r'^%s/(?P\d+)/xls/$' % name, getview, {'klass': klass, 'oper': 'as_xls',}, + url(r'^%s/(?P\d+)/xls/$' % name, getview, + {'klass': klass, 'oper': 'as_xls', }, name='docs_%s_xls' % name), # отправить pdf/xls на email - url(r'^%s/(?P\d+)/email/$' % name, getview, {'klass': klass, 'oper': 'email',}, + url(r'^%s/(?P\d+)/email/$' % name, getview, + {'klass': klass, 'oper': 'email', }, name='docs_%s_email' % name), # поля документа - AJAX - url(r'^%s/(?P\d+)/get/ajax/$' % name, getview, {'klass': klass, 'oper': 'get_ajax',}, + url(r'^%s/(?P\d+)/get/ajax/$' % name, getview, + {'klass': klass, 'oper': 'get_ajax', }, name='docs_%s_get_ajax' % name), # отправить pdf/xls на email - AJAX - url(r'^%s/(?P\d+)/email/ajax/$' % name, getview, {'klass': klass, 'oper': 'email_ajax',}, + url(r'^%s/(?P\d+)/email/ajax/$' % name, getview, + {'klass': klass, 'oper': 'email_ajax', }, name='docs_%s_email_ajax' % name), url(r'^ajax_get_invoices/$', get_invoices, name='ajax_get_invoices'), - url(r'^ajax_get_invoices/(?P\d+)/$', get_invoices, name='ajax_get_invoices'), - url(r'^ajax_get_tbl_items/(?P\d+)/$', get_tbl_items, name='ajax_get_tbl_items'), - url(r'^ajax_get_client_by_invoice/(?P\d+)/$', get_client_by_invoice, name='ajax_get_client_by_invoice'), - url(r'^ajax_toggle_doc_status/(?P\w+)/(?P\d+)/(?P\w+)/$', toggle_doc_status, name='ajax_get_client_by_invoice'), - ) + url(r'^ajax_get_invoices/(?P\d+)/$', get_invoices, + name='ajax_get_invoices'), + url(r'^ajax_get_tbl_items/(?P\d+)/$', get_tbl_items, + name='ajax_get_tbl_items'), + url(r'^ajax_get_client_by_invoice/(?P\d+)/$', + get_client_by_invoice, name='ajax_get_client_by_invoice'), + url( + r'^ajax_toggle_doc_status/(?P\w+)/(?P\d+)/(?P\w+)/$', + toggle_doc_status, name='ajax_get_client_by_invoice'), + ] # доп. обработчики: создать Документ по Счету -urlpatterns += patterns('docs.views', +urlpatterns += [ # создать по Счету -> Акт вып. работ url(r'^%s/add/by/invoice/(?P\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\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\d+)/$' % 'faktura', getview, {'klass': FakturaViews, 'oper': 'add_by_invoice',}, + url(r'^%s/add/by/invoice/(?P\d+)/$' % 'faktura', getview, + {'klass': FakturaViews, 'oper': 'add_by_invoice', }, name='docs_%s_add_by_invoice' % 'faktura'), -) +] diff --git a/src/docs/utils.py b/src/docs/utils.py index dcfd423..097e1d2 100644 --- a/src/docs/utils.py +++ b/src/docs/utils.py @@ -28,7 +28,7 @@ def calc_clean_total_price(obj): def calc_total_nds(obj): """Считает сумму налога.""" total_price = obj.price * obj.qty - nds_rate = get_nds(obj.parent.nds_value)/100 + nds_rate = get_nds(obj.parent.nds_value) / 100 total_nds = total_price * nds_rate return total_nds @@ -52,7 +52,7 @@ def get_total_nds(obj): """Считает сумму налога.""" total_price = obj.price * obj.qty if obj.parent.nds_method: - nds_rate = get_nds(obj.parent.nds_value)/100 + nds_rate = get_nds(obj.parent.nds_value) / 100 total_nds = total_price * nds_rate else: nds_rate = get_nds(obj.parent.nds_value) / (100 + get_nds(obj.parent.nds_value)) diff --git a/src/docs/views/__init__.py b/src/docs/views/__init__.py index 22019e0..c6a3440 100644 --- a/src/docs/views/__init__.py +++ b/src/docs/views/__init__.py @@ -2,14 +2,15 @@ from django.shortcuts import render from django.contrib.auth.decorators import login_required -from docs.views.invoice import InvoiceViews -from docs.views.aktrabot import AktRabotViews -from docs.views.aktsverki import AktSverkiViews -from docs.views.dover import DoverViews -from docs.views.platejka import PlatejkaViews -from docs.views.nakladn import NakladnViews -from docs.views.faktura import FakturaViews -from docs.views.ajax import get_invoices, get_tbl_items, get_client_by_invoice, toggle_doc_status +from docs.views.invoice import InvoiceViews # noqa +from docs.views.aktrabot import AktRabotViews # noqa +from docs.views.aktsverki import AktSverkiViews # noqa +from docs.views.dover import DoverViews # noqa +from docs.views.platejka import PlatejkaViews # noqa +from docs.views.nakladn import NakladnViews # noqa +from docs.views.faktura import FakturaViews # noqa +from docs.views.ajax import (get_invoices, get_tbl_items, # noqa + get_client_by_invoice, toggle_doc_status) # noqa @login_required # важно!!! @@ -22,8 +23,6 @@ def getview(request, *args, **kwargs): return handler(request, *args, **kwargs) -# ----------------------------------------------------------------------------- - @login_required def index(request): """Страница со ссылками на все бух.формы.""" diff --git a/src/docs/views/base_views.py b/src/docs/views/base_views.py index ce153e8..aa47ca4 100644 --- a/src/docs/views/base_views.py +++ b/src/docs/views/base_views.py @@ -37,7 +37,6 @@ from customer.utils import raise_if_no_profile from django.conf import settings import traceback - DEBUG = getattr(settings, 'DEBUG', False) SUPPORT_EMAIL = getattr(settings, 'SUPPORT_EMAIL', '') MEDIA_ROOT = getattr(settings, 'MEDIA_ROOT', '') @@ -94,7 +93,7 @@ class BaseViews(object): # для генерации pdf/xls PDF_TEMPLATE = '' XLS_TEMPLATE = '' - FILENAME = u'Документ № %s, %s' # без расширения + FILENAME = u'Документ № %s, %s' # без расширения MAYBE_SIGNED = False # --- константы для вывода наименований в шаблонах @@ -128,13 +127,13 @@ class BaseViews(object): """Проверить объект класса на типичные ошибки.""" assert self.request is not None, \ (u"%s.request can't be None!" % self.__class__.__name__) - assert self.MODEL is not None,\ + assert self.MODEL is not None, \ (u"%s.MODEL can't be None!" % self.__class__.__name__) assert self.FORM_CLASS is not None, \ (u"%s.FORM_CLASS can't be None!" % self.__class__.__name__) - assert self.EMAIL_FORM_CLASS is not None,\ + assert self.EMAIL_FORM_CLASS is not None, \ (u"%s.EMAIL_FORM_CLASS can't be None!" % self.__class__.__name__) - assert (isinstance(self.ORDER_FIELDS, tuple) or isinstance(self.ORDER_FIELDS, list)),\ + assert (isinstance(self.ORDER_FIELDS, tuple) or isinstance(self.ORDER_FIELDS, list)), \ (u"%s.ORDER_FIELDS should be of tuple or list type!" % self.__class__.__name__) assert self.FILTERSET_CLASS is not None, \ (u"%s.FILTERSET_CLASS can't be None!" % self.__class__.__name__) @@ -149,7 +148,7 @@ class BaseViews(object): def get_ordering(self): """Поле и порядок сортировки.""" - order_field, order_type = 'doc_date', 'desc' # default + order_field, order_type = 'doc_date', 'desc' # default params = dict(self.request.GET.items()) if params.get(ORDER_VAR) in self.ORDER_FIELDS: order_field = params.get(ORDER_VAR) @@ -248,7 +247,7 @@ class BaseViews(object): def init_form(self): """Начальные значения полей формы документа.""" - initial = {'doc_date': datetime.now(),} + initial = {'doc_date': datetime.now(), } # номер нового документа doc_num = self.MODEL.objects.get_max_doc_num(self.request.user) or 0 initial['doc_num'] = doc_num + 1 @@ -322,7 +321,7 @@ class BaseViews(object): data=self.request.POST, instance=obj) if form.is_valid(): - new_obj = form.save() + form.save() return redirect(self.REDIRECT_AFTER_EDIT) else: form = self.FORM_CLASS(self.request.user, instance=obj) @@ -381,7 +380,7 @@ class BaseViews(object): c1 = time() pdf = render_pdf_to_string(self.request, self.PDF_TEMPLATE, params) if DEBUG: - print('%s generation time (seconds): %s' % (self.PDF_TEMPLATE, time()-c1,)) + print('%s generation time (seconds): %s' % (self.PDF_TEMPLATE, time() - c1,)) return pdf def get_xls(self, *args, **kwargs): @@ -399,7 +398,7 @@ class BaseViews(object): c1 = time() xls = render_xls_to_string(self.request, self.XLS_TEMPLATE, params) if DEBUG: - print('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time()-c1,)) + print('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time() - c1,)) return xls def as_img(self, *args, **kwargs): @@ -454,15 +453,15 @@ class BaseViews(object): imgs.sort() email_form = self.EMAIL_FORM_CLASS() dictionary = { - 'obj': obj, - 'images': imgs, - 'padeji': self.PADEJI, - 'padeji_mnoj': self.PADEJI_MNOJ, - 'url_prefix': self.URL_PREFIX, - 'template_create_docs': self.TEMPLATE_CREATE_DOCS, - 'template_linked_docs_list': self.TEMPLATE_LINKED_DOCS_LIST, - 'email_form': email_form, - 'maybe_sign': self.MAYBE_SIGNED, + 'obj': obj, + 'images': imgs, + 'padeji': self.PADEJI, + 'padeji_mnoj': self.PADEJI_MNOJ, + 'url_prefix': self.URL_PREFIX, + 'template_create_docs': self.TEMPLATE_CREATE_DOCS, + 'template_linked_docs_list': self.TEMPLATE_LINKED_DOCS_LIST, + 'email_form': email_form, + 'maybe_sign': self.MAYBE_SIGNED, } return render(self.request, self.TEMPLATE_IMG, dictionary) except: @@ -500,7 +499,7 @@ class BaseViews(object): def send_email(self, subject, to, body, files, sign_doc): """Отправка письма.""" - dict_context = {'body': body, 'support_email': SUPPORT_EMAIL,} + dict_context = {'body': body, 'support_email': SUPPORT_EMAIL} email_body = render_to_string(self.EMAIL_MSG_TEMPLATE, dict_context) attachments = [] @@ -595,8 +594,8 @@ class BaseViews(object): data = { 'success': form.is_valid(), - 'field_errors': form.errors, # ошибки полей - 'form_errors': non_field_errors, # ошибки формы + 'field_errors': form.errors, # ошибки полей + 'form_errors': non_field_errors, # ошибки формы } if form.is_valid() and result: data['message'] = {'title': 'Инфо', 'msg': 'Письмо отправлено.'} @@ -611,6 +610,7 @@ class BaseViews(object): data = json.dumps(obj, default=dthandler()) return HttpResponse(data, content_type='application/json') + # ----------------------------------------------------------------------------- @@ -639,9 +639,9 @@ class BaseItemsViews(BaseViews): def set_item_formset_class(self, extra_count=2): """Класс FormSet-а для табличной части документа.""" self.ITEM_FORMSET_CLASS = inlineformset_factory( - parent_model = self.MODEL, - model = self.ITEM_MODEL, - form = self.ITEM_FORM_CLASS, + parent_model=self.MODEL, + model=self.ITEM_MODEL, + form=self.ITEM_FORM_CLASS, extra=extra_count, can_delete=True, ) @@ -863,7 +863,7 @@ class BaseItemsViews(BaseViews): c1 = time() pdf = render_pdf_to_string(self.request, self.PDF_TEMPLATE, params) if DEBUG: - print('%s generation time (seconds): %s' % (self.PDF_TEMPLATE, time()-c1,)) + print('%s generation time (seconds): %s' % (self.PDF_TEMPLATE, time() - c1,)) return pdf def get_xls(self, *args, **kwargs): @@ -882,5 +882,5 @@ class BaseItemsViews(BaseViews): c1 = time() xls = render_xls_to_string(self.request, self.XLS_TEMPLATE, params) if DEBUG: - print('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time()-c1,)) + print('%s generation time (seconds): %s' % (self.XLS_TEMPLATE, time() - c1,)) return xls diff --git a/src/docs/views/dover.py b/src/docs/views/dover.py index a10e996..e4d54f9 100644 --- a/src/docs/views/dover.py +++ b/src/docs/views/dover.py @@ -61,7 +61,10 @@ class DoverViews(BaseItemsViews): } def update_list_dict(self, dictionary): - """Здесь можно изменить словарь параметров перед передачей его в шаблон вывода списка документов.""" + """ + Здесь можно изменить словарь параметров перед передачей + его в шаблон вывода списка документов. + """ dictionary['clients_form'] = ClientsListForm(self.request.user) def init_form(self): diff --git a/src/docs/views/invoice.py b/src/docs/views/invoice.py index 0dcb1f2..f804718 100644 --- a/src/docs/views/invoice.py +++ b/src/docs/views/invoice.py @@ -22,7 +22,8 @@ class InvoiceViews(BaseItemsViews): ITEM_FORM_CLASS = InvoiceItemForm # форма табличной части документа ITEM_FORM_PREFIX = 'invoice_items' # префикс формы табличной части - ORDER_FIELDS = ('doc_date', 'doc_num', 'client__name', 'doc_sum', 'paid_status', 'closed_status') + ORDER_FIELDS = ( + 'doc_date', 'doc_num', 'client__name', 'doc_sum', 'paid_status', 'closed_status') FILTERSET_CLASS = InvoiceFilterSet # фильтры @@ -45,26 +46,26 @@ class InvoiceViews(BaseItemsViews): # для генерации pdf/xls PDF_TEMPLATE = 'docs/invoice/as_pdf.html' XLS_TEMPLATE = 'invoice.xls' - FILENAME = u'Счет № %s, %s' # без расширения + FILENAME = u'Счет № %s, %s' # без расширения MAYBE_SIGNED = True # --- грамматика для вывода наименований в шаблонах PADEJI = { - 'imenit': u'счёт', # кто? что? - 'rodit': u'счёта', # кого? чего? - 'dateln': u'счёту', # кому? чему? - 'vinit': u'счёт', # кого? что? - 'tvorit': u'счётом', # кем? чем? - 'predlojn': u'счёте', # о ком? о чём? + 'imenit': u'счёт', # кто? что? + 'rodit': u'счёта', # кого? чего? + 'dateln': u'счёту', # кому? чему? + 'vinit': u'счёт', # кого? что? + 'tvorit': u'счётом', # кем? чем? + 'predlojn': u'счёте', # о ком? о чём? } PADEJI_MNOJ = { - 'imenit': u'счета', # кто? что? - 'rodit': u'счетов', # кого? чего? - 'dateln': u'счетам', # кому? чему? - 'vinit': u'счета', # кого? что? - 'tvorit': u'счетами', # кем? чем? - 'predlojn': u'счетах', # о ком? о чём? + 'imenit': u'счета', # кто? что? + 'rodit': u'счетов', # кого? чего? + 'dateln': u'счетам', # кому? чему? + 'vinit': u'счета', # кого? что? + 'tvorit': u'счетами', # кем? чем? + 'predlojn': u'счетах', # о ком? о чём? } def update_list_dict(self, dictionary): diff --git a/src/docs/views/nakladn.py b/src/docs/views/nakladn.py index 6d22bae..92b1ecd 100644 --- a/src/docs/views/nakladn.py +++ b/src/docs/views/nakladn.py @@ -48,26 +48,26 @@ class NakladnViews(BaseItemsViews, AddByInvoiceMethodMixin): # для генерации pdf/xls PDF_TEMPLATE = 'docs/nakladn/as_pdf.html' XLS_TEMPLATE = 'nakladn.xls' - FILENAME = u'Накладная № %s, %s' # без расширения + FILENAME = u'Накладная № %s, %s' # без расширения MAYBE_SIGNED = True # --- грамматика для вывода наименований в шаблонах PADEJI = { - 'imenit': u'накладная', # кто? что? - 'rodit': u'накладной', # кого? чего? - 'dateln': u'накладной', # кому? чему? - 'vinit': u'накладную', # кого? что? - 'tvorit': u'накладной', # кем? чем? - 'predlojn': u'накладной', # о ком? о чём? + 'imenit': u'накладная', # кто? что? + 'rodit': u'накладной', # кого? чего? + 'dateln': u'накладной', # кому? чему? + 'vinit': u'накладную', # кого? что? + 'tvorit': u'накладной', # кем? чем? + 'predlojn': u'накладной', # о ком? о чём? } PADEJI_MNOJ = { - 'imenit': u'накладные', # кто? что? - 'rodit': u'накладных', # кого? чего? - 'dateln': u'накладным', # кому? чему? - 'vinit': u'накладные', # кого? что? - 'tvorit': u'накладными', # кем? чем? - 'predlojn': u'накладных', # о ком? о чём? + 'imenit': u'накладные', # кто? что? + 'rodit': u'накладных', # кого? чего? + 'dateln': u'накладным', # кому? чему? + 'vinit': u'накладные', # кого? что? + 'tvorit': u'накладными', # кем? чем? + 'predlojn': u'накладных', # о ком? о чём? } def prepare(self, obj, obj_items, export_to=None): @@ -132,12 +132,12 @@ class NakladnViews(BaseItemsViews, AddByInvoiceMethodMixin): name_rows = max(1, len(name.split('\n'))) + 1 # строка, подитог и итог не помещаются на странице if (curr_rows + name_rows + tbl_page_footer_rows + - tbl_footer_rows > page_rows): + tbl_footer_rows > page_rows): if idx == 0: item.pdf_pagebreak_before = True prev_item = item else: - prev_item = obj_items[idx-1] + prev_item = obj_items[idx - 1] prev_item.pdf_pagebreak_after = True prev_item.pdf_page_footer = True diff --git a/src/docs/views/platejka.py b/src/docs/views/platejka.py index bebd34f..949aaa0 100644 --- a/src/docs/views/platejka.py +++ b/src/docs/views/platejka.py @@ -11,13 +11,13 @@ from .base_views import BaseViews class PlatejkaViews(BaseViews): """Views для платежных поручений.""" - MODEL = Platejka # модель документа - FORM_CLASS = PlatejkaForm # форма документа + MODEL = Platejka # модель документа + FORM_CLASS = PlatejkaForm # форма документа # поля, по которым можно сортировать список документов ORDER_FIELDS = ('doc_date', 'doc_num', 'doc_info', 'doc_total',) - FILTERSET_CLASS = PlatejkaFilterSet # фильтры + FILTERSET_CLASS = PlatejkaFilterSet # фильтры # префикс именованных урлов этого типа документов, для передачи в шаблон URL_PREFIX = 'docs_platejka_' @@ -34,27 +34,30 @@ class PlatejkaViews(BaseViews): # для генерации pdf/xls PDF_TEMPLATE = 'docs/platejka/as_pdf.html' XLS_TEMPLATE = 'platejka.xls' - FILENAME = u'Платежное поручение № %s, %s' # без расширения + FILENAME = u'Платежное поручение № %s, %s' # без расширения # --- грамматика для вывода наименований в шаблонах PADEJI = { - 'imenit': u'платёжное поручение', # кто? что? - 'rodit': u'платёжного поручения', # кого? чего? - 'dateln': u'платёжному поручению', # кому? чему? - 'vinit': u'платёжное поручение', # кого? что? - 'tvorit': u'платёжным поручением', # кем? чем? - 'predlojn': u'платёжном поручении', # о ком? о чём? + 'imenit': u'платёжное поручение', # кто? что? + 'rodit': u'платёжного поручения', # кого? чего? + 'dateln': u'платёжному поручению', # кому? чему? + 'vinit': u'платёжное поручение', # кого? что? + 'tvorit': u'платёжным поручением', # кем? чем? + 'predlojn': u'платёжном поручении', # о ком? о чём? } PADEJI_MNOJ = { - 'imenit': u'платёжные поручения', # кто? что? - 'rodit': u'платёжных поручений', # кого? чего? - 'dateln': u'платёжным поручениям', # кому? чему? - 'vinit': u'платёжные поручения', # кого? что? - 'tvorit': u'платёжными поручениями', # кем? чем? - 'predlojn': u'платёжных поручениях', # о ком? о чём? + 'imenit': u'платёжные поручения', # кто? что? + 'rodit': u'платёжных поручений', # кого? чего? + 'dateln': u'платёжным поручениям', # кому? чему? + 'vinit': u'платёжные поручения', # кого? что? + 'tvorit': u'платёжными поручениями', # кем? чем? + 'predlojn': u'платёжных поручениях', # о ком? о чём? } def update_list_dict(self, dictionary): - """Здесь можно изменить словарь параметров перед передачей его в шаблон вывода списка документов.""" + """ + Здесь можно изменить словарь параметров перед передачей + его в шаблон вывода списка документов. + """ dictionary['dadata_api_key'] = settings.DADATA_API_KEY diff --git a/src/dokumentor/__init__.py b/src/dokumentor/__init__.py index 05aea32..1612c31 100644 --- a/src/dokumentor/__init__.py +++ b/src/dokumentor/__init__.py @@ -12,6 +12,6 @@ env.load(env_file) # This will make sure the app is always imported when # Django starts so that shared_task will use this app. try: - from .celery import app as celery_app + from .celery import app as celery_app # noqa except ImportError as e: warnings.warn('Celery import error, is it installed?') diff --git a/src/dokumentor/celery.py b/src/dokumentor/celery.py index 9989278..207230d 100644 --- a/src/dokumentor/celery.py +++ b/src/dokumentor/celery.py @@ -1,7 +1,7 @@ # coding: utf-8 from celery import Celery -from django.conf import settings +from django.conf import settings # noqa app = Celery('dokumentor') app.config_from_object('django.conf:settings', namespace='CELERY') diff --git a/src/dokumentor/settings/common.py b/src/dokumentor/settings/common.py index 7a7e06c..4819554 100644 --- a/src/dokumentor/settings/common.py +++ b/src/dokumentor/settings/common.py @@ -1,3 +1,4 @@ +# flake8: noqa # -*- coding: utf-8 -*- import os @@ -150,7 +151,7 @@ INSTALLED_APPS = [ # 'cmsplugin_filer_folder', # 'cmsplugin_filer_link', # 'cmsplugin_filer_image', - # 'cmsplugin_filer_teaser' , + # 'cmsplugin_filer_teaser', # 'cmsplugin_filer_video', 'captcha', diff --git a/src/dokumentor/settings/local.py b/src/dokumentor/settings/local.py index 494bcbb..f694048 100644 --- a/src/dokumentor/settings/local.py +++ b/src/dokumentor/settings/local.py @@ -1,3 +1,4 @@ +# flake8: noqa # -*- coding: utf-8 -*- import dj_database_url diff --git a/src/dokumentor/settings/production.py b/src/dokumentor/settings/production.py index aac19d3..f6a0cae 100644 --- a/src/dokumentor/settings/production.py +++ b/src/dokumentor/settings/production.py @@ -1,8 +1,9 @@ +# flake8: noqa # coding: utf-8 import dj_database_url -from src.dokumentor.settings.common import * # noqa +from src.dokumentor.settings.common import * DEBUG = False TEMPLATES[0]['OPTIONS']['debug'] = DEBUG diff --git a/src/dokumentor/settings/stage.py b/src/dokumentor/settings/stage.py index c67c516..38c29be 100644 --- a/src/dokumentor/settings/stage.py +++ b/src/dokumentor/settings/stage.py @@ -1,8 +1,9 @@ +# flake8: noqa # coding: utf-8 import dj_database_url -from src.dokumentor.settings.common import * # noqa +from src.dokumentor.settings.common import * DEBUG = False TEMPLATES[0]['OPTIONS']['debug'] = DEBUG diff --git a/src/dokumentor/settings/testing.py b/src/dokumentor/settings/testing.py index 17d4c3c..b366464 100644 --- a/src/dokumentor/settings/testing.py +++ b/src/dokumentor/settings/testing.py @@ -1,4 +1,6 @@ +# flake8: noqa # -*- coding: utf-8 -*- + import logging import dj_database_url diff --git a/src/dokumentor/urls.py b/src/dokumentor/urls.py index 15c141e..7b4d808 100644 --- a/src/dokumentor/urls.py +++ b/src/dokumentor/urls.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- from django.conf import settings -from django.contrib import admin -from django.conf.urls import patterns, include, url +from django.conf.urls import include, url import autocomplete_light from django.conf.urls.static import static @@ -14,9 +13,7 @@ admin.site.site_header = 'Документор' admin.site.index_title = 'Документор' admin.site.site_title = 'Документор' -urlpatterns = patterns('', - url(r'^admin/doc/', include('django.contrib.admindocs.urls')), - +urlpatterns = [ # Uncomment the next line to enable the admin: url(r'^admin/', include(admin.site.urls)), url(r'autocomplete/', include('autocomplete_light.urls')), @@ -30,16 +27,10 @@ urlpatterns = patterns('', url(r'^captcha/', include('captcha.urls')), url(r'^yandex-money/', include('yandex_money.urls')), url(r'^', include('cms.urls')), -) - +] if settings.DEBUG: - urlpatterns.extend( - static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + - static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) - ) - import debug_toolbar - urlpatterns = [ - url(r'^__debug__/', include(debug_toolbar.urls)), - ] + urlpatterns + urlpatterns += [url(r'^__debug__/', include(debug_toolbar.urls))] + urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/src/dokumentor/wsgi.py b/src/dokumentor/wsgi.py index 88f5bbd..e010a64 100644 --- a/src/dokumentor/wsgi.py +++ b/src/dokumentor/wsgi.py @@ -1,6 +1,6 @@ import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dokumentor.settings") -from django.core.wsgi import get_wsgi_application +from django.core.wsgi import get_wsgi_application # noqa application = get_wsgi_application() diff --git a/src/myauth/admin.py b/src/myauth/admin.py index 9ad9a34..ef0a788 100644 --- a/src/myauth/admin.py +++ b/src/myauth/admin.py @@ -24,7 +24,7 @@ class CustomUserAdmin(UserAdmin): (None, { 'classes': ('wide',), 'fields': ('username', 'email', 'password1', 'password2')} - ), + ), ) form = CustomUserChangeForm add_form = CustomUserCreationForm @@ -32,5 +32,6 @@ class CustomUserAdmin(UserAdmin): search_fields = ('username', 'email', 'first_name', 'last_name') ordering = ('email',) + admin.site.register(DokUser, CustomUserAdmin) admin.site.register(ConfirmEmail) diff --git a/src/myauth/apps.py b/src/myauth/apps.py index 428e0d7..1c6978c 100644 --- a/src/myauth/apps.py +++ b/src/myauth/apps.py @@ -5,5 +5,3 @@ from django.apps import AppConfig class MyAuthConfig(AppConfig): name = 'myauth' verbose_name = 'Авторизация' - - diff --git a/src/myauth/forms.py b/src/myauth/forms.py index 7ac4570..7b2fcee 100644 --- a/src/myauth/forms.py +++ b/src/myauth/forms.py @@ -11,37 +11,47 @@ from customer import consts as customer_consts from myauth.models import DokUser - PASSWORD_MIN_LEN = getattr(settings, 'PASSWORD_MIN_LEN ', 7) PROFILE_CHOICES = ( - (customer_consts.IP_PROFILE, u'Индивидуальный предприниматель (ИП)'), - (customer_consts.ORG_PROFILE, u'Организация (ООО, ЗАО, ОАО, НКО и т.п.)'), + (customer_consts.IP_PROFILE, 'Индивидуальный предприниматель (ИП)'), + (customer_consts.ORG_PROFILE, 'Организация (ООО, ЗАО, ОАО, НКО и т.п.)'), ) class RegistrationForm(forms.Form): """Форма регистрации нового пользователя.""" - email = forms.EmailField(label=u'Укажите e-mail', max_length=75, error_messages={'invalid': u'Неверный формат e-mail.',}, - help_text=u'На него будет выслано письмо с подтверждением.') - - password1 = forms.CharField(label=u'Введите пароль', min_length=PASSWORD_MIN_LEN, widget=forms.PasswordInput, - error_messages={'min_length': u'Не менее %s символов.' % PASSWORD_MIN_LEN,}, - help_text=u'Не менее %s символов.' % PASSWORD_MIN_LEN) - - password2 = forms.CharField(label=u'Повтор пароля', widget=forms.PasswordInput) - - profile_type = forms.ChoiceField(label=u'Тип регистрации', choices=PROFILE_CHOICES, widget=forms.RadioSelect, - error_messages={'required': u'Нужно указать форму собственности вашего бизнеса.',}) + email = forms.EmailField( + label='Укажите e-mail', + max_length=75, + error_messages={'invalid': 'Неверный формат e-mail.'}, + help_text='На него будет выслано письмо с подтверждением.' + ) + + password1 = forms.CharField( + label='Введите пароль', + min_length=PASSWORD_MIN_LEN, + widget=forms.PasswordInput, + error_messages={'min_length': f'Не менее {PASSWORD_MIN_LEN} символов.'}, + help_text=f'Не менее {PASSWORD_MIN_LEN} символов.' + ) + password2 = forms.CharField(label='Повтор пароля', widget=forms.PasswordInput) + + profile_type = forms.ChoiceField( + label='Тип регистрации', + choices=PROFILE_CHOICES, + widget=forms.RadioSelect, + error_messages={'required': 'Нужно указать форму собственности вашего бизнеса.'} + ) def clean_email(self): """Проверить не занят ли email.""" email = self.cleaned_data['email'] try: - DokUser.objects.get(email__iexact = email) + DokUser.objects.get(email__iexact=email) except DokUser.DoesNotExist: return email - raise forms.ValidationError(u'Такой e-mail уже зарегистрирован.') + raise forms.ValidationError('Такой e-mail уже зарегистрирован.') def clean(self): super(RegistrationForm, self).clean() @@ -50,36 +60,40 @@ class RegistrationForm(forms.Form): # проверить чтобы оба пароля совпадали if password1 and password2: if password1 != password2: - set_field_error(self, 'password2', u'Пароли не совпадают.') + set_field_error(self, 'password2', 'Пароли не совпадают.') return self.cleaned_data class ResetPasswordForm(forms.Form): """Форма восстановления пароля.""" - email = forms.EmailField(label=u'Ваш e-mail', max_length=75, - error_messages={'invalid': u'Неверный формат e-mail.', 'required': u'Введите свой e-mail.',}) + email = forms.EmailField( + label='Ваш e-mail', + max_length=75, + error_messages={'invalid': 'Неверный формат e-mail.', 'required': 'Введите свой e-mail.'} + ) def __init__(self, *args, **kwargs): super(ResetPasswordForm, self).__init__(*args, **kwargs) - self.user_cache = None # кешировать юзера в форме, чтобы повторно не ходить в базу из вьюхи + # кешировать юзера в форме, чтобы повторно не ходить в базу из вьюхи + self.user_cache = None def clean_email(self): """Проверить зарегистрирован ли email.""" email = self.cleaned_data['email'] try: - DokUser.objects.get(email__iexact = email) + DokUser.objects.get(email__iexact=email) return email except DokUser.DoesNotExist: - raise forms.ValidationError(u'Такой e-mail не зарегистрирован.') + raise forms.ValidationError('Такой e-mail не зарегистрирован.') def clean(self): super(ResetPasswordForm, self).clean() email = self.cleaned_data.get('email') if email: - self.user_cache = DokUser.objects.get(email__iexact = email) + self.user_cache = DokUser.objects.get(email__iexact=email) if self.user_cache: if not self.user_cache.is_active: - raise forms.ValidationError(u'Пользователь заблокирован.') + raise forms.ValidationError('Пользователь заблокирован.') return self.cleaned_data def get_user(self): @@ -88,13 +102,17 @@ class ResetPasswordForm(forms.Form): class ChangePasswordForm(forms.Form): """Форма изменения пароля.""" - old_password = forms.CharField(label=u'Ваш пароль', widget=forms.PasswordInput) + old_password = forms.CharField(label='Ваш пароль', widget=forms.PasswordInput) - password1 = forms.CharField(label=u'Новый пароль', min_length=PASSWORD_MIN_LEN, widget=forms.PasswordInput, - error_messages={'min_length': u'Не менее %s символов.' % PASSWORD_MIN_LEN,}, - help_text=u'Не менее %s символов.' % PASSWORD_MIN_LEN) + password1 = forms.CharField( + label='Новый пароль', + min_length=PASSWORD_MIN_LEN, + widget=forms.PasswordInput, + error_messages={'min_length': f'Не менее {PASSWORD_MIN_LEN} символов.'}, + help_text=f'Не менее {PASSWORD_MIN_LEN} символов.' + ) - password2 = forms.CharField(label=u'Повторите', widget=forms.PasswordInput) + password2 = forms.CharField(label='Повторите', widget=forms.PasswordInput) def __init__(self, user, *args, **kwargs): super(ChangePasswordForm, self).__init__(*args, **kwargs) @@ -104,7 +122,7 @@ class ChangePasswordForm(forms.Form): """Проверить старый пароль.""" old_password = self.cleaned_data.get('old_password') if old_password and not self._user.check_password(old_password): - raise forms.ValidationError(u'Неверный пароль.') + raise forms.ValidationError('Неверный пароль.') return old_password def clean(self): @@ -114,16 +132,19 @@ class ChangePasswordForm(forms.Form): # проверить чтобы оба новых пароля совпадали if password1 and password2: if password1 != password2: - set_field_error(self, 'password2', u'Пароли не совпадают.') + set_field_error(self, 'password2', 'Пароли не совпадают.') return self.cleaned_data class ChangeEmailForm(forms.Form): """Форма изменения e-mail.""" - password = forms.CharField(label=u'Ваш пароль', widget=forms.PasswordInput) + password = forms.CharField(label='Ваш пароль', widget=forms.PasswordInput) - email = forms.EmailField(label=u'Новый e-mail', max_length=75, - error_messages={'invalid': u'Неверный формат e-mail.', 'required': u'Введите свой e-mail.',}) + email = forms.EmailField( + label='Новый e-mail', + max_length=75, + error_messages={'invalid': 'Неверный формат e-mail.', 'required': 'Введите свой e-mail.'} + ) def __init__(self, user, *args, **kwargs): super(ChangeEmailForm, self).__init__(*args, **kwargs) @@ -133,30 +154,31 @@ class ChangeEmailForm(forms.Form): """Проверить пароль.""" password = self.cleaned_data.get('password') if password and not self._user.check_password(password): - raise forms.ValidationError(u'Неверный пароль.') + raise forms.ValidationError('Неверный пароль.') return password def clean_email(self): """Проверить не зарегистрирован ли email.""" email = self.cleaned_data['email'] try: - DokUser.objects.get(email__iexact = email) - raise forms.ValidationError(u'Такой e-mail уже зарегистрирован.') + DokUser.objects.get(email__iexact=email) + raise forms.ValidationError('Такой e-mail уже зарегистрирован.') except DokUser.DoesNotExist: return email class LoginForm(forms.Form): """Форма логина.""" - email = forms.EmailField(label=u'Укажите e-mail', max_length=75) - password = forms.CharField(label=u'Введите пароль', widget=forms.PasswordInput) - reset_old_login = forms.BooleanField(label=u'Сбросить старый вход', required=False) + email = forms.EmailField(label='Укажите e-mail', max_length=75) + password = forms.CharField(label='Введите пароль', widget=forms.PasswordInput) + reset_old_login = forms.BooleanField(label='Сбросить старый вход', required=False) # TODO капча на случай если пароль не ввели правильно с первого раза def __init__(self, *args, **kwargs): super(LoginForm, self).__init__(*args, **kwargs) - self.user_cache = None # кешировать юзера в форме, чтобы повторно не лазить в базу из вьюхи + # кешировать юзера в форме, чтобы повторно не лазить в базу из вьюхи + self.user_cache = None def clean(self): super(LoginForm, self).clean() @@ -165,19 +187,26 @@ class LoginForm(forms.Form): reset_old_login = self.cleaned_data.get('reset_old_login') if email and password: try: - username = DokUser.objects.get(email__iexact = email).username - self.user_cache = authenticate(username = username, password = password) + username = DokUser.objects.get(email__iexact=email).username + self.user_cache = authenticate(username=username, password=password) if self.user_cache: if not self.user_cache.is_active: - set_field_error(self, 'email', u'Пользователь заблокирован.') + set_field_error(self, 'email', 'Пользователь заблокирован.') if not self.user_cache.profile.confirmed: - set_field_error(self, 'email', u'Для подтверждения адреса электронной почты перейдите по адресу, указанному в письме. Если вы не получили письмо с активацией, попробуйте зарегистрироваться ещё раз или укажите другой адрес электронной почты.') + msg = "Для подтверждения адреса электронной почты перейдите по адресу," \ + "указанному в письме. Если вы не получили письмо с активацией, " \ + "попробуйте зарегистрироваться ещё раз или укажите другой " \ + "адрес электронной почты." + + set_field_error(self, 'email', msg) if self.user_cache.profile.user_session_key and not reset_old_login: - set_field_error(self, 'email', u'Пользователь уже вошёл в систему. Установите флаг "Сбросить старый вход", чтобы войти.') + msg = "Пользователь уже вошёл в систему. Установите флаг " \ + "'Сбросить старый вход', чтобы войти." + set_field_error(self, 'email', msg) else: - set_field_error(self, 'password', u'Неверное сочетание e-mail / пароль.') + set_field_error(self, 'password', 'Неверное сочетание e-mail / пароль.') except DokUser.DoesNotExist: - set_field_error(self, 'email', u'Такой e-mail не зарегистрирован.') + set_field_error(self, 'email', 'Такой e-mail не зарегистрирован.') return self.cleaned_data def get_user(self): @@ -185,7 +214,7 @@ class LoginForm(forms.Form): class CaptchedLoginForm(LoginForm): - captcha = CaptchaField(label=u'Введите код с картинки') + captcha = CaptchaField(label='Введите код с картинки') class CustomUserCreationForm(UserCreationForm): @@ -193,6 +222,7 @@ class CustomUserCreationForm(UserCreationForm): A form that creates a user, with no privileges, from the given email and password. """ + def clean_username(self): # Since User.username is unique, this check is redundant, # but it sets a nicer error message than the ORM. See #13147. @@ -207,8 +237,8 @@ class CustomUserCreationForm(UserCreationForm): model = DokUser fields = ("username", "email",) + class CustomUserChangeForm(UserChangeForm): class Meta: model = DokUser fields = '__all__' - diff --git a/src/myauth/managers.py b/src/myauth/managers.py index 5ce5708..4e9bc45 100644 --- a/src/myauth/managers.py +++ b/src/myauth/managers.py @@ -29,21 +29,21 @@ class ResetKeyManager(models.Manager): def create_key(self, user): """Создает или обновляет ключ восстановления пароля.""" key = hashlib.sha1('%s' % random()).hexdigest() - reset_key, created = self.get_or_create(user=user, defaults={'key': key,}) + reset_key, created = self.get_or_create(user=user, defaults={'key': key}) if not created: - reset_key.key = key # обновить ключ + reset_key.key = key # обновить ключ reset_key.save() return reset_key class CustomUserManager(BaseUserManager): def _create_user(self, username, email, password, - is_staff, is_superuser, **extra_fields): + is_staff, is_superuser, **extra_fields): """ Creates and saves a User with the given email and password. """ now = timezone.now() - if not email : + if not email: raise ValueError('The given email must be set') email = self.normalize_email(email) user = self.model(email=email, @@ -56,9 +56,7 @@ class CustomUserManager(BaseUserManager): return user def create_user(self, username, email, password=None, **extra_fields): - return self._create_user(username, email, password, False, False, - **extra_fields ) + return self._create_user(username, email, password, False, False, **extra_fields) def create_superuser(self, username, email, password, **extra_fields): - return self._create_user(username, email, password, True, True, - **extra_fields) + return self._create_user(username, email, password, True, True, **extra_fields) diff --git a/src/myauth/models.py b/src/myauth/models.py index 90c0d4f..83e24bc 100644 --- a/src/myauth/models.py +++ b/src/myauth/models.py @@ -42,13 +42,13 @@ class DokUser(AbstractBaseUser, PermissionsMixin): verbose_name_plural = _('users') def get_absolute_url(self): - return "/users/%s/" % urlquote(self.email) + return f"/users/{urlquote(self.email)}/" def get_full_name(self): """ Returns the first_name plus the last_name, with a space in between. """ - full_name = '%s %s' % (self.first_name, self.last_name) + full_name = f'{self.first_name} {self.last_name}' return full_name.strip() def get_short_name(self): @@ -82,17 +82,11 @@ class ConfirmEmail(models.Model): verbose_name_plural = u'запросы подтверждения email' ordering = ['-created_at', ] - def __unicode__(self): - status = u'не подтвержден' - if self.is_confirmed: - status = u'подтвержден' - return u'%s, email %s' % (self.user.email, status,) - def __str__(self): status = u'не подтвержден' if self.is_confirmed: status = u'подтвержден' - return u'%s, email %s' % (self.user.email, status,) + return f'{self.user.email}, email {status}' class ResetKey(models.Model): @@ -110,24 +104,21 @@ class ResetKey(models.Model): validators=[ RegexValidator( regex='[0-9a-f]{40}', - message=u'Введите значение длиной 40 символов, состоящее из цифр 0-9 и букв a-f.' + message='Введите значение длиной 40 символов, состоящее из цифр 0-9 и букв a-f.' ), MinLengthValidator(40), ] ) - created_at = models.DateTimeField(u'создан', auto_now_add=True) - updated_at = models.DateTimeField(u'изменен', auto_now=True) + created_at = models.DateTimeField('создан', auto_now_add=True) + updated_at = models.DateTimeField('изменен', auto_now=True) objects = managers.ResetKeyManager() class Meta: - verbose_name = u'ключ восстановления пароля' - verbose_name_plural = u'ключи восстановления паролей' + verbose_name = 'ключ восстановления пароля' + verbose_name_plural = 'ключи восстановления паролей' ordering = ['-created_at', ] - def __unicode__(self): - return u'%s, %s' % (self.user.email, self.key,) - def __str__(self): - return u'%s, %s' % (self.user.email, self.key,) + return f'{self.user.email}, {self.key}' diff --git a/src/myauth/tasks.py b/src/myauth/tasks.py index 98828dc..f06411a 100644 --- a/src/myauth/tasks.py +++ b/src/myauth/tasks.py @@ -1,2 +1,3 @@ -from myauth.emails import send_reset_password_email, \ - send_registration_email, send_new_password_email +# flake8: noqa +from myauth.emails import (send_reset_password_email, + send_registration_email, send_new_password_email) diff --git a/src/myauth/urls.py b/src/myauth/urls.py index fbc111b..f4ce8d6 100644 --- a/src/myauth/urls.py +++ b/src/myauth/urls.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- -from django.conf.urls import * +from django.conf.urls import url from django.views.generic import TemplateView from myauth import views -urlpatterns = patterns('', +urlpatterns = [ url(r'^register/$', views.register, name='myauth_register'), url(r'^login/$', views.login, name='myauth_login'), @@ -43,4 +43,4 @@ urlpatterns = patterns('', views.confirm_rm_profile, name='auth_confirm_rm_profile' ), -) +] diff --git a/src/myauth/views.py b/src/myauth/views.py index b51a284..6118762 100644 --- a/src/myauth/views.py +++ b/src/myauth/views.py @@ -18,7 +18,6 @@ from customer.models import UserProfile, UserProfileFilters, License from myauth import forms, models, emails - REGISTRATION_OPEN = getattr(settings, 'REGISTRATION_OPEN', True) @@ -76,14 +75,14 @@ def register(request): form = form_class(data=request.POST, prefix=form_prefix) if form.is_valid(): new_user = _create_user(request, **form.cleaned_data) - confirm_url = reverse('myauth_confirm_email', args=[new_user.username,]) + confirm_url = reverse('myauth_confirm_email', args=[new_user.username]) emails.send_registration_email.delay(new_user.email, confirm_url) messages.add_message(request, messages.INFO, success_msg) return redirect(success_url) else: form = form_class(prefix=form_prefix) - return render(request, template_name, {'form': form,}) + return render(request, template_name, {'form': form, }) @sensitive_variables() @@ -120,7 +119,7 @@ def confirm_registered_email(request, key): def reset(request): """Запросить ключ восстановления пароля.""" form_class = forms.ResetPasswordForm - form_prefix='reset' + form_prefix = 'reset' template_name = 'myauth/reset.html' success_url = 'myauth_reset_key_ready' @@ -129,13 +128,13 @@ def reset(request): if form.is_valid(): user = form.get_user() key = models.ResetKey.objects.create_key(user) - confirm_url = reverse('myauth_confirm_reset', args=[key.key,]) + confirm_url = reverse('myauth_confirm_reset', args=[key.key, ]) emails.send_reset_password_email.delay(user.email, confirm_url) return redirect(success_url) else: form = form_class(prefix=form_prefix) - return render(request, template_name, {'form': form,}) + return render(request, template_name, {'form': form, }) @sensitive_variables() @@ -230,7 +229,7 @@ def login(request): form = form_class(data=request.POST, prefix=form_prefix) if form.is_valid(): auth.login(request, form.get_user()) - old_session_key = request.user.profile.user_session_key + # old_session_key = request.user.profile.user_session_key request.user.profile.user_session_key = request.session.session_key request.user.profile.save() del request.session['login_count'] @@ -244,7 +243,7 @@ def login(request): else: form = form_class(prefix=form_prefix) - return render(request, template_name, {'form': form,}) + return render(request, template_name, {'form': form, }) def logout(request): diff --git a/src/pages/models.py b/src/pages/models.py deleted file mode 100644 index 71a8362..0000000 --- a/src/pages/models.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.db import models - -# Create your models here. diff --git a/src/pages/tests.py b/src/pages/tests.py deleted file mode 100644 index 501deb7..0000000 --- a/src/pages/tests.py +++ /dev/null @@ -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) diff --git a/src/pages/views.py b/src/pages/views.py index 7f682b7..fbb3303 100644 --- a/src/pages/views.py +++ b/src/pages/views.py @@ -2,7 +2,6 @@ from django.shortcuts import redirect from cms.views import details -from cms.models.pagemodel import Page def site_index(request): diff --git a/src/yandex_money/apps.py b/src/yandex_money/apps.py index 7585f96..e931bbb 100644 --- a/src/yandex_money/apps.py +++ b/src/yandex_money/apps.py @@ -5,5 +5,3 @@ from django.apps import AppConfig class YandexMoneyConfig(AppConfig): name = 'yandex_money' verbose_name = 'Яндекс.Деньги' - - diff --git a/src/yandex_money/forms.py b/src/yandex_money/forms.py index ea9532e..056929e 100644 --- a/src/yandex_money/forms.py +++ b/src/yandex_money/forms.py @@ -102,7 +102,7 @@ class BasePaymentForm(forms.Form): scid = self.cleaned_data['scid'] if ( scid != settings.YANDEX_MONEY_SCID and - not scid in Payment.get_used_scids() + scid not in Payment.get_used_scids() ): raise forms.ValidationError(self.error_messages[self.ERROR_MESSAGE_CODES.BAD_SCID]) return scid @@ -111,7 +111,7 @@ class BasePaymentForm(forms.Form): shop_id = self.cleaned_data['shopId'] if ( shop_id != settings.YANDEX_MONEY_SHOP_ID and - not shop_id in Payment.get_used_shop_ids() + shop_id not in Payment.get_used_shop_ids() ): raise forms.ValidationError(self.error_messages[self.ERROR_MESSAGE_CODES.BAD_SHOP_ID]) return shop_id diff --git a/src/yandex_money/urls.py b/src/yandex_money/urls.py index 20d2846..e9cdc3e 100644 --- a/src/yandex_money/urls.py +++ b/src/yandex_money/urls.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- -from django.conf.urls import patterns, url +from django.conf.urls import url from .views import NoticeFormView from .views import CheckOrderFormView -urlpatterns = patterns('', +urlpatterns = [ url(r'^check/$', CheckOrderFormView.as_view(), name='yandex_money_check'), url(r'^aviso/$', NoticeFormView.as_view(), name='yandex_money_notice'), -) +] diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..084ca60 --- /dev/null +++ b/tox.ini @@ -0,0 +1,4 @@ +[flake8] +ignore = E731 F405 +max-line-length = 99 +exclude = ./venv/*, ./node_modules/*, **/conf/**, **/migrations/**, **/templates/**, static/*