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 = str(host[0]) + '://' + str(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 = str(host[0]) + '://' + str(host[1]) weekdays = set(request.GET.getlist('weekdays', [])) add_days = 'add_days' in request.GET if not weekdays: messages.error(request, 'Выберите несколько дней недели.') return redirect('school:school') try: weekdays = [int(weekday) for weekday in weekdays] except ValueError: messages.error(request, 'Ошибка выбора дней недели.') return redirect('school:school') if add_days: _school_payment = SchoolPayment.objects.get( user=request.user, date_start__lte=now().date(), date_end__gte=now().date(), add_days=False, ) school_payment = SchoolPayment.objects.create( user=request.user, weekdays=weekdays, add_days=True, ) else: 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, add_days=False, date_start__lte=now().date(), date_end__gte=now().date(), status__in=[ Pingback.PINGBACK_TYPE_REGULAR, Pingback.PINGBACK_TYPE_GOODWILL, Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, ], ).last() if school_payment: if payment.add_days: date_start = now() date_end = school_payment.date_end else: 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 = { 'payment_id': payment.id, 'amount': payment.amount, 'status': payment.status, 'course': payment.course.id, 'created_at': payment.created_at, 'update_at': payment.update_at, } elif 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, } payment.save() product_payment_to_mixpanel.delay( payment.user.id, f'{product_type_name.title()} payment', now().strftime('%Y-%m-%dT%H:%M:%S'), properties, ) 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)