Перейти с PaymentWall на cloudpayments

remotes/origin/feature/cloudpayments
gzbender 7 years ago
parent 7207527052
commit 8d24888d58
  1. 8
      api/v1/views.py
  2. 2
      apps/course/management/commands/fix_access_expire.py
  3. 5
      apps/course/templates/course/course.html
  4. 23
      apps/course/views.py
  5. 3
      apps/notification/tasks.py
  6. 16
      apps/payment/management/commands/roistat_set_statuses.py
  7. 6
      apps/payment/management/commands/send_transactions_to_roistat.py
  8. 18
      apps/payment/migrations/0033_payment_payment_platform.py
  9. 21
      apps/payment/migrations/0034_fill_payment_platform.py
  10. 18
      apps/payment/migrations/0035_auto_20190222_0233.py
  11. 87
      apps/payment/models.py
  12. 30
      apps/payment/templates/payment/cloud_payments_test.html
  13. 55
      apps/payment/templates/payment/cloudpayments_widget.html
  14. 188
      apps/payment/views.py
  15. 4
      apps/school/templates/school/summer_school.html
  16. 21
      apps/school/views.py
  17. 17
      apps/user/models.py
  18. 19
      apps/user/views.py
  19. 8
      project/context_processors.py
  20. 3
      project/settings.py
  21. 6
      project/urls.py
  22. 10
      project/views.py
  23. 1
      web/src/js/modules/popup.js

@ -1,4 +1,3 @@
import json
from datetime import datetime from datetime import datetime
from decimal import Decimal from decimal import Decimal
@ -6,9 +5,8 @@ from django.contrib.auth import get_user_model
from django.db.models import Q from django.db.models import Q
from rest_framework import status, views, viewsets, generics, mixins from rest_framework import status, views, viewsets, generics, mixins
from rest_framework.decorators import (detail_route, list_route, action, from rest_framework.decorators import (detail_route, list_route, action,
permission_classes, authentication_classes as auth_classes) permission_classes)
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.settings import api_settings
from . import ExtendedModelViewSet, BothListFormatMixin from . import ExtendedModelViewSet, BothListFormatMixin
@ -80,7 +78,9 @@ User = get_user_model()
class AuthorBalanceViewSet(ExtendedModelViewSet): class AuthorBalanceViewSet(ExtendedModelViewSet):
queryset = AuthorBalance.objects.filter( queryset = AuthorBalance.objects.filter(
Q(type=1) | Q(payment__status__in=Payment.PW_PAID_STATUSES), Q(type=AuthorBalance.OUT)
| Q(payment__payment_platform=Payment.PAYMENT_PLATFORM_PAYMENTWALL, payment__status__in=Payment.PAID_STATUSES)
| Q(payment__payment_platform=Payment.PAYMENT_PLATFORM_CLOUDPAYMENTS, payment__status=Payment.STATUS_PAID),
# author__role__in=[User.AUTHOR_ROLE, User.ADMIN_ROLE, User.TEACHER_ROLE], # author__role__in=[User.AUTHOR_ROLE, User.ADMIN_ROLE, User.TEACHER_ROLE],
) )
serializer_class = AuthorBalanceCreateSerializer serializer_class = AuthorBalanceCreateSerializer

@ -18,7 +18,7 @@ class Command(BaseCommand):
course.access_duration = access_duration course.access_duration = access_duration
course.save() course.save()
for payment in CoursePayment.objects.filter(status__in=CoursePayment.PW_PAID_STATUSES): for payment in CoursePayment.objects.paid():
payment.access_expire = payment.created_at.date() + timedelta(days=payment.course.access_duration) payment.access_expire = payment.created_at.date() + timedelta(days=payment.course.access_duration)
payment.save() payment.save()

@ -22,6 +22,11 @@
{% block ogdescription %}{{ course.short_description | striptags }}{% endblock ogdescription %} {% block ogdescription %}{{ course.short_description | striptags }}{% endblock ogdescription %}
{% block head %}
{{ block.super }}
<script src="https://widget.cloudpayments.ru/bundles/cloudpayments"></script>
{% endblock head %}
{% block content %} {% block content %}
<div class="section section_border course"> <div class="section section_border course">
<div class="section__center center center_sm"> <div class="section__center center center_sm">

