На сайте клиента должны появляться все нововведения, пришедшие в обновлениях продукта.
Доработки должны быть максимально изолированы от процесса импорта. Чтобы можно было их отключить, подтвердить, что проблема не у нас на канале, и отправить баг-репорт в саппорт.
Работы по мержингу доработок с обновлённым сайтом должны либо отсутствовать, либо быть минимальными в особо критичных ситуациях.
Из этих требований вытекают условия — совсем не трогать класс CIBlockCMLImport и стараться не трогать catalog.import.1c. Практически во всех наших задачах этого можно достичь с помощью обработчиков.
iblock.OnStartIBlockElementAdd / iblock.OnStartIBlockElementUpdate Знакомые, наверное, почти каждому события. Вызываются перед добавлением/обновлением элемента инфоблока до валидации полей и свойств, первым аргументом передаётся &$arFields. С помощью них можно назначать обязательные, но отсутствующие значения характеристик товаров, давать уникальные символьные коды по своим алгоритмам и менять привязку к разделам.
iblock.OnAfterIBlockElementAdd / iblock.OnAfterIBlockElementUpdate События вызываются после создания/обновления элемента инфоблока. В обработчик первым аргументом передаётся &$arFields. При использовании OnAfterIBlockElementAdd стоит помнить, что оно вызывается в любом случае — хоть при успешно созданном элементе, хоть при ошибке. Поэтому надо обязательно проверять ключ RESULT и корректировать логику в зависимости от него. Через эти обработчики можно производить действия постфактум — создать вспомогательные записи в БД, что-то где-то обновить и т.п. Например, создать элемент в ИБ «Производители» и привязать к нему товар, если в выгрузке значение свойства — строка, а не ссылка на справочник. Или пронаследовать некоторые характеристики всех торговых предложений в основной товар для более быстрой фильтрации в каталоге.
catalog.OnSuccessCatalogImport1C Самое вкусное оставил напоследок. Данное событие появилось около года назад. Вызывается оно в компоненте catalog.import.1c в самом конце импорта — перед отдачей строки success, сигнализирующей 1Ске об успешном окончании обмена. С помощью этого события можно организовать пост-обработку импортированных товаров/ТП - перегенерировать неуправляемый кеш, вычислить диапазон цен для товара с торговыми предложениями, импортировать скидки как нативные битриксовые скидки. Стоит заметить, что на этом шаге весь xml-файл ещё доступен в таблице b_xml_tree, поэтому потенциал события огромен. А если прибавить к этому ещё и возможность реализации пошаговости, то можно сделать свой маленький изолированный импорт без каких-либо модификаций основного так, что 1Ска ничего и не заподозрит:-) Собственно, это событие и его обсуждение тут и сподвигло написать данный пост — показать, как можно на основе этого события реализовать пошаговость. Пример (с подсветкой):
AddEventHandler('catalog', 'OnSuccessCatalogImport1C', 'customCatalogImportStep');
function customCatalogImportStep()
{
$stepInterval = (int) COption::GetOptionString("catalog", "1C_INTERVAL", "-");
$startTime = time();
// Флаг импорта файла торговых предложений
$isOffers = strpos($_REQUEST['filename'], 'offers') !== false;
$NS = &$_SESSION["BX_CML2_IMPORT"]["NS"];
if (!isset($NS['custom']['lastId'])) {
// Последний отработанный элемент для пошаговости.
$NS['custom']['lastId'] = 0;
$NS['custom']['counter'] = 0;
}
// Условия выборки элементов для обработки
$arFilter = array(
'IBLOCK_ID' => 1024,
'ACTIVE' => 'Y',
);
$res = CIBlockElement::GetList(array('ID' => 'ASC'), array_merge($arFilter, array('>ID' => $NS['custom']['lastId'])));
$errorMessage = null;
while ($arItem = $res->Fetch()) {
/*
// Что-нибудь делаем
if (updateElement($arItem['ID']) === false) {
$error = true;
}
*/
if ($error === true) {
$errorMessage = 'Что-то случилось.';
break;
}
$NS['custom']['lastId'] = $arItem['ID'];
$NS['custom']['counter']++;
// Прерывание по времени шага
if ($stepInterval > 0 && (time() - $startTime) > $stepInterval) {
break;
}
}
if ($arItem != false) {
if ($errorMessage === null) {
print "progress\n";
print "Обработано " . $NS['custom']['counter'] . ' элементов, осталось ' . $res->SelectedRowsCount();
} else {
print "failure\n" . $errorMessage;
}
$contents = ob_get_contents();
ob_end_clean();
if (toUpper(LANG_CHARSET) != "WINDOWS-1251") {
$contents = $GLOBALS['APPLICATION']->ConvertCharset($contents, LANG_CHARSET, "windows-1251");
}
header("Content-Type: text/html; charset=windows-1251");
print $contents;
exit;
}
}
В примере происходит выборка из некоего инфоблока и совершение действий над элементами этого инфоблока. Если при обновлении произошла ошибка, 1Ске вернётся статус failure с текстом ошибки. Если всё успешно прошло, происходит выход из обработчика и компонент catalog.import.1c завершает работу (обнуляет сессию и возвращает success).
Заключение Вот как-то так мы и работаем с 1ской — пишем тз, рисуем таблички, генерим примеры и изворачиваемся подобными способами в особых ситуациях:-)
Не main, а iblock конечно же. Событие, срабатывающее после окончания импорта, действительно очень вкусное А вот использовать его для реализации продолжения пошагового импорта - очуменная идея! Спасибо!
Я думаю, метод Неймана - это единственный правильный вариант использования обработчика OnSuccessCatalogImport1C, потому что использовать этот обработчик без пошаговости - это убийство импорта.
Сталкивались с той же проблемой что вы описываете, но решили ее немного по-другому. Вместо копирования класса CIBlockCMLImport мы его наследуем и переопределяем нужные методы (с вызовом родительский). А также подменяем вызовы компонента на свои.
В результате фичи которые появляются в этом классе появляются и у нас. В случае если не появляются - нужно сделать diff всего 2х файлов - component.php (у нашего компонента) и 1c_exchange2.php (на который перенаправляется обмен).
А копировать класс и менять его это варварство, конечно.
Андрей, ну так ведь метод даже если и был известен кому-то до вас, но опубликован не был - это точно. Значит - ваш авторский. Вы, кстати, не являетесь потомков того самого барона фон Неймана, который сформулировал принципы организации ЭВМ?
iblock.OnBeforeIBlockElementAdd или iblock.OnAfterIBlockElementAdd может помочь решить следующую проблему? Не корректно работает выгрузка номенклатуры в отдельные инфоблоки - товары выгружаются, предложения выгружаются, но все без характеристик
посмотрел - характеристики есть только в файле import.xml а вроле должны быть в offers.xml, а их их нет
скорее всего 1С не правильно выгружает товары с разными характеристиками (в 1С стоит галочка вести учет по доп. характеристикам) версия 1С не типовая УТ, а Комплексная Автоматизация
мне хотя бы теоретически - как обработчик события использовать я представляю, xml с помощью PHP тоже можно разобрать, а вот где данные из import.xml и offers.xml хранятся? Ни при каждом же добавлении товара читать их из файла import.xml и искать нужные характеристики, чтобы записать их в добавленный товар?
Аверков Денис, данные в процессе импорта находятся в таблице b_xml_tree, для их чтения есть специальный класс. Посмотрите в качестве примера стандартный /bitrix/modules/iblock/classes/general/cml2.php
посмотрел данные в таблице b_xml_tree - там нет характеристик товара из import.xml - придется работать с файлом /upload/1c_catalog/import.xml - обрабатывать событие catalog.OnSuccessCatalogImport1C
не подходит даже при catalog.OnSuccessCatalogImport1C там импорт некорректно происходит товары с характеристиками вообще не добавляются никуда, только без характеристик думаю, все из-за схемы cml2 1С выдает файлы с версией схемы 2.03, а для корректного импорта надо как минимум 2.04, или ошибаюсь? Как же поменять выдаваемые 1С файлы? 1С 8.2 Комплексная автоматизация редакция 1.1 (1.1.23.2) хотя здесь http://1c.1c-bitrix.ru/ecommerce/require_1C.php написано, что совместима только с 1С 8.1 КА 1.0.16 то есть с нашей версией нет полной совместимости? и как можно 1С-ку подпилить, чтобы выдавала cml2 с версией схемы 2.04?
Аверков Денис, чтобы характеристики товара появились на сайте (в виде нормальных свойств), они должны быть заведены в 1С как свойства. Если в выгрузке приходят тэги ХарактеристикиТовара, они будут в b_xml_tree и с помощью обработчика можно вытащить всё, что требуется. Хотя лучше привести базу или обработку к нужному для стандартного импорта формату.
Нейман Андрей, в 1С большая номенклатура и много разных категорий, сущностей, есть Товары разных типов, каждый со своим набором свойств, есть даже такие товары, как авансовая предоплата по договору... эти свойства появляются у всех товаров одновременно... Привести к нужному для стандартного импорта формату - это только в 1С?
Нейман Андрей, в `b_xml_tree` ничего не нашел SELECT * FROM `b_xml_tree` WHERE `NAME` like '%ракт%' SELECT * FROM `b_xml_tree` WHERE `NAME` like '%войст%' ничего не дали или как-то называются они по-другому?
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».