From: fomichev Date: Wed, 16 Apr 2025 09:33:50 +0000 (+0300) Subject: Вывод расчетов X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=c1b8dcc63aaf3579f96ec072a2f03880567a5c3d;p=erp24_rep%2Fyii-erp24%2F.git Вывод расчетов --- diff --git a/erp24/controllers/BouquetController.php b/erp24/controllers/BouquetController.php index 6adf096b..73e366ea 100644 --- a/erp24/controllers/BouquetController.php +++ b/erp24/controllers/BouquetController.php @@ -4,6 +4,7 @@ namespace app\controllers; use Exception; use Yii; +use yii\base\DynamicModel; use yii\db\Expression; use yii\filters\AccessControl; use yii\helpers\ArrayHelper; @@ -257,8 +258,25 @@ class BouquetController extends Controller { $request = Yii::$app->request; - $month = $request->post('month') ? (int)$request->post('month') : 5; - $year = $request->post('year') ? (int)$request->post('year') : 2025; + $month = $request->post('month', 5); + $year = $request->post('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::getBouquetSpiecesMonthGoal($month, $year); @@ -270,6 +288,7 @@ class BouquetController extends Controller $storesMap = ArrayHelper::map($stores, 'id', 'name'); return $this->render('month-goal', [ + 'model' => $model, // передаём динамическую модель 'result' => $result, 'storesMap' => $storesMap, 'month' => $month, diff --git a/erp24/services/StorePlanService.php b/erp24/services/StorePlanService.php index 4137efd3..4a4c9fb0 100755 --- a/erp24/services/StorePlanService.php +++ b/erp24/services/StorePlanService.php @@ -803,110 +803,111 @@ class StorePlanService } - public static function getBouquetSpiecesMonthGoal($month, $year) { - $stores = ArrayHelper::map(CityStore::find()->select(['id'])->where(['visible' => CityStore::IS_VISIBLE])->asArray()->all(), 'id', 'id'); - $storesParams = ArrayHelper::map(CityStoreParams::find() - ->select(['store_id', 'address_region']) - ->where(['store_id' => array_keys($stores)]) - ->andWhere(['not', ['address_region' => '']]) - ->asArray() - ->indexBy('store_id') - ->all(), 'store_id', 'address_region'); + public static function getBouquetSpiecesMonthGoal($month, $year) + { + $stores = ArrayHelper::map( + CityStore::find() + ->select(['id']) + ->where(['visible' => CityStore::IS_VISIBLE]) + ->asArray() + ->all(), + 'id', + 'id' + ); + $storesParams = ArrayHelper::map( + CityStoreParams::find() + ->select(['store_id', 'address_region']) + ->where(['store_id' => array_keys($stores)]) + ->andWhere(['not', ['address_region' => '']]) + ->asArray() + ->indexBy('store_id') + ->all(), + 'store_id', + 'address_region' + ); $matrixTypesIds = StorePlanService::getActiveMatrixTypes(); - $storesForecasts = []; - // получаем букеты из матрицы + if ($matrixTypesIds) { foreach ($matrixTypesIds as $matrixTypeId) { $bouquetsArray = StorePlanService::getBouqetsByDate($month, $year, $matrixTypeId); - $forecasts = ArrayHelper::getColumn($bouquetsArray , 'bouquetForecast'); + $forecasts = ArrayHelper::getColumn($bouquetsArray, 'bouquetForecast'); foreach ($forecasts as $forecastArray) { if (is_array($forecastArray)) { foreach ($forecastArray as $fc) { $bouquetPrice = 0; - if(isset($storesParams[$fc["type_sales_id"]])){ - $bouquetPrice = BouquetCompositionPrice::find() + if (isset($storesParams[$fc["type_sales_id"]])) { + $priceModel = BouquetCompositionPrice::find() ->where(['bouquet_id' => $fc['bouquet_id']]) - ->andWhere(['region_id' => $storesParams[$fc["type_sales_id"]]])->one()->price; + ->andWhere(['region_id' => $storesParams[$fc["type_sales_id"]]]) + ->one(); + if ($priceModel !== null) { + $bouquetPrice = $priceModel->price; + } } - - $storesForecasts[] = array_merge($fc, ['matrixTypeId' => $matrixTypeId], ['price' => $bouquetPrice] ); - + $storesForecasts[] = array_merge($fc, [ + 'matrixTypeId' => $matrixTypeId, + 'price' => $bouquetPrice + ]); } } } } } - $resultArr = []; + + $resultData = []; + $debugData = []; + //var_dump($storesParams);die(); foreach ($storesForecasts as $storeForecast) { $products = ArrayHelper::toArray(BouquetCompositionProducts::getCompositionProducts($storeForecast['bouquet_id'])); $productGuids = array_filter(array_column($products, 'product_guid')); - $pricesData = ArrayHelper::map(PricesDynamic::find() - ->where(['product_id' => $productGuids]) - ->andWhere(['active' => 1]) - ->andWhere(['region_id' => $storesParams[$fc["type_sales_id"]]]) - ->select(['price', 'product_id'])->asArray()->all(), 'product_id', 'price') ; - // var_dump($products); die(); + $pricesData = ArrayHelper::map( + PricesDynamic::find() + ->where(['product_id' => $productGuids]) + ->andWhere(['active' => 1]) + ->andWhere(['region_id' => $storesParams[$storeForecast["type_sales_id"]]]) + ->select(['price', 'product_id']) + ->asArray() + ->all(), + 'product_id', + 'price' + ); foreach ($products as $product) { - $species = Products1cNomenclature::find()->where(['id' => $product['product_guid']])->one()->species; - $productCost = round($pricesData[$product['product_guid']] * $product['count'] * 1.15, 2); - if (!isset($resultArr[$storeForecast["type_sales_id"]][$species][$storeForecast["type_sales"]])) { - $resultArr[$storeForecast["type_sales_id"]][$species][$storeForecast["type_sales"]] = 0; + $productModel = Products1cNomenclature::find()->where(['id' => $product['product_guid']])->one(); + $species = ($productModel !== null) ? $productModel->species : 'Неизвестно'; + $basePrice = isset($pricesData[$product['product_guid']]) ? $pricesData[$product['product_guid']] : 0; + $rawCalculation = $basePrice * $product['count'] * $storeForecast["type_sales_value"]; + $productCost = round($rawCalculation * 1.15, 2); + + if (!isset($resultData[$storeForecast["type_sales_id"]][$species][$storeForecast["type_sales"]])) { + $resultData[$storeForecast["type_sales_id"]][$species][$storeForecast["type_sales"]] = 0; } - $resultArr[$storeForecast["type_sales_id"]][$species][$storeForecast["type_sales"]] += $productCost; - + $resultData[$storeForecast["type_sales_id"]][$species][$storeForecast["type_sales"]] += $productCost; + + $debugData[$storeForecast["type_sales_id"]][$species][$storeForecast["type_sales"]][] = [ + 'product_guid' => $product['product_guid'], + 'price' => $basePrice, + 'count' => $product['count'], + 'forecast' => $storeForecast["type_sales_value"], + 'bouquet_id' => $storeForecast["bouquet_id"], + 'raw_calculation' => $rawCalculation, + 'rounded' => $productCost, + ]; } - } + $finalResult = []; - foreach ($resultArr as $typeSalesId => $speciesData) { + foreach ($resultData as $typeSalesId => $speciesData) { foreach ($speciesData as $species => $salesDetails) { $finalResult[$typeSalesId][$species] = round(array_sum($salesDetails), 2); } } - return ['detail' => $resultArr, 'final' => $finalResult]; - - - + return ['detail' => $resultData, 'final' => $finalResult, 'debug' => $debugData]; } - public static function getBouquetGoal($bouquet) { - $onlineStores = BouquetForecast::getStoresList( - $bouquet['id'], - BouquetForecast::ONLINE_STORES, - CityStore::class, - ['visible' => CityStore::IS_VISIBLE], - $bouquet['forecast_month'], - $bouquet['forecast_year'] - ); - $marketplaceStores = BouquetForecast::getStoresList( - $bouquet['id'], - BouquetForecast::MARKETPLACE, - CityStore::class, - ['visible' => CityStore::IS_VISIBLE], - $bouquet['forecast_month'], - $bouquet['forecast_year'] - ); - $offlineStores = BouquetForecast::getStoresList( - $bouquet['id'], - BouquetForecast::OFFLINE_STORES, - StoreType::class, - [], - $bouquet['forecast_month'], - $bouquet['forecast_year'] - ); - return [ - 'onlineStores' => $onlineStores, - 'marketplaceStores' => $marketplaceStores, - 'offlineStores' => $offlineStores, - - ]; -} - - } diff --git a/erp24/views/bouquet/month-goal.php b/erp24/views/bouquet/month-goal.php index 29a07842..b37b5895 100644 --- a/erp24/views/bouquet/month-goal.php +++ b/erp24/views/bouquet/month-goal.php @@ -1,94 +1,139 @@ store_name] -@var $month integer -@var $year integer - */ +$saleTypesLabels = [ + 1 => 'Оффлайн', + 2 => 'Интернет магазины', + 3 => 'Маркетплейсы', +]; ?> -

Цели на месяц: /

- - - - - 1, 'max' => 12]) ?> - - - 2000, 'max' => 2100]) ?> - - 'btn btn-primary']) ?> - - -
- - -

