From: fomichev Date: Thu, 15 May 2025 13:52:57 +0000 (+0300) Subject: Расчет цели выбор магазина X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=d5e64ba8d91091bcba925224dc53bb9447694efe;p=erp24_rep%2Fyii-erp24%2F.git Расчет цели выбор магазина --- diff --git a/erp24/controllers/BouquetController.php b/erp24/controllers/BouquetController.php index 6051e805..a31e736f 100644 --- a/erp24/controllers/BouquetController.php +++ b/erp24/controllers/BouquetController.php @@ -301,7 +301,47 @@ class BouquetController extends Controller 'year' => $year, ]); } + public function actionMonthGoalForecast() + { + $request = Yii::$app->request; + $post = $request->post(); + $month = $post['DynamicModel']['month'] ?? 5; + $year = $post['DynamicModel']['year'] ?? 2025; + + $model = DynamicModel::validateData( + ['month' => $month, 'year' => $year], + [ + [['month', 'year'], 'required'], + ['month', 'integer', 'min' => 1, 'max' => 12], + ['year', 'integer', 'min' => 2000, 'max' => 2100], + ] + ); + + if ($request->isPost && $model->validate()) { + $month = $model->month; + $year = $model->year; + } else { + $model->month = $month; + $model->year = $year; + } + + $result = StorePlanService::getBouquetSpiecesMonthGoalFromForecast($month, $year, 2); +//var_dump($result); die(); + $stores = CityStore::find() + ->select(['id', 'name']) + ->where(['visible' => CityStore::IS_VISIBLE]) + ->asArray() + ->all(); + $storesMap = ArrayHelper::map($stores, 'id', 'name'); + return $this->render('month-goal-forecast', [ + 'model' => $model, // передаём динамическую модель + 'result' => $result, + 'storesMap' => $storesMap, + 'month' => $month, + 'year' => $year, + ]); + } public function actionGetGuidBouquets() { $model = new DynamicModel(['excelFile']); diff --git a/erp24/services/StorePlanService.php b/erp24/services/StorePlanService.php index 97b8ddcc..650f13d1 100755 --- a/erp24/services/StorePlanService.php +++ b/erp24/services/StorePlanService.php @@ -15,6 +15,7 @@ use yii_app\records\CityStoreParams; use yii_app\records\MatrixBouquetForecast; use yii_app\records\Motivation; use yii_app\records\PricesDynamic; +use yii_app\records\Products1c; use yii_app\records\Products1cAdditionalCharacteristics; use yii_app\records\Products1cNomenclature; use yii_app\records\Sales; @@ -910,22 +911,27 @@ class StorePlanService } - public static function getBouquetSpiecesMonthGoalFromForecast($month, $year) + public static function getBouquetSpiecesMonthGoalFromForecast($month, $year, $storeId = null) { - $stores = ArrayHelper::map( - CityStore::find() - ->select(['id']) - ->where(['visible' => CityStore::IS_VISIBLE]) - ->asArray() - ->all(), - 'id', - 'id' - ); + $stores = []; + if (!empty($storeId)) { + $stores[] = $storeId; + } else { + $stores = ArrayHelper::getColumn( + CityStore::find() + ->select(['id']) + ->where(['visible' => CityStore::IS_VISIBLE]) + ->asArray() + ->all(), + 'id' + ); + } + // var_dump($stores); die(); $storesParams = ArrayHelper::map( CityStoreParams::find() ->select(['store_id', 'address_region']) - ->where(['store_id' => array_keys($stores)]) + ->where(['store_id' => $stores]) ->andWhere(['not', ['address_region' => '']]) ->asArray() ->indexBy('store_id') @@ -934,13 +940,12 @@ class StorePlanService 'address_region' ); - // Все прогнозы на месяц $forecasts = MatrixBouquetForecast::find() ->where(['year' => $year, 'month' => $month]) ->andWhere(['not', ['bouquet_id' => null]]) ->asArray() ->all(); - + // var_dump($forecasts); die(); $resultData = []; $debugData = []; @@ -973,7 +978,7 @@ class StorePlanService 'l_store' => 'offline', 'xl_store' => 'offline', 'marketplace' => 'marketplace', - 'internet' => 'internet' + 'internet' => 'online' ]; foreach ($types as $field => $typeSales) { diff --git a/erp24/views/bouquet/month-goal-forecast.php b/erp24/views/bouquet/month-goal-forecast.php new file mode 100644 index 00000000..c9b91dc4 --- /dev/null +++ b/erp24/views/bouquet/month-goal-forecast.php @@ -0,0 +1,291 @@ + 'Оффлайн', + 2 => 'Интернет магазины', + 3 => 'Маркетплейсы', +]; + +?> +
+

Цели букета на месяц: /

+ +
+ + Url::to(['bouquet/month-goal']), + 'method' => 'post', + ]); ?> + + field($model, 'month')->input('number')->label('Месяц') ?> + field($model, 'year')->input('number')->label('Год') ?> + +
+ 'btn btn-primary']) ?> +
+ + +
+ +
+ +

