Запретить изменения описаний товаров при выгрузке из 1С УТ на сайт

Просмотров: 20908

При разработке сайтов на Битрикс, с интеграцией с 1С Управление Тороговлей, нужно запретить изменения полей при обмене. В частности, детальное описание и картинку товара.

изменения описаний товаров при выгрузке

Если вы используете 1C для выгрузки структуры каталога, цен, торговых предложений и свойств товаров на ваш сайт, а описания и картинки вы добавляете уже после выгрузки, то у вас могут возникнуть проблемы. При обмене данными, информация, добавленная на сайте, может быть перезаписана. Это происходит потому, что 1C "видит", что у товара нет описания (в своей базе), но на сайте оно присутствует, и поэтому происходит удаление этого товара.

Чтобы избежать такой ситуации, можно воспользоваться событиями OnBeforeIBlockElementUpdate и OnBeforeIBlockElementAdd. Для этого добавьте следующий код в файл /bitrix/php_interface/init.php (если файла нет, создайте его):


AddEventHandler("iblock", "OnBeforeIBlockElementUpdate","DoNotUpdate");
function DoNotUpdate(&$arFields)
{
    if ($_REQUEST['mode'] == 'import') {
        unset($arFields['PREVIEW_PICTURE']);
        unset($arFields['DETAIL_PICTURE']);
        unset($arFields['PREVIEW_TEXT']);
        unset($arFields['DETAIL_TEXT']);
    }
}

AddEventHandler("iblock", "OnBeforeIBlockElementAdd","DoNotAdd");
function DoNotAdd(&$arFields)
{
    if ($_REQUEST['mode'] == 'import') {
        unset($arFields['PREVIEW_PICTURE']);
        unset($arFields['DETAIL_PICTURE']);
        unset($arFields['PREVIEW_TEXT']);
        unset($arFields['DETAIL_TEXT']);
    }
}

В данном случае мы запретили изменение и добавление следующих полей: картинка анонса, детальная картинка, текст анонса и детальный текст. Путем добавления соответствующих строк вы можете запретить изменение любого поля товара.

Аналог на D7 для запрета изменений при обмене данными

Вы также можете использовать D7 для реализации запрета на изменение полей при обмене данными. Вот пример кода:

use Bitrix\Main\EventManager;

EventManager::getInstance()->addEventHandler(
    'iblock',
    'OnBeforeIBlockElementUpdate',
    'DoNotUpdate'
);

EventManager::getInstance()->addEventHandler(
    'iblock',
    'OnBeforeIBlockElementAdd',
    'DoNotAdd'
);

function DoNotUpdate(&$arFields)
{
    if ($_REQUEST['mode'] == 'import') {
        unset($arFields['PREVIEW_PICTURE']);
        unset($arFields['DETAIL_PICTURE']);
        unset($arFields['PREVIEW_TEXT']);
        unset($arFields['DETAIL_TEXT']);
    }
}

function DoNotAdd(&$arFields)
{
    if ($_REQUEST['mode'] == 'import') {
        unset($arFields['PREVIEW_PICTURE']);
        unset($arFields['DETAIL_PICTURE']);
        unset($arFields['PREVIEW_TEXT']);
        unset($arFields['DETAIL_TEXT']);
    }
}

Дополнено: изменение полей товара при обмене с 1С

Написано спустя какое-то время, в обсуждении к заметке описаны случаи когда нужно изменить информацию о товарах, а не о элементах (это немного разное).

Дополняю: обновление габаритов товаров после обмена с 1С, например нужно увеличить все габариты на 1000:

AddEventHandler("iblock", "OnAfterIBlockElementAdd", "UpdateDimensionsAfterElementAddOrUpdate");
AddEventHandler("iblock", "OnAfterIBlockElementUpdate", "UpdateDimensionsAfterElementAddOrUpdate");

function UpdateDimensionsAfterElementAddOrUpdate(&$arFields)
{
    if (CModule::IncludeModule("iblock") && CModule::IncludeModule("catalog")) {
        if ($_REQUEST['mode'] == 'import' || $_REQUEST['mode'] == 'update') {
            // Обновление габаритов (увеличение на 1000 из 1С)
            $arProduct = CCatalogProduct::GetByID($arFields['ID']);
            if ($arProduct) {
                $updatedFields = array(
                    'WIDTH' => $arProduct['WIDTH'] * 1000,
                    'LENGTH' => $arProduct['LENGTH'] * 1000,
                    'HEIGHT' => $arProduct['HEIGHT'] * 1000
                );
                CCatalogProduct::Update($arFields['ID'], $updatedFields);
            }
        }
    }
}

В этом примере обработчик события UpdateDimensionsAfterElementAddOrUpdate будет срабатывать как при добавлении нового элемента, так и при его обновлении. Внутри обработчика происходит проверка на режим импорта или обновления, и соответственно выполняется обновление габаритов.

Информацию о товаре (как товаре) получаем и обновляем методами CCatalogProduct::GetByID и CCatalogProduct::Update

Гость Артур 31.05.2022
Добрый день, прошу помощи в решении такой проблемы, нужно запретить 1с при обмене, изменять Названия свойств каталога и предложений. У нас несколько номенклатур, и у каждого индивидуальный набор характеристик. Проблема в том что в 1с - характеристики имеют названия Цвет(Платья),Размер(Платья) и тд, соответственно в таком виде и выгружаются на сайт. Я редактирую Цвет(Платья) - в Цвет и тд, но после обмена все возвращается к исходному виду как в 1с. Можно с помощью init.php запретить это делать? Не могу разобраться какие параметры отвечают за эти свойства, чтобы прописать в инит
Михаил Базаров 01.06.2022
Цитата
Гость Артур написал:
Добрый день, прошу помощи в решении такой проблемы, нужно запретить 1с при обмене, изменять Названия свойств каталога и предложений.

Тут конечно сходу не подсказать правильный ответ, без экспериментов на живую не обойтись.
Первое что можно попробовать это вот так
Код
unset($arFields['PROPERTY_*']['NAME'])


Если не сработает- то вариант жестче:
Получаем название каждого свойства из инфоблока, сохраняем во временную переменную и снова устанавливаем после перезаписи.
Код на вскидку, надо пробовать и дорабатывать, привожу просто в качестве ориентира- куда копать.

Код
$tmpPropName = $arFields['PROPERTY']['NAME'];
/* здесь случилась перезапись */
$arFields = Array(
    "NAME" => $tmpPropName
);
$ibp = new CIBlockProperty;
if(!$ibp->Update($ID, $arFields))
Максим 01.09.2022
А не подскажете, как отменить добавление товара? То есть, фактически требуется только обновлять товары, имеющиеся на сайте, не добавляя новых.

пробовал варианты:
Код
if (!empty($_GET['mode']) && $_GET['mode'] == 'import') {
    unset($arFields);
}
Код
if (!empty($_GET['mode']) && $_GET['mode'] == 'import') {
    global $APPLICATION;
    $APPLICATION->throwException("Пропускаем этот товар " . $arFields['XML_ID']. ' ' .  $arFields['NAME']);
    return false;
}

в первом случае товары добавляются с одним названием
во втором случае товары не добавляются и через некоторое время выгрузка прекращается с ошибкой, указанной в исключении.

при этом, выгрузка прекращается не на первом пропущенном товаре (логировал с помощью AddMessage2Log())
Alex 04.11.2022
Подскажите пожалуйста. Делаю выгрузку на сайт, описание падает в анонс. Написал обработку в init.php но он не срабатывает

AddEventHandler("catalog", "OnBeforeProductUpdate", Array("My_Class", "OnBeforeProductUpdate"));

