- PVSM.RU - https://www.pvsm.ru -

Как мы интегрировали платежную систему в российский проект

image

Пять месяцев назад мы опубликовали NPM модуль для работы с новой версией Яндекс.Касса, которая вышла в октябре 2017 года. Наш модуль попал в официальную документацию, и его уже скачали более 1300 раз.

image

На Хабре, совместно с коллегами из Яндекса, мы уже рассказывали [1] об опыте создания модуля, но за кадром остался наш опыт, который мы получили, когда столкнулись с интеграцией платежной системы для российских клиентов.

Поэтому сегодня мы хотим рассказать, как для одного из отечественных клиентов мы переходили от интеграции привычных нам заграничных платежных систем на русские аналоги, с какими трудностями столкнулись и как их решали.

Как работали с платёжными системами

Раньше мы работали только с платежными системами зарубежных клиентов. У нас был опыт интеграции с Authorize.net, Paypal, Braintree, Stripe, Payoneer, Wirecard и Svea.

С этими платёжными системами легко взаимодействовать и реализовать разные функции. Например, когда мы работали над сервисом грузоперевозок по Европе, мы интегрировали в проект несколько систем оплаты и написали алгоритм — он реализовывал сложную логику денежных операций. Когда пользователь заказывал услугу, система переводила деньги со счёта заказчика на счёт сервиса, а алгоритм проводил транзакции: пересчитывал оплату в случае проблем с доставкой, конвертировал в валюту, проводил возврат и перенос сроков платежей, списывал процент за использование сервиса.

Лучшие представители платёжных систем позволяют начать разработку в песочнице даже без регистрации. У многих — отличная документация, и почти все помогают решать задачи без активного участия поддержки. Разработчики могут из личного кабинета управлять правами и доступами. Платёжные системы имеют SDK для большинства популярных платформ, что уже сейчас — негласный стандарт.

Чтобы интегрировать платёжную систему, разработчику нужно:

  1. Зарегистрироваться на сайте и получить доступ к песочнице.
  2. Скачать SDK и подключить его. Вставить в нужных местах приложения вызовы функций платежной системы.
  3. Протестировать все сценарии и убедиться, что всё работает правильно.
  4. Заниматься другими задачами, пока заказчик решает финансовые и юридические вопросы.
  5. В нужный момент времени переключить приём платежей в «боевой» режим.

Что поменялось

Год назад мы начали работать и на отечественном рынке. Одним из первых проектов стало приложение Sellsay [2]. Оно помогает пользователям развивать навыки в переговорах, а также является площадкой для взаимной профессиональной помощи.

У приложения много возможностей помимо стандартных функций: авторизации и регистрации, создания и редактирования проектов. Через сервис вы можете обратиться
к бизнес-тренеру. Если вы обладаете необходимыми знаниями, вы можете получить сертификат и стать самостоятельным тренером, участвовать в событиях и тренингах
от создателей приложения, зарабатывать деньги.

Чтобы в сервисе могли расплачиваться, было необходимо интегрировать платёжную систему — такую, где можно платить рублями и долларами, переносить срок платежа и делать его возврат, сохранять карты и не вводить данные при повторных покупках, использовать Apple и Android Pay. Чтобы это реализовать, мы выбрали систему Braintree.

И тут мы допустили огромный фейл. Мы согласовали и реализовали основной функционал работы с платёжной системой, но не учли одной важной детали. Узнали о ней за две недели до релиза, когда готовили проект к запуску. Мы не учли, что Braintree не работает с компаниями из России. Зарегистрировать компанию в штатах — не вариант. У нас остался один выход: в кратчайшие сроки заменить систему оплаты.

Яндекс.Касса: работа с первой версией API

После анализа систем мы остановились на Яндекс.Кассе: сервис позволял реализовать почти весь функционал, подходил клиенту по цене и решал проблему 54-ФЗ при подключении онлайн-кассы.

Чуть позже мы поняли, что наше видение интеграции в корне отличается от видения Яндекс.Кассы и её службы безопасности. Весь этап интеграции запомнился больше бесконечными договорами, бланками и созвонами, нежели написанием кода.

