Создание способа оплаты через модуль

Способ оплаты — это группа нескольких PHP- и TPL-файлов, а также записи в таблице payment_processors.

Поля таблицы payment_processors

  • processor (string) — поле с названием способа оплаты. Для всех языков будет отображаться одинаково, но лучше заполнять его латинскими символами.

  • processor_script (string) — название PHP-файла, в котором описана логика работы процессора нового способа оплаты.

    Примечание

    Укажите только название файла, например, foo_bar.php. Указывать директории или другие символы не нужно. По умолчанию этот файл запускается из директории app/payments. А если название модуля указать в поле addon в таблице payment_processors, то файл будет запускаться из директории app/addons/{$addon_name}/payments, где $addon_name - название модуля.

  • processor_template (string) — это относительный путь без первого слэша (/) к TPL-файлу шаблона, который отображается для покупателя, создающего заказ. Путь должен быть относителен директории design/themes/{$theme_name}/templates. Например: views/orders/components/payments/cc.tpl.

    Если способу оплаты нужен разработанный с нуля шаблон, укажите к нему путь в модуле. Например, вот так выглядит путь к шаблону модуля PayPal: addons/paypal/views/orders/components/payments/paypal_express.tpl.

    В директории design/themes/responsive/templates/views/orders/components/payments находятся шаблоны темы responsive. Используйте их в качестве основы или примера, указав путь к шаблону в поле processor_template.

  • admin_template (string) — это название TPL-файла шаблона, который появляется при создании и редактировании способа оплаты в отдельной вкладке. Этот шаблон содержит поля и формы, где администраторы указывают параметры способа оплаты, например, токены и т.п.

    Примечание

    Укажите название TPL-файла без директории и других символов. Например: foo_processor_template.tpl. По умолчанию этот файл запускается из директории design/backend/templates/views/payments/components/cc_processors.

    Если способ оплаты добавлен модулем, и поле addon в таблице payment_processors заполнено корректно, файл будет запускаться из директории design/backend/templates/addons/{$addon_name}/views/payments/components/cc_processors; где {$addon_name} — название модуля.

  • callback (ENUM(‘Y’,’N’)) — определяет, как сработает оплата заказа:

    • Y — способ оплаты отправит запрос на сервер, где обрабатывается заказ, без перенаправления покупателя на этот сервер. Например, так можно сделать с помощью cURL.

      Подсказка

      Так работают PayPal Pro и Authorize.Net.

    • N — покупателя, который оставляет заказ, перенаправит на сторону сервера, где обрабатывается заказ, чтобы совершить оплату.

      Подсказка

      Так работают способы оплаты DPS PX Access и Player.

  • type (ENUM(‘P’,’C’,’B’)) — определяет, где именно появится шаблон, указанный в поле processor_template.

    • P (Payment gateway - Платёжный шлюз) — шаблон появится в секции “Способы оплаты” на странице оформления заказа.

      Подсказка

      Страница оформления заказа находится здесь: dispatch=checkout.checkout.

    • C (Checkout - Оформление заказа) — шаблон появится в качестве кнопки оплаты в корзине.

      Подсказка

      Корзина находится здесь: dispatch=checkout.cart.

    • B (Both - Оба) — шаблон появится в обоих местах.

  • addon (string) — идентификатор модуля, добавляющего способ оплаты (например, paypal).

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

Скрипт обработки платежей

Используем в качестве примера скрипт процессора с типом callback = "N".

Логическое ядро способа оплаты — PHP-файл, указанный в поле processor_script в таблице payment_processors. Это обычный скрипт, подключенный через директиву include. После этого подключения выполняется содержимое файла.

Этот файл используют в двух разных сценариях, поэтому он включает в себя алгоритм с логическим разветвлением, которое позволяет запускать только часть скрипта, в зависимости от контекста (т.е. от того, зачем он запущен).

В следующем примере скрипт находится в директории app/addons/sample_payment/payments. Назовем его sample_payment_processor.php и добавим минимально необходимый для работы скрипта код:

<?php

// app/addons/sample_payment/payments/sample_payment_processor.php — директория файла.
// Запрещаем обращение к скрипту напрямую, он должен быть включен через директиву "include". Константа "BOOTSTRAP" объявляется во время запуска.

defined('BOOTSTRAP') or die('Access denied');
//  Есть два разных сценария для запуска скрипта.

