From cbb9b7231271074eeb8cd6ef0aaa5908f7b4165d Mon Sep 17 00:00:00 2001 From: fomichev Date: Tue, 8 Apr 2025 10:14:13 +0300 Subject: [PATCH] =?utf8?q?=D0=A2=D0=BE=D0=B2=D0=B0=D1=80=D1=8B=20=D1=81=20?= =?utf8?q?=D0=B8=D1=81=D1=82=D0=BE=D1=80=D0=B8=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- erp24/controllers/CategoryPlanController.php | 9 ++ erp24/services/StorePlanService.php | 101 ++++++++++++++++++ .../views/category-plan/show-history-data.php | 43 +++++++- 3 files changed, 148 insertions(+), 5 deletions(-) diff --git a/erp24/controllers/CategoryPlanController.php b/erp24/controllers/CategoryPlanController.php index f3dac776..054cfb90 100644 --- a/erp24/controllers/CategoryPlanController.php +++ b/erp24/controllers/CategoryPlanController.php @@ -305,6 +305,7 @@ class CategoryPlanController extends Controller { $subcategoryList = []; $speciesList = []; $weightedResults = []; + $productSalesShare = []; $model = new DynamicModel(['storeId', 'month', 'category', 'subcategory', 'species']); $model->addRule(['storeId', 'month', 'category'], 'required'); @@ -355,6 +356,13 @@ class CategoryPlanController extends Controller { $result['without_history'] ); + + $productSalesShare = StorePlanService::calculateProductSalesShare( + $storeId, + $selectedMonth, + $result['with_history'] + ); + } } } @@ -362,6 +370,7 @@ class CategoryPlanController extends Controller { return $this->render('show-history-data', [ 'result' => $result, 'weighted' => $weightedResults, + 'productSalesShare' => $productSalesShare, 'model' => $model, 'storeList' => $storeList, 'monthsList' => $monthsList, diff --git a/erp24/services/StorePlanService.php b/erp24/services/StorePlanService.php index 58c56ce4..dd088a6d 100755 --- a/erp24/services/StorePlanService.php +++ b/erp24/services/StorePlanService.php @@ -6,6 +6,7 @@ use DateTime; use yii\db\Expression; use yii\helpers\ArrayHelper; use yii_app\records\Motivation; +use yii_app\records\PricesDynamic; use yii_app\records\Products1cAdditionalCharacteristics; use yii_app\records\Sales; use yii_app\records\SalesProducts; @@ -439,5 +440,105 @@ class StorePlanService return $weightedResults; } + /** + * Получает цену для товара для указанного месяца. + * + * @param string $productId GUID товара. + * @param string $year Год (например, "2025"). + * @param string $month Месяц в формате "mm" (например, "03"). + * @return float Цена, если найдена запись, иначе 0. + */ + public static function getPriceForProductAndMonth($productId, $year, $month) + { + // Для проверки возьмем первый день месяца + $dateToCheck = "$year-$month-01"; + $priceRecord = PricesDynamic::find() + ->where(['product_id' => $productId, 'active' => 1]) + ->andWhere(['<=', 'date_from', $dateToCheck]) + ->andWhere([ + 'or', + ['>=', 'date_to', $dateToCheck], + ['date_to' => null] + ]) + ->one(); + if ($priceRecord) { + return (float)$priceRecord->price; + } + return 0; + } + + /** + * Вычисляет для каждого товара с историей: + * - месячные продажи (сумма недельных продаж за месяц), + * - взвешенные продажи по месяцам (с учетом цены и веса), + * - итоговую взвешенную сумму, + * - долю товара от общей взвешенной суммы по всем товарам. + * + * @param int $storeId Идентификатор магазина. + * @param string $selectedMonth Целевой месяц в формате "mm". + * @param array $productsWithHistory Массив товаров с историей (из calculateHistoricalShare), каждый элемент содержит: + * [ + * 'guid' => , + * 'weekly_sales' => [ 'mm' => [week0, week1, week2, week3], ... ] + * ] + * @return array Массив, где ключ – GUID товара, а значение – массив с данными: + * [ + * 'monthlySales' => [ 'mm' => суммарные продажи за месяц, ... ], + * 'monthlyWeighted' => [ 'mm' => (продажи * цена * вес), ... ], + * 'weightedSum' => итоговая взвешенная сумма, + * 'share' => доля товара (от 0 до 1) + * ] + */ + public static function calculateProductSalesShare($storeId, $selectedMonth, $productsWithHistory) + { + $year = date('Y'); + + + $weightedMonths = []; + for ($i = 1; $i <= 3; $i++) { + $timestamp = strtotime("-{$i} month", strtotime("$year-$selectedMonth-01")); + $weightedMonths[] = [ + 'year' => date('Y', $timestamp), + 'month' => date('m', $timestamp), + 'weight' => 4 - $i, + ]; + } + + $productsData = []; + $globalTotal = 0; + + + foreach ($productsWithHistory as $product) { + $guid = $product['guid']; + $monthlySales = []; + $monthlyWeighted = []; + $weightedSum = 0; + + foreach ($weightedMonths as $mInfo) { + $mKey = $mInfo['month']; + $sales = isset($product['weekly_sales'][$mKey]) ? array_sum($product['weekly_sales'][$mKey]) : 0; + + $price = self::getPriceForProductAndMonth($guid, $mInfo['year'], $mInfo['month']); + $monthlySales[$mKey] = $sales; + $weightedValue = $sales * $price * $mInfo['weight']; + $monthlyWeighted[$mKey] = $weightedValue; + $weightedSum += $weightedValue; + } + $productsData[$guid] = [ + 'monthlySales' => $monthlySales, + 'monthlyWeighted' => $monthlyWeighted, + 'weightedSum' => $weightedSum, + ]; + $globalTotal += $weightedSum; + } + + foreach ($productsData as $guid => &$data) { + $data['share'] = ($globalTotal > 0) ? $data['weightedSum'] / $globalTotal : 0; + } + unset($data); + + return $productsData; + } + } diff --git a/erp24/views/category-plan/show-history-data.php b/erp24/views/category-plan/show-history-data.php index c408532b..bd79da79 100644 --- a/erp24/views/category-plan/show-history-data.php +++ b/erp24/views/category-plan/show-history-data.php @@ -105,8 +105,11 @@ JS; - + + + + @@ -115,8 +118,10 @@ JS; + + + @@ -149,9 +180,11 @@ JS;
GUID продуктаНаименование продукта / GUID Недельные продажиВзвешенная сумма продажДоля товара (%)Детали по месяцам
where(['id' => $product['guid']])->one(); + echo ($productModel !== null) ? Html::encode($productModel->name) : Html::encode($product['guid']); ?> - name) : Html::encode($product['guid']) ?> +
+
$weekData): ?> @@ -124,6 +129,32 @@ JS;
+ + + + + + $sales): ?> +
+ Месяц : + продажи = , + взвеш. = +
+ + +
where(['id' => $product['guid']])->one(); - echo ($productModel !== null) ? Html::encode($productModel->name) : Html::encode($product['guid']); - ?> + $productModel = Products1c::find()->where(['id' => $product['guid']])->one(); ?> + name) : Html::encode($product['guid']); ?>
+ + +
$weekData): ?> -- 2.39.5