Электронная коммерция стала трендом 2020 года. Крупные игроки рынка начали активно развивать сервисы доставки продуктов и готовых блюд. Как грибы после дождя выросли новые маркетплейсы. Даже те, кто был далёк от интернета и технологий, вынужденно погрузились в тему дистанционной торговли. Почему — все знают, но сегодня поговорим не об этом. Перейдём сразу к ключевому звену коммерции — приёму платежей. В статье поделюсь несколькими рекомендациями о том, как с ним работать.

image

Меня зовут Андрей Шубин, работаю в VK в команде разработки e-commerce — в сентябре мы запустили Маркет ВКонтакте. Занимаюсь веб-разработкой десять лет, из них семь работаю с интернет-магазинами, маркетплейсами и другими проектами, продающими через сеть. Последние три года возглавлял разработку для электронной коммерции в компании Siberian Wellness — у неё есть представительства в большинстве стран СНГ, ЕС, немного в Юго-Восточной Азии и Северной Америке. Именно из-за такой обширной географии мне довелось познакомиться с локальными платёжными агрегаторами, а также с законодательством некоторых стран.

Эта статья будет полезна разработчикам уровня middle, которые взялись за новое для себя направление — ступили на скользкий путь e-commerce. Если вы в этой сфере давно, некоторые кейсы могут показаться очевидными. Буду рад любому фидбэку в комментариях.

Типы данных


Только ленивый не говорил, что вычислительная техника может допускать некоторую погрешность при работе с числами с плавающей точкой. Да-да, попробуйте сложить 0,1 и 0,2, если раньше этого не делали, — будете удивлены. Но в работе с финансами точность и однозначность — это то, что должно быть на первом месте. Если где-то в расчётах проскользнёт лишняя копейка, последствия могут быть печальными. Конечно, за одну копейку с вами связываться никто не будет — хотя известны случаи, когда ФНС таки отправляла налогоплательщику требование уплатить недоимку в 0,01 ?. Но при относительно больших оборотах разница между фактически полученной суммой и той, что отображена в чеках, может принять критическое значение — и тогда знакомство с налоговым инспектором вам гарантировано. Особенно если всё происходит в Германии или Чехии.

Кстати, раз уж речь зашла о других странах и типах данных. В мире есть очень дешёвые валюты — и с ними обороты компании могут измеряться суммами с целым паровозом нулей. В моей практике это были вьетнамский донг и белорусский рубль до 2017 года. Если вам предстоит работать с одной из таких валют, проверьте своё хранилище на предмет разрядности. Иначе может случиться то же самое, что сделал с ютубом клип Gangnam Style в декабре 2014-го.

Общение с платёжной системой


В общем случае жизненный цикл платёжной транзакции выглядит так:

  1. Принимаем заказ.
  2. Формируем ссылку на платёжный шлюз, в который вшиваем сумму к оплате, номер заказа и что там ещё попросит платёжная система.
  3. Редиректим клиента по этому адресу.
  4. Клиент вводит данные карты и перенаправляется на страницу благодарности (thank you page) магазина.
  5. Банк списывает со счёта клиента деньги и делает callback-запрос на специальный эндпоинт с нашей стороны.
  6. Меняем статус заказа и проводим попутные манипуляции.

Выглядит красиво и очень логично. Когда разрабатываешь систему, которая потенциально может быть заточена под торговлю на внешнем рынке, а то и не на одном, очень чешутся руки все процессы стандартизировать: создать такую библиотеку классов, чтобы для внедрения новой платёжной системы было достаточно дописать один. И здесь лежат очень коварные грабли: далеко не все платёжные системы считают, что описанная выше схема исчерпывающая и не требует изменений. Примеры? Их достаточно:

  • В Казахстане система не признавала редирект методом GET. Она требовала сначала на бэкенде сформировать зашифрованную строку с параметрами платежа, а затем нарисовать в магазине HTML-форму, где единственным параметром должна быть эта строка. И уже форму нужно было отправлять синхронно — после этого пользователь попадал на страницу, где мог ввести номер карты. Но просто дождаться callback-запроса недостаточно: необходимо было сделать ещё один запрос с бэкенда, чтобы дать банку понять, что мы готовы принять оплату.
  • В Чехии ввели онлайн-кассы — и из-за этого требовалось кроме суммы передать на сторону платёжного шлюза полный список позиций на чешском языке, включая цены и рассчитанные значения НДС. И если вы даёте клиенту скидку, то не можете просто взять и закинуть её в чек отрицательным числом. Так не работает. Нужно пересчитать стоимость всех позиций с учётом этой скидки или распределить её размер по конкретным позициям. И подойти к этому с умом — потому что у разных товаров может отличаться ставка НДС, а если вы случайно дадите скидку на товары с большей ставкой, этим может заинтересоваться налоговый инспектор во время камеральной проверки.
  • Нацбанк Молдовы переложил на продавца обязанность отправлять клиенту электронный чек. При этом в нём требуется отображать определённую банковскую информацию. Получать её нужно из callback-запроса от банка либо отдельным методом API. А ещё местные ребята не особо следили за актуальностью документации и не могли ответить на наши вопросы в письмах — так что пришлось ехать туда лично и общаться с техдиром.
  • В Узбекистане пошли дальше: решили, что один цикл «запрос — ответ» — это слишком просто. Считаем вместе:

    • раз — банк узнаёт, готовы ли мы вообще принять платёж;
    • два — банк передаёт ID покупателя, который мы ему передали раньше, а мы должны подтвердить, что это действительно наш пользователь;
    • три — банк сообщает номер заказа и сумму к оплате, а мы проверяем, что всё ОК, и даём соответствующий ответ;
    • четыре — банк подтверждает, что деньги успешно списаны, мы отвечаем, что приняли.

    И только в этот момент мы наконец меняем статус заказа у себя и движемся дальше. Четыре запроса вместо одного!
  • Вьетнамский оператор эквайринга вообще не присылает callback-запрос. Мы должны сами запросить статус транзакции. И при этом использовать ID транзакции, который присваивается оператором и передаётся GET-параметром на thank you page.

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

