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

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

При разработке сайтов на Битрикс, с интеграцией с 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

Михаил Базаров 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
Максим 08.07.2024
Чтобы не запретить обновлять поле торговых предложений CML2_LINK, unset не подойдет.
У меня работает такой код в init.php  (может кому то пригодится):
Код
AddEventHandler("iblock", "OnBeforeIBlockElementUpdate","DoNotUpdate");
function DoNotUpdate(&$arFields)
{
    if (($_REQUEST['mode']=='import'))
    {
        $arSelect = Array("ID", "IBLOCK_ID", "NAME", "PROPERTY_CML2_LINK");
        $arFilter = Array("IBLOCK_ID"=>"ИД_ИНФОБЛОКА_ТОРГОВЫХ_ПРЕДЛОЖЕНИЙ", "ID"=>$arFields['ID']);
        $res = CIBlockElement::GetList(Array(), $arFilter, false, Array(), $arSelect);
        while($ob = $res->GetNextElement()){
            $arProps = $ob->GetProperties();
        }
        $arFields['PROPERTY_VALUES'][ИД_СВОЙСТВА_CML2_LINK] = $arProps['CML2_LINK']['VALUE'];
    }
}

Блог-note: заметки разработчика

Вывести свойство отдельно ото всех или исключить из всех

Иногда, на сайте, под управлением 1С-Битрикс, нужно вывести какое-то конкретное свойство отдельно ото всех, или вообще н...

Как работает система сертификации партнеров 1С-Битрикс, уровни партнеров и специалистов

Сертификация от «1С-Битрикс» – это объективная оценка знаний и практических навыков разработки проектов на платформе от ...

Сортировать товары по названию, цене и свойствам в каталоге 1С-Битрикс

Задача: реализовать возможность сортировки товаров в разделах каталога. Сортировка должна работать с использованием AJAX...

Фотогалерея на шаблоне новостей в 1С-Битрикс

Частенько стоит задача, по мимо стандартных "Картинка для анонса" и "Детальная картинка", добавить в...

Удалить всех пользователей которые не делали заказов в магазине 1С-Битрикс

Задача: сайт проработал 7 лет и все время на нем была открытая регистрация, создано много мертвых учетных записей (б...

Постраничная навигация в списке разделов Битрикс- catalog.section.list

Если в магазине очень много разделов и хочется вывести их с постраничной навигацией: можно воспользоваться методами CDBR...

Добавление своих полей в почтовые шаблоны Битрикс

Иногда нужно внести свои поля в почтовые шаблоны битрикс. Например: добавить имя и номер телефона заказчика в почтовый ш...

Получить множественное пользовательское поле раздела. Значения множественного UF_ поля через API

Задача: У разделов инфоблока есть множественное поле типа список. Зная ID раздела, нужно получить и вывести всю информац...

Вывести все разделы в которых находится элемент инфоблока

Если нужно вывести все разделы, со всей доступной информацией о них, внутри элемента инфоблока, например в карточке това...