@ -1,6 +1,5 @@
from datetime import timedelta from datetime import timedelta
from paymentwall import Pingback
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.db.models import Q from django.db.models import Q
@ -234,13 +233,8 @@ class CourseView(DetailView):
if self.request.user.is_authenticated: if self.request.user.is_authenticated:
context['next'] = self.request.GET.get('next', None) context['next'] = self.request.GET.get('next', None)
# берем последнюю оплату курса # берем последнюю оплату курса
payments = self.object.payments.filter( payments = self.object.payments.paid().filter(
user=self.request.user, user=self.request.user)
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
])
payment = payments.filter(access_expire__gte=now().date()).order_by('-access_expire').first() payment = payments.filter(access_expire__gte=now().date()).order_by('-access_expire').first()
context['payment'] = payment context['payment'] = payment
context['access_duration'] = ((payment.access_expire - now().date()).days + 1) if payment else self.object.access_duration context['access_duration'] = ((payment.access_expire - now().date()).days + 1) if payment else self.object.access_duration
@ -249,7 +243,8 @@ class CourseView(DetailView):
payments.filter(access_expire__lt=now().date()).exists()) payments.filter(access_expire__lt=now().date()).exists())
context['pending'] = self.object.payments.filter( context['pending'] = self.object.payments.filter(
user=self.request.user, user=self.request.user,
status=Pingback.PINGBACK_TYPE_RISK_UNDER_REVIEW, payment_platform=CoursePayment.PAYMENT_PLATFORM_PAYMENTWALL,
status=CoursePayment.STATUS_PINGBACK_TYPE_RISK_UNDER_REVIEW,
).exists() ).exists()
context['only_lessons'] = self.only_lessons context['only_lessons'] = self.only_lessons
if self.only_lessons: if self.only_lessons:
@ -328,8 +323,7 @@ class CoursesView(ListView):
else: else:
context['age_name'] = '' context['age_name'] = ''
if self.request.user.is_authenticated: if self.request.user.is_authenticated:
can_buy_again_courses = list(CoursePayment.objects.filter(user=self.request.user, can_buy_again_courses = list(CoursePayment.objects.paid().filter(user=self.request.user,
status__in=CoursePayment.PW_PAID_STATUSES,
access_expire__lte=now().date() + timedelta(7)).values_list('course_id', flat=True)) access_expire__lte=now().date() + timedelta(7)).values_list('course_id', flat=True))
for course in context['course_items']: for course in context['course_items']:
if course.id in can_buy_again_courses: if course.id in can_buy_again_courses:
@ -350,13 +344,8 @@ class LessonView(DetailView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
response = super().get(request, *args, **kwargs) response = super().get(request, *args, **kwargs)
paid = request.user.is_authenticated and self.object.course.payments.filter( paid = request.user.is_authenticated and self.object.course.payments.paid().filter(
user=self.request.user, user=self.request.user,
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
access_expire__gte=now().date(), access_expire__gte=now().date(),
).exists() ).exists()
# если это не автор или админ # если это не автор или админ

@ -84,8 +84,7 @@ def sendgrid_update_recipients():
for user in users: for user in users:
last_course_purchase = course_payments.get(user.id) and course_payments.get(user.id).strftime(date_format) last_course_purchase = course_payments.get(user.id) and course_payments.get(user.id).strftime(date_format)
last_school_purchase = school_payments.get(user.id) and school_payments.get(user.id).strftime(date_format) last_school_purchase = school_payments.get(user.id) and school_payments.get(user.id).strftime(date_format)
courses_purchased = CoursePayment.objects.filter(user=user, courses_purchased = CoursePayment.objects.paid().filter(user=user,).values_list('course_id', flat=True)
status__in=CoursePayment.PW_PAID_STATUSES).values_list('course_id', flat=True)
data.append({ data.append({
'first_name': user.first_name, 'first_name': user.first_name,
'last_name': user.last_name, 'last_name': user.last_name,

@ -1,10 +1,10 @@
import requests import requests
from paymentwall import Pingback
from django.conf import settings from django.conf import settings
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from apps.payment.models import Payment
class Command(BaseCommand): class Command(BaseCommand):
help = 'Update statuses on Roistat' help = 'Update statuses on Roistat'
@ -12,32 +12,32 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
body = [ body = [
{ {
'id': str(Pingback.PINGBACK_TYPE_REGULAR), 'id': str(Payment.STATUS_PAID),
'name': 'PINGBACK_TYPE_REGULAR', 'name': 'PINGBACK_TYPE_REGULAR',
'type': 'paid', 'type': 'paid',
}, },
{ {
'id': str(Pingback.PINGBACK_TYPE_GOODWILL), 'id': str(Payment.STATUS_PINGBACK_TYPE_GOODWILL),
'name': 'PINGBACK_TYPE_GOODWILL', 'name': 'PINGBACK_TYPE_GOODWILL',
'type': 'paid', 'type': 'paid',
}, },
{ {
'id': str(Pingback.PINGBACK_TYPE_NEGATIVE), 'id': str(Payment.STATUS_PINGBACK_TYPE_NEGATIVE),
'name': 'PINGBACK_TYPE_NEGATIVE', 'name': 'PINGBACK_TYPE_NEGATIVE',
'type': 'canceled', 'type': 'canceled',
}, },
{ {
'id': str(Pingback.PINGBACK_TYPE_RISK_UNDER_REVIEW), 'id': str(Payment.STATUS_PINGBACK_TYPE_RISK_UNDER_REVIEW),
'name': 'PINGBACK_TYPE_RISK_UNDER_REVIEW', 'name': 'PINGBACK_TYPE_RISK_UNDER_REVIEW',
'type': 'progress', 'type': 'progress',
}, },
{ {
'id': str(Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED), 'id': str(Payment.STATUS_PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED),
'name': 'PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED', 'name': 'PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED',
'type': 'paid', 'type': 'paid',
}, },
{ {
'id': str(Pingback.PINGBACK_TYPE_RISK_REVIEWED_DECLINED), 'id': str(Payment.STATUS_PINGBACK_TYPE_RISK_REVIEWED_DECLINED),
'name': 'PINGBACK_TYPE_RISK_REVIEWED_DECLINED', 'name': 'PINGBACK_TYPE_RISK_REVIEWED_DECLINED',
'type': 'canceled', 'type': 'canceled',
}, },

@ -1,6 +1,4 @@
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand
from django.utils.timezone import now
from paymentwall.pingback import Pingback
from apps.payment.tasks import transaction_to_roistat from apps.payment.tasks import transaction_to_roistat
from apps.payment.models import Payment from apps.payment.models import Payment
@ -22,7 +20,7 @@ class Command(BaseCommand):
start_id = options.get('start_id') start_id = options.get('start_id')
print('start_id=' + str(start_id)) print('start_id=' + str(start_id))
payments = Payment.objects.filter(id__gte=start_id, status__in=Payment.PW_PAID_STATUSES) payments = Payment.objects.paid().filter(id__gte=start_id)
for payment in payments: for payment in payments:
print('TRANSACTION: ' + str(payment.id)) print('TRANSACTION: ' + str(payment.id))

@ -0,0 +1,18 @@
# Generated by Django 2.0.7 on 2019-02-22 02:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('payment', '0032_auto_20190207_1233'),
]
operations = [
migrations.AddField(
model_name='payment',
name='payment_platform',
field=models.PositiveSmallIntegerField(choices=[(1, 'PaymentWall'), (2, 'Cloudpayments')], null=True),
),
]

@ -0,0 +1,21 @@
# Generated by Django 2.0.7 on 2019-02-22 02:14
from django.db import migrations
def forwards(apps, schema_editor):
Payment = apps.get_model('payment', 'Payment')
for payment in Payment.objects.filter(payment_platform__isnull=True):
payment.payment_platform = 1 # PAYMENT_PLATFORM_PAYMENTWALL
payment.save()
class Migration(migrations.Migration):
dependencies = [
('payment', '0033_payment_payment_platform'),
]
operations = [
migrations.RunPython(forwards),
]

@ -0,0 +1,18 @@
# Generated by Django 2.0.7 on 2019-02-22 02:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('payment', '0034_fill_payment_platform'),
]
operations = [
migrations.AlterField(
model_name='payment',
name='payment_platform',
field=models.PositiveSmallIntegerField(choices=[(1, 'PaymentWall'), (2, 'Cloudpayments')], default=2),
),
]

@ -1,9 +1,7 @@
from decimal import Decimal
import arrow import arrow
import short_url import short_url
from django.db.models import Func, F from django.db.models import Func, F, Q
from paymentwall import Pingback
from polymorphic.models import PolymorphicModel from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager from polymorphic.managers import PolymorphicManager
@ -14,7 +12,6 @@ from django.core.validators import RegexValidator
from django.utils.timezone import now from django.utils.timezone import now
from django.conf import settings from django.conf import settings
from apps.content.models import ImageObject
from project.utils import weekdays_in_date_range from project.utils import weekdays_in_date_range
from apps.course.models import Course from apps.course.models import Course
@ -85,24 +82,46 @@ class PaymentManger(PolymorphicManager):
def all(self): def all(self):
return self.filter(status__isnull=False) return self.filter(status__isnull=False)
def paid(self):
return self.filter(
Q(payment_platform=Payment.PAYMENT_PLATFORM_PAYMENTWALL, status__in=Payment.PAID_STATUSES)
| Q(payment_platform=Payment.PAYMENT_PLATFORM_CLOUDPAYMENTS, status=Payment.STATUS_PAID))
class Payment(PolymorphicModel): class Payment(PolymorphicModel):
PW_PAID_STATUSES = [ STATUS_PAID = 0
Pingback.PINGBACK_TYPE_REGULAR, STATUS_PINGBACK_TYPE_GOODWILL = 1
Pingback.PINGBACK_TYPE_GOODWILL, STATUS_PINGBACK_TYPE_NEGATIVE = 2
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, STATUS_PINGBACK_TYPE_RISK_UNDER_REVIEW = 200
STATUS_PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED = 201
STATUS_PINGBACK_TYPE_RISK_REVIEWED_DECLINED = 202
STATUS_PINGBACK_TYPE_RISK_AUTHORIZATION_VOIDED = 203
STATUS_PINGBACK_TYPE_SUBSCRIPTION_CANCELLATION = 12
STATUS_PINGBACK_TYPE_SUBSCRIPTION_EXPIRED = 13
STATUS_PINGBACK_TYPE_SUBSCRIPTION_PAYMENT_FAILED = 14
PAID_STATUSES = [
STATUS_PAID,
STATUS_PINGBACK_TYPE_GOODWILL,
STATUS_PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
] ]
PW_STATUS_CHOICES = ( PW_STATUS_CHOICES = (
(Pingback.PINGBACK_TYPE_REGULAR, 'regular',), (STATUS_PAID, 'regular',),
(Pingback.PINGBACK_TYPE_GOODWILL, 'goodwill',), (STATUS_PINGBACK_TYPE_GOODWILL, 'goodwill',),
(Pingback.PINGBACK_TYPE_NEGATIVE, 'negative',), (STATUS_PINGBACK_TYPE_NEGATIVE, 'negative',),
(Pingback.PINGBACK_TYPE_RISK_UNDER_REVIEW, 'risk under review',), (STATUS_PINGBACK_TYPE_RISK_UNDER_REVIEW, 'risk under review',),
(Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, 'risk reviewed accepted',), (STATUS_PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, 'risk reviewed accepted',),
(Pingback.PINGBACK_TYPE_RISK_REVIEWED_DECLINED, 'risk reviewed declined',), (STATUS_PINGBACK_TYPE_RISK_REVIEWED_DECLINED, 'risk reviewed declined',),
(Pingback.PINGBACK_TYPE_RISK_AUTHORIZATION_VOIDED, 'risk authorization voided',), (STATUS_PINGBACK_TYPE_RISK_AUTHORIZATION_VOIDED, 'risk authorization voided',),
(Pingback.PINGBACK_TYPE_SUBSCRIPTION_CANCELLATION, 'subscription cancelation',), (STATUS_PINGBACK_TYPE_SUBSCRIPTION_CANCELLATION, 'subscription cancelation',),
(Pingback.PINGBACK_TYPE_SUBSCRIPTION_EXPIRED, 'subscription expired',), (STATUS_PINGBACK_TYPE_SUBSCRIPTION_EXPIRED, 'subscription expired',),
(Pingback.PINGBACK_TYPE_SUBSCRIPTION_PAYMENT_FAILED, 'subscription payment failed',), (STATUS_PINGBACK_TYPE_SUBSCRIPTION_PAYMENT_FAILED, 'subscription payment failed',),
)
PAYMENT_PLATFORM_PAYMENTWALL = 1
PAYMENT_PLATFORM_CLOUDPAYMENTS = 2
PAYMENT_PLATFORM_CHOICES = (
(PAYMENT_PLATFORM_PAYMENTWALL, 'PaymentWall'),
(PAYMENT_PLATFORM_CLOUDPAYMENTS, 'Cloudpayments'),
) )
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Пользователь', related_name='payments') user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Пользователь', related_name='payments')
amount = models.DecimalField('Итого', max_digits=8, decimal_places=2, default=0, editable=False) amount = models.DecimalField('Итого', max_digits=8, decimal_places=2, default=0, editable=False)
@ -112,6 +131,7 @@ class Payment(PolymorphicModel):
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True) update_at = models.DateTimeField(auto_now=True)
bonus = models.ForeignKey('payment.UserBonus', null=True, on_delete=models.SET_NULL, related_name='purchase_payments') bonus = models.ForeignKey('payment.UserBonus', null=True, on_delete=models.SET_NULL, related_name='purchase_payments')
payment_platform = models.PositiveSmallIntegerField(choices=PAYMENT_PLATFORM_CHOICES, default=PAYMENT_PLATFORM_CLOUDPAYMENTS)
objects = PaymentManger() objects = PaymentManger()
@ -152,15 +172,14 @@ class Payment(PolymorphicModel):
elif isinstance(payment, GiftCertificatePayment): elif isinstance(payment, GiftCertificatePayment):
price = payment.gift_certificate.price price = payment.gift_certificate.price
elif course: elif course:
paid_before = CoursePayment.objects.filter(user=user, course=course, status__in=Payment.PW_PAID_STATUSES).exists() paid_before = CoursePayment.objects.paid().filter(user=user, course=course).exists()
price = course.price / 2 if paid_before else course.price price = course.price / 2 if paid_before else course.price
else: else:
if user: if user:
school_payments = SchoolPayment.objects.filter( school_payments = SchoolPayment.objects.paid().filter(
user=user, user=user,
date_start__lte=date_start, date_start__lte=date_start,
date_end__gte=date_start, date_end__gte=date_start,
status__in=Payment.PW_PAID_STATUSES,
) )
school_schedules_purchased = school_payments.annotate( school_schedules_purchased = school_payments.annotate(
joined_weekdays=Func(F('weekdays'), function='unnest', ) joined_weekdays=Func(F('weekdays'), function='unnest', )
@ -206,26 +225,26 @@ class Payment(PolymorphicModel):
# TODO change to property # TODO change to property
def is_paid(self): def is_paid(self):
return self.status in self.PW_PAID_STATUSES if self.payment_platform == Payment.PAYMENT_PLATFORM_PAYMENTWALL:
return self.status in self.PAID_STATUSES
if self.payment_platform == Payment.PAYMENT_PLATFORM_CLOUDPAYMENTS:
return self.status == Payment.STATUS_PAID
# TODO? delete ? change to property # TODO? delete ? change to property
def is_deliverable(self): def is_deliverable(self):
return self.status in [ return self.is_paid()
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
]
# TODO change to property # TODO change to property
def is_under_review(self): def is_under_review(self):
return self.status == Pingback.PINGBACK_TYPE_RISK_UNDER_REVIEW return (self.payment_platform == Payment.PAYMENT_PLATFORM_PAYMENTWALL
and self.status == self.STATUS_PINGBACK_TYPE_RISK_UNDER_REVIEW)
# TODO change to property # TODO change to property
def is_cancelable(self): def is_cancelable(self):
return self.status in [ return (self.payment_platform == Payment.PAYMENT_PLATFORM_PAYMENTWALL and self.status in [
Pingback.PINGBACK_TYPE_NEGATIVE, self.STATUS_PINGBACK_TYPE_NEGATIVE,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_DECLINED, self.STATUS_PINGBACK_TYPE_RISK_REVIEWED_DECLINED,
] ])
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
amount_data = Payment.calc_amount(payment=self) amount_data = Payment.calc_amount(payment=self)
@ -284,6 +303,10 @@ class SchoolPayment(Payment):
]) ])
return days return days
@property
def weekdays_str(self):
return ', '.join([SchoolSchedule.WEEKDAY_SHORT_NAMES[wd - 1] for wd in self.weekdays])
@property @property
def date_end_humanize(self): def date_end_humanize(self):
return arrow.get(self.date_end, settings.TIME_ZONE).humanize(locale='ru') return arrow.get(self.date_end, settings.TIME_ZONE).humanize(locale='ru')

@ -1,30 +0,0 @@
{% extends "templates/lilcity/index.html" %} {% load static %}
{% block head %}
<script src="https://widget.cloudpayments.ru/bundles/cloudpayments"></script>
{% endblock head %}
{% block content %}
<button class="btn" id="pay_btn">Pay</button>
{% endblock content %}
{% block foot_js %}
<script>
document.getElementById('pay_btn').onclick = function() {
var widget = new cp.CloudPayments();
widget.charge({ // options
publicId: 'pk_9ae020cd5fed74499dee247067d17', //id из личного кабинета
description: 'Пример оплаты (деньги сниматься не будут)', //назначение
amount: 1, //сумма
currency: 'RUB', //валюта
invoiceId: '{{ invoice_id }}', //номер заказа (необязательно)
// accountId: 'user@example.com', //идентификатор плательщика (необязательно)
data: {
test: true //произвольный набор параметров
}
},
"{% url 'cloud_payments_callback_test' %}?invoice_id={{ invoice_id }}",
"{% url 'cloud_payments_callback_test' %}?invoice_id={{ invoice_id }}");
}
</script>
{% endblock foot_js %}

@ -0,0 +1,55 @@
{% extends "templates/lilcity/index.html" %} {% load static settings %}
{% block head %}
<script src="https://widget.cloudpayments.ru/bundles/cloudpayments"></script>
{% endblock head %}
{% block content %}
<!--<div class="section">
<div class="section__center center">
<div style="margin-bottom: 25px;">
{% if payment.course %}
Курс <b>{{ payment.course.title }}</b>
{% endif %}
{% if payment.gift_certificate %}
Подарочный сертификат на {{ payment.gift_certificate.price }} руб.
{% endif %}
{% if not payment.course and not payment.gift_certificate %}
Подписка на онлайн школу до {{ payment.date_end_humanize }}, {{ payment.weekdays_str }}
{% endif %}
</div>
<button class="btn" id="pay_btn">Оплатить {{ payment.amount }} руб.</button>
</div>
</div> -->
{% endblock content %}
{% block foot_js %}
<script>
function pay() {
var widget = new cp.CloudPayments();
widget.charge({ // options
publicId: '{% setting "CLOUD_PAYMENTS_PUBLIC_ID" %}', //id из личного кабинета
{% if payment.course %}
description: 'Оплата курса {{ payment.course.title }}',
{% endif %}
{% if payment.gift_certificate %}
description: 'Оплата подарочного сертификата на {{ payment.gift_certificate.price }} руб.',
{% endif %}
{% if not payment.course and not payment.gift_certificate %}
description: 'Оплата школы до {{ payment.date_end_humanize }}, {{ payment.weekdays_str }}',
{% endif %}
amount: {{ payment.amount|floatformat }}, //сумма
currency: 'RUB', //валюта
invoiceId: '{{ payment.id }}', //номер заказа (необязательно)
requireEmail: false,
},
function(payment_data){
var url = "{% url 'payment-success' payment.id %}";
},
function(reason){
showNotification(reason);
});
}
pay();
</script>
{% endblock foot_js %}

@ -12,11 +12,11 @@ import random
from cloudpayments import CloudPayments from cloudpayments import CloudPayments
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404, JsonResponse
from django.shortcuts import redirect, get_object_or_404 from django.shortcuts import redirect, get_object_or_404
from django.views.generic import View, TemplateView, DetailView from django.views.generic import View, TemplateView, DetailView
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.urls import reverse_lazy from django.urls import reverse_lazy, reverse
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.timezone import now from django.utils.timezone import now
from django.conf import settings from django.conf import settings
@ -56,9 +56,10 @@ class SchoolBuySuccessView(TemplateView):
@method_decorator(login_required, name='dispatch') @method_decorator(login_required, name='dispatch')
class CourseBuyView(TemplateView): class CourseBuyView(TemplateView):
template_name = 'payment/paymentwall_widget.html' template_name = 'payment/cloudpayments_widget.html'
def get(self, request, pk=None, *args, **kwargs): def get(self, request, pk=None, *args, **kwargs):
#TODO: cloudpayments
use_bonuses = request.GET.get('use_bonuses') use_bonuses = request.GET.get('use_bonuses')
host = urlsplit(self.request.META.get('HTTP_REFERER')) host = urlsplit(self.request.META.get('HTTP_REFERER'))
host = str(host[0]) + '://' + str(host[1]) host = str(host[0]) + '://' + str(host[1])
@ -67,8 +68,7 @@ class CourseBuyView(TemplateView):
if request.user == course.author: if request.user == course.author:
messages.error(request, 'Вы не можете приобрести свой курс.') messages.error(request, 'Вы не можете приобрести свой курс.')
return redirect(reverse_lazy('course', args=[course.id])) return redirect(reverse_lazy('course', args=[course.id]))
prev_payment = CoursePayment.objects.filter(user=request.user, course=course, prev_payment = CoursePayment.objects.paid().filter(user=request.user, course=course).order_by('-access_expire').first()
status__in=Payment.PW_PAID_STATUSES).order_by('-access_expire').first()
access_duration = course.access_duration or 90 access_duration = course.access_duration or 90
access_expire = prev_payment.access_expire + timedelta(days=access_duration) if prev_payment \ access_expire = prev_payment.access_expire + timedelta(days=access_duration) if prev_payment \
else now().date() + timedelta(days=access_duration - 1) else now().date() + timedelta(days=access_duration - 1)
@ -77,12 +77,13 @@ class CourseBuyView(TemplateView):
course=course, course=course,
access_expire=access_expire, access_expire=access_expire,
roistat_visit=roistat_visit, roistat_visit=roistat_visit,
payment_platform=CoursePayment.PAYMENT_PLATFORM_CLOUDPAYMENTS,
) )
if use_bonuses: if use_bonuses:
if request.user.bonus >= course_payment.amount: if request.user.bonus >= course_payment.amount:
bonus = UserBonus.objects.create(amount= -course_payment.amount, user=request.user, payment=course_payment) bonus = UserBonus.objects.create(amount= -course_payment.amount, user=request.user, payment=course_payment)
course_payment.amount = 0 course_payment.amount = 0
course_payment.status = Pingback.PINGBACK_TYPE_REGULAR course_payment.status = Payment.STATUS_PAID
else: else:
bonus = UserBonus.objects.create(amount= -request.user.bonus, user=request.user, bonus = UserBonus.objects.create(amount= -request.user.bonus, user=request.user,
payment=course_payment) payment=course_payment)
@ -91,31 +92,15 @@ class CourseBuyView(TemplateView):
course_payment.save() course_payment.save()
if course_payment.is_paid(): if course_payment.is_paid():
return redirect(reverse_lazy('course_payment_success', args=[course.id])) return redirect(reverse_lazy('course_payment_success', args=[course.id]))
product = Product( context = {
f'course_{course_payment.id}', 'payment': course_payment,
course_payment.amount, }
'RUB', return self.render_to_response(context=context)
f'Курс "{course.title}"',
)
widget = Widget(
str(request.user.id),
'p1_1',
[product],
extra_params={
'lang': 'ru',
'evaluation': 1,
'demo': 1,
'test_mode': 1,
'success_url': host + str(reverse_lazy('course_payment_success', args=[course.id])),
'failure_url': host + str(reverse_lazy('payment-error')),
}
)
return self.render_to_response(context={'widget': widget.get_html_code()})
@method_decorator(login_required, name='dispatch') @method_decorator(login_required, name='dispatch')
class SchoolBuyView(TemplateView): class SchoolBuyView(TemplateView):
template_name = 'payment/paymentwall_widget.html' template_name = 'payment/cloudpayments_widget.html'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
host = urlsplit(self.request.META.get('HTTP_REFERER')) host = urlsplit(self.request.META.get('HTTP_REFERER'))
@ -126,23 +111,26 @@ class SchoolBuyView(TemplateView):
date_start = request.GET.get('date_start') date_start = request.GET.get('date_start')
date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d') or now().date() date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d') or now().date()
if not weekdays: if not weekdays:
messages.error(request, 'Выберите несколько дней недели.') messages.error(request, 'Выберите несколько дней недели')
if request.is_ajax():
return JsonResponse({
'error': 'Выберите несколько дней недели'
})
return redirect('school:school') return redirect('school:school')
try: try:
weekdays = [int(weekday) for weekday in weekdays] weekdays = [int(weekday) for weekday in weekdays]
except ValueError: except ValueError:
messages.error(request, 'Ошибка выбора дней недели.') messages.error(request, 'Ошибка выбора дней недели')
if request.is_ajax():
return JsonResponse({
'error': 'Ошибка выбора дней недели'
})
return redirect('school:school') return redirect('school:school')
prev_school_payment = SchoolPayment.objects.filter( prev_school_payment = SchoolPayment.objects.paid().filter(
user=request.user, user=request.user,
date_start__lte=date_start, date_start__lte=date_start,
date_end__gte=date_start, date_end__gte=date_start,
add_days=False, add_days=False,
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
).last() ).last()
add_days = bool(prev_school_payment) add_days = bool(prev_school_payment)
if add_days: if add_days:
@ -157,6 +145,10 @@ class SchoolBuyView(TemplateView):
# Если произойдет ошибка и оплату бонусами повторят еще раз на те же дни, то вернет ошибку # Если произойдет ошибка и оплату бонусами повторят еще раз на те же дни, то вернет ошибку
if school_payment.amount <= 0: if school_payment.amount <= 0:
messages.error(request, 'Выбранные дни отсутствуют в оставшемся периоде подписки') messages.error(request, 'Выбранные дни отсутствуют в оставшемся периоде подписки')
if request.is_ajax():
return JsonResponse({
'error': 'Выбранные дни отсутствуют в оставшемся периоде подписки'
})
return redirect(reverse_lazy('school:school')) return redirect(reverse_lazy('school:school'))
else: else:
school_payment = SchoolPayment.objects.create( school_payment = SchoolPayment.objects.create(
@ -170,7 +162,7 @@ class SchoolBuyView(TemplateView):
if request.user.bonus >= school_payment.amount: if request.user.bonus >= school_payment.amount:
bonus = UserBonus.objects.create(amount= -school_payment.amount, user=request.user, payment=school_payment) bonus = UserBonus.objects.create(amount= -school_payment.amount, user=request.user, payment=school_payment)
school_payment.amount = 0 school_payment.amount = 0
school_payment.status = Pingback.PINGBACK_TYPE_REGULAR school_payment.status = Payment.STATUS_PAID
else: else:
bonus = UserBonus.objects.create(amount= -request.user.bonus, user=request.user, bonus = UserBonus.objects.create(amount= -request.user.bonus, user=request.user,
payment=school_payment) payment=school_payment)
@ -178,27 +170,22 @@ class SchoolBuyView(TemplateView):
school_payment.bonus = bonus school_payment.bonus = bonus
school_payment.save() school_payment.save()
if school_payment.is_paid(): if school_payment.is_paid():
if request.is_ajax():
return JsonResponse({
'status': 'ok',
'paid': True,
})
return redirect(reverse_lazy('payment-success')) return redirect(reverse_lazy('payment-success'))
product = Product(
f'school_{school_payment.id}', if request.is_ajax():
school_payment.amount, return JsonResponse({
'RUB', 'status': 'ok',
'Школа', 'amount': school_payment.amount,
) 'payment_id': school_payment.id,
widget = Widget( 'success_url': reverse('payment-success', args=[school_payment.id]),
str(request.user.id), 'description': f'Оплата школы до {school_payment.date_end_humanize}, {school_payment.weekdays_str}',
'p1_1', })
[product], return self.render_to_response(context={'payment': school_payment})
extra_params={
'lang': 'ru',
'evaluation': 1,
'demo': 1,
'test_mode': 1,
'success_url': host + str(reverse_lazy('payment-success')),
'failure_url': host + str(reverse_lazy('payment-error')),
}
)
return self.render_to_response(context={'widget': widget.get_html_code()})
@method_decorator(csrf_exempt, name='dispatch') @method_decorator(csrf_exempt, name='dispatch')
@ -407,19 +394,80 @@ class CloudPaymentsTestView(TemplateView):
return self.render_to_response(context) return self.render_to_response(context)
class CloudPaymentsCallbackTestView(TemplateView): class PaymentSuccessView(View):
template_name = 'payment/cloud_payments_callback_test.html'
def get(self, request, *args, **kwargs): def post(self, request, payment_id):
context = self.get_context_data(**kwargs) payment_data = request.POST.get('payment_data')
invoice_id = request.GET.get('invoice_id')
client = CloudPayments('pk_9ae020cd5fed74499dee247067d17', 'a7d5f88ea69ef59f8b5db2252e39cedf')
context['test_ok'] = bool(client.test())
try: try:
t = client.find_payment(int(invoice_id)) payment = Payment.objects.get(id=payment_id)
print('transaction.status', t.status, 'transaction.reason', t.reason) except Payment.DoesNotExist:
# status = 'Completed', reason = 'Approved' raise Http404()
context['transaction'] = t client = CloudPayments(settings.CLOUD_PAYMENTS_PUBLIC_ID, settings.CLOUD_PAYMENTS_API_KRY)
except: transaction = client.find_payment(payment_id)
context['transaction'] = None if transaction.status == 'Completed' and transaction.reason == 'Approved':
return self.render_to_response(context) payment.data = payment_data
payment.status = Payment.STATUS_PAID
payment.save()
author_balance = getattr(payment, 'author_balance', None)
if author_balance and author_balance.type == AuthorBalance.IN:
payment.author_balance.status = AuthorBalance.DECLINED
payment.author_balance.save()
if isinstance(payment, CoursePayment):
product_type_name = 'course'
properties = {
'payment_id': payment.id,
'amount': payment.amount,
'status': payment.status,
'course': payment.course.id,
'created_at': payment.created_at,
'update_at': payment.update_at,
}
redirect_to = reverse('course_payment_success', args=[payment.course_id])
elif isinstance(payment, SchoolPayment):
product_type_name = 'school'
properties = {
'payment_id': payment.id,
'amount': payment.amount,
'status': payment.status,
'weekdays': payment.weekdays,
'add_days': payment.add_days,
'date_start': payment.date_start,
'date_end': payment.date_end,
'created_at': payment.created_at,
'update_at': payment.update_at,
}
redirect_to = reverse('payment-success')
elif isinstance(payment, GiftCertificatePayment):
product_type_name = 'gift_certificate'
properties = {
'payment_id': payment.id,
'amount': payment.amount,
'status': payment.status,
'gift_certificate': payment.gift_certificate.id,
'created_at': payment.created_at,
'update_at': payment.update_at,
}
redirect_to = reverse('gift-certificate-payment-success', args=[payment_id])
product_payment_to_mixpanel.delay(
payment.user.id,
f'{product_type_name.title()} payment',
now().strftime('%Y-%m-%dT%H:%M:%S'),
properties,
)
transaction_to_roistat.delay(
payment.user.id,
payment.id,
f'{product_type_name.title()} payment',
payment.amount,
now().strftime('%Y-%m-%d %H:%M:%S'),
payment.STATUS_PAID,
product_type_name,
payment.roistat_visit,
)
return redirect_to
return reverse('payment-error')

@ -1,6 +1,10 @@
{% extends "templates/lilcity/index.html" %} {% load static %} {% extends "templates/lilcity/index.html" %} {% load static %}
{% block title %}Онлайн-школа LilCity{% endblock title%} {% block title %}Онлайн-школа LilCity{% endblock title%}
{% block ogimage %}http://{{request.META.HTTP_HOST}}{% static 'img/og_main.jpg' %}{% endblock %} {% block ogimage %}http://{{request.META.HTTP_HOST}}{% static 'img/og_main.jpg' %}{% endblock %}
{% block head %}
{{ block.super }}
<script src="https://widget.cloudpayments.ru/bundles/cloudpayments"></script>
{% endblock head %}
{% block content %} {% block content %}
{% if not is_purchased and not prev_school_payments_exists %} {% if not is_purchased and not prev_school_payments_exists %}
{% include "../summer/promo.html" %} {% include "../summer/promo.html" %}

@ -1,5 +1,4 @@
from datetime import datetime, timedelta, date from datetime import datetime, timedelta, date
from paymentwall import Pingback
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib.auth.decorators import login_required, user_passes_test
@ -67,15 +66,10 @@ class LiveLessonsDetailView(DetailView):
if lesson_date: if lesson_date:
self.object = LiveLesson.objects.get(date=datetime.strptime(lesson_date, '%d-%m-%y')) self.object = LiveLesson.objects.get(date=datetime.strptime(lesson_date, '%d-%m-%y'))
if request.user.is_authenticated: if request.user.is_authenticated:
is_purchased = SchoolPayment.objects.filter( is_purchased = SchoolPayment.objects.paid().filter(
user=request.user, user=request.user,
date_start__lte=now(), date_start__lte=now(),
date_end__gte=now() - timedelta(days=7), date_end__gte=now() - timedelta(days=7),
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
weekdays__contains=[self.object.date.weekday() + 1], weekdays__contains=[self.object.date.weekday() + 1],
).exists() ).exists()
if not is_purchased and request.user.role not in [User.ADMIN_ROLE, User.TEACHER_ROLE]: if not is_purchased and request.user.role not in [User.ADMIN_ROLE, User.TEACHER_ROLE]:
@ -142,17 +136,15 @@ class SchoolView(TemplateView):
prev_school_payments = None prev_school_payments = None
prev_range = [date_now - timedelta(days=7), date_now - timedelta(days=1)] prev_range = [date_now - timedelta(days=7), date_now - timedelta(days=1)]
if self.request.user.is_authenticated: if self.request.user.is_authenticated:
school_payment = SchoolPayment.objects.filter( school_payment = SchoolPayment.objects.paid().filter(
user=self.request.user, user=self.request.user,
status__in=SchoolPayment.PW_PAID_STATUSES,
date_start__lte=date_now, date_start__lte=date_now,
date_end__gte=date_now date_end__gte=date_now
) )
school_payment_exists = school_payment.exists() school_payment_exists = school_payment.exists()
school_purchased_future = SchoolPayment.objects.filter( school_purchased_future = SchoolPayment.objects.paid().filter(
user=self.request.user, user=self.request.user,
status__in=SchoolPayment.PW_PAID_STATUSES,
date_start__gt=date_now, date_start__gt=date_now,
date_end__gt=date_now date_end__gt=date_now
) )
@ -167,15 +159,10 @@ class SchoolView(TemplateView):
joined_weekdays=Func(F('weekdays'), function='unnest',) joined_weekdays=Func(F('weekdays'), function='unnest',)
).values_list('joined_weekdays', flat=True).distinct() ).values_list('joined_weekdays', flat=True).distinct()
prev_school_payments = SchoolPayment.objects.filter( prev_school_payments = SchoolPayment.objects.paid().filter(
date_start__lte=prev_range[1], date_start__lte=prev_range[1],
date_end__gte=prev_range[0], date_end__gte=prev_range[0],
user=self.request.user, user=self.request.user,
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
weekdays__len__gt=0, weekdays__len__gt=0,
) )

@ -110,13 +110,12 @@ class User(AbstractUser):
def balance(self): def balance(self):
from apps.payment.models import Payment, AuthorBalance from apps.payment.models import Payment, AuthorBalance
income = self.balances.filter( income = self.balances.filter(
type=AuthorBalance.IN, Q(payment__payment_platform=Payment.PAYMENT_PLATFORM_PAYMENTWALL, payment__status__in=Payment.PAID_STATUSES)
payment__isnull=False, | Q(payment__payment_platform=Payment.PAYMENT_PLATFORM_CLOUDPAYMENTS, payment__status=Payment.STATUS_PAID),
payment__status__in=Payment.PW_PAID_STATUSES, type=AuthorBalance.IN,).aggregate(
).aggregate( models.Sum('amount'),
models.Sum('amount'), models.Sum('commission'),
models.Sum('commission'), )
)
income_amount = income.get('amount__sum') or 0 income_amount = income.get('amount__sum') or 0
income_commission = income.get('commission__sum') or 0 income_commission = income.get('commission__sum') or 0
@ -129,7 +128,9 @@ class User(AbstractUser):
def bonus(self): def bonus(self):
from apps.payment.models import Payment from apps.payment.models import Payment
return int(self.bonuses.filter( return int(self.bonuses.filter(
Q(payment__isnull=False, payment__status__in=Payment.PW_PAID_STATUSES) | Q(is_service=True), Q(payment__payment_platform=Payment.PAYMENT_PLATFORM_PAYMENTWALL, payment__status__in=Payment.PAID_STATUSES)
| Q(payment__payment_platform=Payment.PAYMENT_PLATFORM_CLOUDPAYMENTS, payment__status=Payment.STATUS_PAID)
| Q(is_service=True),
).aggregate(models.Sum('amount')).get('amount__sum') or 0) ).aggregate(models.Sum('amount')).get('amount__sum') or 0)