Финальные суммы по магазинам

+ + $speciesData): ?> +

Магазин:

+ new ArrayDataProvider([ + 'allModels' => array_map(fn($species, $sum) => [ + 'species' => $species, + 'sum' => $sum, + ], array_keys($speciesData), $speciesData), + 'pagination' => false, + ]), + 'columns' => [ + ['attribute' => 'species', 'label' => 'Вид продукции'], + ['attribute' => 'sum', 'label' => 'Сумма'], + ], + ]) ?> + + +

Нет данных.

+ + +
+ +

Детальный расчёт по магазинам

+ + $speciesData): ?> +

Магазин:

+ new ArrayDataProvider([ + 'allModels' => array_map(function ($species, $salesTypes) use ($saleTypesLabels) { + $sum = array_sum($salesTypes); + return [ + 'species' => $species, + 'offline' => $salesTypes[1] ?? 0, + 'online' => $salesTypes[2] ?? 0, + 'marketplace' => $salesTypes[3] ?? 0, + 'sum' => $sum, + ]; + }, array_keys($speciesData), $speciesData), + 'pagination' => false, + ]), + 'columns' => [ + ['attribute' => 'species', 'label' => 'Вид продукции'], + ['attribute' => 'offline', 'label' => 'Оффлайн'], + ['attribute' => 'online', 'label' => 'Интернет'], + ['attribute' => 'marketplace', 'label' => 'Маркетплейсы'], + ['attribute' => 'sum', 'label' => 'Итого'], + ], + ]) ?> + + +

Нет данных.

+ + +
+ +

Детальный разбор по магазинам

+ + $speciesData): ?> +

Магазин:

+ $saleTypes): ?> +

Вид продукции:

+ $entries): ?> +
Тип продаж:
+ new ArrayDataProvider([ + 'allModels' => $entries, + 'pagination' => false, + ]), + 'columns' => [ + ['attribute' => 'product_guid', + 'value' => function ($model, $key, $index, $widget) { + return \yii_app\records\Products1c::find()->where(['id' => $model['product_guid']])->one()->name . + " (" . $model['product_guid'] . ")"; + }, + 'label' => 'Product GUID'], + ['attribute' => 'bouquet_id', + 'value' => function ($model, $key, $index, $widget) { + return \yii_app\records\MatrixBouquetForecast::find()->where(['bouquet_id' => $model['bouquet_id']])->one()->bouquet_name; + }, + 'label' => 'Букет'], + ['attribute' => 'price', 'label' => 'Цена'], + ['attribute' => 'count', 'label' => 'Кол-во'], + ['attribute' => 'forecast', 'label' => 'Прогноз'], + ['attribute' => 'raw_calculation', 'label' => 'Базовый расчёт'], + ['attribute' => 'rounded', 'label' => 'С наценкой за сборку'], + ], +// 'export' => [ +// 'fontAwesome' => true +// ], +// 'exportConfig' => [ +// 'html' => [], +// 'csv' => [ +// 'label' => Yii::t('kvgrid', 'CSV'), +// 'icon' => '', +// 'iconOptions' => ['class' => 'text-primary'], +// 'showHeader' => true, +// 'showPageSummary' => true, +// 'showFooter' => true, +// 'showCaption' => true, +// 'filename' => Yii::t('kvgrid', 'grid-export'), +// 'alertMsg' => Yii::t('kvgrid', 'The CSV export file will be generated for download.'), +// 'options' => ['title' => Yii::t('kvgrid', 'Comma Separated Values')], +// 'mime' => 'application/csv', +// 'config' => [ +// 'colDelimiter' => ",", +// 'rowDelimiter' => "\r\n", +// ], +// ], +// 'txt' => [], +// 'xls' => [], +// 'pdf' => [], +// 'json' => [], +// ], +// 'panel' => [ +// 'after' => '', +// 'heading' => Html::encode($storesMap[$storeId] ?? $storeId) , +// 'type' => 'primary', +// 'before' => '', +// ], + ]) ?> + + + + +

