prod
Dmitriy Shesterkin 9 years ago
parent 280bc58695
commit 841f27ee61
  1. 36
      src/customer/admin.py
  2. 30
      src/customer/consts.py
  3. 22
      src/customer/emails.py
  4. 301
      src/customer/models.py
  5. 22
      src/customer/tasks.py
  6. 4
      src/dokumentor/settings/common.py
  7. 11
      src/myauth/views.py
  8. 2
      src/tests/conftest.py
  9. 13
      src/tests/fixtures/auth.py
  10. 19
      src/tests/fixtures/models.py
  11. 18
      src/tests/test_tasks.py
  12. 6
      src/tests/test_utils.py
  13. 2
      templates/emails/greeting.txt
  14. 19
      templates/emails/offer_big_period_purchased_license_bonus.txt
  15. 2
      tox.ini

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.utils import timezone
from customer import forms
from customer import models
@ -12,12 +13,45 @@ class UserProfileAdmin(admin.ModelAdmin):
class LicenseAdmin(admin.ModelAdmin):
list_display = ('get_company', 'term', 'status', 'order_date', 'date_from', 'date_to')
list_display = (
'user_email',
'license_owner',
'term_display',
'status',
'order_date',
'date_from',
'date_to',
'balance_days',
)
list_display_links = list_display
search_fields = ('company__email',)
list_filter = ('status', 'term', 'order_date', 'date_from', 'date_to')
def user_email(self, obj):
if obj.company.users.first():
return obj.company.users.first().email
else:
return 'Нет пользователя'
user_email.short_description = 'Email пользователя'
def term_display(self, obj):
return obj.get_term()
term_display.short_description = 'Срок лицензии'
def license_owner(self, obj):
return obj.get_company()
license_owner.short_description = 'Компания'
def balance_days(self, obj):
delta = obj.date_to - timezone.now().date()
return delta.days
balance_days.short_description = 'Остаток дней'
class BankAccountAdmin(admin.ModelAdmin):
class Media:

@ -4,28 +4,28 @@ IP_PROFILE = 1
ORG_PROFILE = 2
PROFILE_TYPES = (
(IP_PROFILE, u'Индивидуальный предприниматель'),
(ORG_PROFILE, u'Организация'),
(IP_PROFILE, 'Индивидуальный предприниматель'),
(ORG_PROFILE, 'Организация'),
)
LICENSE_STATUSES = (
(-1, u'Пробный период'),
(0, u'Не оплачен'),
(1, u'Оплачен'),
(2, u'Активирован'),
(3, u'Срок действия истёк'),
(4, u'Заморожен'),
(-1, 'Пробный период'),
(0, 'Не оплачен'),
(1, 'Оплачен'),
(2, 'Активирован'),
(3, 'Срок действия истёк'),
(4, 'Заморожен'),
)
PAYFORMS = (
(-1, u'Бесплатно'),
(0, u'Безналичный расчёт'),
(1, u'Банковская карта'),
(-1, 'Бесплатно'),
(0, 'Безналичный расчёт'),
(1, 'Банковская карта'),
)
TERMS = (
(1, u'1 месяц'),
(6, u'6 месяцев'),
(12, u'12 месяцев'),
(24, u'24 месяца'),
(1, '1 месяц'),
(6, '6 месяцев'),
(12, '12 месяцев'),
(24, '24 месяца'),
)

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from celery import task
from django.conf import settings
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from commons.utils import get_site_url
@task
def send_offer_buy_licence_for_get_bonus(user_email, url):
template_name = 'emails/offer_big_period_purchased_license_bonus.txt'
subject = 'Документор: Получите бонус'
dict_context = {'user_email': user_email,
'support_email': settings.SUPPORT_EMAIL,
'url': url,
'site_url': get_site_url()
}
email_body = render_to_string(template_name, dict_context)
email = EmailMessage(subject=subject, to=(user_email,), body=email_body)
return email.send()

