Яндекс деньги

feature/fix_generate_pass
Andrey 8 years ago
parent 347455ced7
commit cfe1238b67
  1. 2
      access/models.py
  2. 40
      access/tasks.py
  3. 27
      csv/load_bills.py
  4. 20
      finance/migrations/0009_auto_20171108_1930.py
  5. 22
      finance/migrations/0010_auto_20171109_1140.py
  6. 5
      finance/models.py
  7. 91
      finance/pay.py
  8. 67
      finance/tasks.py
  9. 21
      finance/views.py
  10. 127
      finance/yandex_pay.py
  11. 79
      journals/tasks.py
  12. 18
      lms/settings.py
  13. 2
      lms/urls.py

@ -1,9 +1,7 @@
# encoding=utf-8
import random
import string
import json
from celery.result import AsyncResult
from django.contrib.contenttypes.models import ContentType
from django_celery_results.models import TaskResult

@ -1,40 +0,0 @@
# coding=utf-8
from celery.task import periodic_task
from datetime import timedelta, datetime
from access.models import User, TrafSource, TrafTokenHistory
# @periodic_task(run_every=timedelta(minutes=20))
# def check_prepo_delay():
# # Проверка просроченых задач преподавателя
# for res in User.objects.filter(delay_date__lte=datetime.now(), in_role='T'):
# res.delay = False
# res.delay_description = ''
# res.delay_date = None
# res.save()
#
#
# @periodic_task(run_every=timedelta(minutes=1))
# def check_online():
# for user in User.objects.filter(status='ON', last_time__lte=datetime.now()-timedelta(minutes=10)):
# user.status = 'OFF'
# user.save()
#
#
# @periodic_task(run_every=timedelta(hours=1))
# def check_traf_source():
# for source in TrafSource.objects.filter(on=True).exclude(live_time=None):
# if source.token and source.token_start + timedelta(hours=source.live_time) < datetime.now():
# source.on = False
# TrafTokenHistory.objects.create(token=source.token, source=source, live_time=source.live_time, date_start=source.token_start, date_end=datetime.now())
# source.token = None
# source.token_start = None
# source.save()
#@periodic_task(run_every=timedelta(minutes=1))
#def sync_users():
# for user in User.objects.filter(sync=False):
# result = sent_sync_user(user)
# if result:
# user._set_synced()

@ -1,6 +1,7 @@
import os, sys, django, csv
from django.contrib.auth import get_user_model
from django.db import IntegrityError
sys.path.append("../")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings")
@ -20,7 +21,7 @@ if __name__ == '__main__':
bill_kwarg['course'] = Course.objects.get(id=row.pop('course__id', None))
opener_id = row.pop('opener__id', None)
bill_kwarg['opener'] = get_user_model().objects.get(id=opener_id) if opener_id \
else get_user_model().objects.get(email="kate.gazukina@skillbox.ru")
else get_user_model().objects.get(email="kate.gazukina@skillbox.ru")
email = row.pop('user__email', None)
try:
@ -35,14 +36,20 @@ if __name__ == '__main__':
bill_kwarg['comment'] = row.pop('comment', None)
bill_kwarg['description'] = row.pop('description', None)
bill = Bill.objects.create(**bill_kwarg)
try:
price = int(row.pop('price', None))
except ValueError:
price = None
bill = Bill.objects.create(**bill_kwarg)
method = row.pop('bill_method', None)
try:
price = int(row.pop('price', None))
except ValueError:
price = None
try:
real_price = int(row.pop('real_price', None))
except ValueError:
real_price = None
Invoice.objects.create(bill=bill, price=price, real_price=real_price, **row)
try:
real_price = int(row.pop('real_price', None))
except ValueError:
real_price = None
Invoice.objects.create(bill=bill, method=method, price=price, real_price=real_price, **row)
except IntegrityError:
pass

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-11-08 19:30
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0008_auto_20171108_1435'),
]
operations = [
migrations.AlterField(
model_name='invoice',
name='key',
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Ключ платежа'),
),
]

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-11-09 11:40
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('courses', '0007_auto_20171103_1627'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('finance', '0009_auto_20171108_1930'),
]
operations = [
migrations.AlterUniqueTogether(
name='bill',
unique_together=set([('course', 'opener', 'user')]),
),
]