Не ждите! Пишите первыми


Сделать на своей стороне эндпоинт, на который будет стучаться платёжная система со своими запросами, — это очень заманчиво. Но будем честны — никто из нас не в состоянии обеспечить 100%-й аптайм: в какой-то момент может отвалиться связь с сервером базы данных или с каким-то другим сервисом, и тогда ваше приложение не сможет отдать ожидаемый ответ. И здесь уже надо смотреть по документации, как поведёт себя конкретная платёжная система (если об этом, конечно, там написано).

Например, в том же Казахстане местный банк делал три запроса с разницей в секунду и после третьего фейла считал транзакцию неуспешной. При этом деньги клиента зависали где-то между счётом клиента и нашим р/с. Сдвинуть их в ту или иную сторону можно было двумя способами: либо делать отдельный API-запрос в течение ограниченного времени, либо идти в отделение банка, с которым заключён договор эквайринга, и писать заявление от руки. Знакомо?

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

Если такой возможности нет, то callback-запросы от банков лучше принимать на отдельный сервер, которому нужно обеспечить максимальный аптайм. В идеале это должен быть простой веб-сервер, который пишет таски в брокер сообщений. Совсем круто, если будет кластер таких серверов. Эх, мечты… На самом деле такой монстр, скорее всего, не потребуется, но направление вы поняли.

Откройте глаза! Мониторинг — наше всё


В работе с платежами есть скрытые процессы, от которых зависит вся цепочка электронной торговли. Чтобы не быть голословным, приведу пример из практики. У нас был договор интернет-эквайринга со Сбером и договор аренды онлайн-касс с Orange Data. Интеграции из коробки между этими двумя конторами нет, поэтому пришлось делать её на своей стороне. Обработали callback от Сбера, сформировали запрос к оператору фискальных данных, который генерирует чек и отправляет его в налоговую и клиенту на электронную почту. И вот в один не самый прекрасный день Orange Data аннулирует токен авторизации — и чеки перестают выписываться и отправляться. Чтобы вы понимали, штраф за невыдачу одного чека — 40 000 рублей. А узнали мы о сбое в процессе совершенно случайно, спустя два месяца: один дотошный пользователь позвонил в контакт-центр спросить, почему ему не пришёл чек… Спасибо, добрый человек! Мы успели всё пофиксить и разослать зависшие чеки до конца отчётного периода. А если бы не сделали этого, размер штрафов не оставил бы компании шансов на выживание.

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

Иногда нужно поработать ручками


E-commerce, как и любой IT-продукт, — это не только мы с вами (разработчики), но и целая инфраструктура: с юристами, региональными менеджерами, службой логистики и клиентской поддержки. Вот на последней остановимся подробнее.

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

А ведь большинства жалоб можно избежать: достаточно реализовать возможность вручную проводить манипуляции с заказами. Клиент оплатил покупку, и он вправе её получить — и будет требовать этого. Так что ему безразлично, что вы «технически не можете начать собирать заказ, пока не подтвердится оплата». Он будет звонить в контакт-центр, надеясь на решение, а получит дежурные фразы: «технически невозможно», «вы можете оставить претензию» и «перезвоните позже». Пожалейте коллег — дайте им инструмент, устраняющий проблему клиента в один клик. Они будут вам благодарны — и, может, как-нибудь в понедельник с утра угостят шипящей витаминкой.

Вместо заключения


Я описал далеко не все проблемы, с которыми мы сталкиваемся при работе в электронной коммерции. Не стал рассказывать и о курьёзных случаях в практике — одна документация на монгольском языке чего стоит. А ещё совсем не затронул аспекты работы в правовом поле конкретных стран и многое другое — об этом, возможно, поговорим в других моих статьях. Но надеюсь, что этот материал вам пригодится, сэкономит время и нервы. Если есть вопросы или хотите просто почитать умопомрачительные истории — добро пожаловать в комментарии!

P. S. Обращаюсь от имени всех разработчиков из e-commerce — к финтех-разработчикам. Ребят, ну сядьте вы уже, договоритесь, выработайте единый стандарт взаимодействия с мерчантом. Все же от этого выиграют!