Платёжный модуль
Способ оплаты в PrestaShop — это отдельный модуль. Он делает две вещи: показывает свой вариант на шаге оплаты и, когда покупатель его выбрал, превращает корзину в заказ. Платёжный модуль наследует не Module, а PaymentModule — в нём уже есть метод создания заказа.
Отзывы здесь ни при чём, поэтому пример — отдельный модуль acmepay с оплатой при получении.
Структура
modules/acmepay/
├── acmepay.php
└── controllers/
└── front/
└── validation.phpГлавный класс
<?php
// modules/acmepay/acmepay.php
use PrestaShop\PrestaShop\Core\Payment\PaymentOption;
if (!defined('_PS_VERSION_')) {
exit;
}
class AcmePay extends PaymentModule
{
public function __construct()
{
$this->name = 'acmepay';
$this->tab = 'payments_gateways';
$this->version = '1.0.0';
$this->author = 'Acme';
$this->currencies = true;
$this->currencies_mode = 'checkbox';
parent::__construct();
$this->displayName = $this->trans('Оплата при получении', [], 'Modules.Acmepay.Admin');
}
public function install(): bool
{
return parent::install() && $this->registerHook('paymentOptions');
}
}От обычного модуля класс отличают родитель PaymentModule, раздел payments_gateways и два свойства о валютах: они говорят, что способ оплаты можно включать для каждой валюты отдельно.
Вариант оплаты
На шаге оплаты движок вызывает хук paymentOptions и собирает от модулей список вариантов:
// modules/acmepay/acmepay.php
public function hookPaymentOptions(array $params): array
{
$option = new PaymentOption();
$option->setCallToActionText($this->trans('Оплатить при получении', [], 'Modules.Acmepay.Shop'));
$option->setAction($this->context->link->getModuleLink($this->name, 'validation', [], true));
return [$option];
}setCallToActionText() задаёт подпись варианта, setAction() — адрес, на который покупателя отправит кнопка «Оформить заказ». Здесь это контроллер validation самого модуля.
Установите модуль и дойдите на витрине до шага оплаты: в списке появился вариант «Оплатить при получении».
php bin/console prestashop:module install acmepayСоздание заказа
<?php
// modules/acmepay/controllers/front/validation.php
class AcmepayValidationModuleFrontController extends ModuleFrontController
{
public function postProcess(): void
{
$cart = $this->context->cart;
$customer = new Customer((int) $cart->id_customer);
if (!$cart->id || !Validate::isLoadedObject($customer) || !$this->module->active) {
Tools::redirect($this->context->link->getPageLink('order'));
}
$this->module->validateOrder(
(int) $cart->id,
(int) Configuration::get('PS_OS_PREPARATION'),
(float) $cart->getOrderTotal(true, Cart::BOTH),
$this->module->displayName,
null,
[],
(int) $this->context->currency->id,
false,
$customer->secure_key
);
Tools::redirect($this->context->link->getPageLink('order-confirmation', true, null, [
'id_cart' => (int) $cart->id,
'id_module' => (int) $this->module->id,
'id_order' => (int) $this->module->currentOrder,
'key' => $customer->secure_key,
]));
}
}validateOrder() создаёт заказ из корзины, списывает остатки, отправляет письмо покупателю и вызывает хук actionValidateOrder. Затем покупателя перенаправляют на стандартную страницу «Заказ подтверждён». Заказ появится в панели в разделе «Заказы».
Аргументы validateOrder
| Аргумент | Что передают |
|---|---|
| Номер корзины | $cart->id |
| Состояние заказа | Номер из настроек: PS_OS_PAYMENT — оплачен, PS_OS_PREPARATION — в обработке, PS_OS_ERROR — ошибка оплаты |
| Сумма | Сколько оплачено. Если она не совпадёт с суммой корзины, заказ получит состояние ошибки |
| Название способа | Строка, которая сохранится в заказе |
| Номер валюты | Валюта оплаты |
| Ключ покупателя | secure_key — защита от подмены корзины |
Оплата на внешнем сервисе
При оплате картой покупателя отправляют на страницу банка, и схема удлиняется:
setAction()ведёт на контроллер, который создаёт платёж в банке и перенаправляет туда покупателя.- Банк сообщает о результате запросом на отдельный контроллер модуля — уведомление.
- Контроллер уведомления проверяет подпись запроса и только тогда вызывает
validateOrder()с состояниемPS_OS_PAYMENT.
Страница после заказа
Чтобы показать на странице подтверждения свои указания — например, реквизиты, — модуль подписывается на хук displayPaymentReturn и возвращает шаблон, как любой хук вывода.
Частая ошибка
Заказ создают в контроллере, на который покупатель возвращается из банка, и верят параметру вроде status=paid в адресе. Такой адрес можно открыть вручную и получить «оплаченный» заказ. Заказ подтверждают только по уведомлению банка с проверенной подписью, а сумму берут из уведомления и сверяют с корзиной.