@ -21,6 +21,9 @@ class Bill(models.Model):
class Meta:
verbose_name = 'Счет'
verbose_name_plural = 'Счета'
unique_together = (
('course', 'opener', 'user',),
)
class Invoice(models.Model):
@ -43,7 +46,7 @@ class Invoice(models.Model):
real_price = models.IntegerField(verbose_name='Полученная сумма', null=True, blank=True,
help_text='Сумма, минус комиссия')
method = models.CharField(verbose_name='Способ оплаты', max_length=2, default='Y', choices=BILL_METHOD)
key = models.CharField(verbose_name='Ключ платежа', blank=True, max_length=255, default='')
key = models.CharField(verbose_name='Ключ платежа', blank=True, max_length=255, null=True)
comment = models.TextField(verbose_name='Комментарий продавца', help_text='Будет показано пользователю',
blank=True, editable=False)
bill = models.ForeignKey(to=Bill, verbose_name="Связный счёт")

@ -1,91 +0,0 @@
# coding=utf-8
## Реализация платежных сервисов
from django.shortcuts import render
from lms.decors import response_decor
from finance.models import Bill
from django.http import Http404
from lms.tools import gen_pay_sig
@response_decor(template='good_pay.html', without_auth=True)
def success(request):
# Страница успешного платежа
if request.GET.get('sp_sig') and gen_pay_sig(request.GET) == request.GET.get('sp_sig'):
try:
bill = Bill.objects.get(id=request.GET['sp_order_id'])
except Bill.DoesNotExist:
raise Http404
else:
bill.status = 'F' if request.GET['sp_result'] == '1' else 'C'
bill.out_id = request.GET['sp_payment_id']
bill._method = 'S'
bill.save()
url = '/?success_pay=True' if bill.service.freepay else '/?success_pay=True&course_id={0}'.format(bill.service.course.id)
if bill.admitad_uid:
url += '&admitad_uid={0}&order_id={1}&email={2}'.format(bill.admitad_uid, bill.id, bill.user.email)
return {'redirect': url}
else:
raise Http404
@response_decor(template='fail_pay.html', without_auth=True)
def fail(request):
# Страница ошибки платежа
if request.GET.get('sp_sig') and gen_pay_sig(request.GET) == request.GET.get('sp_sig'):
try:
bill = Bill.objects.get(id=request.GET['sp_order_id'])
except Bill.DoesNotExist:
raise Http404
else:
bill.status = 'F' if request.GET['sp_result'] else 'C'
bill.out_id = request.GET['sp_payment_id']
bill._method = 'S'
bill.save()
url = '/?fail_pay=True&fail_url={0}'.format(bill.service.url) if bill.service.freepay else '/?fail_pay=True&fail_pay_id={0}'.format(bill.id)
return {'redirect': url}
else:
raise Http404
def result(request):
# Страница получения результата о платежах
if request.GET.get('sp_sig') and gen_pay_sig(request.GET) == request.GET.get('sp_sig'):
try:
bill = Bill.objects.get(id=request.GET['sp_order_id'])
except Bill.DoesNotExist:
keys = {'sp_salt': request.GET['sp_salt'],
'sp_status': 'error',
'sp_description': 'Order not found'}
return render(request, 'simplepayresult.xml',
{"salt": request.GET['sp_salt'],
'status': 'error',
'description': 'Order not found',
'sig': gen_pay_sig(keys)},
content_type="application/xhtml+xml")
else:
bill.status = 'F' if request.GET['sp_result'] == '1' else 'C'
bill.out_id = request.GET['sp_payment_id']
bill._method = 'S'
bill.save()
keys = {'sp_salt': request.GET['sp_salt'],
'sp_status': 'ok',
'sp_description': 'Good pay'}
return render(request, 'simplepayresult.xml',
{'salt': request.GET['sp_salt'],
'status': 'ok',
'sig': gen_pay_sig(keys),
'description': 'Good pay'},
content_type="application/xhtml+xml")
else:
raise Http404

