Событие перед записью свойств торговых предложений
На скриншоте указано для каких свойств вызывается событие:

Здесь видно, что это событие отличается от [onSetPropsForItem] тем, что вызывается в момент импорта характеристик модификаций МС в свойства торговых предложений БУС.
[OnSetSkuProps] Событие перед записью свойств торговых предложений
Событие вызывается перед записью свойств торговых предложений. Позволяет модифицировать массив свойств, который будет передан в CIBlockElement::SetPropertyValuesEx().
Событие вызывается для каждой модификации — и при создании, и при обновлении, даже если модулю нечего записывать (arResultSku пуст). При создании оно вызывается и тогда, когда товар каталога для модификации создать не удалось. SetPropertyValuesEx() модуль вызывает, только если итоговый arResultSku непуст.
- Исключение из обработчика модуль не перехватывает — оно обрывает шаг импорта. Оборачивайте код в
try/catch. - Параметры последнего обработчика, вернувшего
EventResult::SUCCESS, целиком заменяютarResultSku. Ответы не сливаются: каждый обработчик получает исходный массив модуля. EventResult::ERRORигнорируется. Чтобы ничего не записывать, вернитеSUCCESSс пустым массивом.SUCCESSбез параметров даётnull, который модуль передаёт вcount()— на PHP 8 этоTypeError. Всегда возвращайте полный массив, а если менять нечего — не возвращайте ничего.
- Описание события
- Пример кода
Параметры события
| Параметр | Тип | Описание |
|---|---|---|
itemBx | array | Элемент инфоблока Битрикс (торговое предложение) |
itemMs | object | Элемент из МойСклад (модификация) |
propSkuList | array | Массив с параметрами свойств Битрикса |
arResultSku | array | Массив свойств для записи через CIblockElement::SetPropertyValuesEx() |
Структура itemBx
// при создании торгового предложения — только:
[
'ID' => 1234,
'IBLOCK_ID' => 5,
]
// при обновлении — элемент из выборки модуля:
[
'ID' => 1234,
'IBLOCK_ID' => 5,
'NAME' => 'Товар (Красный, L)',
'XML_ID' => 'parentcode#abc123externalcode', // или без префикса родителя — зависит от настройки XML_ID модификаций
// ... CODE, ACTIVE, SORT, тексты и картинки
]
Доступ к характеристикам модификации МС (itemMs)
// Перебор характеристик модификации:
foreach ($itemMs->characteristics as $prop) {
$prop->id; // UUID характеристики в МС: '25f3a-...'
$prop->name; // Название: 'Цвет'
$prop->value; // Значение: 'Красный'
}
Структура propSkuList
[
'PROP_IDS' => [
'msCharUUID1' => 123, // UUID характеристики МС => ID свойства Битрикс
'msCharUUID2' => 456,
],
'PROP_TYPES' => [
123 => [
'TYPE' => 'S', // тип свойства, см. ниже
'PARAM' => '', // для E — ID привязанного инфоблока, для S:directory — TABLE_NAME HL-блока
],
456 => [
'TYPE' => 'L',
'PARAM' => '',
],
789 => [
'TYPE' => 'S:directory',
'PARAM' => 'b_hlbd_color', // TABLE_NAME HL-блока справочника
'HL_CLASS' => '...', // класс сущности HL-блока или null, если HL-блок не найден
],
],
'PROP_ENUMS' => [
'msCharUUID1' => [
'КРАСНЫЙ' => 15, // значение в верхнем регистре => ID значения списка / ID элемента / UF_XML_ID
'СИНИЙ' => 16,
],
'msCharUUID2' => [
'L' => 20,
'M' => 21,
'S' => 22,
],
],
]
Особенности propSkuList:
PROP_IDS— только характеристики, сопоставленные со свойствами поддерживаемых типов (S,N,L,E,S:directory).PROP_TYPES— типы всех одиночных свойствS,L,N,E,Fи множественныхFинфоблока торговых предложений, а не только сопоставленных. ПоэтомуTYPEможет быть иS:HTML,S:Date,S:DateTime,F,F:Multipleи т.п. КлючHL_CLASSесть только уS:directory— у остальных его нет вовсе (а неnull), проверяйте черезisset()/!empty().PROP_ENUMS— к моменту события модуль уже сам создал недостающие значения для характеристик этой модификации: значение списка (L), элемент привязанного инфоблока (E, ключ —NAMEв верхнем регистре →ID), строку HL-блока (S:directory,UF_NAMEв верхнем регистре →UF_XML_ID, гдеUF_XML_ID— транслит значения). Они уже есть вPROP_ENUMSи вarResultSku.- Если ни одна характеристика не сопоставлена со свойством поддерживаемого типа,
propSkuListможет прийти пустым массивом без ключейPROP_IDS,PROP_ENUMS,PROP_TYPES.
Структура arResultSku
[
123 => 'Красный', // строковое свойство
456 => 20, // ID значения списка
789 => 'red-xml-id', // UF_XML_ID для справочника
// ...
]
Возвращаемое значение
Верните EventResult::SUCCESS с модифицированным массивом $arResultSku. Этот массив будет передан в CIBlockElement::SetPropertyValuesEx().
return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS, $arResultSku);
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'rbs.moyskladstocks',
'OnSetSkuProps',
'OnSetSkuPropsHandler'
);
function OnSetSkuPropsHandler(\Bitrix\Main\Event $event)
{
$eventParams = $event->getParameters();
//Элемент БУС (массив)
$itemBx = $eventParams['itemBx'];
//Элемент МС (объект)
$itemMs = $eventParams['itemMs'];
//Массив с параметрами свойств Битрикса, подробнее описаны ниже
$propSkuList = $eventParams['propSkuList'];
//Массив, который можно менять для установки новых свойств. Данные записываются в метод CIblockElement::SetPropertyValuesEx()
$arResultSku = $eventParams['arResultSku'];
//доступ к текущим характеристикам осуществляется через их перебор
foreach ($itemMs->characteristics as $prop) {
//значение характеристики модификации МС
$propValue = $prop->value;
//значение в верхнем регистре, необходимо чтобы определить существующее значение
//свойства типа "Список", "Эл. инфоблока" или "Справочник"
//поскольку эти свойства записываются через их ID, а не строковое значение
$enumKeyValue = mb_strtoupper($propValue);
//характеристика не сопоставлена со свойством (или propSkuList пуст)
if (!isset($propSkuList['PROP_IDS'][$prop->id])) {
continue;
}
//доступ к ID свойству битрикса, ассоциированному с характеристикой
$propIdBx = $propSkuList['PROP_IDS'][$prop->id];
//тип свойства битрикса
$propType = $propSkuList['PROP_TYPES'][$propIdBx]['TYPE'];
//ниже описаны возможные типы свойств торг. предложения битрикса, куда будут импортироваться характеристики
switch ($propType) {
case 'S': //свойства типа "строка"
$arResultSku[$propIdBx] = $prop->value;
break;
case 'N': //свойства типа "число"
$arResultSku[$propIdBx] = (float)$prop->value;
break;
case 'L': //свойства типа "список"
if (isset($propSkuList['PROP_ENUMS'][$prop->id][$enumKeyValue])) {
//текущее значение свойства в виде ID значения списка
$enumId = $propSkuList['PROP_ENUMS'][$prop->id][$enumKeyValue];
if ((int)$enumId > 0) {
$arResultSku[$propIdBx] = $enumId;
}
}
break;
case 'E': //свойства типа "Привязка к элементам инфоблока"
//считывание ID инфоблока, который привязан к свойству
$iblock_id = $propSkuList['PROP_TYPES'][$propIdBx]['PARAM'];
if (isset($propSkuList['PROP_ENUMS'][$prop->id][$enumKeyValue])) {
//текущее значение ID привязанного элемента инфоблока
$elementId = $propSkuList['PROP_ENUMS'][$prop->id][$enumKeyValue];
if ((int)$elementId > 0) {
$arResultSku[$propIdBx] = $elementId ;
}
}
break;
case 'S:directory': //свойства типа "Справочник"
//делаем проверку что модуль корректно загрузил сущность справочника для работы с ним
if (!empty($propSkuList['PROP_TYPES'][$propIdBx]['PARAM']) && $propSkuList['PROP_TYPES'][$propIdBx]['HL_CLASS'] !== null) {
//теперь можем работать со справочником как с классом, со всеми стандартными методами
$entityDataClass = $propSkuList['PROP_TYPES'][$propIdBx]['HL_CLASS'];
//$entityDataClass::add();
//$entityDataClass::update();
//$entityDataClass::getList();
$ufXmlId = ''; //заметьте что привязка к справочнику идет не по ID элемента
//справочника, а по полю UF_XML_ID, которое автоматом создается при
//создании свойства типа "Справочник"
if (isset($propSkuList['PROP_ENUMS'][$prop->id][$enumKeyValue])) {
$ufXmlId = $propSkuList['PROP_ENUMS'][$prop->id][$enumKeyValue];
}
//если есть текущий UF_XML_ID, то можем с ним работать
if(!empty($ufXmlId)){
$arResultSku[$propIdBx] = $ufXmlId;
}
//Пример найти текущий элемент справочника
$hlItem = $entityDataClass::getList([
'filter' => [
'=UF_XML_ID' => $ufXmlId
]
])->fetch();
//$hlItem['UF_NAME'] -- название справочника, которое выводится на сайте
//$hlItem['ID'] -- его значение, которое можно передавать в метод $entityDataClass::update();
//но не советую менять поле UF_NAME, лучше создать новый элемент справочника
//еще пример если нужно подставлять значения справочников исходя из характеристик модификации МС
if($prop->value === '#000') {
$ufNewXmlId = 'black'; //пусть будет ассоциация с текущим значением характеристики
$hlItem = $entityDataClass::getList([
'filter' => [
'=UF_XML_ID' => $ufNewXmlId
]
])->fetch();
//можно искать по любому полю, важно чтобы в элементе
//было нужное значение у поля
//$hlItem['UF_NAME']
//подставляем если нашли элемент с непустым UF_XML_ID
if(isset($hlItem['UF_XML_ID']) && !empty($hlItem['UF_XML_ID'])){
$arResultSku[$propIdBx] = $hlItem['UF_XML_ID'];
} else {
//если он пустой или отсутсвует, то создаем новый с заполненным полем UF_XML_ID
$result = $entityDataClass::add([
'UF_NAME' => 'черный',
'UF_XML_ID' => $ufNewXmlId
]);
if($result->isSuccess()){
$arResultSku[$propIdBx] = $ufNewXmlId;
}
}
}
}
break;
}
}
//Отправляем \Bitrix\Main\EventResult::SUCCESS только в случае, если нужно поменять данные перед отправкой
return new \Bitrix\Main\EventResult(\Bitrix\Main\EventResult::SUCCESS, $arResultSku);
}