Encodera

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

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

Оглавление

Модуль доставки

Перевозчик в PrestaShop — запись в панели в разделе «Доставка → Перевозчики» с названием, сроком и таблицей цен. Обычно его создают вручную, и модуль не нужен. Модуль доставки пишут, когда стоимость надо считать кодом: запросить тариф у службы доставки или применить свою формулу. Такой модуль наследует CarrierModule.

Пример — отдельный модуль acmeship в папке modules/acmeship.

Главный класс

<?php
// modules/acmeship/acmeship.php
if (!defined('_PS_VERSION_')) {
    exit;
}
 
class AcmeShip extends CarrierModule
{
    public $id_carrier;
 
    public function __construct()
    {
        $this->name = 'acmeship';
        $this->tab = 'shipping_logistics';
        $this->version = '1.0.0';
        $this->author = 'Acme';
 
        parent::__construct();
 
        $this->displayName = $this->trans('Курьер Acme', [], 'Modules.Acmeship.Admin');
    }
 
    public function getOrderShippingCost($cart, $shippingCost)
    {
        return 5.0;
    }
 
    public function getOrderShippingCostExternal($cart)
    {
        return $this->getOrderShippingCost($cart, 0);
    }
}

Два метода обязательны. Движок вызывает их, когда считает доставку для корзины, и берёт возвращённое число как стоимость без налога. Здесь доставка всегда стоит 5 единиц валюты магазина. В свойство id_carrier движок перед вызовом записывает номер перевозчика.

МетодКогда вызывается
getOrderShippingCost($cart, $shippingCost)У перевозчика заданы диапазоны цен; во втором аргументе — цена из таблицы
getOrderShippingCostExternal($cart)Диапазоны не используются

Создание перевозчика

Сам по себе модуль в списке доставки не появится: при установке он должен создать перевозчика, привязанного к модулю.

// modules/acmeship/acmeship.php
public function install(): bool
{
    if (!parent::install() || !$this->registerHook('actionCarrierUpdate')) {
        return false;
    }
 
    $carrier = new Carrier();
    $carrier->name = 'Acme Courier';
    $carrier->active = true;
    $carrier->is_module = true;
    $carrier->external_module_name = $this->name;
    $carrier->shipping_external = true;
    $carrier->need_range = true;
 
    foreach (Language::getLanguages(false) as $language) {
        $carrier->delay[(int) $language['id_lang']] = '2 дня';
    }
 
    if (!$carrier->add()) {
        return false;
    }
 
    return Configuration::updateValue('ACMESHIP_CARRIER_ID', (int) $carrier->id);
}

Carrier — модель ядра. Свойства is_module, external_module_name и shipping_external связывают перевозчика с модулем: стоимость будет спрашиваться у него. delay — текст о сроке доставки на каждом языке. Номер созданного перевозчика модуль запоминает в настройках.

Что ещё нужно перевозчику

Чтобы вариант показался покупателю, перевозчику назначают зоны, группы покупателей и диапазоны. Проще всего сделать это после установки в панели: «Доставка → Перевозчики», кнопка изменения у «Acme Courier».

ЧтоЗачем
ЗоныВ какие регионы возит
ГруппыКаким группам покупателей доступен
Диапазоны веса или ценыОбязательны при need_range, даже если цену считает код

Модули для распространения делают это в install() кодом — методами и моделями ядра addZone(), setGroups(), RangeWeight, RangePrice.

Как увидеть результат

php bin/console prestashop:module install acmeship

Настройте зоны и диапазоны, положите товар в корзину и дойдите до шага доставки: в списке появится «Acme Courier» с ценой 5 и сроком «2 дня».

Расчёт по корзине

// modules/acmeship/acmeship.php
public function getOrderShippingCost($cart, $shippingCost)
{
    $weight = $cart->getTotalWeight();
 
    if ($weight > 30) {
        return false;
    }
 
    return 5.0 + $weight * 0.5;
}

Стоимость теперь зависит от веса корзины. Значение false означает, что перевозчик для этой корзины недоступен, — вариант не покажется.

Смена номера перевозчика

Когда владелец магазина редактирует перевозчика, PrestaShop не меняет запись, а создаёт копию с новым номером — чтобы старые заказы ссылались на прежние условия. Модуль должен обновить сохранённый номер:

// modules/acmeship/acmeship.php
public function hookActionCarrierUpdate(array $params): void
{
    if ((int) $params['id_carrier'] === (int) Configuration::get('ACMESHIP_CARRIER_ID')) {
        Configuration::updateValue('ACMESHIP_CARRIER_ID', (int) $params['carrier']->id);
    }
}

В id_carrier приходит старый номер, в carrier — новый объект.

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

В getOrderShippingCost() обращаются к внешней службе доставки без кеша и без ограничения времени. Метод вызывается на каждой странице с корзиной, и медленный ответ службы тормозит весь магазин. Сохраняйте полученный тариф для пары «корзина — адрес» и ставьте короткий тайм-аут запроса.

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

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