39 $soldProductsDbResult = self::getProductsSoldAmountFromShipmentsList($filter);
41 while ($soldProduct = $soldProductsDbResult->fetch())
43 $storeId = (int)$soldProduct[
'STORE_ID'];
44 if (!isset($result[$storeId]))
46 $result[$storeId] = [];
49 $measureId = (int)$soldProduct[
'MEASURE_ID'] ?: \CCatalogMeasure::getDefaultMeasure(
true)[
'ID'];
50 if (!isset($result[$storeId][$measureId]))
52 $result[$storeId][$measureId] = 0.0;
55 $result[$storeId][$measureId] += (float)$soldProduct[
'QUANTITY_SUM'];
63 $shipmentsDbResult = self::getProductsSoldAmountFromShipmentsList($filter);
66 while ($row = $shipmentsDbResult->fetch())
68 $result[$row[
'PRODUCT_ID']] ??= 0;
69 $result[$row[
'PRODUCT_ID']] += (float)$row[
'QUANTITY_SUM'];
76 $filter[
'STORES'] = $storeId;
83 $soldProductsDbResult = self::getProductsSoldPricesFromShipmentsList($filter);
85 while ($soldProduct = $soldProductsDbResult->fetch())
87 $storeId = (int)$soldProduct[
'STORE_ID'];
88 $result[$storeId] ??= [];
89 $currencyId = $soldProduct[
'CURRENCY'];
90 $result[$storeId][$currencyId] ??= [];
91 $result[$storeId][$currencyId][
'COST_PRICE'] ??= 0.0;
92 $result[$storeId][$currencyId][
'COST_PRICE'] += (float)$soldProduct[
'COST_PRICE_SUM'];
93 $result[$storeId][$currencyId][
'TOTAL_SOLD'] ??= 0.0;
94 $result[$storeId][$currencyId][
'TOTAL_SOLD'] += (float)$soldProduct[
'TOTAL_SOLD'];
102 $shipmentsDbResult = self::getProductsSoldPricesFromShipmentsList($filter);
105 while ($row = $shipmentsDbResult->fetch())
107 $currencyId = $row[
'CURRENCY'];
108 $result[$row[
'PRODUCT_ID']][$currencyId] ??= [];
109 $result[$row[
'PRODUCT_ID']][$currencyId][
'COST_PRICE'] ??= 0.0;
110 $result[$row[
'PRODUCT_ID']][$currencyId][
'COST_PRICE'] += (float)$row[
'COST_PRICE_SUM'];
111 $result[$row[
'PRODUCT_ID']][$currencyId][
'TOTAL_SOLD'] ??= 0.0;
112 $result[$row[
'PRODUCT_ID']][$currencyId][
'TOTAL_SOLD'] += (float)$row[
'TOTAL_SOLD'];
120 $filter[
'=STORES'] = $storeId;
129 $getListParameters[
'select'][
'CURRENCY'] =
'BASKET.CURRENCY';
130 $getListParameters[
'select'][
'BASKET_PRICE'] =
'BASKET.PRICE';
131 $getListParameters[
'select'][
'DATE_DEDUCTED'] =
'DELIVERY.DATE_DEDUCTED';
133 $getListParameters[
'runtime'][] =
new Reference(
134 'S_PRODUCT_BATCH_SHIPMENT',
135 StoreBatchDocumentElementTable::class,
136 Join::on(
'this.S_BARCODE.ID',
'ref.SHIPMENT_ITEM_STORE_ID')
139 $getListParameters[
'select'][
'COST_PRICE'] =
'S_PRODUCT_BATCH_SHIPMENT.BATCH_PRICE';
140 $getListParameters[
'select'][
'BASKET_QUANTITY'] =
'S_PRODUCT_BATCH_SHIPMENT.AMOUNT';
142 return ShipmentItemTable::getList($getListParameters)->fetchAll();
149 private static function getProductsSoldAmountFromShipmentsList(array $filter = []): \
Bitrix\Main\ORM\
Query\
Result
153 $getListParameters[
'select'][
'MEASURE_ID'] =
'BASKET.PRODUCT.MEASURE';
154 $getListParameters[
'select'][] =
'QUANTITY_SUM';
155 $getListParameters[
'group'] = [
'BASKET.PRODUCT_ID',
'S_BARCODE.STORE_ID'];
162 return ShipmentItemTable::getList($getListParameters);
169 private static function getProductsSoldPricesFromShipmentsList(array $filter = []): \
Bitrix\Main\ORM\
Query\
Result
174 $storeBatchQuery->registerRuntimeField(
178 [
'AMOUNT',
'BATCH_PRICE']
181 $storeBatchQuery->registerRuntimeField(
188 $storeBatchQuery->setSelect([
189 'SHIPMENT_ITEM_STORE_ID',
194 $storeBatchQuery->setGroup([
'SHIPMENT_ITEM_STORE_ID',
'BATCH_CURRENCY']);
197 $getListParameters[
'runtime'][] =
new Reference(
199 Base::getInstanceByQuery($storeBatchQuery),
200 Join::on(
'this.S_BARCODE.ID',
'ref.SHIPMENT_ITEM_STORE_ID')
203 $getListParameters[
'select'][
'COST_PRICE_SUM'] =
'SUBQUERY.COST_PRICE_SUM';
204 $getListParameters[
'select'][
'CURRENCY'] =
'SUBQUERY.BATCH_CURRENCY';
208 [
'BASKET.PRICE',
'SUBQUERY.SUM_AMOUNT']
211 $getListParameters[
'select'][] =
'TOTAL_SOLD';
212 $getListParameters[
'group'] = [
'BASKET.PRODUCT_ID',
'S_BARCODE.STORE_ID',
'CURRENCY'];
214 return ShipmentItemTable::getList($getListParameters);
219 $filter = self::prepareFilter($filter);
222 $productIds = array_column($reservedData,
'PRODUCT_ID');
227 ?? array_column($reservedData,
'STORE_ID')
234 $storesData[
'STORE_IDS'] = $storeIds;
238 $storesPositionData = array_fill_keys(
241 'reservedData' => [],
245 foreach ($reservedData as $reservedPosition)
247 $storesPositionData[$reservedPosition[
'STORE_ID']][
'reservedData'][] = $reservedPosition;
250 foreach ($storesPositionData as $storeId => $fieldData)
262 $intervalStartDate =
new DateTime();
263 $intervalStartDate->add(self::DEFAULT_DATE_INTERVAL);
266 'FROM' => $intervalStartDate->toString(),
267 'TO' => $currentDate->toString(),
271 private static function getProductPrice(
int $productId): float
273 if (!isset(self::$productPrice[$productId]))
276 self::$productPrice[$productId] ??= 0;
279 return self::$productPrice[$productId];
282 private static function prepareFilter(array $filter): array
284 if (isset($filter[
'REPORT_INTERVAL_from']) && isset($filter[
'REPORT_INTERVAL_to']))
286 $filter[
'REPORT_INTERVAL'] = [
287 'FROM' => $filter[
'REPORT_INTERVAL_from'],
288 'TO' => $filter[
'REPORT_INTERVAL_to'],
292 $accessController = AccessController::getCurrent();
293 if (!$accessController->checkCompleteRight(ActionDictionary::ACTION_STORE_VIEW))
295 $availableStores = $accessController->getPermissionValue(ActionDictionary::ACTION_STORE_VIEW) ?? [];
297 if (isset($filter[
'STORES']) && is_array($filter[
'STORES']))
299 $filter[
'STORES'] = array_values(array_intersect($availableStores, $filter[
'STORES']));
303 $filter[
'STORES'] = $availableStores;
309 !isset($filter[
'REPORT_INTERVAL'])
310 || !isset($filter[
'REPORT_INTERVAL'][
'FROM'])
311 || !isset($filter[
'REPORT_INTERVAL'][
'TO'])
317 $filter[
'INNER_MOVEMENT'] = (bool)($filter[
'INNER_MOVEMENT'] ??
true);
334 $getListParameters[
'select'][
'QUANTITY'] =
'QUANTITY';
341 ProductInfo::initBasePrice(...array_column($storesData,
'PRODUCT_ID'));
342 StoreInfo::loadStoreName(...array_column($storesData,
'STORE_ID'));
346 if (isset($filter[
'STORES']))
348 $storesInfo = array_fill_keys($filter[
'STORES'], []);
350 foreach ($storesData as $shipmentItem)
352 $storeId = $shipmentItem[
'STORE_ID'];
353 $productId = $shipmentItem[
'PRODUCT_ID'];
354 if (!isset($storesInfo[$storeId]))
356 $storesInfo[$storeId] = [];
359 if (!isset($storesInfo[$storeId][$productId]))
361 $storesInfo[$storeId][$productId] = (float)$shipmentItem[
'QUANTITY'];
365 $storesInfo[$storeId][$productId] += (float)$shipmentItem[
'QUANTITY'];
370 foreach ($storesInfo as $storeId => $storeInfo)
373 foreach ($storeInfo as $productId => $quantity)
375 $store->addProduct(
new ProductInfo($productId, $quantity));
385 $filter = self::prepareFilter($filter);
389 'STORE_ID' =>
'S_BARCODE.STORE_ID',
390 'PRODUCT_ID' =>
'BASKET.PRODUCT_ID',
393 'filter' => self::formShipmentDataFilter($filter),
398 ShipmentItemStoreTable::class,
399 Join::on(
'this.ID',
'ref.ORDER_DELIVERY_BASKET_ID')
400 ))->configureJoinType(Join::TYPE_LEFT),
405 private static function formShipmentDataFilter(array $filter): array
408 '=DELIVERY.DEDUCTED' =>
'Y',
409 '>S_BARCODE.STORE_ID' => 0,
412 if (isset($filter[
'STORES']))
414 $formedFilter[
'=S_BARCODE.STORE_ID'] = $filter[
'STORES'];
417 if (isset($filter[
'=STORES']))
419 $formedFilter[
'=S_BARCODE.STORE_ID'] = $filter[
'=STORES'];
422 if (isset($filter[
'PRODUCTS']))
424 $formedFilter[
'=BASKET.PRODUCT_ID'] = $filter[
'PRODUCTS'];
427 if (isset($filter[
'REPORT_INTERVAL']))
429 $formedFilter[
'>=DELIVERY.DATE_DEDUCTED'] =
new DateTime($filter[
'REPORT_INTERVAL'][
'FROM']);
430 $formedFilter[
'<=DELIVERY.DATE_DEDUCTED'] =
new DateTime($filter[
'REPORT_INTERVAL'][
'TO']);
433 return $formedFilter;
456 public static function computeSoldPercent(
float $shippedSum,
float $arrivedSum,
int $precision = 2): float
459 if ($shippedSum === 0.0)
463 elseif ($arrivedSum === 0.0)
469 $soldPercent = ($shippedSum / $arrivedSum) * 100;
472 return round($soldPercent, $precision);
477 $filter = self::prepareFilter($filter);
481 'PRODUCT_ID' =>
'ELEMENTS.ELEMENT_ID',
482 'QUANTITY' =>
'ELEMENTS.AMOUNT',
483 'STORE_ID' =>
'ELEMENTS.STORE_TO',
486 'filter' => self::formArrivedDataFilter($filter),
490 private static function formArrivedDataFilter(array $filter): array
493 if ($filter[
'INNER_MOVEMENT'])
498 '=DOC_TYPE' => $docTypes,
500 '>ELEMENTS.ELEMENT_ID' => 0,
503 if (isset($filter[
'STORES']))
505 $formedFilter[
'=ELEMENTS.STORE_TO'] = $filter[
'STORES'];
508 if (isset($filter[
'PRODUCTS']))
510 $formedFilter[
'=ELEMENTS.ELEMENT_ID'] = $filter[
'PRODUCTS'];
513 if (isset($filter[
'REPORT_INTERVAL']))
515 $formedFilter[
'>=DATE_STATUS'] =
new DateTime($filter[
'REPORT_INTERVAL'][
'FROM']);
516 $formedFilter[
'<=DATE_STATUS'] =
new DateTime($filter[
'REPORT_INTERVAL'][
'TO']);
519 return $formedFilter;
528 'QUANTITY' =>
'AMOUNT',
530 'filter' => self::formReservedDataFilter($filter),
536 private static function formReservedDataFilter(array $filter): array
542 $filter = self::prepareFilter($filter);
543 if (isset($filter[
'STORES']))
545 $formedFilter[
'=STORE_ID'] = $filter[
'STORES'];
549 $formedFilter[
'!=QUANTITY'] = 0;
552 if (isset($filter[
'PRODUCTS']))
554 $formedFilter[
'=PRODUCT_ID'] = $filter[
'PRODUCTS'];
557 return $formedFilter;
560 private static function combineUniqueColumnElements(array $arraysList,
string $columnKey): array
562 $combineColumnElements = [];
563 foreach ($arraysList as $item)
565 $columnElements = array_column($item, $columnKey);
566 array_push($combineColumnElements, ...$columnElements);
569 return array_unique($combineColumnElements);
572 protected static function formField(array $storeReservedData,
int $storeId =
null): array
575 foreach ($storeReservedData as $storePosition)
581 'SUM_STORED' => $storedSum,
584 if ($storeId !==
null)
586 $result[
'STORE_ID'] = $storeId;
594 return self::getProductPrice($productId) * $productCount;
604 'PURCHASING_CURRENCY',
605 'PURCHASING_CURRENCY_AMOUNT' =>
'CURRENCY_TABLE.CURRENT_BASE_RATE',
608 '=ID' => $productIds,
613 CurrencyTable::class,
614 Join::on(
'this.PURCHASING_CURRENCY',
'ref.CURRENCY')
615 ))->configureJoinType(Join::TYPE_LEFT),
619 foreach ($productsData as $product)
621 self::$productPrice[$product[
'ID']] = (float)$product[
'PURCHASING_PRICE'];
624 $defaultCurrencyAmount = (float)\CCurrency::getCurrency(
$defaultCurrency)[
'CURRENT_BASE_RATE'];
625 $currentCurrencyAmount = (float)$product[
'PURCHASING_CURRENCY_AMOUNT'];
627 self::$productPrice[$product[
'ID']] *= $currentCurrencyAmount;
628 self::$productPrice[$product[
'ID']] /= $defaultCurrencyAmount;
static getList(array $parameters=array())