diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py
index 781af25e..e393aac9 100644
--- a/api/v1/serializers/course.py
+++ b/api/v1/serializers/course.py
@@ -128,6 +128,7 @@ class CourseCreateSerializer(DispatchContentMixin,
'from_author',
'cover',
'price',
+ 'old_price',
'age',
'is_infinite',
'deferred_start_at',
@@ -280,6 +281,7 @@ class CourseSerializer(DynamicFieldsMixin, serializers.ModelSerializer):
'from_author',
'cover',
'price',
+ 'old_price',
'age',
'is_infinite',
'deferred_start_at',
diff --git a/api/v1/serializers/payment.py b/api/v1/serializers/payment.py
index 8d50f217..7c48cf46 100644
--- a/api/v1/serializers/payment.py
+++ b/api/v1/serializers/payment.py
@@ -3,7 +3,7 @@ from rest_framework import serializers
from apps.payment.models import (
AuthorBalance, Payment,
CoursePayment, SchoolPayment,
- GiftCertificatePayment)
+ GiftCertificatePayment, UserBonus,)
from .user import UserSerializer
from .course import CourseSerializer
@@ -200,3 +200,68 @@ class GiftCertificatePaymentSerializer(serializers.ModelSerializer):
'created_at',
'update_at',
)
+
+
+class UserBonusCreateSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = UserBonus
+ fields = (
+ 'user', 'amount', 'payment', 'referral', 'created_at', 'is_service', 'action_name',
+ )
+ read_only_fields = (
+ 'id',
+ 'created_at',
+ )
+
+ def to_representation(self, instance):
+ return UserBonusSerializer(instance, context=self.context).to_representation(instance)
+
+
+class UserBonusSerializer(serializers.ModelSerializer):
+ user = UserSerializer()
+ payment = serializers.SerializerMethodField()
+ referral = serializers.SerializerMethodField()
+
+ class Meta:
+ model = UserBonus
+ fields = (
+ 'user', 'amount', 'payment', 'referral', 'created_at', 'is_service', 'action_name',
+ )
+ read_only_fields = (
+ 'id',
+ 'user',
+ 'created_at',
+ )
+
+ def get_payment(self, instance):
+ try:
+ p = instance.payment
+ except Exception:
+ return None
+ if not p:
+ return None
+ data = {
+ 'id': p.id,
+ 'created_at': p.created_at,
+ 'amount': p.amount,
+ 'data': p.data,
+ 'status': p.status,
+ }
+ if isinstance(instance.payment, CoursePayment):
+ data['course'] = {
+ 'id': p.course.id,
+ 'title': p.course.title,
+ }
+ return data
+
+ def get_referral(self, instance):
+ try:
+ r = instance.referral
+ except Exception:
+ return None
+ if not r:
+ return None
+ return {
+ 'id': r.id,
+ 'referral': UserSerializer(instance=r.referral).data,
+ }
diff --git a/api/v1/urls.py b/api/v1/urls.py
index b86acbbc..07baaaf1 100644
--- a/api/v1/urls.py
+++ b/api/v1/urls.py
@@ -19,7 +19,7 @@ from .views import (
SchoolScheduleViewSet, LiveLessonViewSet,
PaymentViewSet, ObjectCommentsViewSet,
ContestViewSet, ContestWorkViewSet,
- AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet)
+ AuthorBalanceUsersViewSet, CaptureEmail, FAQViewSet, UserGalleryViewSet, BonusesViewSet)
router = DefaultRouter()
router.register(r'author-requests', AuthorRequestViewSet, base_name='author-requests')
@@ -43,10 +43,9 @@ router.register(r'galleries', GalleryViewSet, base_name='galleries')
router.register(r'gallery-images', GalleryImageViewSet, base_name='gallery-images')
router.register(r'faq', FAQViewSet, base_name='faq')
router.register(r'school-schedules', SchoolScheduleViewSet, base_name='school-schedules')
-
+router.register(r'bonuses', BonusesViewSet, base_name='bonuses')
router.register(r'users', UserViewSet, base_name='users')
router.register(r'user-gallery', UserGalleryViewSet, base_name='user-gallery')
-
router.register(r'contests', ContestViewSet, base_name='contests')
router.register(r'contest-works', ContestWorkViewSet, base_name='contest_works')
diff --git a/api/v1/views.py b/api/v1/views.py
index 3164c00a..c2b43019 100644
--- a/api/v1/views.py
+++ b/api/v1/views.py
@@ -39,7 +39,7 @@ from .serializers.school import (
)
from .serializers.payment import (
AuthorBalanceSerializer, AuthorBalanceCreateSerializer,
- PaymentSerializer,
+ PaymentSerializer, UserBonusSerializer, UserBonusCreateSerializer,
CoursePaymentCreateSerializer, SchoolPaymentCreateSerializer)
from .serializers.user import (
AuthorRequestSerializer,
@@ -68,7 +68,7 @@ from apps.content.models import (
Contest, ContestWork, FAQ)
from apps.payment.models import (
AuthorBalance, Payment,
- CoursePayment, SchoolPayment,
+ CoursePayment, SchoolPayment, UserBonus,
)
from apps.school.models import SchoolSchedule, LiveLesson
from apps.user.models import AuthorRequest
@@ -724,7 +724,37 @@ class CaptureEmail(views.APIView):
return Response({'status': 'ok'})
-
class FAQViewSet(ExtendedModelViewSet):
queryset = FAQ.objects.all()
serializer_class = FAQSerializer
+
+
+class BonusesViewSet(ExtendedModelViewSet):
+ queryset = UserBonus.objects.all()
+ serializer_class = UserBonusCreateSerializer
+ serializer_class_map = {
+ 'list': UserBonusSerializer,
+ }
+ permission_classes = (IsAdmin,)
+ filter_fields = ('user', 'referral', 'payment', 'is_service', 'action_name')
+ search_fields = (
+ 'action_name',
+ 'user__email',
+ 'user__first_name',
+ 'user__last_name',
+ 'referral__referral__email',
+ 'referral__referral__first_name',
+ 'referral__referral__last_name',
+ )
+
+ def list(self, request, *args, **kwargs):
+ queryset = self.filter_queryset(self.get_queryset())
+
+ if request.query_params.get('page'):
+ page = self.paginate_queryset(queryset)
+ if page is not None:
+ serializer = self.get_serializer(page, many=True)
+ return self.get_paginated_response(serializer.data)
+
+ serializer = self.get_serializer(queryset, many=True)
+ return Response(serializer.data)
diff --git a/apps/course/migrations/0047_course_old_price.py b/apps/course/migrations/0047_course_old_price.py
new file mode 100644
index 00000000..5c389496
--- /dev/null
+++ b/apps/course/migrations/0047_course_old_price.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.0.7 on 2019-01-13 23:55
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('course', '0046_auto_20181009_2334'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='course',
+ name='old_price',
+ field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='Старая цена курса'),
+ ),
+ ]
diff --git a/apps/course/models.py b/apps/course/models.py
index 6272a318..42a1dd81 100644
--- a/apps/course/models.py
+++ b/apps/course/models.py
@@ -80,6 +80,10 @@ class Course(BaseModel, DeactivatedMixin):
verbose_name='Обложка курса', on_delete=models.SET_NULL,
null=True, blank=True,
)
+ old_price = models.DecimalField(
+ 'Старая цена курса',
+ max_digits=10, decimal_places=2, null=True, blank=True
+ )
price = models.DecimalField(
'Цена курса', help_text='Если цена не выставлена, то курс бесплатный',
max_digits=10, decimal_places=2, null=True, blank=True
@@ -132,7 +136,7 @@ class Course(BaseModel, DeactivatedMixin):
return self.get_absolute_url()
def get_absolute_url(self):
- return reverse_lazy('course', args=[self.id])
+ return reverse_lazy('course', args=[self.slug or self.id])
@property
def is_free(self):
diff --git a/apps/course/templates/course/_items.html b/apps/course/templates/course/_items.html
index ff72a87d..a5bfa123 100644
--- a/apps/course/templates/course/_items.html
+++ b/apps/course/templates/course/_items.html
@@ -7,7 +7,7 @@
data-course data-course-id={{ course.id }}
{% if course.is_deferred_start and course.status == 2 %}data-future-course data-future-course-time={{ course.deferred_start_at.timestamp }}{% endif %}
>
-
+
{% thumbnail course.cover.image "300x200" crop="center" as im %}
{% empty %}
@@ -50,10 +50,13 @@
{{ course.category | upper }}
{% if not course.is_free %}
+ {% if course.old_price %}
+