From: fomichev Date: Mon, 9 Jun 2025 14:30:20 +0000 (+0300) Subject: Рефакторинг и организация кода X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=1906ee0fcaeb387dfd3d2fdd1fa507679a4ad6bc;p=erp24_rep%2Fyii-erp24%2F.git Рефакторинг и организация кода --- diff --git a/erp24/controllers/AutoPlannogrammaController.php b/erp24/controllers/AutoPlannogrammaController.php index f70bb5f2..5e44bd9b 100644 --- a/erp24/controllers/AutoPlannogrammaController.php +++ b/erp24/controllers/AutoPlannogrammaController.php @@ -906,10 +906,11 @@ class AutoPlannogrammaController extends BaseController $productSalesForecast = $service->calculateProductForecastInPiecesProductsWithHistory( $filters['store_id'], $filters['month'], - $productSalesShare, + $filters['year'], $goals, - $filters['subcategory'], + $productSalesShare, $filters['category'], + $filters['subcategory'], $filters['species'] ); @@ -1037,11 +1038,13 @@ class AutoPlannogrammaController extends BaseController $productSalesForecast = $service->calculateProductForecastInPiecesProductsWithHistory( $filters['store_id'], $filters['month'], - $productSalesShare, + $filters['year'], $goals, - $filters['subcategory'], + $productSalesShare, $filters['category'], + $filters['subcategory'], $filters['species'] + ); $matrixForecast = MatrixBouquetForecast::find() @@ -1285,7 +1288,9 @@ class AutoPlannogrammaController extends BaseController $filters['plan_date'] = $filters['year'] . '-' . str_pad($filters['month'], 2, '0', STR_PAD_LEFT) . '-01'; // var_dump( $filters['plan_date']); die(); $service = new AutoPlannogrammaService(); -//$goals = $service->calculateFullGoalChain($filters); + //$goals = $service->calculateFullGoalChain($filters); + //$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); @@ -1303,18 +1308,19 @@ class AutoPlannogrammaController extends BaseController } - $result = StorePlanService::calculateHistoricalShare( + /* $result = StorePlanService::calculateHistoricalShare( $filters['store_id'], $filters['month'], $filters['year'], - $filters['category'], - $filters['subcategory'], - $filters['species'] - ); + null, + null, + null + );*/ $noHistoryProductData = $service->calculateSpeciesForecastForProductsWithoutHistory($filters['plan_date'], $filters); + $historyProductData = $service->calculateSpeciesForecastForProductsWithHistory($filters['plan_date'], $filters, $goals); - $productSalesShare = StorePlanService::calculateProductSalesShareProductsWithHistory( + /* $productSalesShare = StorePlanService::calculateProductSalesShareProductsWithHistory( $filters['store_id'], $filters['month'], $result['with_history'] @@ -1328,7 +1334,7 @@ class AutoPlannogrammaController extends BaseController $filters['subcategory'], $filters['category'], $filters['species'] - ); + );*/ $matrixForecast = MatrixBouquetForecast::find() ->where(['year' => $filters['year'], 'month' => $filters['month']]) @@ -1356,7 +1362,7 @@ class AutoPlannogrammaController extends BaseController $cleanedSpeciesGoals = $service->subtractSpeciesGoals($goals, $bouquetSpeciesForecast, $noHistoryProductData); - $salesProductForecastShare = $service->calculateProductForecastShare($noHistoryProductData, $productSalesForecast); + $salesProductForecastShare = $service->calculateProductForecastShare($noHistoryProductData, $historyProductData); $productForecastSpecies = $service->calculateProductSalesBySpecies($salesProductForecastShare, $cleanedSpeciesGoals); @@ -1365,7 +1371,6 @@ class AutoPlannogrammaController extends BaseController $weeklySalesForecast = $service->calculateWeeklyProductForecastPieces($productForecastSpecies, $weeklySales); - $weeklySalesForecastFormated = $service->pivotWeeklyForecast($weeklySalesForecast); $flatData = array_filter($weeklySalesForecastFormated, function ($row) use ($filters) { @@ -1382,7 +1387,7 @@ class AutoPlannogrammaController extends BaseController $dataProvider = new ArrayDataProvider([ 'allModels' => $flatData, - 'pagination' => ['pageSize' => 100], + 'pagination' => ['pageSize' => 1000], ]); } return $this->render('week-sales-products_forecast', [ diff --git a/erp24/services/AutoPlannogrammaService.php b/erp24/services/AutoPlannogrammaService.php index e0ee09a2..7ab2e473 100644 --- a/erp24/services/AutoPlannogrammaService.php +++ b/erp24/services/AutoPlannogrammaService.php @@ -12,6 +12,7 @@ use yii_app\records\BouquetComposition; use yii_app\records\CityStore; use yii_app\records\CityStoreParams; use yii_app\records\ExportImportTable; +use yii_app\records\MatrixBouquetForecast; use yii_app\records\PricesDynamic; use yii_app\records\Products1c; use yii_app\records\Products1cNomenclature; @@ -773,7 +774,7 @@ class AutoPlannogrammaService $dateFromForCategory = (new \DateTime($datePlan))->modify('-' . (self::CATEGORY_LOOKBACK_MONTHS + self::LOOKBACK_MONTHS) . ' months')->format('Y-m-d'); $monthCategoryShare = $this->getMonthCategoryShareOrWriteOff($dateFromForCategory, $filters); - $monthCategoryGoal = $this->getMonthCategoryGoal($monthCategoryShare, $datePlan, $filters); + $monthCategoryGoal = $this->getMonthCategoryGoal($monthCategoryShare, $datePlan, $filters['type']); $monthSubcategoryShare = $this->getMonthSubcategoryShareOrWriteOff($datePlan, $filters); $monthSubcategoryGoal = $this->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal); @@ -1614,6 +1615,71 @@ class AutoPlannogrammaService return $result; } + + public function calculateSpeciesForecastForProductsWithHistory($dateFrom, $filters, $goals): array + { + // Получение ID видимых магазинов + $storeIds = array_map(fn($store) => $store->id, $this->getVisibleStores()); + + $subcategory = !empty($filters['subcategory']) ? $filters['subcategory'] : null; + $species = !empty($filters['species']) ? $filters['species'] : null; + + // Применение фильтра по магазину, если указан + if (!empty($filters['store_id'])) { + $storeIds = array_intersect($storeIds, [(int)$filters['store_id']]); + } + $date = new \DateTime($dateFrom); + $month = $date->format('m'); + $year = $date->format('Y'); + + $result = []; + + foreach ($storeIds as $storeId) { + $histResult = StorePlanService::calculateHistoricalShare( + $storeId, + $month, + $year, + $filters['category'], + $subcategory, + $species + ); + + $productsWithHistory = $histResult['with_history'] ?? []; + if (empty($productsWithHistory)) { + continue; + } + + $productSalesShare = StorePlanService::calculateProductSalesShareProductsWithHistory( + $filters['store_id'], + $filters['month'], + $productsWithHistory + ); + + if (empty($productSalesShare)) { + continue; + } + + $productSalesForecast = $this->calculateProductForecastInPiecesProductsWithHistory( + $filters['store_id'], + $filters['month'], + $year, + $goals, + $productSalesShare, + $filters['category'], + $filters['subcategory'], + $filters['species'] + + ); + + + if (!empty($productSalesForecast)) { + $result = array_merge($result, $productSalesForecast); + } + } + + return $result; + } + public function mapGoalsBySpecies(array $rows): array { $mapped = []; foreach ($rows as $row) { @@ -1800,12 +1866,12 @@ class AutoPlannogrammaService } public function calculateProductForecastInPiecesProductsWithHistory( - int $storeId, - string $month, - array $productSalesShare, - array $speciesGoals, - string $subcategory = null, + int $storeId, + string $month, string $year, + array $speciesGoals, + array $productSalesShare, string $category = null, + string $subcategory = null, string $species = null ): array { $result = []; @@ -1869,6 +1935,8 @@ class AutoPlannogrammaService $forecastCount = $forecastSum / $priceRecord->price; $result[] = [ + 'month' => $month, + 'year' => $year, 'product_id' => $productId, 'goal' => $goal, 'goal_share' => round($forecastSum, 2), @@ -1897,68 +1965,80 @@ class AutoPlannogrammaService array $pieciesForecastProductsNoHistyory, array $pieciesForecastProductWithHistory ): array { - $shareResult = []; + $groupedForecasts = []; + + // Обработка товаров без истории + foreach ($pieciesForecastProductsNoHistyory as $group) { + $base = [ + 'store_id' => $group['store_id'], + 'month' => $group['month'], + 'year' => $group['year'], + 'category' => $group['category'], + 'subcategory' => $group['subcategory'], + 'species' => $group['species'], + ]; - $info = $pieciesForecastProductsNoHistyory[0] ?? null; - if (!$info) { - return []; - } + foreach ($group['forecasts'] as $productId => $forecast) { + $key = implode('|', [ + $base['store_id'], $base['category'], $base['subcategory'], $base['species'] + ]); - $noHistoryMap = $info['forecasts'] ?? []; + $groupedForecasts[$key]['meta'] = $base; + $groupedForecasts[$key]['products'][$productId] = [ + 'product_id' => $productId, + 'forecast_pieces' => (float)$forecast, + 'history_status' => 'No history', + ]; + } + } - $piecesMap = []; + // Обработка товаров с историей foreach ($pieciesForecastProductWithHistory as $item) { - if (isset($item['product_id'], $item['forecast_pieces'])) { - $piecesMap[$item['product_id']] = $item['forecast_pieces']; - } + $key = implode('|', [ + $item['store_id'], $item['category'], $item['subcategory'], $item['species'] + ]); + + $groupedForecasts[$key]['meta'] = [ + 'store_id' => $item['store_id'], + 'month' => $item['month'], + 'year' => $item['year'], + 'category' => $item['category'], + 'subcategory' => $item['subcategory'], + 'species' => $item['species'], + ]; + + $groupedForecasts[$key]['products'][$item['product_id']] = [ + 'product_id' => $item['product_id'], + 'forecast_pieces' => (float)$item['forecast_pieces'], + 'history_status' => 'With history', + ]; } - $allProductIds = array_merge( - array_keys($noHistoryMap), - array_keys($piecesMap) - ); + $result = []; - $quantityMap = []; - foreach ($allProductIds as $pid) { - if (isset($piecesMap[$pid])) { - $quantityMap[$pid] = $piecesMap[$pid]; - } elseif (isset($noHistoryMap[$pid])) { - $quantityMap[$pid] = (float)$noHistoryMap[$pid]; - } else { - $quantityMap[$pid] = 0; + foreach ($groupedForecasts as $group) { + $meta = $group['meta']; + $products = $group['products']; + + $totalForecast = array_sum(array_column($products, 'forecast_pieces')); + + if ($totalForecast <= 0) { + continue; } - } - $totalPieces = array_sum($quantityMap); - if ($totalPieces <= 0) { - return []; - } + foreach ($products as $product) { + $share = round($product['forecast_pieces'] / $totalForecast, 4); - $storeId = $info['store_id']; - $month = $info['month']; - $year = $info['year']; - $category = $info['category']; - $subcategory = $info['subcategory']; - $species = $info['species']; - - foreach ($quantityMap as $pid => $count) { - $share = $count / $totalPieces; - - $shareResult[] = [ - 'store_id' => $storeId, - 'month' => $month, - 'year' => $year, - 'category' => $category, - 'subcategory' => $subcategory, - 'species' => $species, - 'product_id' => $pid, - 'forecast_pieces'=> $count, - 'share' => round($share, 4), - 'history_status' => in_array($pid, array_keys($noHistoryMap)) ? 'No history' : 'With history' - ]; + $result[] = array_merge($meta, [ + 'product_id' => $product['product_id'], + 'forecast_pieces' => $product['forecast_pieces'], + 'share' => $share, + 'history_status' => $product['history_status'], + ]); + } } - return $shareResult; + return $result; } /** @@ -2305,4 +2385,47 @@ class AutoPlannogrammaService } + public function calculateFullForecastForWeek(array $filters): array + { + $bouquetSpeciesForecast = []; + $goals = $this->calculateFullGoalChain($filters); + $noHistoryProductData = $this->calculateSpeciesForecastForProductsWithoutHistory($filters['plan_date'], $filters); + $historyProductData = $this->calculateSpeciesForecastForProductsWithHistory($filters['plan_date'], $filters, $goals); + $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 + ]; + } + } + } + + } + $cleanedSpeciesGoals = $this->subtractSpeciesGoals($goals, $bouquetSpeciesForecast, $noHistoryProductData); + + $salesProductForecastShare = $this->calculateProductForecastShare($noHistoryProductData, $historyProductData); + + $productForecastSpecies = $this->calculateProductSalesBySpecies($salesProductForecastShare, $cleanedSpeciesGoals); + + $weeklySales = $this->getHistoricalSpeciesShareByWeek($filters['plan_date'], $filters); + + $weeklySalesForecast = $this->calculateWeeklyProductForecastPieces($productForecastSpecies, $weeklySales); + + return $weeklySalesForecast; + } + + } \ No newline at end of file diff --git a/erp24/services/StorePlanService.php b/erp24/services/StorePlanService.php index 9a11fcfb..8ae90891 100755 --- a/erp24/services/StorePlanService.php +++ b/erp24/services/StorePlanService.php @@ -367,6 +367,7 @@ class StorePlanService if (!isset($salesHistory[$guid])) { $salesHistory[$guid] = [ + 'store_id' => $storeId, 'category' => $row['category'], 'subcategory' => $row['subcategory'], 'species' => $row['species'], @@ -403,6 +404,7 @@ class StorePlanService foreach ($salesHistory as $guid => $info) { $monthsData = $info['data']; $metaFields = [ + 'store_id' => $info['store_id'], 'category' => $info['category'], 'subcategory' => $info['subcategory'], 'species' => $info['species'],