Итоговые суммы по магазинам и видам продукции

- - - - - - - - - - - $speciesData): ?> - - $sum): ?> - - - - - - - - - - - - - -
МагазинВид продукцииСумма
Нет данных для отображения.
- - -

Подробный расчёт по магазинам

- - - - - - - - - - - - $speciesData): ?> - - $saleTypes): ?> - $amount): ?> - - - - - - - +
+

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

+ +
+ + Url::to(['your-controller/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; + }, + 'label' => 'Product GUID'], + ['attribute' => 'bouquet_id', + 'value' => function ($model, $key, $index, $widget) { + return \yii_app\records\BouquetComposition::find()->where(['id' => $model['bouquet_id']])->one()->name; + }, + 'label' => 'Букет'], + ['attribute' => 'price', 'label' => 'Цена'], + ['attribute' => 'count', 'label' => 'Кол-во'], + ['attribute' => 'forecast', 'label' => 'Прогноз'], + ['attribute' => 'raw_calculation', 'label' => 'Базовый расчёт'], + ['attribute' => 'rounded', 'label' => 'С наценкой за сборку'], + ], + ]) ?> - -
- - - - -
МагазинВид продукцииТип продажСумма
Нет данных для отображения.
\ No newline at end of file + + +

Нет данных.

+ + +