Django python платежные системы

Saved searches

Use saved searches to filter your results more quickly

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.

Django app for Sberbank payment API

License

madprogrammer/django-sberbank

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Sign In Required

Please sign in to use Codespaces.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching GitHub Desktop

If nothing happens, download GitHub Desktop and try again.

Launching Xcode

If nothing happens, download Xcode and try again.

Launching Visual Studio Code

Your codespace will open once ready.

There was a problem preparing your codespace, please try again.

Latest commit

Git stats

Files

Failed to load latest commit information.

README.md

Оплата через платежный API Сбербанка в Django

Это Django-приложение позволяет быстро приделать к сайту на Django прием оплаты с банковских карт с помощью платежного API Сбербанка. Приложение поддерживает:

  • Оплату через веб-формы (пользователь вводит данные карты на сервере Сбербанка)
  • Оплату с помощью Apple Pay и Google Pay
  • Привязку банковских карт и получение списка привязанных карт
  • Отслеживание истории транзакций и журналирование обмена с API Сбербанка в БД
INSTALLED_APPS = [ . 'sberbank', . ]
MERCHANTS = < %merchant_id%: < 'username': '%merchant_username%', 'password': '%merchant_password%', 'success_url': 'http://ваш.домен/sberbank/payment/success', 'fail_url': 'http://ваш.домен/sberbank/payment/fail', 'app_success_url': 'http://ваш.домен/payment/success', 'app_fail_url': 'http://ваш.домен/payment/fail', > >
urlpatterns = [ . url('/sberbank', include('sberbank.urls')) ]

Переменная окружения: ENVIRONMENT

Параметры словаря MERCHANTS

  • success_url — на данный URL Сбербанк будет перенаправлять браузер после успешного платежа
  • fail_url — на данный URL Сбербанк будет перенаправлять браузер после неуспешного платежа
  • app_success_url — это URL, с помощью которого ваше приложение может среагировать на успешный платеж после того, как отработает коллбэк success_url .
  • app_fail_url — это URL, с помощью которого ваше приложение может среагировать на неуспешный платеж после того, как отработает коллбэк fail_url .
Читайте также:  Html colors codes generator

Платеж с помощью веб-формы

from sberbank.service import BankService from sberbank.models import Payment, Status . try: # Сумма в рублях amount = 10.0 # Уникальный ID пользователя, используется для привязки карт # Если None, пользователь не сможет выбрать ранее привязанную карту # или привязать карту в процессе оплаты client_id = request.data.get("client_id") svc = BankService(%merchant_id%) # url - адрес, на который следует перенаправить пользователя для оплаты # payment - объект Payment из БД, содержит информацию о платеже # description - назначение платежа в веб-форме банка # params - произвольные параметры, которые можно привязать к платежу payment, url = svc.pay(amount, params='foo': 'bar'>, client_id=client_id, description="Оплата заказа №1234") return HttpResponseRedirect(url) except Exception as exc: # Что-то пошло не так raise

Привязка карты со списанием и возвратом 1 рубля

from sberbank.service import BankService from sberbank.models import Payment, Status . try: # Уникальный ID пользователя, используется для привязки карт # параметр необходимо передавать при использовании функции привязки карт # через списание и возврат client_id = request.data.get("client_id") if client_id is None: return HttpResponseBadRequest() svc = BankService(%merchant_id%) # url - адрес, на который следует перенаправить пользователя для оплаты # payment - объект Payment из БД, содержит информацию о платеже payment, url = svc.bind_refund(client_id=client_id) return HttpResponseRedirect(url) except Exception as exc: # Что-то пошло не так raise

Оплата с помощью Apple/Google Pay

from sberbank.service import BankService from sberbank.models import Payment, Status . try: # Уникальный ID пользователя, используется для привязки карт # параметр необходимо передавать при использовании функции привязки карт # через списание и возврат client_id = request.data.get("client_id") # Сумма платежа в рублях amount = 10.0 # Токен, переданный приложением для Apple/Android # библиотека сама определяет тип платежа по формату # переданного токена и вызывает соответствующее API Сбербанка token = request.data.get("token") # IP адрес клиента ip = request.META.get('REMOTE_ADDR', '127.0.0.1') svc = BankService(%merchant_id%) payment, response = svc.mobile_pay(amount, token, ip, client_id=client_id, params='foo': 'bar'>, description="Оплата заказа №1234") if response['success'] != True: return Response("status": "error">) if payment.status == Status.SUCCEEDED: # Платеж успешен json_response = "status": "success"> # Платежи с некоторых карт требуют особой обработки на клиенте # При наличии в ответе acsUrl клиенту нужно перенаправить пользователя # на адрес redirect_url, POST-запросом передав параметры в виде x-www-form-urlencoded if response['data'].get('acsUrl'): json_response.update("redirect_url": response['data'].get('acsUrl', '')>) json_response.update("params": < 'paReq': response['data'].get('paReq', ''), 'termUrl': response['data'].get('termUrl', ''), 'orderId': response['data'].get('orderId', '')>>) return Response(json_response) except Exception as exc: # Что-то пошло не так raise

Периодическая проверка платежей по которым не известно состояние

Читайте также:  Html image position relative to text

