-
-
-
-
{% endif %}
{% endblock content %}
+
+{% block foot %}
+{% include "templates/blocks/popup_course_buy.html" %}
+{% endblock foot %}
diff --git a/apps/course/tests/__init__.py b/apps/course/tests/__init__.py
new file mode 100644
index 00000000..7230f40d
--- /dev/null
+++ b/apps/course/tests/__init__.py
@@ -0,0 +1,8 @@
+# TODO: test_course_access_duration
+'''
+сделать поле "продолжительность доступа" у курсов: автор указывает продолжительность,
+после покупки по истечению указанного кол-ва дней у пользователя нет доступа к курсу,
+но он может его купить с 50% скидкой, при покупке курса появляется надпись "осталось Х дней доступа",
+так же за неделю до окончания можно купить курс еще раз с 50% скидкой, при этом доступ продлевается
+на указанное кол-во дней в продолжительности
+'''
diff --git a/apps/course/views.py b/apps/course/views.py
index 7ac3297d..fe9d5810 100644
--- a/apps/course/views.py
+++ b/apps/course/views.py
@@ -12,6 +12,7 @@ from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.utils.translation import gettext as _
+from django.utils.timezone import now
from apps.payment.models import AuthorBalance
from .models import Course, Like, Lesson, CourseComment, LessonComment
@@ -231,14 +232,21 @@ class CourseView(DetailView):
context = super().get_context_data(**kwargs)
if self.request.user.is_authenticated:
context['next'] = self.request.GET.get('next', None)
- context['paid'] = self.object.payments.filter(
+ # берем последнюю оплату курса
+ payments = self.object.payments.filter(
user=self.request.user,
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
- ],
- ).exists()
+ ])
+ payment = payments.filter(access_expire__gte=now().date()).order_by('-access_expire').first()
+ context['payment'] = payment
+ context['access_duration'] = ((payment.access_expire - now().date()).days + 1) if payment else self.object.access_duration
+ context['paid'] = bool(payment)
+ context['can_buy_again'] = bool(self.object.price) and (context['access_duration'] < 7 if payment else
+ payments.filter(access_expire__lt=now().date()).exists())
+ context['course_price'] = self.object.price / 2 if context['can_buy_again'] else self.object.price
context['pending'] = self.object.payments.filter(
user=self.request.user,
status=Pingback.PINGBACK_TYPE_RISK_UNDER_REVIEW,
@@ -340,6 +348,7 @@ class LessonView(DetailView):
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
+ access_expire__gte=now().date(),
).exists()
# если это не автор или админ
if not (request.user.is_authenticated and
diff --git a/apps/payment/management/commands/fill_access_expired.py b/apps/payment/management/commands/fill_access_expired.py
new file mode 100644
index 00000000..b9fd134a
--- /dev/null
+++ b/apps/payment/management/commands/fill_access_expired.py
@@ -0,0 +1,18 @@
+from datetime import timedelta
+
+from django.core.management.base import BaseCommand
+from django.db.models import F
+
+from apps.payment.models import CoursePayment
+
+
+class Command(BaseCommand):
+ help = 'Fill payment.access_expire where it is not filled'
+
+ def handle(self, *args, **options):
+
+ for payment in CoursePayment.objects.filter(access_expire__isnull=True):
+ payment.access_expire = payment.created_at.date() + timedelta(days=payment.course.access_duration)
+ payment.save()
+
+
diff --git a/apps/payment/migrations/0031_coursepayment_access_expired.py b/apps/payment/migrations/0031_coursepayment_access_expired.py
new file mode 100644
index 00000000..bf472d32
--- /dev/null
+++ b/apps/payment/migrations/0031_coursepayment_access_expired.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.0.7 on 2019-02-06 17:10
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('payment', '0030_auto_20190114_1649'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='coursepayment',
+ name='access_expired',
+ field=models.DateField(null=True, verbose_name='Доступ к курсу до даты'),
+ ),
+ ]
diff --git a/apps/payment/migrations/0032_auto_20190207_1233.py b/apps/payment/migrations/0032_auto_20190207_1233.py
new file mode 100644
index 00000000..764c08a2
--- /dev/null
+++ b/apps/payment/migrations/0032_auto_20190207_1233.py
@@ -0,0 +1,18 @@
+# Generated by Django 2.0.7 on 2019-02-07 12:33
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('payment', '0031_coursepayment_access_expired'),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name='coursepayment',
+ old_name='access_expired',
+ new_name='access_expire',
+ ),
+ ]
diff --git a/apps/payment/models.py b/apps/payment/models.py
index 5b4e7615..07547e19 100644
--- a/apps/payment/models.py
+++ b/apps/payment/models.py
@@ -152,18 +152,15 @@ class Payment(PolymorphicModel):
elif isinstance(payment, GiftCertificatePayment):
price = payment.gift_certificate.price
elif course:
- price = course.price
+ paid_before = CoursePayment.objects.filter(user=user, course=course, status__in=Payment.PW_PAID_STATUSES).exists()
+ price = course.price / 2 if paid_before else course.price
else:
if user:
school_payments = SchoolPayment.objects.filter(
user=user,
date_start__lte=date_start,
date_end__gte=date_start,
- status__in=[
- Pingback.PINGBACK_TYPE_REGULAR,
- Pingback.PINGBACK_TYPE_GOODWILL,
- Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
- ],
+ status__in=Payment.PW_PAID_STATUSES,
)
school_schedules_purchased = school_payments.annotate(
joined_weekdays=Func(F('weekdays'), function='unnest', )
@@ -265,6 +262,7 @@ class Payment(PolymorphicModel):
class CoursePayment(Payment):
course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='Курс', related_name='payments')
+ access_expire = models.DateField('Доступ к курсу до даты', null=True)
class Meta:
verbose_name = 'Платеж за курс'
diff --git a/apps/payment/views.py b/apps/payment/views.py
index b9491321..31a0f389 100644
--- a/apps/payment/views.py
+++ b/apps/payment/views.py
@@ -67,9 +67,14 @@ class CourseBuyView(TemplateView):
if request.user == course.author:
messages.error(request, 'Вы не можете приобрести свой курс.')
return redirect(reverse_lazy('course', args=[course.id]))
+ prev_payment = CoursePayment.objects.filter(user=request.user, course=course,
+ status__in=Payment.PW_PAID_STATUSES).order_by('-access_expire').first()
+ access_expire = prev_payment.access_expire + timedelta(days=course.access_duration) if prev_payment \
+ else now().date() + timedelta(days=course.access_duration - 1)
course_payment = CoursePayment.objects.create(
user=request.user,
course=course,
+ access_expire=access_expire,
roistat_visit=roistat_visit,
)
if use_bonuses:
diff --git a/project/templates/blocks/popup_course_buy.html b/project/templates/blocks/popup_course_buy.html
index 0498564d..6158a551 100644
--- a/project/templates/blocks/popup_course_buy.html
+++ b/project/templates/blocks/popup_course_buy.html
@@ -37,7 +37,7 @@
Итого:
-
{{ course.price }}р.
+
{{ course_price }}р.