Код
class My_Class
   {
      function OnBeforeProductUpdate(&$arFields)
         {
            if (@$_REQUEST['mode']=='import')//импорт из 1с?
         {
         $arFields["PREVIEW_TEXT"]=$arFields["DETAIL_TEXT"];
         }
      }
   }

Подскажите как исправить
Михаил Базаров 04.11.2022
Это событие устарело, не сработает если отключена поддержка устаревших событий в модуле каталога.

Попробуйте использовать OnAfterIBlockElementUpdate
Как-то так, не проверял.
Код
AddEventHandler("iblock", "OnAfterIBlockElementUpdate", Array("MyClass", "OnAfterIBlockElementUpdateHandler"));

class MyClass
{
    // создаем обработчик события "OnAfterIBlockElementUpdate"
    function OnAfterIBlockElementUpdateHandler(&$arFields)
    {
           if ($_REQUEST['mode']=='import') {
               $arFields["PREVIEW_TEXT"]=$arFields["DETAIL_TEXT"];
          }
    }
}
Константин 22.03.2023
Добрый день, Михаил!
Есть задача - не передавать названия складов из 1С, а лучше даже менять при выгрузке

В общем нашел такой вариант:

Код
<?
AddEventHandler(&#39;catalog&#39;, &#39;OnBeforeCatalogStoreUpdate&#39;, &#39;storeUpdateHandler&#39;);
function storeUpdateHandler($storeId, &$arFields) {
   if (isset($_GET[&#39;type&#39;], $_GET[&#39;mode&#39;]) && $_GET[&#39;type&#39;] === &#39;catalog&#39; && $_GET[&#39;mode&#39;] === &#39;import&#39;) 
       {
    $newStoreTitle = $arFields[&#39;TITLE&#39;];
    $res = CCatalogStore::GetList([],[
        "ID"    =>   $storeId
    ]);
    if($ar_res = $res->GetNext()) {
        $oldStoreTitle = $ar_res[&#39;TITLE&#39;];
        if ($newStoreTitle !== $oldStoreTitle) {
            print_r(&#39;На сайте наименование склада #&#39;.$storeId.&#39; (&#39;.$oldStoreTitle.&#39;) отличается от наименования в выгрузке (&#39;.$newStoreTitle.&#39;). Наименование не меняем&#39;.PHP_EOL);            $arFields[&#39;TITLE&#39;] = htmlspecialcharsback($oldStoreTitle);         
        }
   }
    }
}   
?>


Переделал его как-то под ваш, не знаю правильно или нет

Код
<?
AddEventHandler(&#39;catalog&#39;, &#39;OnBeforeCatalogStoreUpdate&#39;, &#39;storeUpdateHandler&#39;);
function storeUpdateHandler($storeId, &$arFields) 
{
   if ($_REQUEST[&#39;mode&#39;]==&#39;import&#39;) 
    {
    unset($arFields[&#39;TITLE&#39;]);
    }
}
?>


но здесь идет отмена, а как заменить? сможете подсказать
Константин 22.03.2023
заменить название склада
Михаил Базаров 22.03.2023
Думаю вот так должно получиться

Код
$arFields['TITLE'] = 'NEW NAME';
Гость 05.02.2024
Здравствуйте! а не подскажите как запретить 1с менять расположение разделов. Ну на пример, я убрал с главной страницы пару разделов в под разделы, но 1с после обмена всё выставляет как у него в 1с структурировано. Изменить саму структуру в 1с нельзя по причине "типа менеджерам магазина так сложно искать товары".))))
Михаил Базаров 05.02.2024
Проверить негде, но чисто логически можно
Код
unset($arFields['SECTION_ID']);
unset($arFields['SECTION_CODE']);

Плюс, вроде бы помню это уже обсуждалось в комментариях. Но не точно  :)
Пролистайте всю ветку
https://bazarow.ru/forum/forum1/125-zapretit-izmeneniya-opisaniy-tovarov-pri-vygruzke-iz-1s-ut-na-sayt