@ -50,25 +50,25 @@ class UploadAndRename(object):
class UserProfile(models.Model):
"""Профиль пользователя."""
profile_type = models.PositiveSmallIntegerField(u'Тип профиля', choices=consts.PROFILE_TYPES)
profile_type = models.PositiveSmallIntegerField('Тип профиля', choices=consts.PROFILE_TYPES)
# общие поля
boss_surname = models.CharField(u'Фамилия', max_length=30, default='',
help_text=u'Используется для строки "подпись" в документах.')
boss_name = models.CharField(u'Имя', max_length=30, default='')
boss_midname = models.CharField(u'Отчество', max_length=30, default='')
boss_surname = models.CharField('Фамилия', max_length=30, default='',
help_text='Используется для строки "подпись" в документах.')
boss_name = models.CharField('Имя', max_length=30, default='')
boss_midname = models.CharField('Отчество', max_length=30, default='')
# длина: 10 для организаций, 12 для ИП
inn = models.CharField(u'ИНН', max_length=12, default='')
inn = models.CharField('ИНН', max_length=12, default='')
# длина: 13 для организаций, 15 для ИП
ogrn = models.CharField(u'ОГРН/ОГРНИП', max_length=15, default='')
ogrn = models.CharField('ОГРН/ОГРНИП', max_length=15, default='')
# длина: 8 для организаций, 8 или 10 для ИП
okpo = models.CharField(u'ОКПО', max_length=10, blank=True, default='')
okpo = models.CharField('ОКПО', max_length=10, blank=True, default='')
glavbuh_surname = models.CharField('Фамилия', max_length=30, blank=True, default='',
help_text='Используется для строки "подпись" в документах.')
glavbuh_name = models.CharField(u'Имя', max_length=30, blank=True, default='')
glavbuh_midname = models.CharField(u'Отчество', max_length=30, blank=True, default='')
glavbuh_name = models.CharField('Имя', max_length=30, blank=True, default='')
glavbuh_midname = models.CharField('Отчество', max_length=30, blank=True, default='')
address = models.CharField(
'Фактический адрес',
@ -77,17 +77,17 @@ class UserProfile(models.Model):
help_text='Будет подставляться в создаваемые счета, акты и накладные.'
)
jur_address = models.CharField(u'Юридический адрес', max_length=256, blank=True, default='',
help_text=u'Как в учредительных документах.')
jur_address = models.CharField('Юридический адрес', max_length=256, blank=True, default='',
help_text='Как в учредительных документах.')
real_address = models.CharField(u'Почтовый адрес', max_length=256, blank=True, default='',
help_text=u'Используется только для карточки компании.')
real_address = models.CharField('Почтовый адрес', max_length=256, blank=True, default='',
help_text='Используется только для карточки компании.')
phone_code = models.CharField(u'Код города', max_length=10, blank=True, default='')
phone = models.CharField(u'Номер телефона', max_length=20, blank=True, default='')
phone_code = models.CharField('Код города', max_length=10, blank=True, default='')
phone = models.CharField('Номер телефона', max_length=20, blank=True, default='')
fax_code = models.CharField(u'Код города', max_length=10, blank=True, default='')
fax = models.CharField(u'Номер телефона', max_length=20, blank=True, default='')
fax_code = models.CharField('Код города', max_length=10, blank=True, default='')
fax = models.CharField('Номер телефона', max_length=20, blank=True, default='')
email = models.EmailField(
'Электронная почта',
@ -108,36 +108,36 @@ class UserProfile(models.Model):
max_length=256,
blank=True,
default='',
help_text=u'Требуется для счет-фактуры.'
help_text='Требуется для счет-фактуры.'
)
ip_reg_date = models.DateField(u'Дата регистрации ИП', blank=True, null=True)
ip_reg_date = models.DateField('Дата регистрации ИП', blank=True, null=True)
# поля, только для Организации
name = models.CharField(
'Краткое название организации',
max_length=256,
default='',
help_text=u'Будет подставляться в создаваемые документы.'
help_text='Будет подставляться в создаваемые документы.'
)
full_name = models.CharField(
'Полное название организации',
max_length=256,
blank=True,
default='',
help_text=u'Как в учредительных документах.'
help_text='Как в учредительных документах.'
)
kpp = models.CharField(u'КПП', max_length=9, default='')
kpp = models.CharField('КПП', max_length=9, default='')
boss_title = models.CharField(
u'Должность руководителя',
'Должность руководителя',
max_length=256,
blank=True,
default=''
)
na_osnovanii = models.CharField(
u'Действует на основании',
'Действует на основании',
max_length=256,
blank=True,
default=''
@ -151,13 +151,13 @@ class UserProfile(models.Model):
upload_to=UploadAndRename(PROFILE_IMAGES_UPLOAD_DIR, 'boss_sign.png')
)
glavbuh_sign = models.ImageField(
u'Подпись бухгалтера',
'Подпись бухгалтера',
blank=True,
default='',
upload_to=UploadAndRename(PROFILE_IMAGES_UPLOAD_DIR, 'glavbuh_sign.png')
)
stamp = models.ImageField(
u'Печать',
'Печать',
blank=True,
default='',
upload_to=UploadAndRename(PROFILE_IMAGES_UPLOAD_DIR, 'stamp.png')
@ -169,30 +169,30 @@ class UserProfile(models.Model):
upload_to=UploadAndRename(PROFILE_IMAGES_UPLOAD_DIR, 'logo.png')
)
created_at = models.DateTimeField(u'Создан', auto_now_add=True)
updated_at = models.DateTimeField(u'Изменен', auto_now=True)
active = models.BooleanField(u'Активен', default=False)
confirmed = models.BooleanField(u'Подтверждён', default=False)
created_at = models.DateTimeField('Создан', auto_now_add=True)
updated_at = models.DateTimeField('Изменен', auto_now=True)
active = models.BooleanField('Активен', default=False)
confirmed = models.BooleanField('Подтверждён', default=False)
user_session_key = models.CharField(
u'Ключ сессии (служебная информация)',
'Ключ сессии (служебная информация)',
max_length=256,
blank=True,
default='',
help_text=u'Руками не трогать...'
help_text='Руками не трогать...'
)
objects = managers.UserProfileManager()
class Meta:
verbose_name = u'Реквизиты (профиль)'
verbose_name_plural = u'Реквизиты (профили)'
verbose_name = 'Реквизиты (профиль)'
verbose_name_plural = 'Реквизиты (профили)'
def __unicode__(self):
return u'%s, ИНН %s' % (self.get_company_name()[0:30], self.inn or u'не указан')
return '%s, ИНН %s' % (self.get_company_name()[0:30], self.inn or 'не указан')
def __str__(self):
return u'%s, ИНН %s' % (self.get_company_name()[0:30], self.inn or u'не указан')
return '%s, ИНН %s' % (self.get_company_name()[0:30], self.inn or 'не указан')
def save(self, *args, **kwargs):
self.inn = only_numerics(self.inn)
@ -268,54 +268,52 @@ class UserProfile(models.Model):
`ИП ФИО` или `Название Организации`.
"""
if self.profile_type == consts.IP_PROFILE:
return u'ИП %s' % self.get_boss_full_fio()
return 'ИП %s' % self.get_boss_full_fio()
elif self.profile_type == consts.ORG_PROFILE:
return self.name.strip()
return u''
return ''
def get_inn_and_kpp(self):
"""Возвращает пару ИНН/КПП или только ИНН, если это ИП или КПП не заполнен."""
if self.profile_type == consts.ORG_PROFILE:
kpp = self.kpp.strip()
if kpp:
return u'%s/%s' % (self.inn, kpp,)
return '%s/%s' % (self.inn, kpp,)
return self.inn
def get_boss_title(self):
"""Текст 'Индивидуальный предприниматель' или 'Руководитель организации'."""
if self.profile_type == consts.IP_PROFILE:
return u'Индивидуальный предприниматель'
return 'Индивидуальный предприниматель'
elif self.profile_type == consts.ORG_PROFILE:
return u'Руководитель организации'
return u''
return 'Руководитель организации'
return ''
def get_boss_fio(self):
"""Фамилия и инициалы руководителя ИП/организации."""
if self.boss_surname and self.boss_name and self.boss_midname:
return u'%s %s.%s.' % (self.boss_surname, self.boss_name[0], self.boss_midname[0],)
return u''
return '%s %s.%s.' % (self.boss_surname, self.boss_name[0], self.boss_midname[0],)
return ''
def get_boss_full_fio(self):
"""Полное ФИО руководителя ИП/организации."""
return (u'%s %s %s' % (self.boss_surname, self.boss_name, self.boss_midname,)).strip()
return ('%s %s %s' % (self.boss_surname, self.boss_name, self.boss_midname,)).strip()
def get_glavbuh_fio(self):
"""Фамилия и инициалы главного бухгалтера."""
if self.glavbuh_surname and self.glavbuh_name and self.glavbuh_midname:
return (u'%s %s. %s.' % (self.glavbuh_surname, self.glavbuh_name[0],
self.glavbuh_midname[0],)).strip()
return u''
return f'{self.glavbuh_surname} {self.glavbuh_name[0]}. {self.glavbuh_midname[0]}.'
return ''
def get_glavbuh_full_fio(self):
"""Полное ФИО главного бухгалтера."""
return (u'%s %s %s' % (self.glavbuh_surname, self.glavbuh_name,
self.glavbuh_midname,)).strip()
return f'{self.glavbuh_surname} {self.glavbuh_name} {self.glavbuh_midname}'
def get_full_phone(self):
"""(Код города) Номер телефона."""
phone_code = self.phone_code.strip('() ')
phone_code = u'(%s)' % phone_code if phone_code else phone_code
return (u'%s %s' % (phone_code, self.phone,)).strip()
phone_code = f'({phone_code})'
return f'{phone_code} {self.phone}'
def get_email(self):
try:
@ -326,8 +324,8 @@ class UserProfile(models.Model):
def get_full_fax(self):
"""(Код города) Номер факса."""
fax_code = self.fax_code.strip('() ')
fax_code = u'(%s)' % fax_code if fax_code else fax_code
return (u'%s %s' % (fax_code, self.fax,)).strip()
fax_code = '(%s)' % fax_code if fax_code else fax_code
return ('%s %s' % (fax_code, self.fax,)).strip()
def validate_has_profile_account(self):
"""
@ -344,34 +342,34 @@ class BankAccount(models.Model):
"""Расчетные счета."""
company = models.ForeignKey(UserProfile, related_name='bank_accounts')
bik = models.CharField(u'БИК', max_length=10)
name = models.CharField(u'Наименование банка', max_length=256)
bik = models.CharField('БИК', max_length=10)
name = models.CharField('Наименование банка', max_length=256)
short_name = models.CharField(
'Сокращенное название банка',
max_length=100,
blank=True,
default=''
)
korr_account = models.CharField(u'Корр. счет', max_length=20)
account = models.CharField(u'Расчетный счет', max_length=20)
korr_account = models.CharField('Корр. счет', max_length=20)
account = models.CharField('Расчетный счет', max_length=20)
is_main = models.BooleanField(u'Основной счет', default=False)
is_main = models.BooleanField('Основной счет', default=False)
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.BankAccountManager()
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.account, self.short_name[0:30] or self.name[0:30],)).strip()
return ('%s, %s' % (self.account, self.short_name[0:30] or self.name[0:30],)).strip()
def __str__(self):
return (u'%s, %s' % (self.account, self.short_name[0:30] or self.name[0:30],)).strip()
return ('%s, %s' % (self.account, self.short_name[0:30] or self.name[0:30],)).strip()
def save(self, *args, **kwargs):
self.bik = only_numerics(self.bik)
@ -399,7 +397,7 @@ class Client(models.Model):
"""Контрагенты."""
company = models.ForeignKey(UserProfile, related_name='clients')
name = models.CharField(u'Наименование', max_length=256, db_index=True)
name = models.CharField('Наименование', max_length=256, db_index=True)
name_short_self = models.CharField(
'Короткое наименование',
@ -414,52 +412,52 @@ class Client(models.Model):
blank=True
)
inn = models.CharField(u'ИНН', max_length=12)
kpp = models.CharField(u'КПП', max_length=9, blank=True, default='') # Организация
ogrn = models.CharField(u'ОГРН', max_length=15, default='')
okpo = models.CharField(u'ОКПО', max_length=10, blank=True, default='') # ИП
address = models.CharField(u'Юр. адрес', max_length=256)
inn = models.CharField('ИНН', max_length=12)
kpp = models.CharField('КПП', max_length=9, blank=True, default='') # Организация
ogrn = models.CharField('ОГРН', max_length=15, default='')
okpo = models.CharField('ОКПО', max_length=10, blank=True, default='') # ИП
address = models.CharField('Юр. адрес', max_length=256)
# банковские реквизиты
bank_bik = models.CharField(u'БИК', max_length=10, blank=True, default='')
bank_name = models.CharField(u'Наименование банка', max_length=256, blank=True, default='')
bank_bik = models.CharField('БИК', max_length=10, blank=True, default='')
bank_name = models.CharField('Наименование банка', max_length=256, blank=True, default='')
bank_short_name = models.CharField(
'Сокращенное наименование банка',
max_length=256,
blank=True,
default=''
)
bank_korr_account = models.CharField(u'Корр. счет', max_length=20, blank=True, default='')
bank_account = models.CharField(u'Расчетный счет', max_length=20, blank=True, default='')
bank_korr_account = models.CharField('Корр. счет', max_length=20, blank=True, default='')
bank_account = models.CharField('Расчетный счет', max_length=20, blank=True, default='')
# контакты
contact_name = models.CharField(u'Имя', max_length=50, blank=True, default='')
contact_email = models.EmailField(u'E-mail', max_length=50, blank=True, default='')
contact_phone = models.CharField(u'Телефон', max_length=50, blank=True, default='')
contact_skype = models.CharField(u'Skype', max_length=20, blank=True, default='')
contact_other = models.CharField(u'Другое', max_length=256, blank=True, default='')
contact_name = models.CharField('Имя', max_length=50, blank=True, default='')
contact_email = models.EmailField('E-mail', max_length=50, blank=True, default='')
contact_phone = models.CharField('Телефон', max_length=50, blank=True, default='')
contact_skype = models.CharField('Skype', max_length=20, blank=True, default='')
contact_other = models.CharField('Другое', max_length=256, blank=True, default='')
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.ClientManager()
class Meta:
verbose_name = u'Контрагент'
verbose_name_plural = u'Контрагенты'
verbose_name = 'Контрагент'
verbose_name_plural = 'Контрагенты'
ordering = ['name', '-created_at']
def __unicode__(self):
if self.name_short_self:
return (u'%s, %s' % (self.name_short_dadata, self.name_short_self)).strip()
return ('%s, %s' % (self.name_short_dadata, self.name_short_self)).strip()
else:
return (u'%s, ИНН %s' % (self.name, self.inn or u'не указан',)).strip()
return ('%s, ИНН %s' % (self.name, self.inn or 'не указан',)).strip()
def __str__(self):
if self.name_short_self:
return (u'%s, %s' % (self.name_short_dadata, self.name_short_self)).strip()
return ('%s, %s' % (self.name_short_dadata, self.name_short_self)).strip()
else:
return (u'%s, ИНН %s' % (self.name, self.inn or u'не указан',)).strip()
return ('%s, ИНН %s' % (self.name, self.inn or 'не указан',)).strip()
def save(self, *args, **kwargs):
self.inn = only_numerics(self.inn)
@ -475,7 +473,7 @@ class Client(models.Model):
"""Возвращает пару ИНН/КПП или только ИНН, если КПП не заполнен."""
kpp = self.kpp.strip()
if kpp:
return u'%s/%s' % (self.inn, kpp,)
return '%s/%s' % (self.inn, kpp,)
return self.inn
@ -486,47 +484,47 @@ class UserProfileFilters(models.Model):
company = models.OneToOneField(UserProfile, related_name='profile_filters', primary_key=True)
# общие фильтры
show_profile_type = models.BooleanField(u'Тип профиля', default=True)
show_profile_type = models.BooleanField('Тип профиля', default=True)
show_inn = models.BooleanField(u'ИНН', default=True)
show_ogrn = models.BooleanField(u'ОГРН/ОГРНИП', default=True)
show_okpo = models.BooleanField(u'ОКПО', default=True)
show_inn = models.BooleanField('ИНН', default=True)
show_ogrn = models.BooleanField('ОГРН/ОГРНИП', default=True)
show_okpo = models.BooleanField('ОКПО', default=True)
show_glavbuh = models.BooleanField(u'Главный бухгалтер', default=True)
show_glavbuh = models.BooleanField('Главный бухгалтер', default=True)
show_bank_account = models.BooleanField(u'Банковские реквизиты', default=True)
show_bank_account = models.BooleanField('Банковские реквизиты', default=True)
bank_account = models.ForeignKey(
BankAccount,
related_name='+',
verbose_name=u'Расчетный счет',
verbose_name='Расчетный счет',
blank=True,
null=True,
default=None
)
show_contact_info = models.BooleanField(u'Контактная информация', default=True)
show_address = models.BooleanField(u'Фактический адрес', default=True)
show_jur_address = models.BooleanField(u'Юридический адрес', default=True)
show_real_address = models.BooleanField(u'Почтовый адрес', default=True)
show_phone = models.BooleanField(u'Телефон', default=True)
show_fax = models.BooleanField(u'Факс', default=True)
show_email = models.BooleanField(u'Электронная почта', default=True)
show_site = models.BooleanField(u'Сайт', default=True)
show_contact_info = models.BooleanField('Контактная информация', default=True)
show_address = models.BooleanField('Фактический адрес', default=True)
show_jur_address = models.BooleanField('Юридический адрес', default=True)
show_real_address = models.BooleanField('Почтовый адрес', default=True)
show_phone = models.BooleanField('Телефон', default=True)
show_fax = models.BooleanField('Факс', default=True)
show_email = models.BooleanField('Электронная почта', default=True)
show_site = models.BooleanField('Сайт', default=True)
show_logo = models.BooleanField(u'Логотип', default=True)
show_logo = models.BooleanField('Логотип', default=True)
# только для ИП
show_ip_boss_fio = models.BooleanField(u'Фамилия, Имя, Отчество', default=True)
show_svid_gos_reg = models.BooleanField(u'Свид-во о гос. регистрации', default=True)
show_ip_reg_date = models.BooleanField(u'Дата регистрации ИП', default=True)
show_ip_boss_fio = models.BooleanField('Фамилия, Имя, Отчество', default=True)
show_svid_gos_reg = models.BooleanField('Свид-во о гос. регистрации', default=True)
show_ip_reg_date = models.BooleanField('Дата регистрации ИП', default=True)
# только для Организации
show_name = models.BooleanField(u'Краткое название организации', default=True)
show_full_name = models.BooleanField(u'Полное название организации', default=True)
show_kpp = models.BooleanField(u'КПП', default=True)
show_name = models.BooleanField('Краткое название организации', default=True)
show_full_name = models.BooleanField('Полное название организации', default=True)
show_kpp = models.BooleanField('КПП', default=True)
show_org_boss_title_and_fio = models.BooleanField(
'Руководитель (Должность, ФИО)', default=True)
show_na_osnovanii = models.BooleanField(u'Действует на основании', default=True)
show_na_osnovanii = models.BooleanField('Действует на основании', default=True)
objects = managers.UserProfileFiltersManager()
@ -550,29 +548,33 @@ class License(models.Model):
related_name='licenses',
verbose_name='пользователь'
)
term = models.IntegerField(verbose_name=u'срок лицензии')
date_from = models.DateField(u'дата начала', null=True, blank=True)
date_to = models.DateField(u'дата окончания', null=True, blank=True)
payform = models.IntegerField(verbose_name=u'форма оплаты',
term = models.IntegerField(verbose_name='срок лицензии')
date_from = models.DateField('дата начала', null=True, blank=True)
date_to = models.DateField('дата окончания', null=True, blank=True)
payform = models.IntegerField(verbose_name='форма оплаты',
choices=consts.PAYFORMS, default=0)
status = models.IntegerField(verbose_name=u'статус лицензии',
status = models.IntegerField(verbose_name='статус лицензии',
choices=consts.LICENSE_STATUSES, default=0)
order_date = models.DateField(verbose_name=u'дата заказа', auto_now_add=True)
paid_date = models.DateField(verbose_name=u'дата оплаты', null=True, blank=True)
pay_sum = models.IntegerField(verbose_name=u'сумма оплаты')
deleted = models.BooleanField(u'удалено', default=False)
order_date = models.DateField(verbose_name='дата заказа', auto_now_add=True)
paid_date = models.DateField(verbose_name='дата оплаты', null=True, blank=True)
pay_sum = models.IntegerField(verbose_name='сумма оплаты')
deleted = models.BooleanField('удалено', default=False)
class Meta:
verbose_name = 'Лицензии'
verbose_name_plural = 'Лицензии'
def __init__(self, *args, **kwargs):
super(License, self).__init__(*args, **kwargs)
self.__prev_date = self.paid_date
def __str__(self):
return u'%s - %s %s (%d %s)' % (
return '%s - %s %s (%d %s)' % (
self.company.get_company_name(),
self.term,
numeral.choose_plural(self.term, u"месяц, месяца, месяцев"),
numeral.choose_plural(self.term, "месяц, месяца, месяцев"),
self.pay_sum,
numeral.choose_plural(self.pay_sum, u"рубль, рубля, рублей"),
numeral.choose_plural(self.pay_sum, "рубль, рубля, рублей"),
)
def save(self, *args, **kwargs):
@ -599,47 +601,35 @@ class License(models.Model):
if self.status == 0:
if self.payform == 0:
return u'<a href="%s">Скачать счёт</a>' % reverse(
'customer_license_get_doc',
kwargs={'order_num': self.id}
)
url = reverse('customer_license_get_doc', kwargs={'order_num': self.id})
return f'<a href="{url}">Скачать счёт</a>'
elif self.payform == 1:
return u'Оплатить счёт'
return 'Оплатить счёт'
elif self.payform == 2:
return u'<a href="%s">Скачать квитанцию</a>' % reverse(
'customer_license_get_doc',
kwargs={'order_num': self.id}
)
url = reverse('customer_license_get_doc', kwargs={'order_num': self.id})
return f'<a href="{url}">Скачать квитанцию</a>'
elif self.status in [1, 2]:
return u'История операций'
return 'История операций'
else:
return ''
def get_term(self):
if self.term == 0:
return u'45 дней'
return '45 дней'
else:
return u'%s %s' % (self.term,
numeral.choose_plural(self.term, u"месяц, месяца, месяцев"),
)
return f'{self.term} {numeral.choose_plural(self.term, "месяц, месяца, месяцев")}'
def get_paid_status(self):
if self.status == 1:
return u'Лицензия оплачена, ещё не активирована'
return 'Лицензия оплачена, ещё не активирована'
elif self.status in [2, -1]:
left = relativedelta(self.date_to, datetime.today())
if left.months:
left_str = '%d %s %d %s' % (left.months,
numeral.choose_plural(
left.months, u"месяц, месяца, месяцев"),
left.days,
numeral.choose_plural(left.days, u"день, дня, дней"),
)
left_str = f'{left.months} ' \
f'{numeral.choose_plural(left.months, "месяц, месяца, месяцев")} ' \
f'{left.days} {numeral.choose_plural(left.days, "день, дня, дней")}'
else:
left_str = '%d %s' % (
left.days,
numeral.choose_plural(left.days, u"день, дня, дней"),
)
left_str = f'{left.days} {numeral.choose_plural(left.days, "день, дня, дней")}'
return f'Лицензия активирована: осталось {left_str}'
elif self.status == 3:
return 'Время истекло'
@ -652,9 +642,10 @@ class LicensePrice(models.Model):
choices=consts.TERMS)
price = models.IntegerField(verbose_name='сумма оплаты')
class Meta:
verbose_name = 'Прайс на лицензии'
verbose_name_plural = 'Прайсы на лицензии'
def __str__(self):
return u'%s %s (%d %s)' % (self.term,
numeral.choose_plural(self.term, u"месяц, месяца, месяцев"),
self.price,
numeral.choose_plural(self.price, u"рубль, рубля, рублей"),
)
return f'{self.term} {numeral.choose_plural(self.term, "месяц, месяца, месяцев")} ' \
f'({self.price} {numeral.choose_plural(self.price, "рубль, рубля, рублей")})'

@ -3,6 +3,7 @@ from __future__ import absolute_import
import traceback
from django.core.urlresolvers import reverse
from django.utils import timezone
from datetime import datetime, timedelta
@ -12,7 +13,7 @@ from django.core.mail import mail_admins
from myauth.models import DokUser, ConfirmEmail
from . import emails
from .models import License, UserProfile
from .utils import check_one_profile
@ -41,8 +42,10 @@ def check_license():
@shared_task
def delete_not_activated_users():
today = timezone.now().date()
date_join = today - timezone.timedelta(days=5)
users = DokUser.objects.filter(profile__active=False, profile__confirmed=False).\
filter(profile__created_at__lte=timezone.now() - timezone.timedelta(days=5))
filter(date_joined__lte=date_join)
if users:
for user in users:
profile = user.profile
@ -52,3 +55,18 @@ def delete_not_activated_users():
if confirm:
confirm.delete()
user.delete()
@shared_task
def send_offer_for_get_bonus():
today = timezone.now().date()
date_join_start = today - timezone.timedelta(days=9)
date_join_end = today - timezone.timedelta(days=8)
users = DokUser.objects.filter(profile__active=True, profile__confirmed=True).\
filter(date_joined__gt=date_join_start, date_joined__lt=date_join_end)
for user in users:
licenses = License.objects.filter(company=user.profile).filter(status=2)
if not licenses:
url = reverse('customer_order_license')
emails.send_offer_buy_licence_for_get_bonus.delay(user.email, url)

@ -273,6 +273,10 @@ CELERYBEAT_SCHEDULE = {
'task': 'src.customer.tasks.delete_not_activated_users',
'schedule': timedelta(days=1),
},
'send_offer_for_get_bonus': {
'task': 'src.customer.tasks.send_offer_for_get_bonus',
'schedule': timedelta(days=1),
},
}
CAPTCHA_OUTPUT_FORMAT = \

@ -19,8 +19,6 @@ from customer.models import UserProfile, UserProfileFilters, License
from myauth import forms, models, emails
REGISTRATION_OPEN = getattr(settings, 'REGISTRATION_OPEN', True)
@sensitive_variables()
def _create_user(request, **kwargs):
@ -69,7 +67,7 @@ def register(request):
success_msg = 'Дождитесь письма на указанный Вами адрес и перейдите по ссылке в письме.'
registration_closed_url = 'myauth_registration_closed'
if not REGISTRATION_OPEN:
if not settings.REGISTRATION_OPEN:
return redirect(registration_closed_url)
if request.method == 'POST':
@ -87,7 +85,7 @@ def register(request):
else:
form = form_class(prefix=form_prefix)
return render(request, template_name, {'form': form, })
return render(request, template_name, {'form': form})
@sensitive_variables()
@ -141,7 +139,7 @@ def reset(request):
else:
form = form_class(prefix=form_prefix)
return render(request, template_name, {'form': form, })
return render(request, template_name, {'form': form})
@sensitive_variables()
@ -250,7 +248,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):
@ -258,6 +256,7 @@ def logout(request):
request.user.profile.user_session_key = ''
request.user.profile.save()
except:
# TODO: ???
pass
django_logout(request)
response = redirect('/')

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
pytest_plugins = [
'src.tests.fixtures.auth',
'src.tests.fixtures.models',
'src.tests.fixtures.common'
]

