Your IP : 3.129.25.152
<?php
namespace Bitrix\Catalog\Product;
use Bitrix\Main,
Bitrix\Catalog,
Bitrix\Iblock,
Bitrix\Sale,
Bitrix\Currency;
if (Main\Loader::includeModule('sale'))
{
/**
* Class CatalogProvider
*
* @package Bitrix\Catalog\Product
*/
class CatalogProvider
extends Sale\SaleProviderBase
{
private static $userCache = array();
protected static $hitCache = array();
protected static $priceTitleCache = array();
protected static $clearAutoCache = array();
protected $enableCache = true;
const CACHE_USER_GROUPS = 'USER_GROUPS';
const CACHE_ITEM_WITHOUT_RIGHTS = 'IBLOCK_ELEMENT_PERM_N';
const CACHE_ITEM_RIGHTS = 'IBLOCK_ELEMENT';
const CACHE_ITEM_WITH_RIGHTS = 'IBLOCK_ELEMENT_PERM_Y';
const CACHE_ELEMENT_RIGHTS_MODE = 'ELEMENT_RIGHTS_MODE';
const CACHE_PRODUCT = 'CATALOG_PRODUCT';
const CACHE_VAT = 'VAT_INFO';
const CACHE_IBLOCK_RIGHTS = 'IBLOCK_RIGHTS';
const CACHE_STORE = 'CATALOG_STORE';
const CACHE_STORE_PRODUCT = 'CATALOG_STORE_PRODUCT';
const CACHE_PARENT_PRODUCT_ACTIVE = 'PARENT_PRODUCT_ACTIVE';
const CACHE_CATALOG_IBLOCK_LIST = 'CATALOG_IBLOCK_LIST';
const CACHE_PRODUCT_STORE_LIST = 'CACHE_PRODUCT_STORE_LIST';
const CACHE_PRODUCT_AVAILABLE_LIST = 'CACHE_PRODUCT_AVAILABLE_LIST';
const CATALOG_PROVIDER_EMPTY_STORE_ID = 0;
const BUNDLE_TYPE = 1;
const RESULT_PRODUCT_LIST = 'PRODUCT_DATA_LIST';
const RESULT_CATALOG_LIST = 'CATALOG_DATA_LIST';
/**
* @param array $products
*
* @return Sale\Result
*/
public function getProductData(array $products)
{
return $this->getData($products);
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function getCatalogData(array $products)
{
return $this->getData($products, array('CATALOG_DATA'));
}
/**
* @param array $products
* @param array $options
*
* @return Sale\Result
*/
private function getData(array $products, array $options = array())
{
$context = $this->getContext();
$resultProductList = array_fill_keys(array_keys($products), false);
$result = new Sale\Result();
$userId = (isset($context['USER_ID']) ? (int)$context['USER_ID'] : 0);
if ($userId < 0)
{
$userId = 0;
}
$siteId = false;
if (isset($context['SITE_ID']))
{
$siteId = $context['SITE_ID'];
}
$currency = (isset($context['CURRENCY']) ? Currency\CurrencyManager::checkCurrencyID($context['CURRENCY']) : false);
if ($currency === false)
{
$currency = Sale\Internals\SiteCurrencyTable::getSiteCurrency($siteId ? $siteId : SITE_ID);
}
if (is_array($options) && in_array('DISABLE_CACHE', $options))
{
$this->enableCache = false;
}
$outputVariable = static::getOutputVariable($options);
$productIndex = array();
$productGetIdList = array();
$correctProductIds = array();
$iblockElementSelect = array('ID', 'IBLOCK_ID', 'IBLOCK_SECTION_ID', 'ACTIVE', 'ACTIVE_DATE');
if (is_array($options) && !in_array('CATALOG_DATA', $options))
{
$iblockElementSelect = array_merge($iblockElementSelect, array('NAME', 'DETAIL_PAGE_URL'));
}
$resultList = array();
foreach ($products as $productId => $itemData)
{
$resultList[$productId] = false;
if (!isset($itemData['ITEM_CODE']))
{
$itemData['ITEM_CODE'] = $productId;
$products[$productId]['ITEM_CODE'] = $productId;
}
if (!isset($itemData['BASKET_CODE']))
{
$itemData['BASKET_CODE'] = $productId;
$products[$productId]['BASKET_CODE'] = $productId;
}
$productIndex[$productId][] = $itemData['ITEM_CODE'];
$hash = $productId."|".$userId;
$productCachedData = static::getHitCache(self::CACHE_ITEM_RIGHTS, $hash, $iblockElementSelect);
if ($this->enableCache && !empty($productCachedData))
{
$products[$productId]['PRODUCT_DATA'] = $productCachedData;
$correctProductIds[] = $productId;
}
else
{
$productGetIdList[] = $productId;
}
}
$adminSection = (defined('ADMIN_SECTION') && ADMIN_SECTION === true);
$userGroups = self::getUserGroups($userId);
if (!empty($productGetIdList))
{
$productDataList = $this->getElements(
$productGetIdList,
$iblockElementSelect,
($adminSection ? $userId : null)
);
foreach ($productDataList as $productId => $productData)
{
$products[$productId]['PRODUCT_DATA'] = $productData;
$hash = $productId."|".$userId;
static::setHitCache(self::CACHE_ITEM_RIGHTS, $hash, $productData);
$correctProductIds[] = $productId;
}
$products = static::removeNotExistsItemFromProducts($products, $correctProductIds);
if (empty($products))
{
return static::getResultProvider($result, $outputVariable, $resultList);
}
}
$iblockList = array();
$iblockDataList = array();
$iblockGetIdList = array();
foreach ($products as $productId => $productData)
{
$iblockId = $productData['PRODUCT_DATA']['IBLOCK_ID'];
$iblockList[$iblockId][] = $productId;
}
foreach ($iblockList as $iblockId => $iblockProductIdList)
{
$iblockData = static::getHitCache(self::CACHE_CATALOG_IBLOCK_LIST, $iblockId);
if ($this->enableCache && !empty($iblockData))
{
$iblockDataList[$iblockId] = $iblockData;
}
else
{
$iblockGetIdList[] = $iblockId;
}
}
if (!empty($iblockGetIdList))
{
$iblockDataList = $this->getIblockData($iblockGetIdList) + $iblockDataList;
}
$iblockList = static::removeNotExistsIblockFromList($iblockList, array_keys($iblockDataList));
$iblockProductMap = static::createIblockProductMap($iblockList, $iblockDataList);
$correctProductList = static::checkSkuPermission($iblockProductMap);
$products = static::removeNotExistsItemFromProducts($products, $correctProductList);
if (empty($products))
{
return static::getResultProvider($result, $outputVariable, $resultList);
}
$products = static::changeSubscribeProductQuantity($products, $iblockProductMap);
// catalog product
$catalogSelect = array(
'ID',
'CAN_BUY_ZERO',
'QUANTITY_TRACE',
'QUANTITY',
'QUANTITY_RESERVED',
'MEASURE',
);
if (is_array($options) && !in_array('CATALOG_DATA', $options))
{
$catalogSelect = array_merge($catalogSelect, array(
'WEIGHT',
'WIDTH',
'HEIGHT',
'LENGTH',
'BARCODE_MULTI',
'TYPE',
));
}
$catalogProductDataList = static::getCatalogProducts(array_keys($products), $catalogSelect);
$products = static::removeNotExistsItemFromProducts($products, array_keys($catalogProductDataList));
if (empty($products))
{
return static::getResultProvider($result, $outputVariable, $resultList);
}
$checkQuantityList = array();
foreach ($catalogProductDataList as $catalogProductId => $catalogProductData)
{
$checkQuantityList[$catalogProductId] = ($catalogProductData["CAN_BUY_ZERO"] != 'Y' && $catalogProductData["QUANTITY_TRACE"] == 'Y');
}
// get price
\CCatalogProduct::GetVATDataByIDList(array_keys($products));
if ($adminSection)
{
if ($userId > 0)
{
\CCatalogDiscountSave::SetDiscountUserID($userId);
}
else
{
\CCatalogDiscountSave::Disable();
}
}
Price\Calculation::pushConfig();
Price\Calculation::setConfig(array(
'CURRENCY' => $currency,
'PRECISION' => (int)Main\Config\Option::get('sale', 'value_precision'),
'RESULT_WITH_VAT' => true,
'RESULT_MODE' => Catalog\Product\Price\Calculation::RESULT_MODE_RAW
));
$productPriceList = array();
$priceDataList = \CCatalogProduct::GetOptimalPriceList(
$products,
$userGroups,
'N',
array(),
($adminSection ? $siteId : false)
);
if (empty($priceDataList))
{
$productsQuantityList = $products;
$quantityCorrected = false;
foreach ($productsQuantityList as $productId => $productData)
{
$quantityList = array($productData['BASKET_CODE'] => $productData['QUANTITY']);
if (empty($productData['QUANTITY_LIST']))
{
$quantityList = $productData['QUANTITY_LIST'];
}
if (empty($quantityList))
{
continue;
}
foreach ($quantityList as $basketCode => $quantity)
{
$nearestQuantity = \CCatalogProduct::GetNearestQuantityPrice($productId, $quantity, $userGroups);
if (!empty($nearestQuantity))
{
if (!empty($productData['QUANTITY_LIST']))
{
$productsQuantityList[$productId]['QUANTITY_LIST'][$basketCode]['QUANTITY'] = $nearestQuantity;
}
else
{
$productsQuantityList[$productId]['QUANTITY'] = $nearestQuantity;
}
$quantityCorrected = true;
}
}
}
if ($quantityCorrected)
{
$priceDataList = \CCatalogProduct::GetOptimalPriceList(
$productsQuantityList,
$userGroups,
'N',
array(),
($adminSection ? $siteId : false)
);
}
}
Price\Calculation::popConfig();
if ($adminSection)
{
if ($userId > 0)
{
\CCatalogDiscountSave::ClearDiscountUserID();
}
else
{
\CCatalogDiscountSave::Enable();
}
}
$discountList = array();
if (!empty($priceDataList))
{
foreach ($priceDataList as $productId => $priceBasketDataList)
{
foreach ($priceBasketDataList as $basketCode => $priceData)
{
if ($priceData === false)
continue;
if (empty($priceData['DISCOUNT_LIST']) && !empty($priceData['DISCOUNT']) && is_array($priceData['DISCOUNT']))
{
$priceDataList[$productId][$basketCode]['DISCOUNT_LIST'] = array($priceData['DISCOUNT']);
}
if (!empty($priceData['DISCOUNT_LIST']))
{
if (!isset($discountList[$productId]))
$discountList[$productId] = [];
if (!isset($discountList[$productId][$basketCode]))
$discountList[$productId][$basketCode] = [];
foreach ($priceData['DISCOUNT_LIST'] as $discountItem)
{
$discountList[$productId][$basketCode][] = \CCatalogDiscount::getDiscountDescription($discountItem);
}
unset($discountItem);
}
if (empty($priceData['PRICE']['CATALOG_GROUP_NAME']))
{
if (!empty($priceData['PRICE']['CATALOG_GROUP_ID']))
{
$priceName = self::getPriceTitle($priceData['PRICE']['CATALOG_GROUP_ID']);
if ($priceName != '')
{
$priceDataList[$productId][$basketCode]['PRICE']['CATALOG_GROUP_NAME'] = $priceName;
}
unset($priceName);
}
}
}
}
}
$productQuantityList = array();
foreach ($products as $productId => $productData)
{
$catalogProductData = $catalogProductDataList[$productId];
$quantityList = array();
if (array_key_exists('QUANTITY', $productData))
{
$quantityList = array($productData['BASKET_CODE'] => $productData['QUANTITY']);
}
if (!empty($productData['QUANTITY_LIST']))
{
$quantityList = $productData['QUANTITY_LIST'];
}
$productQuantityList[$productData['BASKET_CODE']]['QUANTITY_RESERVED'] = $catalogProductData['QUANTITY_RESERVED'];
$baseCatalogQuantity = floatval($catalogProductData['QUANTITY']);
$sumQuantity = 0;
$allCount = 0;
foreach ($quantityList as $basketCode => $quantity)
{
$sumQuantity += floatval(abs($quantity));
$allCount++;
}
$catalogQuantityForAvaialable = $baseCatalogQuantity;
$checkCatalogQuantity = $baseCatalogQuantity;
$isEnough = !($checkQuantityList[$productId] === true && $catalogQuantityForAvaialable < $sumQuantity);
$setQuantity = $baseCatalogQuantity;
foreach ($quantityList as $basketCode => $quantity)
{
$quantity = floatval(abs($quantity));
if (!$isEnough)
{
if ($catalogQuantityForAvaialable - $quantity < 0)
{
$quantity = $catalogQuantityForAvaialable;
}
$catalogQuantityForAvaialable -= $quantity;
}
$productQuantityList[$basketCode]['AVAILABLE_QUANTITY'] = ($baseCatalogQuantity >= $quantity || !$checkQuantityList[$productId] ? $quantity : $baseCatalogQuantity);
if (in_array('FULL_QUANTITY', $options))
{
$checkCatalogQuantity -= $quantity;
$setQuantity = $quantity;
$allCount--;
if ($allCount == 0)
{
$setQuantity = $checkCatalogQuantity + $quantity;
}
}
else
{
if ($baseCatalogQuantity - $quantity > 0 || !$checkQuantityList[$productId])
{
$setQuantity = $quantity;
}
}
$productQuantityList[$basketCode]['QUANTITY'] = $setQuantity;
$productPriceList[$basketCode] = $priceDataList[$productId][$basketCode];
}
$measure = isset($catalogProductData['MEASURE']) ? intval($catalogProductData['MEASURE']) : null;
$measureFields = static::getMeasure($measure);
if (!empty($measureFields))
{
$catalogProductDataList[$productId] = $measureFields + $catalogProductDataList[$productId];
}
}
$resultData = static::setCatalogDataToProducts($products, $catalogProductDataList, $options);
$priceResultList = static::createProductPriceList($products, $productPriceList, $discountList);
$resultList = static::createProductResult($products, $resultData, $priceResultList, $productQuantityList);
$resultList = $resultList + $resultProductList;
return static::getResultProvider($result, $outputVariable, $resultList);
}
private static function getOutputVariable(array $options = array())
{
$outputVariable = static::RESULT_PRODUCT_LIST;
if (is_array($options) && in_array('CATALOG_DATA', $options))
{
$outputVariable = static::RESULT_CATALOG_LIST;
}
return $outputVariable;
}
private static function getResultProvider(Sale\Result $result, $outputVariable, array $resultList = array())
{
$result->setData(
array(
$outputVariable => $resultList
)
);
return $result;
}
/**
* @param array $list
* @param array $select
* @param int|null $userId
*
* @return array
*/
private function getElements(array $list, array $select, $userId = null)
{
$filter = array(
'ID' => $list,
'ACTIVE_DATE' => 'Y',
'CHECK_PERMISSIONS' => 'Y',
'MIN_PERMISSION' => 'R'
);
if ($userId !== null)
$filter['PERMISSIONS_BY'] = $userId;
$resultList = array();
$dbIBlockElement = \CIBlockElement::GetList(
array(),
$filter,
false,
false,
$select
);
while ($productData = $dbIBlockElement->GetNext())
{
$resultList[$productData['ID']] = $productData;
}
return $resultList;
}
/**
* @param array $products
*
* @return array|bool|mixed
*/
public function getBundleItems(array $products)
{
$result = new Sale\Result();
$resultList = array();
$productIdList = array();
static $proxyCatalogProductSet = array();
static $proxyCatalogSkuData = array();
$bundleItemList = array();
$bundleIndex = array();
foreach ($products as $productId => $productData)
{
$proxyCatalogProductSetKey = $productId."|".static::BUNDLE_TYPE;
if (!empty($proxyCatalogProductSet[$proxyCatalogProductSetKey]) && is_array($proxyCatalogProductSet[$proxyCatalogProductSetKey]))
{
$childItemList = $proxyCatalogProductSet[$proxyCatalogProductSetKey];
}
else
{
$childItemList = \CCatalogProductSet::getAllSetsByProduct($productId, static::BUNDLE_TYPE);
if (!empty($childItemList) && is_array($childItemList))
{
$proxyCatalogProductSet[$proxyCatalogProductSetKey] = $childItemList;
}
}
if (!empty($childItemList))
{
$bundleItemList = $childItemList + $bundleItemList;
$bundleItemId = reset(array_keys($childItemList));
$bundleIndex[$bundleItemId] = $productId;
}
}
$childIdList = array();
if (empty($bundleItemList))
return $result;
$bundleChildList = array();
$childProducts = array();
$productIndexList = array();
foreach ($bundleItemList as $parentItemid => $bundleItemData)
{
$productId = $bundleIndex[$parentItemid];
foreach ($bundleItemData["ITEMS"] as $childItemid => $item)
{
if (!isset($childIdList[$item['ITEM_ID']]))
$childIdList[$item['ITEM_ID']] = true;
$bundleChildList[$item['ITEM_ID']] = $item;
$childProducts[$item['ITEM_ID']] = array(
'ITEM_CODE' => $item['ITEM_ID'],
'PRODUCT_ID' => $item['ITEM_ID'],
'QUANTITY_LIST' => array($item['ITEM_ID'] => $item['QUANTITY']),
'BUNDLE_CHILD' => true,
);
$productIndexList[$item['ITEM_ID']] = array(
'PRODUCT_ID' => $productId,
'PARENT_ID' => $parentItemid,
'CHILD_ID' => $childItemid
);
}
}
$r = $this->getProductData($childProducts);
if ($r->isSuccess())
{
$resultData = $r->getData();
if (!empty($resultData[static::RESULT_PRODUCT_LIST]))
{
$resultDataList = $resultData[static::RESULT_PRODUCT_LIST];
foreach ($resultDataList as $itemCode => $itemData)
{
$item = $bundleChildList[$itemCode];
if (array_key_exists('QUANTITY_TRACE', $itemData))
unset($itemData['QUANTITY_TRACE']);
$itemData["PRODUCT_ID"] = $item["ITEM_ID"];
$itemData["MODULE"] = "catalog";
$itemData["PRODUCT_PROVIDER_CLASS"] = '\Bitrix\Catalog\Product\CatalogProvider';
// if ($type == \CCatalogProductSet::TYPE_SET)
// {
// $itemData['SET_DISCOUNT_PERCENT'] = ($item['DISCOUNT_PERCENT'] == '' ? false : (float)$item['DISCOUNT_PERCENT']);
// }
$productIdList[] = $item["ITEM_ID"];
$itemData["PROPS"] = array();
if (!empty($proxyCatalogSkuData[$item["ITEM_ID"]]) && is_array($proxyCatalogSkuData[$item["ITEM_ID"]]))
{
$parentSkuData = $proxyCatalogSkuData[$item["ITEM_ID"]];
}
else
{
$parentSkuData = \CCatalogSku::GetProductInfo($item["ITEM_ID"]);
if ($parentSkuData)
{
$proxyCatalogSkuData[$item["ITEM_ID"]] = $parentSkuData;
}
}
if (!empty($parentSkuData))
{
$childDataList = array();
$childIdGetList = array();
$iblockPropertyDataList = array();
$iblockPropertyIdList = array();
$propsSku = array();
foreach ($childIdList as $childId => $parentValue)
{
$productData = static::getHitCache('IBLOCK_ELEMENT', $item["ITEM_ID"]);
if (!empty($productData))
{
$childDataList[$childId] = $productData;
if (!isset($iblockPropertyIdList[$productData['IBLOCK_ID']]))
{
$iblockPropertyIdList[$productData['IBLOCK_ID']] = true;
}
}
else
{
$childIdGetList[] = $childId;
}
}
if (!empty($childIdGetList))
{
$productRes = \CIBlockElement::GetList(array(), array("ID" => $childIdGetList), false, false, array('ID', 'IBLOCK_ID', 'NAME', 'IBLOCK_SECTION_ID'));
while ($productData = $productRes->Fetch())
{
static::setHitCache('IBLOCK_ELEMENT', $productData["ID"], $productData);
$childDataList[$productData["ID"]] = $productData;
if (!isset($iblockPropertyIdList[$productData['IBLOCK_ID']]))
{
$iblockPropertyIdList[$productData['IBLOCK_ID']] = true;
}
}
}
foreach ($iblockPropertyIdList as $iblockPropertyId => $iblockPropertyValue)
{
if ($propsSku = static::getHitCache('IBLOCK_PROPERTY', $iblockPropertyId))
{
$iblockPropertyDataList[$iblockPropertyId] = $propsSku;
}
else
{
$dbOfferProperties = \CIBlock::GetProperties($iblockPropertyId, array(), array("!XML_ID" => "CML2_LINK"));
while($offerProperties = $dbOfferProperties->Fetch())
{
$propsSku[] = $offerProperties["CODE"];
}
static::setHitCache('IBLOCK_PROPERTY', $iblockPropertyId, $propsSku);
}
}
$propSkuHash = (!empty($propsSku)) ? md5(join('|', $propsSku)): md5($item["ITEM_ID"]);
$proxyProductPropertyKey = $item["ITEM_ID"]."_".$parentSkuData["IBLOCK_ID"]."_".$propSkuHash;
$productProperties = static::getHitCache('PRODUCT_PROPERTY', $proxyProductPropertyKey);
if (empty($productProperties))
{
$productProperties = \CIBlockPriceTools::GetOfferProperties(
$item["ITEM_ID"],
$parentSkuData["IBLOCK_ID"],
$propsSku
);
static::setHitCache('PRODUCT_PROPERTY', $proxyProductPropertyKey, $productProperties);
}
if (!empty($productProperties))
{
foreach ($productProperties as $propData)
{
$itemData["PROPS"][] = array(
"NAME" => $propData["NAME"],
"CODE" => $propData["CODE"],
"VALUE" => $propData["VALUE"],
"SORT" => $propData["SORT"]
);
}
}
}
$parentProductIndexData = $productIndexList[$itemCode];
$priceData = array();
if (!empty($itemData['PRICE_LIST']))
{
$priceData = reset($itemData['PRICE_LIST']);
unset($itemData['PRICE_LIST']);
}
$bundleItemList[$parentProductIndexData['PARENT_ID']]["ITEMS"][$parentProductIndexData['CHILD_ID']] = array_merge($item, $itemData, $priceData);
}
}
}
$elementList = static::getHitCache('IBLOCK_ELEMENT_LIST', $productId);
if (empty($elementList))
{
$productRes = \CIBlockElement::GetList(
array(),
array('ID' => $productIdList),
false,
false,
array("ID", "IBLOCK_ID", "IBLOCK_SECTION_ID", "PREVIEW_PICTURE", "DETAIL_PICTURE", "IBLOCK_TYPE_ID", "XML_ID")
);
while ($productData = $productRes->GetNext())
{
$elementList[$productData['ID']] = $productData;
}
if (!empty($elementList) && is_array($elementList))
{
static::setHitCache('IBLOCK_ELEMENT_LIST', $productId, $elementList);
}
}
if (!empty($elementList) && is_array($elementList))
{
foreach ($bundleItemList as $bundleParentId => $bundleItemData)
{
foreach ($bundleItemData["ITEMS"] as $bundleChildId => $item)
{
if (!$elementList[$item["ITEM_ID"]])
continue;
$elementData = $elementList[$item["ITEM_ID"]];
$properties = array();
$strIBlockXmlID = (string)\CIBlock::GetArrayByID($elementData['IBLOCK_ID'], 'XML_ID');
if ($strIBlockXmlID != "")
{
$properties[] = array(
"NAME" => "Catalog XML_ID",
"CODE" => "CATALOG.XML_ID",
"VALUE" => $strIBlockXmlID
);
$elementData['CATALOG_XML_ID'] = $strIBlockXmlID;
}
if (!empty($proxyCatalogSkuData[$item["ITEM_ID"]]) && strpos($elementData["XML_ID"], '#') === false)
{
$parentSkuData = $proxyCatalogSkuData[$item["ITEM_ID"]];
if (!empty($proxyParentData[$parentSkuData['ID']]) && is_array($proxyParentData[$parentSkuData['ID']]))
{
$parentData = $proxyParentData[$parentSkuData['ID']];
}
else
{
$parentIterator = Iblock\ElementTable::getList(
array(
'select' => array('ID', 'XML_ID'),
'filter' => array('ID' => $parentSkuData['ID'])
)
);
$parentData = $parentIterator->fetch();
if (!empty($parentData))
{
$proxyParentData[$parentSkuData['ID']] = $parentData;
}
unset($parentIterator);
}
$elementData["XML_ID"] = $parentData['XML_ID'].'#'.$elementData["XML_ID"];
unset($parentData);
}
$properties[] = array(
"NAME" => "Product XML_ID",
"CODE" => "PRODUCT.XML_ID",
"VALUE" => $elementData["XML_ID"]
);
$bundleItemData = $bundleItemList[$bundleParentId]["ITEMS"][$bundleChildId];
$bundleItemProps = array();
if (is_array($elementData["PROPS"]) && !empty($elementData["PROPS"]))
{
$bundleItemProps = $elementData["PROPS"];
}
if (!empty($properties))
{
$bundleItemProps = $bundleItemProps + $properties;
}
$bundleItemList[$bundleParentId]["ITEMS"][$bundleChildId] = $bundleItemData + array(
'IBLOCK_ID' => $elementData["IBLOCK_ID"],
'IBLOCK_SECTION_ID' => $elementData["IBLOCK_SECTION_ID"],
'PREVIEW_PICTURE' => $elementData["PREVIEW_PICTURE"],
'DETAIL_PICTURE' => $elementData["DETAIL_PICTURE"],
'CATALOG_XML_ID' => $elementData["CATALOG_XML_ID"],
'PRODUCT_XML_ID' => $elementData["XML_ID"],
);
$bundleItemList[$bundleParentId]["ITEMS"][$bundleChildId]['PROPS'] = $bundleItemProps;
}
}
}
foreach(GetModuleEvents("sale", "OnGetSetItems", true) as $eventData)
{
ExecuteModuleEventEx($eventData, array(&$bundleItemList));
}
if (!empty($bundleItemList))
{
foreach ($bundleItemList as $bundleParentId => $bundleData)
{
if (empty($bundleIndex[$bundleParentId]))
continue;
$productId = $bundleIndex[$bundleParentId];
$resultList[$productId] = $bundleData;
}
$result->setData(
array(
'BUNDLE_LIST' => $resultList
)
);
}
return $result;
}
/**
* @param $userId
*
* @return bool|array
*/
protected static function getUserGroups($userId)
{
$userId = (int)$userId;
if ($userId < 0)
return false;
if (!isset(self::$userCache[$userId]))
self::$userCache[$userId] = Main\UserTable::getUserGroupIds($userId);
return self::$userCache[$userId];
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function ship(array $products)
{
return $this->shipProducts($products);
}
/**
* @param array $products
*
* @return array
*/
private function createReverseQuantityProducts(array $products)
{
$resultList = array();
foreach ($products as $productId => $productData)
{
$resultList[$productId] = $productData;
if (array_key_exists('QUANTITY', $productData))
{
$resultList[$productId]['QUANTITY'] *= -1;
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$resultList[$productId]['QUANTITY_LIST'][$basketCode] *= -1;
}
}
}
return $resultList;
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function unship(array $products)
{
$result = new Sale\Result();
$r = $this->tryUnship($products);
if (!$r->isSuccess())
{
$result->addErrors($r->getErrors());
return $result;
}
$data = $r->getData();
if (!empty($data['PRODUCTS_LIST_SHIPPED']))
{
$productsList = array();
foreach ($data['PRODUCTS_LIST_SHIPPED'] as $productId => $value)
{
if ($value && !empty($products[$productId]))
{
$productsList[$productId] = $products[$productId];
}
}
if (!empty($productsList))
{
$this->shipProducts($productsList);
}
}
return $result;
}
/**
* @param array $products
*
* @return Sale\Result
* @throws Main\ObjectNotFoundException
*/
public function deliver(array $products)
{
$result = new Sale\Result();
$resultList = array();
$productOrderList = static::createOrderListFromProducts($products);
$deliverProductList = array();
foreach ($products as $productId => $productData)
{
$userId = null;
$orderPaid = null;
$orderId = null;
if (isset($productData['USER_ID']))
{
$userId = $productData['USER_ID'];
}
if (isset($productData['ORDER_ID']))
{
$orderId = $productData['ORDER_ID'];
}
if (isset($productData['PAID']))
{
$orderPaid = $productData['PAID'];
}
/**
* @var int $orderId
* @var Sale\Order $order
*/
if (isset($productOrderList[$productId]))
{
foreach ($productOrderList[$productId] as $orderId => $order)
{
if (!isset($resultList[$productId]))
{
$deliverProductList[] = array(
'PRODUCT_ID' => $productId,
'USER_ID' => $order->getUserId(),
'PAID' => $order->isPaid(),
'ORDER_ID' => $orderId,
);
}
}
}
else
{
if (isset($productData['USER_ID']))
{
$userId = $productData['USER_ID'];
}
if (isset($productData['ORDER_ID']))
{
$orderId = $productData['ORDER_ID'];
}
if (isset($productData['PAID']))
{
$orderPaid = $productData['PAID'];
}
$deliverProductList[] = array(
'PRODUCT_ID' => $productId,
'USER_ID' => $userId,
'PAID' => $orderPaid,
'ORDER_ID' => $orderId,
);
}
}
if (!empty($deliverProductList))
{
foreach ($deliverProductList as $productData)
{
$productId = $productData['PRODUCT_ID'];
$resultList[$productId] = \CatalogPayOrderCallback(
$productId,
$productData['USER_ID'],
$productData['PAID'],
$productData['ORDER_ID']
);
}
}
if (!empty($resultList))
{
$result->setData(
array(
'DELIVER_PRODUCTS_LIST' => $resultList
)
);
}
return $result;
}
/**
* @param array $items
*
* @return Sale\Result
* @throws Main\ObjectNotFoundException
*/
public function viewProduct(array $items)
{
$result = new Sale\Result();
$resultList = array();
foreach ($items as $productId => $itemData)
{
if (!isset($resultList[$productId]))
{
$context = $this->getContext();
$resultList[$productId] = \CatalogViewedProductCallback(
$productId,
$context['USER_ID'],
$context['SITE_ID']
);
}
}
if (!empty($resultList))
{
$result->setData(
array(
'VIEW_PRODUCTS_LIST' => $resultList
)
);
}
return $result;
}
/**
* @param array $items
*
* @return Sale\Result
* @throws Main\ObjectNotFoundException
*/
public function recurring(array $items)
{
$result = new Sale\Result();
$resultList = array();
foreach ($items as $productId => $itemData)
{
if (!isset($resultList[$productId]))
{
$context = $this->getContext();
$resultList[$productId] = \CatalogRecurringCallback(
$productId,
$context['USER_ID']
);
}
}
if (!empty($resultList))
{
$result->setData(
array(
'RECURRING_PRODUCTS_LIST' => $resultList
)
);
}
return $result;
}
/**
* @param array $items
*
* @return Sale\Result
* @throws Main\ObjectNotFoundException
*/
public function checkBarcode(array $items)
{
$result = new Sale\Result();
$resultList = array();
foreach ($items as $productId => $barcodeParams)
{
$resultList[$barcodeParams['BARCODE']] = false;
$dbres = \CCatalogStoreBarcode::GetList(
array(),
$barcodeParams
);
$resultList[$barcodeParams['BARCODE']] = (bool)($dbres->GetNext());
}
if (!empty($resultList))
{
$result->setData(
array(
'BARCODE_CHECK_LIST' => $resultList
)
);
}
return $result;
}
/**
* @param array $products
*
* @return Sale\Result
*/
protected function shipProducts(array $products)
{
$result = new Sale\Result();
$resultList = array();
foreach ($products as $productId => $productData)
{
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
$resultList[$productId] = false;
}
$availableItems = $this->createProductsListWithCatalogData($products);
$useStoreControl = Catalog\Config\State::isUsedInventoryManagement();
$productStoreDataList = array();
if ($useStoreControl === true)
{
$shipProducts = array();
foreach ($products as $productId => $productData)
{
$shipProducts[$productId] = $productData;
}
$r = $this->getProductListStores($shipProducts);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCT_STORES_LIST']))
{
$productStoreDataList = $data['PRODUCT_STORES_LIST'];
}
}
}
foreach ($availableItems as $productId => $productData)
{
$productStoreData = array();
if (!empty($productStoreDataList) && isset($productStoreDataList[$productId]))
{
$productStoreData = $productStoreDataList[$productId];
}
$r = static::shipProduct($productData, $productStoreData);
if (!$r->isSuccess())
{
$result->addErrors($r->getErrors());
$result->addWarnings($r->getErrors());
}
$resultList[$productId] = $r->isSuccess();
}
$result->setData(
array(
'SHIPPED_PRODUCTS_LIST' => $resultList
)
);
return $result;
}
/**
* @param array $quantityList
*
* @return Sale\Result
*/
private static function updateCatalogStoreAmount(array $quantityList)
{
$result = new Sale\Result();
$resultList = array();
if (empty($quantityList))
{
return $result;
}
foreach ($quantityList as $catalogStoreId => $amount)
{
$resultList[$catalogStoreId] = \CCatalogStoreProduct::Update($catalogStoreId, array("AMOUNT" => $amount));
}
$result->setData(
array(
'AMOUNT_UPDATED_LIST' => $resultList
)
);
return $result;
}
/**
* @param array $productData
* @param array $productStoreDataList
*
* @return Sale\Result
* @throws Main\ArgumentNullException
* @throws Main\ArgumentOutOfRangeException
*/
private static function shipProduct(array $productData, array $productStoreDataList = array())
{
$result = new Sale\Result();
$useStoreControl = Catalog\Config\State::isUsedInventoryManagement();
$productId = $productData['PRODUCT_ID'];
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
$needShip = ($productQuantity < 0);
if ($useStoreControl === true)
{
if (empty($productStoreDataList) && $needShip)
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_STORE_ERROR",
array_merge(
self::getProductCatalogInfo($productId),
array("#PRODUCT_ID#" => $productId)
)
), "DDCT_DEDUCTION_STORE_ERROR"
)
);
return $result;
}
$setQuantityList = array();
$r = static::getSetableStoreQuantityProduct($productData, $productStoreDataList);
if ($r->isSuccess())
{
$resultData = $r->getData();
if (!empty($resultData['QUANTITY_LIST']))
{
$setQuantityList = $resultData['QUANTITY_LIST'];
}
}
else
{
return $r;
}
$r = static::updateCatalogStoreAmount($setQuantityList);
if ($r->isSuccess())
{
$resultData = $r->getData();
if (!empty($resultData['AMOUNT_UPDATED_LIST']))
{
foreach($resultData['AMOUNT_UPDATED_LIST'] as $catalogStoreId => $catalogStoreIsUpdated)
{
if ($catalogStoreIsUpdated === true)
{
static::clearHitCache(self::CACHE_STORE_PRODUCT);
if ($needShip)
{
$r = static::deleteBarcodes($productData);
}
else
{
$r = static::addBarcodes($productData);
}
if (!$r->isSuccess())
{
$result->addErrors($r->getErrors());
}
}
}
}
}
else
{
return $r;
}
return static::shipQuantityWithStoreControl($productData);
}
elseif (isset($productData["CATALOG"]))
{
if ($productData["CATALOG"]["QUANTITY_TRACE"] == "N")
{
return $result;
}
}
return static::shipQuantityWithoutStoreControl($productData);
}
/**
* @param array $productData
*
* @return Sale\Result
*/
private static function shipQuantityWithStoreControl(array $productData)
{
$result = new Sale\Result();
$productId = intval($productData['PRODUCT_ID']);
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
$catalogData = $productData['CATALOG'];
$isExistsReserve = static::isExistsReserve($productData) && static::isReservationEnabled();
$isNeedShip = ($productQuantity < 0);
$productQuantity = abs($productQuantity);
$fields = array();
$catalogReservedQuantity = floatval($catalogData['QUANTITY_RESERVED']);
$catalogQuantity = 0;
if (array_key_exists('QUANTITY', $catalogData))
{
$catalogQuantity = floatval($catalogData['QUANTITY']);
}
elseif (!empty($catalogData['PRICE_LIST']))
{
foreach ($catalogData['PRICE_LIST'] as $basketCode => $catalogValue)
{
$catalogQuantity += floatval($catalogValue['QUANTITY']);
}
}
$sumCatalogQuantity = $catalogReservedQuantity + $catalogQuantity;
if ($isNeedShip)
{
if ($isExistsReserve)
{
if ($catalogReservedQuantity >= $productQuantity)
{
$fields["QUANTITY_RESERVED"] = $catalogReservedQuantity - $productQuantity;
}
elseif ($sumCatalogQuantity >= $productQuantity)
{
$fields["QUANTITY_RESERVED"] = 0;
$fields["QUANTITY"] = $catalogQuantity - ($productQuantity - $catalogReservedQuantity);
}
else
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_NOT_ENOUGHT_QUANTITY_PRODUCT",
array_merge(
self::getProductCatalogInfo($productId),
array("#PRODUCT_ID#" => $productId)
)
), "DDCT_DEDUCTION_NOT_ENOUGHT_QUANTITY_PRODUCT"
)
);
return $result;
}
}
else
{
if ($productQuantity <= $catalogQuantity)
{
$fields["QUANTITY"] = $catalogQuantity - $productQuantity;
}
elseif ($productQuantity <= $sumCatalogQuantity)
{
$fields["QUANTITY"] = 0;
$fields["QUANTITY_RESERVED"] = $catalogReservedQuantity - ($productQuantity - $catalogQuantity);
}
else
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_NOT_ENOUGHT_QUANTITY_PRODUCT",
array_merge(
self::getProductCatalogInfo($productId),
array("#PRODUCT_ID#" => $productId)
)
), "DDCT_DEDUCTION_NOT_ENOUGHT_QUANTITY_PRODUCT"
)
);
return $result;
}
}
}
else
{
if ($isExistsReserve)
{
$fields["QUANTITY_RESERVED"] = $catalogReservedQuantity + $productQuantity;
}
else
{
$fields["QUANTITY"] = $catalogQuantity + $productQuantity;
}
}
$isUpdated = false;
if (!empty($fields))
{
$isUpdated = \CCatalogProduct::Update($productId, $fields);
if ($isUpdated)
{
$quantityValues = array();
if (isset($fields['QUANTITY']))
{
$quantityValues[QuantityControl::QUANTITY_CONTROL_QUANTITY] = $fields['QUANTITY'];
QuantityControl::resetAvailableQuantity($productId);
}
if (isset($fields['QUANTITY_RESERVED']))
{
$quantityValues[QuantityControl::QUANTITY_CONTROL_RESERVED_QUANTITY] = $fields['QUANTITY_RESERVED'];
}
if (!empty($quantityValues))
{
QuantityControl::setValues($productId, $quantityValues);
}
}
}
$result->setData(
array(
'IS_UPDATED' => $isUpdated
)
);
return $result;
}
/**
* @param array $productData
*
* @return Sale\Result
*/
private static function shipQuantityWithoutStoreControl(array $productData)
{
$result = new Sale\Result();
$productId = intval($productData['PRODUCT_ID']);
$catalogData = $productData['CATALOG'];
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
$catalogReservedQuantity = floatval($catalogData['QUANTITY_RESERVED']);
$catalogQuantity = 0;
if (array_key_exists('QUANTITY', $catalogData))
{
$catalogQuantity = floatval($catalogData['QUANTITY']);
}
elseif (!empty($catalogData['PRICE_LIST']))
{
foreach ($catalogData['PRICE_LIST'] as $basketCode => $catalogValue)
{
$catalogQuantity += floatval($catalogValue['QUANTITY']);
}
}
$fields = array();
$isExistsReserve = static::isExistsReserve($productData) && static::isReservationEnabled();
$isNeedShip = ($productQuantity < 0);
if ($isNeedShip)
{
$productQuantity = abs($productQuantity);
if (($productQuantity <= $catalogReservedQuantity + $catalogQuantity) || $catalogData["CAN_BUY_ZERO"] == "Y")
{
if ($isExistsReserve)
{
if ($productQuantity <= $catalogReservedQuantity)
{
$needReservedQuantity = $catalogReservedQuantity - $productQuantity;
if ($productQuantity > $catalogReservedQuantity)
{
$needReservedQuantity = $catalogReservedQuantity;
}
$fields["QUANTITY_RESERVED"] = $needReservedQuantity;
}
else
{
$fields["QUANTITY_RESERVED"] = 0;
$fields["QUANTITY"] = $catalogQuantity - ($productQuantity - $catalogReservedQuantity);
}
}
else
{
if ($productQuantity <= $catalogQuantity)
{
$fields["QUANTITY"] = $catalogQuantity - $productQuantity;
}
else
{
$fields["QUANTITY"] = 0;
$minusQuantity = ($productQuantity - $catalogQuantity);
$needReservedQuantity = $catalogReservedQuantity - $minusQuantity;
if ($minusQuantity > $catalogReservedQuantity)
{
$needReservedQuantity = $catalogReservedQuantity;
}
$fields["QUANTITY_RESERVED"] = $needReservedQuantity;
}
}
}
else //not enough products - don't deduct anything
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_QUANTITY_ERROR",
array_merge(
self::getProductCatalogInfo($productId),
array("#PRODUCT_ID#" => $productId)
)
), "DDCT_DEDUCTION_QUANTITY_ERROR"
)
);
}
}
else
{
if ($isExistsReserve)
{
$fields["QUANTITY_RESERVED"] = $catalogReservedQuantity + $productQuantity;
}
else
{
$fields["QUANTITY"] = $catalogQuantity + $productQuantity;
}
}
if (!empty($fields))
{
$isUpdated = \CCatalogProduct::Update($productId, $fields);
if ($isUpdated)
{
$quantityValues = array();
if (isset($fields['QUANTITY']))
{
$quantityValues[QuantityControl::QUANTITY_CONTROL_QUANTITY] = $fields['QUANTITY'];
QuantityControl::resetAvailableQuantity($productId);
}
if (isset($fields['QUANTITY_RESERVED']))
{
$quantityValues[QuantityControl::QUANTITY_CONTROL_RESERVED_QUANTITY] = $fields['QUANTITY_RESERVED'];
}
if (!empty($quantityValues))
{
QuantityControl::setValues($productId, $quantityValues);
}
}
if (isset($fields['QUANTITY']) && self::isNeedClearPublicCache(
$catalogData['QUANTITY'],
$fields['QUANTITY'],
$catalogData['QUANTITY_TRACE'],
$catalogData['CAN_BUY_ZERO']
))
{
$productInfo = array(
'CAN_BUY_ZERO' => $catalogData['CAN_BUY_ZERO'],
'QUANTITY_TRACE' => $catalogData['QUANTITY_TRACE'],
'OLD_QUANTITY' => $catalogData['QUANTITY'],
'QUANTITY' => $fields['QUANTITY'],
'DELTA' => $fields['QUANTITY'] - $catalogData['QUANTITY']
);
self::clearPublicCache($catalogData['ID'], $productInfo);
}
}
return $result;
}
/**
* @param array $productData
*
* @return bool
*/
private static function isExistsReserve(array $productData)
{
if (empty($productData['SHIPMENT_ITEM_LIST']))
return false;
if (empty($productData['NEED_RESERVE_LIST']))
return false;
/**
* @var $shipmentItemIndex
* @var Sale\ShipmentItem $shipmentItem
*/
foreach ($productData['NEED_RESERVE_LIST'] as $shipmentItemIndex => $isReserve)
{
if (isset($productData['SHIPMENT_ITEM_LIST'][$shipmentItemIndex]))
{
/** @var Sale\ShipmentItem $shipmentItem */
$shipmentItem = $productData['SHIPMENT_ITEM_LIST'][$shipmentItemIndex];
if ($shipmentItem->getNeedReserveQuantity() > 0 || $shipmentItem->getReservedQuantity() > 0)
{
return true;
}
}
if ($isReserve)
{
return true;
}
}
return false;
}
/**
* @param array $productData
* @param array $productStoreDataList
*
* @return Sale\Result
*/
private static function getSetableStoreQuantityProduct(array $productData, array $productStoreDataList)
{
$result = new Sale\Result();
$setQuantityList = array();
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
$isNeedShip = ($productQuantity < 0);
$needQuantityList = static::getNeedQuantityFromStore($productData);
if (empty($needQuantityList))
{
$autoShipStore = static::getAutoShipStoreData($productData, $productStoreDataList);
if (!empty($autoShipStore))
{
$needQuantityList[$autoShipStore['STORE_ID']] = ($productQuantity > $autoShipStore['AMOUNT'] ? $autoShipStore['AMOUNT'] : abs($productQuantity));
$shipmentItemList = $productData['SHIPMENT_ITEM_LIST'];
/** @var Sale\ShipmentItem $shipmentItem */
foreach ($shipmentItemList as $index => $shipmentItem)
{
$shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection();
if ($shipmentItemStoreCollection->count() === 0)
{
/** @var Sale\ShipmentItemStore $item */
$item = $shipmentItemStoreCollection->createItem($shipmentItem->getBasketItem());
$item->setField('STORE_ID', $autoShipStore['STORE_ID']);
$item->setField('QUANTITY', abs($productData['SHIPMENT_ITEM_QUANTITY_LIST'][$index]));
}
}
}
}
if (!empty($productStoreDataList))
{
foreach ($productStoreDataList as $storeId => $productStoreData)
{
$productId = $productStoreData['PRODUCT_ID'];
if ($isNeedShip && (isset($needQuantityList[$storeId]) && $productStoreData['AMOUNT'] < $needQuantityList[$storeId]))
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_QUANTITY_STORE_ERROR",
array_merge(
self::getProductCatalogInfo($productId),
array("#STORE_ID#" => $productStoreData["STORE_ID"], '#PRODUCT_ID#' => $productId)
)
), "DDCT_DEDUCTION_QUANTITY_STORE_ERROR"
)
);
}
else
{
$setQuantity = $productQuantity;
if (isset($needQuantityList[$storeId]))
{
$setQuantity = ($isNeedShip ? -1 : 1) * $needQuantityList[$storeId];
}
elseif (!empty($needQuantityList))
{
continue;
}
$setQuantityList[$productStoreData["ID"]] = $productStoreData["AMOUNT"] + $setQuantity;
}
}
}
if (!empty($setQuantityList))
{
$result->addData(
array(
'QUANTITY_LIST' => $setQuantityList
)
);
}
return $result;
}
/**
* @param array $productData
*
* @return array|bool
*/
private static function getNeedQuantityFromStore(array $productData)
{
if (empty($productData['STORE_DATA_LIST']))
return false;
$resultList = array();
foreach ($productData['STORE_DATA_LIST'] as $shipmentItemIndex => $storeDataList)
{
foreach ($storeDataList as $storeId => $storeData)
{
$resultList[$storeId] += $storeData['QUANTITY'];
}
}
return $resultList;
}
/**
* @param array $productData
*
* @return Sale\Result
*/
private static function deleteBarcodes(array $productData)
{
$result = new Sale\Result();
$storeData = $productData['STORE_DATA_LIST'];
if (!empty($storeData))
{
foreach ($storeData as $basketCode => $storeDataList)
{
foreach($storeDataList as $storeIndex => $storeDataValue)
{
$r = static::deleteBarcode($storeDataValue);
if (!$r->isSuccess())
{
$result->addErrors($r->getErrors());
}
}
}
}
return $result;
}
/**
* @param array $storeData
*
* @return Sale\Result
*/
private static function deleteBarcode(array $storeData)
{
$result = new Sale\Result();
$storeId = $storeData["STORE_ID"];
$productId = $storeData["PRODUCT_ID"];
$barcodeMulti = $storeData['IS_BARCODE_MULTI'];
$barcodeList = $storeData['BARCODE'];
foreach ($barcodeList as $barcodeId => $barcodeValue)
{
if (strval(trim($barcodeValue)) == "" || !$barcodeMulti)
{
continue;
}
$result = new Sale\Result();
$barcodeFields = array(
"STORE_ID" => $storeId,
"BARCODE" => $barcodeValue,
"PRODUCT_ID" => $productId
);
$dbres = \CCatalogStoreBarcode::GetList(
array(),
$barcodeFields,
false,
false,
array("ID", "STORE_ID", "BARCODE", "PRODUCT_ID")
);
$catalogStoreBarcodeRes = $dbres->Fetch();
if ($catalogStoreBarcodeRes)
{
\CCatalogStoreBarcode::Delete($catalogStoreBarcodeRes["ID"]);
}
else
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_BARCODE_ERROR",
array_merge(
self::getProductCatalogInfo($productId),
array("#BARCODE#" => $barcodeValue)
)
), "DDCT_DEDUCTION_BARCODE_ERROR"
)
);
}
}
return $result;
}
/**
* @param array $productData
*
* @return Sale\Result
*/
private static function addBarcodes(array $productData)
{
$result = new Sale\Result();
$storeData = $productData['STORE_DATA_LIST'];
if (!empty($storeData))
{
foreach ($storeData as $shipmentItemIndex => $storeDataList)
{
foreach($storeDataList as $storeIndex => $storeDataValue)
{
$r = static::addBarcode($storeDataValue);
if (!$r->isSuccess())
{
$result->addErrors($r->getErrors());
}
}
}
}
return $result;
}
/**
* @param array $storeData
*
* @return Sale\Result
*/
private static function addBarcode(array $storeData)
{
$result = new Sale\Result();
$storeId = $storeData["STORE_ID"];
$productId = $storeData["PRODUCT_ID"];
$barcodeMulti = $storeData['IS_BARCODE_MULTI'];
$barcodeList = $storeData['BARCODE'];
foreach ($barcodeList as $barcodeId => $barcodeValue)
{
if (strval(trim($barcodeValue)) == "" || !$barcodeMulti)
{
continue;
}
$result = new Sale\Result();
$barcodeFields = array(
"STORE_ID" => $storeId,
"BARCODE" => $barcodeValue,
"PRODUCT_ID" => $productId
);
\CCatalogStoreBarcode::Add($barcodeFields);
}
return $result;
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function reserve(array $products)
{
$result = new Sale\Result();
$resultList = array();
$availableItems = $this->createProductsListWithCatalogData($products);
foreach ($availableItems as $productId => $productData)
{
$resultList[$productId] = false;
$r = static::reserveProduct($productData);
if ($r->isSuccess())
{
$resultData = $r->getData();
if (!empty($resultData))
{
$resultList[$productId] = $resultData;
}
}
else
{
$result->addErrors($r->getErrors());
}
}
$result->setData(array(
'RESERVED_PRODUCTS_LIST' => $resultList
));
return $result;
}
/**
* @param array $productData
*
* @return Sale\Result|bool
*/
private static function reserveProduct(array $productData)
{
$enabledReservation = static::isReservationEnabled();
if (!$enabledReservation)
{
return static::reserveQuantityWithDisabledReservation($productData);
}
return static::reserveQuantityWithEnabledReservation($productData);
}
/**
* @param array $productData
*
* @return Sale\Result
* @throws Main\ObjectNotFoundException
*/
private static function reserveQuantityWithEnabledReservation(array $productData)
{
$result = new Sale\Result();
$resultFields = array();
$fields = array();
$needShipList = array();
$productId = $productData['PRODUCT_ID'];
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
$isNeedReserve = ($productQuantity > 0);
$catalogData = $productData['CATALOG'];
$catalogReservedQuantity = floatval($catalogData['QUANTITY_RESERVED']);
$catalogQuantity = 0;
if (array_key_exists('QUANTITY', $catalogData))
{
$catalogQuantity = floatval($catalogData['QUANTITY']);
}
elseif (!empty($catalogData['PRICE_LIST']))
{
foreach ($catalogData['PRICE_LIST'] as $basketCode => $catalogValue)
{
$catalogQuantity += floatval($catalogValue['QUANTITY']);
}
}
$sumCatalogQuantity = $catalogQuantity + $catalogReservedQuantity;
if (isset($productData['NEED_SHIP']))
{
$needShipList = $productData['NEED_SHIP'];
}
$setQuantityReserved = $catalogReservedQuantity;
$shipmentItemList = $productData['SHIPMENT_ITEM_DATA_LIST'];
$anyoneNeedShip = false;
if (!empty($needShipList))
{
foreach ($needShipList as $shipmentItemIndex => $isNeedShip)
{
if ($setQuantityReserved <= 0)
{
$setQuantityReserved = 0;
break;
}
if ($isNeedShip === true)
{
$shipmentItemQuantity = $shipmentItemList[$shipmentItemIndex];
$setQuantityReserved -= $shipmentItemQuantity;
}
}
}
if ($catalogData["QUANTITY_TRACE"] == "N" || $anyoneNeedShip === true)
{
$fields["QUANTITY_RESERVED"] = $setQuantityReserved;
$resultFields['IS_UPDATED'] = true;
$resultFields['QUANTITY_RESERVED'] = 0;
}
else
{
$resultFields['QUANTITY_RESERVED'] = $catalogReservedQuantity;
if ($isNeedReserve)
{
if ($catalogData["CAN_BUY_ZERO"] == "Y")
{
$fields["QUANTITY_RESERVED"] = $catalogReservedQuantity + $productQuantity;
$fields['QUANTITY'] = $catalogQuantity - $productQuantity;
}
else
{
if ($catalogQuantity >= $productQuantity)
{
$fields["QUANTITY"] = $catalogQuantity - $productQuantity;
$fields["QUANTITY_RESERVED"] = $catalogReservedQuantity + $productQuantity;
}
else
{
$resultFields["QUANTITY_NOT_RESERVED"] = $productQuantity - $catalogQuantity;
$fields["QUANTITY"] = 0;
$fields["QUANTITY_RESERVED"] = $sumCatalogQuantity;
$result->addWarning(
new Sale\ResultWarning(
Main\Localization\Loc::getMessage(
"RSRV_QUANTITY_NOT_ENOUGH_ERROR",
self::getProductCatalogInfo($productId)
), "ERROR_NOT_ENOUGH_QUANTITY"
)
);
}
if (self::isNeedClearPublicCache(
$catalogQuantity,
$fields['QUANTITY'],
$catalogData['QUANTITY_TRACE'],
$catalogData['CAN_BUY_ZERO']
))
{
$productInfo = array(
'CAN_BUY_ZERO' => $catalogData['CAN_BUY_ZERO'],
'QUANTITY_TRACE' => $catalogData['QUANTITY_TRACE'],
'OLD_QUANTITY' => $catalogQuantity,
'QUANTITY' => $fields['QUANTITY'],
'DELTA' => $fields['QUANTITY'] - $catalogData['QUANTITY']
);
self::clearPublicCache($catalogData['ID'], $productInfo);
}
}
}
else //undo reservation
{
$needQuantity = abs($productQuantity);
$fields["QUANTITY"] = $catalogQuantity + $needQuantity;
$needReservedQuantity = $catalogReservedQuantity - $needQuantity;
if ($needQuantity > $catalogReservedQuantity)
{
$needReservedQuantity = $catalogReservedQuantity;
}
$fields["QUANTITY_RESERVED"] = $needReservedQuantity;
if (self::isNeedClearPublicCache(
$catalogData['QUANTITY'],
$fields['QUANTITY'],
$catalogData['QUANTITY_TRACE'],
$catalogData['CAN_BUY_ZERO']
))
{
$productInfo = array(
'CAN_BUY_ZERO' => $catalogData['CAN_BUY_ZERO'],
'QUANTITY_TRACE' => $catalogData['QUANTITY_TRACE'],
'OLD_QUANTITY' => $catalogData['QUANTITY'],
'QUANTITY' => $fields['QUANTITY'],
'DELTA' => $fields['QUANTITY'] - $catalogData['QUANTITY']
);
self::clearPublicCache($catalogData['ID'], $productInfo);
}
}
} //quantity trace
if (!empty($fields) && is_array($fields))
{
$resultFields['IS_UPDATED'] = \CCatalogProduct::Update($productId, $fields);
if ($resultFields['IS_UPDATED'])
{
$quantityValues = array();
if (isset($fields['QUANTITY']))
{
$quantityValues[QuantityControl::QUANTITY_CONTROL_QUANTITY] = $fields['QUANTITY'];
QuantityControl::resetAvailableQuantity($productId);
}
if (isset($fields['QUANTITY_RESERVED']))
{
$quantityValues[QuantityControl::QUANTITY_CONTROL_RESERVED_QUANTITY] = $fields['QUANTITY_RESERVED'];
}
if (!empty($quantityValues))
{
QuantityControl::setValues($productId, $quantityValues);
}
}
}
if (isset($resultFields['IS_UPDATED']))
{
$needReserved = $fields["QUANTITY_RESERVED"] - $resultFields['QUANTITY_RESERVED'];
if ($resultFields['QUANTITY_RESERVED'] > $fields["QUANTITY_RESERVED"])
{
$needReserved = $fields["QUANTITY_RESERVED"];
}
$resultFields["QUANTITY_RESERVED"] = $needReserved;
if (!empty($resultFields))
{
$result->setData($resultFields);
}
}
return $result;
}
/**
* @param array $productData
*
* @return Sale\Result
*/
private static function reserveQuantityWithDisabledReservation(array $productData)
{
$result = new Sale\Result();
$catalogData = $productData['CATALOG'];
$isQuantityTrace = $catalogData["QUANTITY_TRACE"] == 'Y';
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
$catalogQuantity = 0;
if (array_key_exists('QUANTITY', $catalogData))
{
$catalogQuantity = floatval($catalogData['QUANTITY']);
}
elseif (!empty($catalogData['PRICE_LIST']))
{
foreach ($catalogData['PRICE_LIST'] as $basketCode => $catalogValue)
{
$catalogQuantity += floatval($catalogValue['QUANTITY']);
}
}
$isUpdated = true;
$fields = array(
'QUANTITY' => $catalogQuantity
);
if ($isQuantityTrace)
{
$productId = $productData['PRODUCT_ID'];
$fields['QUANTITY'] -= $productQuantity;
if ($catalogData["CAN_BUY_ZERO"] != "Y" && ($catalogQuantity < $productQuantity))
{
$result->addWarning(
new Sale\ResultWarning(
Main\Localization\Loc::getMessage(
"RESERVE_QUANTITY_NOT_ENOUGH_ERROR",
array_merge(
self::getProductCatalogInfo($productId),
array("#PRODUCT_ID#" => $productId)
)
), "RESERVE_QUANTITY_NOT_ENOUGH_ERROR"
)
);
$fields['QUANTITY'] = 0;
}
$isUpdated = \CCatalogProduct::Update($productId, $fields);
}
if ($isUpdated)
{
$result->setData($fields);
}
return $result;
}
/**
* Checks offers parent products existence and activity.
*
* @param $productIds
* @param int $iblockId
*
* @return array
*/
private static function checkParentActivity($productIds, $iblockId = 0)
{
$resultList = array();
$productIdsToLoad = array();
foreach ($productIds as $productId)
{
$cacheKey = $productId.'|'.$iblockId;
if (static::isExistsHitCache(self::CACHE_PARENT_PRODUCT_ACTIVE, $cacheKey))
{
if (static::getHitCache(self::CACHE_PARENT_PRODUCT_ACTIVE, $cacheKey) === 'Y')
{
$resultList[] = $productId;
}
}
else
{
$productIdsToLoad[] = $productId;
}
}
if (!empty($productIdsToLoad))
{
$productToOfferMap = array();
$parentIds = array();
$cacheResult = array_fill_keys($productIdsToLoad, 'N');
$productList = \CCatalogSku::getProductList($productIdsToLoad);
if (!empty($productList))
{
foreach ($productList as $offerId => $productInfo)
{
$productToOfferMap[$productInfo['ID']][] = $offerId;
$parentIds[] = $productInfo['ID'];
}
$itemList = \CIBlockElement::GetList(
array(),
array(
'ID' => array_unique($parentIds),
'IBLOCK_ID' => $iblockId,
'ACTIVE' => 'Y',
'ACTIVE_DATE' => 'Y',
'CHECK_PERMISSIONS' => 'N'
),
false,
false,
array('ID')
);
while ($item = $itemList->Fetch())
{
if (!empty($productToOfferMap[$item['ID']]))
{
foreach ($productToOfferMap[$item['ID']] as $productId)
{
$cacheResult[$productId] = 'Y';
$resultList[] = $productId;
}
}
}
}
foreach ($cacheResult as $productId => $value)
{
static::setHitCache(self::CACHE_PARENT_PRODUCT_ACTIVE, $productId.'|'.$iblockId, $value);
}
}
return $resultList;
}
/**
* @param $priceType
*
* @return string
*/
protected static function getPriceTitle($priceType)
{
$priceType = (int)$priceType;
if ($priceType <= 0)
return '';
if (!isset(self::$priceTitleCache[$priceType]))
{
self::$priceTitleCache[$priceType] = '';
$priceTypeList = \CCatalogGroup::GetListArray();
if (isset($priceTypeList[$priceType]))
{
$groupName = (string)$priceTypeList[$priceType]['NAME_LANG'];
self::$priceTitleCache[$priceType] = ($groupName != '' ? $groupName : $priceTypeList[$priceType]['NAME']);
unset($groupName);
}
unset($priceTypeList);
}
return self::$priceTitleCache[$priceType];
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function tryShip(array $products)
{
$result = new Sale\Result();
$resultList = array();
$useStoreControl = Catalog\Config\State::isUsedInventoryManagement();
$filteredProducts = $this->createQuantityFilteredProducts($products);
if (empty($filteredProducts))
{
$result->setData(
array(
'TRY_SHIP_PRODUCTS_LIST' => array_fill_keys(array_keys($products), true)
)
);
return $result;
}
$availableItems = $this->createProductsListWithCatalogData($filteredProducts);
if (empty($availableItems))
{
$productIdList = array_keys($products);
foreach($productIdList as $productId)
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"SALE_PROVIDER_PRODUCT_NOT_AVAILABLE",
array_merge(
self::getProductCatalogInfo($productId),
array("#PRODUCT_ID#" => $productId)
)
), "SALE_PROVIDER_PRODUCT_NOT_AVAILABLE"
)
);
}
$result->setData(
array(
'TRY_SHIP_PRODUCTS_LIST' => array_fill_keys($productIdList, false)
)
);
return $result;
}
else
{
foreach ($availableItems as $productId => $productData)
{
if (!isset($productData['CATALOG']['ACTIVE']) || $productData['CATALOG']['ACTIVE'] != 'Y')
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"SALE_PROVIDER_PRODUCT_NOT_AVAILABLE",
array_merge(
self::getProductCatalogInfo($productId),
array("#PRODUCT_ID#" => $productId)
)
), "SALE_PROVIDER_PRODUCT_NOT_AVAILABLE"
)
);
$resultList[$productId] = false;
unset($availableItems[$productId]);
}
}
}
if (!empty($availableItems))
{
if ($useStoreControl)
{
$r = $this->checkProductsInStore($availableItems);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCTS_LIST_IN_STORE']))
{
$resultList = $resultList + $data['PRODUCTS_LIST_IN_STORE'];
}
}
else
{
$result->addErrors($r->getErrors());
}
}
else
{
$r = $this->checkProductsQuantity($availableItems);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCTS_LIST_REQUIRED_QUANTITY']))
{
$resultList = $resultList + $data['PRODUCTS_LIST_REQUIRED_QUANTITY'];
}
}
else
{
$result->addErrors($r->getErrors());
}
}
}
if (!empty($resultList))
{
$result->setData(
array(
'TRY_SHIP_PRODUCTS_LIST' => $resultList
)
);
}
return $result;
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function isNeedShip(array $products)
{
$result = new Sale\Result();
$result->setData(
array(
'IS_NEED_SHIP' => static::isReservationEnabled()
)
);
return $result;
}
/**
* @param array $products
*
* @return array
*/
private function createQuantityFilteredProducts(array $products)
{
$resultList = array();
foreach ($products as $productId => $productData)
{
$resultList[$productId] = $productData;
if (array_key_exists('QUANTITY', $productData))
{
if ($productData['QUANTITY'] > 0)
{
unset($resultList[$productId]);
}
else
{
$resultList[$productId] *= -1;
}
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
if ($quantity > 0)
{
unset($resultList[$productId]['QUANTITY_LIST'][$basketCode]);
}
else
{
$resultList[$productId]['QUANTITY_LIST'][$basketCode] *= -1;
}
}
if (empty($resultList[$productId]['QUANTITY_LIST']))
{
unset($resultList[$productId]);
}
}
}
return $resultList;
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function tryUnship(array $products)
{
$result = new Sale\Result();
$resultList = array();
$availableItems = $this->createProductsListWithCatalogData($products);
if (Catalog\Config\State::isUsedInventoryManagement())
{
$r = $this->checkProductsInStore($availableItems);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCTS_LIST_IN_STORE']))
{
$resultList = $data['PRODUCTS_LIST_IN_STORE'];
}
}
}
else
{
$r = $this->checkProductsQuantity($availableItems);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCTS_LIST_REQUIRED_QUANTITY']))
{
$resultList = $data['PRODUCTS_LIST_REQUIRED_QUANTITY'];
}
}
else
{
return $r;
}
}
if (!empty($resultList))
{
$result->setData(array(
'PRODUCTS_LIST_SHIPPED' => $resultList
));
}
return $result;
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function checkProductsInStore(array $products)
{
$result = new Sale\Result();
$resultList = array();
$r = $this->checkProductInStores($products);
if (!$r->isSuccess())
{
return $r;
}
$storeProductMap = $this->createStoreProductMap($products);
$r = $this->checkExistsProductsInStore($products, $storeProductMap);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCTS_LIST_EXISTS_IN_STORE']))
{
$resultList = $data['PRODUCTS_LIST_EXISTS_IN_STORE'];
}
}
else
{
return $r;
}
$r = $this->checkProductQuantityInStore($products);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCTS_LIST_REQUIRED_QUANTITY_IN_STORE']))
{
$resultList = $data['PRODUCTS_LIST_REQUIRED_QUANTITY_IN_STORE'];
}
}
else
{
$result->addErrors($r->getErrors());
}
if (!empty($resultList))
{
$result->addData(
array(
'PRODUCTS_LIST_IN_STORE' => $resultList
)
);
}
return $result;
}
/**
* @param array $products
*
* @return Sale\Result
* @throws Main\SystemException
*/
private function checkProductsQuantity(array $products)
{
$result = new Sale\Result();
$resultList = array();
$availableQuantityList = array();
$r = $this->getAvailableQuantity($products);
if ($r->isSuccess())
{
$resultData = $r->getData();
if (!empty($resultData['AVAILABLE_QUANTITY_LIST']))
{
$availableQuantityList = $resultData['AVAILABLE_QUANTITY_LIST'];
}
}
else
{
return $r;
}
foreach ($products as $productId => $productData)
{
if (empty($productData['CATALOG']))
{
$resultList[$productId] = false;
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"SALE_PROVIDER_PRODUCT_NOT_AVAILABLE",
array_merge(
self::getProductCatalogInfo($productId),
array("#PRODUCT_ID#" => $productId)
)
), "SALE_PROVIDER_PRODUCT_NOT_AVAILABLE"
)
);
continue;
}
$resultList[$productId] = true;
$catalogData = $productData['CATALOG'];
if ($catalogData["CAN_BUY_ZERO"] != "Y" && $catalogData["QUANTITY_TRACE"] == "Y")
{
$productQuantity = 0;
$productReservedQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
$availableQuantity = 0;
if (isset($availableQuantityList[$productId]))
{
$availableQuantity = $availableQuantityList[$productId];
}
$availableQuantity += floatval($catalogData['QUANTITY_RESERVED']);
$enabledReservation = static::isReservationEnabled();
if ($enabledReservation && $productQuantity > $availableQuantity)
{
$resultList[$productId] = false;
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_QUANTITY_ERROR",
array_merge(
self::getProductCatalogInfo($productId),
array("#PRODUCT_ID#" => $productId)
)
), "DDCT_DEDUCTION_QUANTITY_ERROR"
)
);
}
}
}
if (!empty($resultList))
{
$result->setData(
array(
'PRODUCTS_LIST_REQUIRED_QUANTITY' => $resultList
)
);
}
return $result;
}
/**
* @param array $products
*
* @return array
*/
private function createProductsListWithCatalogData(array $products)
{
$productDataList = array();
$productIdList = array_keys($products);
$r = $this->getData($products, array('CATALOG_DATA', 'FULL_QUANTITY'));
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data[static::RESULT_CATALOG_LIST]))
{
$productDataList = $data[static::RESULT_CATALOG_LIST];
}
}
$resultList = array();
$availableListId = array_intersect_key($productIdList, array_keys($productDataList));
if (!empty($availableListId))
{
foreach ($availableListId as $productId)
{
if ($productDataList[$productId] === false)
{
continue;
}
$resultList[$productId] = $products[$productId];
$resultList[$productId]['CATALOG'] = $productDataList[$productId];
}
}
return $resultList;
}
/**
* @param array $products
*
* @return array|bool
* @throws Main\ObjectNotFoundException
*/
protected function createStoreProductMap(array $products)
{
$productStoreDataList = array();
$r = $this->getProductListStores($products);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCT_STORES_LIST']))
{
$productStoreDataList = $data['PRODUCT_STORES_LIST'];
}
}
$canAutoShipList = array();
$r = $this->canProductListAutoShip($products);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCT_CAN_AUTOSHIP_LIST']))
{
$canAutoShipList = $data['PRODUCT_CAN_AUTOSHIP_LIST'];
}
}
$storeProductList = array();
foreach ($products as $productId => $productData)
{
if (!empty($productData['STORE_DATA_LIST']) && static::isExistsBarcode($productData['STORE_DATA_LIST']))
{
$storeProductList[$productId] = $productData['STORE_DATA_LIST'];
continue;
}
elseif (!empty($canAutoShipList[$productId]) && !empty($productStoreDataList[$productId]))
{
foreach ($productData['SHIPMENT_ITEM_DATA_LIST'] as $shipmentItemIndex => $shipmentItemQuantity)
{
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
foreach ($productStoreDataList[$productId] as $productStoreData)
{
$storeId = $productStoreData['STORE_ID'];
$storeProductList[$productId][$shipmentItemIndex][$storeId] = array(
'PRODUCT_ID' => $productId,
'STORE_ID' => $storeId,
'IS_BARCODE_MULTI' => false,
'QUANTITY' => abs($productQuantity)
);
}
}
}
}
return $storeProductList;
}
private function checkProductInStores($products)
{
$result = new Sale\Result();
$productStoreDataList = array();
$canAutoShipList = array();
$r = $this->canProductListAutoShip($products);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCT_CAN_AUTOSHIP_LIST']))
{
$canAutoShipList = $data['PRODUCT_CAN_AUTOSHIP_LIST'];
}
}
$r = $this->getProductListStores($products);
if ($r->isSuccess())
{
$data = $r->getData();
if (!empty($data['PRODUCT_STORES_LIST']))
{
$productStoreDataList = $data['PRODUCT_STORES_LIST'];
}
}
foreach ($products as $productId => $productData)
{
if (!empty($productData['STORE_DATA_LIST']))
{
if (!static::isExistsBarcode($productData['STORE_DATA_LIST']))
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_MULTI_BARCODE_EMPTY", self::getProductCatalogInfo($productId)
), "DDCT_DEDUCTION_MULTI_BARCODE_EMPTY"
)
);
}
continue;
}
elseif ($canAutoShipList[$productId] === false && count($productStoreDataList[$productId]) > 1)
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_STORE_ERROR",
self::getProductCatalogInfo($productId)
), "DEDUCTION_STORE_ERROR1"
)
);
}
}
return $result;
}
private static function isExistsBarcode(array $list)
{
$resultValue = false;
foreach ($list as $shipmentItemIndex => $storeDataList)
{
foreach ($storeDataList as $storeId => $storeValue)
{
if (is_array($storeValue['BARCODE']) && $storeValue['IS_BARCODE_MULTI'] === true)
{
foreach ($storeValue["BARCODE"] as $barcodeId => $barcodeValue)
{
if (strval(trim($barcodeValue)) == "")
{
return $resultValue;
}
}
$resultValue = true;
}
else
{
return (!empty($storeValue['BARCODE']));
}
}
}
return $resultValue;
}
/**
* @param array $products
*
* @return Sale\Result
*/
protected function checkProductQuantityInStore(array $products)
{
$result = new Sale\Result();
$productIdList = array_keys($products);
$resultList = array();
$productQuantityList = array();
$productStoreDataList = array();
$resProps = \CCatalogStoreProduct::GetList(
array(),
array(
"PRODUCT_ID" => $productIdList,
),
false,
false,
array('ID', 'AMOUNT', 'STORE_ID', 'PRODUCT_ID')
);
while($productStoreData = $resProps->Fetch())
{
$productStoreDataList[$productStoreData['PRODUCT_ID']][$productStoreData['STORE_ID']] = $productStoreData;
}
foreach ($products as $productId => $productData)
{
if (empty($productData['CATALOG']))
continue;
$productStoreData = $productStoreDataList[$productId];
$storeDataList = $productData['STORE_DATA_LIST'];
if (!empty($storeDataList))
{
foreach ($storeDataList as $shipmentItemIndex => $barcodeList)
{
foreach($barcodeList as $storeId => $storeDataValue)
{
if (!empty($storeDataValue))
{
if (!isset($productStoreData[$storeId]) || ($productStoreData[$storeId]["AMOUNT"] < $storeDataValue["QUANTITY"]))
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_QUANTITY_STORE_ERROR",
array_merge(
self::getProductCatalogInfo($productId),
array("#STORE_ID#" => $storeId)
)
), "DDCT_DEDUCTION_QUANTITY_STORE_ERROR"
)
);
continue;
}
else
{
if (!isset($productQuantityList[$productId]))
{
$productQuantityList[$productId] = 0;
}
$productQuantityList[$productId] += $storeDataValue["QUANTITY"];
$r = static::checkProductBarcodes($productData, $productStoreData[$storeId], $storeDataValue);
if ($r->isSuccess())
{
if (!array_key_exists($productId, $resultList))
{
$resultList[$productId] = true;
}
}
else
{
$result->addErrors($r->getErrors());
}
}
}
else
{
if (!array_key_exists($productId, $resultList))
{
$resultList[$productId] = true;
}
}
}
}
}
else
{
$resultList[$productId] = true;
if (!isset($productQuantityList[$productId]))
{
$productQuantityList[$productId] = 0;
}
if (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantityList[$productId] += $quantity;
}
}
}
}
if (!empty($productQuantityList))
{
foreach ($productQuantityList as $amountProductId => $amountValue)
{
$product = $products[$amountProductId];
$catalogData = $product['CATALOG'];
$catalogReservedQuantity = floatval($catalogData['QUANTITY_RESERVED']);
$catalogQuantity = 0;
if (array_key_exists('QUANTITY', $catalogData))
{
$catalogQuantity = floatval($catalogData['QUANTITY']);
}
elseif (!empty($catalogData['PRICE_LIST']))
{
foreach ($catalogData['PRICE_LIST'] as $basketCode => $catalogValue)
{
$catalogQuantity += floatval($catalogValue['QUANTITY']);
}
}
if ($product['RESERVED_QUANTITY_LIST'][$product['BASKET_CODE']] > 0)
{
$catalogQuantity += $catalogReservedQuantity;
}
if ($amountValue > $catalogQuantity)
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"SALE_PROVIDER_SHIPMENT_QUANTITY_NOT_ENOUGH",
self::getProductCatalogInfo($amountProductId)
), "SALE_PROVIDER_SHIPMENT_QUANTITY_NOT_ENOUGH"
)
);
}
}
}
if (!empty($resultList))
{
$result->setData(
array(
'PRODUCTS_LIST_REQUIRED_QUANTITY_IN_STORE' => $resultList,
)
);
}
return $result;
}
/**
* @param array
* @param array $storeDataList
*
* @return Sale\Result
*/
protected function checkExistsProductItemInStore(array $productData, array $storeDataList = array())
{
$result = new Sale\Result();
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
// if ($productQuantity > 0)
// return $result;
if (!empty($storeDataList))
{
foreach ($storeDataList as $shipmentItemIndex => $storeData)
{
foreach ($storeData as $storeDataValue)
{
$storeId = $storeDataValue['STORE_ID'];
if (intval($storeId) < -1 || intval($storeId) == 0
|| !isset($storeDataValue["QUANTITY"]) || intval($storeDataValue["QUANTITY"]) < 0)
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_STORE_ERROR",
self::getProductCatalogInfo($productData['PRODUCT_ID'])
), "DDCT_DEDUCTION_STORE_ERROR"
)
);
return $result;
}
}
}
}
else
{
$result->addError( new Sale\ResultError(
Main\Localization\Loc::getMessage("DDCT_DEDUCTION_STORE_ERROR", self::getProductCatalogInfo($productData['PRODUCT_ID'])),
"DEDUCTION_STORE_ERROR1"
));
}
return $result;
}
/**
* @param array $products
* @param array $storeData
*
* @return Sale\Result
*/
protected function checkExistsProductsInStore(array $products, array $storeData = array())
{
$result = new Sale\Result();
$resultList = array();
if (!empty($storeData))
{
foreach ($products as $productId => $productData)
{
$productStoreData = array();
if (!empty($storeData[$productId]))
{
$productStoreData = $storeData[$productId];
}
$resultList[$productId] = true;
if (isset($productData['BUNDLE_PARENT']) && $productData['BUNDLE_PARENT'] === true)
{
continue;
}
$r = $this->checkExistsProductItemInStore($productData, $productStoreData);
if (!$r->isSuccess())
{
$result->addErrors($r->getErrors());
$resultList[$productId] = false;
}
}
}
if (!empty($resultList))
{
$result->setData(
array(
'PRODUCTS_LIST_EXISTS_IN_STORE' => $resultList
)
);
}
return $result;
}
/**
* @param array $productData
* @param array $productStoreData
* @param array $storeData
*
* @return Sale\Result
*/
protected static function checkProductBarcodes(array $productData, array $productStoreData, array $storeData = array())
{
$result = new Sale\Result();
$productId = $productData['PRODUCT_ID'];
$storeId = $productStoreData['STORE_ID'];
if (isset($storeData['BARCODE']) && count($storeData['BARCODE']) > 0)
{
foreach ($storeData['BARCODE'] as $barcodeId => $barcodeValue)
{
if (strval(trim($barcodeValue)) == "" && $storeData['IS_BARCODE_MULTI'] === true)
{
$result->addError(
new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_MULTI_BARCODE_EMPTY",
array_merge(
self::getProductCatalogInfo($productId),
array("#STORE_ID#" => $storeId)
)
), "DDCT_DEDUCTION_MULTI_BARCODE_EMPTY"
)
);
continue;
}
if (!empty($barcodeValue))
{
$fields = array(
"STORE_ID" => static::CATALOG_PROVIDER_EMPTY_STORE_ID,
"BARCODE" => $barcodeValue,
"PRODUCT_ID" => $productId
);
if ($storeData['IS_BARCODE_MULTI'] === true)
{
$fields['STORE_ID'] = $storeId;
}
$dbres = \CCatalogStoreBarcode::GetList(
array(),
$fields,
false,
false,
array("ID", "STORE_ID", "BARCODE", "PRODUCT_ID")
);
if (!$catalogStoreBasrcodeRes = $dbres->Fetch())
{
$result->addError( new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_BARCODE_ERROR",
array_merge(self::getProductCatalogInfo($productId), array("#BARCODE#" => $barcodeValue))
),
"DDCT_DEDUCTION_BARCODE_ERROR"
));
}
}
}
}
else
{
$result->addError( new Sale\ResultError(
Main\Localization\Loc::getMessage(
"DDCT_DEDUCTION_MULTI_BARCODE_EMPTY",
array_merge(self::getProductCatalogInfo($productId), array("#STORE_ID#" => $storeId))
),
"DDCT_DEDUCTION_MULTI_BARCODE_EMPTY"
));
}
return $result;
}
/**
* @param array $products
*
* @return Sale\Result
* @throws Main\ArgumentNullException
*/
private function canProductListAutoShip(array $products)
{
$context = $this->getContext();
if (empty($context['SITE_ID']))
{
throw new Main\ArgumentNullException('SITE_ID');
}
static $canAutoList = array();
$resultList = array();
$hasNew = false;
$countStores = 0;
$isOneStore = false;
$isDefaultStore = false;
$countStoresResult = $this->getStoresCount();
if ($countStoresResult->isSuccess())
{
$countStores = $countStoresResult->get('STORES_COUNT');
}
$countStoresResult->getData();
$defaultDeductionStore = Main\Config\Option::get("sale", "deduct_store_id", "", $context['SITE_ID']);
foreach ($products as $productId => $productData)
{
if (isset($canAutoList[$productId]))
{
$resultList[$productId] = $canAutoList[$productId];
continue;
}
$isOneStore = ($countStores == 1 || $countStores == -1);
$isDefaultStore = ($defaultDeductionStore > 0);
$isOnlyOneStore = ($isOneStore || $isDefaultStore);
$isMulti = false;
if (isset($productData['STORE_DATA_LIST']))
{
$storeData = array();
$shipmentItemStoreData = reset($productData['STORE_DATA_LIST']);
if (!empty($shipmentItemStoreData))
{
$storeData = reset($shipmentItemStoreData);
}
if (!empty($storeData))
{
$isMulti = isset($storeData['IS_BARCODE_MULTI']) && $storeData['IS_BARCODE_MULTI'] === true;
}
}
elseif (isset($productData['IS_BARCODE_MULTI']))
{
$isMulti = isset($productData['IS_BARCODE_MULTI']) && $productData['IS_BARCODE_MULTI'] === true;
}
$resultList[$productId] = ($isOnlyOneStore && !$isMulti);
$hasNew = true;
if ($isMulti)
{
$hasNew = false;
}
}
if ($hasNew)
{
$productStoreList = array();
$r = $this->getProductListStores($products);
if ($r->isSuccess())
{
$productStoreData = $r->getData();
if (array_key_exists('PRODUCT_STORES_LIST', $productStoreData))
{
$productStoreList = $productStoreData['PRODUCT_STORES_LIST'];
}
}
if (!empty($productStoreList))
{
foreach ($products as $productId => $productData)
{
if (!empty($productStoreList[$productId]))
{
$countProductInStore = 0;
$storeDataList = $productStoreList[$productId];
if (!empty($storeDataList))
{
foreach ($storeDataList as $storeId => $storeData)
{
if (floatval($storeData['AMOUNT']) > 0)
{
$countProductInStore++;
}
}
}
$resultList[$productId] = ($countProductInStore == 1);
$canAutoList[$productId] = $resultList[$productId];
}
}
}
}
$result = new Sale\Result();
if (!empty($resultList))
{
$result->setData(
array(
'PRODUCT_CAN_AUTOSHIP_LIST' => $resultList
)
);
}
return $result;
}
/**
* @param array $product
* @param array $productStoreDataList
*
* @return bool|array
*/
private static function getAutoShipStoreData(array $product, array $productStoreDataList)
{
$isMulti = false;
if (isset($product['STORE_DATA_LIST']))
{
$storeData = [];
$shipmentItemStoreData = reset($product['STORE_DATA_LIST']);
if (!empty($shipmentItemStoreData))
{
$storeData = reset($shipmentItemStoreData);
}
if (!empty($storeData))
{
$isMulti = isset($storeData['IS_BARCODE_MULTI']) && $storeData['IS_BARCODE_MULTI'] === true;
}
}
elseif (isset($product['IS_BARCODE_MULTI']))
{
$isMulti = isset($product['IS_BARCODE_MULTI']) && $product['IS_BARCODE_MULTI'] === true;
}
if ($isMulti)
{
return false;
}
$outputStoreData = false;
if (!empty($productStoreDataList))
{
$countProductInStore = 0;
$storeProductData = false;
foreach ($productStoreDataList as $storeId => $storeData)
{
if (floatval($storeData['AMOUNT']) > 0)
{
$countProductInStore++;
if (!$storeProductData)
{
$storeProductData = $storeData;
}
}
}
if ($countProductInStore == 1 && !empty($storeProductData))
{
$outputStoreData = $storeProductData;
}
}
return $outputStoreData;
}
/**
* @param array $products
*
* @return mixed
*/
protected function getCountProductsInStore(array $products)
{
$result = new Sale\Result();
$productStoreList = array();
$productStoreResult = $this->getProductListStores($products);
if ($productStoreResult->isSuccess())
{
$productStoreData = $productStoreResult->getData();
if (array_key_exists('PRODUCT_STORES_LIST', $productStoreData))
{
$productStoreList = $productStoreData['PRODUCT_STORES_LIST'];
}
}
if (empty($productStoreList))
{
return $result;
}
$resultList = array();
foreach ($productStoreList as $productId => $productStoreDataList)
{
foreach ($productStoreDataList as $storeId =>$productStoreData)
{
$productId = $productStoreData['PRODUCT_ID'];
if ($productStoreData['AMOUNT'] > 0)
{
if (!array_key_exists($productId, $resultList) || !array_key_exists($storeId, $resultList[$productId]))
{
$resultList[$productId][$storeId] = 0;
}
$resultList[$productId][$storeId] = $productStoreData['AMOUNT'];
}
}
}
if (!empty($resultList))
{
$result->setData(
array(
'RESULT_LIST' => $resultList
)
);
}
return $result;
}
/**
* @internal
* @return Sale\Result
*/
public function getStoresCount()
{
$result = new Sale\Result();
$count = -1;
if (Catalog\Config\State::isUsedInventoryManagement())
{
$count = count($this->getStoreIds());
}
$result->setData(
array(
'STORES_COUNT' => $count
)
);
return $result;
}
/**
* @return array|false
*/
private function getStoreIds()
{
$context = $this->getContext();
$filterId = array('ACTIVE' => 'Y', 'SHIPPING_CENTER' => 'Y');
if (isset($context['SITE_ID']) && $context['SITE_ID'] != '')
$filterId['+SITE_ID'] = $context['SITE_ID'];
$cacheId = md5(serialize($filterId));
$storeIds = static::getHitCache(self::CACHE_STORE, $cacheId);
if (empty($storeIds))
{
$storeIds = array();
$filter = Main\Entity\Query::filter();
$filter->where('ACTIVE', '=', 'Y');
$filter->where('SHIPPING_CENTER', '=', 'Y');
if (isset($context['SITE_ID']) && $context['SITE_ID'] != '')
{
$subFilter = Main\Entity\Query::filter();
$subFilter->logic('or')->where('SITE_ID', '=', $context['SITE_ID'])->where('SITE_ID', '=', '')->whereNull('SITE_ID');
$filter->where($subFilter);
unset($subFilter);
}
$iterator = Catalog\StoreTable::getList(array(
'select' => array('ID'),
'filter' => $filter,
'order' => array('ID' => 'ASC')
));
while ($row = $iterator->fetch())
$storeIds[] = (int)$row['ID'];
unset($row, $iterator, $filter);
if (!empty($storeIds))
static::setHitCache(self::CACHE_STORE, $cacheId, $storeIds);
}
unset($cacheId, $filterId);
return $storeIds;
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function getProductListStores(array $products)
{
$result = new Sale\Result();
//without store control stores are used for information purposes only
if (!Catalog\Config\State::isUsedInventoryManagement())
return $result;
$resultList = array();
$storeIds = $this->getStoreIds();
if (empty($storeIds))
return $result;
$productGetIdList = array();
foreach ($products as $productId => $productData)
{
$cacheId = md5($productId);
$storeProductDataList = static::getHitCache(self::CACHE_STORE_PRODUCT, $cacheId);
if (!empty($storeProductDataList))
{
$resultList[$productId] = $storeProductDataList;
}
else
{
$productGetIdList[$productId] = $productId;
}
}
if (!empty($productGetIdList))
{
$iterator = Catalog\StoreProductTable::getList(array(
'select' => array('PRODUCT_ID', 'AMOUNT', 'STORE_ID', 'STORE_NAME' => 'STORE.TITLE', 'ID'),
'filter' => array('=PRODUCT_ID' => $productGetIdList, '@STORE_ID' => $storeIds),
'order' => array('STORE_ID' => 'ASC')
));
while ($row = $iterator->fetch())
{
$resultList[$row['PRODUCT_ID']][$row['STORE_ID']] = $row;
}
foreach ($productGetIdList as $productId)
{
if (!empty($resultList[$productId]))
{
$cacheId = md5($productId);
static::setHitCache(self::CACHE_STORE_PRODUCT, $cacheId, $resultList[$productId]);
}
}
}
if (!empty($resultList))
{
$result->setData(
array(
'PRODUCT_STORES_LIST' => $resultList
)
);
}
return $result;
}
/**
* @param $type
* @param $key
* @param array $fields
*
* @return bool|mixed
*/
protected static function getHitCache($type, $key, array $fields = array())
{
if (!empty(self::$hitCache[$type]) && !empty(self::$hitCache[$type][$key]))
{
if (static::isExistsHitCache($type, $key, $fields))
{
return self::$hitCache[$type][$key];
}
}
return false;
}
/**
* @param $type
* @param $key
* @param array $fields
*
* @return bool
*/
protected static function isExistsHitCache($type, $key, array $fields = array())
{
$isExists = false;
if (!empty(self::$hitCache[$type]) && !empty(self::$hitCache[$type][$key]))
{
$isExists = true;
if (!empty($fields) && is_array($fields) && is_array(self::$hitCache[$type][$key]))
{
foreach ($fields as $name)
{
if (!array_key_exists($name, self::$hitCache[$type][$key]))
{
$isExists = false;
break;
}
}
}
}
return $isExists;
}
/**
* @param string $type
* @param string $key
* @param mixed $value
*/
protected static function setHitCache($type, $key, $value)
{
if (empty(self::$hitCache[$type]))
self::$hitCache[$type] = array();
if (empty(self::$hitCache[$type][$key]))
self::$hitCache[$type][$key] = array();
self::$hitCache[$type][$key] = $value;
}
/**
* @param string|null $type
*/
protected static function clearHitCache($type = null)
{
if ($type === null)
self::$hitCache = array();
if (!empty(self::$hitCache[$type]))
unset(self::$hitCache[$type]);
}
/**
* @param $fields
*
* @return array
*/
protected static function clearNotCacheFields($fields)
{
$resultFields = array();
$clearFields = static::getNotCacheFields();
foreach ($fields as $name => $value)
{
$clearName = $name;
if (substr($clearName, 0, 1) == '~')
{
$clearName = substr($clearName, 1, strlen($clearName));
}
if (!in_array($clearName, $clearFields))
{
$resultFields[$name] = $value;
}
}
return $resultFields;
}
/**
* @return array
*/
protected static function getNotCacheFields()
{
return array(
'CAN_BUY_ZERO',
'QUANTITY_TRACE',
'QUANTITY',
'CAN_BUY',
);
}
protected static function checkNeedFields(array $fields, array $need)
{
foreach ($need as $name => $value)
{
if (!array_key_exists($name, $fields))
{
return false;
}
}
return true;
}
protected static function isNeedClearPublicCache($currentQuantity, $newQuantity, $quantityTrace, $canBuyZero, $ratio = 1)
{
if (!defined('BX_COMP_MANAGED_CACHE'))
return false;
if ($canBuyZero == 'Y' || $quantityTrace == 'N')
return false;
if ($currentQuantity * $newQuantity > 0)
return false;
return true;
}
protected static function clearPublicCache($productID, $productInfo = array())
{
$productID = (int)$productID;
if ($productID <= 0)
return;
$iblockID = (int)(isset($productInfo['IBLOCK_ID']) ? $productInfo['IBLOCK_ID'] : \CIBlockElement::GetIBlockByID($productID));
if ($iblockID <= 0)
return;
if (!isset(self::$clearAutoCache[$iblockID]))
{
\CIBlock::clearIblockTagCache($iblockID);
self::$clearAutoCache[$iblockID] = true;
}
$productInfo['ID'] = $productID;
$productInfo['ELEMENT_IBLOCK_ID'] = $iblockID;
$productInfo['IBLOCK_ID'] = $iblockID;
if (isset($productInfo['CAN_BUY_ZERO']))
$productInfo['NEGATIVE_AMOUNT_TRACE'] = $productInfo['CAN_BUY_ZERO'];
foreach (GetModuleEvents('catalog', 'OnProductQuantityTrace', true) as $eventData)
ExecuteModuleEventEx($eventData, array($productID, $productInfo));
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function getAvailableQuantity(array $products)
{
$result = new Sale\Result();
$resultList = array();
$isGotQuantityDataList = array();
foreach ($products as $productId => $productData)
{
$catalogAvailableQuantity = QuantityControl::getAvailableQuantity($productId);
$catalogQuantity = QuantityControl::getQuantity($productId);
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
if ($catalogQuantity === null || ($catalogAvailableQuantity === null || $catalogAvailableQuantity < $productQuantity))
{
continue;
}
$isGotQuantityDataList[$productId] = true;
$catalogSumQuantity = $catalogAvailableQuantity;
$resultList[$productId] = $catalogSumQuantity >= $productQuantity ? $productQuantity : $catalogQuantity;
}
if (count($resultList) != count($products))
{
if ($this->isExistsCatalogData($products))
{
$items = $products;
}
else
{
$items = $this->createProductsListWithCatalogData($products);
}
foreach ($items as $productId => $productData)
{
$productReservedQuantity = 0;
if (!empty($productData['RESERVED_QUANTITY_LIST']))
{
foreach ($productData['RESERVED_QUANTITY_LIST'] as $basketCode => $quantity)
{
$productReservedQuantity += $quantity;
}
}
if (isset($isGotQuantityDataList[$productId]))
continue;
$catalogData = $productData['CATALOG'];
$catalogQuantity = 0;
$catalogReservedQuantity = $catalogData['QUANTITY_RESERVED'];
QuantityControl::setReservedQuantity($productId, $catalogReservedQuantity);
$productQuantity = 0;
if (array_key_exists('QUANTITY', $productData))
{
$productQuantity = $productData['QUANTITY'];
}
elseif (!empty($productData['QUANTITY_LIST']))
{
foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
$productQuantity += $quantity;
}
}
$resultList[$productId] = $productQuantity;
if (isset($catalogData))
{
if (!empty($catalogData['PRICE_LIST']))
{
foreach ($catalogData['PRICE_LIST'] as $basketCode => $catalogValue)
{
$catalogQuantity += $catalogValue['QUANTITY'];
}
}
elseif (array_key_exists('QUANTITY', $catalogData))
{
$catalogQuantity = $catalogData['QUANTITY'];
}
}
QuantityControl::setQuantity($productId, $catalogQuantity);
if ($catalogData["CAN_BUY_ZERO"] != "Y" && $catalogData["QUANTITY_TRACE"] == "Y")
{
$needQuantity = ($productQuantity - $productReservedQuantity);
$resultList[$productId] = $catalogQuantity >= $needQuantity ? $productQuantity : $catalogQuantity;
}
}
}
if (!empty($resultList))
{
$result->setData(
array(
'AVAILABLE_QUANTITY_LIST' => $resultList
)
);
}
return $result;
}
/**
* @param array $products
*
* @return Sale\Result
*/
public function getAvailableQuantityAndPrice(array $products)
{
$result = new Sale\Result();
$availableQuantityListResult = $this->getAvailableQuantity($products);
if ($this->isExistsCatalogData($products))
{
$items = $products;
}
else
{
$items = $this->createProductsListWithCatalogData($products);
}
$priceDataList = array();
foreach ($items as $productId => $productData)
{
$catalogData = $productData['CATALOG'];
if (!empty($catalogData['PRICE_LIST']))
{
$priceDataList[$productId] = $catalogData['PRICE_LIST'];
}
}
$availableQuantityData = array();
if ($availableQuantityListResult->isSuccess())
{
$availableQuantityList = $availableQuantityListResult->getData();
if (isset($availableQuantityList['AVAILABLE_QUANTITY_LIST']))
{
$availableQuantityData = $availableQuantityList['AVAILABLE_QUANTITY_LIST'];
}
}
$result->setData(
array(
'PRODUCT_DATA_LIST' => array(
'PRICE_LIST' => $priceDataList,
'AVAILABLE_QUANTITY_LIST' => $availableQuantityData
)
)
);
return $result;
}
/**
* @param $products
*
* @return bool
*/
private function isExistsCatalogData($products)
{
foreach ($products as $productId => $productData)
{
if (empty($productData['CATALOG']))
{
return false;
}
}
return true;
}
/**
* @param array $products
* @param array $list
*
* @return array
*/
private static function removeNotExistsItemFromProducts(array $products, array $list)
{
$checkList = array_fill_keys($list, true);
foreach ($products as $productId => $productData)
{
if (!isset($checkList[$productId]))
{
unset($products[$productId]);
}
}
return $products;
}
/**
* @param array $list
*
* @return array
*/
private function getIblockData(array $list)
{
$resultList = array();
$res = Catalog\CatalogIblockTable::getList(
array(
'select' => array('IBLOCK_ID', 'SUBSCRIPTION', 'PRODUCT_IBLOCK_ID'),
'filter' => array('=IBLOCK_ID' => $list)
)
);
while($iblockData = $res->fetch())
{
$resultList[$iblockData['IBLOCK_ID']] = $iblockData;
if ($this->enableCache)
{
static::setHitCache(self::CACHE_CATALOG_IBLOCK_LIST, $iblockData['IBLOCK_ID'], $iblockData);
}
}
return $resultList;
}
/**
* @param array $iblockList
* @param array $list
*
* @return array
*/
private static function removeNotExistsIblockFromList(array $iblockList, array $list)
{
$checkList = array();
foreach ($list as $iblockId)
{
$checkList[$iblockId] = true;
}
foreach ($iblockList as $iblockId => $iblockProductIdList)
{
if (!isset($checkList[$iblockId]))
{
unset($iblockList[$iblockId]);
}
}
return $iblockList;
}
/**
* @param array $iblockProductMap
*
* @return array
*/
private function checkSkuPermission(array $iblockProductMap)
{
$resultList = array();
foreach ($iblockProductMap as $iblockId => $iblockData)
{
if ($iblockData['PRODUCT_IBLOCK_ID'] > 0 && !empty($iblockData['PRODUCT_LIST']))
{
$resultList = array_merge(
$resultList,
static::checkParentActivity($iblockData['PRODUCT_LIST'], $iblockData['PRODUCT_IBLOCK_ID'])
);
}
else
{
foreach ($iblockData['PRODUCT_LIST'] as $productId)
{
$resultList[] = $productId;
}
}
}
return $resultList;
}
/**
* @param array $iblockList
* @param array $iblockDataList
*
* @return array
*/
private static function createIblockProductMap(array $iblockList, array $iblockDataList)
{
$resultList = $iblockDataList;
foreach ($iblockList as $iblockId => $iblockProductList)
{
if (isset($iblockDataList[$iblockId]))
{
$resultList[$iblockId]['PRODUCT_LIST'] = $iblockProductList;
}
}
return $resultList;
}
/**
* @param array $products
* @param array $iblockProductMap
*
* @return array
*/
private static function changeSubscribeProductQuantity(array $products, array $iblockProductMap)
{
$resultList = $products;
foreach ($iblockProductMap as $iblockId => $iblockData)
{
if ($iblockData['SUBSCRIPTION'] != 'Y')
continue;
if (empty($iblockData['PRODUCT_LIST']))
continue;
foreach($iblockData['PRODUCT_LIST'] as $productData)
{
$productId = $productData['PRODUCT_ID'];
if (isset($resultList[$productId]))
{
$resultList[$productId]['QUANTITY'] = 1;
}
}
}
return $resultList;
}
/**
* @param array $list
* @param array $select
*
* @return array
*/
private static function getCatalogProducts(array $list, array $select)
{
if (empty($select))
$select = array('*');
elseif (!in_array('ID', $select))
$select[] = 'ID';
Main\Type\Collection::normalizeArrayValuesByInt($list, true);
if (empty($list))
return [];
$resultList = [];
$iterator = Catalog\ProductTable::getList([
'select' => $select,
'filter' => ['@ID' => $list]
]);
while ($row = $iterator->fetch())
{
$resultList[$row['ID']] = $row;
}
unset($row, $iterator);
return $resultList;
}
/**
* @param null $id
*
* @return array
*/
private static function getMeasure($id = null)
{
static $measureList = array();
if (!empty($measureList[$id]))
{
return $measureList[$id];
}
$fields = array(
'MEASURE' => $id,
'MEASURE_NAME' => $id,
'MEASURE_CODE' => 0,
);
if (intval($id) <= 0)
{
$measure = \CCatalogMeasure::getDefaultMeasure(true, true);
$fields['MEASURE_NAME'] = $measure['~SYMBOL_RUS'];
$fields['MEASURE_CODE'] = $measure['CODE'];
}
else
{
$resMeasures = \CCatalogMeasure::getList(
array(),
array('ID' => $id),
false,
false,
array('ID', 'SYMBOL_RUS', 'CODE')
);
$measure = $resMeasures->fetch();
if (!empty($measure))
{
$fields['MEASURE_NAME'] = $measure['SYMBOL_RUS'];
$fields['MEASURE_CODE'] = $measure['CODE'];
}
}
$measureList[$id] = $fields;
return $fields;
}
/**
* @param array $products
* @param array $productPriceList
* @param array $discountList
*
* @return array
*/
private function createProductPriceList(array $products, array $productPriceList, array $discountList = array())
{
$content = $this->getContext();
$priceResultList = array();
foreach ($productPriceList as $basketCode => $priceData)
{
if (!$priceData)
continue;
$priceResultList[$basketCode]['PRODUCT_PRICE_ID'] = $priceData['PRICE']['ID'];
$priceResultList[$basketCode]['NOTES'] = $priceData['PRICE']['CATALOG_GROUP_NAME'];
$priceResultList[$basketCode]['VAT_RATE'] = $priceData['PRICE']['VAT_RATE'];
$priceResultList[$basketCode]['DISCOUNT_NAME'] = null;
$priceResultList[$basketCode]['DISCOUNT_COUPON'] = null;
$priceResultList[$basketCode]['DISCOUNT_VALUE'] = null;
$priceResultList[$basketCode]['DISCOUNT_LIST'] = array();
$discount = array();
if (!empty($discountList[$priceData['PRODUCT_ID']][$basketCode]))
{
$discount = $discountList[$priceData['PRODUCT_ID']][$basketCode];
}
$priceResultList[$basketCode]['PRICE_TYPE_ID'] = $priceData['RESULT_PRICE']['PRICE_TYPE_ID'];
$priceResultList[$basketCode]['BASE_PRICE'] = $priceData['RESULT_PRICE']['BASE_PRICE'];
$priceResultList[$basketCode]['PRICE'] = $priceData['RESULT_PRICE']['DISCOUNT_PRICE'];
$priceResultList[$basketCode]['CURRENCY'] = $priceData['RESULT_PRICE']['CURRENCY'];
$priceResultList[$basketCode]['DISCOUNT_PRICE'] = $priceData['RESULT_PRICE']['DISCOUNT'];
if (isset($priceData['RESULT_PRICE']['PERCENT']))
{
$priceResultList[$basketCode]['DISCOUNT_VALUE'] = ($priceData['RESULT_PRICE']['PERCENT'] > 0
? $priceData['RESULT_PRICE']['PERCENT'] . '%' : null);
}
if (!empty($discount))
{
$priceResultList[$basketCode]['DISCOUNT_LIST'] = $discount;
}
if (!empty($priceData['DISCOUNT']))
{
$priceResultList[$basketCode]['DISCOUNT_NAME'] = '[' .
$priceData['DISCOUNT']['ID'] .
'] ' .
$priceData['DISCOUNT']['NAME'];
if (!empty($priceData['DISCOUNT']['COUPON']))
{
$priceResultList[$basketCode]['DISCOUNT_COUPON'] = $priceData['DISCOUNT']['COUPON'];
}
if (empty($priceResultList[$basketCode]['DISCOUNT_LIST']))
{
$priceResultList[$basketCode]['DISCOUNT_LIST'] = array($priceData['DISCOUNT']);
}
}
}
$resultList = array();
if (!empty($priceResultList))
{
foreach ($products as $productId => $productData)
{
if (!empty($products[$productId]))
{
$productData = $products[$productId];
$quantityList = array();
if (array_key_exists('QUANTITY', $productData))
{
$quantityList = array(
$productData['BASKET_CODE'] => $productData['QUANTITY']
);
}
if (!empty($productData['QUANTITY_LIST']))
{
$quantityList = $productData['QUANTITY_LIST'];
}
foreach($quantityList as $basketCode => $quantity)
{
$resultList[$basketCode] = $priceResultList[$basketCode];
}
}
}
}
return $resultList;
}
private static function setDataToProducts(array $products, array $resultData)
{
$resultList = array();
foreach ($products as $productId => $productData)
{
$resultList[$productId] = $resultData[$productId];
}
return $resultList;
}
/**
* @param array $products
* @param array $items
* @param array $priceList
* @param array $productQuantityList
*
* @return array
*/
private static function createProductResult(array $products, array $items, array $priceList, array $productQuantityList)
{
$resultList = array();
foreach ($products as $productId => $productData)
{
$itemCode = $productData['ITEM_CODE'];
$basketCode = $productData['BASKET_CODE'];
$resultList[$productId] = $items[$productId];
if (isset($productData['PRODUCT_DATA']['ACTIVE']))
{
$resultList[$productId]['ACTIVE'] = $productData['PRODUCT_DATA']['ACTIVE'];
}
$resultList[$productId]['ITEM_CODE'] = $itemCode;
QuantityControl::resetAllQuantity($productId);
QuantityControl::setReservedQuantity($productId, $productQuantityList[$basketCode]['QUANTITY_RESERVED']);
if (!isset($priceList[$basketCode]))
{
$priceList[$basketCode] = array();
}
if (!empty($productData['QUANTITY_LIST']))
{
foreach($productData['QUANTITY_LIST'] as $basketCode => $quantity)
{
QuantityControl::addQuantity($productId, $productQuantityList[$basketCode]['QUANTITY']);
QuantityControl::addAvailableQuantity($productId, $productQuantityList[$basketCode]['AVAILABLE_QUANTITY']);
if (empty($priceList[$basketCode]))
{
continue;
}
$resultList[$productId]['PRICE_LIST'][$basketCode] = array_merge(
array(
'QUANTITY' => $productQuantityList[$basketCode]['QUANTITY'],
'AVAILABLE_QUANTITY' => $productQuantityList[$basketCode]['AVAILABLE_QUANTITY'],
"ITEM_CODE" => $itemCode,
"BASKET_CODE" => $basketCode,
),
$priceList[$basketCode]
);
}
}
else
{
$resultList[$productId]['QUANTITY'] = $productQuantityList[$basketCode]['QUANTITY'];
QuantityControl::addQuantity($productId, $productQuantityList[$basketCode]['QUANTITY']);
QuantityControl::addAvailableQuantity($productId, $productQuantityList[$basketCode]['AVAILABLE_QUANTITY']);
if (!empty($resultList[$productId]))
{
if (empty($priceList[$basketCode]))
{
continue;
}
$resultList[$productId] = $priceList[$basketCode] + $resultList[$productId];
}
}
}
return $resultList;
}
/**
* @param array $products
* @param array $catalogDataList
* @param array $options
*
* @return array
*/
private static function setCatalogDataToProducts(array $products, array $catalogDataList, array $options = array())
{
$resultData = array();
foreach ($products as $productId => $productData)
{
if (!isset($catalogDataList[$productId]))
continue;
$catalogData = $catalogDataList[$productId];
$resultData[$productId] = array(
"CAN_BUY" => "Y",
"CAN_BUY_ZERO" => $catalogData["CAN_BUY_ZERO"],
"QUANTITY_TRACE" => $catalogData["QUANTITY_TRACE"],
'QUANTITY_RESERVED' => floatval($catalogData["QUANTITY_RESERVED"]),
);
if (is_array($options) && !in_array('CATALOG_DATA', $options))
{
$resultData[$productId] = array_merge(
$resultData[$productId],
array(
"NAME" => $productData['PRODUCT_DATA']["~NAME"],
"DETAIL_PAGE_URL" => $productData['PRODUCT_DATA']['~DETAIL_PAGE_URL'],
"MEASURE_ID" => $catalogData["MEASURE"],
"MEASURE_NAME" => $catalogData["MEASURE_NAME"],
"MEASURE_CODE" => $catalogData["MEASURE_CODE"],
"BARCODE_MULTI" => $catalogData["BARCODE_MULTI"],
"WEIGHT" => (float)$catalogData['WEIGHT'],
"DIMENSIONS" => serialize(
array(
"WIDTH" => $catalogData["WIDTH"],
"HEIGHT" => $catalogData["HEIGHT"],
"LENGTH" => $catalogData["LENGTH"]
)
),
"TYPE" => ($catalogData["TYPE"] == \CCatalogProduct::TYPE_SET)
? \CCatalogProductSet::TYPE_SET : null,
)
);
}
$resultData[$productId]["VAT_INCLUDED"] = "Y";
}
return $resultData;
}
/**
* @return bool
*/
protected static function isReservationEnabled()
{
return !(Main\Config\Option::get("catalog", "enable_reservation") == "N"
&& Main\Config\Option::get("sale", "product_reserve_condition") != "S"
&& !Catalog\Config\State::isUsedInventoryManagement());
}
/**
* @param array $products
*
* @return array
* @throws Main\ObjectNotFoundException
*/
public static function createOrderListFromProducts(array $products)
{
$productOrderList = array();
foreach ($products as $productId => $productData)
{
if (!empty($productData['SHIPMENT_ITEM_LIST']))
{
/**
* @var $shipmentItemIndex
* @var Sale\ShipmentItem $shipmentItem
*/
foreach ($productData['SHIPMENT_ITEM_LIST'] as $shipmentItemIndex => $shipmentItem)
{
/** @var Sale\ShipmentItemCollection $shipmentItemCollection */
$shipmentItemCollection = $shipmentItem->getCollection();
if (!$shipmentItemCollection)
{
throw new Main\ObjectNotFoundException('Entity "ShipmentItemCollection" not found');
}
$shipment = $shipmentItemCollection->getShipment();
if (!$shipment)
{
throw new Main\ObjectNotFoundException('Entity "Shipment" not found');
}
/** @var Sale\ShipmentCollection $shipmentCollection */
$shipmentCollection = $shipment->getCollection();
if (!$shipmentCollection)
{
throw new Main\ObjectNotFoundException('Entity "ShipmentCollection" not found');
}
$order = $shipmentCollection->getOrder();
if (!$order)
{
throw new Main\ObjectNotFoundException('Entity "Order" not found');
}
if (empty($productOrderList[$productId][$order->getId()]))
{
$productOrderList[$productId][$order->getId()] = $order;
}
}
}
}
return $productOrderList;
}
/**
* @param $productId
*
* @return array
*/
private static function getProductCatalogInfo($productId)
{
$productId = (int)$productId;
if ($productId <= 0)
return array();
if (!$product = static::getHitCache('IBLOCK_ELEMENT', $productId))
{
$productRes = \CIBlockElement::GetList(array(), array("ID" => $productId), false, false, array('ID', 'IBLOCK_ID', 'NAME', 'IBLOCK_SECTION_ID'));
$product = $productRes->fetch();
if ($product)
{
static::setHitCache('IBLOCK_ELEMENT', $productId, $product);
}
}
return array(
"#PRODUCT_ID#" => $product["ID"],
"#PRODUCT_NAME#" => $product["NAME"],
);
}
}
}