if (defined('PAYMENT_NOTIFICATION')) {
/**
* Получение и обработка ответа от сторонних
* платежных сервисов и систем оплаты.
*/

} else {
/**
* Запуск необходимой для принятия платежей логики,
* после того как клиент нажмет кнопку "Создать заказ".
*/
}

Рассмотрим оба возможных сценария использования скрипта.

Запуск логики, необходимой для принятия платежа, после нажатия кнопки “Оформить заказ”

Скрипт подключается после того, как создается заказ (т.е. после создания записи о заказе в таблице orders). Вот типичные задачи, которые выполняет скрипт в контексте этого сценария:

  • Проверка данных, введенных покупателем при создании заказа. Например, проверка срока действия банковской карты, указанной покупателем.
  • Смена статуса заказа на Неудавшийся, если данные не прошли проверку.
  • Сбор и подготовка данных к отправке на сервер сторонней платёжной системы.
  • Сбор одноразовых токенов и ключей доступа от платёжных систем.
  • Создание URL, на которую будет перенаправлен клиент после того, как будут произведены необходимые действия на сайте платёжной системы.
  • Перенаправление покупателя на сайт платёжной системы, чтобы подтвержить платёж и/или дополнить предоставленные данные.

Процессы, которые происходят до и после выполнения скрипта обработки платежей

  • Покупатели выбирают способ оплаты и нажимают на кнопку “Создать заказ”. Это отправляет POST-запрос к index.php?dispatch=checkout.place_order.

  • Выполняется контроллер checkout.place_order, обращаясь к функции fn_checkout_place_order(). Помимо других аргументов, эта функция принимает массив $_REQUEST. Если функция находит элемент с ключом payment_info в массиве $_REQUEST['payment_info'], то она копирует значение этого элемента в массив $cart с таким же ключом $cart['payment_info']. Это позволяет скрипту работать с данными, введенными клиентами во время выбора способа оплаты. Поля для этих данных указываются в шаблоне processor_template.

  • После этого функция проводит проверки, необходимые перед созданием заказа, и создает заказ со статусом Незавершенный по умолчанию. Этот статус обозначается буквой N в базе данных.

  • Процесс оплаты начинается с вызова функции fn_start_payment(). Во время работы функции объявляются следующие переменные, которые потом можно использовать в скрипте способа оплаты:

    • $order_id (integer) — уникальный идентификатор созданного заказа.

    • $order_info (array) — подробная информация о заказе.

      Подсказка

      Эта информация возвращается функцией fn_get_order_info().

    • $processor_data (array) — информация о способе оплаты.

      Подсказка

      Эта информация возвращается функцией fn_get_processor_data().

  • После скрипт обработки платежей подключается и выполняется директивой include.

    В скрипте должна объявляться переменная $pp_response, которая позже используется в функции fn_start_payment() и передается в обращении к функции fn_finish_payment().

Получение и обработка ответа от сторонних сервисов и платёжных систем

В этом сценарии скрипт обрабатывает HTTP-запрос, отправленный платёжной системой. Например, запрос на возвращение клиента на сайт магазина либо другие запросы, отправленные сервером платёжной системы.

Контроллер payment_notification (с параметром callback = "N") как раз принимает такие запросы. Два из них — обязательные GET параметры:

  • mode (string) — цель запроса, описанная в свободной форме. Значение этого параметра будет в переменной $mode в скрипте обработки платежей. Значения могут быть такими: success, error, redirect, и т.д.
  • payment (string) — название исполняемого файла скрипта оплаты. В названии не нужно указывать расширение .php, например, можно указать sample_payment_processor.

Процессы, происходящие при выполнении контроллера payment_notification:

  • Объявляется константа PAYMENT_NOTIFICATION; её значение — true. Это позволяет провести различие между двумя сценариями выполнения алгоритма.
  • Проверяется, активен ли способ оплаты, использующий платежный процессор, переданный в параметре GET.
  • Скрипт обработки платежей включается с помощью директивы include.

Пример скрипта обработки платежей

Создадим скрипт обработки платежа с параметрами callback = "N" и type = "P". Он будет перенаправлять покупателя на сервер платёжной системы, и способ оплаты появится в секции Способы оплаты на странице оформления заказа.

