Шпаргалка. Интернет эквайринг Сбербанка на практике
Запись от 23.11.2014
Когда передо мной встала задача подключения карт сбербанка я не знал с чего начать - была пара документаций от сбербанка листов на 80 каждая из них ~30% слов, которые никогда не слышал, то есть крайне нечитабельная информация и, как вариант, можно было воспользоваться модулем с маркетплейса за 10т.р. + примерно такую же сумму попросили за доработку модуля под мои задачи. Информации в интернете было минимум или она мне просто не попалась
В итоге пришлось выборочно прочитать документацию сбербанка. Т.к. задачи в проекте относительно простые - пополнение счета клиента, то и кода вышло не много, именно им, как краткой инструкцией я и хочу поделиться (ну и для себя сохранить, на будущее).
Внимание! Колхоз в чистом виде на Старте.
Я предупредил
В самом примитивном(!) варианте нам понадобится 2 файла - index.php, где будет форма для ввода суммы пополнения и обработка результата иpay.php с запросами в Сбербанк.
Алгоритм, примерно, таков:
Начнем с index.php, заполним HTML:
Далее на index.php размещаю/подключаю такой скрипт:
Теперь рассмотрим pay.php, которому и идет обращение из AJAX:
Важное замечание: поскольку здесь используются ваши логины и пароли к сбербанку, то нужно использовать конструкцию <?php, второе - URL для отправки данных должны быть предоставлены самим сбербанком - для тестового и боевого сервера они отличаются.
И еще один момент, сам заказ сохраняется в инфоблоках, через элемент инфоблока можно будет отследить URL, суммы, пользователей, статус оплаты/заказа и т.п.
И возвращаясь к index.php. После того, как на стороне Сбербанка произойдет перечисление средств пользователь вернется на index.php, где в $_REQUEST мы получим данные о заказе - они пригодятся для обновления заказа в элементах инфоблока:
Напоминаю - это примитивный, упрощенный код. На деле, здесь нужно дописывать все else, доработать вариант, если пользователь не вернулся на index.php после оплаты, но все оплатил (например, с интернетом проблемы) - тут нужно запускать агент на запрос статуса заказа или при очередной авторизации пользователя.
Этого кода должно быть достаточно что бы начать работать с интернет эквайрингом от Сбербанка.
В итоге пришлось выборочно прочитать документацию сбербанка. Т.к. задачи в проекте относительно простые - пополнение счета клиента, то и кода вышло не много, именно им, как краткой инструкцией я и хочу поделиться (ну и для себя сохранить, на будущее).
Внимание! Колхоз в чистом виде на Старте.
Я предупредил
В самом примитивном(!) варианте нам понадобится 2 файла - index.php, где будет форма для ввода суммы пополнения и обработка результата иpay.php с запросами в Сбербанк.
Алгоритм, примерно, таков:
- В index.php вводим сумму пополнения баланса;
- AJAX запросом обращаемся к pay.php;
- pay.php сохраняет данные о заказе в инфоблоках и запрашивает у Сбербанка URL для оплаты;
- Скрипт из index.php получает URL для оплаты и перекидывает клиенту на эту страницу;
- После оплаты пользователь попадает на index.php, где производится обновление статуса заказа.
Начнем с index.php, заполним HTML:
Пополнить баланс:
<input type="text" size="6" id="pay-amount" />
<input type="button" value="Пополнить" id="pay" />
<img src='//opt-560835.ssl.1c-bitrix-cdn.ru/images/spinner.gif' style="display: none;" id="pay-spinner" alt='' />
<div id="pay-result"></div>
Здесь у нас поле для ввода суммы пополнения баланса и кнопка "Пополнить", img для прелоадера и div для отображения результата. Далее на index.php размещаю/подключаю такой скрипт:
<script>
$(document).ready(function() {
$("#pay").on("click", function() { // Клик по кнопке "Пополнить"
$("#pay-spinner").show(); // Покажем прелоадер
var arErrors = new Array(); // Массив с возможными ошибками
arErrors["err01"] = "Введите сумму в рублях цифрами!";
$("#pay-result").html(""); // Очищаем поле с результатом
$.ajax({ // Отправим AJAX запрос на наш сервер
type: "POST",
url: "pay.php", // Здесь путь от корня сайта к файлу pay.php
data: ({ // Пересылаемые данные
amount: $("#pay-amount").val()
}),
success: function(data){ // Действия при успешном AJAX запросе
var res = jQuery.parseJSON(data);
if(res.error) { // Если возникли ошибки
if(arErrors[res.message]) { // По коду ошибки достаем её текст из arErrors
$("#pay-result").html(arErrors[res.message]);
}
} else if(res.urlTo) { // Если ошибок не было то перейдем на нужный URL
window.location = res.urlTo;
}
$("#pay-spinner").hide(); // И скорем прелоадер
},
error: function() { // Действия при ошибке AJAX запроса
$("#pay-spinner").hide(); // Скрываем прелоадер и не забываем про console.log()
}
});
});
});
</script>
Если коротко, то на основе введенного значения отправляем AJAX запрос, который должен вернуть URL на страницу сбербанка с перечислением средств. Теперь рассмотрим pay.php, которому и идет обращение из AJAX:
<?php require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
$amount = $_REQUEST["amount"]; // Сохраним переданное значение суммы в $amount
if(is_numeric($amount)) { // Если передано число
$amount = (float) $amount; // Переводим его в float
$amount *= 100; // И умножаем на 100, что бы оперировать копейками
// Сохраним информацию о начале тразнакции
global $USER;
CModule::IncludeModule("iblock");
$seq = new CIBlockSequence($iBlockId, $iCounterId);
$el = new CIBlockElement;
$arProps = Array(
"AMOUNT" => $amount,
"ORDER_ID" => $seq->GetNext(),
"USER" => $USER->GetID()
);
$arElementArray = Array(
"IBLOCK_SECTION_ID" => false,
"IBLOCK_ID" => $iBlockId,
"PROPERTY_VALUES" => $arProps,
"NAME" => "Заказ",
"ACTIVE" => "Y",
);
if($iElementId = $el->Add($arElementArray, true, false, false)) {
// Теперь, после того, как сохранили данные о транзакции
// можно и подготовить данные для подключения к Сбербанку
$iOrderId = $arProps["ORDER_ID"];
$params = Array(
'amount' => $amount, // Сумма пополнения
'orderNumber' => $iOrderId, // Внутренний ID заказа
'password' => 'pwd-api', // Здесь пароль от вашего API юзера в Сбербанке
'userName' => 'user-api', // А тут его логин
'returnUrl' => 'http://mysite.ru/' // URL куда вернуть пользователя после перечисления средств
);
$opts = Array( // А здесь параметры для POST запроса
'http' => Array(
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded",
'content' => http_build_query($params),
'timeout' => 60
)
);
// И отправляем эти данные на сервер сбербанка
$context = stream_context_create($opts);
// Здесь должен быть URL тестового и боевого сервера Сбербанка
$url = 'https://test/payment/rest/register.do';
$result = file_get_contents($url, false, $context);
// Расшифруем полученные данные в массив $arSbrfResult
$arSbrfResult = (array) json_decode($result);
if($arSbrfResult["formUrl"]) { // Если у нас есть URL для оплаты, то...
$arResult = Array( // Готовим массив для вызывающего скрипта
"error" => false, // - без ошибок
"message" => "", // - без сообщения ошибки
"urlTo" => $arSbrfResult["formUrl"] // - и с URL для оплаты
);
CIBlockElement::SetPropertyValuesEx( // В инфоблоке с заказами добавим данные по оплате заказа
$iElementId, $iBlockId,
Array(
"ORDER_ID_SBRF" => $arSbrfResult["orderId"],
"URL_PAY" => $arSbrfResult["formUrl"]
)
);
} else { // а если URL для оплаты нет, передаем массив с ошибками
$arResult = $arSbrfResult; /* errorCode, errorMessage */
}
} else { // Если не удалось сохранить заказ/транзакцию в инфоблоках, то передаем сообщение с ошибкой
$arResult = Array(
"error" => true,
"message" => "err02" // Код ошибки: Ошибка при создании эл-та инфоблока
);
}
} else { // а если пользователь ввел не число...
$arResult = Array(
"error" => true,
"message" => "err01" // Код ошибки: Введите цену цифрами
);
}
echo json_encode($arResult); // Возврат данных в скрипт, вызвавший AJAX
Этот скрипт должен получить значение суммы для оплаты, отправить запрос в Сбербанк и получить URL на оплату, затем передать его в скрипт, вызвавший AJAX. Важное замечание: поскольку здесь используются ваши логины и пароли к сбербанку, то нужно использовать конструкцию <?php, второе - URL для отправки данных должны быть предоставлены самим сбербанком - для тестового и боевого сервера они отличаются.
И еще один момент, сам заказ сохраняется в инфоблоках, через элемент инфоблока можно будет отследить URL, суммы, пользователей, статус оплаты/заказа и т.п.
И возвращаясь к index.php. После того, как на стороне Сбербанка произойдет перечисление средств пользователь вернется на index.php, где в $_REQUEST мы получим данные о заказе - они пригодятся для обновления заказа в элементах инфоблока:
<?php
if($_REQUEST["orderId"] && CModule::IncludeModule("iblock")) {
$resElement = CIBlockElement::GetList(
Array(),
Array(
"IBLOCK_ID" => 3,
"PROPERTY_ORDER_ID_SBRF" => $_REQUEST["orderId"]
),
false,
false,
Array(
"IBLOCK_ID", "ID",
"PROPERTY_ORDER_ID",
"PROPERTY_ORDER_ID_SBRF",
"PROPERTY_AMOUNT",
"PROPERTY_GET"
)
);
if($arElement = $resElement->GetNext()) {
$params = array(
'orderId' => $_REQUEST["orderId"],
'password' => 'pwd-api',
'userName' => 'user-api'
);
$opts = array(
'http' => array(
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded",
'content' => http_build_query($params),
'timeout' => 60
)
);
$context = stream_context_create($opts);
$url = 'https://test/payment/rest/getOrderStatus.do';
$result = file_get_contents($url, false, $context);
$arSbrfResult = (array) json_decode($result);
if($arSbrfResult["OrderStatus"]) {
CIBlockElement::SetPropertyValuesEx(
$arElement["ID"], $iBlockId,
Array("STATUS" => $arSbrfResult["OrderStatus"]+1) // Some magic for prop enum id
);
LocalRedirect($APPLICATION->GetCurDir());
}
}
}
В этом скрипте происходит поиск заказа в инфоблоках и заброс в Сбербанк для получения статуса оплаты, на основе которого будет обновлен элемент инфоблока. Напоминаю - это примитивный, упрощенный код. На деле, здесь нужно дописывать все else, доработать вариант, если пользователь не вернулся на index.php после оплаты, но все оплатил (например, с интернетом проблемы) - тут нужно запускать агент на запрос статуса заказа или при очередной авторизации пользователя.
Этого кода должно быть достаточно что бы начать работать с интернет эквайрингом от Сбербанка.