Если возникает необходимость расчёта стоимости доставки для способов, которые не поддерживаются системой «из коробки», вы можете создать собственный класса для расчёта стоимости и сроков доставки.
Описание классов актуально для версии 5.8.0 и старше; часть свойств и методов может отсутствовать в предыдущих версиях.
Способ доставки настраивается в панели управления модуля «Интернет-магазин». Ему соответствует класс nc_netshop_delivery_method.
Служба доставки — внешний сервис, предоставляющий информацию о стоимости и сроках доставки (API компании, осуществляющей доставку).
Способ расчёта доставки (класс расчёта доставки) — PHP-класс, который отвечает за расчёт сроков и стоимости доставки. Выбирается в способе доставки в поле «Способ автоматического расчёта стоимости доставки». Классы расчёта доставки должны быть наследниками класса nc_netshop_delivery_service.
Тип доставки указывает как производится доставка (курьером по адресу, до пункта выдачи, в почтовое отделение). В классах задаётся с использованием констант nc_netshop_delivery::DELIVERY_TYPE_*.
Варианты доставки позволяют выдавать информацию о нескольких доступных вариантах доставки, настроив в настройках модуля только один способ доставки. Данная возможность полезна, например, при интеграции с агрегаторами доставки, которые позволяют выбрать множество различных служб доставки с различной стоимостью и сроками.
Класс вариантов доставки — nc_netshop_delivery_method_variant — можно использовать везде, где используется nc_netshop_delivery_method (например, при выводе информации о доступных для заказа способах доставки), так как он является его наследником.
Варианты доставки создаются классом расчёта доставки, который должен установить стоимость и сроки доставки. Вариант доставки не может иметь класс расчёта доставки и условия.
Коллекция способов доставки — коллекция nc_netshop_delivery_method_collection, содержащая способы и/или варианты доставки.
my_delivery_service), расширяющий класс nc_netshop_delivery_service.calculate_delivery() (см. ниже).spl_autoload_register(), или в модуле default в function.inc.php подгружать этот класс.
Допустим, класс my_delivery_service находится в файле netcat/modules/default/my_delivery_service.class.php, тогда автозагрузчик этого класса в netcat/modules/default/function.inc.php будет выглядеть следующим образом:
// Загрузка класса my_delivery_service при необходимости
spl_autoload_register(function($class_name) {
    if ($class_name === 'my_delivery_service') {
        include_once nc_module_folder('default') . 'my_delivery_service.class.php';
    }
});
        ShopDeliveryService («Службы доставки») добавить элемент:Все стандартные свойства являются защищёнными (protected).
string $name — название службы доставки (произвольный текст).string $delivery_type — тип доставки, задаётся одной из констант класса nc_netshop_delivery:
nc_netshop_delivery::DELIVERY_TYPE_COURIER — курьерская доставкаnc_netshop_delivery::DELIVERY_TYPE_POST — доставка почтойnc_netshop_delivery::DELIVERY_TYPE_PICKUP — доставка до пункта выдачиnc_netshop_delivery::DELIVERY_TYPE_MULTIPLE — возможны несколько типов доставки (определён метод get_variants(), возвращающий варианты доставки различных типов)array $mapped_fields — список полей, которым нужны соответствия (для получения полей заказа в методе calculate_delivery() или get_variants()). Ключом массива является имя поля, доступное внутри класса в массиве $this->data, а значением — текстовое описание поля, например:
protected $mapped_fields = array(
    // в настройках способа доставки нужно будет выбрать источник значения
    // для поля «город доставки» ($this->data['to_city']):
    'to_city' => 'Город доставки',
);boolean $can_provide_multiple_variants — если true, значит служба доставки может предложить более одного варианта доставки (определён метод get_variants()).В простейшем случае для работа класса расчёта доставки достаточно реализовать только метод calculate_delivery(), остальные методы можно оставить без изменений.
calculate_delivery() — расчёт стоимости и сроков доставкиДанные о заказе будут доступны в свойстве $this->data. По умолчанию в этом массиве доступны элементы:
'items' — состав заказа, экземпляр объекта nc_netshop_item_collection'valuation' — стоимость товаров в заказе'weight' — сумма по полю Weight для всех товаров в заказе. Если сумма по полю Weight равна 0, вес будет равен 100 (грамм), так как внешние службы расчёта стоимости доставки не позволяют рассчитывать вес отправления с нулевым весом. Вес в поле Weight должен быть указан в граммах.'size1', 'size2', 'size3' — габариты общей упаковки товаров в заказе в сантиметрах. Значения вычисляются суммированием значений свойств товаров PackageSize1 PackageSize2 и PackageSize3 с подбором оптимального размера общей упаковки. Для каждого товара без указания габаритов упаковки будут взяты габариты, указанные в настройках модуля («Размер упаковки товара по умолчанию»). Размеры у товаров и в настройках модуля должны быть заданы в сантиметрах.$mapped_fields.Метод calculate_delivery() должен вернуть массив со свойствами:
'price' => стоимость доставки, 'currency' => валюта стоимости доставки, 'min_days' => минимальное количество дней на доставку, 'max_days' => максимальное количество дней на доставку
В случае возникновения ошибки при расчёте и невозможности выдачи правильной оценки доставки нужно вернуть null и установить два свойства у экземпляра класса:
$this->last_error = 'Описание ошибки'; $this->last_error_code = код_ошибки; // например, 1
/**
 * Заготовка для класса расчёта доставки
 */