@ -1,40 +1,27 @@
# coding=utf-8
from celery.task import periodic_task
from datetime import timedelta, datetime
from django.db.models import Q
from finance.models import Price, Bill, ServiceRequest
from courses.models import CourseMap
# @periodic_task(run_every=timedelta(minutes=1))
# def price_map_migrator():
# for price in Price.objects.filter(included=None).exclude(course=None):
# if not price.included.exists():
# inc_type = []
#
# if price.m_type == 'B':
# inc_type = ['B']
# elif price.m_type == 'E':
# inc_type = ['B', 'E']
# elif price.m_type == 'P':
# inc_type = ['B', 'E', 'P']
# for m in CourseMap.objects.filter(course=price.course):
# if m.get_obj().theme.price_type in inc_type:
# price.included.add(m)
#
#
# @periodic_task(run_every=timedelta(hours=1))
# def price_map_migrator():
# for price in Price.objects.exclude(by_time=None):
# for bill in Bill.objects.filter(service=price, fire_date__lt=datetime.now()):
# bill.status = 'H'
# bill.save()
#
#
# @periodic_task(run_every=timedelta(minutes=1))
# def sent_service_request_to_amo():
# sr = ServiceRequest.objects.filter(send=False, send_date__lt=datetime.now()).exclude(Q(name='TEST')| Q(status='E')).first()
# if sr:
# sr.sent_to_amo()
from __future__ import absolute_import, unicode_literals
from celery import shared_task
import requests
from django.core.mail import send_mail
@shared_task
def send_to_yandex(pay):
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,
})
body = {
"subject": 'Спасибо за регистрацию',
"message": '''Вам выставлен счёт, для оплаты перейдите по ссылке %s''' % r.url,
"from_email": 'robo@skillbox.ru',
"recipient_list": [pay.cps_email],
}
send_mail(
**body
)
return r.url

@ -1,12 +1,14 @@
from django.contrib.auth import get_user_model
from courses.models import Course
from finance.tasks import send_to_yandex
from lms.global_decorators import transaction_decorator
from rest_framework.views import APIView
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from django.db.models import Q
from yandex_money.models import Payment
from finance.models import Bill, Invoice
from finance.serializers import BillSerializer, InvoiceSerializer
from lms.tools import get_real_name
@ -34,18 +36,25 @@ class BillListView(APIView):
if bill:
bill['user'] = get_user_model().objects.get(email=bill['user'])
bill['opener'] = get_user_model().objects.get(email=bill['opener'])
bill['course'] = Course.objects.get(title=bill['course'])
bill['course'] = Course.objects.get(title=bill['course'][0])
bill_obj, is_create = Bill.objects.update_or_create(**bill)
invoices = bill_obj.invoice_set.all()
for i in children:
i['method'] = get_real_name(elem=i['method'], array=Invoice.BILL_METHOD)
i['status'] = get_real_name(elem=i['status'], array=Invoice.BILL_STATUSES)
i['method'] = get_real_name(elem=i['method'][0], array=Invoice.BILL_METHOD)
i['status'] = get_real_name(elem=i['status'][0], array=Invoice.BILL_STATUSES)
i['bill'] = bill_obj
invoice, _is_create = Invoice.objects.update_or_create(**i)
invoices = [j for j in invoices if not j.id == invoice.id]
if invoice.method == 'Y' and invoice.status == 'P':
print("Отправить письмо")
pay, _is_create = Payment.objects.get_or_create(
order_amount=invoice.price,
order_number=bill_obj.id,
customer_number=bill_obj.user.id,
user=bill_obj.user,
cps_email=bill_obj.user.email,
)
send_to_yandex(pay)
[i.delete() for i in invoices]
@ -81,4 +90,6 @@ class BillDetailView(APIView):
res,
status=self.status_code,
)
return Response("Permission denied", status=403)
return Response("Permission denied", status=403)

@ -1,127 +0,0 @@
# coding=utf-8
import datetime
from hashlib import md5
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from finance.models import Bill, YandexKassaHistory
from settings.settings import YANDEX_MONEY_SHOP_PASSWORD
def gen_md5(cd):
return md5(';'.join((
cd['action'],
cd['orderSumAmount'],
cd['orderSumCurrencyPaycash'],
cd['orderSumBankPaycash'],
cd['shopId'],
cd['invoiceId'],
cd['customerNumber'],
YANDEX_MONEY_SHOP_PASSWORD,
)).encode('utf-8')).hexdigest().upper()
@csrf_exempt
def aviso(request):
# Страница получения результата о платежах
data = request.POST
tmp = {}
for key, value in data.items():
tmp[key] = value
tmp = str(tmp)
_time = datetime.datetime.now()
_log = YandexKassaHistory.objects.create(text=tmp, _type='paymentAvisoResponse')
result = {
'performedDatetime': _time.isoformat(),
'code': '200',
'shopId': data.get('shopId'),
'invoiceId': data.get('invoiceId'),
'message': ''
}
if not data.get('md5'):
return render(request, 'yandexkassa_result.xml', {'check_type': 'paymentAvisoResponse', 'data': result},
content_type="application/xhtml+xml")
if data['md5'] == gen_md5(data):
try:
bill = Bill.objects.get(id=data['orderNumber'])
except Bill.DoesNotExist:
result['message'] = u'Не найден счет по указанным данным'
else:
if str(bill.user.id) == data['customerNumber']:
bill.status = 'F'
bill.real_price = data['shopSumAmount']
bill.out_id = data['invoiceId']
bill.status_changed = _time
bill.save()
result['code'] = '0'
else:
result['message'] = u'Не найден пользователь, указанный в запросе'
else:
result['code'] = '1'
result['message'] = u'Не сходится ключ платежа'
return render(request, 'yandexkassa_result.xml', {'check_type': 'paymentAvisoResponse', 'data': result},
content_type="application/xhtml+xml")
@csrf_exempt
def check(request):
# Страница получения результата о платежах
data = request.POST
_time = datetime.datetime.now()
tmp = {}
for key, value in data.items():
tmp[key] = value
tmp = str(tmp)
if data.get('action'):
YandexKassaHistory.objects.create(text=tmp, _type=data['action'])
else:
YandexKassaHistory.objects.create(text=tmp, _type='empty_check')
result = {
'performedDatetime': _time.isoformat(),
'code': '200' if data.get('action') == 'checkOrder' else '1',
'shopId': data.get('shopId'),
'orderSumAmount': data.get('orderSumAmount'),
'invoiceId': data.get('invoiceId'),
'message': ''
}
if not data.get('md5'):
return render(request, 'yandexkassa_result.xml',
{'check_type': 'checkOrderResponse',
'data': result},
content_type="application/xhtml+xml")
if data['md5'] == gen_md5(data):
try:
bill = Bill.objects.get(id=data['orderNumber'])
except Bill.DoesNotExist:
result['message'] = u'Не найден счет по указанным данным'
else:
if str(bill.user.id) == data['customerNumber']:
if data['action'] != 'checkOrder':
bill.status = 'B'
bill.out_id = data['invoiceId']
bill.status_changed = _time
bill._method = 'Y'
bill.inside_data = tmp
bill.test = True
bill.save()
result['code'] = '0'
else:
result['message'] = u'Не найден пользователь, указанный в запросе'
else:
result['code'] = '1'
result['message'] = u'Не сходится ключ платежа'
result['tech_message'] = str(data['md5']) + str('_') + str(gen_md5(data))
return render(request, 'yandexkassa_result.xml', {'check_type': 'checkOrderResponse' if data['action'] == 'checkOrder' else 'cancelOrderResponse', 'data': result},
content_type="application/xhtml+xml")