@ -1,13 +0,0 @@
# -*- coding: utf-8 -*-
import pytest
from factories.models import UserFactory, ConfirmEmail
@pytest.fixture
def user():
return UserFactory()
@pytest.fixture
def confirm_email():
return ConfirmEmail()

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
import pytest
from factories.models import UserFactory, ConfirmEmailFactory
@pytest.fixture
def user():
return UserFactory()
@pytest.fixture
def confirm_email():
return ConfirmEmailFactory()
@pytest.fixture()
def profile():
_user = UserFactory()
return _user.profile

@ -6,14 +6,15 @@ from django.utils import timezone
from myauth.models import DokUser, ConfirmEmail
from customer.models import UserProfile
from customer.tasks import delete_not_activated_users
from customer.tasks import delete_not_activated_users, send_offer_for_get_bonus
dates_gte_five = [timezone.now() - timezone.timedelta(days=100),
timezone.now() - timezone.timedelta(days=15),
timezone.now() - timezone.timedelta(days=5)]
timezone.now() - timezone.timedelta(days=6)]
dates_lt_five = [timezone.now() - timezone.timedelta(days=4),
dates_lt_five = [timezone.now() - timezone.timedelta(days=5),
timezone.now() - timezone.timedelta(days=4),
timezone.now() - timezone.timedelta(days=3),
timezone.now() - timezone.timedelta(days=2),
timezone.now() - timezone.timedelta(days=1),
@ -24,10 +25,10 @@ dates_lt_five = [timezone.now() - timezone.timedelta(days=4),
@pytest.mark.django_db
def test_delete_not_activated_users_great_five_days(user, create_date):
user.is_active = False
user.date_joined = create_date
profile = user.profile
profile.active = False
profile.confirmed = False
profile.created_at = create_date
profile.save()
user.save()
ConfirmEmail.objects.get_or_create(user=user)
@ -43,10 +44,10 @@ def test_delete_not_activated_users_great_five_days(user, create_date):
@pytest.mark.django_db
def test_delete_not_activated_users_less_five_day(user, create_date):
user.is_active = False
user.date_joined = create_date
profile = user.profile
profile.active = False
profile.confirmed = False
profile.created_at = create_date
profile.save()
user.save()
ConfirmEmail.objects.get_or_create(user=user)
@ -56,3 +57,10 @@ def test_delete_not_activated_users_less_five_day(user, create_date):
assert DokUser.objects.count() == 1
assert UserProfile.objects.count() == 1
assert ConfirmEmail.objects.count() == 1
@pytest.mark.django_db
def test_send_offer_for_get_bonus(user):
send_offer_for_get_bonus()
print(user)
pass

@ -1,7 +1,10 @@
# -*- coding: utf-8 -*-
import pytest
from django.utils import timezone
from commons.utils import get_site_url
from customer.utils import check_one_profile
def test_utils_with_request(mocked_request):
@ -15,5 +18,6 @@ def test_utils_without_request():
@pytest.mark.django_db
def test_check_one_profile():
def test_check_one_profile(profile):
check_one_profile(profile, timezone.now(), manual=False)
pass

@ -8,6 +8,6 @@
С адреса {{ robot_email }} Вам будут приходить созданные Вами документы и служебные уведомления. Пожалуйста, добавьте его в список своих контактов, чтобы не пропустить ничего важного.
По всем вопросам можно писать на почту {{ support_email }} или в форму "обратная связь", расположенную внизу всех страниц сайте Документор ({{ site_url|default:'https://dokumentor.ru' }}).
---
--
Это письмо отправлено роботом. Пожалуйста не отвечайте на него. По всем вопросам пишите на {{ support_email }}

@ -0,0 +1,19 @@
Здравствуйте!
Прошло уже несколько дней, как Вы зарегистрировались в Документоре и, надеемся, что он Вам нравится.
Если так, то для Вас есть специальное предложение: бонус - ещё 2 или 3 бесплатных месяца за доверие и сотрудничество.
Сейчас у Вас осталось 40 дней бесплатного периода. И это время в любом случае будет бесплатным.
Но, если Вы приобретёте лицензию на 1 или 2 года в течение следующих 10 дней, то мы подарим Вам ещё 2 или 3 месяца бесплатного времени.
Лицензия на 1 год стоит 1800 рублей, подарок к ней - ещё 2 месяца Лицензия на 2 года стоит 3000 рублей, подарок к ней - ещё 3 месяца
Ваш бесплатный период не уменьшится в любом случае. Срок новой лицензии начнётся только после того, как закончится бесплатное время.
Так мы сможем быстрее развивать Документор и внедрять в него новые возможности, которые будут делать Вашу работу ещё удобнее. А Вы сможете пользоваться Документором без повышения цен в течение всего оплаченного и подаренного времени.
Если Вы согласны, купите лицензию здесь {{ site_url }}{{ url }}. Если нет - ничего страшного ;)
{{ site_url }}
--
Это письмо отправлено роботом. Пожалуйста не отвечайте на него. По всем вопросам пишите на {{ support_email }}

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

Loading…
Cancel
Save