From f7644cbe4fdd19e1ed182c11f65cfcf59fc1ce4b Mon Sep 17 00:00:00 2001 From: Vladimir Fomichev Date: Thu, 24 Jul 2025 22:34:10 +0300 Subject: [PATCH] =?utf8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20=D0=BF?= =?utf8?q?=D0=BE=20=D1=80=D0=B0=D1=81=D1=87=D0=B5=D1=82=D1=83=20=D0=B0?= =?utf8?q?=D0=B2=D1=82=D0=BE=D0=BF=D0=BB=D0=B0=D0=BD=D0=BD=D0=BE=D0=B3?= =?utf8?q?=D1=80=D0=B0=D0=BC=D0=BC=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- erp24/commands/CronController.php | 29 +- .../AutoPlannogrammaController.php | 358 +++++++----------- erp24/services/AutoPlannogrammaService.php | 28 ++ erp24/services/StorePlanService.php | 57 +-- erp24/views/auto-plannogramma/calculate.php | 117 ++++++ 5 files changed, 345 insertions(+), 244 deletions(-) create mode 100644 erp24/views/auto-plannogramma/calculate.php diff --git a/erp24/commands/CronController.php b/erp24/commands/CronController.php index bc6275a3..088667e4 100644 --- a/erp24/commands/CronController.php +++ b/erp24/commands/CronController.php @@ -1593,7 +1593,7 @@ class CronController extends Controller public function actionAutoplannogrammaCalculate(): void { $date = new DateTime(); - $date->modify('+2 months'); + $date->modify('+0 months'); $planDate = $date->format('Y-m-01'); $month = (int)$date->format('m'); $year = (int)$date->format('Y'); @@ -1617,8 +1617,18 @@ class CronController extends Controller 'species' => null, 'plan_date' => $planDate ]; - + $this->stdout("Рассчитана автопланограмма для магазина " . json_encode($forecastParams, JSON_UNESCAPED_UNICODE) . "\n", BaseConsole::FG_GREEN); $forecast = $service->calculateFullForecastForWeek($forecastParams); + $logDir = Yii::getAlias('@runtime/logs/autoplannogramma'); + if (!is_dir($logDir)) { + mkdir($logDir, 0755, true); + } + $file = $logDir . '/forecast_store_' . $store->id . '_' . date('Ymd_His') . '.json'; + file_put_contents( + $file, + json_encode($forecast, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) + ); + $this->stdout("Forecast сохранён в $file\n", BaseConsole::FG_BLUE); $writeOffsForecast = $service->getWeeklyProductsWriteoffsForecast($month, $year, $forecast, $store->id); $salesForecast = $service->getWeeklyBouquetProductsSalesForecast($month, $year, $store->id); @@ -1640,11 +1650,16 @@ class CronController extends Controller $productId = $item['product_id']; $week = $item['week']; $quantity = (float)($item['forecast_week_pieces'] ?? 0); - + if ($productId == '0fb4e768-8191-11ef-84ea-ac1f6b1b7573') { + $this->stdout("Сохраняем: product={$productId} week={$week} quantity={$quantity}\n", BaseConsole::FG_CYAN); + $this->stdout($item['forecast_week_pieces'] . "\n", BaseConsole::FG_CYAN); + } $details = []; $total = $quantity; - if (!empty($writeOffsForecast[$productId][$week]['writeOffs'])) { + if (!empty($writeOffsForecast[$productId]) && + !empty($writeOffsForecast[$productId][$week]) && + array_key_exists('writeOffs', $writeOffsForecast[$productId][$week])) { $writeOffs = $writeOffsForecast[$productId][$week]['writeOffs']; $details['writeOffs']['quantity'] = $writeOffs; $total += is_array($writeOffs) ? array_sum($writeOffs) : (float)$writeOffs; @@ -1700,7 +1715,7 @@ class CronController extends Controller 'calculate' => $quantity, 'modify' => null, 'total' => ceil($total) - ]); + ], false); if (!$model->save()) { $errors = implode('; ', array_map( @@ -1717,7 +1732,9 @@ class CronController extends Controller $this->stdout("Сохранена автопланограмма для магазина {$store->name}\n", BaseConsole::FG_GREEN); } catch (Throwable $e) { $this->stderr("Ошибка при расчёте прогноза: {$e->getMessage()}\n", BaseConsole::FG_RED); - Yii::error("Ошибка при расчёте прогноза: " . $e->getMessage(), __METHOD__); + $trace = $e->getTraceAsString(); + Yii::error("Ошибка при расчёте прогноза: " . $e->getMessage() . "\nTrace:\n" . $trace, __METHOD__); + $this->stderr("Трассировка:\n$trace\n", BaseConsole::FG_RED); continue; } } diff --git a/erp24/controllers/AutoPlannogrammaController.php b/erp24/controllers/AutoPlannogrammaController.php index 1ee5b578..7dcf9bca 100644 --- a/erp24/controllers/AutoPlannogrammaController.php +++ b/erp24/controllers/AutoPlannogrammaController.php @@ -2,6 +2,8 @@ namespace app\controllers; +use DateTime; +use Throwable; use Yii; use yii\base\DynamicModel; use yii\data\ArrayDataProvider; @@ -1355,8 +1357,8 @@ class AutoPlannogrammaController extends BaseController $service = new AutoPlannogrammaService(); //$goals = $service->calculateFullGoalChain($filters); - //$forecast = $service->calculateFullForecastForWeek($filters); - //var_dump( $forecast); die(); + $forecast = $service->calculateFullForecastForWeek($filters); + var_dump( $forecast); die(); $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters); $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date']); $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters); @@ -1462,216 +1464,6 @@ class AutoPlannogrammaController extends BaseController } - public function actionControlSpeciesOld() - { - $model = new DynamicModel([ - 'storeId', 'month', 'type', - - ]); - $model->addRule(['month', 'type'], 'required') - ->addRule('storeId', 'integer'); - - $storeList = CityStore::find() - ->select(['name', 'id']) - ->where(['visible' => CityStore::IS_VISIBLE]) - ->indexBy('id') - ->column(); - - $monthsList = []; - for ($i = 0; $i < 12; $i++) { - // получаем метку вида "03-2025" - $ts = strtotime("first day of -{$i} month"); - $key = date('m-Y', $ts); - $monthsList[$key] = $key; - } - - $monthResult = []; - $totals = []; - $weeksData = []; - $weeksShareResult = []; - $weeksGoalResult = []; - $monthCategoryShareResult = []; - $weeksProductForecast = []; - - if ($model->load(Yii::$app->request->post()) && $model->validate()) { - $filters = []; - - list($m, $y) = explode('-', $model->month); - $dateFrom = date("Y-m-d 00:00:00", strtotime(sprintf('%04d-%02d-01', $y, $m))); - $dateTo = date("Y-m-t 23:59:59", strtotime($dateFrom)); - - if ($model->storeId) { - $filters['store_id'] = $model->storeId; - $filters['type'] = $model->type; - $filters['plan_date'] = $dateFrom; - } - - $service = new AutoPlannogrammaService(); - - if ($model->storeId) { - $totals = $service->getStoreTotals( - [$model->storeId], - $dateFrom, - null, - $model->type, - $dateTo - ); - } - - $monthSpeciesGoals = $service->calculateFullGoalChainWeighted($filters); - $monthSpeciesGoalsMap = []; - foreach ($monthSpeciesGoals as $monthSpeciesGoal) { - $monthSpeciesGoalsMap[$monthSpeciesGoal['store_id']] - [$monthSpeciesGoal['category']] - [$monthSpeciesGoal['subcategory']] - [$monthSpeciesGoal['species']] = $monthSpeciesGoal['goal']; - } - - $weeksShareResult = $service->getHistoricalWeeklySpeciesShare($model->month, $filters, null, 'writeOffs'); - $weeksData = $service->calculateWeeklySpeciesGoals($weeksShareResult['weeksData'], $monthSpeciesGoals); - - $datePlan = $filters['plan_date']; - $monthCategoryShare = $service->getMonthCategoryShareOrWriteOffWeighted($datePlan, $filters, null, $filters['type']); - $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $datePlan, $filters['type']); - foreach ($monthCategoryShare as $sid => $cats) { - foreach ($cats as $cat) { - $monthCategoryShareResult[$sid][$cat['category']]['total_sum_cat'] = $cat['total_sum_cat']; - $monthCategoryShareResult[$sid][$cat['category']]['share_of_total'] = $cat['share_of_total']; - } - - } - foreach ($monthCategoryGoal as $cats) { - $monthCategoryShareResult[$cats['store_id']][$cats['category']]['goal'] = $cats['goal']; - - } - - $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOffWeighted($datePlan, $filters, null, $filters['type']); - $monthSubcategoryGoal = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal); - - if ($filters['type'] === 'writeOffs') { - $salesSubShare = $service->getMonthSubcategoryShareOrWriteOffWeighted($datePlan, $filters, null, 'sales'); - $salesSubGoal = $service->getMonthSubcategoryGoal($salesSubShare, $monthCategoryGoal); - - $catGoalMap = []; - foreach ($monthCategoryGoal as $row) { - $catGoalMap[$row['category']] = $row['goal']; - } - $salesSubGoalMap = []; - foreach ($salesSubGoal as $row) { - $salesSubGoalMap[$row['category']][$row['subcategory']] = $row['goal']; - } - - - foreach ($monthSubcategoryShare as &$row) { - $cat = $row['category']; - $sub = $row['subcategory']; - - $writeShare = $row['percent_of_month']; - - $writeGoal = ($catGoalMap[$cat] ?? 0) * $writeShare; - $saleGoal = $salesSubGoalMap[$cat][$sub] ?? 0; - - if ($saleGoal > 0 && $writeGoal > 0.1 * $saleGoal) { - $row['share'] = 0.1; - } - } - unset($row); - $monthSubcategoryGoal = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal); - } - - foreach ($monthSubcategoryShare as $subcat) { - $monthCategoryShareResult[$subcat['store_id']][$subcat['category']][$subcat['subcategory']]['total_sum'] = $subcat['total_sum']; - $monthCategoryShareResult[$subcat['store_id']][$subcat['category']][$subcat['subcategory']]['percent_of_month'] = $subcat['percent_of_month']; - } - foreach ($monthSubcategoryGoal as $cats) { - $monthCategoryShareResult[$cats['store_id']][$cats['category']][$cats['subcategory']]['goal'] = $cats['goal']; - - } - $monthSpeciesShare = $service->getMonthSpeciesShareOrWriteOffWeighted($datePlan, $datePlan, $filters, null, $filters['type']); - $monthSpeciesGoal = $service->getMonthSpeciesGoalDirty($monthSpeciesShare, $monthSubcategoryGoal); - if ($filters['type'] === 'writeOffs') { - $salesSpecShare = $service->getMonthSpeciesShareOrWriteOffWeighted($datePlan, $datePlan, $filters, null, 'sales'); - $salesSpecGoal = $service->getMonthSpeciesGoalDirty($salesSpecShare, $monthSubcategoryGoal); - - $subGoalMap = []; - foreach ($monthSubcategoryGoal as $row) { - $subGoalMap[$row['category']][$row['subcategory']] = $row['goal']; - } - $salesSpecGoalMap = []; - foreach ($salesSpecGoal as $row) { - $salesSpecGoalMap[$row['category']][$row['subcategory']][$row['species']] = $row['goal']; - } - - foreach ($monthSpeciesShare as &$row) { - $cat = $row['category']; - $sub = $row['subcategory']; - $spec = $row['species']; - - $writeShare = $row['percent_of_month']; - $writeGoal = ($subGoalMap[$cat][$sub] ?? 0) * $writeShare; - $saleGoal = $salesSpecGoalMap[$cat][$sub][$spec] ?? 0; - - if ($saleGoal > 0 && $writeGoal > 0.1 * $saleGoal) { - $row['share'] = 0.1; - } - } - unset($row); - - $monthSpeciesGoal = $service->getMonthSpeciesGoalDirty($monthSpeciesShare, $monthSubcategoryGoal); - } - foreach ($monthSpeciesShare as $species) { - $monthCategoryShareResult[$species['store_id']][$species['category']][$species['subcategory']][$species['species']]['total_sum'] = $species['total_sum']; - $monthCategoryShareResult[$species['store_id']][$species['category']][$species['subcategory']][$species['species']]['percent_of_month'] = $species['percent_of_month']; - - } - foreach ($weeksShareResult['weeksData'] as $row) { - $monthCategoryShareResult[$row['store_id']][$row['category']][$row['subcategory']][$row['species']][$row['week']]['sumWeek'] = $row['sumWeek']; - - } - - - foreach ($weeksData as $r) { - $forecasts = $service->calculateWeekForecastSpeciesProducts($r['category'], $r['subcategory'], $r['species'], $r['store_id'], $r['weekly_goal']); - foreach ($forecasts as $forecast) { - $weeksProductForecast[] = [ - 'category' => $forecast['category'] ?? '', - 'subcategory' => $forecast['subcategory'] ?? '', - 'species' => $forecast['species'] ?? '', - 'product_id' => $forecast['product_id'] ?? '', - 'name' => $forecast['name'] ?? '', - 'price' => $forecast['price'] ?? '', - 'goal' => $forecast['goal'] ?? 0, - 'forecast' => $forecast['forecast'] ?? 0, - 'week' => $r['week'], - ]; - } - } - - usort($weeksProductForecast, function ($a, $b) { - foreach (['category', 'subcategory', 'species', 'name', 'week'] as $key) { - $va = $a[$key]; - $vb = $b[$key]; - if ($va < $vb) return -1; - if ($va > $vb) return 1; - } - return 0; - }); - - } - - return $this->render('control-species-old', [ - 'model' => $model, - 'result' => $monthResult, - 'weeksData' => $weeksData, - 'monthCategoryShare' => $monthCategoryShareResult, - 'weeksProductForecast' => $weeksProductForecast, - 'totals' => $totals, - 'storeList' => $storeList, - 'monthsList' => $monthsList, - - ]); - } - public function actionControlSpecies() { @@ -1917,4 +1709,146 @@ class AutoPlannogrammaController extends BaseController } + + /** + * Расчет автопланограммы по одному магазину и рендер GridView + * @param int $store_id + * @param string|null $category + * @param string|null $subcategory + * @param string|null $species + * @param int|null $month + * @param int|null $year + */ + public function actionCalculate( ) { + $request = Yii::$app->request; + $category = $request->get('category',null); + $subcategory = $request->get('subcategory') ?? null; + $species = $request->get('species') ?? null; + $store_id = $request->get('store_id',null) ; + $year = $request->get('year'); + $month = $request->get('month'); + $type = $request->get('type'); + + + $dataProvider = new ArrayDataProvider([ + 'allModels' => [], + 'pagination' => ['pageSize' => 100], + ]); + + + if (!empty($year) && !empty($month)) { + $planDate = sprintf('%04d-%02d-01', $year, $month); + + + $store = CityStore::findOne($store_id); + if (!$store) { + throw new \yii\web\NotFoundHttpException("Store with ID={$store_id} not found."); + } + + $service = new AutoPlannogrammaService(); + + $params = [ + 'month' => $month, + 'year' => $year, + 'type' => AutoPlannogrammaService::TYPE_SALES, + 'store_id' => $store_id, + 'category' => $category, + 'subcategory' => $subcategory, + 'species' => $species, + 'plan_date' => $planDate, + ]; + + try { + $forecast = $service->calculateFullForecastForWeek($params); + //var_dump($forecast);die(); + $writeOffsForecast = $service->getWeeklyProductsWriteoffsForecast($month, $year, $forecast, $store_id); + $salesForecast = $service->getWeeklyBouquetProductsSalesForecast($month, $year, $store_id); + + $existing = Autoplannogramma::find() + ->where(['month' => $month, 'year' => $year, 'store_id' => $store_id, 'week' => array_unique(array_column($forecast, 'week'))]) + ->indexBy(fn($r) => $r->week . '_' . $r->product_id) + ->all(); + + $rows = []; + foreach ($forecast as $item) { + $key = $item['week'] . '_' . $item['product_id']; + $model = $existing[$key] ?? new Autoplannogramma(); + $quantity = (float)($item['forecast_week_pieces'] ?? 0); + $productId = $item['product_id']; + $week = $item['week']; + + + $details = []; + $total = $quantity; + if (!empty($writeOffsForecast[$productId][$week]['writeOffs'])) { + $wo = $writeOffsForecast[$productId][$week]['writeOffs']; + $details['writeOffs']['quantity'] = $wo; + $total += is_array($wo) ? array_sum($wo) : (float)$wo; + } else { + $details['writeOffs']['quantity'] = 0; + } + foreach (['offline', 'online', 'marketplace'] as $type) { + $block = ['share' => 0, 'quantity' => 0, 'groups' => []]; + if (isset($salesForecast[$store_id][$productId][$type]) && is_array($salesForecast[$store_id][$productId][$type])) { + $share = $salesForecast[$store_id][$type]['share'] ?? 0; + $block['share'] = (float)$share; + $block['quantity'] = (float)sprintf('%.2f', round($quantity * $share, 2)); + foreach ($salesForecast[$store_id][$productId][$type] as $k => $v) { + $block['groups'][$k] = (float)$v; + $total += (float)$v; + } + } + $details[$type] = $block; + } + $details['forecast'] = ['quantity' => $quantity]; + $total = (float)sprintf('%.2f', $total); + + $model->setAttributes([ + 'month' => $month, + 'year' => $year, + 'week' => $week, + 'product_id' => $productId, + 'store_id' => $store_id, + 'is_archive' => false, + 'capacity_type' => 1, + 'details' => json_encode($details, JSON_UNESCAPED_UNICODE), + 'calculate' => $quantity, + 'modify' => null, + 'total' => ceil($total), + ], false); + $model->save(); + + + $rows[] = [ + 'week' => $week, + 'product_id' => $productId, + 'calculate' => $model->calculate, + 'total' => $model->total, + 'details' => $model->details, + ]; + } + + } catch (Throwable $e) { + Yii::error($e->getMessage(), __METHOD__); + throw $e; + } + + + $dataProvider = new ArrayDataProvider([ + 'allModels' => $rows, + 'pagination' => ['pageSize' => 50], + 'sort' => ['attributes' => ['week', 'product_id', 'calculate', 'total']], + ]); + } + return $this->render('calculate', [ + 'store' => $store ?? null, + 'month' => $month, + 'year' => $year, + 'category' => $category, + 'subcategory' => $subcategory, + 'species' => $species, + 'dataProvider' => $dataProvider, + ]); + } + } diff --git a/erp24/services/AutoPlannogrammaService.php b/erp24/services/AutoPlannogrammaService.php index 927a24d8..04e286c8 100644 --- a/erp24/services/AutoPlannogrammaService.php +++ b/erp24/services/AutoPlannogrammaService.php @@ -1875,10 +1875,38 @@ class AutoPlannogrammaService foreach ($groupedForecasts as $group) { $meta = $group['meta']; $products = $group['products']; + $query = Products1cNomenclature::find() + ->select('id') + ->where(['category' => $meta['category']]) + ->andWhere(['not in', 'category', ['', 'букет', 'сборка', 'сервис']]) + ->andFilterWhere([ + 'subcategory' => $meta['subcategory'], + 'species' => $meta['species'], + ]); + $allProductIds = $query->column(); + + + foreach ($allProductIds as $pid) { + if (!isset($products[$pid])) { + $products[$pid] = [ + 'product_id' => $pid, + 'forecast_pieces' => 0.0, + 'history_status' => 'No history', // или 'Missing' + ]; + } + } $totalForecast = array_sum(array_column($products, 'forecast_pieces')); if ($totalForecast <= 0) { + foreach ($products as $p) { + $result[] = array_merge($meta, [ + 'product_id' => $p['product_id'], + 'forecast_pieces' => $p['forecast_pieces'], + 'share' => 0.0, + 'history_status' => $p['history_status'], + ]); + } continue; } diff --git a/erp24/services/StorePlanService.php b/erp24/services/StorePlanService.php index 308ebfdc..9d2200e6 100755 --- a/erp24/services/StorePlanService.php +++ b/erp24/services/StorePlanService.php @@ -349,8 +349,8 @@ class StorePlanService ->where(['s.store_id' => $storeId]) ->andWhere(['between', 's.date', $dateStart, $dateEnd]) ->andWhere(['order_id' => ['', '0']]) - //->andWhere(['p1.components' => '']) - ->andWhere(['not in', 'p1c.category', ['', 'букет', 'сборка', 'сервис']]) + ->andWhere(['p1.components' => '']) + ->andWhere(['not in', 'p1c.category', ['', 'сервис']]) ->andFilterWhere(['p1c.category' => $category]) ->andFilterWhere(['p1c.subcategory' => $subcategory]) ->andFilterWhere(['p1c.species' => $species]) @@ -380,6 +380,22 @@ class StorePlanService } } + foreach ($salesHistory as &$history) { + foreach ($periods as $periodKey => $periodData) { + if (!isset($history['data'][$periodKey])) { + $history['data'][$periodKey] = []; + } + + foreach (array_keys($periodData['weeks']) as $weekIndex) { + if (!isset($history['data'][$periodKey][$weekIndex])) { + $history['data'][$periodKey][$weekIndex] = 0; + } + } + ksort($history['data'][$periodKey]); + } + } + unset($history); + return $salesHistory; } @@ -678,25 +694,14 @@ class StorePlanService int $selectedYear, array $medianProductsWithoutHistory ): array { - $accumulator = []; - $prices = []; - $guidToGroup = []; - + $accumulator = []; foreach ($medianProductsWithoutHistory as $guid => $data) { - $q = (float)$data['weightedValue']; - if ($q <= 0) continue; - - $price = self::getPriceForProductAtOffsetMonthWeekly( - $guid, $selectedYear, $selectedMonth, $storeId, 2 - ); - $prices[$guid] = $price; - - $cat = $data['category']; - $sub = $data['subcategory']; - $sp = $data['species']; - $groupKey = implode('|', [$cat,$sub,$sp]); - $guidToGroup[$guid] = $groupKey; + $cat = $data['category']; + $sub = $data['subcategory']; + $sp = $data['species']; + $groupKey = implode('|', [$cat, $sub, $sp]); + $q = (float)$data['weightedValue']; if (!isset($accumulator[$groupKey])) { $accumulator[$groupKey] = [ @@ -710,15 +715,15 @@ class StorePlanService 'forecasts' => [], ]; } - $accumulator[$groupKey]['goal'] += $q * $price; - } - foreach ($medianProductsWithoutHistory as $guid => $qty) { - $groupKey = $guidToGroup[$guid]; - $goal = $accumulator[$groupKey]['goal']; - $price = $prices[$guid] ?? 0.0; - $accumulator[$groupKey]['forecasts'][$guid] = $qty['weightedValue']; + $accumulator[$groupKey]['forecasts'][$guid] = $q; + if ($q > 0) { + $price = self::getPriceForProductAtOffsetMonthWeekly( + $guid, $selectedYear, $selectedMonth, $storeId, 2 + ); + $accumulator[$groupKey]['goal'] += $q * $price; + } } return array_values($accumulator); diff --git a/erp24/views/auto-plannogramma/calculate.php b/erp24/views/auto-plannogramma/calculate.php new file mode 100644 index 00000000..a6b4c399 --- /dev/null +++ b/erp24/views/auto-plannogramma/calculate.php @@ -0,0 +1,117 @@ +getModels(); + +?> +
+ +

title) ?>