@ -1,79 +0,0 @@
# coding=utf-8
from datetime import timedelta, datetime
from celery.task import periodic_task
from django.core.files import File
from management.letters import sent_new_expired
from access.models import User
from journals.models import ExamTry, HomeworkTry, DiplomaJ
from settings.settings import TEACHER
# @periodic_task(run_every=timedelta(hours=1))
# def check_expired():
# # Проверка просроченых задач преподавателя
# for res in (ExamTry.objects.filter(f_date=None).exclude(expired=True),
# HomeworkTry.objects.filter(f_date=None).exclude(expired=True)):
# for _try in res:
# if _try.parent.get_status_flag() not in ['N', 'F']:
# # Проверка экзамена
# if _try.date + timedelta(days=1) < datetime.now():
# _try.expired = True
# _try.save()
# for user in User.objects.filter(in_role='S2'):
# sent_new_expired(_try, user.email)
#
#
# @periodic_task(run_every=timedelta(minutes=1))
# def check_robo_prep():
# teacher = User.objects.get(email=TEACHER)
# handler = []
# for journal in HomeworkTry.objects.filter(teacher=teacher, f_date=None).exclude(success=True, date=None).order_by(
# 'date'):
# if journal.parent.get_status_flag not in ['N', 'F']:
# handler.append(journal)
#
# for journal in ExamTry.objects.filter(teacher=teacher, f_date=None).exclude(success=True, date=None).order_by(
# 'date'):
# if journal.parent.get_status_flag not in ['N', 'F']:
# handler.append(journal)
#
# print(handler)
# for _tr in handler:
# for _cm in _tr.comments.all():
# s = False
# print(_cm.text)
# if 'GO_TO_SUCCESS' in _cm.text:
# _tr.success = True
# _tr.f_date = datetime.now()
# s = True
# elif 'GO_TO_FAIL' in _cm.text:
# _tr.f_date = datetime.now()
# s = True
# if s:
# _tr.save()
#
#
# #@periodic_task(run_every=timedelta(minutes=3))
# #def block_warning():
# # for tm in CourseThemeJ.objects.filter(material__empty=True):
# # for n in CourseThemeJ.objects.filter(material__sort__gte=tm.material.sort-1, f_date=None).exclude(date=None):
# # for u in User.objects.filter(in_role='A'):
# # letters.block_warning(n, n.material.course.get_title(), u)
#
#
# @periodic_task(run_every=timedelta(minutes=3))
# def gen_in_diploma():
# for tm in DiplomaJ.objects.filter(gen=False):
# if not tm.out_image or not tm.in_image:
# _in, _out = tm.draw_key(*tm.draw_name(*tm.draw_date()))
# if _in:
# _in = open(_in, 'rb')
# tm.in_image.save(File(_in).name, File(_in), save=True)
#
# if _out:
# _out = open(_out, 'rb')
# tm.out_image.save(File(_out).name, File(_out), save=True)
# tm.gen = True
# tm.save()

@ -3,6 +3,13 @@ import os
import raven
import environ
import socket
try:
HOSTNAME = socket.gethostname()
except:
HOSTNAME = 'localhost:8000'
root = environ.Path(__file__) - 2
env = environ.Env()
@ -54,9 +61,15 @@ AMO_USER_LOGIN = 'baryshnikov@mokselle.com'
AMO_USER_HASH = 'd639c26c1c1900e5a8cee66cd3395bdc'
AMO_SUBDOMAIN = 'mokselle'
DEFAULT_FROM_EMAIL = 'robo@skillbox.ru'
YANDEX_MONEY_DEBUG = False
YANDEX_MONEY_SCID = '149639'
YANDEX_MONEY_SHOP_ID = '157133'
YANDEX_MONEY_SHOP_PASSWORD = 'nu5Xefise'
YANDEX_SHOP_ID = '157133'
YANDEX_scid = '149639'
YANDEX_MONEY_FAIL_URL = 'https://%s/finance/fail/' % HOSTNAME
YANDEX_MONEY_SUCCESS_URL = 'https://%s/finance/access/' % HOSTNAME
# информировать о случаях, когда модуль вернул Яндекс.Кассе ошибку
YANDEX_MONEY_MAIL_ADMINS_ON_PAYMENT_ERROR = True
# Application definition
# место куда сохраняем пользовательские файлы
@ -87,6 +100,7 @@ INSTALLED_APPS = [
'django_celery_results',
'django_celery_beat',
"djcelery_email",
'yandex_money',
'raven.contrib.django.raven_compat',
'access',
'courses',

@ -9,5 +9,5 @@ urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^media/(?P<path>.*)/$', serve, {'document_root': settings.MEDIA_ROOT}),
url(r'^static/(?P<path>.*)/$', serve, {'document_root': settings.STATIC_ROOT}),
url(r'^yandex-money/', include('yandex_money.urls')),
]

Loading…
Cancel
Save