Так, чтобы получить тестовые ключи, необходимо предоставить ссылку на приложение в Apple Store или Google Play. Откуда у нас ссылка, если приём платежей — обязательное требование для публикации приложения? Эту проблему удалось решить, но и потом возникали ситуации, когда необходимо было реализовать и опубликовать функционал для его активации менеджером.

Да, почти все запросы решаются общением с персональным менеджером. Но если вопросы в личном кабинете попадают к личному менеджеру, то при звонке велика вероятность попасть на случайного, свободного на линии менеджера и получить совершенно случайный ответ. Через некоторое время — попасть на другого менеджера и получить противоположный ответ на тот же вопрос.

Ещё одно неудобство: Яндекс поддерживает API нескольких поколений. Даже у Яндекс.Кассы несколько подсистем, которые используют разную документацию, аутентификацию и так далее. В итоге приходится одновременно реализовывать несвязанные между собой API. Например, реализуете приём платежей, а для отмены необходимо начинать всё сначала: заявки, договор, звонки, изучение и интеграцию API.

Финальные недели перед запуском превратились в ад. Чтобы запустить проект вовремя, нам пришлось усилить команду и работать сверхурочно, а Яндекс.Касса тем временем не упускала возможность дать нам понервничать.

Сравнение Яндекс.Касса со Stripe

В сообществе разработчиков Stripe — лидер по удобству интеграции и работы с платёжной системой. Они первые, кто позаботился о программистах и сделал платёжную систему максимально удобной и гибкой. Это позволило разработчикам не только облегченно вздохнуть, но ускорить и удешевить процесс интеграции.

У Яндекс.Кассы и Stripe можно найти много общего. Например, обе системы построены на REST-like принципах, используют коды ответов HTTP, поддерживают CORS (и ответы приходят в JSON), обе поддерживают идемпотентность. Есть «песочница» — полная копия реального магазина, и переход между режимами производится лишь заменой ключей: не нужно менять API или URL.

Но в тоже время они очень разные, и для того, чтобы показать, насколько у этих систем разные подходы, мы рассмотрим реализацию некоторых этапов на конкретных примерах.

Поскольку на данном проекте реализовали серверную часть на Node.js, то и примеры буду приводить для него.

Подключаем к проекту.

Stripe:

var stripe = require('stripe')('sk_test_...');

Яндекс.Касса:

Подключения нет, ибо нет основной библиотеки; есть хелпер

Запрашиваем данные карты

Stripe:

Подключить аналогично клиентскую библиотеку и запросить токен с отображением формы для ввода карты.

var stripe = Stripe('pk_test_6pRNASCoBOKtIshFeQd4XMUh');
var elements = stripe.elements();

// Create an instance of the card Element
var card = elements.create('card', { style: style });

// Add an instance of the card Element into the `card-element` <div>
card.mount('#card-element');

// On form submit
stripe.createToken(card).then(function(result) {
      // Send the token to your server
      stripeTokenHandler(result.token);
    }
 );

На сервере

stripe.charges.create({
  amount: 2000,
  currency: "usd",
  source: "token from previous step", // obtained with Stripe.js
  description: "Charge for william.brown@example.com"
}, function(err, charge) {
  // asynchronously called
});

Яндекс.Касса:

Она действует иначе: здесь нет ни клиентской, ни серверной части. Просто формируем ссылку: 
<a href="https://money.yandex.ru/eshop.xml?shopId=12345&scid=1234566&sum=3000&customerNumber=73">https://money.yandex.ru/eshop.xml?shopId=12345&scid=1234566&sum=3000&customerNumber=73</a>

По правде говоря, на сайте должна быть платёжная форма. Когда пользователь нажимает «Оплатить», эта форма отправляется на указанный выше адрес и передаёт параметры методом POST. Но у нас мобильное приложение, поэтому пришлось отказаться от формы и формировать ссылку на стороне сервера с открытием в WebView.

Эта ссылка отдаётся клиенту для ввода данных карты и подтверждения платежа. Но тут нас ждал очередной сюрприз: в конце 2017 года Яндекс.Касса не поддерживает адаптивный дизайн. Всевозможные манипуляции с настройками не давали результата.

image
Дизайн не адаптируется под мобильное приложение

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

image
Ура, адаптированный дизайн под мобилку в 2017!

Но только для оплаты банковскими картами

Проверяем факт оплаты

Stripe:

Оплата проверяется в процессе формирования платежа и в случае ошибки функция API вернет соответствующее исключение.