Начнем с создания файла sample_payment_processor.php в директории app/addons/sample_payment/payments и добавим минимальный необходимый код для его работы:

<?php
// Запрещаем прямой доступ к скрипту, потому что он должен быть включен директивой "include".
defined('BOOTSTRAP') or die('Access denied');

//  Два различных контекста выполнения скрипта
if (defined('PAYMENT_NOTIFICATION')) {
/**
* Получение и обработка ответа от сторонних
* платежных сервисов и систем оплаты.
*
* Доступные переменные:
* @var string $mode цель запроса
*/
} else {
/**
* Запуск необходимой для принятия платежей логики,
* после того как клиент нажмет кнопку "Создать заказ".
*
* Доступные переменные:
*
* @var array $order_info     Полная информация о заказе
* @var array $processor_data Информация о обработчике платежа
*/
}

Например, добавим следующий код:

<?php
// Запрещаем прямой доступ к скрипту, потому что он должен быть включен директивой "include".
defined('BOOTSTRAP') or die('Access denied');

//  Два различных контекста выполнения скрипта
if (defined('PAYMENT_NOTIFICATION')) {

fn_print_r("Обработка платежа");

} else {

fn_print_r("Отправка данных");

}

Теперь, если на странице оформления заказа выбрать способ оплаты с этим скриптом обработки платежей и нажать “Создать заказ”, мы увидим распечатанные сообщения “Обработка платежа”, а после — “Отправка данных”. Можно также использовать код любого способа оплаты из директории app/payments как пример.

Добавляем описание для процессора способа оплаты

Можно добавить описание к процессору способа оплаты, которое появится в поле Processor, когда создаете способ оплаты на странице Администрирование → Способы оплаты.

Описание процессора обработки платежей — это динамически формирующаяся языковая переменная в таблице language_values.

Название языковой переменной — processor_description_{$processor_script}; где {$processor_script} — это значение поля processor_script в таблице payment_processors без указания расширения .php.

Например, если значением processor_script будет foo_bar_processor.php, то название языковой переменной будет таким: processor_description_foo_bar_processor.

После добавления этой языковой переменной с описанием процессора способа оплаты в таблицу language_values описание процессора foo_bar_processor появится в Панели администратора.

Значения языковых переменных можно редактировать следующими тремя способами: * в Панели администратора на странице Тексты и языки → Редактировать тексты;

  • SQL-запросом к таблице language_values во время установки модуля;
  • через миграцию.

Режим IFRAME для процессора платежей

Некоторые процессоры позволяют взаимодействовать с платёжными шлюзами с помощью встроенной iframe страницы. При использовании iframe покупателю не нужно покидать сайт магазина.

Примечание

Посмотрите на Skrill QuickCheckout (skrill_qc.php) и Skrill eWallet (skrill_ewallet.php) в app/payments — эти процессоры поддерживают iframe mode. Есть также пример такого модуля на GitHub.

Для работы в режиме iframe платежный процессор должен иметь параметр iframe_mode со значением Y.

Вот пример:

<input
   type="hidden"
   name="payment_data[processor_params][iframe_mode]"
   value="Y"
/>

При выборе оплаты через iframe на странице оформления заказа, кнопка Создать заказ и процессоры в файле checkout.post.php не работают. Из-за этого также покупатель не сможет подписаться на рассылку на этой странице.

Обычно для идентификации заказа используется order_id, но так как в этом случае он ещё не создан, то ему присваивается случайное одноразовое число. Таким образом из константы TIME и user_id генерируется “одноразовый” номер заказа.

  • Платежный шлюз в iframe загружается через режим process_payment контроллера checkout.php, где скрипт процессора подключается с помощью директивы include.
  • Скрипт обработки платежей отправляет всю необходимую информацию платежному шлюзу, включая одноразовый номер заказа и идентификатор сессии.
  • Как только получено уведомление об оплате от шлюза, заказ размещается, и информация о заказе извлекается из сеанса.
  • После получения уведомления об оплате нужно выбрать следующие действия:
    • разместить заказ вручную;
    • связать одноразовый номер заказа с order_id;

Вот такие записи будут добавлены в таблицу order_data, когда будет получено уведомление payment_notification:

order_id тип данные
Идентификатор созданного заказа S Константа TIME
Идентификатор созданного заказа Е Одноразовый номер заказа