class my_delivery_service extends nc_netshop_delivery_service {
    /** @var array  Свойства, которые сопоставляются с полями заказов */
    protected $mapped_fields = array(
        'to_city' => 'Город доставки',
    );
    /**
     * Метод расчёта стоимости доставки
     */
    public function calculate_delivery() {
        // В нашем примере доставка стоит 500 руб. плюс 10 руб. за каждый неполный
        // килограмм веса посылки плюс 0,1% от стоимости товаров
        $weight_in_kilograms = ceil($this->data['weight'] / 1000);
        $delivery_cost = 500 +
                         10 * $weight_in_kilograms +
                         $this->data['valuation'] * 0.001;
        // итоговая стоимость к оплате будет округлена
        // в соответствии с настройками модуля
        // В нашем примере доставка в Москву и Санкт-Петербург заказ доставляется
        // за 1 день, а доставка в другие города занимает от 3 до 5 дней
        if ($this->data['city'] == 'Москва' || $this->data['city'] == 'Санкт-Петербург') {
            $min_days = 1;
            $max_days = 1;
        } else {
            $min_days = 3;
            $max_days = 5;
        }
        return array(
            'price' => $delivery_cost,
            'currency' => 'RUR',
            'min_days' => $min_days,
            'max_days' => $max_days
        );
    }
}
get_variants(nc_netshop_delivery_method $method) — получение вариантов доставкиЕсли служба доставки предлагает различные варианты доставки (с разными типами, стоимостью или сроками), то в классе расчёта доставки:
$can_provide_multiple_variants = truecalculate_delivery() должен возвращать null:
public function calculate_delivery() {
    return null;
}get_variants() должен возвращать коллекцию nc_netshop_delivery_method_collection (даже если окажется, что нет доступных вариантов доставки), содержащую объекты nc_netshop_delivery_method_variant.Метод в качестве аргумента принимает объект nc_netshop_delivery_method со свойствами способа доставки, заданными в модуле.
Метод всегда должен возвращать коллекцию nc_netshop_delivery_method_collection.
При подборе доступных способов доставки для заказа (метод matching() коллекции способов доставки, отбирающий способы доставки по условиям, заданным в настройках модуля) способы доставки с классом расчёта доставки, у которых $can_provide_multiple_variants = true, заменяются на варианты, возвращаемые методом get_variants() этого класса.
При замене способа доставки на варианты к вариантам будут применены настройки способа доставки (прибавлена стоимость доставки, установлены дни и время отправки). К идентификатору, указанному у варианта доставки, будет дописан идентификатор способа доставки (чтобы не было конфликта идентификаторов вариантов разных способов доставки).
<?php
class my_delivery_service extends nc_netshop_delivery_service {
    /** @var string тип доставки */
    protected $delivery_type = nc_netshop_delivery::DELIVERY_TYPE_MULTIPLE;
    /** @var bool служба может предложить более одного варианта доставки */
    protected $can_provide_multiple_variants = true;
    /**
     * Расчёт производится в методе get_variants().
     * @return array|null
     */
    public function calculate_delivery() {
        return null;
    }
    /**
     * @param nc_netshop_delivery_method $method
     * @return nc_netshop_delivery_method_collection
     */
    public function get_variants(nc_netshop_delivery_method $method) {
        $delivery_variants = new nc_netshop_delivery_method_collection();
        // Доставка курьером
        $courier_delivery = $this->get_courier_delivery_variant();
        $delivery_variants->add($courier_delivery);
        // Доставка в пункт выдачи
        $pickup_delivery = $this->get_pickup_delivery_variant();
        $delivery_variants->add($pickup_delivery);
        return $delivery_variants;
    }
    /**
     * Пример метода, возвращающего вариант с информацией о курьерской доставке
     * @return nc_netshop_delivery_method_variant
     */
    protected function get_courier_delivery_variant() {
        $courier_delivery = new nc_netshop_delivery_method_variant(array(
            'id' => 1, // это может быть внешний идентификатор от службы доставки
            // (при выводе вариантов к id варианта будет дописан id способа доставки)
            // id должен быть уникальным в пределах способа доставки
            'name' => 'Экспресс-доставка курьером',
            'description' => 'Доставка в пределах города в день заказа.
                Вы можете проверить товар при курьере.',
            'delivery_type' => nc_netshop_delivery::DELIVERY_TYPE_COURIER,
            'extra_charge_absolute' => 300, // стоимость в рублях
            'extra_charge_relative' => 0,   // стоимость в процентах от суммы заказа
            'minimum_delivery_days' => 0,   // 0 — возможна доставка в тот же день
            'maximum_delivery_days' => 0,   // максимальное число дней на доставку
        ));
        return $courier_delivery;
    }
    /**
     * Пример метода, возвращающего вариант доставки в пункт выдачи
     * @return nc_netshop_delivery_method_variant
     */
    protected function get_pickup_delivery_variant() {
        // Вариант доставки до пункта выдачи (50 руб., доставка на следующий день)
        $pickup_delivery = new nc_netshop_delivery_method_variant(array(
            'id' => 2,
            'name' => 'Доставка в пункты выдачи',
            'description' => '',
            'delivery_type' => nc_netshop_delivery::DELIVERY_TYPE_PICKUP,
            'extra_charge_absolute' => 50,
            'extra_charge_relative' => 0,
            'minimum_delivery_days' => 1,
            'maximum_delivery_days' => 1,
        ));
        // Список внешних (не заданных в Netcat, а полученных от службы доставки)
        // пунктов выдачи в выбранном городе:
        $delivery_points = new nc_netshop_delivery_point_external_collection();
        // Пример объекта с информацией о пункте выдачи заказов
        $delivery_point = new nc_netshop_delivery_point_external(array(
            'id' => 'PVZ-1', // в качестве префикса автоматически будет
                             // добавлен ID варианта доставки
            'name' => 'ГУМ',
            'description' => 'Первый этаж, 1 линия у фонтана',
            'phones' => '+7 495 123-45-67',
            'location_name' => 'Москва',
            'address' => 'Красная площадь, дом 3',
            'latitude' => '55.7547',
            'longitude' => '37.6216',
            'payment_on_delivery_cash' => true,
            'payment_on_delivery_card' => false,
            // тип пункта выдачи может быть:
            // nc_netshop_delivery_point::TYPE_PICKUP — обычный ПВЗ
            // nc_netshop_delivery_point::TYPE_POSTAMAT — постамат
            'type' => nc_netshop_delivery_point::TYPE_PICKUP // по умолчанию
        ));
        // Расписание работы
        $delivery_point_schedule = new nc_netshop_delivery_schedule();
        // с понедельника по пятницу с 10 до 22
        $delivery_point_schedule->add(new nc_netshop_delivery_interval(array(
            'day1' => true,
            'day2' => true,
            'day3' => true,
            'day4' => true,
            'day5' => true,
            'time_from' => '10:00',
            'time_to' => '22:00',
        )));
        // в субботу с 10 до 20 с перерывом с 14 до 14:30
        $delivery_point_schedule->add(new nc_netshop_delivery_interval(array(
            'day6' => true,
            'time_from' => '10:00',
            'time_to' => '14:00',
        )));
        $delivery_point_schedule->add(new nc_netshop_delivery_interval(array(
            'day6' => true,
            'time_from' => '14:30',
            'time_to' => '20:00',
        )));
        // Устанавливаем расписание у пункта выдачи
        $delivery_point->set_schedule($delivery_point_schedule);
        $delivery_points->add($delivery_point);
        // Устанавливаем пункты выдачи у варианта доставки
        $pickup_delivery->set_delivery_points($delivery_points);
        return $pickup_delivery;
    }
}
get_settings_fields() — дополнительные параметры для настройки классаМетод get_settings_fields() может использоваться для указания дополнительных полей для настройки способа расчёта доставки, которые будут выводиться на странице редактирования способа доставки.
Метод должен вернуть массив с описанием полей. Структура массива с описанием полей такая же, как для пользовательских настроек макетов и шаблонов компонентов.
Пример:
public function get_settings_fields() {
    return array(
        'param1' => array(
            'type' => 'string',
            'caption' => 'Параметр 1 (строка)',
        ),
        'param2' => array(
            'type' => 'textarea',
            'caption' => 'Параметр 2 (текстовый блок)',
            'codemirror' => false,
        ),
        'param3' => array(
            'type' => 'select',
            'subtype' => 'static',
            'caption' => 'Параметр 3 (выпадающий список)',
            'options' => array(
                'value1' => 'значение 1',
                'value2' => 'значение 2',
            )
        ),
    );
}
Параметры для службы доставки, заданные в настройках способа доставки, можно получить методом get_setting():
$this->get_setting('param1');
