Merge branch 'sales_features' into 'dev'

Sales features

See merge request !261
remotes/origin/yandex_rebiling
Andrey 8 years ago
commit 2239a94edf
  1. 5
      access/views.py
  2. 8
      courses/models.py
  3. 2
      courses/urls.py
  4. 96
      courses/views.py
  5. 6
      finance/models.py
  6. 2
      finance/serializers.py
  7. 149
      finance/views.py

@ -28,7 +28,10 @@ class TeacherListView(APIView):
status_code = 200
def get(self, request):
return Response([i.email for i in get_user_model().objects.filter(groups__name='teachers')], self.status_code)
return Response([{
'email': i.email,
'token': i.out_key,
} for i in get_user_model().objects.filter(groups__name='teachers')], self.status_code)
class ResetPasswordView(APIView):

@ -58,8 +58,6 @@ class Lesson(models.Model):
class Topic(models.Model):
course = models.ForeignKey(to="Course", verbose_name='курс')
title = models.CharField(verbose_name='Название', max_length=255)
description = models.TextField(verbose_name='Описание', blank=True, null=True)
icon = models.ImageField(verbose_name='Иконка темы', null=True, blank=True)
sort = models.SmallIntegerField(verbose_name='Поле сортировки')
def __str__(self):
@ -75,12 +73,12 @@ class Topic(models.Model):
class CourseManager(models.Manager):
def update_or_create_course(self, image=None, big_image=None, statistic=None,
big_mobile_image=None, slug=None, teachers=None,
big_mobile_image=None, slug=None, teacher_tokens=None,
level=None, direction=None, **kwargs):
slug = slug if slug else slugify(unidecode.unidecode(kwargs['title']))
kwargs['teacher_tokens'] = teachers
kwargs['teacher_tokens'] = teacher_tokens
if image:
path = 'course/image%s.png' % slug
@ -101,7 +99,7 @@ class CourseManager(models.Manager):
kwargs['level'] = get_real_name(COURSE_LEVEL, level)
if direction:
kwargs['direction'] = get_real_name(COURSE_DIRECTION, direction)
kwargs['direction'] = get_real_name(COURSE_DIRECTION, direction[0])
try:
course = self.get(slug=slug)

@ -7,5 +7,7 @@ urlpatterns = [
url(r'lesson/(?P<token>.+)/$', views.LessonDetail.as_view()),
url(r'tree/(?P<slug>.+)/$', views.TreeView.as_view()),
url(r'detail/(?P<slug>.+)/$', views.CourseDetailView.as_view()),
url(r'topic/update/$', views.UpdateTopicView.as_view()),
url(r'topic/delete/(?P<topic_id>[0-9]{1,99})/$', views.DeleteTopicView.as_view()),
url(r'^$', views.CourseListView.as_view()),
]

@ -1,17 +1,19 @@
from django.db.models import F
from jwt import DecodeError
from courses.models import Course, Lesson
from courses.models import Course, Lesson, Topic
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from django.contrib.auth import get_user_model
from courses.serializers import CourseDetailSerializer, CourseTreeSerializer, LessonSerializer, TeacherLessonSerializer
from courses.serializers import CourseDetailSerializer, CourseTreeSerializer, LessonSerializer, TeacherLessonSerializer, \
TopicSerializer
import jwt
from courses.tasks import add_lesson
from lms import settings
import json
class TreeView(APIView):
renderer_classes = (JSONRenderer,)
@ -31,27 +33,6 @@ class CourseListView(APIView):
status_code = 200
def post(self, request):
"""
This API endpoint create/update course.
---
parameters:
- name: level
type: string
required: true
location: form
- name: direction
type: string
required: true
location: form
- name: statistic
type: string
required: true
location: form
...
"""
# TODO: Костыль
teachers_emails = request.JSON.get('teachers', [])
request.JSON['teachers'] = [get_user_model().objects.get(email=i).out_key for i in teachers_emails]
course = Course.objects.update_or_create_course(**request.JSON.dict())
return Response(CourseDetailSerializer(course).data, status=self.status_code)
@ -80,6 +61,69 @@ class CourseDetailView(APIView):
return Response(CourseDetailSerializer(Course.objects.get(slug=slug)).data, self.status_code)
class DeleteTopicView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def delete(request, topic_id):
try:
t = Topic.objects.get(id=topic_id)
except Topic.DoesNotExist:
return Response("Темы не существует", status=404)
t.delete()
return Response(CourseTreeSerializer(t.course).data, status=200)
class UpdateTopicView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def post(request):
topic_id = request.JSON.get('id', None)
sort = request.JSON.get('sort', None)
course_token = request.JSON.get('course_token', None)
title = request.JSON.get('title', None)
if course_token is None:
return Response("Не передан course_token", status=400)
if sort is None:
return Response("Не передан sort", status=400)
try:
course = Course.objects.get(token=course_token)
except Course.DoesNotExist:
return Response("Курс не найден", status=404)
try:
if topic_id:
t = Topic.objects.get(id=topic_id)
if not t.sort == sort:
for topic in reversed():
topic.sort = topic.sort + 1
topic.save()
t.sort = sort
t.title = t.title if title is None else title
t.save()
else:
raise Topic.DoesNotExist()
except Topic.DoesNotExist:
if title is None:
return Response("Не передан title", status=400)
for topic in reversed(course.topic_set.filter(sort__gte=sort)):
topic.sort = topic.sort + 1
topic.save()
Topic.objects.create(
course=course,
title=title,
sort=sort,
)
return Response(CourseTreeSerializer(course).data, status=200)
class LessonInfoView(APIView):
renderer_classes = (JSONRenderer,)
status_code = 200
@ -109,7 +153,7 @@ class LessonDetail(APIView):
l = LessonSerializer(lesson).data
try:
payload = None if jwt_token is None\
payload = None if jwt_token is None \
else jwt.decode(jwt_token, settings.COURSE_PROGRESS_SECRET_KEY, algorithms=['HS256'])
except DecodeError:
payload = None
@ -144,7 +188,7 @@ class LessonDetail(APIView):
if not new_lesson:
return Response("Permission denied", status=403)
#TODO Задача для селери
# TODO Задача для селери
add_lesson(request.user.out_key, course.token, lesson.token, course.get_teacher(), lesson.is_hm)
return Response(l, status=200)

@ -20,6 +20,12 @@ class Bill(models.Model):
def get_full_price(self):
return sum([i.price for i in self.invoice_set.all() if not i.price is None])
def check_validate(self):
return self.invoice_set.filter(is_open=True).count() == 1
def check_pay(self):
return self.invoice_set.filter(status="F").exists()
class Meta:
verbose_name = 'Счет'
verbose_name_plural = 'Счета'

@ -32,7 +32,7 @@ class InvoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Invoice
exclude = ('bill',)
fields = '__all__'
@staticmethod
def get_status(self):

