You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

489 lines
24 KiB

# coding=utf-8
import json
import urllib
import datetime
from simplejson import JSONDecodeError
from django.db import models
import django.utils.timezone
from access.models import User, TrafHistory
from lms.settings import BILL_URL, BILL_LOGIN, DOMAIN, YANDEX_SHOP_ID, YANDEX_scid
from lms.tools import random_string, gen_pay_sig, out_uri, out_date_format
from courses.models import Course, MATERIALS_TYPE, CourseMap
from management.letters import sent_created_my_self_bill, sent_new_my_self_bill, new_student, \
pay_no_public_course, sent_new_service_request_to_out
from service.models import MailBox
class Installment(models.Model):
initiative = models.ForeignKey('Price', verbose_name=u'Иниациатива')
user = models.ForeignKey(User, verbose_name=u'Пользователь')
price = models.IntegerField(verbose_name=u'Общая цена')
first_price = models.IntegerField(verbose_name=u'Первый платеж', default=0)
period = models.IntegerField(verbose_name=u'Месяцев на оплату', default=5)
date = models.DateTimeField(verbose_name=u'Дата открытия', default=datetime.datetime.now, editable=False)
f_date = models.DateField(verbose_name=u'Дата закрытия', blank=True)
rest = models.IntegerField(verbose_name=u'Остаток по задолжности', default=0)
wait = models.IntegerField(verbose_name=u'Дней в задолжности', default=0, help_text=u'Через сколько дней '
u'предоставлять доступ после '
u'просрочки')
expired = models.BooleanField(verbose_name=u'Просрочено', default=False)
payments = models.ManyToManyField('Bill', verbose_name=u'Платежи', blank=True, null=True, related_name='bill_point')
def __str__(self):
return '%s %s' % (self.user, self.price)
def __unicode__(self):
return u'%s %s' % (self.user, self.price)
class Meta:
verbose_name = u'Рассрочка'
verbose_name_plural = u'Рассрочки'
class Price(models.Model):
# Цены
freepay = models.BooleanField(verbose_name=u'Свободный счет', default=False, editable=False)
m_type = models.CharField(verbose_name=u'Тип подписки', max_length=1, choices=MATERIALS_TYPE, default='B')
key = models.CharField(verbose_name=u'Ключ доступа', max_length=255, blank=True, editable=False, null=True)
url = models.URLField(verbose_name=u'Ссылка на оплату', blank=True, null=True, editable=False)
public = models.BooleanField(verbose_name=u'Опубликовать', default=False)
title = models.CharField(verbose_name=u'Услуга', max_length=255, help_text=u'Будет показано пользователям')
cost = models.IntegerField(verbose_name=u'Цена')
course = models.ForeignKey(Course, verbose_name=u'Курс', null=True, blank=True)
description = models.TextField(verbose_name=u'Описание', help_text=u'Будет показано менеджерам')
included = models.ManyToManyField(CourseMap, verbose_name=u'Включены', null=True, blank=True,
help_text=u'Если задействовать эту функцию, стандартная схема подписок будет '
u'не активна')
by_time = models.IntegerField(verbose_name=u'Дней доступа', default=0, blank=True, null=True,
help_text=u'По истечении этого периода доступ будет закрыт для включений.')
post_fire = models.IntegerField(verbose_name=u'Дней сгорания', default=0,
help_text=u'Предоставлении 50% скиндки на X дней. Сработает только при наличии "дней доступа"')
def get_name(self):
return '{1} / {0}'.format(self.course.get_title(), self.title) if self.course else self.title
def __str__(self):
return '%s / %s %s' % (self.course, self.title, self.cost)
def __unicode__(self):
return u'%s / %s %s' % (self.course, self.title, self.cost)
def check_points(self):
# Проверка существования всех точек курса в услуге
results = 0
for point in CourseMap.objects.filter(course=self.course):
if not self.included.filter(id=point.id).exists():
self.included.add(point)
results += 1
return results
def save(self, *args, **kwargs):
if not self.key:
self.key = random_string(length=50)
if self.key and not self.url:
self.url = DOMAIN + '/wallet/pay/self_bill/' + self.key
if not self.course and not self.freepay:
self.freepay = True
elif self.course and self.freepay:
self.freepay = False
super(Price, self).save(*args, **kwargs)
class Meta:
verbose_name = u'Услуга'
verbose_name_plural = u'Услуги'
ordering = ['-id']
class Bill(models.Model):
BILL_STATUSES = (
('W', u'Ожидание согласия'),
('P', u'На оплате'),
('F', u'Оплачен'),
('C', u'Отклонен'),
('B', u'Отклонен банком'),
('H', u'Сгорел')
)
BILL_METHOD = (
('C', u'Наличные'),
('H', u'JustClick'),
('B', u'Банковский перевод'),
('G', u'На расчетный счет'),
('A', u'Альфа-Банк'),
('P', u'PayPal'),
('W', u'WebMoney'),
('S', u'SimplePay'),
('Y', u'YandexKassa')
)
gift = models.BooleanField(verbose_name=u'Подарок', default=False)
status = models.CharField(verbose_name=u'Статус', max_length=1, default='W', choices=BILL_STATUSES)
_method = models.CharField(verbose_name=u'Способ оплаты', max_length=2, default='Y', choices=BILL_METHOD)
price = models.CharField(verbose_name=u'Сумма', max_length=255, null=True, blank=True)
real_price = models.CharField(verbose_name=u'Полученная сумма', max_length=255, null=True, blank=True,
help_text=u'Сумма, минус комиссия')
traf_source = models.ForeignKey(TrafHistory, verbose_name=u'Обращение', blank=True, null=True, editable=False)
service = models.ForeignKey(Price, verbose_name=u'Оплачиваемая услуга')
inside_data = models.TextField(verbose_name=u'Данные проверки', default='', blank=True, editable=False)
#
user = models.ForeignKey(User, verbose_name=u'Плательщик', related_name=u'bill_user')
opener = models.ForeignKey(User, verbose_name=u'Открывший', related_name=u'bill_opener', null=True)
manager = models.ForeignKey(User, verbose_name=u'Менеджер', related_name=u'bill_manager', editable=False, null=True)
#
source_key = models.CharField(verbose_name=u'Исходник ключа', blank=True, max_length=255, default='', editable=False)
key = models.CharField(verbose_name=u'Ключ платежа', blank=True, max_length=255, default='', editable=False)
out_id = models.CharField(verbose_name=u'ID внешнего заказа', max_length=100, blank=True, default='', editable=False)
admitad_uid = models.CharField(verbose_name=u'Ключь admitad', max_length=100, blank=True, default='', editable=False)
date = models.DateTimeField(verbose_name=u'Дата создания счета', default=django.utils.timezone.now, editable=False)
status_changed = models.DateTimeField(verbose_name=u'Дата смены статуса', default=django.utils.timezone.now, editable=False)
comment = models.TextField(verbose_name=u'Комментарий продавца', help_text=u'Будет показано пользователю',
blank=True, editable=False)
description = models.TextField(verbose_name=u'Внутренняя заметка', help_text=u'Показано только внутри', default='',
blank=True)
finish_date = models.DateTimeField(verbose_name=u'Дата завершения', blank=True, null=True, editable=False)
salt = models.CharField(verbose_name=u'Соль', max_length=100, blank=True, default=random_string, editable=False)
views = models.IntegerField(verbose_name=u'Показать напоминание', default=0, help_text=u'Количество показов '
u'напоминания', blank=True)
start_fire = models.DateTimeField(verbose_name=u'Дата начала сгорания', blank=True, null=True)
start_fire_sent = models.BooleanField(verbose_name=u'Письмо сгорания', default=False, editable=False)
fire_date = models.DateTimeField(verbose_name=u'Дата сгорания', blank=True, null=True)
fire_date_sent = models.BooleanField(verbose_name=u'Письмо сгорания', default=False, editable=False)
modals_show = models.BooleanField(verbose_name=u'Модалки показаны', default=False, editable=False)
created_sent = models.BooleanField(verbose_name=u'Отправлено письмо сформированного счета', default=False, editable=False)
create_letters = models.ManyToManyField(MailBox, verbose_name=u'Письма при создании', null=True, blank=True, related_name='bill_create_letter', editable=False)
finish_letters = models.ManyToManyField(MailBox, verbose_name=u'Письма завершения', null=True, blank=True, related_name='bill_finish_letter', editable=False)
def __unicode__(self):
return u'%s:%s %s %s' % (self.id, self.get_status_display(), self.user, self.manager if self.manager else '')
def __str__(self):
return '%s:%s %s %s' % (self.id, self.get_status_display(), self.user, self.manager if self.manager else '')
def get_face(self):
return {
'id': self.id,
'price': self.price,
'status': {'flag': self.status, 'title': self.get_status_display()},
'admitad_uid': self.admitad_uid,
'pay_url': '{0}/wallet/bill_out/{1}'.format(DOMAIN, self.salt),
'service': self.service.key,
'gift': self.gift,
'title': self.get_name(),
'user': '<span style="background: #333;color: #fff;font-weight: bold;padding: 3px 10px;border: 2px solid #ff1;">{0} / {1} / {2}</span>'.format(self.user.get_full_name(), self.user.get_phone(), self.user.email),
'manager': self.manager.get_short_name() if self.manager else ''
}
def get_name(self):
if self.service:
return self.service.get_name()
else:
return 'Свободный счет ID:{0}'.format(self.id)
# TODO: Что это вообще такое? Это далеко не статус
def get_status_flag(self):
if not self.service.by_time and not self.service.included.exists():
return self.service.m_type
elif self.service.by_time:
return 'S'
elif self.service.included.exists():
return 'F'
def get_type(self):
if self.installment:
return 'I'
elif self.freeprice:
return 'F'
elif self.service:
return 'S'
def get_pay_parameters(self):
# Получение параметров для создания подписи
parameters = {
'sp_amount': self.price,
'sp_description': '{0} {1} Заказ: ID{2} Менеджер: {3}'.format(self.get_name(), self.user.full_data(), self.id, self.manager.get_short_name() if self.manager else ''),
'sp_order_id': self.id,
'sp_outlet_id': BILL_LOGIN,
'sp_salt': self.salt,
'sp_user_name': self.user.get_full_name(),
'sp_user_phone': self.user.get_phone(),
'sp_user_contact_email': self.user.email,
'sp_user_ip': self.user.get_ip(), # IP пользователя, совершающего платеж
'sp_user_params': '', # Параметры, передаваемые на ResultURL по этому запросу,
}
result = {}
for key, value in parameters.items():
if value: result[key] = value
return result
def get_comment(self):
return '{0} {1} Заказ: ID{2} Менеджер: {3}'.format(self.get_name(), self.user.full_data(), self.id, self.manager.get_short_name() if self.manager else '')
def gen_robokassa_url(self):
_params = self.get_pay_parameters()
_params['sp_sig'] = gen_pay_sig(_params, method='payment', result=False)
#for key, value in _params.items():
# if value: result += '%s=%s&' % (key, value)
return out_uri(BILL_URL, _params)
def gen_yandex_data(self):
return {'url': 'https://money.yandex.ru/eshop.xml', 'data': {'shopId': YANDEX_SHOP_ID,
'scid': YANDEX_scid,
'orderNumber': self.id,
'customerNumber': self.user.id,
'sum': self.price}}
def gen_pay_link(self):
return '{0}/wallet/bill_out/{1}'.format(DOMAIN, self.salt)
def save(self, *args, **kwargs):
if self.price == '0' or self.gift:
self.finish_date = datetime.datetime.now()
self.status_changed = datetime.datetime.now()
self.gift = True
self.status = 'F'
else:
if not self.comment:
self.comment = self.get_comment()
if not self.salt:
self.salt = random_string()
if not self.price:
self.price = self.service.cost
if (self.service.by_time and self.finish_date) and self.service.post_fire and not self.fire_date:
self.fire_date = self.finish_date + datetime.timedelta(days=(self.service.by_time+self.service.post_fire))
if (self.service.by_time and self.finish_date) and not self.start_fire:
self.start_fire = self.finish_date + datetime.timedelta(days=self.service.by_time)
if self.fire_date or self.views:
self._type = 'P'
if not self.opener:
if self.status == 'W' and self.price != 0 and not self.created_sent:
if self.manager and self.manager.in_role in ['M', 'S'] and not self.traf_source:
for supervisor in User.objects.filter(in_role='S'):
sent_new_my_self_bill(self, supervisor.email)
self.created_sent = True
if (self.status == 'F' or self.status == 'C') and not self.finish_date:
self.finish_date = django.utils.timezone.now()
if self.status == 'F' and not self.gift:
self.user.customer = True
self.user.save()
# Отправить письма куратору
if self.service and self.service.course:
if self.service.course.public:
for mentor in self.service.course.get_mentors():
new_student(self, mentor.email)
else:
for mentor in self.service.course.get_mentors():
pay_no_public_course(self, mentor.email)
if self.manager and self.manager.in_role in ['M', 'S'] and not self.traf_source:
title = 'Оплата отклонена' if self.status == 'C' else 'Счет оплачен'
sent_created_my_self_bill(self, self.manager.email, title)
for supervisor in User.objects.filter(in_role='S'):
sent_created_my_self_bill(self, supervisor.email, title)
super(Bill, self).save(*args, **kwargs)
class Meta:
verbose_name = u'Счет'
verbose_name_plural = u'Счета'
class ServiceRequest(models.Model):
SERVICE_REQUEST_STATUS = (
('S', u'Не обработан'),
('E', u'Ошибка контекста'),
('W', u'В работе'),
('F', u'Продан'),
('B', u'Не продал')
)
BY_TYPE = (
('S', 'Органично'),
('B', 'Привлечен')
)
company = models.CharField(verbose_name=u'Компания продавец', max_length=255, blank=True, default='')
product = models.CharField(verbose_name=u'Продукт', max_length=255, blank=True, default='')
service = models.CharField(verbose_name=u'Услуга', max_length=255, blank=True, default='')
name = models.CharField(verbose_name=u'Имя', max_length=255, blank=True, default='')
email = models.CharField(verbose_name=u'email', max_length=255, blank=True, default='')
phone = models.CharField(verbose_name=u'phone', max_length=255, blank=True, default='')
lead_name = models.CharField(verbose_name=u'Метка amo', max_length=255, blank=True, default='')
data = models.TextField(verbose_name=u'Данные', help_text=u'Словарь упаковывается в строку', default='')
host = models.CharField(verbose_name=u'Источник запроса', default='', editable=False, max_length=255)
_type = models.CharField(verbose_name=u'Тип запроса', max_length=1, choices=BY_TYPE, default='S')
status = models.CharField(verbose_name=u'Статус', max_length=1, choices=SERVICE_REQUEST_STATUS, default='S')
student = models.ForeignKey(User, verbose_name=u'Студент', related_name='student_user', blank=True, null=True)
course = models.ForeignKey(Course, verbose_name=u'Курс', null=True)
manager = models.ForeignKey(User, verbose_name=u'Продавец', related_name='manager_user', blank=True, null=True)
cancel_description = models.TextField(verbose_name=u'Причина отказа', default='', blank=True)
charge = models.TextField(verbose_name=u'Поручение', default='', blank=True)
date = models.DateTimeField(verbose_name=u'Дата заказа', default=datetime.datetime.now)
f_date = models.DateTimeField(verbose_name=u'Дата обаботки', blank=True, null=True)
send = models.BooleanField(verbose_name=u'Отправлен в AMO', default=False, editable=False)
send_date = models.DateTimeField(verbose_name=u'Время отправки', default=datetime.datetime.now, editable=False)
def get_name(self):
if self.course:
return u'Доступ к курсу "%s"' % self.course.get_title()
else:
return u'Счет: ID%s' % self.id
def get_client_name(self):
_name = ''
if self.student:
_name = self.student.get_full_name()
elif self.name:
_name = self.name
return u'%s' % _name
def get_lead_name(self):
if self.lead_name:
_name = self.lead_name
else:
_product = ''
if self.product:
_product = self.product
elif self.course:
_product = self.course.get_title()
_name = u'%s | %s | %s' % (self.company if self.company else 'LMS',
_product,
self.service if self.service else 'Заявка на покупку')
return u'%s' % _name
def sent_to_amo(self):
if self.data:
try:
data = json.loads(self.data.replace("'", "\""))
except JSONDecodeError:
self.status = "E"
else:
name = ''
phone = ''
email = ''
if self.name:
name = self.name
elif self.student:
name = self.student.get_full_name()
if self.phone:
phone = self.phone
elif self.student:
phone = self.student.get_phone()
if self.email:
email = self.email
elif self.student:
email = self.student.email
data = {
'name': name,
'phone': phone,
'email': email,
'lead_name': self.get_lead_name()
}
if data['name'] == '':
data['name'] = 'empty'
urllib.request.urlopen(out_uri('https://skill-box.ru/amocrm/CreateLead.php', data))
if not self.send and self.status != 'E':
data['host'] = self.host
self.send = True
self.save()
self.send_alert(data)
def __unicode__(self):
return u'%s %s' % (self.status, self.student)
def __str__(self):
return u'%s %s' % (self.status, self.student)
def send_alert(self, data):
# Отправка оповещений
# Получить почты
try:
r = RequestAlert.objects.get(title=self.lead_name)
except RequestAlert.DoesNotExists:
pass
else:
# Отправить письма
for i in r.get_mails():
sent_new_service_request_to_out(self.lead_name, data, i)
def save(self, *args, **kwargs):
super(ServiceRequest, self).save(*args, **kwargs)
class Meta:
verbose_name = u'Запрос на покупку'
verbose_name_plural = u'Запросы на прокупки'
class RequestAlert(models.Model):
title = models.CharField(verbose_name=u'Классификатор', max_length=255, editable=False)
requests = models.ManyToManyField(ServiceRequest, verbose_name=u'Количество заявок', blank=True, null=True, editable=False)
mails = models.TextField(verbose_name=u'Список почт', blank=True,
help_text=u'Кому разослать дубли заявки. ЧЕРЕЗ ТОЧКУ С ЗАПЯТОЙ')
date = models.DateTimeField(verbose_name=u'Начало заявок', default=datetime.datetime.now, editable=False)
f_date = models.DateTimeField(verbose_name=u'Последняя заявка', default=datetime.datetime.now, editable=False)
def __unicode__(self):
return u'%s' % self.title
def __str__(self):
return u'%s' % self.title
def _count(self):
return self.requests.filter(date__gte=self.date).count()
def up_count(self, request):
# Увеличение счетчика
self.requests.add(request)
self.f_date = datetime.datetime.now()
self.save()
def get_mails(self):
return map(lambda x: x.replace(" ", ""), str(self.mails).split(';')) if self.mails else []
def get_mails_str(self):
return str(self.mails)
class Meta:
verbose_name = u'Оповещение о новых заявках'
verbose_name_plural = u'Оповещения о новых заявках'
class YandexKassaHistory(models.Model):
_type = models.CharField(verbose_name=u'Тип запроса', max_length=255, default='')
date = models.DateTimeField(verbose_name=u'Дата', default=datetime.datetime.now)
text = models.TextField(verbose_name=u'Текст')
result = models.CharField(verbose_name=u'Результат', max_length=255, default='')
def __unicode__(self):
return u'%s' % out_date_format(self.date)
def __str__(self):
return str(out_date_format(self.date))
class Meta:
verbose_name = u'Яндекс Касса'
verbose_name_plural = u'Яндекс Касса'