Merge branch 'pm_payments_repeat' into 'dev'

Повторные платежи

See merge request !260
remotes/origin/feature/test_courses_^2
Andrey 8 years ago
commit 706c376114
  1. 7
      finance/admin.py
  2. 25
      finance/migrations/0004_auto_20180321_1653.py
  3. 8
      finance/models.py
  4. 4
      finance/signals.py
  5. 86
      finance/tasks.py
  6. 6
      finance/views.py
  7. 3
      lms/settings.py

@ -3,5 +3,10 @@ from django.contrib import admin
from finance.models import Bill, Invoice from finance.models import Bill, Invoice
class InvoiceAdmin(admin.ModelAdmin):
list_display = ('__str__', 'rebilling_on', 'rebilling')
admin.site.register(Bill) admin.site.register(Bill)
admin.site.register(Invoice) admin.site.register(Invoice, InvoiceAdmin)

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2018-03-21 16:53
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0003_auto_20180315_1358'),
]
operations = [
migrations.AddField(
model_name='invoice',
name='rebilling',
field=models.BooleanField(default=False, editable=False, verbose_name='Повторный платеж'),
),
migrations.AddField(
model_name='invoice',
name='rebilling_on',
field=models.BooleanField(default=False, editable=False, verbose_name='Повторять платеж'),
),
]

@ -58,11 +58,9 @@ class Invoice(models.Model):
blank=True, editable=False) blank=True, editable=False)
bill = models.ForeignKey(to=Bill, verbose_name="Связный счёт") bill = models.ForeignKey(to=Bill, verbose_name="Связный счёт")
is_open = models.BooleanField(default=True, verbose_name="Открывает ли платёж курс") is_open = models.BooleanField(default=True, verbose_name="Открывает ли платёж курс")
date = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") date = models.DateTimeField(auto_now_add=True)
rebilling_on = models.BooleanField(verbose_name='Повторять платеж', default=False, editable=False)
def get_comment(self): rebilling = models.BooleanField(verbose_name='Повторный платеж', default=False, editable=False)
return '''Вам выставлен счёт,''' if \
self.comment == "" else self.comment
def __str__(self): def __str__(self):
return '%s:%s %s' % (self.id, self.get_status_display(), self.bill.user) return '%s:%s %s' % (self.id, self.get_status_display(), self.bill.user)

