New ICML generator
This commit is contained in:
parent
16a1a5e9d8
commit
47e6de9d94
40 changed files with 3010 additions and 117 deletions
|
@ -1,3 +1,10 @@
|
|||
## 2021-05-31 v.5.7.0
|
||||
* Переработан генератор ICML каталога:
|
||||
- генератор использует потоковую запись в файл через `XMLWriter`;
|
||||
- по умолчанию опция выгрузки каталога в момент установки модуля отключена;
|
||||
- код генератора каталога теперь использует автолоадер Битрикса.
|
||||
* Скидка на позицию больше не учитывается в заказе при установке произвольной цены для позиции.
|
||||
|
||||
## 2021-01-14 v.5.6.2
|
||||
* Исправлено формирование картинок в ICML при включеном CDN
|
||||
* Убрана некорректная запись внешнего идентификатора платежа для новых платежей по истории
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
- Исправлено формирование картинок в ICML при включеном CDN
|
||||
- Убрана некорректная запись внешнего идентификатора платежа для новых платежей по истории
|
||||
- Добавлена проверка на длину email при отправке в систему
|
||||
- Переработан генератор ICML каталога;
|
||||
- Скидка на позицию больше не учитывается в заказе при установке произвольной цены для позиции.
|
|
@ -1,59 +1,65 @@
|
|||
<?php
|
||||
if (file_exists($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/export_run.php")){
|
||||
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/export_run.php");
|
||||
|
||||
use Bitrix\Highloadblock\HighloadBlockTable;
|
||||
use Intaro\RetailCrm\Icml\IcmlDirector;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupProps;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupPropsCategories;
|
||||
use Intaro\RetailCrm\Repository\CatalogRepository;
|
||||
|
||||
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/retailcrm/export_run.php')) {
|
||||
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/php_interface/retailcrm/export_run.php');
|
||||
} else {
|
||||
ignore_user_abort(true);
|
||||
set_time_limit(0);
|
||||
|
||||
global $APPLICATION;
|
||||
if (!CModule::IncludeModule("iblock")){
|
||||
return;
|
||||
}
|
||||
if (!CModule::IncludeModule("catalog")){
|
||||
return;
|
||||
}
|
||||
if (!CModule::IncludeModule("intaro.retailcrm")){
|
||||
return;
|
||||
}
|
||||
|
||||
$rsSites = CSite::GetList($by, $sort, array('ACTIVE' => 'Y'));
|
||||
while ($ar = $rsSites->Fetch()) {
|
||||
if ($ar['DEF'] == 'Y') {
|
||||
$SERVER_NAME = $ar['SERVER_NAME'];
|
||||
}
|
||||
if (
|
||||
!CModule::IncludeModule('iblock')
|
||||
|| !CModule::IncludeModule('catalog')
|
||||
|| !CModule::IncludeModule('intaro.retailcrm')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$hlblockModule = false;
|
||||
|
||||
if (CModule::IncludeModule('highloadblock')) {
|
||||
$hlblockModule = true;
|
||||
$hlblockList = array();
|
||||
$hlblockListDb = \Bitrix\Highloadblock\HighloadBlockTable::getList();
|
||||
$hlblockList = [];
|
||||
$hlblockListDb = HighloadBlockTable::getList();
|
||||
|
||||
while ($hlblockArr = $hlblockListDb->Fetch()) {
|
||||
$hlblockList[$hlblockArr["TABLE_NAME"]] = $hlblockArr;
|
||||
}
|
||||
}
|
||||
|
||||
$iblockProperties = array(
|
||||
"article" => "article",
|
||||
"manufacturer" => "manufacturer",
|
||||
"color" =>"color",
|
||||
"weight" => "weight",
|
||||
"size" => "size",
|
||||
"length" => "length",
|
||||
"width" => "width",
|
||||
"height" => "height",
|
||||
);
|
||||
$IBLOCK_PROPERTY_SKU = array();
|
||||
$IBLOCK_PROPERTY_SKU_HIGHLOADBLOCK = array();
|
||||
$IBLOCK_PROPERTY_UNIT_SKU = array();
|
||||
$iblockProperties = [
|
||||
'article' => 'article',
|
||||
'manufacturer' => 'manufacturer',
|
||||
'color' => 'color',
|
||||
'weight' => 'weight',
|
||||
'size' => 'size',
|
||||
'length' => 'length',
|
||||
'width' => 'width',
|
||||
'height' => 'height',
|
||||
];
|
||||
|
||||
$iblockPropertySku = [];
|
||||
$iblockPropertySkuHl = [];
|
||||
$iblockPropertyUnitSku = [];
|
||||
$iblockPropertyProduct = [];
|
||||
$iblockPropertyProductHl = [];
|
||||
$iblockPropertyUnitProduct = [];
|
||||
|
||||
foreach ($iblockProperties as $prop) {
|
||||
$skuUnitProps = ('IBLOCK_PROPERTY_UNIT_SKU' . "_" . $prop);
|
||||
$skuUnitProps = $$skuUnitProps;
|
||||
|
||||
if (is_array($skuUnitProps)) {
|
||||
foreach ($skuUnitProps as $iblock => $val) {
|
||||
$IBLOCK_PROPERTY_UNIT_SKU[$iblock][$prop] = $val;
|
||||
$iblockPropertyUnitSku[$iblock][$prop] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +67,7 @@ if (file_exists($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/expor
|
|||
$skuProps = $$skuProps;
|
||||
if (is_array($skuProps)) {
|
||||
foreach ($skuProps as $iblock => $val) {
|
||||
$IBLOCK_PROPERTY_SKU[$iblock][$prop] = $val;
|
||||
$iblockPropertySku[$iblock][$prop] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,22 +78,17 @@ if (file_exists($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/expor
|
|||
|
||||
if (is_array($hbProps)) {
|
||||
foreach ($hbProps as $iblock => $val) {
|
||||
$IBLOCK_PROPERTY_SKU_HIGHLOADBLOCK[$hlblockTable][$iblock][$prop] = $val;
|
||||
$iblockPropertySkuHl[$hlblockTable][$iblock][$prop] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$IBLOCK_PROPERTY_PRODUCT = array();
|
||||
$IBLOCK_PROPERTY_PRODUCT_HIGHLOADBLOCK = array();
|
||||
$IBLOCK_PROPERTY_UNIT_PRODUCT = array();
|
||||
foreach ($iblockProperties as $prop) {
|
||||
$productUnitProps = "IBLOCK_PROPERTY_UNIT_PRODUCT" . "_" . $prop;
|
||||
$productUnitProps = $$productUnitProps;
|
||||
if (is_array($productUnitProps)) {
|
||||
foreach ($productUnitProps as $iblock => $val) {
|
||||
$IBLOCK_PROPERTY_UNIT_PRODUCT[$iblock][$prop] = $val;
|
||||
$iblockPropertyUnitProduct[$iblock][$prop] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,7 +96,7 @@ if (file_exists($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/expor
|
|||
$productProps = $$productProps;
|
||||
if (is_array($productProps)) {
|
||||
foreach ($productProps as $iblock => $val) {
|
||||
$IBLOCK_PROPERTY_PRODUCT[$iblock][$prop] = $val;
|
||||
$iblockPropertyProduct[$iblock][$prop] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,51 +107,52 @@ if (file_exists($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/expor
|
|||
|
||||
if (is_array($hbProps)) {
|
||||
foreach ($hbProps as $iblock => $val) {
|
||||
$IBLOCK_PROPERTY_PRODUCT_HIGHLOADBLOCK[$hlblockTable][$iblock][$prop] = $val;
|
||||
$iblockPropertyProductHl[$hlblockTable][$iblock][$prop] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$productPictures = array();
|
||||
$productPictures = [];
|
||||
|
||||
if (is_array($IBLOCK_PROPERTY_PRODUCT_picture)) {
|
||||
foreach ($IBLOCK_PROPERTY_PRODUCT_picture as $key => $value) {
|
||||
$productPictures[$key]['picture'] = $value;
|
||||
$productPictures[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$skuPictures = array();
|
||||
$skuPictures = [];
|
||||
|
||||
if (is_array($IBLOCK_PROPERTY_SKU_picture)) {
|
||||
foreach ($IBLOCK_PROPERTY_SKU_picture as $key => $value) {
|
||||
$skuPictures[$key]['picture'] = $value;
|
||||
$skuPictures[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$loader = new RetailCrmICML();
|
||||
$loader->profileID = $profile_id;
|
||||
$loader->iblocks = $IBLOCK_EXPORT;
|
||||
$loader->propertiesSKU = $IBLOCK_PROPERTY_SKU;
|
||||
$loader->propertiesUnitSKU = $IBLOCK_PROPERTY_UNIT_SKU;
|
||||
$loader->propertiesProduct = $IBLOCK_PROPERTY_PRODUCT;
|
||||
$loader->propertiesUnitProduct = $IBLOCK_PROPERTY_UNIT_PRODUCT;
|
||||
$loader->productPictures = $productPictures;
|
||||
$loader->skuPictures = $skuPictures;
|
||||
$xmlProps = new XmlSetupPropsCategories(
|
||||
new XmlSetupProps($iblockPropertyProduct, $iblockPropertyUnitProduct, $productPictures),
|
||||
new XmlSetupProps($iblockPropertySku, $iblockPropertyUnitSku, $skuPictures)
|
||||
);
|
||||
|
||||
if ($hlblockModule === true) {
|
||||
$loader->highloadblockSkuProperties = $IBLOCK_PROPERTY_SKU_HIGHLOADBLOCK;
|
||||
$loader->highloadblockProductProperties = $IBLOCK_PROPERTY_PRODUCT_HIGHLOADBLOCK;
|
||||
$xmlProps->highloadblockSku = $iblockPropertySkuHl;
|
||||
$xmlProps->highloadblockProduct = $iblockPropertyProductHl;
|
||||
}
|
||||
|
||||
if ($MAX_OFFERS_VALUE) {
|
||||
$loader->offerPageSize = $MAX_OFFERS_VALUE;
|
||||
}
|
||||
$fileSetup = new XmlSetup($xmlProps);
|
||||
$fileSetup->profileId = $profile_id;
|
||||
$fileSetup->iblocksForExport = $IBLOCK_EXPORT;
|
||||
$fileSetup->maxOffersValue = $MAX_OFFERS_VALUE ?? null;
|
||||
$fileSetup->filePath = $SETUP_FILE_NAME;
|
||||
$fileSetup->loadPurchasePrice = $LOAD_PURCHASE_PRICE === 'Y';
|
||||
$fileSetup->basePriceId = CatalogRepository::getBasePriceId($fileSetup->profileId);
|
||||
$logger = Logger::getInstance('/bitrix/catalog_export/');
|
||||
|
||||
$loader->filename = $SETUP_FILE_NAME;
|
||||
$loader->defaultServerName = $SERVER_NAME;
|
||||
$loader->application = $APPLICATION;
|
||||
$loader->loadPurchasePrice = $LOAD_PURCHASE_PRICE == 'Y';
|
||||
$loader->Load();
|
||||
}
|
||||
if (!is_array($fileSetup->iblocksForExport) || count($fileSetup->iblocksForExport) === 0) {
|
||||
$logger->write(GetMessage("IBLOCK_NOT_SELECTED"), 'i_crm_load_log');
|
||||
} else {
|
||||
$loader = new IcmlDirector($fileSetup, $logger);
|
||||
$loader->generateXml();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
<?
|
||||
|
||||
use Bitrix\Highloadblock\HighloadBlockTable;
|
||||
|
||||
if (file_exists($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/export_setup.php")){
|
||||
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/export_setup.php");
|
||||
} else {
|
||||
if (isset($_POST['ajax']) && $_POST['ajax'] == '1') {
|
||||
CModule::IncludeModule('highloadblock');
|
||||
$rsData = \Bitrix\Highloadblock\HighloadBlockTable::getList(array('filter' => array('TABLE_NAME' => $_POST['table'])));
|
||||
$rsData = HighloadBlockTable::getList(['filter' => ['TABLE_NAME' => $_POST['table']]]);
|
||||
$hlblockArr = $rsData->Fetch();
|
||||
$hlblock = \Bitrix\Highloadblock\HighloadBlockTable::getById($hlblockArr["ID"])->fetch();
|
||||
$entity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity($hlblock);
|
||||
$hlblock = HighloadBlockTable::getById($hlblockArr["ID"])->fetch();
|
||||
$entity = HighloadBlockTable::compileEntity($hlblock);
|
||||
$hbFields = $entity->getFields();
|
||||
$hlblockList['table'] = $hlblockArr["TABLE_NAME"];
|
||||
|
||||
|
@ -55,11 +58,11 @@ if (file_exists($_SERVER["DOCUMENT_ROOT"]."/bitrix/php_interface/retailcrm/expor
|
|||
if (CModule::IncludeModule('highloadblock')) {
|
||||
$hlblockModule = true;
|
||||
$hlblockList = array();
|
||||
$hlblockListDb = \Bitrix\Highloadblock\HighloadBlockTable::getList();
|
||||
$hlblockListDb = HighloadBlockTable::getList();
|
||||
|
||||
while ($hlblockArr = $hlblockListDb->Fetch()) {
|
||||
$hlblock = \Bitrix\Highloadblock\HighloadBlockTable::getById($hlblockArr["ID"])->fetch();
|
||||
$entity = \Bitrix\Highloadblock\HighloadBlockTable::compileEntity($hlblock);
|
||||
$hlblock = HighloadBlockTable::getById($hlblockArr["ID"])->fetch();
|
||||
$entity = HighloadBlockTable::compileEntity($hlblock);
|
||||
$hbFields = $entity->getFields();
|
||||
$hlblockList[$hlblockArr["TABLE_NAME"]]['LABEL'] = $hlblockArr["NAME"];
|
||||
|
||||
|
|
|
@ -495,8 +495,9 @@ if (!empty($oldValues)) {
|
|||
<br>
|
||||
<br>
|
||||
<font class="text"><?=GetMessage("LOAD_NOW");?> </font>
|
||||
<input id="load-now" type="checkbox" name="LOAD_NOW" value="now" checked >
|
||||
<input id="load-now" onchange="checkLoadStatus(this)" type="checkbox" name="LOAD_NOW" value="now">
|
||||
<br>
|
||||
<div id="loadMessage" hidden><?=GetMessage("LOAD_NOW_MSG");?></div>
|
||||
<br>
|
||||
<font class="text"><?=GetMessage("BASE_PRICE");?> </font>
|
||||
<select name="price-types" class="typeselect">
|
||||
|
@ -615,6 +616,16 @@ if (!empty($oldValues)) {
|
|||
getHbFromAjax($(obj).find('option')[obj.selectedIndex], 'product');
|
||||
}
|
||||
};
|
||||
|
||||
function checkLoadStatus(object)
|
||||
{
|
||||
if (object.checked) {
|
||||
$('#loadMessage').show();
|
||||
} else {
|
||||
$('#loadMessage').hide();
|
||||
}
|
||||
}
|
||||
|
||||
function checkProfile(obj)
|
||||
{
|
||||
if (obj.value !== 'none')
|
||||
|
@ -677,12 +688,11 @@ if (!empty($oldValues)) {
|
|||
<input type="hidden" name="continue" value="5">
|
||||
<div style="padding: 1px 13px 2px; height:28px;">
|
||||
<div align="right" style="float:right; width:50%; position:relative;">
|
||||
<input type="submit" name="inst" value="<?php echo GetMessage("MOD_NEXT_STEP"); ?>" class="adm-btn-save">
|
||||
<input type="submit" name="inst" onclick="BX.showWait()" value="<?= GetMessage("MOD_NEXT_STEP"); ?>"
|
||||
class="adm-btn-save">
|
||||
</div>
|
||||
<div align="left" style="float:right; width:50%; position:relative;">
|
||||
<input type="submit" name="back" value="<?php echo GetMessage("MOD_PREV_STEP"); ?>" class="adm-btn-save">
|
||||
<input type="submit" name="back" value="<?= GetMessage("MOD_PREV_STEP"); ?>" class="adm-btn-save">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
|
|
3
intaro.retailcrm/lang/en/export/export_run.php
Normal file
3
intaro.retailcrm/lang/en/export/export_run.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
$MESS['IBLOCK_NOT_SELECTED'] = 'No infoblock selected for export';
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
|
||||
$MESS['IBLOCK_NOT_SELECTED'] = 'No infoblock selected for export';
|
||||
$MESS ['RETAIL_MODULE_NAME'] = 'RetailCRM';
|
||||
$MESS ['MODULE_DESCRIPTION'] = 'Integration module with RetailCRM - specialized CRM for e-commerce';
|
||||
$MESS ['MODULE_PARTNER_NAME'] = 'Intaro Software';
|
||||
|
|
|
@ -17,6 +17,8 @@ $MESS ['NOT_LOADING'] = 'No';
|
|||
$MESS ['CRON_LOADING'] = 'By CRON every 24 hours';
|
||||
$MESS ['AGENT_LOADING'] = 'By Agent every 24 hours (by default)';
|
||||
$MESS ['LOAD_NOW'] = 'Export now';
|
||||
$MESS ['LOAD_NOW_MSG'] = 'The generation will start after you click "Finish installation".
|
||||
This may take some time';
|
||||
$MESS ['PROFILE_NAME'] = 'Profile name:';
|
||||
$MESS ['PROFILE_NAME_EXAMPLE'] = 'RetailCRM catalog export';
|
||||
$MESS ['ERR_FIELDS_PROFILE'] = 'Invalid profile name field';
|
||||
|
|
3
intaro.retailcrm/lang/ru/export/export_run.php
Normal file
3
intaro.retailcrm/lang/ru/export/export_run.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
$MESS['IBLOCK_NOT_SELECTED'] = 'Не выбрано ни одного инфоблока для экспорта';
|
|
@ -17,6 +17,7 @@ $MESS ['NOT_LOADING'] = 'Нет';
|
|||
$MESS ['CRON_LOADING'] = 'С помощью CRON каждые 24 часа';
|
||||
$MESS ['AGENT_LOADING'] = 'Агентом каждые 24 часа (по умолчанию)';
|
||||
$MESS ['LOAD_NOW'] = 'Выгрузить сейчас';
|
||||
$MESS ['LOAD_NOW_MSG'] = 'Генерация начнется после нажатия "Завершить установку". Это может занять некоторое время';
|
||||
$MESS ['PROFILE_NAME'] = 'Имя профиля:';
|
||||
$MESS ['PROFILE_NAME_EXAMPLE'] = 'Выгрузка каталога RetailCRM';
|
||||
$MESS ['ERR_FIELDS_PROFILE'] = 'Неверно заполнено поле имени профиля';
|
||||
|
|
28
intaro.retailcrm/lib/component/agent.php
Normal file
28
intaro.retailcrm/lib/component/agent.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Component;
|
||||
|
||||
use CCatalogExport;
|
||||
use CModule;
|
||||
use Dotenv\Loader;
|
||||
|
||||
/**
|
||||
* Class Agent
|
||||
*
|
||||
* @package Intaro\RetailCrm\Component
|
||||
*/
|
||||
class Agent
|
||||
{
|
||||
/**
|
||||
* @param int $profileId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function preGenerateExport(int $profileId): string
|
||||
{
|
||||
CModule::IncludeModule('catalog');
|
||||
CCatalogExport::PreGenerateExport($profileId);
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
334
intaro.retailcrm/lib/icml/icmldirector.php
Normal file
334
intaro.retailcrm/lib/icml/icmldirector.php
Normal file
|
@ -0,0 +1,334 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Icml;
|
||||
|
||||
use COption;
|
||||
use Intaro\RetailCrm\Icml\Utils\IcmlUtils;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlData;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup;
|
||||
use Intaro\RetailCrm\Repository\CatalogRepository;
|
||||
use Logger;
|
||||
use RetailcrmConfigProvider;
|
||||
|
||||
/**
|
||||
* Class IcmlDirector
|
||||
* @package Intaro\RetailCrm\Icml
|
||||
*/
|
||||
class IcmlDirector
|
||||
{
|
||||
public const INFO = 'INFO';
|
||||
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.
|
||||
*
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup $setup
|
||||
* @param \Logger $logger
|
||||
*/
|
||||
public function __construct(XmlSetup $setup, Logger $logger)
|
||||
{
|
||||
$this->setup = $setup;
|
||||
$this->shopName = RetailcrmConfigProvider::getSiteName();
|
||||
$this->catalogRepository = new CatalogRepository();
|
||||
$this->icmlWriter = new IcmlWriter($this->setup->filePath);
|
||||
$this->xmlOfferDirector = new XmlOfferDirector($this->setup);
|
||||
$this->xmlCategoryDirector = new XmlCategoryDirector($this->setup->iblocksForExport);
|
||||
$this->queryBuilder = new QueryParamsMolder();
|
||||
$this->xmlData = new XmlData();
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Основной метод. Генерирует icml файл католога товаров Битрикс
|
||||
*/
|
||||
public function generateXml(): void
|
||||
{
|
||||
$this->setXmlData();
|
||||
$this->icmlWriter->writeToXmlTop($this->xmlData);
|
||||
$this->logger->write(
|
||||
self::INFO . ': Start writing categories and header',
|
||||
self::FILE_LOG_NAME
|
||||
);
|
||||
$this->icmlWriter->writeToXmlHeaderAndCategories($this->xmlData);
|
||||
$this->logger->write(
|
||||
self::INFO . ': End writing categories in XML and Start writing offers',
|
||||
self::FILE_LOG_NAME
|
||||
);
|
||||
$this->writeOffers();
|
||||
$this->logger->write(
|
||||
self::INFO . ': End writing offers in XML',
|
||||
self::FILE_LOG_NAME
|
||||
);
|
||||
$this->icmlWriter->writeToXmlBottom();
|
||||
$this->logger->write(
|
||||
self::INFO . ': Loading complete (peak memory usage: ' . memory_get_peak_usage() . ')',
|
||||
self::FILE_LOG_NAME
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function setXmlData(): void
|
||||
{
|
||||
$this->xmlData->shopName = $this->shopName;
|
||||
$this->xmlData->company = $this->shopName;
|
||||
$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 файл
|
||||
*
|
||||
* @param int $productIblockId //ID инфоблока товаров в торговом каталоге
|
||||
*/
|
||||
private function writeIblockOffers(int $productIblockId): void
|
||||
{
|
||||
$catalogIblockInfo = $this->catalogRepository->getCatalogIblockInfo($productIblockId);
|
||||
|
||||
//если нет торговых предложений
|
||||
if ($catalogIblockInfo->skuIblockId === null) {
|
||||
$selectParams
|
||||
= $this->queryBuilder->getSelectParams(
|
||||
$this->setup->properties->products->names[$productIblockId],
|
||||
$this->setup->basePriceId
|
||||
);
|
||||
|
||||
$selectParams->pageNumber = 1;
|
||||
$selectParams->nPageSize = self::OFFERS_PART;
|
||||
$selectParams->parentId = null;
|
||||
|
||||
while ($xmlOffers = $this->xmlOfferDirector->getXmlOffersPart($selectParams, $catalogIblockInfo)) {
|
||||
$this->icmlWriter->writeOffers($xmlOffers);
|
||||
|
||||
$selectParams->pageNumber++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//если есть торговые предложения
|
||||
$paramsForProduct
|
||||
= $this->queryBuilder->getSelectParams(
|
||||
$this->setup->properties->products->names[$productIblockId],
|
||||
$this->setup->basePriceId
|
||||
);
|
||||
$paramsForOffer
|
||||
= $this->queryBuilder->getSelectParams(
|
||||
$this->setup->properties->sku->names[$productIblockId],
|
||||
$this->setup->basePriceId
|
||||
);
|
||||
$this->writeOffersAsOffersInXml($paramsForProduct, $paramsForOffer, $catalogIblockInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Эта стратегия записи используется,
|
||||
* когда в каталоге есть торговые предложения
|
||||
*
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $paramsForProduct
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $paramsForOffer
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo
|
||||
*/
|
||||
private function writeOffersAsOffersInXml(
|
||||
SelectParams $paramsForProduct,
|
||||
SelectParams $paramsForOffer,
|
||||
CatalogIblockInfo $catalogIblockInfo
|
||||
): void {
|
||||
$paramsForProduct->pageNumber = 1;
|
||||
$paramsForProduct->nPageSize = $this->calculateProductPageSize();
|
||||
|
||||
do {
|
||||
$productsPart = $this->xmlOfferDirector->getXmlOffersPart($paramsForProduct, $catalogIblockInfo);
|
||||
$paramsForProduct->pageNumber++;
|
||||
|
||||
$this->writeProductsOffers($productsPart, $paramsForOffer, $catalogIblockInfo);
|
||||
} while (!empty($productsPart));
|
||||
}
|
||||
|
||||
/**
|
||||
* Записывает в файл оферы всех товаров из $products
|
||||
*
|
||||
* @param XmlOffer[] $products
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $paramsForOffer
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo
|
||||
*/
|
||||
private function writeProductsOffers(
|
||||
array $products,
|
||||
SelectParams $paramsForOffer,
|
||||
CatalogIblockInfo $catalogIblockInfo
|
||||
): void {
|
||||
$paramsForOffer->nPageSize = $this->calculateOffersPageSize();
|
||||
|
||||
foreach ($products as $product) {
|
||||
$this->writeProductOffers($paramsForOffer, $catalogIblockInfo, $product);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Записывает оферы отдельного продукта в xml файл
|
||||
*
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $paramsForOffer
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer $product
|
||||
*/
|
||||
private function writeProductOffers(
|
||||
SelectParams $paramsForOffer,
|
||||
CatalogIblockInfo $catalogIblockInfo,
|
||||
XmlOffer $product
|
||||
): void {
|
||||
$paramsForOffer->pageNumber = 1;
|
||||
$writingOffersCount = 0;
|
||||
$paramsForOffer->parentId = $product->id;
|
||||
|
||||
do {
|
||||
$xmlOffersPart
|
||||
= $this->xmlOfferDirector->getXmlOffersBySingleProduct($paramsForOffer, $catalogIblockInfo, $product);
|
||||
|
||||
// если это "простой товар", у которого нет ТП, то просто записываем его
|
||||
if ($paramsForOffer->pageNumber === 1 && count($xmlOffersPart) === 0) {
|
||||
$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
|
||||
* и обрезает массив до лимита, если он достигнут
|
||||
*
|
||||
* @param int $writingOffers
|
||||
* @param XmlOffer[] $xmlOffers
|
||||
*
|
||||
* @return XmlOffer[]
|
||||
*/
|
||||
private function trimOffersList(int $writingOffers, array $xmlOffers): array
|
||||
{
|
||||
if (!empty($this->setup->maxOffersValue) && ($writingOffers + count($xmlOffers)) > $this->setup->maxOffersValue) {
|
||||
$sliceIndex
|
||||
= count($xmlOffers) - ($writingOffers + count($xmlOffers) - $this->setup->maxOffersValue);
|
||||
return array_slice($xmlOffers, 0, $sliceIndex);
|
||||
}
|
||||
|
||||
return $xmlOffers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает размер страницы для запроса товаров
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function calculateProductPageSize(): int
|
||||
{
|
||||
if (empty($this->setup->maxOffersValue)) {
|
||||
return self::DEFAULT_PRODUCT_PAGE_SIZE;
|
||||
}
|
||||
|
||||
return (int) ceil(self::OFFERS_PART / $this->setup->maxOffersValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает размер страницы для офферов
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function calculateOffersPageSize(): int
|
||||
{
|
||||
if (empty($this->setup->maxOffersValue)) {
|
||||
return self::OFFERS_PART;
|
||||
}
|
||||
|
||||
return $this->setup->maxOffersValue < self::OFFERS_PART ?
|
||||
$this->setup->maxOffersValue : self::OFFERS_PART;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, нужно ли дальше записывать офферы
|
||||
*
|
||||
* @param int $writingOffers
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer[] $xmlOffers
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function shouldContinueWriting(int $writingOffers, array $xmlOffers): bool
|
||||
{
|
||||
if (empty($this->setup->maxOffersValue)) {
|
||||
return !empty($xmlOffers);
|
||||
}
|
||||
|
||||
return !empty($xmlOffers) && $writingOffers < $this->setup->maxOffersValue;
|
||||
}
|
||||
}
|
227
intaro.retailcrm/lib/icml/icmlwriter.php
Normal file
227
intaro.retailcrm/lib/icml/icmlwriter.php
Normal file
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Icml;
|
||||
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\OfferParam;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlCategory;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlData;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer;
|
||||
use XMLWriter;
|
||||
|
||||
/**
|
||||
* Отвечает за запись данных каталога в файл
|
||||
*
|
||||
* Class IcmlWriter
|
||||
* @package Intaro\RetailCrm\Icml
|
||||
*/
|
||||
class IcmlWriter
|
||||
{
|
||||
public const INFO = 'INFO';
|
||||
public const CATEGORY_PART = 1000;
|
||||
|
||||
/**
|
||||
* @var \XMLWriter
|
||||
*/
|
||||
private $writer;
|
||||
|
||||
/**
|
||||
* IcmlWriter constructor.
|
||||
* @param $filePath
|
||||
*/
|
||||
public function __construct($filePath)
|
||||
{
|
||||
$this->writer = new XMLWriter();
|
||||
$this->writer->openURI($_SERVER['DOCUMENT_ROOT'] . $filePath);
|
||||
$this->writer->setIndent(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlData $data
|
||||
*/
|
||||
public function writeToXmlTop(XmlData $data): void
|
||||
{
|
||||
$this->writer->startElement('yml_catalog');
|
||||
$this->writeSimpleAttribute('date', Date('Y-m-d H:i:s'));
|
||||
|
||||
$this->writer->startElement('shop');
|
||||
$this->writeSimpleElement('name', $data->shopName);
|
||||
$this->writeSimpleElement('company', $data->company);
|
||||
}
|
||||
|
||||
public function writeToXmlBottom(): void
|
||||
{
|
||||
$this->writer->endElement();
|
||||
$this->writer->endElement();
|
||||
$this->writer->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlData $data
|
||||
*/
|
||||
public function writeToXmlHeaderAndCategories(XmlData $data): void
|
||||
{
|
||||
$this->writer->startElement('categories');
|
||||
|
||||
foreach ($data->categories as $key => $category) {
|
||||
$this->writeCategory($category);
|
||||
|
||||
if (
|
||||
count($data->categories) === $key + 1
|
||||
|| is_int(count($data->categories) / self::CATEGORY_PART)
|
||||
) {
|
||||
$this->writer->flush();
|
||||
}
|
||||
}
|
||||
|
||||
$this->writer->endElement();
|
||||
$this->writer->flush();
|
||||
}
|
||||
|
||||
public function startOffersBlock(): void
|
||||
{
|
||||
$this->writer->startElement('offers');
|
||||
}
|
||||
|
||||
public function endBlock(): void
|
||||
{
|
||||
$this->writer->endElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param XmlOffer[] $offers
|
||||
*/
|
||||
public function writeOffers(array $offers): void
|
||||
{
|
||||
foreach ($offers as $offer) {
|
||||
$this->writeOffer($offer);
|
||||
}
|
||||
|
||||
$this->writer->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer $offer
|
||||
*/
|
||||
private function writeOffer(XmlOffer $offer): void
|
||||
{
|
||||
$this->writer->startElement('offer');
|
||||
$this->writeSimpleAttribute('id', $offer->id);
|
||||
$this->writeSimpleAttribute('productId', $offer->productId);
|
||||
$this->writeSimpleAttribute('quantity', $offer->quantity);
|
||||
|
||||
foreach ($offer->categoryIds as $categoryId) {
|
||||
$this->writeSimpleElement('categoryId', $categoryId);
|
||||
}
|
||||
|
||||
if (!empty($offer->picture)) {
|
||||
$this->writeSimpleElement('picture', $offer->picture);
|
||||
}
|
||||
|
||||
if (!empty($offer->unitCode->code)) {
|
||||
$this->writer->startElement('unit');
|
||||
$this->writeSimpleAttribute('code', $offer->unitCode->code);
|
||||
$this->writeSimpleAttribute('name', $offer->unitCode->name);
|
||||
$this->writeSimpleAttribute('sym', $offer->unitCode->sym);
|
||||
$this->writer->endElement();
|
||||
}
|
||||
|
||||
foreach ($offer->params as $param) {
|
||||
$this->writeParam($param);
|
||||
}
|
||||
|
||||
$this->writeSimpleElement('url', $offer->url);
|
||||
$this->writeSimpleElement('price', $offer->price);
|
||||
$this->writeSimpleElement('name', $offer->name);
|
||||
$this->writeSimpleElement('productName', $offer->productName);
|
||||
$this->writeSimpleElement('xmlId', $offer->xmlId);
|
||||
$this->writeOptionalSimpleElement('vendor', $offer->vendor);
|
||||
$this->writeOptionalSimpleElement('barcode', $offer->barcode);
|
||||
$this->writeOptionalSimpleElement('vatRate', $offer->vatRate);
|
||||
$this->writeOptionalSimpleElement('weight', $offer->weight);
|
||||
$this->writeOptionalSimpleElement('dimensions', $offer->dimensions);
|
||||
$this->writeOptionalSimpleElement('purchasePrice', $offer->purchasePrice);
|
||||
$this->writer->endElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает ноду, если значение не пустое
|
||||
*
|
||||
* @param string $name
|
||||
* @param $value
|
||||
*/
|
||||
private function writeOptionalSimpleElement(string $name, $value): void
|
||||
{
|
||||
if (!empty($value)) {
|
||||
$this->writeSimpleElement($name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param $value
|
||||
*/
|
||||
private function writeSimpleElement(string $name, $value): void
|
||||
{
|
||||
$this->writer->startElement($name);
|
||||
$this->writer->text($this->prepareValue($value));
|
||||
$this->writer->endElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param $value
|
||||
*/
|
||||
private function writeSimpleAttribute(string $name, $value): void
|
||||
{
|
||||
$this->writer->startAttribute($name);
|
||||
$this->writer->text($this->prepareValue($value));
|
||||
$this->writer->endAttribute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareValue($text): string
|
||||
{
|
||||
global $APPLICATION;
|
||||
|
||||
return strip_tags($APPLICATION->ConvertCharset($text, 'utf-8', 'utf-8'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlCategory $category
|
||||
*/
|
||||
private function writeCategory(XmlCategory $category): void
|
||||
{
|
||||
$this->writer->startElement('category');
|
||||
$this->writeSimpleAttribute('id', $category->id);
|
||||
$this->writeParentId($category->parentId);
|
||||
$this->writeSimpleElement('name', $category->name);
|
||||
$this->writeSimpleElement('picture', $category->picture);
|
||||
$this->writer->endElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\OfferParam $param
|
||||
*/
|
||||
private function writeParam(OfferParam $param): void
|
||||
{
|
||||
$this->writer->startElement('param');
|
||||
$this->writeSimpleAttribute('name', $param->name);
|
||||
$this->writeSimpleAttribute('code', $param->code);
|
||||
$this->writer->text($this->prepareValue($param->value));
|
||||
$this->writer->endElement();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $parentId
|
||||
*/
|
||||
private function writeParentId(string $parentId)
|
||||
{
|
||||
if ($parentId > 0) {
|
||||
$this->writeSimpleAttribute('parentId', $parentId);
|
||||
}
|
||||
}
|
||||
}
|
80
intaro.retailcrm/lib/icml/queryparamsmolder.php
Normal file
80
intaro.retailcrm/lib/icml/queryparamsmolder.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Icml;
|
||||
|
||||
use Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams;
|
||||
|
||||
/**
|
||||
* Class QueryParamsMolder
|
||||
* @package Intaro\RetailCrm\Icml
|
||||
*/
|
||||
class QueryParamsMolder
|
||||
{
|
||||
/**
|
||||
* Формирует параметры товаров или офферов для запросов к БД на основе настроек экспорта
|
||||
*
|
||||
* @param array|null $userProps
|
||||
* @param int $basePriceId
|
||||
* @return \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams
|
||||
*/
|
||||
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 = [
|
||||
'IBLOCK_ID',
|
||||
'IBLOCK_SECTION_ID',
|
||||
'NAME',
|
||||
'DETAIL_PICTURE',
|
||||
'PREVIEW_PICTURE',
|
||||
'DETAIL_PAGE_URL',
|
||||
'CATALOG_QUANTITY',
|
||||
'CATALOG_PRICE_' . $basePriceId,
|
||||
'CATALOG_PURCHASING_PRICE',
|
||||
'EXTERNAL_ID',
|
||||
'CATALOG_GROUP_' . $basePriceId,
|
||||
'ID',
|
||||
'LID',
|
||||
];
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $parentId
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $info
|
||||
* @return array
|
||||
*/
|
||||
public function getWhereForOfferPart(?int $parentId, CatalogIblockInfo $info): array
|
||||
{
|
||||
if ($parentId === null) {
|
||||
return [
|
||||
'IBLOCK_ID' => $info->productIblockId,
|
||||
'ACTIVE' => 'Y',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'IBLOCK_ID' => $info->skuIblockId,
|
||||
'ACTIVE' => 'Y',
|
||||
'PROPERTY_' . $info->skuPropertyId => $parentId,
|
||||
];
|
||||
}
|
||||
}
|
140
intaro.retailcrm/lib/icml/xmlcategorydirector.php
Normal file
140
intaro.retailcrm/lib/icml/xmlcategorydirector.php
Normal file
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace Intaro\RetailCrm\Icml;
|
||||
|
||||
use Bitrix\Main\ArgumentException;
|
||||
use Bitrix\Main\ORM\Objectify\Collection;
|
||||
use Bitrix\Main\ORM\Objectify\EntityObject;
|
||||
use Bitrix\Main\SystemException;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlCategory;
|
||||
use Intaro\RetailCrm\Repository\CatalogRepository;
|
||||
use Intaro\RetailCrm\Repository\FileRepository;
|
||||
use Intaro\RetailCrm\Repository\SiteRepository;
|
||||
|
||||
/**
|
||||
* Class XmlCategoryDirector
|
||||
* @package Intaro\RetailCrm\Icml
|
||||
*/
|
||||
class XmlCategoryDirector
|
||||
{
|
||||
private const MILLION = 1000000;
|
||||
|
||||
/**
|
||||
* @var \Intaro\RetailCrm\Repository\CatalogRepository
|
||||
*/
|
||||
private $catalogRepository;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $iblocksForExport;
|
||||
|
||||
/**
|
||||
* @var \Intaro\RetailCrm\Icml\XmlCategoryFactory
|
||||
*/
|
||||
private $xmlCategoryFactory;
|
||||
|
||||
/**
|
||||
* @var \Intaro\RetailCrm\Repository\FileRepository
|
||||
*/
|
||||
private $fileRepository;
|
||||
|
||||
public function __construct(array $iblocksForExport)
|
||||
{
|
||||
$this->iblocksForExport = $iblocksForExport;
|
||||
$this->catalogRepository = new CatalogRepository();
|
||||
$this->xmlCategoryFactory = new XmlCategoryFactory();
|
||||
$this->fileRepository = new FileRepository(SiteRepository::getDefaultServerName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return XmlCategory[]
|
||||
*/
|
||||
public function getXmlCategories(): array
|
||||
{
|
||||
$xmlCategories = [];
|
||||
|
||||
foreach ($this->iblocksForExport as $iblockId) {
|
||||
$categories = $this->catalogRepository->getCategoriesByIblockId($iblockId);
|
||||
|
||||
if ($categories === null) {
|
||||
$categoryId = self::MILLION + $iblockId;
|
||||
$xmlCategory = $this->makeXmlCategoryFromIblock($iblockId, $categoryId);
|
||||
|
||||
if (!$xmlCategory) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$xmlCategories[$categoryId] = $xmlCategory;
|
||||
}
|
||||
|
||||
$xmlCategories = array_merge($xmlCategories, $this->getXmlSubCategories($categories));
|
||||
}
|
||||
|
||||
return $xmlCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает коллекцию подкатегорий категории
|
||||
*
|
||||
* @param \Bitrix\Main\ORM\Objectify\Collection $categories
|
||||
* @return XmlCategory[]
|
||||
*/
|
||||
public function getXmlSubCategories(Collection $categories): array
|
||||
{
|
||||
$xmlCategories = [];
|
||||
|
||||
foreach ($categories as $categoryKey => $category) {
|
||||
if (!$category instanceof EntityObject) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$xmlCategory = $this->xmlCategoryFactory->create(
|
||||
$category,
|
||||
$this->fileRepository->getImageUrl($category->get('PICTURE'))
|
||||
);
|
||||
|
||||
if (!$xmlCategory) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$xmlCategories[$categoryKey] = $this->xmlCategoryFactory->create(
|
||||
$category,
|
||||
$this->fileRepository->getImageUrl($category->get('PICTURE'))
|
||||
);
|
||||
} catch (ArgumentException | SystemException $exception) {
|
||||
AddMessage2Log($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return $xmlCategories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает XmlCategory из инфоблока
|
||||
*
|
||||
* @param int $iblockId
|
||||
* @param int $categoryId
|
||||
* @return \Intaro\RetailCrm\Model\Bitrix\Xml\XmlCategory|null
|
||||
*/
|
||||
public function makeXmlCategoryFromIblock(int $iblockId, int $categoryId): ?XmlCategory
|
||||
{
|
||||
$iblock = $this->catalogRepository->getIblockById($iblockId);
|
||||
|
||||
if ($iblock === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->xmlCategoryFactory->create(
|
||||
$iblock,
|
||||
$this->fileRepository->getImageUrl($iblock->get('PICTURE')),
|
||||
$categoryId
|
||||
);
|
||||
} catch (ArgumentException | SystemException $exception) {
|
||||
AddMessage2Log($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
43
intaro.retailcrm/lib/icml/xmlcategoryfactory.php
Normal file
43
intaro.retailcrm/lib/icml/xmlcategoryfactory.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Icml;
|
||||
|
||||
use Bitrix\Main\ArgumentException;
|
||||
use Bitrix\Main\ORM\Objectify\Collection;
|
||||
use Bitrix\Main\ORM\Objectify\EntityObject;
|
||||
use Bitrix\Main\SystemException;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlCategory;
|
||||
use Intaro\RetailCrm\Repository\CatalogRepository;
|
||||
use Intaro\RetailCrm\Repository\FileRepository;
|
||||
use Intaro\RetailCrm\Repository\SiteRepository;
|
||||
|
||||
/**
|
||||
* Отвечает за создание XmlCategory
|
||||
*
|
||||
* Class XmlCategoryFactory
|
||||
* @package Intaro\RetailCrm\Icml
|
||||
*/
|
||||
class XmlCategoryFactory
|
||||
{
|
||||
/**
|
||||
* @param \Bitrix\Main\ORM\Objectify\EntityObject $category
|
||||
* @param string $picture
|
||||
* @param int|null $categoryId
|
||||
*
|
||||
* @return \Intaro\RetailCrm\Model\Bitrix\Xml\XmlCategory|null
|
||||
*/
|
||||
public function create(EntityObject $category, string $picture, int $categoryId = null): ?XmlCategory
|
||||
{
|
||||
try {
|
||||
$xmlCategory = new XmlCategory();
|
||||
$xmlCategory->id = $categoryId ?? $category->get('ID');
|
||||
$xmlCategory->name = $category->get('NAME');
|
||||
$xmlCategory->parentId = $categoryId ? 0 : $category->get('IBLOCK_SECTION_ID');
|
||||
$xmlCategory->picture = $picture;
|
||||
} catch (ArgumentException | SystemException $exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $xmlCategory;
|
||||
}
|
||||
}
|
520
intaro.retailcrm/lib/icml/xmlofferbuilder.php
Normal file
520
intaro.retailcrm/lib/icml/xmlofferbuilder.php
Normal file
|
@ -0,0 +1,520 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Icml;
|
||||
|
||||
use Bitrix\Catalog\ProductTable;
|
||||
use Bitrix\Main\ArgumentException;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
private $xmlOffer;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $categories;
|
||||
|
||||
/**
|
||||
* IcmlDataManager constructor.
|
||||
*
|
||||
* XmlOfferBuilder constructor.
|
||||
*
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup $setup
|
||||
* @param array $measure
|
||||
* @param string|null $defaultServerName
|
||||
*/
|
||||
public function __construct(XmlSetup $setup, array $measure, ?string $defaultServerName)
|
||||
{
|
||||
$this->setup = $setup;
|
||||
$this->purchasePriceNull = RetailcrmConfigProvider::getCrmPurchasePrice();
|
||||
$this->measures = $this->prepareMeasures($measure);
|
||||
$this->defaultServerName = $defaultServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
$this->addDataFromParams();
|
||||
$this->addDataFromItem($this->productProps, $this->categories);
|
||||
|
||||
return $this->xmlOffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $categories
|
||||
*/
|
||||
public function setCategories(array $categories)
|
||||
{
|
||||
$this->categories = $categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $skuHlParams
|
||||
*/
|
||||
public function setSkuHlParams($skuHlParams): void
|
||||
{
|
||||
$this->skuHlParams = $skuHlParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $productHlParams
|
||||
*/
|
||||
public function setProductHlParams($productHlParams): void
|
||||
{
|
||||
$this->productHlParams = $productHlParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $selectParams
|
||||
*/
|
||||
public function setSelectParams(SelectParams $selectParams): void
|
||||
{
|
||||
$this->selectParams = $selectParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $productProps
|
||||
*/
|
||||
public function setOfferProps(array $productProps): void
|
||||
{
|
||||
$this->productProps = $productProps;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $barcode
|
||||
*/
|
||||
public function setBarcode(string $barcode): void
|
||||
{
|
||||
$this->barcode = $barcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo
|
||||
*/
|
||||
public function setCatalogIblockInfo(CatalogIblockInfo $catalogIblockInfo): void
|
||||
{
|
||||
$this->catalogIblockInfo = $catalogIblockInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $getProductPicture
|
||||
*/
|
||||
public function setPicturesPath(string $getProductPicture): void
|
||||
{
|
||||
$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,
|
||||
$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->quantity = $item['CATALOG_QUANTITY'] ?? '';
|
||||
$this->xmlOffer->url = $item['DETAIL_PAGE_URL']
|
||||
? $this->defaultServerName . $item['DETAIL_PAGE_URL']
|
||||
: '';
|
||||
$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 = $item['CATALOG_VAT'] ?? 'none';
|
||||
$this->xmlOffer->unitCode = $this->getUnitCode($item['CATALOG_MEASURE'], $item['ID']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает закупочную цену, если она требуется настройками
|
||||
*
|
||||
* @param array $product
|
||||
* @param bool|null $isLoadPrice
|
||||
* @param string $purchasePriceNull
|
||||
* @return int|null
|
||||
*/
|
||||
private function getPurchasePrice(array $product, ?bool $isLoadPrice, string $purchasePriceNull): ?int
|
||||
{
|
||||
if ($isLoadPrice) {
|
||||
if ($product['CATALOG_PURCHASING_PRICE']) {
|
||||
return $product['CATALOG_PURCHASING_PRICE'];
|
||||
}
|
||||
|
||||
if ($purchasePriceNull === 'Y') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает массив обычных свойств
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
$codeWithValue = $params . '_VALUE';
|
||||
|
||||
if (isset($productProps[$codeWithValue])) {
|
||||
$resultParams[$key] = $productProps[$codeWithValue];
|
||||
} elseif (isset($productProps[$params])) {
|
||||
$resultParams[$key] = $productProps[$params];
|
||||
}
|
||||
}
|
||||
|
||||
return $resultParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет параметры с пустыми и нулевыми значениями
|
||||
*
|
||||
* @param array $params
|
||||
* @return array
|
||||
*/
|
||||
private function dropEmptyParams(array $params): array
|
||||
{
|
||||
return array_diff($params, ['', 0, '0']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Разделяем вендора и остальные параметры
|
||||
*
|
||||
* @param array $resultParams
|
||||
* @return array
|
||||
*/
|
||||
private function extractVendorFromParams(array $resultParams): array
|
||||
{
|
||||
$vendor = null;
|
||||
|
||||
if (isset($resultParams['manufacturer'])) {
|
||||
$vendor = $resultParams['manufacturer'];
|
||||
|
||||
unset($resultParams['manufacturer']);
|
||||
}
|
||||
|
||||
return [$resultParams, $vendor];
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует вес товара в килограммы для ноды 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 = '';
|
||||
|
||||
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
|
||||
*
|
||||
* Данные должны быть переведены в сантиметры
|
||||
* и представлены в формате Длина/Ширина/Высота
|
||||
*
|
||||
* @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,
|
||||
];
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
/**
|
||||
* Собираем объект параметре заказа
|
||||
*
|
||||
* @param array $params
|
||||
* @return OfferParam[]
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Собираем объект единицы измерения для товара
|
||||
*
|
||||
* @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'] ?? '';
|
||||
|
||||
return $unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет запрещенные в 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']);
|
||||
}
|
||||
}
|
||||
|
||||
return $measures;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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'] ?? '';
|
||||
|
||||
return $unit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
} 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');
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
206
intaro.retailcrm/lib/icml/xmlofferdirector.php
Normal file
206
intaro.retailcrm/lib/icml/xmlofferdirector.php
Normal file
|
@ -0,0 +1,206 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Icml;
|
||||
|
||||
use Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup;
|
||||
use Intaro\RetailCrm\Repository\CatalogRepository;
|
||||
use Intaro\RetailCrm\Repository\FileRepository;
|
||||
use Intaro\RetailCrm\Repository\HlRepository;
|
||||
use Intaro\RetailCrm\Repository\MeasureRepository;
|
||||
use Intaro\RetailCrm\Repository\SiteRepository;
|
||||
|
||||
/**
|
||||
* Class XmlOfferDirector
|
||||
* @package Intaro\RetailCrm\Icml
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* XmlOfferFactory constructor.
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetup $setup
|
||||
*/
|
||||
public function __construct(XmlSetup $setup)
|
||||
{
|
||||
$this->setup = $setup;
|
||||
$this->fileRepository = new FileRepository(SiteRepository::getDefaultServerName());
|
||||
$this->catalogRepository = new CatalogRepository();
|
||||
$this->xmlOfferBuilder = new XmlOfferBuilder(
|
||||
$setup,
|
||||
MeasureRepository::getMeasures(),
|
||||
SiteRepository::getDefaultServerName()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает страницу (массив) с товарами или торговыми предложениями (в зависимости от $param)
|
||||
*
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $param
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo
|
||||
* @return XmlOffer[]
|
||||
*/
|
||||
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']));
|
||||
|
||||
$offers[] = $this->xmlOfferBuilder->build();
|
||||
}
|
||||
|
||||
return $offers;
|
||||
}
|
||||
|
||||
/**
|
||||
* возвращает массив XmlOffers для конкретного продукта
|
||||
*
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $paramsForOffer
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer $product
|
||||
* @return XmlOffer[]
|
||||
*/
|
||||
public function getXmlOffersBySingleProduct(
|
||||
SelectParams $paramsForOffer,
|
||||
CatalogIblockInfo $catalogIblockInfo,
|
||||
XmlOffer $product
|
||||
): array {
|
||||
$xmlOffers = $this->getXmlOffersPart($paramsForOffer, $catalogIblockInfo);
|
||||
|
||||
return $this->addProductInfo($xmlOffers, $product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Декорирует оферы информацией из товаров
|
||||
*
|
||||
* @param XmlOffer[] $xmlOffers
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer $product
|
||||
* @return \Intaro\RetailCrm\Model\Bitrix\Xml\XmlOffer[]
|
||||
*/
|
||||
private function addProductInfo(array $xmlOffers, XmlOffer $product): array
|
||||
{
|
||||
foreach ($xmlOffers as $offer) {
|
||||
$offer->productId = $product->id;
|
||||
$offer->params = array_merge($offer->params, $product->params);
|
||||
$offer->unitCode = $offer->unitCode === null ? null : $offer->unitCode->merge($product->unitCode);
|
||||
$offer->vatRate = $offer->vatRate === 'none' ? $product->vatRate : $offer->vatRate;
|
||||
$offer->vendor = $offer->mergeValues($product->vendor, $offer->vendor);
|
||||
$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->categoryIds = $product->categoryIds;
|
||||
$offer->productName = $product->productName;
|
||||
}
|
||||
|
||||
return $xmlOffers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение настраиваемых параметров, если они лежат в HL-блоке
|
||||
*
|
||||
* @param int $iblockId //ID инфоблока товаров, даже если данные нужны по SKU
|
||||
* @param array $productProps
|
||||
* @param array $configurableParams
|
||||
* @param array $hls
|
||||
* @return array
|
||||
*/
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
): 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,
|
||||
$product,
|
||||
$param->configurable,
|
||||
$this->setup->properties->highloadblockProduct
|
||||
));
|
||||
|
||||
//достаем значения из HL блоков торговых предложений
|
||||
$this->xmlOfferBuilder->setSkuHlParams($this->getHlParams(
|
||||
$catalogIblockInfo->productIblockId,
|
||||
$product,
|
||||
$param->configurable,
|
||||
$this->setup->properties->highloadblockSku
|
||||
));
|
||||
$this->xmlOfferBuilder->setSelectParams($param);
|
||||
$this->xmlOfferBuilder->setOfferProps($product);
|
||||
$this->xmlOfferBuilder->setBarcode($barcodes[$product['ID']] ?? '');
|
||||
$this->xmlOfferBuilder->setCatalogIblockInfo($catalogIblockInfo);
|
||||
$this->xmlOfferBuilder->setPicturesPath(
|
||||
$this
|
||||
->fileRepository
|
||||
->getProductPicture($product, $pictureProperty ?? '')
|
||||
);
|
||||
}
|
||||
}
|
13
intaro.retailcrm/lib/lang/ru/icml/xmlofferbuilder.php
Normal file
13
intaro.retailcrm/lib/lang/ru/icml/xmlofferbuilder.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
$MESS['ROOT_CATEGORY_FOR_CATALOG'] = "Корневой раздел для каталога \"%s\"";
|
||||
$MESS['PARAM_NAME_article'] = 'Артикул';
|
||||
$MESS['PARAM_NAME_manufacturer'] = 'Производитель';
|
||||
$MESS['PARAM_NAME_color'] = 'Цвет';
|
||||
$MESS['PARAM_NAME_weight'] = 'Вес (габариты)';
|
||||
$MESS['PARAM_NAME_length'] = 'Длина (габариты)';
|
||||
$MESS['PARAM_NAME_width'] = 'Ширина (габариты)';
|
||||
$MESS['PARAM_NAME_height'] = 'Высота (габариты)';
|
||||
$MESS['PARAM_NAME_picture'] = 'Фото';
|
||||
$MESS['PARAM_NAME_size'] = 'Размер';
|
||||
$MESS['UNIT_ERROR'] = 'Ошибка получения unit кода';
|
32
intaro.retailcrm/lib/model/bitrix/orm/catalogiblockinfo.php
Normal file
32
intaro.retailcrm/lib/model/bitrix/orm/catalogiblockinfo.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Orm;
|
||||
|
||||
/**
|
||||
* Class CatalogIblockInfo
|
||||
* @package Intaro\RetailCrm\Model\Bitrix\Orm
|
||||
*/
|
||||
class CatalogIblockInfo
|
||||
{
|
||||
/**
|
||||
* ID инфоблока торговых предложений
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $skuIblockId;
|
||||
|
||||
/**
|
||||
* ID инфоблока товаров
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $productIblockId;
|
||||
|
||||
/**
|
||||
* ID свойства привязки торговых предложений к товарам
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $skuPropertyId;
|
||||
}
|
94
intaro.retailcrm/lib/model/bitrix/orm/iblockcatalog.php
Normal file
94
intaro.retailcrm/lib/model/bitrix/orm/iblockcatalog.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Orm;
|
||||
|
||||
use Bitrix\Main,
|
||||
Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\Entity\BooleanField;
|
||||
use Bitrix\Main\Entity\IntegerField;
|
||||
use Bitrix\Main\Entity\ReferenceField;
|
||||
|
||||
Loc::loadMessages(__FILE__);
|
||||
|
||||
/**
|
||||
* Class IblockCatalogTable
|
||||
*
|
||||
* Fields:
|
||||
* <ul>
|
||||
* <li> IBLOCK_ID int mandatory
|
||||
* <li> YANDEX_EXPORT bool optional default 'N'
|
||||
* <li> SUBSCRIPTION bool optional default 'N'
|
||||
* <li> VAT_ID int optional
|
||||
* <li> PRODUCT_IBLOCK_ID int mandatory
|
||||
* <li> SKU_PROPERTY_ID int mandatory
|
||||
* <li> VAT reference to {@link \Bitrix\Catalog\CatalogVatTable}
|
||||
* <li> IBLOCK reference to {@link \Bitrix\Iblock\IblockTable}
|
||||
* <li> PRODUCT_IBLOCK reference to {@link \Bitrix\Iblock\IblockTable}
|
||||
* <li> SKU_PROPERTY reference to {@link \Bitrix\Iblock\IblockPropertyTable}
|
||||
* </ul>
|
||||
*
|
||||
* @package Bitrix\Catalog
|
||||
**/
|
||||
class IblockCatalogTable extends Main\Entity\DataManager
|
||||
{
|
||||
/**
|
||||
* Returns DB table name for entity.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getTableName()
|
||||
{
|
||||
return 'b_catalog_iblock';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns entity map definition.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public static function getMap(): ?array
|
||||
{
|
||||
try {
|
||||
return [
|
||||
new IntegerField('IBLOCK_ID'),
|
||||
new BooleanField('YANDEX_EXPORT'),
|
||||
new BooleanField('SUBSCRIPTION'),
|
||||
new IntegerField('VAT_ID'),
|
||||
new IntegerField('PRODUCT_IBLOCK_ID'),
|
||||
new IntegerField('SKU_PROPERTY_ID'),
|
||||
new ReferenceField(
|
||||
'VAT',
|
||||
'Bitrix\Catalog\CatalogVat',
|
||||
['=this.VAT_ID' => 'ref.ID']
|
||||
),
|
||||
new ReferenceField(
|
||||
'IBLOCK',
|
||||
'Bitrix\Iblock\Iblock',
|
||||
['=this.IBLOCK_ID' => 'ref.ID']
|
||||
),
|
||||
new ReferenceField(
|
||||
'PRODUCT_IBLOCK',
|
||||
'Bitrix\Iblock\Iblock',
|
||||
['=this.PRODUCT_IBLOCK_ID' => 'ref.ID']
|
||||
),
|
||||
new ReferenceField(
|
||||
'SKU_PROPERTY',
|
||||
'Bitrix\Iblock\IblockProperty',
|
||||
['=this.SKU_PROPERTY_ID' => 'ref.ID']
|
||||
),
|
||||
new ReferenceField(
|
||||
'SECTION',
|
||||
'Bitrix\Iblock\IblockSection',
|
||||
['=this.IBLOCK_ID' => 'ref.IBLOCK_ID']
|
||||
),
|
||||
new ReferenceField(
|
||||
'OFFERS_IBLOCK',
|
||||
'Bitrix\Iblock\IblockSection',
|
||||
['=this.IBLOCK_ID' => 'this.ID']
|
||||
),
|
||||
];
|
||||
} catch (Main\ArgumentException | Main\SystemException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
34
intaro.retailcrm/lib/model/bitrix/xml/offerparam.php
Normal file
34
intaro.retailcrm/lib/model/bitrix/xml/offerparam.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @category Integration
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
* @author RetailCRM <integration@retailcrm.ru>
|
||||
* @license MIT
|
||||
* @link http://retailcrm.ru
|
||||
* @see http://retailcrm.ru/docs
|
||||
*/
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Xml;
|
||||
|
||||
/**
|
||||
* Class OfferParam
|
||||
* @package Intaro\RetailCrm\Model\Bitrix\Xml
|
||||
*/
|
||||
class OfferParam
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $code;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $value;
|
||||
}
|
54
intaro.retailcrm/lib/model/bitrix/xml/selectparams.php
Normal file
54
intaro.retailcrm/lib/model/bitrix/xml/selectparams.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @category Integration
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
* @author RetailCRM <integration@retailcrm.ru>
|
||||
* @license MIT
|
||||
* @link http://retailcrm.ru
|
||||
* @see http://retailcrm.ru/docs
|
||||
*/
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Xml;
|
||||
|
||||
/**
|
||||
* Class SelectParams
|
||||
* @package Intaro\RetailCrm\Model\Bitrix\Xml
|
||||
*/
|
||||
class SelectParams
|
||||
{
|
||||
/**
|
||||
* конфигурируемые свойства
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $configurable;
|
||||
|
||||
/**
|
||||
* обязательные свойства
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $main;
|
||||
|
||||
/**
|
||||
* номер запрашиваемой страницы
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $pageNumber;
|
||||
|
||||
/**
|
||||
* количество товаров на странице
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $nPageSize;
|
||||
|
||||
/**
|
||||
* id товара у торогового предложения, если запрашивается SKU
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $parentId;
|
||||
}
|
51
intaro.retailcrm/lib/model/bitrix/xml/unit.php
Normal file
51
intaro.retailcrm/lib/model/bitrix/xml/unit.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @category Integration
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
* @author RetailCRM <integration@retailcrm.ru>
|
||||
* @license MIT
|
||||
* @link http://retailcrm.ru
|
||||
* @see http://retailcrm.ru/docs
|
||||
*/
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Xml;
|
||||
|
||||
/**
|
||||
* единица измерения для товара, элемент не является обязательным в icml
|
||||
*
|
||||
* Class Unit
|
||||
* @package Intaro\RetailCrm\Model\Bitrix\Xml
|
||||
*/
|
||||
class Unit
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $code;
|
||||
|
||||
/**
|
||||
* единица измерения товара
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $sym;
|
||||
|
||||
/**
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\Unit|null $unitCode
|
||||
* @return \Intaro\RetailCrm\Model\Bitrix\Xml\Unit
|
||||
*/
|
||||
public function merge(?Unit $unitCode): Unit
|
||||
{
|
||||
if ($this->code === null && $unitCode !== null) {
|
||||
return $unitCode;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
39
intaro.retailcrm/lib/model/bitrix/xml/xmlcategory.php
Normal file
39
intaro.retailcrm/lib/model/bitrix/xml/xmlcategory.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @category Integration
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
* @author RetailCRM <integration@retailcrm.ru>
|
||||
* @license MIT
|
||||
* @link http://retailcrm.ru
|
||||
* @see http://retailcrm.ru/docs
|
||||
*/
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Xml;
|
||||
|
||||
/**
|
||||
* Class XmlCategory
|
||||
*/
|
||||
class XmlCategory
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $parentId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $picture;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
}
|
39
intaro.retailcrm/lib/model/bitrix/xml/xmldata.php
Normal file
39
intaro.retailcrm/lib/model/bitrix/xml/xmldata.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @category Integration
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
* @author RetailCRM <integration@retailcrm.ru>
|
||||
* @license MIT
|
||||
* @link http://retailcrm.ru
|
||||
* @see http://retailcrm.ru/docs
|
||||
*/
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Xml;
|
||||
|
||||
/**
|
||||
* Class XmlData
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
*/
|
||||
class XmlData
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $shopName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $company;
|
||||
|
||||
/**
|
||||
* @var \Intaro\RetailCrm\Model\Bitrix\Xml\XmlCategory[]
|
||||
*/
|
||||
public $categories;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $filePath;
|
||||
}
|
131
intaro.retailcrm/lib/model/bitrix/xml/xmloffer.php
Normal file
131
intaro.retailcrm/lib/model/bitrix/xml/xmloffer.php
Normal file
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @category Integration
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
* @author RetailCRM <integration@retailcrm.ru>
|
||||
* @license MIT
|
||||
* @link http://retailcrm.ru
|
||||
* @see http://retailcrm.ru/docs
|
||||
*/
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Xml;
|
||||
|
||||
/**
|
||||
* Class XmlOffer
|
||||
* @package Intaro\RetailCrm\Model\Bitrix\Xml
|
||||
*/
|
||||
class XmlOffer
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $productId;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $quantity;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $picture;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $url;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
public $price;
|
||||
|
||||
/**
|
||||
* Категории, к которым относится товар
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $categoryIds;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $xmlId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $productName;
|
||||
|
||||
/**
|
||||
* @var OfferParam[]
|
||||
*/
|
||||
public $params;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $vendor;
|
||||
|
||||
/**
|
||||
* @var Unit
|
||||
*/
|
||||
public $unitCode;
|
||||
|
||||
/**
|
||||
* ставка налога (НДС)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $vatRate;
|
||||
|
||||
/**
|
||||
* штрих-код
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $barcode;
|
||||
|
||||
/**
|
||||
* Закупочная цена
|
||||
*
|
||||
* @var mixed|null
|
||||
*/
|
||||
public $purchasePrice;
|
||||
|
||||
/**
|
||||
* Вес товара
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $weight;
|
||||
|
||||
/**
|
||||
* Габариты товара
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $dimensions;
|
||||
|
||||
/**
|
||||
* @param $productValue
|
||||
* @param $offerValue
|
||||
* @return mixed
|
||||
*/
|
||||
public function mergeValues($productValue, $offerValue)
|
||||
{
|
||||
return empty($offerValue) ? $productValue : $offerValue;
|
||||
}
|
||||
}
|
74
intaro.retailcrm/lib/model/bitrix/xml/xmlsetup.php
Normal file
74
intaro.retailcrm/lib/model/bitrix/xml/xmlsetup.php
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @category Integration
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
* @author RetailCRM <integration@retailcrm.ru>
|
||||
* @license MIT
|
||||
* @link http://retailcrm.ru
|
||||
* @see http://retailcrm.ru/docs
|
||||
*/
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Xml;
|
||||
|
||||
/**
|
||||
* Class XmlSetup
|
||||
* @package Intaro\RetailCrm\Model\Bitrix\Xml
|
||||
*/
|
||||
class XmlSetup
|
||||
{
|
||||
/**
|
||||
* XmlSetup constructor.
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupPropsCategories $xmlProps
|
||||
*/
|
||||
public function __construct(XmlSetupPropsCategories $xmlProps)
|
||||
{
|
||||
$this->properties = $xmlProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $profileId;
|
||||
|
||||
/**
|
||||
* id инфоблоков, которые подлежат экспорту - IBLOCK_EXPORT
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $iblocksForExport;
|
||||
|
||||
/**
|
||||
* Путь, по которому сохраняется xml - SETUP_FILE_NAME
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $filePath;
|
||||
|
||||
/**
|
||||
* синхронизируемые свойства
|
||||
*
|
||||
* @var \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupPropsCategories
|
||||
*/
|
||||
public $properties;
|
||||
|
||||
/**
|
||||
* максимальное количество торговых предложений у товара - MAX_OFFERS_VALUE
|
||||
*
|
||||
* @var null|int
|
||||
*/
|
||||
public $maxOffersValue;
|
||||
|
||||
/**
|
||||
* выгружать ли закупочную цену
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $loadPurchasePrice;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
public $basePriceId;
|
||||
}
|
55
intaro.retailcrm/lib/model/bitrix/xml/xmlsetupprops.php
Normal file
55
intaro.retailcrm/lib/model/bitrix/xml/xmlsetupprops.php
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @category Integration
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
* @author RetailCRM <integration@retailcrm.ru>
|
||||
* @license MIT
|
||||
* @link http://retailcrm.ru
|
||||
* @see http://retailcrm.ru/docs
|
||||
*/
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Xml;
|
||||
|
||||
/**
|
||||
* Class XmlSetupProps
|
||||
*
|
||||
* @package Intaro\RetailCrm\Model\Bitrix\Xml
|
||||
*/
|
||||
class XmlSetupProps
|
||||
{
|
||||
/**
|
||||
* XmlSetupProps constructor.
|
||||
* @param array $names
|
||||
* @param array $units
|
||||
* @param array|null $pictures
|
||||
*/
|
||||
public function __construct(array $names, array $units, ?array $pictures)
|
||||
{
|
||||
$this->names = $names;
|
||||
$this->units = $units;
|
||||
$this->pictures = $pictures;
|
||||
}
|
||||
|
||||
/**
|
||||
* названия свойств
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $names;
|
||||
|
||||
/**
|
||||
* меры измерения
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $units;
|
||||
|
||||
/**
|
||||
* свойства, из которых нужно брать картинки
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $pictures;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* PHP version 7.1
|
||||
*
|
||||
* @category Integration
|
||||
* @package Intaro\RetailCrm\Model\Bitrix
|
||||
* @author RetailCRM <integration@retailcrm.ru>
|
||||
* @license MIT
|
||||
* @link http://retailcrm.ru
|
||||
* @see http://retailcrm.ru/docs
|
||||
*/
|
||||
namespace Intaro\RetailCrm\Model\Bitrix\Xml;
|
||||
|
||||
/**
|
||||
* Class XmlSetupProps
|
||||
* @package Intaro\RetailCrm\Model\Bitrix\Xml
|
||||
*/
|
||||
class XmlSetupPropsCategories
|
||||
{
|
||||
/**
|
||||
* XmlSetupPropsCategories constructor.
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupProps $products
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\XmlSetupProps $sku
|
||||
*/
|
||||
public function __construct(XmlSetupProps $products, XmlSetupProps $sku)
|
||||
{
|
||||
$this->products = $products;
|
||||
$this->sku = $sku;
|
||||
}
|
||||
|
||||
/**
|
||||
* Синхронизируемые свойства товаров
|
||||
*
|
||||
* @var XmlSetupProps
|
||||
*/
|
||||
public $products;
|
||||
|
||||
/**
|
||||
* Синхронизируемые свойства торговых предложений
|
||||
*
|
||||
* @var XmlSetupProps
|
||||
*/
|
||||
public $sku;
|
||||
|
||||
/**
|
||||
* Синхронизируемые свойства торговых предложений, находящиеся в HL блоках
|
||||
*
|
||||
* массив с названиями HL блоков, элементы которого содержат,
|
||||
* синхронизируемые св-ва
|
||||
*
|
||||
* @var array[][]
|
||||
*/
|
||||
public $highloadblockSku;
|
||||
|
||||
/**
|
||||
* Синхрозируемые свойства товаров, находящиеся в HL блоках
|
||||
*
|
||||
* массив с названиями HL блоков, элементы которого содержат,
|
||||
* синхронизируемые св-ва
|
||||
*
|
||||
* @var array[][]
|
||||
*/
|
||||
public $highloadblockProduct;
|
||||
}
|
179
intaro.retailcrm/lib/repository/catalogrepository.php
Normal file
179
intaro.retailcrm/lib/repository/catalogrepository.php
Normal file
|
@ -0,0 +1,179 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Repository;
|
||||
|
||||
use Bitrix\Iblock\IblockTable;
|
||||
use Bitrix\Iblock\SectionTable;
|
||||
use Bitrix\Main\ArgumentException;
|
||||
use Bitrix\Main\ObjectPropertyException;
|
||||
use Bitrix\Main\ORM\Objectify\Collection;
|
||||
use Bitrix\Main\ORM\Objectify\EntityObject;
|
||||
use Bitrix\Main\SystemException;
|
||||
use CCatalogGroup;
|
||||
use CCatalogSku;
|
||||
use CCatalogStoreBarCode;
|
||||
use CIBlockElement;
|
||||
use Intaro\RetailCrm\Icml\QueryParamsMolder;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo;
|
||||
use Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams;
|
||||
use RetailcrmConfigProvider;
|
||||
|
||||
/**
|
||||
* Class CatalogRepository
|
||||
* @package Intaro\RetailCrm\Repository
|
||||
*/
|
||||
class CatalogRepository
|
||||
{
|
||||
/**
|
||||
* @var \Intaro\RetailCrm\Icml\QueryParamsMolder
|
||||
*/
|
||||
private $builder;
|
||||
|
||||
/**
|
||||
* CatalogRepository constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->builder = new QueryParamsMolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение категорий, к которым относится товар
|
||||
*
|
||||
* @param int $offerId
|
||||
* @return array
|
||||
*/
|
||||
public function getProductCategoriesIds(int $offerId): array
|
||||
{
|
||||
$query = CIBlockElement::GetElementGroups($offerId, false, ['ID']);
|
||||
$ids = [];
|
||||
|
||||
while ($category = $query->GetNext()) {
|
||||
$ids[] = $category['ID'];
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns products IDs with barcodes by infoblock id
|
||||
*
|
||||
* @param int $iblockId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getProductBarcodesByIblockId(int $iblockId): 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'];
|
||||
}
|
||||
}
|
||||
|
||||
return $barcodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Xml\SelectParams $param
|
||||
* @param \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo $catalogIblockInfo
|
||||
* @return \CIBlockResult|int
|
||||
*/
|
||||
public function getProductPage(SelectParams $param, CatalogIblockInfo $catalogIblockInfo)
|
||||
{
|
||||
return CIBlockElement::GetList(
|
||||
[],
|
||||
$this->builder->getWhereForOfferPart($param->parentId, $catalogIblockInfo),
|
||||
false,
|
||||
['nPageSize' => $param->nPageSize, 'iNumPage' => $param->pageNumber, 'checkOutOfRange' => true],
|
||||
array_merge($param->configurable, $param->main)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iblockId
|
||||
* @return \Bitrix\Main\ORM\Objectify\Collection|null
|
||||
*/
|
||||
public function getCategoriesByIblockId(int $iblockId): ?Collection
|
||||
{
|
||||
try {
|
||||
return SectionTable::query()
|
||||
->addSelect('*')
|
||||
->where('IBLOCK_ID', $iblockId)
|
||||
->fetchCollection();
|
||||
} catch (ObjectPropertyException | ArgumentException | SystemException $exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $iblockId
|
||||
* @return EntityObject|null
|
||||
*/
|
||||
public function getIblockById($iblockId): ?EntityObject
|
||||
{
|
||||
try {
|
||||
return IblockTable::query()
|
||||
->where('ID', $iblockId)
|
||||
->fetchObject();
|
||||
} catch (ObjectPropertyException | ArgumentException | SystemException $exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает информацию об инфоблоке торговых предложений по ID инфоблока товаров
|
||||
*
|
||||
* @param int $productIblockId
|
||||
* @return \Intaro\RetailCrm\Model\Bitrix\Orm\CatalogIblockInfo
|
||||
*/
|
||||
public function getCatalogIblockInfo(int $productIblockId): CatalogIblockInfo
|
||||
{
|
||||
$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
|
||||
*/
|
||||
public static function getBasePriceId(?int $profileId): int
|
||||
{
|
||||
$basePriceId = RetailcrmConfigProvider::getCatalogBasePriceByProfile($profileId);
|
||||
|
||||
if (!$basePriceId) {
|
||||
$dbPriceType = CCatalogGroup::GetList(
|
||||
[],
|
||||
['BASE' => 'Y'],
|
||||
false,
|
||||
false,
|
||||
['ID']
|
||||
);
|
||||
|
||||
$result = $dbPriceType->GetNext();
|
||||
return $result['ID'];
|
||||
}
|
||||
|
||||
return $basePriceId;
|
||||
}
|
||||
}
|
67
intaro.retailcrm/lib/repository/filerepository.php
Normal file
67
intaro.retailcrm/lib/repository/filerepository.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Repository;
|
||||
|
||||
use CFile;
|
||||
|
||||
/**
|
||||
* Class FileRepository
|
||||
* @package Intaro\RetailCrm\Repository
|
||||
*/
|
||||
class FileRepository
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $defaultServerName;
|
||||
|
||||
/**
|
||||
* FileRepository constructor.
|
||||
* @param string $defaultServerName
|
||||
*/
|
||||
public function __construct(string $defaultServerName)
|
||||
{
|
||||
$this->defaultServerName = $defaultServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $fileId
|
||||
* @return string
|
||||
*/
|
||||
public function getImageUrl(?int $fileId): string
|
||||
{
|
||||
if (!$fileId) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$pathImage = CFile::GetPath($fileId);
|
||||
$validation = '/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i';
|
||||
|
||||
if ((bool) preg_match($validation, $pathImage) === false) {
|
||||
return $this->defaultServerName . $pathImage;
|
||||
}
|
||||
|
||||
return $pathImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $product
|
||||
* @param string $pictureProp
|
||||
* @return string
|
||||
*/
|
||||
public function getProductPicture(array $product, string $pictureProp = ''): string
|
||||
{
|
||||
$picture = '';
|
||||
$pictureId = $product['PROPERTY_' . $pictureProp . '_VALUE'] ?? null;
|
||||
|
||||
if (isset($product['DETAIL_PICTURE'])) {
|
||||
$picture = $this->getImageUrl($product['DETAIL_PICTURE']);
|
||||
} elseif (isset($product['PREVIEW_PICTURE'])) {
|
||||
$picture = $this->getImageUrl($product['PREVIEW_PICTURE']);
|
||||
} elseif ($pictureId !== null) {
|
||||
$picture = $this->getImageUrl($pictureId);
|
||||
}
|
||||
|
||||
return $picture ?? '';
|
||||
}
|
||||
}
|
56
intaro.retailcrm/lib/repository/hlrepository.php
Normal file
56
intaro.retailcrm/lib/repository/hlrepository.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Repository;
|
||||
|
||||
use Bitrix\Main\ArgumentException;
|
||||
use Bitrix\Main\ObjectPropertyException;
|
||||
use Bitrix\Main\SystemException;
|
||||
use Intaro\RetailCrm\Service\Hl;
|
||||
|
||||
/**
|
||||
* Class HlRepository
|
||||
* @package Intaro\RetailCrm\Repository
|
||||
*/
|
||||
class HlRepository
|
||||
{
|
||||
/**
|
||||
* @var \Bitrix\Main\Entity\DataManager|string|null
|
||||
*/
|
||||
private $hl;
|
||||
|
||||
public function __construct($hlName)
|
||||
{
|
||||
$this->hl = Hl::getHlClassByTableName($hlName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $propertyValue
|
||||
* @return array|null
|
||||
*/
|
||||
public function getDataByXmlId(?string $propertyValue): ?array
|
||||
{
|
||||
try {
|
||||
$result = $this->hl::query()
|
||||
->setSelect(['*'])
|
||||
->where('UF_XML_ID', '=', $propertyValue)
|
||||
->fetch();
|
||||
|
||||
if ($result === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
} catch (ObjectPropertyException | ArgumentException | SystemException $exception) {
|
||||
AddMessage2Log($exception->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Bitrix\Main\Entity\DataManager|string|null
|
||||
*/
|
||||
public function getHl()
|
||||
{
|
||||
return $this->hl;
|
||||
}
|
||||
}
|
29
intaro.retailcrm/lib/repository/measurerepository.php
Normal file
29
intaro.retailcrm/lib/repository/measurerepository.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Repository;
|
||||
|
||||
use CCatalogMeasure;
|
||||
|
||||
/**
|
||||
* Class MeasureRepository
|
||||
* @package Intaro\RetailCrm\Repository
|
||||
*/
|
||||
class MeasureRepository
|
||||
{
|
||||
/**
|
||||
* Получает доступные в Битриксе единицы измерения для товаров
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getMeasures(): array
|
||||
{
|
||||
$measures = [];
|
||||
$resMeasure = CCatalogMeasure::getList();
|
||||
|
||||
while ($measure = $resMeasure->Fetch()) {
|
||||
$measures[$measure['ID']] = $measure;
|
||||
}
|
||||
|
||||
return $measures;
|
||||
}
|
||||
}
|
29
intaro.retailcrm/lib/repository/siterepository.php
Normal file
29
intaro.retailcrm/lib/repository/siterepository.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Repository;
|
||||
|
||||
use CSite;
|
||||
use RetailcrmConfigProvider;
|
||||
|
||||
/**
|
||||
* Class SiteRepository
|
||||
* @package Intaro\RetailCrm\Repository
|
||||
*/
|
||||
class SiteRepository
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function getDefaultServerName(): ?string
|
||||
{
|
||||
$rsSites = CSite::GetList($by, $sort, ['ACTIVE' => 'Y']);
|
||||
|
||||
while ($ar = $rsSites->Fetch()) {
|
||||
if ($ar['DEF'] === 'Y') {
|
||||
return RetailcrmConfigProvider::getProtocol() . $ar['SERVER_NAME'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
76
intaro.retailcrm/lib/service/hl.php
Normal file
76
intaro.retailcrm/lib/service/hl.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace Intaro\RetailCrm\Service;
|
||||
|
||||
use Bitrix\Main\ArgumentException;
|
||||
use Bitrix\Main\Entity\DataManager;
|
||||
use Bitrix\Main\Loader;
|
||||
use Bitrix\Highloadblock as Highloadblock;
|
||||
use Bitrix\Main\LoaderException;
|
||||
use Bitrix\Main\ObjectPropertyException;
|
||||
use Bitrix\Main\SystemException;
|
||||
|
||||
/**
|
||||
* Class Hl
|
||||
*
|
||||
* Позволяет получить DataManager для HL-блоков
|
||||
*
|
||||
* @package Intaro\RetailCrm\Service
|
||||
*/
|
||||
class Hl
|
||||
{
|
||||
/**
|
||||
* Получение DataManager класса управления HLBlock
|
||||
*
|
||||
* @param int $HlBlockId
|
||||
* @return \Bitrix\Main\Entity\DataManager|null
|
||||
* @throws \Bitrix\Main\ArgumentException
|
||||
* @throws \Bitrix\Main\LoaderException
|
||||
* @throws \Bitrix\Main\ObjectPropertyException
|
||||
* @throws \Bitrix\Main\SystemException
|
||||
*/
|
||||
public static function getHlClassById(int $HlBlockId): ?DataManager
|
||||
{
|
||||
Loader::includeModule('highloadblock');
|
||||
|
||||
$hlblock = Highloadblock\HighloadBlockTable::getById($HlBlockId)->fetch();
|
||||
|
||||
if (!$hlblock) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$entity = Highloadblock\HighloadBlockTable::compileEntity($hlblock);
|
||||
|
||||
return $entity->getDataClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение DataManager класса управления HLBlock по названию таблицы
|
||||
*
|
||||
* @param string $name
|
||||
* @return \Bitrix\Main\Entity\DataManager|string|null
|
||||
*/
|
||||
public static function getHlClassByTableName(string $name)
|
||||
{
|
||||
try {
|
||||
Loader::includeModule('highloadblock');
|
||||
|
||||
$hlblock = Highloadblock\HighloadBlockTable::query()
|
||||
->addSelect('*')
|
||||
->where('TABLE_NAME', '=', $name)
|
||||
->exec()
|
||||
->fetch();
|
||||
|
||||
if (!$hlblock) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$entity = Highloadblock\HighloadBlockTable::compileEntity($hlblock);
|
||||
|
||||
return $entity->getDataClass();
|
||||
} catch (ObjectPropertyException | ArgumentException | SystemException | LoaderException $exception) {
|
||||
AddMessage2Log($exception->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
19
intaro.retailcrm/lib/vendor/symfony/component/process/LICENSE
vendored
Normal file
19
intaro.retailcrm/lib/vendor/symfony/component/process/LICENSE
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2004-2021 Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
86
intaro.retailcrm/lib/vendor/symfony/component/process/executablefinder.php
vendored
Normal file
86
intaro.retailcrm/lib/vendor/symfony/component/process/executablefinder.php
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Intaro\RetailCrm\Vendor\Symfony\Component\Process;
|
||||
|
||||
/**
|
||||
* Generic executable finder.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class ExecutableFinder
|
||||
{
|
||||
private $suffixes = ['.exe', '.bat', '.cmd', '.com'];
|
||||
|
||||
/**
|
||||
* Replaces default suffixes of executable.
|
||||
*/
|
||||
public function setSuffixes(array $suffixes)
|
||||
{
|
||||
$this->suffixes = $suffixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new possible suffix to check for executable.
|
||||
*/
|
||||
public function addSuffix(string $suffix)
|
||||
{
|
||||
$this->suffixes[] = $suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an executable by name.
|
||||
*
|
||||
* @param string $name The executable name (without the extension)
|
||||
* @param string|null $default The default to return if no executable is found
|
||||
* @param array $extraDirs Additional dirs to check into
|
||||
*
|
||||
* @return string|null The executable path or default value
|
||||
*/
|
||||
public function find(string $name, string $default = null, array $extraDirs = []): ?string
|
||||
{
|
||||
if (ini_get('open_basedir')) {
|
||||
$searchPath = array_merge(explode(\PATH_SEPARATOR, ini_get('open_basedir')), $extraDirs);
|
||||
$dirs = [];
|
||||
foreach ($searchPath as $path) {
|
||||
// Silencing against https://bugs.php.net/69240
|
||||
if (@is_dir($path)) {
|
||||
$dirs[] = $path;
|
||||
} else {
|
||||
if (basename($path) == $name && @is_executable($path)) {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$dirs = array_merge(
|
||||
explode(\PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
|
||||
$extraDirs
|
||||
);
|
||||
}
|
||||
|
||||
$suffixes = [''];
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
$pathExt = getenv('PATHEXT');
|
||||
$suffixes = array_merge($pathExt ? explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
|
||||
}
|
||||
foreach ($suffixes as $suffix) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (@is_file($file = $dir.\DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === \DIRECTORY_SEPARATOR || @is_executable($file))) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
}
|
99
intaro.retailcrm/lib/vendor/symfony/component/process/phpexecutablefinder.php
vendored
Normal file
99
intaro.retailcrm/lib/vendor/symfony/component/process/phpexecutablefinder.php
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Intaro\RetailCrm\Vendor\Symfony\Component\Process;
|
||||
|
||||
/**
|
||||
* An executable finder specifically designed for the PHP executable.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class PhpExecutableFinder
|
||||
{
|
||||
private $executableFinder;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->executableFinder = new ExecutableFinder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds The PHP executable.
|
||||
*
|
||||
* @return string|false The PHP executable path or false if it cannot be found
|
||||
*/
|
||||
public function find(bool $includeArgs = true)
|
||||
{
|
||||
if ($php = getenv('PHP_BINARY')) {
|
||||
if (!is_executable($php)) {
|
||||
$command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v';
|
||||
if ($php = strtok(exec($command.' '.escapeshellarg($php)), \PHP_EOL)) {
|
||||
if (!is_executable($php)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $php;
|
||||
}
|
||||
|
||||
$args = $this->findArguments();
|
||||
$args = $includeArgs && $args ? ' '.implode(' ', $args) : '';
|
||||
|
||||
// PHP_BINARY return the current sapi executable
|
||||
if (\PHP_BINARY && \in_array(\PHP_SAPI, ['cgi-fcgi', 'cli', 'cli-server', 'phpdbg'], true)) {
|
||||
return \PHP_BINARY.$args;
|
||||
}
|
||||
|
||||
if ($php = getenv('PHP_PATH')) {
|
||||
if (!@is_executable($php)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $php;
|
||||
}
|
||||
|
||||
if ($php = getenv('PHP_PEAR_PHP_BIN')) {
|
||||
if (@is_executable($php)) {
|
||||
return $php;
|
||||
}
|
||||
}
|
||||
|
||||
if (@is_executable($php = \PHP_BINDIR.('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
|
||||
return $php;
|
||||
}
|
||||
|
||||
$dirs = [\PHP_BINDIR];
|
||||
if ('\\' === \DIRECTORY_SEPARATOR) {
|
||||
$dirs[] = 'C:\xampp\php\\';
|
||||
}
|
||||
|
||||
return $this->executableFinder->find('php', false, $dirs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the PHP executable arguments.
|
||||
*
|
||||
* @return array The PHP executable arguments
|
||||
*/
|
||||
public function findArguments(): array
|
||||
{
|
||||
$arguments = [];
|
||||
if ('phpdbg' === \PHP_SAPI) {
|
||||
$arguments[] = '-qrr';
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Class RetailCrmOrderTest
|
||||
*/
|
||||
use \Bitrix\Main\Loader;
|
||||
|
||||
class RetailCrmICMLTest extends BitrixTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
COption::SetOptionString('intaro.retailcrm', 'api_version', 'v5');
|
||||
CModule::IncludeModule('intaro.retailcrm');
|
||||
}
|
||||
|
||||
public function testModuleInstalled()
|
||||
{
|
||||
$this->assertTrue(Loader::includeModule("intaro.retailcrm"));
|
||||
}
|
||||
|
||||
public function testGetImageUrl()
|
||||
{
|
||||
$test = new RetailCrmICML();
|
||||
$result = $test->getImageUrl(1);
|
||||
|
||||
if (!empty($result)) {
|
||||
$this->assertIsString($result);
|
||||
$this->assertEquals("/upload/iblock/c44/test.jpg", $result);
|
||||
} else {
|
||||
$this->assertEmpty($result);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue