1
0
mirror of synced 2024-12-12 07:06:04 +03:00
bitrix-module/intaro.retailcrm/lib/icml/xmlofferbuilder.php

626 lines
18 KiB
PHP
Raw Normal View History

2021-05-31 16:33:02 +03:00
<?php
namespace Intaro\RetailCrm\Icml;
use Bitrix\Catalog\ProductTable;
use Bitrix\Highloadblock\HighloadBlockTable;
use Bitrix\Iblock;
2021-05-31 16:33:02 +03:00
use Bitrix\Main\ArgumentException;
use Bitrix\Main\Entity;
use Bitrix\Main\Loader;
use Bitrix\Main\UserField\Internal\UserFieldHelper;
2021-05-31 16:33:02 +03:00
use Intaro\RetailCrm\Icml\Utils\IcmlUtils;
use Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo;
use Intaro\RetailCrm\Model\Bitrix\Xml\OfferParam;
use Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams;
use Intaro\RetailCrm\Model\Bitrix\Xml\Unit;
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer;
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup;
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupPropsCategories;
use Logger;
use RetailcrmConfigProvider;
/**
* Отвечает за создание XMLOffer
*
* Class XmlOfferBuilder
* @package Intaro\RetailCrm\Icml
*/
class XmlOfferBuilder
{
/**
* @var \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup
*/
private $setup;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var bool|string|null
*/
private $purchasePriceNull;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var array
*/
private $measures;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var string|null
*/
private $serverName;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var array
*/
private $skuHlParams;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var array
*/
private $productHlParams;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var string
*/
private $productPicture;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo
*/
private $catalogIblockInfo;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var array
*/
private $productProps;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var string
*/
private $barcode;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams
*/
private $selectParams;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @var \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer
*/
private $xmlOffer;
2021-05-31 16:33:02 +03:00
/**
* @var array
*/
private $categories;
2021-09-08 16:31:17 +03:00
/**
* @var array
*/
private $vatRates;
/**
* @var SettingsService
*/
private $settingsService;
2021-05-31 16:33:02 +03:00
/**
* IcmlDataManager constructor.
*
* XmlOfferBuilder constructor.
*
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup $setup
* @param array $measure
* @param string|null $serverName
2021-05-31 16:33:02 +03:00
*/
public function __construct(XmlSetup $setup, array $measure, ?string $serverName)
2021-05-31 16:33:02 +03:00
{
$this->setup = $setup;
$this->setSettingsService();
2021-05-31 16:33:02 +03:00
$this->purchasePriceNull = RetailcrmConfigProvider::getCrmPurchasePrice();
$this->vatRates = $this->settingsService->vatRates;
2021-05-31 16:33:02 +03:00
$this->measures = $this->prepareMeasures($measure);
$this->serverName = $serverName;
Loader::includeModule("highloadblock");
Loader::includeModule('iblock');
Loader::includeModule('catalog');
2021-05-31 16:33:02 +03:00
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @return \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer
*/
public function build(): XmlOffer
{
$this->xmlOffer = new XmlOffer();
$this->xmlOffer->barcode = $this->barcode;
$this->xmlOffer->picture = $this->productPicture;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
$this->addDataFromParams();
$this->addDataFromItem($this->productProps, $this->categories);
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return $this->xmlOffer;
}
2021-09-08 16:31:17 +03:00
private function setSettingsService(): void
{
global $PROFILE_ID;
$this->settingsService = SettingsService::getInstance([], '', $PROFILE_ID);
}
2021-05-31 16:33:02 +03:00
/**
* @param array $categories
*/
public function setCategories(array $categories)
{
$this->categories = $categories;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @param mixed $skuHlParams
*/
public function setSkuHlParams($skuHlParams): void
{
$this->skuHlParams = $skuHlParams;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @param mixed $productHlParams
*/
public function setProductHlParams($productHlParams): void
{
$this->productHlParams = $productHlParams;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $selectParams
*/
public function setSelectParams(SelectParams $selectParams): void
{
$this->selectParams = $selectParams;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @param array $productProps
*/
public function setOfferProps(array $productProps): void
{
$this->productProps = $productProps;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @param string $barcode
*/
public function setBarcode(string $barcode): void
{
$this->barcode = $barcode;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo
*/
public function setCatalogIblockInfo(CatalogIblockInfo $catalogIblockInfo): void
{
$this->catalogIblockInfo = $catalogIblockInfo;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @param string $getProductPicture
*/
public function setPicturesPath(string $getProductPicture): void
{
$this->productPicture = $getProductPicture;
}
2021-09-08 16:31:17 +03:00
public function setServerName(string $serverName): void
{
$this->serverName = $serverName;
}
2021-05-31 16:33:02 +03:00
/**
* Добавляет в XmlOffer значения настраиваемых параметров, производителя, вес и габариты
*/
private function addDataFromParams(): void
{
$resultParams = array_merge($this->productHlParams, $this->skuHlParams);
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
//достаем значения из обычных свойств
$resultParams = array_merge($resultParams, $this->getSimpleParams(
$resultParams,
$this->selectParams->configurable,
$this->productProps
));
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
[$resultParams, $this->xmlOffer->dimensions]
= $this->extractDimensionsFromParams(
$this->setup->properties,
$resultParams,
$this->catalogIblockInfo->productIblockId
);
[$resultParams, $this->xmlOffer->weight]
= $this->extractWeightFromParams(
$this->setup->properties,
$resultParams,
$this->catalogIblockInfo->productIblockId
);
[$resultParams, $this->xmlOffer->vendor] = $this->extractVendorFromParams($resultParams);
$resultParams = $this->dropEmptyParams($resultParams);
$this->xmlOffer->params = $this->createParamObject($resultParams);
}
/**
* Добавляет в объект XmlOffer информацию из GetList
*
* @param array $item
* @param array $categoryIds
*/
private function addDataFromItem(array $item, array $categoryIds): void
{
$this->xmlOffer->id = $item['ID'];
$this->xmlOffer->productId = $item['ID'];
$this->xmlOffer->productType = (int) $item['CATALOG_TYPE'];
2021-05-31 16:33:02 +03:00
$this->xmlOffer->quantity = $item['CATALOG_QUANTITY'] ?? '';
$this->xmlOffer->url = $item['DETAIL_PAGE_URL']
? $this->serverName . $item['DETAIL_PAGE_URL']
2021-05-31 16:33:02 +03:00
: '';
$this->xmlOffer->price = $item['CATALOG_PRICE_' . $this->setup->basePriceId];
$this->xmlOffer->purchasePrice = $this->getPurchasePrice(
$item,
$this->setup->loadPurchasePrice,
$this->purchasePriceNull
);
$this->xmlOffer->categoryIds = $categoryIds;
$this->xmlOffer->name = $item['NAME'];
$this->xmlOffer->xmlId = $item['EXTERNAL_ID'] ?? '';
$this->xmlOffer->productName = $item['NAME'];
$this->xmlOffer->vatRate = $this->getVatRate($item);
2021-05-31 16:33:02 +03:00
$this->xmlOffer->unitCode = $this->getUnitCode($item['CATALOG_MEASURE'], $item['ID']);
$this->xmlOffer->activity = $item['ACTIVE'];
$this->xmlOffer->markable = $this->isMarkableOffer($item['ID']);
2021-05-31 16:33:02 +03:00
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* Возвращает закупочную цену, если она требуется настройками
*
* @param array $product
* @param bool|null $isLoadPrice
* @param string $purchasePriceNull
2021-11-02 11:23:42 +03:00
* @return float|null
2021-05-31 16:33:02 +03:00
*/
2021-11-02 11:23:42 +03:00
private function getPurchasePrice(array $product, ?bool $isLoadPrice, string $purchasePriceNull): ?float
2021-05-31 16:33:02 +03:00
{
if ($isLoadPrice) {
if ($product['CATALOG_PURCHASING_PRICE']) {
return $product['CATALOG_PURCHASING_PRICE'];
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
if ($purchasePriceNull === 'Y') {
return 0;
}
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return null;
}
2021-09-08 16:31:17 +03:00
/**
* Возвращает значение активной ставки НДС, если она указана в товаре
*
* @param array $product
* @return string
*/
private function getVatRate(array $product): string
{
if (
!empty($product['VAT_ID'])
&& array_key_exists($product['VAT_ID'], $this->vatRates)
&& is_string($this->vatRates[$product['VAT_ID']]['RATE'])
) {
return $this->vatRates[$product['VAT_ID']]['RATE'];
}
if (
!empty($product['CATALOG_VAT_ID'])
&& array_key_exists($product['CATALOG_VAT_ID'], $this->vatRates)
&& is_string($this->vatRates[$product['CATALOG_VAT_ID']]['RATE'])
) {
return $this->vatRates[$product['CATALOG_VAT_ID']]['RATE'];
}
return 'none';
}
2021-05-31 16:33:02 +03:00
/**
* Возвращает массив обычных свойств
*
* @param array $resultParams
* @param array $configurableParams
* @param array $productProps
* @return array
*/
private function getSimpleParams(array $resultParams, array $configurableParams, array $productProps): array
{
foreach ($configurableParams as $key => $params) {
if (isset($resultParams[$key])) {
continue;
}
2021-09-08 16:31:17 +03:00
$codeWithValue = strtoupper($params) . '_VALUE';
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
if (isset($productProps[$codeWithValue])) {
$resultParams[$key] = $productProps[$codeWithValue];
} elseif (isset($productProps[$params])) {
$resultParams[$key] = $productProps[$params];
}
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return $resultParams;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* Удаляет параметры с пустыми и нулевыми значениями
*
* @param array $params
* @return array
*/
private function dropEmptyParams(array $params): array
{
return array_diff($params, ['', 0, '0']);
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* Разделяем вендора и остальные параметры
*
* @param array $resultParams
* @return array
*/
private function extractVendorFromParams(array $resultParams): array
{
$vendor = null;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
if (isset($resultParams['manufacturer'])) {
$vendor = $resultParams['manufacturer'];
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
unset($resultParams['manufacturer']);
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return [$resultParams, $vendor];
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* Преобразует вес товара в килограммы для ноды weight
*
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupPropsCategories $xmlSetupPropsCategories
* @param array $resultParams
* @param int $iblockId
* @return array
*/
private function extractWeightFromParams(
XmlSetupPropsCategories $xmlSetupPropsCategories,
array $resultParams,
int $iblockId
): array {
$factors = [
'mg' => 0.000001,
'g' => 0.001,
'kg' => 1,
];
$unit = '';
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
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'];
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
if (isset($resultParams['weight'], $factors[$unit])) {
$weight = $resultParams['weight'] * $factors[$unit];
} else {
$weight = '';
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
if (isset($resultParams['weight'])) {
unset($resultParams['weight']);
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return [$resultParams, $weight];
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* Получение данных для ноды dimensions
*
* Данные должны быть переведены в сантиметры
* и представлены в формате Длина/Ширина/Высота
*
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupPropsCategories $xmlSetupPropsCategories
* @param array $resultParams
* @param int $iblockId
* @return array
*/
private function extractDimensionsFromParams(
XmlSetupPropsCategories $xmlSetupPropsCategories,
array $resultParams,
int $iblockId
): array {
$dimensionsParams = ['length', 'width', 'height'];
$dimensions = '';
$factors = [
'mm' => 0.1,
'cm' => 1,
'm' => 100,
];
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
foreach ($dimensionsParams as $key => $param) {
$unit = '';
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
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];
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
if (isset($factors[$unit], $resultParams[$param])) {
$dimensions .= $resultParams[$param] * $factors[$unit];
} else {
$dimensions .= '0';
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
if (count($dimensionsParams) > $key + 1) {
$dimensions .= '/';
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
if (isset($resultParams[$param])) {
unset($resultParams[$param]);
}
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return [$resultParams, $dimensions === '0/0/0' ? '' : $dimensions];
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* Собираем объект параметре заказа
*
* @param array $params
* @return OfferParam[]
*/
private function createParamObject(array $params): array
{
$offerParams = [];
$names = $this->settingsService->actualPropList;
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
foreach ($params as $code => $value) {
2021-09-08 16:31:17 +03:00
if (!isset($names[$code])) {
2021-05-31 16:33:02 +03:00
continue;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
$offerParam = new OfferParam();
$offerParam->name = $names[$code];
2021-05-31 16:33:02 +03:00
$offerParam->code = $code;
$offerParam->value = $value;
$offerParams[] = $offerParam;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return $offerParams;
}
/**
* Собираем объект единицы измерения для товара
*
* @param int $measureIndex
* @return \Intaro\RetailCrm\Model\Bitrix\Xml\Unit
*/
private function createUnitFromCode(int $measureIndex): Unit
{
$unit = new Unit();
$unit->name = $this->measures[$measureIndex]['MEASURE_TITLE'] ?? '';
$unit->code = $this->measures[$measureIndex]['SYMBOL_INTL'] ?? '';
$unit->sym = $this->measures[$measureIndex]['SYMBOL_RUS'] ?? '';
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return $unit;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* Удаляет запрещенные в unit сode символы
*
* @link https://docs.retailcrm.ru/Developers/modules/ICML
*
* @param array $measures
*
* @return array
*/
private function prepareMeasures(array $measures): array
{
foreach ($measures as &$measure) {
if (isset($measure['SYMBOL_INTL'])) {
$measure['SYMBOL_INTL'] = preg_replace("/[^a-zA-Z_\-]/",'', $measure['SYMBOL_INTL']);
}
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return $measures;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @param array $currentMeasure
*
* @return \Intaro\RetailCrm\Model\Bitrix\Xml\Unit
*/
private function createUnitFromProductTable(array $currentMeasure): Unit
{
$clearCurrentMeasure = $this->prepareMeasures(array_shift($currentMeasure));
$unit = new Unit();
$unit->name = $clearCurrentMeasure['MEASURE']['MEASURE_TITLE'] ?? '';
$unit->code = $clearCurrentMeasure['MEASURE']['SYMBOL_INTL'] ?? '';
$unit->sym = $clearCurrentMeasure['MEASURE']['SYMBOL_RUS'] ?? '';
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return $unit;
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
/**
* @param int|null $measureId
* @param int $itemId
*
* @return \Intaro\RetailCrm\Model\Bitrix\Xml\Unit|null
*/
private function getUnitCode(?int $measureId, int $itemId): ?Unit
{
if (isset($measureId) && !empty($measureId)) {
return $this->createUnitFromCode($measureId);
2021-09-08 16:31:17 +03:00
}
try {
$currentMeasure = ProductTable::getCurrentRatioWithMeasure($itemId);
if (is_array($currentMeasure)) {
return $this->createUnitFromProductTable($currentMeasure);
2021-05-31 16:33:02 +03:00
}
2021-09-08 16:31:17 +03:00
} catch (ArgumentException $exception) {
Logger::getInstance()->write(GetMessage('UNIT_ERROR'), 'i_crm_load_log');
2021-05-31 16:33:02 +03:00
}
2021-09-08 16:31:17 +03:00
2021-05-31 16:33:02 +03:00
return null;
}
/**
* Метод для проверки можно ли маркировать товар.
*
* @param $offerId
*
* @return string|null
*/
private function isMarkableOffer($offerId): ?string
{
$idHlBlock = $this->getHighloadBlockIdByName('ProductMarkingCodeGroup');
$hlBlock = HighloadBlockTable::getById($idHlBlock)->fetch();
$hlBlockData = HighloadBlockTable::compileEntity($hlBlock)->getDataClass();
$userFieldManager = UserFieldHelper::getInstance()->getManager();
$userFieldsData = $userFieldManager->GetUserFields(ProductTable::getUfId(), $offerId);
$ufProductGroup = $userFieldsData['UF_PRODUCT_GROUP']['VALUE'] ?? null;
$isMarkableOffer = null;
if ($ufProductGroup !== null) {
$productGroup = $hlBlockData::getList(["select" => ["UF_NAME"], "filter" => ['ID' => $ufProductGroup]]);
$isMarkableOffer = !empty($productGroup->Fetch()['UF_NAME']) ? 'Y' : 'N';
}
return $isMarkableOffer;
}
/**
* Метод для получения ID Highload-блока по названию блока.
*
* Таблица в БД - b_hlsys_marking_code_group
* По умолчанию ID Highload-блока ProductMarkingCodeGroup - 1.
*
* @param $blockName
*
* @return mixed|null
*/
private function getHighloadBlockIdByName($blockName)
{
$hlBlock = HighloadBlockTable::getList(['filter' => ['NAME' => $blockName], 'select' => ['ID']])->fetch();
return $hlBlock['ID'] ?? 1;
}
2021-05-31 16:33:02 +03:00
}