@ -41,7 +41,6 @@ class BillListView(APIView):
if request.user.is_authenticated and (request.user.groups.filter(name__in=['managers','lead_managers']).exists()
or request.user.is_superuser):
bill = request.JSON.get('bill')
children = request.JSON.get('children', [])
if bill:
user = get_user_model().objects.get(email=bill['user'])
@ -60,66 +59,105 @@ class BillListView(APIView):
bill_obj.comment = comment
bill_obj.save()
for i in children:
status = get_real_name(elem=i['status'], array=Invoice.BILL_STATUSES)
try:
invoice_id = i['id']
except KeyError:
invoice_id = None
try:
if not invoice_id is None:
invoice = Invoice.objects.get(id=i['id'])
if invoice.status == "P" or invoice.status == status:
continue
else:
raise Invoice.DoesNotExist
except Invoice.DoesNotExist:
i['method'] = get_real_name(elem=i['method'], array=Invoice.BILL_METHOD)
i['status'] = status
i['bill'] = bill_obj
i['yandex_pay'] = None
invoice = Invoice.objects.create(**i)
if i['method'] == 'Y' and invoice.yandex_pay is None:
yandex_pay = Payment.objects.create(
order_amount=i['price'],
shop_amount=0,
customer_number=bill_obj.user.id,
user=bill_obj.user,
cps_email=bill_obj.user.email,
)
invoice.yandex_pay = yandex_pay
invoice.save()
msg = EmailMessage(
'Выставлен новый счёт.',
'''Менеджер %s выставил счёт пользователю %s на курс "%s".'''
% (
invoice.bill.opener.get_full_name(),
invoice.bill.user.email,
Course.objects.get(token=invoice.bill.course_token).title,
),
'robo@skillbox.ru',
[invoice.bill.opener.email],
bcc=['dmitry.dolya@skillbox.ru'],
)
msg.send()
res = {
"bill": BillSerializer(bill_obj).data,
"children": [InvoiceSerializer(i).data for i in bill_obj.invoice_set.all()],
}
return Response(res, status=200)
return Response(BillSerializer(bill_obj).data, status=200)
return Response("Bill not set", status=400)
return Response("Course detail access only for manager users", status=403)
class InvoiceDetailView(APIView):
renderer_classes = (JSONRenderer,)
@staticmethod
def delete(request):
invoice_id = request.JSON.get('invoice_id', None)
if invoice_id is None:
return Response("invoice_id must be set", status=400)
try:
i = Invoice.objects.get(id=invoice_id)
if not i.status == "F" and not (i.bill.check_pay() and i.is_open):
i.delete()
except Invoice.DoesNotExist:
pass
return Response(status=204)
@transaction_decorator
def post(self, request):
if request.user.is_authenticated and (request.user.groups.filter(name__in=['managers','lead_managers']).exists()
or request.user.is_superuser):
invoice_data = request.JSON.get('invoice', None)
if invoice_data is None:
return Response("Invoice mast be set", status=400)
try:
bill = Bill.objects.get(id=invoice_data.pop('bill'))
except (Bill.DoesNotExist, KeyError):
return Response('Bill id must be set', status=400)
invoice_data['method'] = get_real_name(elem=invoice_data['method'], array=Invoice.BILL_METHOD)
invoice_data['status'] = get_real_name(elem=invoice_data['status'], array=Invoice.BILL_METHOD)
if bill.check_validate() and invoice_data['is_open']:
return Response("Уже есть платёж открывающий курс", status=400)
try:
invoice = Invoice.objects.get(id=invoice_data['id'])
except (Invoice.DoesNotExist, KeyError):
if bill.check_pay():
return Response(
"Нельзя добавить новый платёж, так как один из платежей по счёту уже оплачен", status=400)
invoice = Invoice.objects.create(**invoice_data)
if invoice.status == "F":
return Response(InvoiceSerializer(invoice).data, status=200)
invoice.real_price = None
invoice.method = invoice_data['method']
invoice.status = invoice_data['status']
if invoice.status == "F":
invoice.real_price = invoice_data['real_price']
if bill.check_pay() and (invoice.price < invoice_data['price']):
return Response("""Нельзя менять стоимость по счёту в большую сторону,
когда один из платежей оплачен""", status=400)
invoice.price = invoice_data['price']
invoice.is_open = invoice_data['is_open']
if invoice.method == 'Y' and invoice.yandex_pay is None:
yandex_pay = Payment.objects.create(
order_amount=invoice.price,
shop_amount=0,
customer_number=bill.user.id,
user=bill.user,
cps_email=bill.user.email,
)
invoice.yandex_pay = yandex_pay
msg = EmailMessage(
'Выставлен новый счёт.',
'''Менеджер %s выставил счёт пользователю %s на курс "%s".'''
% (
invoice.bill.opener.get_full_name(),
invoice.bill.user.email,
Course.objects.get(token=invoice.bill.course_token).title,
),
'robo@skillbox.ru',
[invoice.bill.opener.email],
bcc=['dmitry.dolya@skillbox.ru'],
)
msg.send()
invoice.save()
return Response(InvoiceSerializer(invoice).data, status=200)
return Response("Invoice detail access only for manager users", status=403)
class BillDetailView(APIView):
renderer_classes = (JSONRenderer,)
status_code = 200
@ -343,7 +381,6 @@ class YandexAvisoView(APIView):
'response': xml_res,
})
msg = EmailMessage(
'Успешная оплата.',
'''Пользователь "%s", перевёл %s рублей. Номер платежа в яндекс кассе %s'''

Loading…
Cancel
Save