Хабрахабр

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

image

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

image

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Например, обе системы построены на REST-like принципах, используют коды ответов HTTP, поддерживают CORS (и ответы приходят в JSON), обе поддерживают идемпотентность. У Яндекс.Кассы и Stripe можно найти много общего. Есть «песочница» — полная копия реального магазина, и переход между режимами производится лишь заменой ключей: не нужно менять 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', ); // 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. Мы смогли найти готовый модуль для формирования правильного ответа.

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

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-модуль, который любой желающий может самостоятельно интегрировать в свой проект.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть