Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Платёжный модуль

Способ оплаты в 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 — защита от подмены корзины

Оплата на внешнем сервисе

При оплате картой покупателя отправляют на страницу банка, и схема удлиняется:

  1. setAction() ведёт на контроллер, который создаёт платёж в банке и перенаправляет туда покупателя.
  2. Банк сообщает о результате запросом на отдельный контроллер модуля — уведомление.
  3. Контроллер уведомления проверяет подпись запроса и только тогда вызывает validateOrder() с состоянием PS_OS_PAYMENT.

Страница после заказа

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

Частая ошибка

Заказ создают в контроллере, на который покупатель возвращается из банка, и верят параметру вроде status=paid в адресе. Такой адрес можно открыть вручную и получить «оплаченный» заказ. Заказ подтверждают только по уведомлению банка с проверенной подписью, а сумму берут из уведомления и сверяют с корзиной.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.