From 627a7bed98ba96bd6335a54ee7d8ceeb394646e5 Mon Sep 17 00:00:00 2001 From: gzbender Date: Mon, 30 Sep 2019 22:43:32 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=B2=D0=B5=D0=B4=D0=BE=D0=BC=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=B1=20=D0=BE=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=87=D0=B0=D0=BD=D0=B8=D0=B8=20=D0=B4=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=83=D0=BF=D0=B0=20=D0=BA=20=D0=BA=D1=83=D1=80=D1=81=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/payment/views.py | 566 ++++++++++++++++++------------------------ 1 file changed, 245 insertions(+), 321 deletions(-) diff --git a/apps/payment/views.py b/apps/payment/views.py index 4341e32b..54bbfef1 100644 --- a/apps/payment/views.py +++ b/apps/payment/views.py @@ -14,7 +14,7 @@ from django.http import HttpResponse, Http404 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.urls import reverse from django.utils.decorators import method_decorator from django.utils.timezone import now @@ -35,146 +35,129 @@ class DisallowedPingbackHost(Exception): pass -@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, is_camp=False, *args, **kwargs): - context = { - 'duration': request.GET.get('duration'), - 'camp': is_camp, - 'school': not is_camp - } - return self.render_to_response(context=context) - - -@method_decorator(login_required, name='dispatch') -class CourseBuyView(TemplateView): +class BuyMixin(object): template_name = 'payment/pay.html' - def get(self, request, pk=None, *args, **kwargs): - use_bonuses = request.GET.get('use_bonuses') - host = urlsplit(self.request.META.get('HTTP_REFERER')) - host = str(host[0]) + '://' + str(host[1]) - course = Course.objects.get(id=pk) + def get(self, request, *args, **kwargs): roistat_visit = request.COOKIES.get('roistat_visit', None) - 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_duration = course.access_duration or 90 - access_expire = prev_payment.access_expire + timedelta(days=access_duration) if prev_payment \ - else now().date() + timedelta(days=access_duration - 1) - course_payment = CoursePayment.objects.create( - user=request.user, - course=course, - access_expire=access_expire, - roistat_visit=roistat_visit, - ) - if use_bonuses and request.user.bonus: - if request.user.bonus >= course_payment.amount: - bonus = UserBonus.objects.create(amount= -course_payment.amount, user=request.user, payment=course_payment) - course_payment.amount = 0 - course_payment.status = Pingback.PINGBACK_TYPE_REGULAR - else: - bonus = UserBonus.objects.create(amount= -request.user.bonus, user=request.user, - payment=course_payment) - course_payment.amount -= request.user.bonus - course_payment.bonus = bonus - course_payment.save() - if course_payment.is_paid(): - return redirect(reverse_lazy('course_payment_success', args=[course.id])) - product = Product( - f'course_{course_payment.id}', - course_payment.amount, - 'RUB', - f'Курс "{course.title}"', - ) - widget = Widget( - str(request.user.id), - 'p1_1', - [product], - extra_params={ - 'email': request.user.email, - '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')), - } - ) - attrs = {} - if request.user_agent.is_mobile: - attrs['width'] = '100%' - attrs['height'] = '600' - return self.render_to_response(context={'widget': widget.get_html_code(attrs)}) - + use_bonuses = request.GET.get('use_bonuses') + product_name = '' + context = self.get_context_data(**kwargs) + payment = None -@method_decorator(login_required, name='dispatch') -class SchoolBuyView(TemplateView): - template_name = 'payment/pay.html' + if self.product_type == 'gift_certificate': + gift_certificate = get_object_or_404(GiftCertificate, pk=kwargs.get('pk')) - def get(self, request, *args, **kwargs): - host = urlsplit(self.request.META.get('HTTP_REFERER')) - host = str(host[0]) + '://' + str(host[1]) - use_bonuses = request.GET.get('use_bonuses') - roistat_visit = request.COOKIES.get('roistat_visit', None) - date_start = request.GET.get('date_start') - duration = request.GET.get('duration') - payment_id = request.GET.get('payment_id') - package = get_object_or_404(Package, duration=duration) - date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d').date() or now().date() - prev_payment = SchoolPayment.objects.paid().filter( + payment = GiftCertificatePayment.objects.create( + user=request.user, + gift_certificate=gift_certificate, + roistat_visit=roistat_visit, ) + + success_url = reverse('gift-certificate-payment-success', args=[payment.id]) + product_name = 'Подарочный сертификат' + + if self.product_type == 'course': + course = Course.objects.get(id=kwargs.get('pk')) + + if request.user == course.author: + messages.error(request, 'Вы не можете приобрести свой курс.') + return redirect(reverse('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_duration = course.access_duration or 90 + access_expire = prev_payment.access_expire + timedelta(days=access_duration) if prev_payment \ + else now().date() + timedelta(days=access_duration - 1) + payment = CoursePayment.objects.create( + user=request.user, + course=course, + access_expire=access_expire, + roistat_visit=roistat_visit, + ) + success_url = reverse('course_payment_success', args=[course.id]) + product_name = f'Курс "{course.title}"' + context['course'] = course + + if self.product_type == 'school': + date_start = request.GET.get('date_start') + duration = request.GET.get('duration') + payment_id = request.GET.get('payment_id') + + package = get_object_or_404(Package, duration=duration) + date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d').date() or now().date() + prev_payment = SchoolPayment.objects.paid().filter( user=self.request.user, - date_end__gte=now().date(),).last() - if prev_payment and prev_payment.date_end > date_start: - date_start = prev_payment.date_end + timedelta(1) - if payment_id: - school_payment = get_object_or_404(SchoolPayment, id=payment_id) - else: - amount_data = SchoolPayment.calc_amount(package=package, user=request.user, date_start=date_start) - school_payment = SchoolPayment.objects.create( + date_end__gte=now().date(), ).last() + if prev_payment and prev_payment.date_end > date_start: + date_start = prev_payment.date_end + timedelta(1) + if payment_id: + payment = get_object_or_404(SchoolPayment, id=payment_id) + else: + amount_data = SchoolPayment.calc_amount(package=package, user=request.user, date_start=date_start) + payment = SchoolPayment.objects.create( + user=request.user, + weekdays=amount_data.get('weekdays'), + roistat_visit=roistat_visit, + date_start=amount_data.get('date_start'), + date_end=amount_data.get('date_end'), + package=package, + ) + if payment_id and payment.bonus and not use_bonuses: + bonus = payment.bonus + payment.amount += payment.bonus + payment.bonus = None + bonus.delete() + success_url = '%s?duration=%s' % (reverse('payment-success'), duration) + product_name = 'Подписка' + context['school'] = True + + if self.product_type == 'drawing_camp': + date_start = request.GET.get('date_start') + date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d').date() or now().date() + date_start, date_end = Payment.get_date_range(date_start, months=1, is_camp=True) + prev_payment = DrawingCampPayment.objects.filter( + user=request.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, + ], + ).exists() + if prev_payment: + return HttpResponse(status=403) + payment = DrawingCampPayment.objects.create( user=request.user, - weekdays=amount_data.get('weekdays'), roistat_visit=roistat_visit, - date_start=amount_data.get('date_start'), - date_end=amount_data.get('date_end'), - package=package, + date_start=date_start, + date_end=date_end, ) + success_url = reverse('camp-payment-success') + product_name = 'Подписка' + context['camp'] = True + if use_bonuses and request.user.bonus: - if request.user.bonus >= school_payment.amount: - bonus = UserBonus.objects.create(amount= -school_payment.amount, user=request.user, payment=school_payment) - school_payment.amount = 0 - school_payment.status = Pingback.PINGBACK_TYPE_REGULAR + if request.user.bonus >= payment.amount: + bonus = UserBonus.objects.create(amount=-payment.amount, user=request.user, payment=payment) + payment.amount = 0 + payment.status = Pingback.PINGBACK_TYPE_REGULAR else: - school_payment.amount -= request.user.bonus - bonus = UserBonus.objects.create(amount= -request.user.bonus, user=request.user, - payment=school_payment) - school_payment.bonus = bonus - school_payment.save() - if school_payment.is_paid(): - return redirect('%s?duration=%s' % (str(reverse_lazy('payment-success')), duration)) - if payment_id and school_payment.bonus and not use_bonuses: - bonus = school_payment.bonus - school_payment.amount += school_payment.bonus - school_payment.bonus = None - bonus.delete() + bonus = UserBonus.objects.create(amount=-request.user.bonus, user=request.user, + payment=payment) + payment.amount -= request.user.bonus + payment.bonus = bonus + payment.save() + if payment.is_paid(): + self.after_buy(payment) + return redirect(success_url) + product = Product( - f'school_{school_payment.id}', - school_payment.amount, + f'course_{payment.id}', + payment.amount, 'RUB', - 'Подписка', + product_name, ) widget = Widget( str(request.user.id), @@ -186,8 +169,8 @@ class SchoolBuyView(TemplateView): 'evaluation': 1, 'demo': 1, 'test_mode': 1, - 'success_url': host + str(reverse_lazy('payment-success')) + '?duration=%s' % duration, - 'failure_url': host + str(reverse_lazy('payment-error')), + 'success_url': request.build_absolute_uri(success_url), + 'failure_url': request.build_absolute_uri(reverse('payment-error')), } ) if self.request.is_ajax(): @@ -196,86 +179,143 @@ class SchoolBuyView(TemplateView): if request.user_agent.is_mobile: attrs['width'] = '100%' attrs['height'] = '600' - return self.render_to_response(context={ - 'widget': widget.get_html_code(attrs), - 'school': True, - 'payment': school_payment, - }) + context['widget'] = widget.get_html_code(attrs) + return self.render_to_response(context) + def after_buy(self, payment): + product_type_name = None + if isinstance(payment, CoursePayment): + product_type_name == 'course' + elif isinstance(payment, SchoolPayment): + product_type_name == 'school' + elif isinstance(payment, DrawingCampPayment): + product_type_name == 'drawing_camp' + elif isinstance(payment, GiftCertificatePayment): + product_type_name == 'gift_certificate' + + 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, + } + elif product_type_name == 'drawing_camp': + properties = { + 'payment_id': payment.id, + 'amount': payment.amount, + 'status': payment.status, + 'date_start': payment.date_start, + 'date_end': payment.date_end, + 'created_at': payment.created_at, + 'update_at': payment.update_at, + } + elif 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, + } -@method_decorator(login_required, name='dispatch') -class DrawingCampBuyView(TemplateView): - template_name = 'payment/pay.html' + product_payment_to_mixpanel.delay( + payment.user.id, + f'{product_type_name.title()} payment', + now().strftime('%Y-%m-%dT%H:%M:%S'), + properties, + ) - def get(self, request, *args, **kwargs): - host = urlsplit(self.request.META.get('HTTP_REFERER')) - host = str(host[0]) + '://' + str(host[1]) - use_bonuses = request.GET.get('use_bonuses') - roistat_visit = request.COOKIES.get('roistat_visit', None) - date_start = request.GET.get('date_start') - date_start = date_start and datetime.datetime.strptime(date_start, '%Y-%m-%d').date() or now().date() - date_start, date_end = Payment.get_date_range(date_start, months=1, is_camp=True) - prev_payment = DrawingCampPayment.objects.filter( - user=request.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, - ], - ).exists() - if prev_payment: - return HttpResponse(status=403) - camp_payment = DrawingCampPayment.objects.create( - user=request.user, - roistat_visit=roistat_visit, - date_start=date_start, - date_end=date_end, + transaction_to_roistat.delay( + payment.user.id, + payment.id, + f'{product_type_name.title()} payment', + payment.amount, + datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'), + payment.status, + product_type_name, + payment.roistat_visit, ) - if use_bonuses and request.user.bonus: - if request.user.bonus >= camp_payment.amount: - bonus = UserBonus.objects.create(amount=-camp_payment.amount, user=request.user, - payment=camp_payment) - camp_payment.amount = 0 - camp_payment.status = Pingback.PINGBACK_TYPE_REGULAR + + if product_type_name == 'course': + send_email.delay('Спасибо за покупку!', payment.user.email, 'notification/email/buy_email.html', + product_type=product_type_name, url=payment.course.url, + username=payment.user.get_full_name(), course_title=payment.course.title, + access_duration=payment.access_duration) + elif product_type_name != 'school': + send_email.delay('Спасибо за покупку!', payment.user.email, 'notification/email/buy_email.html', + product_type=product_type_name) + elif product_type_name != 'drawing_camp': + send_email.delay('Спасибо за покупку!', payment.user.email, 'notification/email/buy_email.html', + product_type=product_type_name, date_start=payment.date_start, date_end=payment.date_end) + + author_balance = getattr(payment, 'author_balance', None) + if author_balance and author_balance.type == AuthorBalance.IN: + if payment.is_deliverable(): + payment.author_balance.status = AuthorBalance.ACCEPTED + elif payment.is_under_review(): + payment.author_balance.status = AuthorBalance.PENDING else: - bonus = UserBonus.objects.create(amount=-request.user.bonus, user=request.user, - payment=camp_payment) - camp_payment.amount -= request.user.bonus - camp_payment.bonus = bonus - camp_payment.save() - if camp_payment.is_paid(): - return redirect(reverse_lazy('camp-payment-success')) - product = Product( - f'drawing_camp_{camp_payment.id}', - camp_payment.amount, - 'RUB', - 'Школа', - ) - widget = Widget( - str(request.user.id), - 'p1_1', - [product], - extra_params={ - 'email': request.user.email, - 'lang': 'ru', - 'evaluation': 1, - 'demo': 1, - 'test_mode': 1, - 'success_url': host + str(reverse_lazy('camp-payment-success')), - 'failure_url': host + str(reverse_lazy('payment-error')), - } - ) - attrs = {} - if request.user_agent.is_mobile: - attrs['width'] = '100%' - attrs['height'] = '600' - return self.render_to_response(context={'widget': widget.get_html_code(attrs)}) + payment.author_balance.status = AuthorBalance.DECLINED + payment.author_balance.save() + + +@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, is_camp=False, *args, **kwargs): + context = { + 'duration': request.GET.get('duration'), + 'camp': is_camp, + 'school': not is_camp + } + return self.render_to_response(context=context) + + +@method_decorator(login_required, name='dispatch') +class CourseBuyView(BuyMixin, TemplateView): + template_name = 'payment/pay.html' + product_type = 'course' + + +@method_decorator(login_required, name='dispatch') +class SchoolBuyView(BuyMixin, TemplateView): + template_name = 'payment/pay.html' + product_type = 'school' + +@method_decorator(login_required, name='dispatch') +class DrawingCampBuyView(BuyMixin, TemplateView): + template_name = 'payment/pay.html' + product_type = 'drawing_camp' @method_decorator(csrf_exempt, name='dispatch') -class PaymentwallCallbackView(View): +class PaymentwallCallbackView(BuyMixin, View): def get_request_ip(self): x_forwarded_for = self.request.META.get('HTTP_X_FORWARDED_FOR') @@ -327,88 +367,8 @@ class PaymentwallCallbackView(View): product_type_name, ) - 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, - } - elif product_type_name == 'drawing_camp': - properties = { - 'payment_id': payment.id, - 'amount': payment.amount, - 'status': payment.status, - 'date_start': payment.date_start, - 'date_end': payment.date_end, - 'created_at': payment.created_at, - 'update_at': payment.update_at, - } - elif 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, - } - + self.after_buy(payment) 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, - ) - - transaction_to_roistat.delay( - payment.user.id, - payment.id, - f'{product_type_name.title()} payment', - payment.amount, - datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'), - pingback.get_type(), - product_type_name, - payment.roistat_visit, - ) - - if product_type_name == 'course': - send_email.delay('Спасибо за покупку!', payment.user.email, 'notification/email/buy_email.html', - product_type=product_type_name, url=payment.course.url, - username=payment.user.get_full_name(), course_title=payment.course.title, - access_duration=payment.access_duration) - elif product_type_name != 'school': - send_email.delay('Спасибо за покупку!', payment.user.email, 'notification/email/buy_email.html', - product_type=product_type_name) - elif product_type_name != 'drawing_camp': - send_email.delay('Спасибо за покупку!', payment.user.email, 'notification/email/buy_email.html', - product_type=product_type_name, date_start=payment.date_start, date_end=payment.date_end) - - 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: raise DisallowedPingbackHost @@ -427,45 +387,9 @@ class GiftCertificatesView(TemplateView): @method_decorator(login_required, name='dispatch') -class GiftCertificateBuyView(TemplateView): +class GiftCertificateBuyView(BuyMixin, TemplateView): model = GiftCertificate - template_name = 'payment/pay.html' - - def get(self, request, pk, *args, **kwargs): - gift_certificate = get_object_or_404(GiftCertificate, pk=pk) - roistat_visit = request.COOKIES.get('roistat_visit', None) - gift_certificate_payment = GiftCertificatePayment.objects.create( - user=request.user, - gift_certificate=gift_certificate, - roistat_visit=roistat_visit,) - context = self.get_context_data(**kwargs) - product = Product( - f'gift_certificate_{gift_certificate_payment.id}', - gift_certificate_payment.amount, - 'RUB', - 'Подарочный сертификат', - ) - host = urlsplit(self.request.META.get('HTTP_REFERER')) - host = str(host[0]) + '://' + str(host[1]) - 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('gift-certificate-payment-success', args=[gift_certificate_payment.id])), - 'failure_url': host + str(reverse_lazy('payment-error')), - } - ) - attrs = {} - if request.user_agent.is_mobile: - attrs['width'] = '100%' - attrs['height'] = '600' - context['widget'] = widget.get_html_code(attrs) - return self.render_to_response(context) + product_type = 'gift_certificate' @method_decorator(login_required, name='dispatch')