from datetime import timedelta from celery.task import periodic_task from sberbank.tasks import check_payments @periodic_task(run_every=timedelta(minutes=20)) def task_check_payments(): check_payments()

Источник

Разработка своей системы биллинга на Django

При разработке большинства сервисов возникает потребность во внутреннем биллинге для аккаунтов сервиса. Так и в нашем сервисе возникла такая задача. Готовые пакеты для её решения мы так и не смогли найти, в итоге пришлось разрабатывать систему биллинга с нуля.
В статье хочу рассказать о нашем опыте и подводных камнях, с которыми пришлось столкнуться во время разработки.

Задачи

Задачи, которые нам предстояло решить были типичны для любой системы денежного учета: прием платежей, лог транзакций, оплата и повторяющиеся платежи (подписка).

Транзакции

Основной единицей системы, очевидно, была выбрана транзакция. Для транзакции была написана следующая простая модель:

class UserBalanceChange(models.Model): user = models.ForeignKey('User', related_name='balance_changes') reason = models.IntegerField(choices=REASON_CHOICES, default=NO_REASON) amount = models.DecimalField(_('Amount'), default=0, max_digits=18, decimal_places=6) datetime = models.DateTimeField(_('date'), default=timezone.now) 

Транзакция состоит из ссылки на пользователя, причины пополнения (или списания), суммы транзакции и времени совершения операции.

Баланс

Баланс пользователя очень легко посчитать при помощи функции annotate из ORM Django (считаем сумму значений одного столбца), но мы столкнулись с тем, что при большом количестве транзакций данная операция сильно нагружает БД. Поэтому было решено денормализовать БД, добавив поле “balance” в модель пользователя. Данное поле обновляется в методе “save” в модели “UserBalanceChange”, а для уверенности в актуальности данных в нем, мы каждую ночь его пересчитываем.
Правильнее, конечно же, хранить информацию о текущем балансе пользователя в кэше (например, в Redis) и инвалидировать при каждом изменении модели.

Прием платежей

  • Регистрируемся в платежной системе;
  • Получаем API ключи;
  • Устанавливаем соответствующий пакет для Django;
  • Реализовываем форму оплаты;
  • Реализовываем функцию зачисления средств на баланс после оплаты.
from robokassa.signals import result_received def payment_received(sender, **kwargs): order = OrderForPayment.objects.get(id=kwargs['InvId']) user = User.objects.get(id=order.user.id) order.success=True order.save() try: sum = float(order.payment) except Exception, e: pass else: balance_change = UserBalanceChange(user=user, amount=sum, reason=BALANCE_REASONS.ROBOKASSA) balance_change.save() 

По аналогии можно подключить любую систему оплаты, например PayPal, Яндекс.Касса

Читайте также:  Узнать номер символа java

Списание средств

Со списаниями чуть сложнее – перед операцией необходимо проверять, каким будет баланс счета после проведения операции, причем “по-честному” – при помощи annotate. Это необходимо делать для того, чтобы не обслуживать пользователя “в кредит”, что особенно важно, когда транзакции выполняются на большие суммы.

payment_sum = 8.32 users = User.objects.filter(id__in=has_clients, balance__gt=payment_sum).select_related('tariff') 

Здесь мы написали без annotate, так как в данейшем есть дополнительные проверки.

Повторяющиеся списания

  • между выполнениями задачи в celery никогда не пройдет ровно час (биллинг-период);
  • пользователь пополняет свой баланс (он становится >0) и получает доступ к услугам между биллинг-периодами, снимать за период было бы нечестно;
  • пользователь может поменять тариф в любое время;
  • celery может по каким-либо причинам перестать выполнять задачи
  • Каждый биллинг-период мы смотрим время last_hourly_billing и списываем сумму согласно тарифному плану, затем обновляем поле last_hourly_billing;
  • При смене тарифного плана мы списываем сумму по прошлому тарифу и обновляем поле last_hourly_billing;
  • При активации услуги мы обновляем поле last_hourly_billing.
def charge_tariff_hour_rate(user): now = datetime.now second_rate = user.get_second_rate() hour_rate = (now - user.last_hourly_billing).total_seconds() * second_rate balance_change_reason = UserBalanceChange.objects.create( user=user, reason=UserBalanceChange.TARIFF_HOUR_CHARGE, amount=-hour_rate, ) balance_change_reason.save() user.last_hourly_billing = now user.save() 

Данная система, к сожалению, не является гибкой: если мы добавим еще один тип повторяющихся платежей — придется добавлять новое поле. Скорее всего, в процессе рефакторинга, мы напишем дополнительную модель. Примерно такую:

class UserBalanceSubscriptionLast(models.Model): user = models.ForeignKey('User', related_name='balance_changes') subscription = models.ForeignKey('Subscription', related_name='subscription_changes') datetime = models.DateTimeField(_('date'), default=timezone.now) 

Эта модель позволит очень гибко реализовать повторяющиеся платежи.

Dashboard

  • Последние 5 оплат и график платежей пользователей за последний месяц;
  • Пользователи, у которых баланс приближается к 0 (из тех, кто уже платил);

P.S. Уже в процессе написания статьи нашел готовый пакет django-account-balances, думаю, что можно обратить внимание, если вы делаете систему лояльности.

Источник

Оцените статью