07.07.2019

Пользовательские ограничения в службах доставки

У служб доставки, как и у платежных систем имеется возможность настраивать ограничения по ряду предустановленных условий. Таким образом, например, службу доставки можно настроить так, что она будет работать только для некоторого местоположения, только для заказов такой-то стоимости,веса или выбрать другие ограничения из стандартных ограничений. Иногда таких условий может не хватать. Для расширения стандартного набора ограничений своими собственными можно использовать событие onSaleDeliveryRestrictionsClassNamesBuildList

<?Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'sale',
    'onSaleDeliveryRestrictionsClassNamesBuildList',
    'myDeliveryFunction'
);?>

Одно из последних ограничений с которым я столкнулся - это ограничение по доступности РПО "Посылка онлайн" в пункте назначения. У Почты России существует соответсвующий тариф, который дешевле чем обычная посылка. Но данным способом можно отправлять не во все отделения. Для проверки нужно использовать запрос к тарификатору Почты России

У меня получилась следующая реализация данного ограничения:

<?php

namespace Gricuk\Sale\Delivery\Restrictions;

use Bitrix\Main\Data\Cache;
use Bitrix\Main\Web\HttpClient;
use Bitrix\Sale\Delivery\Restrictions;
use Bitrix\Sale\Internals\Entity;

/** Ограничение по доступности РПО Посылка онлайн в месте назначения
 * Class RestrictRusPostOnline
 * @package Gricuk\Sale\Delivery\Restrictions
 */
class RestrictRusPostOnline extends Restrictions\Base
{
    public static function onSaleDeliveryRestrictionsClassNamesBuildList()
    {
        return new \Bitrix\Main\EventResult(
            \Bitrix\Main\EventResult::SUCCESS,
            array(
                '\Gricuk\Sale\Delivery\Restrictions\RestrictRusPostOnline' => '/local/php_interface/lib/Gricuk/Sale/Delivery/Restrictions/RestrictRusPostOnline.php',
            )
        );
    }

    public static function getClassTitle()
    {
        return 'посылка/курьер онлайн';
    }

    public static function getClassDescription()
    {
        return 'доставка будет доступна только там где можно расчитать стоимость доставки для РПО Посылка онлайн';
    }

    /** Выполняет проверку на доступность службы доставки
     * @param $zip
     * @param array $restrictionParams
     * @param int $serviceId
     * @return bool
     */
    public static function check($zip, array $restrictionParams, $serviceId = 0)
    {
        if (!empty($restrictionParams["COUNTRY"]) && (strlen($zip) > 0)) {
            return false;//Если не заполнен ZIP
        }
        try {
            $url = "https://tariff.russianpost.ru/tariff/v1/calculate?json&object={$restrictionParams["RPO"]}&from={$restrictionParams["ZIP_FROM"]}&to={$zip}&weight=300";

            $result = self::sendRequest($url);

            if (!empty($result['errors'])) {
                return false;//Если есть ошибки от Почты России
            }
        } catch (\Exception $e) {
            return false;//Если не получилось сделать запрос
        }

        return true;
    }

    /**Преобразует $shipment в то что будет передано в первый параметр метода self::check
     * @param Entity $shipment
     * @return mixed|string|null
     * @throws \Bitrix\Main\ArgumentException
     * @throws \Bitrix\Main\NotImplementedException
     */
    protected static function extractParams(Entity $shipment)
    {
        /** @var \Bitrix\Sale\Order $order */
        $order = $shipment->getCollection()->getOrder();

        return $order->getPropertyCollection()->getDeliveryLocationZip()->getValue();
    }

    /** Возвращает массив параметров, описывающий ограничение
     * @param int $entityId
     * @return array
     */
    public static function getParamsStructure($entityId = 0)
    {
        return array(
            "ZIP_FROM" => array(
                "TYPE" => "STRING",
                "LABEL" => "Индекс места отправления",
            ),
            "RPO" => array(
                "TYPE" => "ENUM",
                "LABEL" => "РПО",
                "OPTIONS" => [
                    "23030" => "Посылка онлайн обыкновенная",
                    "24030" => "Курьер онлайн обыкновенный",
                ]
            )
        );
    }

    /**
     * @param $url
     * @return mixed
     */
    protected static function sendRequest($url)
    {
        $result = false;
        $cache = Cache::createInstance();
        if ($cache->initCache(86400, md5($url))) {
            $result = $cache->getVars();
        } elseif ($cache->startDataCache()) {
            try {
                $httpClient = new HttpClient([
                    "socketTimeout" => 5,
                    "streamTimeout" => 10
                ]);
                $resultString = $httpClient->get($url);

                $result = json_decode($resultString, true);
                $cache->endDataCache($result);
            } catch (\Exception $e) {

            }
        }

        return $result;
    }
}