3namespace Bitrix\Catalog\Integration\Report\StoreStock;
5\Bitrix\Main\Loader::includeModule(
'sale');
7use Bitrix\Catalog\Access\AccessController;
8use Bitrix\Catalog\Access\ActionDictionary;
9use Bitrix\Catalog\Integration\Report\StoreStock\Entity\ProductInfo;
10use Bitrix\Catalog\Integration\Report\StoreStock\Entity\Store\StoreInfo;
11use Bitrix\Catalog\Integration\Report\StoreStock\Entity\Store\StoreWithProductsInfo;
12use Bitrix\Catalog\StoreBatchDocumentElementTable;
13use Bitrix\Catalog\StoreDocumentTable;
14use Bitrix\Main\ORM\Fields\ExpressionField;
15use Bitrix\Sale\Internals\ShipmentItemStoreTable;
16use Bitrix\Sale\Internals\ShipmentItemTable;
17use Bitrix\Catalog\StoreProductTable;
18use Bitrix\Catalog\ProductTable;
19use Bitrix\Currency\CurrencyManager;
20use Bitrix\Currency\CurrencyTable;
21use Bitrix\Main\Type\DateTime;
22use Bitrix\Main\ORM\Fields\Relations\Reference;
23use Bitrix\Main\ORM\Query\Join;
36 $soldProductsDbResult = self::getProductsSoldAmountFromShipmentsList(
$filter);
38 while ($soldProduct = $soldProductsDbResult->fetch())
40 $storeId = (int)$soldProduct[
'STORE_ID'];
46 $measureId = (int)$soldProduct[
'MEASURE_ID'] ?: \CCatalogMeasure::getDefaultMeasure(
true)[
'ID'];
47 if (!isset(
$result[$storeId][$measureId]))
49 $result[$storeId][$measureId] = 0.0;
52 $result[$storeId][$measureId] += (float)$soldProduct[
'QUANTITY_SUM'];
60 $shipmentsDbResult = self::getProductsSoldAmountFromShipmentsList(
$filter);
63 while ($row = $shipmentsDbResult->fetch())
65 $result[$row[
'PRODUCT_ID']] ??= 0;
66 $result[$row[
'PRODUCT_ID']] += (float)$row[
'QUANTITY_SUM'];
83 foreach ($soldProductsDbResult as $item)
85 $storeId = (int)$item[
'STORE_ID'];
87 $batchCurrencyId = $item[
'BATCH_CURRENCY'];
89 $result[$storeId][$batchCurrencyId] ??= [];
90 $result[$storeId][$batchCurrencyId][
'COST_PRICE'] ??= 0.0;
91 $result[$storeId][$batchCurrencyId][
'TOTAL_SOLD'] ??= 0.0;
92 $result[$storeId][$batchCurrencyId][
'COST_PRICE'] +=
93 (float)$item[
'COST_PRICE']
94 * (
float)$item[
'BASKET_QUANTITY']
98 $basketCurrencyId = $item[
'BASKET_CURRENCY'];
100 $result[$storeId][$basketCurrencyId] ??= [];
101 $result[$storeId][$basketCurrencyId][
'COST_PRICE'] ??= 0.0;
102 $result[$storeId][$basketCurrencyId][
'TOTAL_SOLD'] ??= 0.0;
103 $result[$storeId][$basketCurrencyId][
'TOTAL_SOLD'] +=
104 (float)$item[
'BASKET_PRICE']
105 * (
float)$item[
'BASKET_QUANTITY']
118 foreach ($shipmentsDbResult as $item)
120 $batchCurrencyId = $item[
'BATCH_CURRENCY'];
122 $result[$item[
'PRODUCT_ID']][$batchCurrencyId] ??= [];
123 $result[$item[
'PRODUCT_ID']][$batchCurrencyId][
'COST_PRICE'] ??= 0.0;
124 $result[$item[
'PRODUCT_ID']][$batchCurrencyId][
'TOTAL_SOLD'] ??= 0.0;
125 $result[$item[
'PRODUCT_ID']][$batchCurrencyId][
'COST_PRICE'] +=
126 (float)$item[
'COST_PRICE']
127 * (
float)$item[
'BASKET_QUANTITY']
131 $basketCurrencyId = $item[
'BASKET_CURRENCY'];
133 $result[$item[
'PRODUCT_ID']][$basketCurrencyId] ??= [];
134 $result[$item[
'PRODUCT_ID']][$basketCurrencyId][
'COST_PRICE'] ??= 0.0;
135 $result[$item[
'PRODUCT_ID']][$basketCurrencyId][
'TOTAL_SOLD'] ??= 0.0;
136 $result[$item[
'PRODUCT_ID']][$basketCurrencyId][
'TOTAL_SOLD'] +=
137 (float)$item[
'BASKET_PRICE']
138 * (
float)$item[
'BASKET_QUANTITY']
157 $getListParameters[
'select'][
'BASKET_CURRENCY'] =
'BASKET.CURRENCY';
158 $getListParameters[
'select'][
'BASKET_PRICE'] =
'BASKET.PRICE';
159 $getListParameters[
'select'][
'DATE_DEDUCTED'] =
'DELIVERY.DATE_DEDUCTED';
161 $getListParameters[
'runtime'][] =
new Reference(
162 'S_PRODUCT_BATCH_SHIPMENT',
163 StoreBatchDocumentElementTable::class,
164 Join::on(
'this.S_BARCODE.ID',
'ref.SHIPMENT_ITEM_STORE_ID')
167 $getListParameters[
'select'][
'COST_PRICE'] =
'S_PRODUCT_BATCH_SHIPMENT.BATCH_PRICE';
168 $getListParameters[
'select'][
'BASKET_QUANTITY'] =
'S_PRODUCT_BATCH_SHIPMENT.AMOUNT';
169 $getListParameters[
'select'][
'BATCH_CURRENCY'] =
'S_PRODUCT_BATCH_SHIPMENT.BATCH_CURRENCY';
171 return ShipmentItemTable::getList($getListParameters)->fetchAll();
182 $getListParameters[
'select'][
'MEASURE_ID'] =
'BASKET.PRODUCT.MEASURE';
183 $getListParameters[
'select'][] =
'QUANTITY_SUM';
184 $getListParameters[
'group'] = [
'BASKET.PRODUCT_ID',
'S_BARCODE.STORE_ID'];
191 return ShipmentItemTable::getList($getListParameters);
199 $productIds = array_column($reservedData,
'PRODUCT_ID');
204 ?? array_column($reservedData,
'STORE_ID')
211 $storesData[
'STORE_IDS'] = $storeIds;
215 $storesPositionData = array_fill_keys(
218 'reservedData' => [],
222 foreach ($reservedData as $reservedPosition)
224 $storesPositionData[$reservedPosition[
'STORE_ID']][
'reservedData'][] = $reservedPosition;
227 foreach ($storesPositionData as $storeId => $fieldData)
239 $intervalStartDate =
new DateTime();
240 $intervalStartDate->add(self::DEFAULT_DATE_INTERVAL);
243 'FROM' => $intervalStartDate->toString(),
244 'TO' => $currentDate->toString(),
248 private static function getProductPrice(
int $productId): float
250 if (!isset(self::$productPrice[$productId]))
253 self::$productPrice[$productId] ??= 0;
256 return self::$productPrice[$productId];
261 if (isset(
$filter[
'REPORT_INTERVAL_from']) && isset(
$filter[
'REPORT_INTERVAL_to']))
264 'FROM' =>
$filter[
'REPORT_INTERVAL_from'],
265 'TO' =>
$filter[
'REPORT_INTERVAL_to'],
272 $availableStores =
$accessController->getPermissionValue(ActionDictionary::ACTION_STORE_VIEW) ?? [];
276 $filter[
'STORES'] = array_values(array_intersect($availableStores,
$filter[
'STORES']));
280 $filter[
'STORES'] = $availableStores;
286 !isset(
$filter[
'REPORT_INTERVAL'])
287 || !isset(
$filter[
'REPORT_INTERVAL'][
'FROM'])
288 || !isset(
$filter[
'REPORT_INTERVAL'][
'TO'])
294 $filter[
'INNER_MOVEMENT'] = (bool)(
$filter[
'INNER_MOVEMENT'] ??
true);
311 $getListParameters[
'select'][
'QUANTITY'] =
'QUANTITY';
318 ProductInfo::initBasePrice(...array_column($storesData,
'PRODUCT_ID'));
319 StoreInfo::loadStoreName(...array_column($storesData,
'STORE_ID'));
325 $storesInfo = array_fill_keys(
$filter[
'STORES'], []);
327 foreach ($storesData as $shipmentItem)
329 $storeId = $shipmentItem[
'STORE_ID'];
330 $productId = $shipmentItem[
'PRODUCT_ID'];
331 if (!isset($storesInfo[$storeId]))
333 $storesInfo[$storeId] = [];
336 if (!isset($storesInfo[$storeId][$productId]))
338 $storesInfo[$storeId][$productId] = (float)$shipmentItem[
'QUANTITY'];
342 $storesInfo[$storeId][$productId] += (float)$shipmentItem[
'QUANTITY'];
347 foreach ($storesInfo as $storeId => $storeInfo)
350 foreach ($storeInfo as $productId => $quantity)
352 $store->addProduct(
new ProductInfo($productId, $quantity));
366 'STORE_ID' =>
'S_BARCODE.STORE_ID',
367 'PRODUCT_ID' =>
'BASKET.PRODUCT_ID',
370 'filter' => self::formShipmentDataFilter(
$filter),
375 ShipmentItemStoreTable::class,
376 Join::on(
'this.ID',
'ref.ORDER_DELIVERY_BASKET_ID')
377 ))->configureJoinType(Join::TYPE_LEFT),
385 '=DELIVERY.DEDUCTED' =>
'Y',
386 '>S_BARCODE.STORE_ID' => 0,
391 $formedFilter[
'=S_BARCODE.STORE_ID'] =
$filter[
'STORES'];
396 $formedFilter[
'=S_BARCODE.STORE_ID'] =
$filter[
'=STORES'];
399 if (isset(
$filter[
'PRODUCTS']))
401 $formedFilter[
'=BASKET.PRODUCT_ID'] =
$filter[
'PRODUCTS'];
404 if (isset(
$filter[
'REPORT_INTERVAL']))
406 $formedFilter[
'>=DELIVERY.DATE_DEDUCTED'] =
new DateTime(
$filter[
'REPORT_INTERVAL'][
'FROM']);
407 $formedFilter[
'<=DELIVERY.DATE_DEDUCTED'] =
new DateTime(
$filter[
'REPORT_INTERVAL'][
'TO']);
410 return $formedFilter;
436 if ($shippedSum === 0.0)
440 elseif ($arrivedSum === 0.0)
446 $soldPercent = ($shippedSum / $arrivedSum) * 100;
458 'PRODUCT_ID' =>
'ELEMENTS.ELEMENT_ID',
459 'QUANTITY' =>
'ELEMENTS.AMOUNT',
460 'STORE_ID' =>
'ELEMENTS.STORE_TO',
463 'filter' => self::formArrivedDataFilter(
$filter),
475 '=DOC_TYPE' => $docTypes,
477 '>ELEMENTS.ELEMENT_ID' => 0,
482 $formedFilter[
'=ELEMENTS.STORE_TO'] =
$filter[
'STORES'];
485 if (isset(
$filter[
'PRODUCTS']))
487 $formedFilter[
'=ELEMENTS.ELEMENT_ID'] =
$filter[
'PRODUCTS'];
490 if (isset(
$filter[
'REPORT_INTERVAL']))
492 $formedFilter[
'>=DATE_STATUS'] =
new DateTime(
$filter[
'REPORT_INTERVAL'][
'FROM']);
493 $formedFilter[
'<=DATE_STATUS'] =
new DateTime(
$filter[
'REPORT_INTERVAL'][
'TO']);
496 return $formedFilter;
505 'QUANTITY' =>
'AMOUNT',
507 'filter' => self::formReservedDataFilter(
$filter),
522 $formedFilter[
'=STORE_ID'] =
$filter[
'STORES'];
526 $formedFilter[
'!=QUANTITY'] = 0;
529 if (isset(
$filter[
'PRODUCTS']))
531 $formedFilter[
'=PRODUCT_ID'] =
$filter[
'PRODUCTS'];
534 return $formedFilter;
537 private static function combineUniqueColumnElements(
array $arraysList,
string $columnKey):
array
539 $combineColumnElements = [];
540 foreach ($arraysList as $item)
542 $columnElements = array_column($item, $columnKey);
543 array_push($combineColumnElements, ...$columnElements);
546 return array_unique($combineColumnElements);
552 foreach ($storeReservedData as $storePosition)
558 'SUM_STORED' => $storedSum,
561 if ($storeId !==
null)
563 $result[
'STORE_ID'] = $storeId;
571 return self::getProductPrice($productId) * $productCount;
581 'PURCHASING_CURRENCY',
582 'PURCHASING_CURRENCY_AMOUNT' =>
'CURRENCY_TABLE.CURRENT_BASE_RATE',
585 '=ID' => $productIds,
590 CurrencyTable::class,
591 Join::on(
'this.PURCHASING_CURRENCY',
'ref.CURRENCY')
592 ))->configureJoinType(Join::TYPE_LEFT),
596 foreach ($productsData as $product)
598 self::$productPrice[$product[
'ID']] = (float)$product[
'PURCHASING_PRICE'];
601 $defaultCurrencyAmount = (float)\CCurrency::getCurrency(
$defaultCurrency)[
'CURRENT_BASE_RATE'];
602 $currentCurrencyAmount = (float)$product[
'PURCHASING_CURRENCY_AMOUNT'];
604 self::$productPrice[$product[
'ID']] *= $currentCurrencyAmount;
605 self::$productPrice[$product[
'ID']] /= $defaultCurrencyAmount;
static getShippedData(array $filter)
static getPositionPrice(int $productId, float $productCount)
static getProductsSoldAmountForProducts($filter=[])
static initProductPrice(array $productIds)
static getArrivedData(array $filter)
static getReservedData(array $filter)
static getDefaultReportInterval()
static computeSoldPercent(float $shippedSum, float $arrivedSum, int $precision=2)
const DEFAULT_DATE_INTERVAL
static getProductsSoldPricesForDeductedPeriod(array $filter=[])
static formField(array $storeReservedData, int $storeId=null)
static getProductsSoldPricesForProducts($filter=[])
static getStoreStockSaleData(bool $isOneField, array $filter)
static getProductsSoldPricesForProductsOnStore(int $storeId, $filter=[])
static getProductsSoldAmountForStores($filter=[])
static getProductsSoldAmountForProductsOnStore(int $storeId, $filter=[])
static formStoresListFromStoresData(array $filter, array $storesData)
static getShippedDataListParameters(array $filter)
static getProductsSoldPricesForStores(array $filter=[])
static getArrivedDataListParameters(array $filter)
const TYPE_STORE_ADJUSTMENT
static getList(array $parameters=array())
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)