Вводные данные
-
Имеем файл с товарами price.xml
-
Требуется его распарсить и добавить товары в ИБ с каталогом с помощью Битрикс API
<?php
global $USER;
use Bitrix\Catalog\Model\Product;
use Bitrix\Main\Diag\Debug;
use Bitrix\Main\Loader;
$_SERVER["DOCUMENT_ROOT"] = realpath(dirname(__FILE__) . "/../..");
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS", true);
define('CHK_EVENT', true);
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
include('simple_html_dom.php');
set_time_limit(0);
Debug::startTimeLabel('parseItemsLabel');
// Очищаем лог.
file_put_contents($_SERVER["DOCUMENT_ROOT"] . '/z_logs/products/parse_items.txt', '');
file_put_contents($_SERVER["DOCUMENT_ROOT"] . '/z_logs/products/parse_items_error.txt', '');
file_put_contents($_SERVER["DOCUMENT_ROOT"] . '/z_logs/products/parse_items_total.txt', '');
Debug::writeToFile(
'========= СТАРТ ОБРАБОТЧИКА ' . date('d.m.Y H:i:s') . ' =========',
'',
'z_logs/products/parse_items.txt'
);
// price.xml
// В этом файле мы парсим элементы
$IBLOCK_ID = 10;
CModule::IncludeModule("iblock");
CModule::IncludeModule('search');
Cmodule::IncludeModule('catalog');
$el = new CIBlockElement;
// Выбираем существующие разделы
$addedSections = [];
$rsSect = CIBlockSection::GetList(
['sort' => 'asc'],
["IBLOCK_ID" => $IBLOCK_ID],
false,
["ID", "IBLOCK_ID", "IBLOCK_SECTION_ID", "NAME", "DESCRIPTION", "UF_*"]
);
while ($arSect = $rsSect->GetNext()) {
$addedSections[$arSect["UF_GUID"]] = $arSect["ID"];
}
// Выбираем существующие элементы
$addedElements = [];
$rsElem = CIBlockElement::GetList(
['sort' => 'asc'],
["IBLOCK_ID" => $IBLOCK_ID],
false,
false,
[
"ID",
"PROPERTY_farmItemId",
],
);
while ($arElem = $rsElem->Fetch()) {
$addedElements[$arElem["PROPERTY_FARMITEMID_VALUE"]] = $arElem["ID"];
}
// Заголовки инструкции
$instructionArr = [
"INDICATION" => "Показания",
"CONTRA_INDICATION" => "Противопоказания",
"SPECIAL_INSTRUCTION" => "Особые указания",
"PHARM_ACTION" => "Фармакологическое действие",
"DOSAGE" => "Дозировка",
"INTERACTION" => "Взаимодействие",
"OVER_DOSAGE" => "Передозировка",
"SIDE_EFFECT" => "Побочные действия",
];
$items = simplexml_load_string(file_get_contents($_SERVER["DOCUMENT_ROOT"] . '/efarma/files/price/price/price.xml'));
$i = 0;
$added = 0;
$updated = 0;
$addedErr = 0;
$updatedErr = 0;
$jj = 0;
$step = $argv[1] ? (int) $argv[1] : 1;
$stepCount = 20000;
//$stepCount = 4000;
$itemsCount = count($items->PRICES->priceItems);
$stepUp = false;
function setEfarmePrice($productId, $price, $PRICE_TYPE_ID = 2): void
{
$arFields = [
"PRODUCT_ID" => $productId,
"CATALOG_GROUP_ID" => $PRICE_TYPE_ID,
"PRICE" => $price,
"CURRENCY" => "RUB",
];
$res = CPrice::GetList(
[],
[
"PRODUCT_ID" => $productId,
"CATALOG_GROUP_ID" => $PRICE_TYPE_ID,
]
);
if ($arr = $res->Fetch()) {
CPrice::Update($arr['PRODUCT_ID'], $arFields);
} else {
CPrice::Add($arFields);
}
}
Debug::writeToFile(
'Парсинг на этапе ' . $step . ' начат, элементов - ' . $itemsCount,
date('d.m.Y H:i:s'),
'z_logs/products/parse_items.txt'
);
foreach ($items->PRICES->priceItems as $item) {
$jj++;
//Если элемент не попадает в диапазон шага - пропускаем
if ($jj > $stepCount * $step || $jj <= $stepCount * ($step - 1)) {
continue;
}
Debug::writeToFile(
'Код: ' . $item->goodsCode . ' Название: ' . $item->itemName,
'Обрабатываю товар',
'z_logs/products/parse_items.txt'
);
if ($jj === $stepCount * $step || $jj === $itemsCount) {
if ($jj !== $itemsCount) {
$stepUp = true;
}
}
//Записываем свойства
$farmItemID = "" . $item->farmItemId;
$PROP = [];
$PROP[45] = $farmItemID; // farmItemId
$PROP[46] = $item->esItemId; // esItemId
$PROP[47] = $item->country; // Страна
$PROP[48] = $item->manufName; // Производитель
$PROP[49] = $item->barcode; // Штрих-код
$PROP[50] = $item->INN; // МНН
$PROP[41] = $item->IS_PRESCRIPTION; // рецепт
$PROP[40] = $item->goodsCode; // goodsCode
$PROP[44] = $item->dosage; // Дозировка
$PROP[51] = isset($item->IS_SALE_REMOTE) && (int) $item->IS_SALE_REMOTE == 0 ? 'Нет' : 'Да'; //Доступен для доставки
$ourPred = [];
// Хиты продаж
if ($item->IS_HIT == 1) {
//$ourPred[] = 55;
$PROP[55] = 'Y';
}
//Мы советуем
if ($item->IS_RECOMMENDED == 1) {
//$ourPred[] = 56;
$PROP[56] = 'Y';
}
// Новинки
if ($item->IS_NEWS == 1) {
//$ourPred[] = 57;
$PROP[57] = 'Y';
}
// По акции
if ($item->IS_ACTION_GOODS == 1) {
//$ourPred[] = 54;
$PROP[54] = 'Y';
}
$price = (string) $item->price;
//$PROP[47] = $ourPred;
Debug::writeToFile(
$price,
'Цена Ефарма',
'z_logs/products/parse_items.txt'
);
$vatId = '';
if ($item->taxRate) {
$ob = CCatalogVat::GetList(
[],
['RATE' => $item->taxRate],
[]
);
if ($res = $ob->GetNext()) {
$vatId = $res['ID'];
}
$ob = CCatalogVat::GetList(
['CSORT' => 'ASC'],
['RATE' => $item->taxRate],
[]
);
if ($res = $ob->GetNext()) {
$vatId = $res['ID'];
}
}
// Собираем в массив группы которым принадлежит
$sections = [];
foreach ($item->groups->item as $section) {
$section = "" . $section;
if (array_key_exists($section, $addedSections)) {
$sections[] = $addedSections[$section];
}
}
$arLoadProductArray = [
"MODIFIED_BY" => $USER->GetID(), //элемент изменен текущим пользователем
"IBLOCK_SECTION_ID" => false, //элемент лежит в корне раздела
"IBLOCK_ID" => $IBLOCK_ID,
"PROPERTY_VALUES" => $PROP,
"NAME" => $item->itemName,
"CODE" => CUtil::translit($item->itemName, 'ru', ["replace_space" => "-", "replace_other" => "-"]),
// "ACTIVE" => "Y"
];
//Если элемент не существует добавляем
if (!array_key_exists($farmItemID, $addedElements)) {
Debug::writeToFile(
'Элемент НЕ существует: пытаюсь добавить',
'',
'z_logs/products/parse_items.txt'
);
$arLoadProductArray['ACTIVE'] = 'Y';
if ($PRODUCT_ID = $el->Add($arLoadProductArray)) {
$el->SetElementSection($PRODUCT_ID, $sections);
try {
setEfarmePrice($PRODUCT_ID, $price);
$result = Product::update($PRODUCT_ID, ['VAT_ID' => $vatId, 'VAT_INCLUDED' => 'Y']
);
} catch (Exception $e) {
Debug::dumpToFile(
$e->getMessage(),
'errorAddUpdate. goodsCode: ' . $item->goodsCode,
'z_logs/products/parse_items_error.txt'
);
}
if ($result && $result->isSuccess() && !$result->getAffectedRowsCount()) {
try {
$arFields = ['ID' => $PRODUCT_ID, 'VAT_ID' => $vatId, 'VAT_INCLUDED' => 'Y'];
Product::add(['fields' => $arFields]);
} catch (Exception $e) {
Debug::dumpToFile(
$e->getMessage(),
'errorAddAdd. goodsCode: ' . $item->goodsCode,
'z_logs/products/parse_items_error.txt'
);
}
}
//fwrite($fg, $farmItemID.": Элемент добавлен\r\n");
$added++;
} else {
$addedErr++;
//fwrite($fg, $farmItemID.": ".$el->LAST_ERROR."\r\n");
}
Debug::writeToFile(
'-------------------------------------------------',
$jj . ' Обработка товара завершена',
'z_logs/products/parse_items.txt'
);
//Если элемент существует обновляем
} else {
Debug::writeToFile(
'Элемент существует: пытаюсь обновить',
'',
'z_logs/products/parse_items.txt'
);
if ($el->Update($addedElements[$farmItemID], $arLoadProductArray)) {
$el->SetElementSection($addedElements[$farmItemID], $sections);
try {
setEfarmePrice($addedElements[$farmItemID], $price);
$result = Product::update(
$addedElements[$farmItemID],
['VAT_ID' => $vatId, 'VAT_INCLUDED' => 'Y']
);
} catch (Exception $e) {
Debug::dumpToFile(
$e->getMessage(),
'errorUpdateUpdate. goodsCode: ' . $item->goodsCode,
'z_logs/products/parse_items_error.txt'
);
}
if ($result && $result->isSuccess() && !$result->getAffectedRowsCount()) {
try {
$arFields = ['ID' => $addedElements[$farmItemID], 'VAT_ID' => $vatId, 'VAT_INCLUDED' => 'Y'];
Product::add(['fields' => $arFields]);
} catch (Exception $e) {
Debug::dumpToFile(
$e->getMessage(),
'errorUpdateAdd. goodsCode: ' . $item->goodsCode,
'z_logs/products/parse_items_error.txt'
);
}
}
//fwrite($fg, $farmItemID.": Элемент обновлен\r\n");
$updated++;
} else {
$updatedErr++;
//fwrite($fg, $farmItemID.": ".$el->LAST_ERROR."\r\n")
}
Debug::writeToFile(
'-------------------------------------------------',
$jj . ' Обработка товара завершена',
'z_logs/products/parse_items.txt'
);
}
//if($i==100){break;}
$i++;
}
// Выполняем переиндексацию поиска.
$NS = false;
$NS = CSearch::ReIndexAll(true, 60, $NS);
while (is_array($NS)) {
$NS = CSearch::ReIndexAll(true, 60, $NS);
}
Debug::writeToFile(
'Индексация выполнена на этапе ' . $step,
date('d.m.Y H:i:s'),
'z_logs/products/parse_items.txt'
);
Debug::writeToFile(
'========= ФИНАЛ ' . date('d.m.Y H:i:s') . ' =========',
'',
'z_logs/products/parse_items.txt'
);
Debug::endTimeLabel('parseItemsLabel');
$totalData = "Добавлено: "
. $added
. "\r\nОбновлено: "
. $updated
. "\r\nОшибки добавления: "
. $addedErr
. "\r\nОшибки обновления: "
. $updatedErr;
Debug::writeToFile($totalData, date('d.m.Y H:i:s'), 'z_logs/products/parse_items_total.txt');
Debug::writeToFile(Debug::getTimeLabels(), 'Время выполнения скрипта', 'z_logs/products/parse_items_total.txt');
if ($stepUp) {
$nextStep = $step + 1;
exec('php ' . $_SERVER["DOCUMENT_ROOT"] . '/local/cron/parse_items.php ' . $nextStep);
}
Добавляем скрипт в crontab