Периодически на проектах встречается задача внедрить не стандартную логику определения местоположения в компоненте оформления заказа.
Большинство решений предлагают, по сути, эмулировать смену уже на отображенной странице с последующей перегрузкой при помощи 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. Для этого скопировать его код в новый метод из примера выше, и внести необходимые правки. В этом случае возможно родительский метод вызывать нет необходимости (зависит от внесенных правок)