Периодически на проектах встречается задача внедрить не стандартную логику определения местоположения в компоненте оформления заказа.
Большинство решений предлагают, по сути, эмулировать смену уже на отображенной странице с последующей перегрузкой при помощи JavaScrip. Вот еще один вариант, но без лишних перегрузок. Решение работает на основе обработчика события компонента bitrix:sale.order.ajax OnSaleComponentOrderProperties.
В первую очередь выносим идентификаторы свойств, которые нам понадобятся в доступные переменные
class ProjectConfig { /** * ИД свойства заказа Почтовый индекс */ const PROPERTY_ZIP_ID = 4; /** * ИД свойства заказа Местоположение */ const PROPERTY_LOCATION_ID = 6; }
Далее добавляем метод обработчика события. Для примера "нестандартной" логики я взял хранение местоположение в свойстве UF_LOCATION пользователя сайта. Компонент оперирует кодом местоположения из-за этого первым делом по значению UF_LOCATION получаем код нужного местоположения. Следующим шагом, необходимо проверить почтовый индекс на соответствие местоположению. Полученные значения местоположения и индекса заносим в соответствующие переменные массива $arUserResult['ORDER_PROP'].
class SaleHandlers { private static $cacheZipTimout = 300000000; /** * Проверяем почтовый индекс по местоположению. Если не входит в список - возвращаем первый из списка * @param $locationId int ИД местоположения * @param $zip int индекс */ public static function checkZip ($locationId,$zip){ $arResult = array(); $cache = Bitrix\Main\Data\Cache::createInstance(); if ($cache->initCache(self::$cacheZipTimout, 'location_index_'.$locationId, 'zip_locations')) { $arResult = $cache->getVars(); } elseif ($cache->startDataCache()) { $rsZip = CSaleLocation::GetLocationZIP($locationId); while ($arZip = $rsZip->fetch()) { $arResult[$arZip['ZIP']] = true; } $cache->endDataCache($arResult); } reset($arResult); return (array_key_exists($zip,$arResult)) ? $zip : key($arResult); } public static function OnSaleComponentOrderProperties(&$arUserResult, $request, &$arParams, &$arResult) { global $USER; if ($USER->IsAuthorized()) { $arUser= Main\UserTable::getList([ 'filter' => ['ID' => $USER->GetID()], 'select' => [ 'UF_LOCATION', 'LOCATION_CODE'=>'LOCATION.CODE' ], 'runtime' => [ new Main\Entity\ReferenceField( 'LOCATION', '\Bitrix\Sale\Location\LocationTable', [ 'this.UF_LOCATION' => 'ref.ID' ] ) ] ])->fetch(); $arUserResult['ORDER_PROP'][Opt::PROPERTY_LOCATION_ID] = $arUser['LOCATION_CODE']; $arUserResult['ORDER_PROP'][Opt::PROPERTY_ZIP_ID] = self::checkZip( $arUser['UF_LOCATION'], $arUserResult['ORDER_PROP'][Opt::PROPERTY_ZIP_ID] ); } } }
Следующий шаг зарегистрировать классы и обработчик в init.php
use Bitrix\Main\EventManager; Bitrix\Main\Loader::registerAutoLoadClasses(null, array( 'ProjectConfig' => '/local/php_interface/classes/projectconfig.php', 'SaleHandlers' => '/local/php_interface/handlers/salehandlers.php', )); $eventManager = EventManager::getInstance(); $eventManager->addEventHandler( "sale", 'OnSaleComponentOrderProperties', array("SaleHandlers", "OnSaleComponentOrderProperties") );
Следующая задача изменить страницу оформления заказа. Стандартный компонент оформления заказа выполнен практически полностью на JavaScript. Нам необходимо запретить редактирование местоположения. Для этого необходимо переопределить метод объекта BX.Sale.OrderAjaxComponent сохраняем метод editActiveRegionBlock. И создаем альтернативный, в котором сначала проверяем необходимость отображения блока. Если вывод полей редактирование то просто выходим, иначе вызываем родительский editActiveRegionBlock.
Для этого в каталоге с шаблоном компонента создаем скрипт (например order_ajax_ext.js) содержащий следующий код:
(function () { 'use strict'; BX.namespace('BX.Sale.OrderAjaxComponentExt'); BX.Sale.OrderAjaxComponentExt = BX.Sale.OrderAjaxComponent; BX.Sale.OrderAjaxComponentExt.parentEditActiveRegionBlock = BX.Sale.OrderAjaxComponent.editActiveRegionBlock; BX.Sale.OrderAjaxComponentExt.editActiveRegionBlock =function (activeNodeMode) { if (this.initialized.region) { return; } BX.Sale.OrderAjaxComponent.parentEditActiveRegionBlock(activeNodeMode); }; })();И подключаем его в template.php после подключения штатного order_ajax.js командой
$this->addExternalJs($templateFolder.'/order_ajax_ext.js');
Обратите внимание: предотвращается редактирование всей информации блока "Регион доставки", т.е. если вам необходимо дать доступ на редактирование части полей этого блока - надо более детально разобрать и исправить метод BX.Sale.OrderAjaxComponent.editActiveRegionBlock. Для этого скопировать его код в новый метод из примера выше, и внести необходимые правки. В этом случае возможно родительский метод вызывать нет необходимости (зависит от внесенных правок)