From c3a6a608b14dd7cf37da5ab5793b2c129b9cb377 Mon Sep 17 00:00:00 2001 From: fomichev Date: Fri, 16 May 2025 13:07:59 +0300 Subject: [PATCH] =?utf8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?utf8?q?=D0=B8=D0=B5=20=D1=82=D0=B8=D0=BF=D0=BE=D0=B2=20=D0=BC=D0=B0?= =?utf8?q?=D1=82=D1=80=D0=B8=D1=86=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- erp24/controllers/BouquetController.php | 22 +- ...5_create_matrix_bouquet_forecast_table.php | 6 +- erp24/records/MatrixBouquetForecast.php | 16 +- erp24/services/StorePlanService.php | 218 ++++++++++-------- erp24/views/bouquet/get-guid-bouquet.php | 6 +- erp24/views/bouquet/month-goal-forecast.php | 23 +- 6 files changed, 165 insertions(+), 126 deletions(-) diff --git a/erp24/controllers/BouquetController.php b/erp24/controllers/BouquetController.php index d7694441..79d38467 100644 --- a/erp24/controllers/BouquetController.php +++ b/erp24/controllers/BouquetController.php @@ -308,10 +308,12 @@ class BouquetController extends Controller $month = $post['DynamicModel']['month'] ?? 5; $year = $post['DynamicModel']['year'] ?? 2025; $storeId = $post['DynamicModel']['storeId'] ?? 2; + $matrix = $post['DynamicModel']['matrix'] ?? []; $model = DynamicModel::validateData( - ['month' => $month, 'year' => $year, 'storeId' => $storeId], + ['month' => $month, 'year' => $year, 'storeId' => $storeId, 'matrix' => $matrix], [ + ['matrix', 'each', 'rule' => ['string']], [['month', 'year', 'storeId'], 'required'], ['month', 'integer', 'min' => 1, 'max' => 12], ['storeId', 'integer', 'min' => 1, 'max' => 100], @@ -329,7 +331,7 @@ class BouquetController extends Controller $model->storeId = $storeId; } - $result = StorePlanService::getBouquetSpiecesMonthGoalFromForecast($month, $year, $storeId); + $result = StorePlanService::getBouquetSpiecesMonthGoalFromForecast($month, $year, $storeId, $matrix); //var_dump($result); die(); $stores = CityStore::find() ->select(['id', 'name']) @@ -337,6 +339,11 @@ class BouquetController extends Controller ->asArray() ->all(); $storesMap = ArrayHelper::map($stores, 'id', 'name'); + $matrixGroups = ArrayHelper::map( + MatrixBouquetForecast::find()->select(['group'])->distinct()->asArray()->all(), + 'group', + 'group' + ); return $this->render('month-goal-forecast', [ 'model' => $model, // передаём динамическую модель @@ -344,6 +351,7 @@ class BouquetController extends Controller 'storesMap' => $storesMap, 'month' => $month, 'year' => $year, + 'matrixGroups' => $matrixGroups, ]); } public function actionGetGuidBouquets() @@ -379,8 +387,8 @@ class BouquetController extends Controller $forecast = MatrixBouquetForecast::find() ->where([ - 'bouquet_name' => $name, - 'bouquet_group' => $group, + 'name' => $name, + 'group' => $group, 'year' => $year, 'month' => $month, ]) @@ -403,15 +411,15 @@ class BouquetController extends Controller } } else { $forecast = new MatrixBouquetForecast(); - $forecast->bouquet_name = $name; - $forecast->bouquet_group = $group; + $forecast->name = $name; + $forecast->group = $group; $forecast->year = $year; $forecast->month = $month; $forecast->created_at = date('Y-m-d H:i:s'); $forecast->updated_at = date('Y-m-d H:i:s'); $product = Products1c::find()->select(['id'])->where(['name' => $name])->one(); - $forecast->bouquet_id = $product ? $product->id : null; + $forecast->guid = $product ? $product->id : null; foreach ($newValues as $field => $value) { $forecast->$field = $value; diff --git a/erp24/migrations/m250514_143555_create_matrix_bouquet_forecast_table.php b/erp24/migrations/m250514_143555_create_matrix_bouquet_forecast_table.php index e730e398..0251e7f5 100644 --- a/erp24/migrations/m250514_143555_create_matrix_bouquet_forecast_table.php +++ b/erp24/migrations/m250514_143555_create_matrix_bouquet_forecast_table.php @@ -18,9 +18,9 @@ class m250514_143555_create_matrix_bouquet_forecast_table extends Migration if (!isset($tableSchema)) { $this->createTable(self::TABLE_NAME, [ 'id' => $this->primaryKey(), - 'bouquet_id' => $this->string()->comment('ИД букета'), - 'bouquet_name' => $this->string()->comment('Наименование букета'), - 'bouquet_group' => $this->string()->comment('Матрица букета'), + 'guid' => $this->string()->comment('ИД букета'), + 'name' => $this->string()->comment('Наименование букета'), + 'group' => $this->string()->comment('Матрица букета'), 'year' => $this->integer()->comment('Год'), 'month' => $this->integer()->comment('Месяц'), 's_store' => $this->integer()->comment('Прогноз для оффлайн магазинов типа s'), diff --git a/erp24/records/MatrixBouquetForecast.php b/erp24/records/MatrixBouquetForecast.php index 9ab692ed..12669faf 100644 --- a/erp24/records/MatrixBouquetForecast.php +++ b/erp24/records/MatrixBouquetForecast.php @@ -8,9 +8,9 @@ use Yii; * This is the model class for table "matrix_bouquet_forecast". * * @property int $id - * @property string|null $bouquet_id ИД букета - * @property string|null $bouquet_name Наименование букета - * @property string|null $bouquet_group Матрица букета + * @property string|null $guid ИД букета + * @property string|null $name Наименование букета + * @property string|null $group Матрица букета * @property int|null $year Год * @property int|null $month Месяц * @property int|null $s_store Прогноз для оффлайн магазинов типа s @@ -40,11 +40,11 @@ class MatrixBouquetForecast extends \yii\db\ActiveRecord public function rules() { return [ - [['bouquet_id', 'bouquet_name', 'bouquet_group', 'year', 'month', 's_store', 'm_store', 'l_store', 'xl_store', 'marketplace', 'internet', 'created_at', 'updated_at'], 'default', 'value' => null], + [['guid', 'name', 'group', 'year', 'month', 's_store', 'm_store', 'l_store', 'xl_store', 'marketplace', 'internet', 'created_at', 'updated_at'], 'default', 'value' => null], [['year', 'month', 's_store', 'm_store', 'l_store', 'xl_store', 'marketplace', 'internet'], 'default', 'value' => null], [['year', 'month', 's_store', 'm_store', 'l_store', 'xl_store', 'marketplace', 'internet'], 'integer'], [['created_at', 'updated_at'], 'safe'], - [['bouquet_id', 'bouquet_name', 'bouquet_group'], 'string', 'max' => 255], + [['guid', 'name', 'group'], 'string', 'max' => 255], ]; } @@ -55,9 +55,9 @@ class MatrixBouquetForecast extends \yii\db\ActiveRecord { return [ 'id' => 'ID', - 'bouquet_id' => 'Bouquet ID', - 'bouquet_name' => 'Bouquet Name', - 'bouquet_group' => 'Bouquet Group', + 'guid' => 'Guid', + 'name' => 'Name', + 'group' => 'Group', 'year' => 'Year', 'month' => 'Month', 's_store' => 'S Store', diff --git a/erp24/services/StorePlanService.php b/erp24/services/StorePlanService.php index a5664825..4dcb214b 100755 --- a/erp24/services/StorePlanService.php +++ b/erp24/services/StorePlanService.php @@ -911,10 +911,10 @@ class StorePlanService } - public static function getBouquetSpiecesMonthGoalFromForecast($month, $year, $storeId = null) + public static function getBouquetSpiecesMonthGoalFromForecast($month, $year, $storeId = null, $matrixGroups = []) { $stores = []; - + $forecasts = []; if (!empty($storeId)) { $stores[] = $storeId; } else { @@ -927,120 +927,138 @@ class StorePlanService 'id' ); } - // var_dump($stores); die(); - $storesParams = CityStoreParams::find() - ->select(['store_id', 'address_region', 'store_type']) - ->where(['store_id' => $stores]) - ->andWhere(['not', ['address_region' => '']]) - ->asArray() - ->indexBy('store_id') - ->all(); + $types = [ + 's_store' => 'offline', + 'm_store' => 'offline', + 'l_store' => 'offline', + 'xl_store' => 'offline', + 'marketplace' => 'marketplace', + 'internet' => 'online' + ]; + + $storeSizeTypes = [ + 1 => 's_store', + 2 => 'm_store', + 3 => 'l_store', + 4 => 'xl_store', - $forecasts = MatrixBouquetForecast::find() - ->where(['year' => $year, 'month' => $month]) - ->andWhere(['not', ['bouquet_id' => null]]) + ]; + // var_dump($stores); die(); + $storesParams = CityStoreParams::find() + ->select(['store_id', 'address_region', 'store_type']) + ->where(['store_id' => $stores]) + ->andWhere(['not', ['address_region' => '']]) ->asArray() + ->indexBy('store_id') ->all(); - // var_dump($forecasts); die(); + $resultData = []; $debugData = []; + if (!empty($matrixGroups)) { + foreach ($matrixGroups as $matrixGroup) { + $forecasts = MatrixBouquetForecast::find() + ->where(['year' => $year, 'month' => $month]) + ->andWhere(['not', ['guid' => null]]) + ->andWhere(['group' => $matrixGroup]) + ->asArray() + ->all(); + foreach ($forecasts as $forecast) { + $products = []; + + $product = Products1c::find() + ->select(['components']) + ->where(['id' => $forecast['guid']]) + ->asArray() + ->one(); + + if ($product && !empty($product['components'])) { + $components = json_decode($product['components'], true); + if (is_array($components)) { + foreach ($components as $productId => $count) { + $products[] = [ + 'product_guid' => $productId, + 'count' => (float)$count, + ]; + } + } + } - foreach ($forecasts as $forecast) { - $products = []; + $productGuids = array_filter(array_column($products, 'product_guid')); - $product = Products1c::find() - ->select(['components']) - ->where(['id' => $forecast['bouquet_id']]) - ->asArray() - ->one(); - - if ($product && !empty($product['components'])) { - $components = json_decode($product['components'], true); - if (is_array($components)) { - foreach ($components as $productId => $count) { - $products[] = [ - 'product_guid' => $productId, - 'count' => (float)$count, - ]; - } - } - } - $productGuids = array_filter(array_column($products, 'product_guid')); - $types = [ - 's_store' => 'offline', - 'm_store' => 'offline', - 'l_store' => 'offline', - 'xl_store' => 'offline', - 'marketplace' => 'marketplace', - 'internet' => 'online' - ]; - $storeSizeTypes = [ - 1 => 's_store', - 2 => 'm_store', - 3 => 'l_store', - 4 => 'xl_store', - ]; + foreach ($storesParams as $storeId => $params) { + // var_dump($storesParams);die(); + foreach ($types as $field => $typeSales) { - foreach ($types as $field => $typeSales) { - - $typeSalesValue = (int)$forecast[$field]; - if ($typeSalesValue <= 0) { - continue; - } + $typeSalesValue = (int)$forecast[$field]; + if ($typeSalesValue <= 0) { + continue; + } + } + $regionId = $params['address_region']; + if (!$regionId) { + if (CityStore::find()->where(['id' => $storeId])->one()->city_id == 1342) { + $regionId = 52; + } elseif (CityStore::find()->where(['id' => $storeId])->one()->city_id == 1) { + $regionId = 77; + } else { + $regionId = 52; + } + } - foreach ($storesParams as $storeId => $params) { - $regionId = $params['region_id']; - if (!$regionId) { - if (CityStore::find()->where(['id' => $storeId])->one()->city_id == 1342) { - $regionId = 52; - } elseif (CityStore::find()->where(['id' => $storeId])->one()->city_id == 1) { - $regionId = 77; - } else { - $regionId = null; + $pricesData = ArrayHelper::map( + PricesDynamic::find() + ->where(['product_id' => $productGuids]) + ->andWhere(['active' => 1]) + ->andWhere(['region_id' => $regionId]) + ->select(['price', 'product_id']) + ->asArray() + ->all(), + 'product_id', + 'price' + ); + + foreach ($products as $product) { + $productModel = Products1cNomenclature::findOne($product['product_guid']); + $species = $productModel?->species ?? 'Неизвестно'; + $basePrice = $pricesData[$product['product_guid']] ?? 0; + $rawCalculation = $basePrice * $product['count'] * $typeSalesValue; + $productCost = round($rawCalculation * 1.15, 2); + + if (!isset($resultData[$storeId][$species][$typeSales])) { + $resultData[$storeId][$species][$typeSales] = 0; + } + $resultData[$storeId][$species][$typeSales] += $productCost; + + $debugData[$storeId][$species][$typeSales][] = [ + 'product_guid' => $product['product_guid'], + 'price' => $basePrice, + 'count' => $product['count'], + 'forecast' => $typeSalesValue, + 'guid' => $forecast['guid'], + 'raw_calculation' => $rawCalculation, + 'rounded' => $productCost, + ]; + } } - } - $pricesData = ArrayHelper::map( - PricesDynamic::find() - ->where(['product_id' => $productGuids]) - ->andWhere(['active' => 1]) - ->andWhere(['or', ['region_id' => $regionId], ['region_id' => null]]) - ->select(['price', 'product_id']) - ->asArray() - ->all(), - 'product_id', - 'price' - ); - - foreach ($products as $product) { - $productModel = Products1cNomenclature::findOne($product['product_guid']); - $species = $productModel?->species ?? 'Неизвестно'; - $basePrice = $pricesData[$product['product_guid']] ?? 0; - $rawCalculation = $basePrice * $product['count'] * $typeSalesValue; - $productCost = round($rawCalculation * 1.15, 2); - - if (!isset($resultData[$storeId][$species][$typeSales])) { - $resultData[$storeId][$species][$typeSales] = 0; - } - $resultData[$storeId][$species][$typeSales] += $productCost; - - $debugData[$storeId][$species][$typeSales][] = [ - 'product_guid' => $product['product_guid'], - 'price' => $basePrice, - 'count' => $product['count'], - 'forecast' => $typeSalesValue, - 'bouquet_id' => $forecast['bouquet_id'], - 'raw_calculation' => $rawCalculation, - 'rounded' => $productCost, - ]; - } } } + } else { + return [ + 'detail' => [], + 'final' => [], + 'debug' => [] + ]; } + // var_dump($forecasts); die(); + + // var_dump( $forecasts); die(); + + $finalResult = []; foreach ($resultData as $storeId => $speciesData) { @@ -1051,8 +1069,8 @@ class StorePlanService return [ 'detail' => $resultData, - 'final' => $finalResult, - 'debug' => $debugData + 'final' => $finalResult, + 'debug' => $debugData ]; } diff --git a/erp24/views/bouquet/get-guid-bouquet.php b/erp24/views/bouquet/get-guid-bouquet.php index c5371230..e63d9a14 100644 --- a/erp24/views/bouquet/get-guid-bouquet.php +++ b/erp24/views/bouquet/get-guid-bouquet.php @@ -25,13 +25,13 @@ $this->title = 'Импорт прогноза по букетам'; 'dataProvider' => $dataProvider, 'columns' => [ 'id', - 'bouquet_id', + 'guid', [ - 'attribute' => 'bouquet_group', + 'attribute' => 'group', 'label' => 'Группа букета', ], [ - 'attribute' => 'bouquet_name', + 'attribute' => 'name', 'label' => 'Название букета', ], 'year', diff --git a/erp24/views/bouquet/month-goal-forecast.php b/erp24/views/bouquet/month-goal-forecast.php index 227cf122..3026eb77 100644 --- a/erp24/views/bouquet/month-goal-forecast.php +++ b/erp24/views/bouquet/month-goal-forecast.php @@ -1,6 +1,7 @@ 'Оффлайн', @@ -34,6 +36,17 @@ $saleTypesLabels = [ field($model, 'year')->input('number')->label('Год') ?> field($model, 'storeId')->dropDownList($storesMap)->label('Магазин') ?> + field($model, 'matrix')->widget(\kartik\select2\Select2::class, [ + 'data' => $matrixGroups, + 'language' => 'ru', + 'options' => [ + 'placeholder' => 'Выберите группы матриц', + 'multiple' => true, + ], + 'pluginOptions' => [ + 'allowClear' => true, + ], + ])->label('Группы матриц') ?>
'btn btn-primary']) ?>
@@ -120,9 +133,9 @@ $saleTypesLabels = [ " (" . $model['product_guid'] . ")"; }, 'label' => 'Product GUID'], - ['attribute' => 'bouquet_id', + ['attribute' => 'guid', 'value' => function ($model, $key, $index, $widget) { - return \yii_app\records\MatrixBouquetForecast::find()->where(['bouquet_id' => $model['bouquet_id']])->one()->bouquet_name; + return \yii_app\records\MatrixBouquetForecast::find()->where(['guid' => $model['guid']])->one()->name; }, 'label' => 'Букет'], ['attribute' => 'price', 'label' => 'Цена'], @@ -214,11 +227,11 @@ $saleTypesLabels = [ } ], [ - 'attribute' => 'bouquet_id', + 'attribute' => 'guid', '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']; + $bouquet = \yii_app\records\MatrixBouquetForecast::find()->where(['guid' => $model['guid']])->one(); + return $bouquet ? $bouquet->name : $model['guid']; } ], ['attribute' => 'price', 'label' => 'Цена'], -- 2.39.5