]);
}
- public function action81()
+ public function actionMonthProductsSpeciesShare()
{
$request = Yii::$app->request;
'pagination' => ['pageSize' => 100],
]);
}
- return $this->render('81', [
+ return $this->render('month-products-species-share', [
+ 'dataProvider' => $dataProvider,
+ 'filters' => $filters,
+ ]);
+ }
+
+
+ public function actionMonthProductsSpeciesForecast()
+ {
+ $request = Yii::$app->request;
+
+ $filters = [
+ 'category' => $request->get('category'),
+ 'subcategory' => $request->get('subcategory') ?? null,
+ 'species' => $request->get('species') ?? null,
+ 'store_id' => $request->get('store_id') ?? [],
+ 'year' => $request->get('year'),
+ 'month' => $request->get('month'),
+ 'type' => $request->get('type'),
+ ];
+
+ $dataProvider = new ArrayDataProvider([
+ 'allModels' => [],
+ 'pagination' => ['pageSize' => 100],
+ ]);
+
+ $bouquetSpeciesForecast = [];
+ // Обработка даты на год и месяц
+ if (!empty($filters['year']) && !empty($filters['month'])) {
+ $filters['plan_date'] = $filters['year'] . '-' . str_pad($filters['month'], 2, '0', STR_PAD_LEFT) . '-01';
+ //var_dump($filters); die();
+ $service = new AutoPlannogrammaService();
+
+ //$goals = $service->calculateFullGoalChain($filters);
+ $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters);
+ $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date']);
+ $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters);
+ $monthSubcategoryGoal = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal);
+ $monthSpeciesShare = $service->getMonthSpeciesShareOrWriteOff($filters['plan_date'], $filters);
+ $goals = $service->getMonthSpeciesGoalDirty($monthSpeciesShare, $monthSubcategoryGoal);
+
+ if ($filters['type'] == AutoPlannogrammaService::TYPE_WRITE_OFFS) {
+ $monthCategoryWriteOffsShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']);
+ $monthCategoryWriteOffsGoal = $service->getMonthCategoryGoal($monthCategoryWriteOffsShare, $filters['plan_date'], $filters['type']);
+ $monthSubcategoryWriteOffsShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']);
+ $monthSubcategoryWriteOffsGoals = $service->getMonthSubcategoryGoal($monthSubcategoryWriteOffsShare, $monthCategoryWriteOffsGoal, $filters['type']);
+ $monthSpeciesWriteOffShare = $service->getMonthSpeciesShareOrWriteOff($filters['plan_date'], $filters, $filters['type']);
+ $goals = $service->getMonthSpeciesGoalDirty($monthSpeciesWriteOffShare, $monthSubcategoryWriteOffsGoals, $filters['type'], $data);
+ }
+
+
+ $result = StorePlanService::calculateHistoricalShare(
+ $filters['store_id'],
+ $filters['month'],
+ $filters['year'],
+ $filters['category'],
+ $filters['subcategory'],
+ $filters['species']
+ );
+
+ $noHistoryProductData = $service->calculateSpeciesForecastForProductsWithoutHistory($filters['plan_date'], $filters);
+
+ $productSalesShare = StorePlanService::calculateProductSalesShareProductsWithHistory(
+ $filters['store_id'],
+ $filters['month'],
+ $result['with_history']
+ );
+
+ $productSalesForecast = $service->calculateProductForecastInPiecesProductsWithHistory(
+ $filters['store_id'],
+ $filters['month'],
+ $filters['category'],
+ $filters['subcategory'],
+ $filters['species'],
+ $productSalesShare,
+ $goals
+ );
+
+ $matrixForecast = MatrixBouquetForecast::find()
+ ->where(['year' => $filters['year'], 'month' => $filters['month']])
+ ->asArray()
+ ->all();
+ $matrixGroups = array_unique(ArrayHelper::getColumn($matrixForecast, 'group'));
+ $bouquetForecast = StorePlanService::getBouquetSpiecesMonthGoalFromForecast($filters['month'], $filters['year'], $filters['store_id'], $matrixGroups);
+ $speciesData = $bouquetForecast['final'];
+ foreach ($speciesData as $store_id => $categoryData) {
+ foreach ($categoryData as $category => $subcategoryData) {
+ foreach ($subcategoryData as $subcategory => $species) {
+ foreach ($species as $speciesInd => $row) {
+ $bouquetSpeciesForecast[] = [
+ 'category' => $category,
+ 'subcategory' => $subcategory,
+ 'store_id' => $store_id,
+ 'species' => $speciesInd,
+ 'goal' => $row
+ ];
+ }
+ }
+ }
+
+ }
+ $cleanedSpeciesGoals = $service->subtractSpeciesGoals($goals, $bouquetSpeciesForecast, $noHistoryProductData);
+
+
+ $salesProductForecastShare = $service->calculateProductForecastShare($noHistoryProductData, $productSalesForecast);
+
+ $productForecastSpecies = $service->calculateProductSalesBySpecies($salesProductForecastShare, $cleanedSpeciesGoals);
+
+ //var_dump($salesProductForecastShare); die();
+
+
+
+
+
+ $flatData = array_filter($productForecastSpecies, function ($row) use ($filters) {
+ foreach ($filters as $key => $value) {
+ if (empty($value)) continue;
+ if (!isset($row[$key])) continue;
+
+ if (stripos((string)$row[$key], (string)$value) === false) {
+ return false;
+ }
+ }
+ return true;
+ });
+
+ $dataProvider = new ArrayDataProvider([
+ 'allModels' => $flatData,
+ 'pagination' => ['pageSize' => 100],
+ ]);
+ }
+ return $this->render('month-products-species-forecast', [
'dataProvider' => $dataProvider,
'filters' => $filters,
]);
}
//var_dump($bouquetSpeciesForecast); die();
$noHistoryProductData = $service->calculateSpeciesForecastForProductsWithoutHistory($filters['plan_date'], $filters);
- //var_dump($noHistoryProductData); die();
+ // var_dump($noHistoryProductData); die();
$cleanedSpeciesGoals = $service->subtractSpeciesGoals($data, $bouquetSpeciesForecast, $noHistoryProductData);
//var_dump($cleanedSpeciesGoals); die();
*/
public function calculateSpeciesForecastForProductsWithoutHistory($dateFrom, $filters): array
{
- $t0 = hrtime(true);
// Получение ID видимых магазинов
$storeIds = array_map(fn($store) => $store->id, $this->getVisibleStores());
$year = $date->format('Y');
$result = [];
- $initTime = (hrtime(true) - $t0) / 1e6; // миллисекунды
- Yii::warning( "Init (getVisibleStores + filters): {$initTime} ms\n");
+
foreach ($storeIds as $storeId) {
$t1 = hrtime(true);
$histResult = StorePlanService::calculateHistoricalShare(
$subcategory,
$species
);
- $dur = (hrtime(true) - $t1) / 1e6;
- Yii::warning( "calculateHistoricalShare for store {$storeId}: {$dur} ms\n");
$productsWithoutHistory = $histResult['without_history'] ?? [];
if (empty($productsWithoutHistory)) {
}
// ——————— WEIGHTED SALES ————————
- $t2 = hrtime(true);
+
$medianResults = StorePlanService::calculateMedianSalesForProductsWithoutHistoryExtended(
$storeId, $month, $year, $productsWithoutHistory
);
- $dur = (hrtime(true) - $t2) / 1e6;
- Yii::warning("calculateMedianSalesForProductsWithoutHistory for store {$storeId}: {$dur} ms\n");
if (empty($medianResults)) {
continue;
}
// ——————— COST CALCULATION ————————
- $t3 = hrtime(true);
+
$costs = StorePlanService::calculateCostForProductsWithoutHistory(
$storeId, $month, $year, $medianResults
);
- $dur = (hrtime(true) - $t3) / 1e6;
- Yii::warning( "calculateCostForProductsWithoutHistory for store {$storeId}: {$dur} ms\n");
if (!empty($costs)) {
$result = array_merge($result, $costs);
}
}
- $totalTime = (hrtime(true) - $t0) / 1e6;
- Yii::warning( "Total calculateSpeciesForecastForProductsWithoutHistory: {$totalTime} ms\n");
-
return $result;
}
*
* @param int $storeId
* @param array $periods Массив периодов, сформированный функцией getPeriods.
- * @param string $category
+ * @param string|null $category
* @param string|null $subcategory
* @param string|null $species
*
- * @return array Структура данных:
- * [
- * 'product_guid1' => [
- * 'YYYY-MM' => [
- * 0 => salesCount_week1,
- * 1 => salesCount_week2,
- * ...
- * ],
- * ...
- * ],
- * ...
- * ]
+ * @return array
*/
- private static function getSalesHistory($storeId, $periods, $category, $subcategory = null, $species = null)
+ private static function getSalesHistory($storeId, $periods, $category = null, $subcategory = null, $species = null)
{
$salesHistory = [];
$query = Sales::find()->alias('s')
->select([
'p1c.id as product_guid',
- 'COUNT(*) as sales_count'
+ 'COUNT(*) as sales_count',
+ 'p1c.category',
+ 'p1c.subcategory',
+ 'p1c.species',
])
->innerJoin('sales_products sp', 's.id = sp.check_id')
->innerJoin('products_1c_nomenclature p1c', 'p1c.id = sp.product_id')
->where(['s.store_id' => $storeId])
->andWhere(['between', 's.date', $dateStart, $dateEnd])
->andWhere(['order_id' => ['', '0']])
- ->andWhere(['p1c.category' => $category]);
-
- if ($subcategory !== null) {
- $query->andWhere(['p1c.subcategory' => $subcategory]);
- }
- if ($species !== null) {
- $query->andWhere(['p1c.species' => $species]);
- }
+ ->andFilterWhere(['p1c.category' => $category])
+ ->andFilterWhere(['p1c.subcategory' => $subcategory])
+ ->andFilterWhere(['p1c.species' => $species])
+ ->groupBy([
+ 'p1c.id',
+ 'p1c.category',
+ 'p1c.subcategory',
+ 'p1c.species',
+ ]);
- $query->groupBy('p1c.id');
$results = $query->asArray()->all();
+ foreach ($results as $row) {
+ $guid = $row['product_guid'];
- foreach ($results as $result) {
- $guid = $result['product_guid'];
if (!isset($salesHistory[$guid])) {
- $salesHistory[$guid] = [];
- }
- if (!isset($salesHistory[$guid][$periodKey])) {
- $salesHistory[$guid][$periodKey] = [];
+ $salesHistory[$guid] = [
+ 'category' => $row['category'],
+ 'subcategory' => $row['subcategory'],
+ 'species' => $row['species'],
+ 'data' => [],
+ ];
}
- $salesHistory[$guid][$periodKey][$weekIndex] = (int)$result['sales_count'];
+
+ $salesHistory[$guid]['data'][$periodKey][$weekIndex] = (int)$row['sales_count'];
}
}
}
* 'without_history' => [...],
* ]
*/
- private static function analyzeHistory($salesHistory, $periods)
+ private static function analyzeHistory(array $salesHistory, array $periods)
{
$productsWithHistory = [];
$productsWithoutHistory = [];
- foreach ($salesHistory as $guid => $monthsData) {
+ foreach ($salesHistory as $guid => $info) {
+ $monthsData = $info['data'];
+ $metaFields = [
+ 'category' => $info['category'],
+ 'subcategory' => $info['subcategory'],
+ 'species' => $info['species'],
+ ];
$hasHistoryInAllPeriods = true;
- $weeklySalesData = [];
+ $weeklySalesData = [];
foreach ($periods as $periodKey => $periodData) {
$weeksCount = count($periodData['weeks']);
if (!isset($monthsData[$periodKey])) {
$hasHistoryInAllPeriods = false;
- // Заполняем пустыми значениями столько недель, сколько их есть в периоде.
$weekData = array_fill(0, $weeksCount, 0);
} else {
- $weekData = [];
+ $weekData = [];
$activeWeeks = 0;
- for ($weekIndex = 0; $weekIndex < $weeksCount; $weekIndex++) {
- $salesCount = isset($monthsData[$periodKey][$weekIndex]) ? $monthsData[$periodKey][$weekIndex] : 0;
- $weekData[$weekIndex] = $salesCount;
- if ($weekIndex == 4) {
- continue; //пропускаем 5 неполную неделю в учете активных продаж
- }
- if ($salesCount > 0) {
+ for ($i = 0; $i < $weeksCount; $i++) {
+ $count = $monthsData[$periodKey][$i] ?? 0;
+ $weekData[$i] = $count;
+
+ if ($i < 4 && $count > 0) {
$activeWeeks++;
}
}
$hasHistoryInAllPeriods = false;
}
}
+
$weeklySalesData[$periodKey] = $weekData;
}
- $productData = [
- 'guid' => $guid,
- 'weekly_sales' => $weeklySalesData,
- ];
+ $item = array_merge(
+ ['guid' => $guid],
+ $metaFields,
+ ['weekly_sales' => $weeklySalesData]
+ );
if ($hasHistoryInAllPeriods) {
- $productsWithHistory[] = $productData;
+ $productsWithHistory[] = $item;
} else {
- $productsWithoutHistory[] = $productData;
+ $productsWithoutHistory[] = $item;
}
}
}
+
/**
* Метод вычисляет значение продаж для товаров без истории.
*
*/
public static function calculateMedianSalesForProductsWithoutHistoryExtended($storeId, $selectedMonth, $selectedYear, $productsWithoutHistory)
{
- $t0 = hrtime(true);
$targetDate = strtotime("{$selectedYear}-{$selectedMonth}-01");
$periods = self::getPeriods($targetDate, 3);
$medianSalesResults = [];
- $initTime = (hrtime(true) - $t0) / 1e6; // миллисекунды
- Yii::warning( "Init (periods): {$initTime} ms\n");
+
foreach ($productsWithoutHistory as $product) {
$guid = $product['guid'];
- $t1 = hrtime(true);
+
+
$similarProductIds = self::getSimilarProductIDs($guid);
if (empty($similarProductIds)) {
$medianSalesResults[$guid] = 0;
continue;
}
- $dur = (hrtime(true) - $t1) / 1e6;
- Yii::warning( "getSimilarProductIDs for product {$guid} {$storeId}: {$dur} ms\n");
+
$medianSales = [];
$salesValuesForEachMonth = [];
- $t2 = hrtime(true);
+
foreach ($periods as $periodKey => $monthInfo) {
list($median, $salesValues) = self::calculateMedianSalesForPeriod($storeId, $similarProductIds, $monthInfo);
$medianSales[$periodKey] = $median;
$salesValuesForEachMonth[$periodKey] = $salesValues;
}
- $dur = (hrtime(true) - $t2) / 1e6;
- Yii::warning("calculateMedianSalesForPeriod for product {$guid} {$storeId}: {$dur} ms\n");
- $t3 = hrtime(true);
$median3 = self::calculateMedianSalesOverPeriods($storeId, $similarProductIds, $periods);
$medianSalesResults[$guid] = [
+ 'store_id' => $storeId,
+ 'category' => $product['category'],
+ 'subcategory' => $product['subcategory'],
+ 'species' => $product['species'],
'weightedValue' => $median3,
'medianSales' => $medianSales,
'salesValues' => $salesValuesForEachMonth,
];
- $dur = (hrtime(true) - $t3) / 1e6;
- Yii::warning( "computeWeightedValue for product {$guid} {$storeId}: {$dur} ms\n");
- }
- $totalTime = (hrtime(true) - $t0) / 1e6;
- Yii::warning( "Total calculateWeightedSalesForProductsWithoutHistory: {$totalTime} ms\n");
+ }
return $medianSalesResults;
}
$guidToGroup = [];
- foreach ($medianProductsWithoutHistory as $guid => $qty) {
- $q = (float)$qty;
+ foreach ($medianProductsWithoutHistory as $guid => $data) {
+ $q = (float)$data['weightedValue'];
if ($q <= 0) continue;
$price = self::getPriceForProductAtOffsetMonthWeekly(
);
$prices[$guid] = $price;
- $nom = Products1cNomenclature::findOne($guid);
- $cat = $nom->category ?? '';
- $sub = $nom->subcategory ?? '';
- $sp = $nom->species ?? '';
+ $cat = $data['category'];
+ $sub = $data['subcategory'];
+ $sp = $data['species'];
$groupKey = implode('|', [$cat,$sub,$sp]);
$guidToGroup[$guid] = $groupKey;
+++ /dev/null
-<?php
-?>
- <div class="filter-form" style="margin-bottom: 20px;">
- <?php use kartik\date\DatePicker;
- use kartik\grid\GridView;
- use kartik\select2\Select2;
- use yii\helpers\ArrayHelper;
- use yii\helpers\Html;
- use yii\widgets\ActiveForm;
- use yii_app\records\CityStore;
- use yii_app\records\Products1cNomenclature;
- ?>
- <h1 class="ms-3 mb-4"><?= Html::encode("Расчет доли товара от общего количества внутри вида (month_goods_sales_share)") ?></h1>
- <?php
- $form = ActiveForm::begin(['method' => 'get']); ?>
- <div class="row p-3">
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['category' => $filters['category'] ?? '']), 'category')->widget(Select2::class, [
- 'data' => ArrayHelper::map(
- Products1cNomenclature::find()->select('category')->distinct()->asArray()->all(),
- 'category',
- 'category'
- ),
- 'options' => ['placeholder' => 'Категория', 'name' => 'category'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('Категория') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['subcategory' => $filters['subcategory'] ?? '']), 'subcategory')->widget(Select2::class, [
- 'data' => ArrayHelper::map(
- Products1cNomenclature::find()->select('subcategory')->distinct()->asArray()->all(),
- 'subcategory',
- 'subcategory'
- ),
- 'options' => ['placeholder' => 'Подкатегория', 'name' => 'subcategory'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('Подкатегория') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['species' => $filters['species'] ?? '']), 'species')->widget(Select2::class, [
- 'data' => ArrayHelper::map(
- Products1cNomenclature::find()->select('species')->distinct()->asArray()->all(),
- 'species',
- 'species'
- ),
- 'options' => ['placeholder' => 'Тип товара', 'name' => 'species'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('Товар') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['store_id' => $filters['store_id'] ?? '']), 'store_id')->widget(Select2::class, [
- 'data' => ArrayHelper::map(
- CityStore::findAll(['visible' => CityStore::IS_VISIBLE]),
- 'id',
- 'name'
- ),
- 'options' => ['placeholder' => 'Магазин', 'name' => 'store_id'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('Магазин') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['month' => $filters['month'] ?? '']), 'month')->dropDownList(\yii_app\helpers\DateHelper::MONTH_NUMBER_NAMES, [
- 'prompt' => 'Месяц',
- 'name' => 'month',
- ])->label('Плановый месяц') ?>
- </div>
-
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['year' => $filters['year'] ?? '']), 'year')->dropDownList(['2025' => 2025, '2026' => 2026], [
- 'prompt' => 'Год',
- 'name' => 'year',
- ])->label('Плановый год') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['type' => $filters['type'] ?? '']), 'type')->widget(Select2::class, [
- 'data' => [
- 'writeOffs' => 'Списания',
- 'sales' => 'Продажи'
- ],
- 'options' => ['placeholder' => 'Тип', 'name' => 'type'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('По дефолту продажи!') ?>
- </div>
- <div class="col-md">
- <?= Html::submitButton('Фильтровать', ['class' => 'btn btn-primary']) ?>
- </div>
- <div class="col-md">
- <?= Html::a('Сбросить', ['auto-plannogramma/8'], ['class' => 'btn btn-default']) ?>
- </div>
- </div>
-
- <?php ActiveForm::end(); ?>
- </div>
-
-
-
-<?php
-$columns = [
- ['attribute' => 'store_id', 'label' => 'Магазин', 'value' => function ($data) {
- return CityStore::findOne($data['store_id'])->name ?? null;
- }],
- ['attribute' => 'category', 'label' => 'Категория'],
- ['attribute' => 'subcategory', 'label' => 'Подкатегория'],
- ['attribute' => 'species', 'label' => 'Тип'],
- ['attribute' => 'product_id', 'label' => 'GUID Товара', ],
- ['attribute' => 'product_id', 'label' => 'Имя Товара',
- 'value' => function ($data) {
- return \yii_app\records\Products1c::findOne($data['product_id'])->name ?? null;
- },
- ],
- ['attribute' => 'forecast_pieces', 'label' => 'Прогноз в шт', 'format' => ['decimal', 2]],
- ['attribute' => 'share', 'label' => 'Доля',
-
- 'format' => ['percent', 2]],
-
- ['attribute' => 'history_status', 'label' => 'Статус товара', ],
-];
-
-
-?>
-<?= GridView::widget([
- 'dataProvider' => $dataProvider,
- 'columns' => $columns,
-]); ?>
-<?php
+++ /dev/null
-<?php
-?>
- <div class="filter-form" style="margin-bottom: 20px;">
- <?php use kartik\date\DatePicker;
- use kartik\grid\GridView;
- use kartik\select2\Select2;
- use yii\helpers\ArrayHelper;
- use yii\helpers\Html;
- use yii\widgets\ActiveForm;
- use yii_app\records\CityStore;
- use yii_app\records\Products1cNomenclature;
- ?>
- <h1 class="ms-3 mb-4"><?= Html::encode("Расчет доли товара от общего количества внутри вида (month_goods_sales_share)") ?></h1>
- <?php
- $form = ActiveForm::begin(['method' => 'get']); ?>
- <div class="row p-3">
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['category' => $filters['category'] ?? '']), 'category')->widget(Select2::class, [
- 'data' => ArrayHelper::map(
- Products1cNomenclature::find()->select('category')->distinct()->asArray()->all(),
- 'category',
- 'category'
- ),
- 'options' => ['placeholder' => 'Категория', 'name' => 'category'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('Категория') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['subcategory' => $filters['subcategory'] ?? '']), 'subcategory')->widget(Select2::class, [
- 'data' => ArrayHelper::map(
- Products1cNomenclature::find()->select('subcategory')->distinct()->asArray()->all(),
- 'subcategory',
- 'subcategory'
- ),
- 'options' => ['placeholder' => 'Подкатегория', 'name' => 'subcategory'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('Подкатегория') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['species' => $filters['species'] ?? '']), 'species')->widget(Select2::class, [
- 'data' => ArrayHelper::map(
- Products1cNomenclature::find()->select('species')->distinct()->asArray()->all(),
- 'species',
- 'species'
- ),
- 'options' => ['placeholder' => 'Тип товара', 'name' => 'species'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('Товар') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['store_id' => $filters['store_id'] ?? '']), 'store_id')->widget(Select2::class, [
- 'data' => ArrayHelper::map(
- CityStore::findAll(['visible' => CityStore::IS_VISIBLE]),
- 'id',
- 'name'
- ),
- 'options' => ['placeholder' => 'Магазин', 'name' => 'store_id'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('Магазин') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['month' => $filters['month'] ?? '']), 'month')->dropDownList(\yii_app\helpers\DateHelper::MONTH_NUMBER_NAMES, [
- 'prompt' => 'Месяц',
- 'name' => 'month',
- ])->label('Плановый месяц') ?>
- </div>
-
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['year' => $filters['year'] ?? '']), 'year')->dropDownList(['2025' => 2025, '2026' => 2026], [
- 'prompt' => 'Год',
- 'name' => 'year',
- ])->label('Плановый год') ?>
- </div>
- <div class="col-md">
- <?= $form->field(new \yii\base\DynamicModel(['type' => $filters['type'] ?? '']), 'type')->widget(Select2::class, [
- 'data' => [
- 'writeOffs' => 'Списания',
- 'sales' => 'Продажи'
- ],
- 'options' => ['placeholder' => 'Тип', 'name' => 'type'],
- 'pluginOptions' => ['allowClear' => true],
- ])->label('По дефолту продажи!') ?>
- </div>
- <div class="col-md">
- <?= Html::submitButton('Фильтровать', ['class' => 'btn btn-primary']) ?>
- </div>
- <div class="col-md">
- <?= Html::a('Сбросить', ['auto-plannogramma/8'], ['class' => 'btn btn-default']) ?>
- </div>
- </div>
-
- <?php ActiveForm::end(); ?>
- </div>
-
-
-
-<?php
-$columns = [
- ['attribute' => 'store_id', 'label' => 'Магазин', 'value' => function ($data) {
- return CityStore::findOne($data['store_id'])->name ?? null;
- }],
- ['attribute' => 'category', 'label' => 'Категория'],
- ['attribute' => 'subcategory', 'label' => 'Подкатегория'],
- ['attribute' => 'species', 'label' => 'Тип'],
- ['attribute' => 'product_id', 'label' => 'GUID Товара', ],
- ['attribute' => 'product_id', 'label' => 'Имя Товара',
- 'value' => function ($data) {
- return \yii_app\records\Products1c::findOne($data['product_id'])->name ?? null;
- },
- ],
- ['attribute' => 'forecast_pieces', 'label' => 'Прогноз в шт', 'format' => ['decimal', 2]],
- ['attribute' => 'share', 'label' => 'Доля',
-
- 'format' => ['percent', 2]],
- ['attribute' => 'cleanGoal', 'label' => 'Цель вида очищенная', 'format' => ['decimal', 2]],
- ['attribute' => 'product_sales', 'label' => 'Прогноз в стоимости внутри вида', 'format' => ['decimal', 2]],
- ['attribute' => 'history_status', 'label' => 'Статус товара', ],
-];
-
-
-?>
-<?= GridView::widget([
- 'dataProvider' => $dataProvider,
- 'columns' => $columns,
-]); ?>
-<?php
--- /dev/null
+<?php
+?>
+ <div class="filter-form" style="margin-bottom: 20px;">
+ <?php use kartik\date\DatePicker;
+ use kartik\grid\GridView;
+ use kartik\select2\Select2;
+ use yii\helpers\ArrayHelper;
+ use yii\helpers\Html;
+ use yii\widgets\ActiveForm;
+ use yii_app\records\CityStore;
+ use yii_app\records\Products1cNomenclature;
+ ?>
+ <h1 class="ms-3 mb-4"><?= Html::encode("Расчет прогноза товаров внутри вида (month_goods_sales_share)") ?></h1>
+ <?php
+ $form = ActiveForm::begin(['method' => 'get']); ?>
+ <div class="row p-3">
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['category' => $filters['category'] ?? '']), 'category')->widget(Select2::class, [
+ 'data' => ArrayHelper::map(
+ Products1cNomenclature::find()->select('category')->distinct()->asArray()->all(),
+ 'category',
+ 'category'
+ ),
+ 'options' => ['placeholder' => 'Категория', 'name' => 'category'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('Категория') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['subcategory' => $filters['subcategory'] ?? '']), 'subcategory')->widget(Select2::class, [
+ 'data' => ArrayHelper::map(
+ Products1cNomenclature::find()->select('subcategory')->distinct()->asArray()->all(),
+ 'subcategory',
+ 'subcategory'
+ ),
+ 'options' => ['placeholder' => 'Подкатегория', 'name' => 'subcategory'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('Подкатегория') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['species' => $filters['species'] ?? '']), 'species')->widget(Select2::class, [
+ 'data' => ArrayHelper::map(
+ Products1cNomenclature::find()->select('species')->distinct()->asArray()->all(),
+ 'species',
+ 'species'
+ ),
+ 'options' => ['placeholder' => 'Тип товара', 'name' => 'species'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('Товар') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['store_id' => $filters['store_id'] ?? '']), 'store_id')->widget(Select2::class, [
+ 'data' => ArrayHelper::map(
+ CityStore::findAll(['visible' => CityStore::IS_VISIBLE]),
+ 'id',
+ 'name'
+ ),
+ 'options' => ['placeholder' => 'Магазин', 'name' => 'store_id'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('Магазин') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['month' => $filters['month'] ?? '']), 'month')->dropDownList(\yii_app\helpers\DateHelper::MONTH_NUMBER_NAMES, [
+ 'prompt' => 'Месяц',
+ 'name' => 'month',
+ ])->label('Плановый месяц') ?>
+ </div>
+
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['year' => $filters['year'] ?? '']), 'year')->dropDownList(['2025' => 2025, '2026' => 2026], [
+ 'prompt' => 'Год',
+ 'name' => 'year',
+ ])->label('Плановый год') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['type' => $filters['type'] ?? '']), 'type')->widget(Select2::class, [
+ 'data' => [
+ 'writeOffs' => 'Списания',
+ 'sales' => 'Продажи'
+ ],
+ 'options' => ['placeholder' => 'Тип', 'name' => 'type'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('По дефолту продажи!') ?>
+ </div>
+ <div class="col-md">
+ <?= Html::submitButton('Фильтровать', ['class' => 'btn btn-primary']) ?>
+ </div>
+ <div class="col-md">
+ <?= Html::a('Сбросить', ['auto-plannogramma/8'], ['class' => 'btn btn-default']) ?>
+ </div>
+ </div>
+
+ <?php ActiveForm::end(); ?>
+ </div>
+
+
+
+<?php
+$columns = [
+ ['attribute' => 'store_id', 'label' => 'Магазин', 'value' => function ($data) {
+ return CityStore::findOne($data['store_id'])->name ?? null;
+ }],
+ ['attribute' => 'category', 'label' => 'Категория'],
+ ['attribute' => 'subcategory', 'label' => 'Подкатегория'],
+ ['attribute' => 'species', 'label' => 'Тип'],
+ ['attribute' => 'product_id', 'label' => 'GUID Товара', ],
+ ['attribute' => 'product_id', 'label' => 'Имя Товара',
+ 'value' => function ($data) {
+ return \yii_app\records\Products1c::findOne($data['product_id'])->name ?? null;
+ },
+ ],
+ ['attribute' => 'forecast_pieces', 'label' => 'Прогноз в шт', 'format' => ['decimal', 2]],
+ ['attribute' => 'share', 'label' => 'Доля',
+
+ 'format' => ['percent', 2]],
+ ['attribute' => 'cleanGoal', 'label' => 'Цель вида очищенная', 'format' => ['decimal', 2]],
+ ['attribute' => 'product_sales', 'label' => 'Прогноз в стоимости внутри вида', 'format' => ['decimal', 2]],
+ ['attribute' => 'history_status', 'label' => 'Статус товара', ],
+];
+
+
+?>
+<?= GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'columns' => $columns,
+]); ?>
+<?php
--- /dev/null
+<?php
+?>
+ <div class="filter-form" style="margin-bottom: 20px;">
+ <?php use kartik\date\DatePicker;
+ use kartik\grid\GridView;
+ use kartik\select2\Select2;
+ use yii\helpers\ArrayHelper;
+ use yii\helpers\Html;
+ use yii\widgets\ActiveForm;
+ use yii_app\records\CityStore;
+ use yii_app\records\Products1cNomenclature;
+ ?>
+ <h1 class="ms-3 mb-4"><?= Html::encode("Расчет доли товара от общего количества внутри вида (month_goods_sales_share)") ?></h1>
+ <?php
+ $form = ActiveForm::begin(['method' => 'get']); ?>
+ <div class="row p-3">
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['category' => $filters['category'] ?? '']), 'category')->widget(Select2::class, [
+ 'data' => ArrayHelper::map(
+ Products1cNomenclature::find()->select('category')->distinct()->asArray()->all(),
+ 'category',
+ 'category'
+ ),
+ 'options' => ['placeholder' => 'Категория', 'name' => 'category'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('Категория') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['subcategory' => $filters['subcategory'] ?? '']), 'subcategory')->widget(Select2::class, [
+ 'data' => ArrayHelper::map(
+ Products1cNomenclature::find()->select('subcategory')->distinct()->asArray()->all(),
+ 'subcategory',
+ 'subcategory'
+ ),
+ 'options' => ['placeholder' => 'Подкатегория', 'name' => 'subcategory'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('Подкатегория') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['species' => $filters['species'] ?? '']), 'species')->widget(Select2::class, [
+ 'data' => ArrayHelper::map(
+ Products1cNomenclature::find()->select('species')->distinct()->asArray()->all(),
+ 'species',
+ 'species'
+ ),
+ 'options' => ['placeholder' => 'Тип товара', 'name' => 'species'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('Товар') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['store_id' => $filters['store_id'] ?? '']), 'store_id')->widget(Select2::class, [
+ 'data' => ArrayHelper::map(
+ CityStore::findAll(['visible' => CityStore::IS_VISIBLE]),
+ 'id',
+ 'name'
+ ),
+ 'options' => ['placeholder' => 'Магазин', 'name' => 'store_id'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('Магазин') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['month' => $filters['month'] ?? '']), 'month')->dropDownList(\yii_app\helpers\DateHelper::MONTH_NUMBER_NAMES, [
+ 'prompt' => 'Месяц',
+ 'name' => 'month',
+ ])->label('Плановый месяц') ?>
+ </div>
+
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['year' => $filters['year'] ?? '']), 'year')->dropDownList(['2025' => 2025, '2026' => 2026], [
+ 'prompt' => 'Год',
+ 'name' => 'year',
+ ])->label('Плановый год') ?>
+ </div>
+ <div class="col-md">
+ <?= $form->field(new \yii\base\DynamicModel(['type' => $filters['type'] ?? '']), 'type')->widget(Select2::class, [
+ 'data' => [
+ 'writeOffs' => 'Списания',
+ 'sales' => 'Продажи'
+ ],
+ 'options' => ['placeholder' => 'Тип', 'name' => 'type'],
+ 'pluginOptions' => ['allowClear' => true],
+ ])->label('По дефолту продажи!') ?>
+ </div>
+ <div class="col-md">
+ <?= Html::submitButton('Фильтровать', ['class' => 'btn btn-primary']) ?>
+ </div>
+ <div class="col-md">
+ <?= Html::a('Сбросить', ['auto-plannogramma/8'], ['class' => 'btn btn-default']) ?>
+ </div>
+ </div>
+
+ <?php ActiveForm::end(); ?>
+ </div>
+
+
+
+<?php
+$columns = [
+ ['attribute' => 'store_id', 'label' => 'Магазин', 'value' => function ($data) {
+ return CityStore::findOne($data['store_id'])->name ?? null;
+ }],
+ ['attribute' => 'category', 'label' => 'Категория'],
+ ['attribute' => 'subcategory', 'label' => 'Подкатегория'],
+ ['attribute' => 'species', 'label' => 'Тип'],
+ ['attribute' => 'product_id', 'label' => 'GUID Товара', ],
+ ['attribute' => 'product_id', 'label' => 'Имя Товара',
+ 'value' => function ($data) {
+ return \yii_app\records\Products1c::findOne($data['product_id'])->name ?? null;
+ },
+ ],
+ ['attribute' => 'forecast_pieces', 'label' => 'Прогноз в шт', 'format' => ['decimal', 2]],
+ ['attribute' => 'share', 'label' => 'Доля',
+
+ 'format' => ['percent', 2]],
+
+ ['attribute' => 'history_status', 'label' => 'Статус товара', ],
+];
+
+
+?>
+<?= GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'columns' => $columns,
+]); ?>
+<?php