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.
 
 
 
 
 
 

221 lines
8.3 KiB

import logging
import json
from datetime import timedelta
from urllib.parse import urlsplit
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.shortcuts import redirect, get_object_or_404
from django.views.generic import View, TemplateView
from django.views.decorators.csrf import csrf_exempt
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.utils.timezone import now
from paymentwall import Pingback, Product, Widget
from apps.course.models import Course
from apps.school.models import SchoolSchedule
from apps.payment.tasks import transaction_to_mixpanel, product_payment_to_mixpanel
from .models import AuthorBalance, CoursePayment, SchoolPayment
logger = logging.getLogger('django')
@method_decorator(login_required, name='dispatch')
class CourseBuySuccessView(TemplateView):
template_name = 'payment/course_payment_success.html'
def get(self, request, pk=None, *args, **kwargs):
course = get_object_or_404(Course, pk=pk)
return self.render_to_response(context={'course': course})
@method_decorator(login_required, name='dispatch')
class SchoolBuySuccessView(TemplateView):
template_name = 'payment/payment_success.html'
def get(self, request, pk=None, *args, **kwargs):
return self.render_to_response(context={'school': True})
@method_decorator(login_required, name='dispatch')
class CourseBuyView(TemplateView):
template_name = 'payment/paymentwall_widget.html'
def get(self, request, pk=None, *args, **kwargs):
host = urlsplit(self.request.META.get('HTTP_REFERER'))
host = host[0] + '://' + host[1]
course = Course.objects.get(id=pk)
if request.user == course.author:
messages.error(request, 'Вы не можете приобрести свой курс.')
return redirect(reverse_lazy('course', args=[course.id]))
course_payment = CoursePayment.objects.create(
user=request.user,
course=course,
)
product = Product(
f'course_{course_payment.id}',
course.price,
'RUB',
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')
class SchoolBuyView(TemplateView):
template_name = 'payment/paymentwall_widget.html'
def get(self, request, *args, **kwargs):
host = urlsplit(self.request.META.get('HTTP_REFERER'))
host = host[0] + '://' + host[1]
weekdays = set(request.GET.getlist('weekdays', []))
if not weekdays:
messages.error(request, 'Выберите несколько дней недели.')
return redirect('index')
try:
weekdays = [int(weekday) for weekday in weekdays]
except ValueError:
messages.error(request, 'Ошибка выбора дней недели.')
return redirect('index')
school_payment = SchoolPayment.objects.create(
user=request.user,
weekdays=weekdays,
)
product = Product(
f'school_{school_payment.id}',
school_payment.amount,
'RUB',
'Школа',
)
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('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')
class PaymentwallCallbackView(View):
def get_request_ip(self):
x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = self.request.META.get('REMOTE_ADDR')
return ip
def get(self, request, *args, **kwargs):
payment_raw_data = request.GET.copy()
pingback = Pingback(payment_raw_data, self.get_request_ip())
if pingback.validate():
product_type_name, payment_id = pingback.get_product().get_id().split('_')
if product_type_name == 'course':
product_payment_class = CoursePayment
elif product_type_name == 'school':
product_payment_class = SchoolPayment
else:
return HttpResponse(status=403)
try:
payment = product_payment_class.objects.get(pk=payment_id)
except product_payment_class.DoesNotExist:
return HttpResponse(status=403)
logger.info(
json.dumps(payment_raw_data),
)
payment.status = pingback.get_type()
payment.data = payment_raw_data
if pingback.is_deliverable():
transaction_to_mixpanel.delay(
payment.user.id,
payment.amount,
now().strftime('%Y-%m-%dT%H:%M:%S'),
product_type_name,
)
if product_type_name == 'school':
school_payment = SchoolPayment.objects.filter(
user=payment.user,
date_start__lte=now(),
date_end__gt=now(),
status__in=[
Pingback.PINGBACK_TYPE_REGULAR,
Pingback.PINGBACK_TYPE_GOODWILL,
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,
],
).last()
if school_payment:
date_start = school_payment.date_end + timedelta(days=1)
date_end = date_start + timedelta(days=30)
else:
date_start = now()
date_end = now() + timedelta(days=30)
payment.date_start = date_start
payment.date_end = date_end
if product_type_name == 'course':
properties = {
'status': payment.status,
'course': payment.course.id,
'created_at': payment.created_at,
'update_at': payment.update_at,
}
elif product_type_name == 'school':
properties = {
'status': payment.status,
'weekdays': payment.weekdays,
'date_start': payment.date_start,
'date_end': payment.date_end,
'created_at': payment.created_at,
'update_at': payment.update_at,
}
product_payment_to_mixpanel.delay(
payment.user.id,
f'{school_payment.title()} payment',
now().strftime('%Y-%m-%dT%H:%M:%S'),
properties=properties,
)
payment.save()
author_balance = getattr(payment, 'author_balance', None)
if author_balance and author_balance.type == AuthorBalance.IN:
if pingback.is_deliverable():
payment.author_balance.status = AuthorBalance.ACCEPTED
elif pingback.is_under_review():
payment.author_balance.status = AuthorBalance.PENDING
else:
payment.author_balance.status = AuthorBalance.DECLINED
payment.author_balance.save()
return HttpResponse('OK')
else:
return HttpResponse(status=403)