import csv import logging import requests from django.contrib.auth import get_user_model from django.core.mail import EmailMessage from django.db.models import Q from django.http import HttpResponse, HttpResponseForbidden from django.shortcuts import redirect from rest_framework.renderers import JSONRenderer from rest_framework.response import Response from rest_framework.views import APIView from yandex_money.models import Payment from django.conf import settings from courses.models import Course from courses.api import CourseParamsApi from finance.models import Bill, Invoice from finance.serializers import BillSerializer, InvoiceSerializer from lms.global_decorators import transaction_decorator from lms.tools import get_real_name from django.utils import timezone logger_yandex = logging.getLogger('yandex_money') class BillListView(APIView): renderer_classes = (JSONRenderer,) @staticmethod def get(request): if request.user.is_authenticated: return Response( [BillSerializer(i).data for i in Bill.objects.filter(Q(user=request.user) | Q(opener=request.user))], status=200, ) return Response("Permission denied", status=403) @transaction_decorator def post(self, request): if request.user.is_authenticated and (request.user.groups.filter(name__in=['managers','lead_managers']).exists() or request.user.is_superuser): bill = request.JSON.get('bill') children = request.JSON.get('children', []) if bill: user = get_user_model().objects.get(email=bill['user']) opener = get_user_model().objects.get(email=bill['opener']) description = bill['description'] comment = bill['comment'] course_token = bill['course_token'] try: bill_obj = Bill.objects.get(user=user, course_token=course_token) except Bill.DoesNotExist: bill_obj = Bill.objects.create(user=user, course_token=course_token) bill_obj.opener = opener bill_obj.description = description bill_obj.comment = comment bill_obj.save() for i in children: status = get_real_name(elem=i['status'], array=Invoice.BILL_STATUSES) try: invoice_id = i['id'] except KeyError: invoice_id = None try: if not invoice_id is None: invoice = Invoice.objects.get(id=i['id']) if invoice.status == "P" or invoice.status == status: continue else: raise Invoice.DoesNotExist except Invoice.DoesNotExist: i['method'] = get_real_name(elem=i['method'], array=Invoice.BILL_METHOD) i['status'] = status i['bill'] = bill_obj i['yandex_pay'] = None invoice = Invoice.objects.create(**i) if i['method'] == 'Y' and invoice.yandex_pay is None: yandex_pay = Payment.objects.create( order_amount=i['price'], shop_amount=0, customer_number=bill_obj.user.id, user=bill_obj.user, cps_email=bill_obj.user.email, ) invoice.yandex_pay = yandex_pay invoice.save() msg = EmailMessage( 'Выставлен новый счёт.', '''Менеджер %s выставил счёт пользователю %s на курс "%s".''' % ( invoice.bill.opener.get_full_name(), invoice.bill.user.email, Course.objects.get(token=invoice.bill.course_token).title, ), 'robo@skillbox.ru', [invoice.bill.opener.email], bcc=['dmitry.dolya@skillbox.ru'], ) msg.send() res = { "bill": BillSerializer(bill_obj).data, "children": [InvoiceSerializer(i).data for i in bill_obj.invoice_set.all()], } return Response(res, status=200) return Response("Bill not set", status=400) return Response("Course detail access only for manager users", status=403) class BillDetailView(APIView): renderer_classes = (JSONRenderer,) status_code = 200 def get(self, request, pk): if request.user.is_authenticated: try: bill = Bill.objects.get(id=pk) except Bill.DoesNotExist: return Response("Bill not found", status=404) res = { "bill": BillSerializer(bill).data, "children": [InvoiceSerializer(i).data for i in bill.invoice_set.all()], } return Response( res, status=self.status_code, ) return Response("Permission denied", status=403) class FindBillView(APIView): renderer_classes = (JSONRenderer,) status_code = 200 @staticmethod def get(request): if request.user.is_authenticated() and \ (request.user.is_superuser or request.user.groups.filter(name__in=['managers', 'lead_managers']).exists()): key = request.GET.get('key', None) count = int(request.GET.get('count', '10')) if key: res = Bill.objects.filter( Q(opener__email__contains=key.lower()) | Q(user__email__contains=key.lower()) ) else: res = Bill.objects.all() res = res[:(count if len(res) > count else len(res))] return Response( [BillSerializer(i).data for i in res], status=200 ) return Response('Permission denied', status=403) class YandexPay(APIView): renderer_classes = (JSONRenderer,) @staticmethod def get(request, pk): try: pay = Payment.objects.get(id=pk) r = requests.post('https://money.yandex.ru/eshop.xml', data={ 'shopId': pay.shop_id, 'scid': pay.scid, 'sum': pay.order_amount, 'customerNumber': pay.customer_number, 'orderNumber': pay.order_number, 'cps_email': pay.cps_email, 'shopSuccessURL': settings.YANDEX_MONEY_SUCCESS_URL, 'shopFailURL': settings.YANDEX_MONEY_FAIL_URL, }) msg = EmailMessage( 'Пользователь перешёл на страницу оплаты.', '''Пользователь "%s" перешёл на страницу оплаты курса "%s".''' % (pay.invoice.bill.user.email, Course.objects.get(token=pay.invoice.bill.course_token).title), 'robo@skillbox.ru', [pay.invoice.bill.opener.email], bcc=['dmitry.dolya@skillbox.ru'], ) msg.send() return redirect(r.url) except Payment.DoesNotExist: return Response('Payment not found', status=404) def get_invoices(request): if not request.user.is_authenticated and (request.user.groups.filter(name="finance") or request.user.is_superuser): return HttpResponseForbidden() date_from = request.GET.get('from', None) date_to = request.GET.get('to', None) file_name = "invoices" file_name = file_name + "__from_%s" % date_from if date_from else file_name file_name = file_name + "__to_%s" % date_to if date_to else file_name invoices = Invoice.objects.filter(method="Y", status="F") invoices = invoices.filter(yandex_pay__performed_datetime__lt=date_to) if date_to else invoices invoices = invoices.filter(yandex_pay__performed_datetime__gte=date_from) if date_from else invoices response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename="%s.csv"' % file_name writer = csv.writer(response) writer.writerow(['date', 'time', 'student_email', 'full_name', 'course', 'price', 'real_price', 'key']) for i in invoices.order_by('-date'): course_api = CourseParamsApi(i.bill.course_token) writer.writerow([ i.yandex_pay.performed_datetime.date(), i.yandex_pay.performed_datetime.time(), i.bill.user.email, i.bill.user.get_full_name(), course_api.get_slug_and_title()['title'], i.price, i.real_price, i.key, ]) return response class YandexCheckView(APIView): renderer_classes = (JSONRenderer,) @staticmethod def post(request): data = dict() for i in request.body.decode('utf-8').split('&'): key = i.split('=')[0] val = i.split('=')[1] data[key] = val logger_yandex.info('Проверка платежа запрос', exc_info=True, extra={ 'request': data, }) try: pay = Payment.objects.get(order_number=data['orderNumber']) except Payment.DoesNotExist: logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ 'request': "Payment with id=%s not found" % data['orderNumber'], }) return Response(status=204) if not pay.status == Payment.STATUS.PROCESSED: logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ 'request': "Payment with id=%s have status %s" % (data['orderNumber'], pay.status), }) return Response(status=204) if not pay.shop_id == int(data['shopId']): logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ 'request': "ShopId=%s not match" % (data['shopId'],), }) return Response(status=204) if not pay.scid == int(data['scid']): logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ 'request': "scid=%s not match" % (data['scid'],) }) return Response(status=204) if not pay.order_amount == float(data['orderSumAmount']): logger_yandex.error('Ошибка проверки платежа', exc_info=True, extra={ 'request': "Expected amount is %s received amount is %s" % (pay.order_amount, data['orderSumAmount']), }) return Response(status=204) now = timezone.now() pay.performed_datetime = now.isoformat() pay.save() xml_res = """ """ % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id)) logger_yandex.info('Проверка платежа ответ', exc_info=True, extra={ 'response': xml_res, }) return HttpResponse(xml_res, content_type='application/xml') class YandexAvisoView(APIView): renderer_classes = (JSONRenderer,) @staticmethod def post(request): data = dict() for i in request.body.decode('utf-8').split('&'): key = i.split('=')[0] val = i.split('=')[1] data[key] = val try: pay = Payment.objects.get(order_number=data['orderNumber']) except Payment.DoesNotExist: logger_yandex.error('Ошибка подтверждения платежа', exc_info=True, extra={ 'request': "Payment with invoice_id=%s not found" % data['orderNumber'], }) return Response(status=204) logger_yandex.info('Подтверждение платежа запрос', exc_info=True, extra={ 'request': 'Get success pay with invoice_id(yandex) %s' % str(data['invoiceId']), }) pay.shop_amount = data['shopSumAmount'] pay.status = Payment.STATUS.SUCCESS now = timezone.now() pay.performed_datetime = now.isoformat() pay.save() xml_res = """ """ % (pay.performed_datetime, str(data['invoiceId']), str(pay.shop_id)) logger_yandex.info('Подтверждение платежа ответ', exc_info=True, extra={ 'response': xml_res, }) msg = EmailMessage( 'Успешная оплата.', '''Пользователь "%s", перевёл %s рублей. Номер платежа в яндекс кассе %s''' % (pay.invoice.bill.user.email, str(pay.invoice.price), str(data['invoiceId'])), 'robo@skillbox.ru', [pay.invoice.bill.opener.email], bcc=['dmitry.dolya@skillbox.ru', 'vera.procenko@skillbox.ru'], ) msg.send() return HttpResponse(xml_res, content_type='application/xml') class YandexFailView(APIView): renderer_classes = (JSONRenderer,) @staticmethod def post(request): data = dict() for i in request.body.decode('utf-8').split('&'): key = i.split('=')[0] val = i.split('=')[1] data[key] = val logger_yandex.error(data) return redirect(to=settings.DOMAIN) class DemoYandexCheckView(YandexCheckView): """для тестирования платежей""" pass class DemoYandexAvisoView(YandexAvisoView): pass