@ -3,7 +3,6 @@ from PIL import Image
from uuid import uuid4 from uuid import uuid4
from os.path import splitext from os.path import splitext
from datetime import timedelta from datetime import timedelta
from paymentwall import Pingback
import short_url import short_url
from django.conf import settings from django.conf import settings
@ -61,23 +60,13 @@ class ProfileView(TemplateView):
context['is_author'] = context['published'] or self.request.user.role == User.AUTHOR_ROLE context['is_author'] = context['published'] or self.request.user.role == User.AUTHOR_ROLE
context['user_gift_certificates'] = UserGiftCertificate.objects.filter(user=self.request.user) context['user_gift_certificates'] = UserGiftCertificate.objects.filter(user=self.request.user)
context['paid'] = Course.objects.filter( context['paid'] = Course.objects.filter(
payments__in=CoursePayment.objects.filter( payments__in=CoursePayment.objects.paid().filter(
user=self.object, user=self.object,
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
), ),
).distinct() ).distinct()
school_payment = SchoolPayment.objects.filter( school_payment = SchoolPayment.objects.paid().filter(
user=self.object, user=self.object,
date_end__gte=now(), date_end__gte=now(),
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
) )
context['is_school_purchased'] = school_payment.exists() context['is_school_purchased'] = school_payment.exists()
if context['is_school_purchased']: if context['is_school_purchased']:
@ -303,7 +292,9 @@ class BonusHistoryView(TemplateView):
config = Config.load() config = Config.load()
context = self.get_context_data(**kwargs) context = self.get_context_data(**kwargs)
context['bonuses'] = request.user.bonuses.filter( context['bonuses'] = request.user.bonuses.filter(
Q(payment__isnull=False, payment__status__in=Payment.PW_PAID_STATUSES) | Q(is_service=True), Q(payment__payment_platform=Payment.PAYMENT_PLATFORM_PAYMENTWALL, payment__status__in=Payment.PAID_STATUSES)
| Q(payment__payment_platform=Payment.PAYMENT_PLATFORM_CLOUDPAYMENTS, payment__status=Payment.STATUS_PAID)
| Q(is_service=True)
) )
context['referrer_url'] = 'https://%s%s?referrer=%s' % ( context['referrer_url'] = 'https://%s%s?referrer=%s' % (
settings.MAIN_HOST, reverse('index'), short_url.encode_url(request.user.id) settings.MAIN_HOST, reverse('index'), short_url.encode_url(request.user.id)

@ -1,6 +1,5 @@
from django.db.models import Func, F from django.db.models import Func, F
from django.utils.timezone import now from django.utils.timezone import now
from paymentwall.pingback import Pingback
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.conf import settings from django.conf import settings
from apps.config.models import Config from apps.config.models import Config
@ -21,13 +20,8 @@ def baner(request):
def school_purchased(request): def school_purchased(request):
if request.user.is_authenticated: if request.user.is_authenticated:
n = now().date() n = now().date()
school_payment = SchoolPayment.objects.filter( school_payment = SchoolPayment.objects.paid().filter(
user=request.user, user=request.user,
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
date_start__lte=n, date_start__lte=n,
date_end__gte=n date_end__gte=n
) )

@ -264,6 +264,9 @@ CELERY_BEAT_SCHEDULE = {
}, },
} }
CLOUD_PAYMENTS_PUBLIC_ID = os.getenv('CLOUD_PAYMENTS_PUBLIC_ID', 'pk_9ae020cd5fed74499dee247067d17')
CLOUD_PAYMENTS_API_KRY = os.getenv('CLOUD_PAYMENTS_API_KRY', 'a7d5f88ea69ef59f8b5db2252e39cedf')
try: try:
from paymentwall import * from paymentwall import *
except ImportError: except ImportError:

@ -35,7 +35,7 @@ from apps.payment.views import (
CourseBuySuccessView, CourseBuyView, CourseBuySuccessView, CourseBuyView,
PaymentwallCallbackView, SchoolBuySuccessView, PaymentwallCallbackView, SchoolBuySuccessView,
SchoolBuyView, GiftCertificatesView, GiftCertificateBuyView, SchoolBuyView, GiftCertificatesView, GiftCertificateBuyView,
GiftCertificateBuySuccessView, GiftCertificateGetView, CloudPaymentsTestView, CloudPaymentsCallbackTestView) GiftCertificateBuySuccessView, GiftCertificateGetView, CloudPaymentsTestView, PaymentSuccessView)
from .views import AboutView, IndexView, SchoolSchedulesView from .views import AboutView, IndexView, SchoolSchedulesView
@ -66,6 +66,8 @@ urlpatterns = [
path('payments/course/<int:pk>/success', CourseBuySuccessView.as_view(), name='course_payment_success'), path('payments/course/<int:pk>/success', CourseBuySuccessView.as_view(), name='course_payment_success'),
path('payments/school/success', SchoolBuySuccessView.as_view(), name='payment-success'), path('payments/school/success', SchoolBuySuccessView.as_view(), name='payment-success'),
path('payments/error', TemplateView.as_view(template_name='payment/payment_error.html'), name='payment-error'), path('payments/error', TemplateView.as_view(template_name='payment/payment_error.html'), name='payment-error'),
path('payments/<int:payment_id>/success', PaymentSuccessView.as_view(), name='payment-success'),
path('cloud_payments_test', CloudPaymentsTestView.as_view(), name='cloud_payments_test'),
path('school/checkout', SchoolBuyView.as_view(), name='school-checkout'), path('school/checkout', SchoolBuyView.as_view(), name='school-checkout'),
path('search/', SearchView.as_view(), name='search'), path('search/', SearchView.as_view(), name='search'),
path('user/profile/', ProfileView.as_view(), name='user-profile'), path('user/profile/', ProfileView.as_view(), name='user-profile'),
@ -98,8 +100,6 @@ urlpatterns = [
name='gift-certificate-payment-success'), name='gift-certificate-payment-success'),
path('gift-certificate/<str:slug>/get', GiftCertificateGetView.as_view(), name='gift-certificate-get'), path('gift-certificate/<str:slug>/get', GiftCertificateGetView.as_view(), name='gift-certificate-get'),
path('faq', FAQView.as_view(), name='faq'), path('faq', FAQView.as_view(), name='faq'),
path('cloud_payments_callback_test', CloudPaymentsCallbackTestView.as_view(), name='cloud_payments_callback_test'),
path('cloud_payments_test', CloudPaymentsTestView.as_view(), name='cloud_payments_test'),
] ]