Нет данных.

+ + + +

Детальный разбор по всем магазинам

+ $speciesData) { + foreach ($speciesData as $species => $saleTypes) { + foreach ($saleTypes as $saleType => $entries) { + foreach ($entries as $entry) { + $entry['month'] = $month; + $entry['year'] = $year; + $entry['store_id'] = $storeId; + $entry['store_name'] = isset($storesMap[$storeId]) ? $storesMap[$storeId] : $storeId; + $entry['species'] = $species; + $entry['sale_type'] = $saleType; + $entry['sale_type_label']= isset($saleTypesLabels[$saleType]) ? $saleTypesLabels[$saleType] : $saleType; + $flattenedDebug[] = $entry; + } + } + } + } + } + $debugProvider = new ArrayDataProvider([ + 'allModels' => $flattenedDebug, + 'pagination' => false, + ]); + $gridColumns = [ + ['attribute' => 'month', 'label' => 'Месяц'], + ['attribute' => 'year', 'label' => 'Год'], + ['attribute' => 'store_name', 'label' => 'Магазин'], + ['attribute' => 'species', 'label' => 'Вид продукции'], + ['attribute' => 'sale_type_label', 'label' => 'Тип продаж'], + [ + 'attribute' => 'product_guid', + 'label' => 'Product GUID', + 'value' => function ($model, $key, $index, $widget) { + $product = \yii_app\records\Products1c::find()->where(['id' => $model['product_guid']])->one(); + return $product ? $product->name . " (" . $model['product_guid'] . ")" : $model['product_guid']; + } + ], + [ + 'attribute' => 'bouquet_id', + 'label' => 'Букет', + 'value' => function ($model, $key, $index, $widget) { + $bouquet = \yii_app\records\MatrixBouquetForecast::find()->where(['bouquet_id' => $model['bouquet_id']])->one(); + return $bouquet ? $bouquet->bouquet_name : $model['bouquet_id']; + } + ], + ['attribute' => 'price', 'label' => 'Цена'], + ['attribute' => 'count', 'label' => 'Кол-во'], + ['attribute' => 'forecast', 'label' => 'Прогноз'], + ['attribute' => 'raw_calculation', 'label' => 'Базовый расчёт'], + ['attribute' => 'rounded', 'label' => 'С наценкой за сборку'], + ]; + $exportMenu = ExportMenu::widget([ + 'dataProvider' => $debugProvider, + 'columns' => $gridColumns, + 'exportConfig' => [ + ExportMenu::FORMAT_EXCEL => [ + 'label' => 'Excel', + 'options' => ['title' => 'Сохранить в Excel'], + ], + ExportMenu::FORMAT_TEXT => false, + ExportMenu::FORMAT_HTML => false, + ExportMenu::FORMAT_CSV => false, + ExportMenu::FORMAT_PDF => false, + + ], + 'filename' => 'export_' . date('Y-m-d'), + 'showColumnSelector' => false, + 'showConfirmAlert' => false, + 'target' => ExportMenu::TARGET_SELF, + 'dropdownOptions' => [ + 'label' => 'Экспорт данных', + ], + ]); + echo $exportMenu; + echo GridView::widget([ + 'dataProvider' => $debugProvider, + 'columns' => $gridColumns, +// 'exportConfig' => [ +// GridView::CSV => [ +// 'label' => 'CSV', +// 'icon' => 'glyphicon glyphicon-download', +// 'iconOptions' => ['class' => 'text-primary'], +// 'showHeader' => true, +// 'showPageSummary' => false, +// 'showFooter' => false, +// 'filename' => 'debug-export-' . date('Y-m-d_H-i-s'), +// 'alertMsg' => 'CSV файл будет загружен в ближайшее время.', +// 'options' => ['title' => 'CSV'], +// 'mime' => 'application/csv', +// 'config' => [ +// 'colDelimiter' => ",", +// 'rowDelimiter' => "\r\n", +// ], +// ], +// // Другие типы экспорта можно отключить, если не нужны: +// GridView::HTML => false, +// GridView::TEXT => false, +// GridView::EXCEL => false, +// GridView::PDF => false, +// GridView::JSON => false, +// ], +// 'toolbar' => [ +// '{export}', +// '{toggleData}', +// ], +// 'panel' => [ +// 'heading' => 'Детальный разбор (Debug) по всем магазинам', +// 'type' => GridView::TYPE_PRIMARY, +// ], + ]); + + ?> + +