+ 'get']); ?> +
+
+ 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('Категория') ?> +
+
+ 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('Подкатегория') ?> +
+
+ 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('Товар') ?> +
+
+ 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('Магазин') ?> +
+
+ field(new \yii\base\DynamicModel(['month' => $filters['month'] ?? '']), 'month')->dropDownList(\yii_app\helpers\DateHelper::MONTH_NUMBER_NAMES, [ + 'prompt' => 'Месяц', + 'name' => 'month', + ])->label('Плановый месяц') ?> +
+ +
+ field(new \yii\base\DynamicModel(['year' => $filters['year'] ?? '']), 'year')->dropDownList(['2025' => 2025, '2026' => 2026], [ + 'prompt' => 'Год', + 'name' => 'year', + ])->label('Плановый год') ?> +
+
+ field(new \yii\base\DynamicModel(['type' => $filters['type'] ?? '']), 'type')->widget(Select2::class, [ + 'data' => [ + 'writeOffs' => 'Списания', + 'sales' => 'Продажи' + ], + 'options' => ['placeholder' => 'Тип', 'name' => 'type'], + 'pluginOptions' => ['allowClear' => true], + ])->label('По дефолту продажи!') ?> +
+
+ 'btn btn-primary']) ?> +
+
+ 'btn btn-default']) ?> +
+
+ + +
+
+ + + $dataProvider, + 'columns' => [ + ['attribute' => 'week', 'label' => 'Неделя'], + ['attribute' => 'product_id', 'label' => 'Product GUID'], + ['attribute' => 'calculate', 'label' => 'Calculate'], + ['attribute' => 'total', 'label' => 'Total'], + [ + 'attribute' => 'details', + 'label' => 'Details', + 'format' => 'raw', + 'value' => function($model) { + return '
' . Html::encode(json_encode($model['details'], JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT)) . '
'; + } + ], + ], + ]); ?> -- 2.39.5