@ -6,7 +6,6 @@ from django.db.models import Min, Func, F
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.views.generic import TemplateView from django.views.generic import TemplateView
from django.utils.timezone import now from django.utils.timezone import now
from paymentwall.pingback import Pingback
from apps.course.models import Course from apps.course.models import Course
from apps.school.models import SchoolSchedule from apps.school.models import SchoolSchedule
@ -50,15 +49,10 @@ class IndexView(TemplateView):
) )
date_now = now_time.date() date_now = now_time.date()
if self.request.user.is_authenticated: if self.request.user.is_authenticated:
school_payment = SchoolPayment.objects.filter( school_payment = SchoolPayment.objects.paid().filter(
user=self.request.user, user=self.request.user,
date_start__lte=date_now, date_start__lte=date_now,
date_end__gte=date_now, date_end__gte=date_now,
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
) )
school_payment_exists = school_payment.exists() school_payment_exists = school_payment.exists()
school_schedules_purchased = school_payment.annotate( school_schedules_purchased = school_payment.annotate(
@ -105,7 +99,7 @@ class IndexView(TemplateView):
'school_schedules': SchoolSchedule.objects.all(), 'school_schedules': SchoolSchedule.objects.all(),
'school_schedules_purchased': set(school_schedules_purchased), 'school_schedules_purchased': set(school_schedules_purchased),
'teachers': User.objects.filter(role=User.TEACHER_ROLE, show_in_mainpage=True), 'teachers': User.objects.filter(role=User.TEACHER_ROLE, show_in_mainpage=True),
'works_count': Payment.objects.filter(status__in=Payment.PW_PAID_STATUSES).count() * 5, 'works_count': Payment.objects.paid().count() * 5,
'subscription_ends': school_payment.filter(add_days=False).first().date_end if school_payment_exists else None, 'subscription_ends': school_payment.filter(add_days=False).first().date_end if school_payment_exists else None,
'subscription_ends_humanize': school_payment.filter(add_days=False).first().date_end_humanize if school_payment_exists else None, 'subscription_ends_humanize': school_payment.filter(add_days=False).first().date_end_humanize if school_payment_exists else None,

@ -215,6 +215,7 @@ $(document).ready(function () {
} }
if(data === '.js-popup-course-buy'){ if(data === '.js-popup-course-buy'){
//TODO: cloudpayments
const updateCourseCart = () => { const updateCourseCart = () => {
const $orderPrice = popup.find('.order_price_text'); const $orderPrice = popup.find('.order_price_text');
const useBonuses = $bonusesCheckbox.prop('checked'); const useBonuses = $bonusesCheckbox.prop('checked');

Loading…
Cancel
Save