@ -16,7 +16,7 @@ def invoice_signal(instance, **kwargs):
course = Course.objects.get(token=instance.bill.course_token) course = Course.objects.get(token=instance.bill.course_token)
if instance.yandex_pay and instance.method == 'Y' and instance.status == 'P': if instance.yandex_pay and instance.method == 'Y' and instance.status == 'P' and not instance.rebilling:
msg = EmailMessage( msg = EmailMessage(
'Вам выставлен новый счёт', 'Вам выставлен новый счёт',
"""%s для оплаты перейдите по ссылке """%s для оплаты перейдите по ссылке
@ -27,7 +27,7 @@ def invoice_signal(instance, **kwargs):
) )
msg.send() msg.send()
if instance.status == 'F': if instance.status == 'F' and not instance.rebilling:
if instance.is_open: if instance.is_open:
try: try:
Progress.objects.get( Progress.objects.get(

@ -0,0 +1,86 @@
import json
from datetime import datetime, timedelta
import logging
import os
import requests
from django_celery_beat.models import CrontabSchedule, PeriodicTask
from yandex_money.models import Payment
from finance.models import Invoice
from lms import celery_app
from django.conf import settings
logger_yandex = logging.getLogger('yandex_money')
def setup_periodic_billing(order_number):
# TODO: настроить периодичность и срок окончания
# 12:00 первого числа каждого месяца
schedule, _ = CrontabSchedule.objects.get_or_create(
minute='0',
hour='12',
day_of_week='*',
day_of_month='1',
month_of_year='*'
)
PeriodicTask.objects.create(
crontab=schedule,
name='Periodic billing (order_number={})'.format(order_number),
task='finance.tasks.periodic_billing',
kwargs=json.dumps({
'order_number': order_number
}),
expires=datetime.utcnow() + timedelta(days=180) # в течение полугода
)
@celery_app.task
def periodic_billing(order_number):
try:
sample = Invoice.objects.get(yandex_pay__order_number=order_number)
except Invoice.DoesNotExist:
raise ValueError('Номер заказа {} не найден'.format(order_number))
bill = sample.bill
invoice = Invoice.objects.create(
status='P',
price=sample.price,
method=sample.method,
rebilling=True,
bill=bill
)
if invoice.method == 'Y':
user = bill.user
yandex_pay = Payment.objects.create(
invoice_id=sample.yandex_pay.invoice_id,
order_amount=invoice.price,
customer_number=user.id,
user=user,
cps_email=user.email
)
invoice.yandex_pay = yandex_pay
invoice.save()
repeat_card_payment(invoice)
def repeat_card_payment(invoice):
resp = requests.post(settings.YANDEX_MONEY_MWS_URL + 'repeatCardPayment',
data={
'clientOrderId': invoice.id, # уникальное возрастающее целое число
'invoiceId': invoice.yandex_pay.invoice_id,
'amount': invoice.price,
'orderNumber': invoice.yandex_pay.order_number
},
cert=(
os.path.join(settings.SSL_ROOT, 'skillbox.cer'),
os.path.join(settings.SSL_ROOT, 'skillbox.key')
),
verify=os.path.join(settings.SSL_ROOT, 'yamoney_chain.cer'))
logger_yandex.info(resp.text)

@ -21,6 +21,7 @@ from courses.models import Course
from courses.api import CourseParamsApi from courses.api import CourseParamsApi
from finance.models import Bill, Invoice from finance.models import Bill, Invoice
from finance.serializers import BillSerializer, InvoiceSerializer from finance.serializers import BillSerializer, InvoiceSerializer
from finance.tasks import setup_periodic_billing
from lms.global_decorators import transaction_decorator from lms.global_decorators import transaction_decorator
from lms.tools import get_real_name from lms.tools import get_real_name
from django.utils import timezone from django.utils import timezone
@ -254,6 +255,7 @@ class YandexPay(APIView):
'customerNumber': pay.customer_number, 'customerNumber': pay.customer_number,
'orderNumber': pay.order_number, 'orderNumber': pay.order_number,
'cps_email': pay.cps_email, 'cps_email': pay.cps_email,
'rebillingOn': pay.invoice.rebilling_on,
'shopSuccessURL': settings.YANDEX_MONEY_SUCCESS_URL, 'shopSuccessURL': settings.YANDEX_MONEY_SUCCESS_URL,
'shopFailURL': settings.YANDEX_MONEY_FAIL_URL, 'shopFailURL': settings.YANDEX_MONEY_FAIL_URL,
}) })
@ -399,6 +401,7 @@ class YandexAvisoView(APIView):
pay.shop_amount = data['shopSumAmount'] pay.shop_amount = data['shopSumAmount']
pay.status = Payment.STATUS.SUCCESS pay.status = Payment.STATUS.SUCCESS
pay.invoice_id = data['invoiceId']
now = timezone.now() now = timezone.now()
pay.performed_datetime = now.isoformat() pay.performed_datetime = now.isoformat()
pay.save() pay.save()
@ -428,6 +431,9 @@ class YandexAvisoView(APIView):
msg.attach_alternative(html_content, "text/html") msg.attach_alternative(html_content, "text/html")
msg.send() msg.send()
if pay.invoice.rebilling_on:
setup_periodic_billing(pay.order_number)
return HttpResponse(xml_res, content_type='application/xml') return HttpResponse(xml_res, content_type='application/xml')

@ -47,6 +47,7 @@ YANDEX_MONEY_SHOP_ID = '157133'
YANDEX_MONEY_SHOP_PASSWORD = 'nu5Xefise' YANDEX_MONEY_SHOP_PASSWORD = 'nu5Xefise'
YANDEX_MONEY_FAIL_URL = '%s/api/v1/finance/yandex/fail/' % DOMAIN YANDEX_MONEY_FAIL_URL = '%s/api/v1/finance/yandex/fail/' % DOMAIN
YANDEX_MONEY_SUCCESS_URL = '%s/' % DOMAIN YANDEX_MONEY_SUCCESS_URL = '%s/' % DOMAIN
YANDEX_MONEY_MWS_URL = 'https://penelope.yamoney.ru/webservice/mws/api/'
# информировать о случаях, когда модуль вернул Яндекс.Кассе ошибку # информировать о случаях, когда модуль вернул Яндекс.Кассе ошибку
YANDEX_MONEY_MAIL_ADMINS_ON_PAYMENT_ERROR = True YANDEX_MONEY_MAIL_ADMINS_ON_PAYMENT_ERROR = True
# Application definition # Application definition
@ -180,6 +181,8 @@ STATIC_ROOT = os.path.join(BASE_DIR, 'static')
STATIC_URL = '/static/' STATIC_URL = '/static/'
SSL_ROOT = os.path.join(BASE_DIR, 'ssl')
RAVEN_CONFIG = { RAVEN_CONFIG = {
'dsn': 'http://1a09557dbd144e52af4b14bea569c114:fbb5dfaa39e64f02a1b4cc7ac665d7d7@sentry.skillbox.ru/7' 'dsn': 'http://1a09557dbd144e52af4b14bea569c114:fbb5dfaa39e64f02a1b4cc7ac665d7d7@sentry.skillbox.ru/7'
} }

Loading…
Cancel
Save