# -*- coding: utf-8 -*- import os from datetime import datetime, timedelta from PIL import Image from pytils import numeral from dateutil.relativedelta import relativedelta from django.db import models from django.conf import settings from django.db.models import Max from django.core.urlresolvers import reverse from . import consts, managers, utils from project.myauth.models import DokUser from project.commons.utils import only_numerics PROFILE_IMAGES_UPLOAD_DIR = 'customer/profile/' # куда сохранять загруженные изображения BOSS_SIGN_IMG_SIZE = (159, 65) GLAVBUH_SIGN_IMG_SIZE = (159, 65) STAMP_IMG_SIZE = (180, 180) LOGO_SIZE = (351, 121) def get_profile(user): """Возвращает профиль пользователя или None.""" try: return user.profile except: return None def upload_to(path, new_filename=None): """Куда и под каким именем сохранить загруженный файл.""" def get_upload_path(instance, filename): filename = new_filename or filename try: profile_dir = instance.get_first_user().username except: profile_dir = 'NoUser' return os.path.join(path, profile_dir, filename) return get_upload_path class UserProfile(models.Model): """Профиль пользователя.""" profile_type = models.PositiveSmallIntegerField(u'Тип профиля', 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='') inn = models.CharField(u'ИНН', max_length=12, default='') # длина: 10 для организаций, 12 для ИП ogrn = models.CharField(u'ОГРН/ОГРНИП', max_length=15, default='') # длина: 13 для организаций, 15 для ИП okpo = models.CharField(u'ОКПО', max_length=10, blank=True, default='') # длина: 8 для организаций, 8 или 10 для ИП glavbuh_surname = models.CharField(u'Фамилия', max_length=30, blank=True, default='', help_text=u'Используется для строки "подпись" в документах.') glavbuh_name = models.CharField(u'Имя', max_length=30, blank=True, default='') glavbuh_midname = models.CharField(u'Отчество', max_length=30, blank=True, default='') address = models.CharField(u'Фактический адрес', max_length=256, default='', help_text=u'Будет подставляться в создаваемые счета, акты и накладные.') jur_address = models.CharField(u'Юридический адрес', max_length=256, blank=True, default='', help_text=u'Как в учредительных документах.') real_address = models.CharField(u'Почтовый адрес', max_length=256, blank=True, default='', help_text=u'Используется только для карточки компании.') phone_code = models.CharField(u'Код города', max_length=10, blank=True, default='') phone = models.CharField(u'Номер телефона', 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='') email = models.EmailField(u'Электронная почта', max_length=75, blank=True, default='') site = models.CharField(u'Сайт', max_length=256, blank=True, default='') # поля, только для ИП svid_gos_reg = models.CharField(u'Свид-во о гос. регистрации', max_length=256, blank=True, default='', help_text=u'Требуется для счет-фактуры.') ip_reg_date = models.DateField(u'Дата регистрации ИП', blank=True, null=True) # поля, только для Организации name = models.CharField(u'Краткое название организации', max_length=256, default='', help_text=u'Будет подставляться в создаваемые документы.') full_name = models.CharField(u'Полное название организации', max_length=256, blank=True, default='', help_text=u'Как в учредительных документах.') kpp = models.CharField(u'КПП', 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='') # подписи, печать и логотип boss_sign = models.ImageField(u'Подпись руководителя', blank=True, default='', upload_to=upload_to(PROFILE_IMAGES_UPLOAD_DIR, 'boss_sign.bmp')) glavbuh_sign = models.ImageField(u'Подпись бухгалтера', blank=True, default='', upload_to=upload_to(PROFILE_IMAGES_UPLOAD_DIR, 'glavbuh_sign.bmp')) stamp = models.ImageField(u'Печать', blank=True, default='', upload_to=upload_to(PROFILE_IMAGES_UPLOAD_DIR, 'stamp.bmp')) logo = models.ImageField(u'Логотип', blank=True, default='', upload_to=upload_to(PROFILE_IMAGES_UPLOAD_DIR, 'logo.bmp')) 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) user_session_key = models.CharField(u'Ключ сессии (служебная информация)', max_length=256, blank=True, default='', help_text=u'Руками не тро...') objects = managers.UserProfileManager() class Meta: verbose_name = u'Реквизиты (профиль)' verbose_name_plural = u'Реквизиты (профили)' def __unicode__(self): return u'%s, ИНН %s' % (self.get_company_name()[0:30], self.inn or u'не указан') def save(self, *args, **kwargs): self.inn = only_numerics(self.inn) self.ogrn = only_numerics(self.ogrn) self.okpo = only_numerics(self.okpo) self.kpp = only_numerics(self.kpp) def process_img(orig_img, size): w = orig_img.width h = orig_img.height if w > size[0] or h > size[1]: filename = str(orig_img.path) img = Image.open(filename).convert("RGB") img.thumbnail(size, Image.ANTIALIAS) img.save(filename, 'BMP') super(UserProfile, self).save(*args, **kwargs) if self.boss_sign: process_img(self.boss_sign, size=BOSS_SIGN_IMG_SIZE) if self.glavbuh_sign: process_img(self.glavbuh_sign, size=GLAVBUH_SIGN_IMG_SIZE) if self.stamp: process_img(self.stamp, size=STAMP_IMG_SIZE) if self.logo: process_img(self.logo, size=LOGO_SIZE) def is_ip(self): return self.profile_type == consts.IP_PROFILE def is_org(self): return self.profile_type == consts.ORG_PROFILE def check_name_not_filled(self): """`ИП ФИО` или `Название Организации`.""" if self.is_ip(): return self.get_boss_full_fio().strip() == '' elif self.is_org(): return self.name.strip() == '' return False def get_main_bank_account(self): try: bank_accounts = BankAccount.objects.filter(company=self, is_main=True)[0] except: return None def get_first_user(self): try: first_user = DokUser.objects.filter(profile=self)[0] return first_user except: return None 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() == '' if result: return True if self.is_ip(): return self.ogrn == '' elif self.is_org(): return self.kpp == '' def get_company_name(self): """`ИП ФИО` или `Название Организации`.""" if self.profile_type == consts.IP_PROFILE: return u'ИП %s' % self.get_boss_full_fio() elif self.profile_type == consts.ORG_PROFILE: return self.name.strip() return u'' 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 self.inn def get_boss_title(self): """Текст 'Индивидуальный предприниматель' или 'Руководитель организации'.""" if self.profile_type == consts.IP_PROFILE: return u'Индивидуальный предприниматель' elif self.profile_type == consts.ORG_PROFILE: return u'Руководитель организации' return u'' 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'' def get_boss_full_fio(self): """Полное ФИО руководителя ИП/организации.""" return (u'%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'' def get_glavbuh_full_fio(self): """Полное ФИО главного бухгалтера.""" return (u'%s %s %s' % (self.glavbuh_surname, self.glavbuh_name, self.glavbuh_midname,)).strip() 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() def get_email(self): try: return self.get_first_user().email except: return None 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() 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) short_name = models.CharField(u'Сокращенное название банка', max_length=100, blank=True, default='') address = models.CharField(u'Местонахождение', max_length=256, blank=True, default='') # TODO delete field? korr_account = models.CharField(u'Корр. счет', max_length=20) account = models.CharField(u'Расчетный счет', max_length=20) is_main = models.BooleanField(u'Основной счет', default=False) created_at = models.DateTimeField(u'Создан', auto_now_add=True) updated_at = models.DateTimeField(u'Изменен', auto_now=True) objects = managers.BankAccountManager() class Meta: verbose_name = u'Расчётный счет' verbose_name_plural = u'Расчётные счета' ordering = ['-created_at'] def __unicode__(self): return (u'%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) self.korr_account = only_numerics(self.korr_account) self.account = only_numerics(self.account) super(BankAccount, self).save(*args, **kwargs) if self.is_main: # если задано, что это будет основной счет, то сбросить у остальных счетов пользователя этот признак BankAccount.objects.filter(company=self.company, is_main=True).exclude(pk=self.pk).update(is_main=False) else: # если нет основного счета, то установить его принудительно BankAccount.objects.force_main(company=self.company) def delete(self, *args, **kwargs): super(BankAccount, self).delete(*args, **kwargs) # если нет основного счета, то установить его принудительно BankAccount.objects.force_main(company=self.company) class Client(models.Model): """Контрагенты.""" company = models.ForeignKey(UserProfile, related_name='clients') name = models.CharField(u'Наименование', max_length=256, db_index=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) # банковские реквизиты bank_bik = models.CharField(u'БИК', max_length=10, blank=True, default='') bank_name = models.CharField(u'Наименование банка', max_length=256, blank=True, default='') bank_address = models.CharField(u'Местонахождение', max_length=256, blank=True, default='') # TODO delete field? bank_korr_account = models.CharField(u'Корр. счет', max_length=20, blank=True, default='') bank_account = models.CharField(u'Расчетный счет', 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='') created_at = models.DateTimeField(u'Создан', auto_now_add=True) updated_at = models.DateTimeField(u'Изменен', auto_now=True) objects = managers.ClientManager() class Meta: verbose_name = u'Контрагент' verbose_name_plural = u'Контрагенты' ordering = ['name', '-created_at'] def __unicode__(self): return (u'%s, ИНН %s' % (self.name[0:30], self.inn or u'не указан',)).strip() def save(self, *args, **kwargs): self.inn = only_numerics(self.inn) self.kpp = only_numerics(self.kpp) self.ogrn = only_numerics(self.ogrn) self.okpo = only_numerics(self.okpo) self.bank_bik = only_numerics(self.bank_bik) self.bank_korr_account = only_numerics(self.bank_korr_account) self.bank_account = only_numerics(self.bank_account) super(Client, self).save(*args, **kwargs) def get_inn_and_kpp(self): """Возвращает пару ИНН/КПП или только ИНН, если КПП не заполнен.""" kpp = self.kpp.strip() if kpp: return u'%s/%s' % (self.inn, kpp,) return self.inn class UserProfileFilters(models.Model): """Фильтрация реквизитов: какие данные показывать/скрывать при генерации карточки компании.""" company = models.OneToOneField(UserProfile, related_name='profile_filters', primary_key=True) # общие фильтры show_profile_type = models.BooleanField(u'Тип профиля', default=True) show_inn = models.BooleanField(u'ИНН', default=True) show_ogrn = models.BooleanField(u'ОГРН/ОГРНИП', default=True) show_okpo = models.BooleanField(u'ОКПО', default=True) show_glavbuh = models.BooleanField(u'Главный бухгалтер', default=True) show_bank_account = models.BooleanField(u'Банковские реквизиты', default=True) bank_account = models.ForeignKey(BankAccount, related_name='+', verbose_name=u'Расчетный счет', 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_logo = models.BooleanField(u'Логотип', 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_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_na_osnovanii = models.BooleanField(u'Действует на основании', default=True) objects = managers.UserProfileFiltersManager() class Meta: verbose_name = u'Фильтры реквизитов' verbose_name_plural = u'Фильтры реквизитов' def __unicode__(self): return u'%s' % self.user.email def save(self, *args, **kwargs): # всегда включены self.show_ip_boss_fio = True self.show_name = True super(UserProfileFilters, self).save(*args, **kwargs) class License(models.Model): company = models.ForeignKey(UserProfile, related_name='licenses', verbose_name=u'пользователь') 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'форма оплаты', choices=consts.PAYFORMS, default=0) status = models.IntegerField(verbose_name=u'статус лицензии', 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) def __init__(self, *args, **kwargs): super(License, self).__init__(*args, **kwargs) self.__prev_date = self.paid_date def __unicode__(self): return u'%s - %s %s (%d %s)' % ( self.company.get_company_name(), self.term, numeral.choose_plural(self.term, u"месяц, месяца, месяцев"), self.pay_sum, numeral.choose_plural(self.pay_sum, u"рубль, рубля, рублей"), ) def save(self, *args, **kwargs): if not self.__prev_date and self.paid_date: max_date_license = License.objects.filter(company=self.company).aggregate(Max('date_to'))['date_to__max'] today = datetime.now().date() if max_date_license < today: max_date_license = today - timedelta(1) self.date_from = max_date_license + relativedelta(days=1) self.date_to = self.date_from + relativedelta(months=self.term, days=-1) self.company.active = True self.company.save() self.status = 1 utils.check_one_profile(self.company, License, datetime.now(), manual=True) super(License, self).save(*args, **kwargs) def get_company(self): return self.company.get_company_name() def get_action_link(self): if self.status == 0: if self.payform == 0: return u'Скачать счёт' % reverse('customer_license_get_doc', kwargs={'order_num': self.id}) elif self.payform == 1: return u'Оплатить счёт' elif self.payform == 2: return u'Скачать квитанцию' % reverse('customer_license_get_doc', kwargs={'order_num': self.id}) elif self.status in [1, 2]: return u'История операций' else: return '' def get_term(self): if self.term == 0: return u'45 дней' else: return u'%s %s' % (self.term, numeral.choose_plural(self.term, u"месяц, месяца, месяцев"), ) def get_paid_status(self): if self.status == 1: return u'Лицензия оплачена, ещё не активирована' 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"день, дня, дней"), ) else: left_str = '%d %s' % ( left.days, numeral.choose_plural(left.days, u"день, дня, дней"), ) return u'Лицензия активирована: осталось %s' % left_str elif self.status == 3: return u'Время истекло' else: return None class LicensePrice(models.Model): term = models.IntegerField(verbose_name=u'срок лицензии', choices=consts.TERMS) price = models.IntegerField(verbose_name=u'сумма оплаты') def __unicode__(self): return u'%s %s (%d %s)' % (self.term, numeral.choose_plural(self.term, u"месяц, месяца, месяцев"), self.price, numeral.choose_plural(self.price, u"рубль, рубля, рублей"), )