$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 => $species) {
- foreach ($species as $specieInd => $row) {
- $bouquetSpeciesForecast[] = [
- 'store_id' => $store_id,
- 'species' => $specieInd,
- 'goal' => $row
- ];
+ 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
+ ];
+ }
+ }
}
+
}
//var_dump($matrixGroups); die();
$flatData = array_filter($bouquetSpeciesForecast, function ($row) use ($filters) {
'filters' => $filters,
]);
}
+
+
+ public function action9()
+ {
+ $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();
+ $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);
+ $data = $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']);
+ $data = $service->getMonthSpeciesGoalDirty($monthSpeciesWriteOffShare, $monthSubcategoryWriteOffsGoals, $filters['type'], $data);
+ }
+
+ //var_dump($data); die();
+ $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
+ ];
+ }
+ }
+ }
+
+ }
+ //var_dump($bouquetSpeciesForecast); die();
+ $noHistoryProductData = $service->calculateSpeciesForecastForProductsWithoutHistory($filters['plan_date'], $filters);
+ var_dump($noHistoryProductData); die();
+ $cleanedSpeciesGoals = $service->subtractSpeciesGoals($data, $bouquetSpeciesForecast, $noHistoryProductData);
+
+
+ $flatData = array_filter($cleanedSpeciesGoals, 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('9', [
+ 'dataProvider' => $dataProvider,
+ 'filters' => $filters,
+ ]);
+ }
}
return $result;
}
+ public function mapGoalsBySpecies(array $rows): array {
+ $mapped = [];
+ foreach ($rows as $row) {
+ $mapped[$row['store_id']][$row['category']][$row['subcategory']][$row['species']] = $row['goal'];
+ }
+ return $mapped;
+ }
+
+ public function subtractSpeciesGoals(array $data, array $forecast, array $noHistory): array {
+ $forecastMap = $this->mapGoalsBySpecies($forecast);
+ $noHistoryMap = $this->mapGoalsBySpecies($noHistory);
+ $result = [];
+
+ foreach ($data as $row) {
+ $storeId = $row['store_id'];
+ $category = $row['category'];
+ $subcategory = $row['subcategory'];
+ $species = $row['species'];
+ $originalGoal = $row['goal'];
+
+ $forecastGoal = $forecastMap[$storeId][$category][$subcategory][$species] ?? 0;
+ $noHistoryGoal = $noHistoryMap[$storeId][$category][$subcategory][$species] ?? 0;
+
+ $cleanGoal = $originalGoal - $forecastGoal - $noHistoryGoal;
+
+
+ $result[] = [
+ 'store_id' => $storeId,
+ 'category' => $category,
+ 'subcategory' => $subcategory,
+ 'species' => $species,
+ 'goal' => $cleanGoal
+ ];
+ }
+
+ return $result;
+ }
+
+
}
\ No newline at end of file
}
}
$speciesCache = Products1cNomenclature::find()
- ->select(['id', 'species'])
+ ->select(['id', 'species', 'category', 'subcategory'])
->where(['id' => array_unique($allComponentGuids)])
->indexBy('id')->asArray()->all();
foreach ($forecasts as $forecast) {
foreach ($products as $product) {
$guid = $product['product_guid'];
$species = $speciesCache[$guid]['species'] ?? 'Неизвестно';
+ $category = $speciesCache[$guid]['category'] ?? 'Неизвестно';
+ $subcategory = $speciesCache[$guid]['subcategory'] ?? 'Неизвестно';
$price = $priceCache[$regionId][$guid] ?? 0;
$raw = $price * $product['count'] * $typeSalesValue;
$cost = round($raw * BouquetCompositionPrice::SURCHARGE_ASSEMBLY, 2);
- $resultData[$sid][$species][$typeSales] = ($resultData[$sid][$species][$typeSales] ?? 0) + $cost;
+ $resultData[$sid][$category][$subcategory][$species][$typeSales] = ($resultData[$sid][$category][$subcategory][$species][$typeSales] ?? 0) + $cost;
$detailData[$sid][$species][$typeSales][] = [
'product_guid' => $guid,
'price' => $price,
}
$finalResult = [];
- foreach ($resultData as $storeId => $speciesData) {
- foreach ($speciesData as $species => $salesData) {
- $finalResult[$storeId][$species] = round(array_sum($salesData), 2);
+ foreach ($resultData as $storeId => $categoryData) {
+ foreach ($categoryData as $category => $subcategoryData) {
+ foreach ($subcategoryData as $subcategory => $speciesData) {
+ foreach ($speciesData as $species => $salesData) {
+ $finalResult[$storeId][$category][$subcategory][$species] = round(array_sum($salesData), 2);
+ }
+ }
}
+
}
return [
'detail' => $resultData,
--- /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_cleared_goal)") ?></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' => 'goal', 'label' => 'Сумма', 'format' => ['decimal', 2]],
+];
+
+
+?>
+<?= GridView::widget([
+ 'dataProvider' => $dataProvider,
+ 'columns' => $columns,
+]); ?>
+<?php