Яндекс.Касса:

Пользователи производят оплату на стороне Яндекс.Кассы, но приложение пользователя ещё не знает о факте оплаты. Поэтому Яндекс.Касса должна сообщить серверу, что оплата была осуществлена. Для этого разработчики должны создать WebHook и настроить Яндекс.Кассу, чтобы она могла использовать адреса из WebHook для передачи факта оплаты.

Уведомление сервера об оплате происходит в 2 этапа:

  • Проверка возможности оплаты. Наш сервер всё проверяет, разрешает или запрещает списать средства, например, проверяет остатки товара, либо корректность цен.
  • Выполнение оплаты. Яндекс.Касса сообщает нашему серверу, что деньги списаны и оплата прошла успешно. В этот момент необходимо зафиксировать в базе факт оплаты.

Но и тут нас ждут сюрпризы:

  1. Чтобы изменить адреса, нужно отправить запрос менеджеру и опять ждать.
  2. Необходимо реализовать специальный алгоритм проверки валидности данных от Яндекс.Кассы.
  3. Сервер должен возвращать специально сформированный XML. Мы смогли найти готовый модуль [3] для формирования правильного ответа.

Отменяем платёж

Stripe:

stripe.refunds.create({
  charge: "ch_1BTuEo2eZvKYlo2CSGqKz76n"
}, function(err, refund) {
  // asynchronously called
});

Яндекс.Касса:

Магазину необходимо получить сертификат X.509 для работы с MWS. Сертификат выдаётся удостоверяющим центром Яндекс.Денег, с помощью которого магазин формирует запросы к Яндекс.Кассе.

Как можно догадаться, согласование и подключение заняло некоторое время. Оно плавно вышло за границы дедлайна.

Сохраняем карты

Stripe:

stripe.customers.create({
  email: "paying.user@example.com",
  source: "src_18eYalAHEMiOZZp1l9ZTjSU0",
}, function(err, customer) {
  // asynchronously called
});

Яндекс.Касса:

Описываем правила отмены сохранения карт и реализуем возможность удаления. Затем отправляем приложение на ревью в службу безопасности Яндекс.Кассы и ждём ответа.

Если ответ положительный, появляется возможность сохранять карты после успешной оплаты и совершать повторные платежи при помощи протокола MWS.

Пример запроса из документации:

POST https://server:port/webservice/mws/api/repeatCardPayment
DATA: clientOrderId=123456789&invoiceId=2000000123&amount=10.00&cvv=643

Из примеров видно, что Stripe более приспособлен для разработчиков и обладает большим разнообразием функций и возможностей. Но есть одно большое НО: Stripe, как и Braintree, не работает в России, хоть и может принимать платежи из разных стран. Владелец аккаунта на Stripe должен быть резидентом доступных ему стран — Россия не в их числе. К тому же Stripe не позволяет использовать протокол 3-D Secure — подтверждение через SMS-сообщение. И если банк не принимает платежи без данного протокола, вы не сможете провести оплату. Яндекс.Касса же работает в России и поддерживает протокол 3-D Secure.

Что в результате

Даже с учетом того, что нам пришлось делать много дополнительной работы и общаться с поддержкой, мы не только успели почти все завершить в срок, но и провели еще и дополнительную работу. За неделю до релиза вышла новая версия API Яндекс.Кассы и мы создали NPM-модуль и переписали код.

Когда мы разобрались в новой версии API, то приятно удивились: разработчики явно смотрели на зарубежные аналоги и применили лучшие практики. Некоторые проблемы предыдущей версии были решены. В документации по новой API не было SDK для Node.js. Мы планируем работать на российском рынке и дальше, и нам понадобится такой инструмент. Поэтому мы решили создать NPM-модуль, который любой желающий может самостоятельно интегрировать в свой проект.

Автор: repjov

Источник [4]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/node-js/281404

Ссылки в тексте:

[1] рассказывали: https://habr.com/company/yamoney/blog/348070/

[2] стало приложение Sellsay: https://itunes.apple.com/ru/app/sellsay/id1180568573?mt=8

[3] смогли найти готовый модуль: https://www.npmjs.com/package/node-yandex-kassa

[4] Источник: https://habr.com/post/412643/?utm_campaign=412643