При выгрузке из может возникнуть ситуация, когда товар привязан к нескольким разделам каталога, но вот выбрать основной из 1С они не могут. Поэтому основным выбирается тот, у которого ID меньше. Подробнее про основной раздел и о том, как может быть важно его указывать можно прочитать в этой статье.

Предлагаю способ, как менять основной раздел на лету. Для этого нужно, чтобы внешний код XML_ID (или как его еще называют ГУИД/GUID) основного раздела из 1С передавали просто в строковое свойство товара. Тогда по событиям добавления и изменения элемента мы будем подменять программно ID основного раздела.

Для начала напишем функцию, которая ищет ID раздела инфоблока по его внешнему коду XML_ID.

<?php

function getSectionIdByXmlId($iblockId, $sectionXmlId)
{
    $entityIblockSection = \Bitrix\Iblock\Model\Section::compileEntityByIblock($iblockId);

    $section = $entityIblockSection::getList([
        'select' => [
            'ID', //выбираем только ID, остальное нам не нужно
        ],
        'filter' => [
            'XML_ID' => $sectionXmlId,
        ],
    ])->fetch();

    return $section ? $section['ID'] : false;
}

Также добавим вспомогательную функцию, которая возвращает массив свойств элементов инфоблока.

<?php

function getIblockProperties($iblockId)
{
    if (empty($iblockId)) return false;

    $filter = [
        'IBLOCK_ID' => $iblockId,
    ];

    $propertyList = \CIBlockProperty::GetList(
        ['SORT' => 'ASC'],
        $filter
    );

    while ($property = $propertyList->Fetch()) {
        $res[$property['CODE']] = [
            'ID' => $property['ID'],
            'CODE' => $property['CODE'],
            'NAME' => $property['NAME'],
        ];
    }

    return !empty($res) ? $res : false;
}

Далее "подписываемся" на события добавления и изменения элемента ИБ и пишем функцию обработчик.

<?php

$eventManager = \Bitrix\Main\EventManager::getInstance();

$eventManager->addEventHandler(
    'iblock',
    'OnBeforeIBlockElementAdd',
    'changeMainSection'
);

$eventManager->addEventHandler(
    'iblock',
    'OnBeforeIBlockElementUpdate',
    'changeMainSection'
);

function changeMainSection(&$arFields)
{
    if ($arFields['IBLOCK_ID'] != CATALOG_ID) return; //подставьте свой ID инфоблока каталога

    if ($properties = $arFields['PROPERTY_VALUES']) {
        //получаем массив свойств инфоблока
        $iProps = getIblockProperties($arFields['IBLOCK_ID']);
        //получаем ID свойства, где MAIN_SECTION_UID - код свойства с УИДом
        $sectionUidPropId = $iProps['MAIN_SECTION_UID']['ID'];

        if ($sectionUidPropId && $properties[$sectionUidPropId]) {
            $uidProp = reset($properties[$sectionUidPropId]);

            if ((is_array($uidProp) && $uidProp['VALUE'])) {
                //ищем ID раздела по внешнему коду из свойства элемента
                $sectionId = getSectionIdByXmlId($arFields['IBLOCK_ID'], $uidProp['VALUE']);
                
                if ($sectionId) {
                    //подменяем ID основного раздела
                    $arFields['IBLOCK_SECTION_ID'] = $sectionId;
                }
            }
        }
    }
}

Этапы обработчика:

  • Получаем ID свойства с УИДом по его коду;
  • Получаем значение свойства с УИДом из обновляемого элемента;
  • Ищем ID раздела по его внешнему коду;
  • Подменяем основной раздел IBLOCK_SECTION_ID.

Весь представленный код размещаем в /local/php_interface/init.php.

Дополнительно: вместого того, чтобы жестко задавать CATALOG_ID в коде, можете воспользоваться функцией получения ID инфоблока по его символьному коду. Подробнее в этой статье.