diff --git a/CHANGELOG.md b/CHANGELOG.md index f2d98038..292072a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 2021-09-08 v.5.8.1 +* Оптимизирована работа генератора icml каталога +* В генератор каталога добавлена возможность указывать свойства выгрузки одновременно для простых товаров и товаров с торговыми предложениями +* Исправлена ошибка выгрузки заказов из неподключенного к CRM магазина при использовании нескольких сайтов на одной лицензии +* Изменена логика обмена оплатами: для интеграционных оплат дата оплаты больше не передается из Битрикса + ## 2021-08-19 v.5.8.0 * Добавлена синхронизация ответственного менеджера в заказе * Исправлена ошибка выгрузки заказов с корпоративными клиентами, уже присутствующими в системе diff --git a/intaro.retailcrm/description.ru b/intaro.retailcrm/description.ru index 0c64ac49..2edd9465 100644 --- a/intaro.retailcrm/description.ru +++ b/intaro.retailcrm/description.ru @@ -1,3 +1,4 @@ -- Добавлена синхронизация ответственного менеджера в заказе -- Исправлена ошибка выгрузки заказов с корпоративными клиентами, уже присутствующими в системе -- Исправлена ошибка выгрузки остатков при наличии более 100 складов в Битрикс +- Оптимизирована работа генератора icml каталога +- В генератор каталога добавлена возможность указывать свойства выгрузки одновременно для простых товаров и товаров с торговыми предложениями +- Исправлена ошибка выгрузки заказов из неподключенного к CRM магазина при использовании нескольких сайтов на одной лицензии +- Изменена логика обмена оплатами: для интеграционных оплат дата оплаты больше не передается из Битрикса diff --git a/intaro.retailcrm/install/version.php b/intaro.retailcrm/install/version.php index e9cffb04..a2826427 100644 --- a/intaro.retailcrm/install/version.php +++ b/intaro.retailcrm/install/version.php @@ -1,6 +1,6 @@ '5.8.0', - 'VERSION_DATE' => '2021-08-19 16:00:00', + 'VERSION' => '5.8.1', + 'VERSION_DATE' => '2021-09-08 14:00:00', ]; diff --git a/intaro.retailcrm/lib/icml/icmldirector.php b/intaro.retailcrm/lib/icml/icmldirector.php index 17f81ba2..8519d55f 100644 --- a/intaro.retailcrm/lib/icml/icmldirector.php +++ b/intaro.retailcrm/lib/icml/icmldirector.php @@ -23,52 +23,52 @@ class IcmlDirector public const OFFERS_PART = 500; public const FILE_LOG_NAME = 'i_crm_load_log'; public const DEFAULT_PRODUCT_PAGE_SIZE = 1; - + /** * @var IcmlWriter */ private $icmlWriter; - + /** * @var \Intaro\RetailCrm\Icml\XmlOfferDirector */ private $xmlOfferDirector; - + /** * @var \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup */ private $setup; - + /** * @var \Intaro\RetailCrm\Repository\CatalogRepository */ private $catalogRepository; - + /** * @var string */ private $shopName; - + /** * @var \Intaro\RetailCrm\Icml\XmlCategoryDirector */ private $xmlCategoryDirector; - + /** * @var \Intaro\RetailCrm\Icml\QueryParamsMolder */ private $queryBuilder; - + /** * @var \Intaro\RetailCrm\Model\Bitrix\Xml\XmlData */ private $xmlData; - + /** * @var \Logger */ private $logger; - + /** * RetailCrmlXml constructor. * @@ -87,7 +87,7 @@ class IcmlDirector $this->xmlData = new XmlData(); $this->logger = $logger; } - + /** * Основной метод. Генерирует icml файл католога товаров Битрикс */ @@ -115,7 +115,7 @@ class IcmlDirector self::FILE_LOG_NAME ); } - + /** * @return void */ @@ -126,21 +126,21 @@ class IcmlDirector $this->xmlData->filePath = $this->setup->filePath; $this->xmlData->categories = $this->xmlCategoryDirector->getXmlCategories(); } - + /** * записывает оферы всех торговых каталогов в xml файл */ private function writeOffers(): void { $this->icmlWriter->startOffersBlock(); - + foreach ($this->setup->iblocksForExport as $iblockId) { $this->writeIblockOffers($iblockId); } - + $this->icmlWriter->endBlock(); } - + /** * записывает оферы конкретного торгового каталога товаров в xml файл * @@ -149,7 +149,7 @@ class IcmlDirector private function writeIblockOffers(int $productIblockId): void { $catalogIblockInfo = $this->catalogRepository->getCatalogIblockInfo($productIblockId); - + //если нет торговых предложений if ($catalogIblockInfo->skuIblockId === null) { $selectParams @@ -157,20 +157,21 @@ class IcmlDirector $this->setup->properties->products->names[$productIblockId], $this->setup->basePriceId ); - + $selectParams->pageNumber = 1; $selectParams->nPageSize = self::OFFERS_PART; $selectParams->parentId = null; - + $selectParams->allParams = array_merge($selectParams->configurable, $selectParams->main); + while ($xmlOffers = $this->xmlOfferDirector->getXmlOffersPart($selectParams, $catalogIblockInfo)) { $this->icmlWriter->writeOffers($xmlOffers); - + $selectParams->pageNumber++; } - + return; } - + //если есть торговые предложения $paramsForProduct = $this->queryBuilder->getSelectParams( @@ -182,10 +183,10 @@ class IcmlDirector $this->setup->properties->sku->names[$productIblockId], $this->setup->basePriceId ); - + $this->writeOffersAsOffersInXml($paramsForProduct, $paramsForOffer, $catalogIblockInfo); } - + /** * Эта стратегия записи используется, * когда в каталоге есть торговые предложения @@ -201,15 +202,16 @@ class IcmlDirector ): void { $paramsForProduct->pageNumber = 1; $paramsForProduct->nPageSize = $this->calculateProductPageSize(); - + $paramsForProduct->allParams = array_merge($paramsForProduct->configurable, $paramsForProduct->main); + do { $productsPart = $this->xmlOfferDirector->getXmlOffersPart($paramsForProduct, $catalogIblockInfo); $paramsForProduct->pageNumber++; - + $this->writeProductsOffers($productsPart, $paramsForOffer, $catalogIblockInfo); } while (!empty($productsPart)); } - + /** * Записывает в файл оферы всех товаров из $products * @@ -223,12 +225,12 @@ class IcmlDirector CatalogIblockInfo $catalogIblockInfo ): void { $paramsForOffer->nPageSize = $this->calculateOffersPageSize(); - + foreach ($products as $product) { $this->writeProductOffers($paramsForOffer, $catalogIblockInfo, $product); } } - + /** * Записывает оферы отдельного продукта в xml файл * @@ -244,7 +246,8 @@ class IcmlDirector $paramsForOffer->pageNumber = 1; $writingOffersCount = 0; $paramsForOffer->parentId = $product->id; - + $paramsForOffer->allParams = array_merge($paramsForOffer->configurable, $paramsForOffer->main); + do { $xmlOffersPart = $this->xmlOfferDirector->getXmlOffersBySingleProduct($paramsForOffer, $catalogIblockInfo, $product); @@ -254,19 +257,19 @@ class IcmlDirector $this->icmlWriter->writeOffers([$product]); break; } - + if (!empty($xmlOffersPart)) { $xmlOffersPart = $this->trimOffersList($writingOffersCount, $xmlOffersPart); - + $this->icmlWriter->writeOffers($xmlOffersPart); - + $writingOffersCount += count($xmlOffersPart); $paramsForOffer->pageNumber++; } } while ($this->shouldContinueWriting($writingOffersCount, $xmlOffersPart)); } - + /** * Проверяет,не достигнул ли лимит по записываемым оферам maxOffersValue * и обрезает массив до лимита, если он достигнут @@ -283,10 +286,10 @@ class IcmlDirector = count($xmlOffers) - ($writingOffers + count($xmlOffers) - $this->setup->maxOffersValue); return array_slice($xmlOffers, 0, $sliceIndex); } - + return $xmlOffers; } - + /** * Возвращает размер страницы для запроса товаров * @@ -297,10 +300,10 @@ class IcmlDirector if (empty($this->setup->maxOffersValue)) { return self::DEFAULT_PRODUCT_PAGE_SIZE; } - + return (int) ceil(self::OFFERS_PART / $this->setup->maxOffersValue); } - + /** * Возвращает размер страницы для офферов * @@ -311,11 +314,11 @@ class IcmlDirector if (empty($this->setup->maxOffersValue)) { return self::OFFERS_PART; } - + return $this->setup->maxOffersValue < self::OFFERS_PART ? $this->setup->maxOffersValue : self::OFFERS_PART; } - + /** * Проверяет, нужно ли дальше записывать офферы * @@ -329,7 +332,7 @@ class IcmlDirector if (empty($this->setup->maxOffersValue)) { return !empty($xmlOffers); } - + return !empty($xmlOffers) && $writingOffers < $this->setup->maxOffersValue; } } diff --git a/intaro.retailcrm/lib/icml/queryparamsmolder.php b/intaro.retailcrm/lib/icml/queryparamsmolder.php index 81833955..e5775c50 100644 --- a/intaro.retailcrm/lib/icml/queryparamsmolder.php +++ b/intaro.retailcrm/lib/icml/queryparamsmolder.php @@ -21,26 +21,30 @@ class QueryParamsMolder public function getSelectParams(?array $userProps, int $basePriceId): SelectParams { $catalogFields = ['catalog_length', 'catalog_width', 'catalog_height', 'catalog_weight']; - + $params = new SelectParams(); - + foreach ($userProps as $key => $name) { if ($name === '') { unset($userProps[$key]); continue; } - + if (in_array($name, $catalogFields, true)) { $userProps[$key] = strtoupper($userProps[$key]); } else { $userProps[$key] = 'PROPERTY_' . $userProps[$key]; } } - + $params->configurable = $userProps ?? []; $params->main = [ + 'LANG_DIR', + 'CODE', 'IBLOCK_ID', + 'IBLOCK_CODE', 'IBLOCK_SECTION_ID', + 'IBLOCK_EXTERNAL_ID', 'NAME', 'DETAIL_PICTURE', 'PREVIEW_PICTURE', @@ -53,10 +57,10 @@ class QueryParamsMolder 'ID', 'LID', ]; - + return $params; } - + /** * @param int|null $parentId * @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $info @@ -70,7 +74,7 @@ class QueryParamsMolder 'ACTIVE' => 'Y', ]; } - + return [ 'IBLOCK_ID' => $info->skuIblockId, 'ACTIVE' => 'Y', diff --git a/intaro.retailcrm/lib/icml/xmlofferbuilder.php b/intaro.retailcrm/lib/icml/xmlofferbuilder.php index 0d3d2628..c388feac 100644 --- a/intaro.retailcrm/lib/icml/xmlofferbuilder.php +++ b/intaro.retailcrm/lib/icml/xmlofferbuilder.php @@ -27,57 +27,57 @@ class XmlOfferBuilder * @var \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup */ private $setup; - + /** * @var bool|string|null */ private $purchasePriceNull; - + /** * @var array */ private $measures; - + /** * @var string|null */ private $defaultServerName; - + /** * @var array */ private $skuHlParams; - + /** * @var array */ private $productHlParams; - + /** * @var string */ private $productPicture; - + /** * @var \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo */ private $catalogIblockInfo; - + /** * @var array */ private $productProps; - + /** * @var string */ private $barcode; - + /** * @var \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams */ private $selectParams; - + /** * @var \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer */ @@ -86,7 +86,7 @@ class XmlOfferBuilder * @var array */ private $categories; - + /** * IcmlDataManager constructor. * @@ -103,7 +103,7 @@ class XmlOfferBuilder $this->measures = $this->prepareMeasures($measure); $this->defaultServerName = $defaultServerName; } - + /** * @return \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer */ @@ -112,13 +112,13 @@ class XmlOfferBuilder $this->xmlOffer = new XmlOffer(); $this->xmlOffer->barcode = $this->barcode; $this->xmlOffer->picture = $this->productPicture; - + $this->addDataFromParams(); $this->addDataFromItem($this->productProps, $this->categories); - + return $this->xmlOffer; } - + /** * @param array $categories */ @@ -126,7 +126,7 @@ class XmlOfferBuilder { $this->categories = $categories; } - + /** * @param mixed $skuHlParams */ @@ -134,7 +134,7 @@ class XmlOfferBuilder { $this->skuHlParams = $skuHlParams; } - + /** * @param mixed $productHlParams */ @@ -142,7 +142,7 @@ class XmlOfferBuilder { $this->productHlParams = $productHlParams; } - + /** * @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $selectParams */ @@ -150,16 +150,16 @@ class XmlOfferBuilder { $this->selectParams = $selectParams; } - + /** * @param array $productProps */ public function setOfferProps(array $productProps): void { $this->productProps = $productProps; - + } - + /** * @param string $barcode */ @@ -167,7 +167,7 @@ class XmlOfferBuilder { $this->barcode = $barcode; } - + /** * @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo */ @@ -175,7 +175,7 @@ class XmlOfferBuilder { $this->catalogIblockInfo = $catalogIblockInfo; } - + /** * @param string $getProductPicture */ @@ -183,21 +183,21 @@ class XmlOfferBuilder { $this->productPicture = $getProductPicture; } - + /** * Добавляет в XmlOffer значения настраиваемых параметров, производителя, вес и габариты */ private function addDataFromParams(): void { $resultParams = array_merge($this->productHlParams, $this->skuHlParams); - + //достаем значения из обычных свойств $resultParams = array_merge($resultParams, $this->getSimpleParams( $resultParams, $this->selectParams->configurable, $this->productProps )); - + [$resultParams, $this->xmlOffer->dimensions] = $this->extractDimensionsFromParams( $this->setup->properties, @@ -242,7 +242,7 @@ class XmlOfferBuilder $this->xmlOffer->vatRate = $item['CATALOG_VAT'] ?? 'none'; $this->xmlOffer->unitCode = $this->getUnitCode($item['CATALOG_MEASURE'], $item['ID']); } - + /** * Возвращает закупочную цену, если она требуется настройками * @@ -257,15 +257,15 @@ class XmlOfferBuilder if ($product['CATALOG_PURCHASING_PRICE']) { return $product['CATALOG_PURCHASING_PRICE']; } - + if ($purchasePriceNull === 'Y') { return 0; } } - + return null; } - + /** * Возвращает массив обычных свойств * @@ -280,19 +280,19 @@ class XmlOfferBuilder if (isset($resultParams[$key])) { continue; } - + $codeWithValue = $params . '_VALUE'; - + if (isset($productProps[$codeWithValue])) { $resultParams[$key] = $productProps[$codeWithValue]; } elseif (isset($productProps[$params])) { $resultParams[$key] = $productProps[$params]; } } - + return $resultParams; } - + /** * Удаляет параметры с пустыми и нулевыми значениями * @@ -303,7 +303,7 @@ class XmlOfferBuilder { return array_diff($params, ['', 0, '0']); } - + /** * Разделяем вендора и остальные параметры * @@ -313,16 +313,16 @@ class XmlOfferBuilder private function extractVendorFromParams(array $resultParams): array { $vendor = null; - + if (isset($resultParams['manufacturer'])) { $vendor = $resultParams['manufacturer']; - + unset($resultParams['manufacturer']); } - + return [$resultParams, $vendor]; } - + /** * Преобразует вес товара в килограммы для ноды weight * @@ -342,26 +342,26 @@ class XmlOfferBuilder 'kg' => 1, ]; $unit = ''; - + if (!empty($xmlSetupPropsCategories->products->names[$iblockId]['weight'])) { $unit = $xmlSetupPropsCategories->products->units[$iblockId]['weight']; } elseif (!empty($xmlSetupPropsCategories->sku->names[$iblockId]['weight'])) { $unit = $xmlSetupPropsCategories->sku->units[$iblockId]['weight']; } - + if (isset($resultParams['weight'], $factors[$unit])) { $weight = $resultParams['weight'] * $factors[$unit]; } else { $weight = ''; } - + if (isset($resultParams['weight'])) { unset($resultParams['weight']); } - + return [$resultParams, $weight]; } - + /** * Получение данных для ноды dimensions * @@ -385,34 +385,34 @@ class XmlOfferBuilder 'cm' => 1, 'm' => 100, ]; - + foreach ($dimensionsParams as $key => $param) { $unit = ''; - + if (!empty($xmlSetupPropsCategories->products->names[$iblockId][$param])) { $unit = $xmlSetupPropsCategories->products->units[$iblockId][$param]; } elseif (!empty($xmlSetupPropsCategories->sku->names[$iblockId][$param])) { $unit = $xmlSetupPropsCategories->sku->units[$iblockId][$param]; } - + if (isset($factors[$unit], $resultParams[$param])) { $dimensions .= $resultParams[$param] * $factors[$unit]; } else { $dimensions .= '0'; } - + if (count($dimensionsParams) > $key + 1) { $dimensions .= '/'; } - + if (isset($resultParams[$param])) { unset($resultParams[$param]); } } - + return [$resultParams, $dimensions === '0/0/0' ? '' : $dimensions]; } - + /** * Собираем объект параметре заказа * @@ -422,21 +422,21 @@ class XmlOfferBuilder private function createParamObject(array $params): array { $offerParams = []; - + foreach ($params as $code => $value) { $paramName = GetMessage('PARAM_NAME_' . $code); - + if (empty($paramName)) { continue; } - + $offerParam = new OfferParam(); $offerParam->name = $paramName; $offerParam->code = $code; $offerParam->value = $value; $offerParams[] = $offerParam; } - + return $offerParams; } @@ -452,10 +452,10 @@ class XmlOfferBuilder $unit->name = $this->measures[$measureIndex]['MEASURE_TITLE'] ?? ''; $unit->code = $this->measures[$measureIndex]['SYMBOL_INTL'] ?? ''; $unit->sym = $this->measures[$measureIndex]['SYMBOL_RUS'] ?? ''; - + return $unit; } - + /** * Удаляет запрещенные в unit сode символы * @@ -472,10 +472,10 @@ class XmlOfferBuilder $measure['SYMBOL_INTL'] = preg_replace("/[^a-zA-Z_\-]/",'', $measure['SYMBOL_INTL']); } } - + return $measures; } - + /** * @param array $currentMeasure * @@ -489,10 +489,10 @@ class XmlOfferBuilder $unit->name = $clearCurrentMeasure['MEASURE']['MEASURE_TITLE'] ?? ''; $unit->code = $clearCurrentMeasure['MEASURE']['SYMBOL_INTL'] ?? ''; $unit->sym = $clearCurrentMeasure['MEASURE']['SYMBOL_RUS'] ?? ''; - + return $unit; } - + /** * @param int|null $measureId * @param int $itemId @@ -503,18 +503,18 @@ class XmlOfferBuilder { if (isset($measureId) && !empty($measureId)) { return $this->createUnitFromCode($measureId); - } else { - try { - $currentMeasure = ProductTable::getCurrentRatioWithMeasure($itemId); - - if (is_array($currentMeasure)) { - return $this->createUnitFromProductTable($currentMeasure); - } - } catch (ArgumentException $exception) { - Logger::getInstance()->write(GetMessage('UNIT_ERROR'), 'i_crm_load_log'); - } } - + + try { + $currentMeasure = ProductTable::getCurrentRatioWithMeasure($itemId); + + if (is_array($currentMeasure)) { + return $this->createUnitFromProductTable($currentMeasure); + } + } catch (ArgumentException $exception) { + Logger::getInstance()->write(GetMessage('UNIT_ERROR'), 'i_crm_load_log'); + } + return null; } } diff --git a/intaro.retailcrm/lib/icml/xmlofferdirector.php b/intaro.retailcrm/lib/icml/xmlofferdirector.php index 2e49c06e..0baf2996 100644 --- a/intaro.retailcrm/lib/icml/xmlofferdirector.php +++ b/intaro.retailcrm/lib/icml/xmlofferdirector.php @@ -2,6 +2,8 @@ namespace Intaro\RetailCrm\Icml; +use CIBlock; +use CIBlockSection; use Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo; use Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams; use Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer; @@ -22,22 +24,27 @@ class XmlOfferDirector * @var \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup */ private $setup; - + /** * @var \Intaro\RetailCrm\Repository\FileRepository */ private $fileRepository; - + /** * @var \Intaro\RetailCrm\Repository\CatalogRepository */ private $catalogRepository; - + /** * @var \Intaro\RetailCrm\Icml\XmlOfferBuilder */ - private $xmlOfferBuilder; - + private $xmlOfferBuilder; + + /** + * @var array + */ + private $barcodes; + /** * XmlOfferFactory constructor. * @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup $setup @@ -52,8 +59,9 @@ class XmlOfferDirector MeasureRepository::getMeasures(), SiteRepository::getDefaultServerName() ); + $this->barcodes = $this->catalogRepository->getBarcodes(); } - + /** * Возвращает страницу (массив) с товарами или торговыми предложениями (в зависимости от $param) * @@ -64,19 +72,22 @@ class XmlOfferDirector public function getXmlOffersPart(SelectParams $param, CatalogIblockInfo $catalogIblockInfo): array { $ciBlockResult = $this->catalogRepository->getProductPage($param, $catalogIblockInfo); - $barcodes = $this->catalogRepository->getProductBarcodesByIblockId($catalogIblockInfo->productIblockId); $offers = []; - - while ($offer = $ciBlockResult->GetNext()) { - $this->setXmlOfferParams($param, $offer, $catalogIblockInfo, $barcodes); - $this->xmlOfferBuilder->setCategories($this->catalogRepository->getProductCategoriesIds($offer['ID'])); - + + while ($offer = $ciBlockResult->Fetch()) { + $categories = $this->catalogRepository->getProductCategories($offer['ID']); + $offer['DETAIL_PAGE_URL'] = $this->replaceUrlTemplate($offer, $categories); + + $this->setXmlOfferParams($param, $offer, $catalogIblockInfo); + $this->xmlOfferBuilder + ->setCategories(array_column($categories, 'IBLOCK_SECTION_ELEMENT_IBLOCK_SECTION_ID')); + $offers[] = $this->xmlOfferBuilder->build(); } - + return $offers; } - + /** * возвращает массив XmlOffers для конкретного продукта * @@ -91,10 +102,10 @@ class XmlOfferDirector XmlOffer $product ): array { $xmlOffers = $this->getXmlOffersPart($paramsForOffer, $catalogIblockInfo); - + return $this->addProductInfo($xmlOffers, $product); } - + /** * Декорирует оферы информацией из товаров * @@ -113,13 +124,15 @@ class XmlOfferDirector $offer->picture = $offer->mergeValues($product->picture, $offer->picture); $offer->weight = $offer->mergeValues($product->weight, $offer->weight); $offer->dimensions = $offer->mergeValues($product->dimensions, $offer->dimensions); + $offer->barcode = $offer->mergeValues($product->barcode, $offer->barcode); $offer->categoryIds = $product->categoryIds; $offer->productName = $product->productName; + $offer->url = $this->mergeUrls($product->url, $offer->url); } - + return $xmlOffers; } - + /** * Получение настраиваемых параметров, если они лежат в HL-блоке * @@ -132,23 +145,23 @@ class XmlOfferDirector private function getHlParams(int $iblockId, array $productProps, array $configurableParams, array $hls): array { $params = []; - + foreach ($hls as $hlName => $hlBlockProduct) { if (isset($hlBlockProduct[$iblockId])) { reset($hlBlockProduct[$iblockId]); $firstKey = key($hlBlockProduct[$iblockId]); $hlRepository = new HlRepository($hlName); - + if ($hlRepository->getHl() === null) { continue; } $result = $hlRepository->getDataByXmlId($productProps[$configurableParams[$firstKey] . '_VALUE']); - + if ($result === null) { continue; } - + foreach ($hlBlockProduct[$iblockId] as $hlPropCodeKey => $hlPropCode) { if (isset($result[$hlPropCode])) { $params[$hlPropCodeKey] = $result[$hlPropCode]; @@ -156,28 +169,26 @@ class XmlOfferDirector } } } - + return $params; } - + /** * @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $param * @param array $product * @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo - * @param array $barcodes */ private function setXmlOfferParams( SelectParams $param, array $product, - CatalogIblockInfo $catalogIblockInfo, - array $barcodes + CatalogIblockInfo $catalogIblockInfo ): void { if ($param->parentId === null) { $pictureProperty = $this->setup->properties->products->pictures[$catalogIblockInfo->productIblockId]; } else { $pictureProperty = $this->setup->properties->sku->pictures[$catalogIblockInfo->productIblockId]; } - + //достаем значения из HL блоков товаров $this->xmlOfferBuilder->setProductHlParams($this->getHlParams( $catalogIblockInfo->productIblockId, @@ -185,7 +196,7 @@ class XmlOfferDirector $param->configurable, $this->setup->properties->highloadblockProduct )); - + //достаем значения из HL блоков торговых предложений $this->xmlOfferBuilder->setSkuHlParams($this->getHlParams( $catalogIblockInfo->productIblockId, @@ -195,7 +206,7 @@ class XmlOfferDirector )); $this->xmlOfferBuilder->setSelectParams($param); $this->xmlOfferBuilder->setOfferProps($product); - $this->xmlOfferBuilder->setBarcode($barcodes[$product['ID']] ?? ''); + $this->xmlOfferBuilder->setBarcode($this->barcodes[$product['ID']] ?? ''); $this->xmlOfferBuilder->setCatalogIblockInfo($catalogIblockInfo); $this->xmlOfferBuilder->setPicturesPath( $this @@ -203,7 +214,94 @@ class XmlOfferDirector ->getProductPicture($product, $pictureProperty ?? '') ); } - + + /** + * @param array $offer + * @param array $categories + * + * @return string + */ + private function replaceUrlTemplate(array $offer, array $categories): string + { + if (strpos($offer['DETAIL_PAGE_URL'], '#PRODUCT_URL#')) { + return $offer['DETAIL_PAGE_URL']; + } + + $replaceableUrlParts = [ + '#SITE_DIR#'=> 'LANG_DIR', + '#ID#' => 'ID', + '#CODE#' => 'CODE', + '#EXTERNAL_ID#' => 'EXTERNAL_ID', + '#IBLOCK_TYPE_ID#' => 'IBLOCK_TYPE_ID', + '#IBLOCK_ID#' => 'IBLOCK_ID', + '#IBLOCK_CODE#' => 'IBLOCK_CODE', + '#IBLOCK_EXTERNAL_ID#' => 'IBLOCK_EXTERNAL_ID', + '#ELEMENT_ID#' => 'ID', + '#ELEMENT_CODE#' => 'CODE', + ]; + + $resultUrl = $offer['DETAIL_PAGE_URL']; + + foreach ($replaceableUrlParts as $key => $replaceableUrlPart) { + if (isset($offer[$replaceableUrlPart])) { + $resultUrl = str_replace($key, $offer[$replaceableUrlPart], $resultUrl); + } + } + + if ( + isset($categories[0]['IBLOCK_SECTION_ELEMENT_IBLOCK_SECTION_ID']) + && strpos($offer['DETAIL_PAGE_URL'], '#SECTION_ID#') !== false + ) { + $resultUrl = str_replace( + '#SECTION_ID#', + $categories[0]['IBLOCK_SECTION_ELEMENT_IBLOCK_SECTION_ID'], + $resultUrl + ); + } + + if ( + isset($categories[0]['IBLOCK_SECTION_ELEMENT_IBLOCK_SECTION_CODE']) + && strpos($offer['DETAIL_PAGE_URL'], '#SECTION_CODE#') !== false + ) { + $resultUrl = str_replace( + '#SECTION_CODE#', + $categories[0]['IBLOCK_SECTION_ELEMENT_IBLOCK_SECTION_CODE'], + $resultUrl + ); + } + + if ( + isset( + $categories[0]['IBLOCK_SECTION_ELEMENT_IBLOCK_SECTION_CODE'], + $categories[0]['IBLOCK_SECTION_ELEMENT_IBLOCK_SECTION_ID'] + ) + && strpos($offer['DETAIL_PAGE_URL'], '#SECTION_CODE_PATH#') !== false + ) { + $resultUrl = str_replace( + '#SECTION_CODE_PATH#', + CIBlockSection::getSectionCodePath($categories[0]['IBLOCK_SECTION_ELEMENT_IBLOCK_SECTION_ID']), + $resultUrl + ); + } + + return str_replace('//', '/', $resultUrl); + } + + /** + * @param string $productUrl + * @param string $offerUrl + * + * @return string + */ + private function mergeUrls(string $productUrl, string $offerUrl): string + { + if (strpos($offerUrl, '#PRODUCT_URL#') !== false) { + return $productUrl; + } + + return $offerUrl; + } + /** * @param array $offerParams * @param array $productParams @@ -211,7 +309,7 @@ class XmlOfferDirector private function mergeParams(array $offerParams, array $productParams): array { $offerCodes = []; - + /** @var \Intaro\RetailCrm\Model\Bitrix\Xml\OfferParam $offerParam */ foreach ($offerParams as $offerParam) { $offerCodes[] = $offerParam->code; @@ -222,10 +320,10 @@ class XmlOfferDirector if (in_array($productParam->code, $offerCodes, true)) { continue; } - + $offerParams[] = $productParam; } - + return $offerParams; } } diff --git a/intaro.retailcrm/lib/model/bitrix/xml/selectparams.php b/intaro.retailcrm/lib/model/bitrix/xml/selectparams.php index f807af46..22a9f7ea 100644 --- a/intaro.retailcrm/lib/model/bitrix/xml/selectparams.php +++ b/intaro.retailcrm/lib/model/bitrix/xml/selectparams.php @@ -23,14 +23,14 @@ class SelectParams * @var array */ public $configurable; - + /** * обязательные свойства * * @var array */ public $main; - + /** * номер запрашиваемой страницы * @@ -44,11 +44,16 @@ class SelectParams * @var int */ public $nPageSize; - + /** * id товара у торогового предложения, если запрашивается SKU * * @var int */ public $parentId; + + /** + * @var array + */ + public $allParams; } diff --git a/intaro.retailcrm/lib/repository/catalogrepository.php b/intaro.retailcrm/lib/repository/catalogrepository.php index 3c6f26a2..e07a044d 100644 --- a/intaro.retailcrm/lib/repository/catalogrepository.php +++ b/intaro.retailcrm/lib/repository/catalogrepository.php @@ -2,7 +2,9 @@ namespace Intaro\RetailCrm\Repository; +use Bitrix\Catalog\StoreBarcodeTable; use Bitrix\Iblock\IblockTable; +use Bitrix\Iblock\SectionElementTable; use Bitrix\Iblock\SectionTable; use Bitrix\Main\ArgumentException; use Bitrix\Main\ObjectPropertyException; @@ -28,7 +30,7 @@ class CatalogRepository * @var \Intaro\RetailCrm\Icml\QueryParamsMolder */ private $builder; - + /** * CatalogRepository constructor. */ @@ -36,52 +38,53 @@ class CatalogRepository { $this->builder = new QueryParamsMolder(); } - + /** * Получение категорий, к которым относится товар * * @param int $offerId * @return array */ - public function getProductCategoriesIds(int $offerId): array + public function getProductCategories(int $offerId): array { - $query = CIBlockElement::GetElementGroups($offerId, false, ['ID']); - $ids = []; - - while ($category = $query->GetNext()) { - $ids[] = $category['ID']; + try { + $categories = SectionElementTable::query() + ->addSelect('IBLOCK_SECTION.ID') + ->addSelect('IBLOCK_SECTION.CODE') + ->where('IBLOCK_ELEMENT_ID', $offerId) + ->fetchAll(); + } catch (ObjectPropertyException | ArgumentException | SystemException $exception) { + return []; } - - return $ids; + + return $categories; } - + /** * Returns products IDs with barcodes by infoblock id * - * @param int $iblockId - * * @return array */ - public function getProductBarcodesByIblockId(int $iblockId): array + public function getBarcodes(): array { $barcodes = []; - $dbBarCode = CCatalogStoreBarCode::getList( - [], - ['IBLOCK_ID' => $iblockId], - false, - false, - ['PRODUCT_ID', 'BARCODE'] - ); - - while ($arBarCode = $dbBarCode->GetNext()) { - if (!empty($arBarCode)) { - $barcodes[$arBarCode['PRODUCT_ID']] = $arBarCode['BARCODE']; - } + + try { + $arBarCodes = StoreBarcodeTable::query() + ->addSelect('PRODUCT_ID') + ->addSelect('BARCODE') + ->fetchAll(); + } catch (ObjectPropertyException | ArgumentException | SystemException $exception) { + return []; } - + + foreach ($arBarCodes as $arBarCode){ + $barcodes[$arBarCode['PRODUCT_ID']] = $arBarCode['BARCODE']; + } + return $barcodes; } - + /** * @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $param * @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo @@ -94,10 +97,10 @@ class CatalogRepository $this->builder->getWhereForOfferPart($param->parentId, $catalogIblockInfo), false, ['nPageSize' => $param->nPageSize, 'iNumPage' => $param->pageNumber, 'checkOutOfRange' => true], - array_merge($param->configurable, $param->main) + $param->allParams ); } - + /** * @param int $iblockId * @return \Bitrix\Main\ORM\Objectify\Collection|null @@ -113,7 +116,7 @@ class CatalogRepository return null; } } - + /** * @param $iblockId * @return EntityObject|null @@ -128,7 +131,7 @@ class CatalogRepository return null; } } - + /** * Возвращает информацию об инфоблоке торговых предложений по ID инфоблока товаров * @@ -139,20 +142,20 @@ class CatalogRepository { $catalogIblockInfo = new CatalogIblockInfo(); $info = CCatalogSKU::GetInfoByProductIBlock($productIblockId); - + if ($info === false) { $catalogIblockInfo->productIblockId = $productIblockId; - + return $catalogIblockInfo; } - + $catalogIblockInfo->skuIblockId = $info['IBLOCK_ID']; $catalogIblockInfo->productIblockId = $info['PRODUCT_IBLOCK_ID']; $catalogIblockInfo->skuPropertyId = $info['SKU_PROPERTY_ID']; - + return $catalogIblockInfo; } - + /** * @param int|null $profileId * @return int @@ -160,7 +163,7 @@ class CatalogRepository public static function getBasePriceId(?int $profileId): int { $basePriceId = RetailcrmConfigProvider::getCatalogBasePriceByProfile($profileId); - + if (!$basePriceId) { $dbPriceType = CCatalogGroup::GetList( [], @@ -169,11 +172,11 @@ class CatalogRepository false, ['ID'] ); - + $result = $dbPriceType->GetNext(); return $result['ID']; } - + return $basePriceId; } } diff --git a/intaro.retailcrm/lib/repository/measurerepository.php b/intaro.retailcrm/lib/repository/measurerepository.php index f268423b..7958d467 100644 --- a/intaro.retailcrm/lib/repository/measurerepository.php +++ b/intaro.retailcrm/lib/repository/measurerepository.php @@ -2,7 +2,10 @@ namespace Intaro\RetailCrm\Repository; -use CCatalogMeasure; +use Bitrix\Catalog\MeasureTable; +use Bitrix\Main\ArgumentException; +use Bitrix\Main\ObjectPropertyException; +use Bitrix\Main\SystemException; /** * Class MeasureRepository @@ -18,12 +21,22 @@ class MeasureRepository public static function getMeasures(): array { $measures = []; - $resMeasure = CCatalogMeasure::getList(); - - while ($measure = $resMeasure->Fetch()) { - $measures[$measure['ID']] = $measure; + + try { + $resMeasures = MeasureTable::query() + ->addSelect('ID') + ->addSelect('MEASURE_TITLE') + ->addSelect('SYMBOL_INTL') + ->addSelect('SYMBOL') + ->fetchAll(); + } catch (ObjectPropertyException | ArgumentException | SystemException $exception) { + return []; } - + + foreach ($resMeasures as $resMeasure) { + $measures[$resMeasure['ID']] = $resMeasure; + } + return $measures; } }