From: fomichev Date: Fri, 6 Jun 2025 12:01:26 +0000 (+0300) Subject: Исправление по ревью и очистка кода X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=a77a34924351bdb4a3728a09231a10e0bbe618ad;p=erp24_rep%2Fyii-erp24%2F.git Исправление по ревью и очистка кода --- diff --git a/erp24/controllers/AutoPlannogrammaController.php b/erp24/controllers/AutoPlannogrammaController.php index e927abfc..57ee035b 100644 --- a/erp24/controllers/AutoPlannogrammaController.php +++ b/erp24/controllers/AutoPlannogrammaController.php @@ -766,7 +766,7 @@ class AutoPlannogrammaController extends BaseController } } - //var_dump($matrixGroups); die(); + $flatData = array_filter($bouquetSpeciesForecast, function ($row) use ($filters) { foreach ($filters as $key => $value) { if (empty($value)) continue; @@ -814,11 +814,10 @@ class AutoPlannogrammaController extends BaseController // Обработка даты на год и месяц 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(); $data = $service->calculateSpeciesForecastForProductsWithoutHistory($filters['plan_date'], $filters); - //var_dump($data); die(); $flatData = array_filter($data, function ($row) use ($filters) { foreach ($filters as $key => $value) { if (empty($value)) continue; @@ -865,7 +864,7 @@ class AutoPlannogrammaController extends BaseController // Обработка даты на год и месяц 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(); //$goals = $service->calculateFullGoalChain($filters); @@ -943,12 +942,6 @@ class AutoPlannogrammaController extends BaseController // $productForecastSpecies = $service->calculateProductSalesBySpecies($salesProductForecastShare, $cleanedSpeciesGoals); - // var_dump($salesProductForecastShare); die(); - - - - - $flatData = array_filter($salesProductForecastShare, function ($row) use ($filters) { foreach ($filters as $key => $value) { if (empty($value)) continue; @@ -996,7 +989,7 @@ class AutoPlannogrammaController extends BaseController // Обработка даты на год и месяц 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(); //$goals = $service->calculateFullGoalChain($filters); @@ -1074,14 +1067,6 @@ class AutoPlannogrammaController extends BaseController $productForecastSpecies = $service->calculateProductSalesBySpecies($salesProductForecastShare, $cleanedSpeciesGoals); - - - //var_dump($productForecastSpecies); die(); - - - - - $flatData = array_filter($productForecastSpecies, function ($row) use ($filters) { foreach ($filters as $key => $value) { if (empty($value)) continue; @@ -1171,11 +1156,10 @@ class AutoPlannogrammaController extends BaseController } } - //var_dump($bouquetSpeciesForecast); die(); + $noHistoryProductData = $service->calculateSpeciesForecastForProductsWithoutHistory($filters['plan_date'], $filters); - // var_dump($noHistoryProductData); die(); + $cleanedSpeciesGoals = $service->subtractSpeciesGoals($data, $bouquetSpeciesForecast, $noHistoryProductData); - //var_dump($cleanedSpeciesGoals); die(); $flatData = array_filter($cleanedSpeciesGoals, function ($row) use ($filters) { foreach ($filters as $key => $value) { @@ -1224,7 +1208,7 @@ class AutoPlannogrammaController extends BaseController // Обработка даты на год и месяц 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['plan_date']); die(); + $service = new AutoPlannogrammaService(); @@ -1283,9 +1267,9 @@ class AutoPlannogrammaController extends BaseController // Обработка даты на год и месяц 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['plan_date']); die(); + $service = new AutoPlannogrammaService(); -//$goals = $service->calculateFullGoalChain($filters); + $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters); $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date']); $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters); @@ -1481,7 +1465,7 @@ class AutoPlannogrammaController extends BaseController $monthCategoryShareResult[$cats['store_id']][$cats['category']]['goal'] = $cats['goal']; } - //var_dump($monthCategoryShareResult); die(); + $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOffWeighted($datePlan, $filters, null, $filters['type']); $monthSubcategoryGoal = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal); @@ -1515,7 +1499,7 @@ class AutoPlannogrammaController extends BaseController unset($row); $monthSubcategoryGoal = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal); } - // var_dump($monthSubcategoryShare); die(); + foreach ($monthSubcategoryShare as $subcat) { $monthCategoryShareResult[$subcat['store_id']][$subcat['category']][$subcat['subcategory']]['total_sum'] = $subcat['total_sum']; $monthCategoryShareResult[$subcat['store_id']][$subcat['category']][$subcat['subcategory']]['percent_of_month'] = $subcat['percent_of_month']; @@ -1595,7 +1579,7 @@ class AutoPlannogrammaController extends BaseController }); } -//var_dump($weeksProductForecast); die(); + return $this->render('control-species-old', [ 'model' => $model, 'result' => $monthResult, @@ -1693,9 +1677,6 @@ class AutoPlannogrammaController extends BaseController $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($datePlan, $filters, $filters['type']); $monthSubcategoryGoal = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal, $filters['type'], $monthSubcategorySalesGoal); - - - // var_dump($monthSubcategoryShare); die(); foreach ($monthSubcategoryShare as $subcat) { $monthCategoryShareResult[$subcat['store_id']][$subcat['category']][$subcat['subcategory']]['total_sum'] = $subcat['total_sum']; $monthCategoryShareResult[$subcat['store_id']][$subcat['category']][$subcat['subcategory']]['percent'] = $subcat['percent']; @@ -1724,7 +1705,6 @@ class AutoPlannogrammaController extends BaseController $monthCategoryShareResult[$row['store_id']][$row['category']][$row['subcategory']][$row['species']][$row['week']]['sumWeek'] = $row['sumWeek']; } - //var_dump($monthCategoryShareResult); die(); foreach ($weeksData as $r) { $forecasts = $service->calculateWeekForecastSpeciesProducts($r['category'], $r['subcategory'], $r['species'], $r['store_id'], $r['weekly_goal']); @@ -1754,7 +1734,7 @@ class AutoPlannogrammaController extends BaseController }); } -//var_dump($weeksProductForecast); die(); + return $this->render('control-species', [ 'model' => $model, 'result' => $monthResult, diff --git a/erp24/services/AutoPlannogrammaService.php b/erp24/services/AutoPlannogrammaService.php index d33643e7..4fc64cb0 100644 --- a/erp24/services/AutoPlannogrammaService.php +++ b/erp24/services/AutoPlannogrammaService.php @@ -1708,7 +1708,6 @@ class AutoPlannogrammaService ->andWhere(['nom.category' => null]) ->asArray() ->all(); - // var_dump( $salesProducts); die(); $components = []; $rows = []; @@ -2627,375 +2626,7 @@ class AutoPlannogrammaService // Недельные расчеты - /** - * Получает суммы продаж или списаний по видам (species) для каждой недели указанного месяца. - * - * @param string $monthYear месяц-год в формате MM-YYYY, например '03-2025' - * @param array|null $filters опциональные фильтры ['store_id'=>...] - * @param array|null $productFilter опциональный фильтр по product_id - * @param string $type 'sales' или 'writeOffs' - * @return array массив строк: [ - * ['week'=>1,'store_id'=>...,'category'=>...,'subcategory'=>...,'species'=>...,'sum'=>...], - * ... - * ] - */ - public function getWeeklySpeciesDataForMonth( - string $monthYear, - ?array $filters = null, - ?array $productFilter = null, - string $type = 'sales' - ): array { - [$monthStr, $yearStr] = explode('-', $monthYear); - $month = (int)$monthStr; - $year = (int)$yearStr; - - $dateFrom = strtotime(sprintf('%04d-%02d-01 00:00:00', $year, $month)); - $dateTo = strtotime('+1 month -1 second', $dateFrom); - - $stores = $this->getVisibleStores(); - $storeIds = array_map(fn($s)=>$s->id, $stores); - if (!empty($filters['store_id'])) { - $storeIds = array_intersect($storeIds, [(int)$filters['store_id']]); - } - if (empty($storeIds)) { - return []; - } - - $dayOfWeek = (int)date('N', $dateFrom); - $firstMonday = $dayOfWeek === 1 - ? $dateFrom - : strtotime('next monday', $dateFrom); - - - $weekRanges = []; - for ($wkStart = $firstMonday; $wkStart <= $dateTo; $wkStart += 7 * 86400) { - $wkEnd = $wkStart + 6 * 86400; - if ($wkEnd > $dateTo) { - $wkEnd = $dateTo; - } - $periodStart = max($wkStart, $dateFrom); - $periodEnd = min($wkEnd, $dateTo); - $daysInMonth = floor(($periodEnd - $periodStart) / 86400) + 1; - if ($daysInMonth >= 4) { - $weekRanges[] = [ - 'index' => (int)date('W', $wkStart), - 'start' => date('Y-m-d H:i:s', $wkStart), - 'end' => date('Y-m-d 23:59:59', $wkEnd), - ]; - } - } - - $result = []; - - foreach ($weekRanges as $range) { - $exprWeek = new Expression((string)$range['index']); - $query = (new Query())->select([ - 'week' => $exprWeek, - 'store_id' => 'ex.entity_id', - 'category' => 'p1c.category', - 'subcategory' => 'p1c.subcategory', - 'species' => 'p1c.species', - 'total_sum' => new Expression( - $type === 'writeOffs' - ? 'SUM(CAST(wop.summ AS NUMERIC))' - : 'SUM(sp.summ)' - ), - ]); - - if ($type === 'writeOffs') { - $query->from(['w' => 'write_offs']) - ->leftJoin(['ex' => 'export_import_table'], 'ex.export_val = w.store_id') - ->leftJoin(['wop'=> 'write_offs_products'], 'wop.write_offs_id = w.id') - ->leftJoin(['p1c'=> 'products_1c_nomenclature'], 'p1c.id = wop.product_id') - ->andWhere(['>=', 'w.date', $range['start']]) - ->andWhere(['<=', 'w.date', $range['end']]); - if ($productFilter !== null) { - $query->andWhere(['wop.product_id' => $productFilter]); - } - } else { - $query->from(['s' => 'sales']) - ->leftJoin(['sp' => 'sales_products'], 'sp.check_id = s.id') - ->leftJoin(['ex' => 'export_import_table'], 'ex.export_val = s.store_id_1c') - ->leftJoin(['p1c'=> 'products_1c_nomenclature'], 'p1c.id = sp.product_id') - ->andWhere(['>=', 's.date', $range['start']]) - ->andWhere(['<=', 's.date', $range['end']]); - if ($productFilter !== null) { - $query->andWhere(['sp.product_id' => $productFilter]); - } - } - - $query->andWhere(['ex.entity_id' => $storeIds]) - ->andWhere(['<>', 'p1c.species', '']) - ->groupBy(['week','ex.entity_id','p1c.category','p1c.subcategory','p1c.species']); - - $rows = $query->all(); - foreach ($rows as $row) { - $result[] = [ - 'week' => $row['week'], - 'store_id' => $row['store_id'], - 'category' => $row['category'], - 'subcategory' => $row['subcategory'], - 'species' => $row['species'], - 'sum' => (float)$row['total_sum'], - ]; - } - } - - return $result; - } - - /** - * Исторический недельный отчёт и доли по видам с учётом store_id. - * - * @param string $monthYear месяц-год в формате MM-YYYY - * @param array|null $filters - * @param array|null $productFilter - * @param string $type - * @return array{ 'weeksData': array } - * возвращает плоский список строк: - * [ - * ['week'=>1, 'store_id'=>2, 'category'=>'...', 'subcategory'=>'...', 'species'=>'...', 'percent'=>0.32], - * ... - * ] - */ - public function getHistoricalWeeklySpeciesShare( - string $monthYear, - ?array $filters = null, - ?array $productFilter = null, - string $type = 'sales' - ): array { - [$monthStr, $yearStr] = explode('-', $monthYear); - $month = (int)$monthStr; - $year = (int)$yearStr; - - $historical = []; - for ($yr = $year - 2; $yr < $year; $yr++) { - $mYear = sprintf('%02d-%d', $month, $yr); - $weeklyData = $this->getWeeklySpeciesDataForMonth( - $mYear, $filters, $productFilter, $type - ); - - foreach ($weeklyData as $row) { - $week = $row['week']; - $sid = $row['store_id']; - $cat = $row['category']; - $sub = $row['subcategory']; - $spec = $row['species']; - $sumWeek = $row['sum']; - - $historical[$week] ??= []; - $historical[$week][$sid] ??= []; - $historical[$week][$sid][$cat] ??= []; - $historical[$week][$sid][$cat][$sub] ??= []; - $historical[$week][$sid][$cat][$sub][$spec] = - ($historical[$week][$sid][$cat][$sub][$spec] ?? 0) + $sumWeek; - } - } - - $dateFrom = sprintf('%04d-%02d-01 00:00:00', $year, $month); - $dateTo = date('Y-m-d H:i:s', strtotime("$dateFrom +1 month -1 second")); - $monthWeighted = $this->getMonthSpeciesShareOrWriteOffWeighted( - $dateFrom, $dateTo, $filters, $productFilter, $type - ); - $monthMap = []; - foreach ($monthWeighted as $m) { - $sid = $m['store_id']; - $cat = $m['category']; - $sub = $m['subcategory']; - $spec = $m['species']; - $sumMonth = $m['total_sum']; - - $monthMap[$sid] ??= []; - $monthMap[$sid][$cat] ??= []; - $monthMap[$sid][$cat][$sub]??= []; - $monthMap[$sid][$cat][$sub][$spec] = - ($monthMap[$sid][$cat][$sub][$spec] ?? 0) + $sumMonth; - } - - - $weeksList = array_keys($historical); - sort($weeksList, SORT_NUMERIC); - - $speciesList = []; - foreach ($monthMap as $sid => $byCat) { - foreach ($byCat as $cat => $bySub) { - foreach ($bySub as $sub => $bySpec) { - foreach ($bySpec as $spec => $_) { - $speciesList[] = compact('sid','cat','sub','spec'); - } - } - } - } - - - $rows = []; - foreach ($speciesList as $comb) { - $sid = $comb['sid']; - $cat = $comb['cat']; - $sub = $comb['sub']; - $spec = $comb['spec']; - - $sumMonth = $monthMap[$sid][$cat][$sub][$spec] ?? 0; - if ($sumMonth <= 0) { - continue; // нет месячного итога - } - - foreach ($weeksList as $week) { - $sumWeek = $historical[$week][$sid][$cat][$sub][$spec] ?? 0; - $percent = $sumWeek > 0 ? round($sumWeek / $sumMonth, 4) : null; - $rows[] = [ - 'week' => $week, - 'store_id' => $sid, - 'category' => $cat, - 'subcategory' => $sub, - 'species' => $spec, - 'sumWeek' => $sumWeek, - 'percent' => $percent, - ]; - } - } - - $grouped = []; - foreach ($rows as $idx => $row) { - $key = "{$row['store_id']}|{$row['category']}|{$row['subcategory']}|{$row['species']}"; - $grouped[$key][] = $idx; - } - foreach ($grouped as $key => $indices) { - $sumPercent = 0.0; - foreach ($indices as $i) { - $sumPercent += $rows[$i]['percent']; - } - if ($sumPercent < 1.0) { - $diff = 1.0 - $sumPercent; - $count = count($indices); - $add = $diff / $count; - foreach ($indices as $i) { - $rows[$i]['percent'] = round($rows[$i]['percent'] + $add, 4); - } - } - } - - return ['weeksData' => $rows]; - } - - - /** - * Рассчитывает недельную цель для каждого вида (species) по данным недельных долей - * и целям месяца. - * @param array $weeksShareData - * @param array $monthSpeciesGoals - * @return array - * Плоский массив строк с полями: week, store_id, category, subcategory, - * species, percent, monthly_goal, weekly_goal - */ - public function calculateWeeklySpeciesGoals( - array $weeksShareData, - array $monthSpeciesGoals - ): array { - $monthSpeciesGoalsMap = []; - foreach ($monthSpeciesGoals as $monthSpeciesGoal) { - $monthSpeciesGoalsMap[$monthSpeciesGoal['store_id']] - [$monthSpeciesGoal['category']] - [$monthSpeciesGoal['subcategory']] - [$monthSpeciesGoal['species']] = $monthSpeciesGoal['goal'] ; - } - $result = []; - foreach ($weeksShareData as $row) { - $week = $row['week']; - $sid = $row['store_id']; - $cat = $row['category']; - $sub = $row['subcategory']; - $spec = $row['species']; - $percent = $row['percent']; - - $monthlyGoal = $monthSpeciesGoalsMap[$sid][$cat][$sub][$spec] ?? null; - - $weeklyGoal = 0; - if ($monthlyGoal !== null && $percent !== null) { - $weeklyGoal = round($percent * $monthlyGoal, 4); - } - - $result[] = [ - 'week' => $week, - 'store_id' => $sid, - 'category' => $cat, - 'subcategory' => $sub, - 'species' => $spec, - 'percent' => $percent, - 'monthly_goal' => $monthlyGoal, - 'weekly_goal' => $weeklyGoal, - ]; - } - return $result; - } - - /** - * Возвращает дату понедельника ISO-недели в формате YYYY-MM-DD - * - * @param int $year ISO-год (может отличаться от календарного в границах года) - * @param int $week номер ISO-недели (1–53) - * @return string дата понедельника, например '2025-03-10' - */ - public static function getIsoWeekStart(int $year, int $week): string - { - $iso = $year . 'W' . str_pad($week, 2, '0', STR_PAD_LEFT) . '1'; - return date('Y-m-d', strtotime($iso)); - } - - - public static function calculateWeekForecastSpeciesProducts($category, $subcategory, $species, $storeId, $goal) - { - $speciesProductForecast = []; - $products = Products1cNomenclature::find() - ->select(['id', 'name']) - ->where(['category' => $category]) - ->andWhere(['subcategory' => $subcategory]) - ->andWhere(['species' => $species]) - ->indexBy('id') - ->asArray() - ->all(); - - $productsIds = ArrayHelper::getColumn($products, 'id'); - if (CityStore::find()->where(['id' => $storeId])->one()->city_id == 1342) { - $region = 52; - } elseif (CityStore::find()->where(['id' => $storeId])->one()->city_id == 1) { - $region = 77; - } else { - $region = null; - } - $priceRecords = PricesDynamic::find() - ->select(['product_id', 'price']) - ->where(['product_id' => $productsIds]) - ->andWhere(['active' => 1]) - ->andWhere(['or', ['region_id' => $region], ['region_id' => null]]) - ->indexBy('product_id') - ->asArray() - ->all(); - - foreach ($priceRecords as $id => $record) { - if ($goal == 0 || (int)$record['price'] == 0) { - $forecast = 0; - } else { - $forecast = round(max($goal / (float)$record['price'], 1), 0); - } - $speciesProductForecast[] = [ - 'category' => $category, - 'subcategory' => $subcategory, - 'species' => $species, - 'product_id' => $record['product_id'], - 'name' => $products[$id]['name'], - 'price' => $record['price'] ?? $goal ?? 1, - 'goal' => $goal ?? 0, - 'forecast' => $forecast - - ]; - - } - - return $speciesProductForecast; - - } // альтернативные методы расчета списаний