From: marina Date: Thu, 15 May 2025 13:34:56 +0000 (+0300) Subject: ыыы X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=a05eb61a5f47311f2702f00495db8ad67f571de5;p=erp24_rep%2Fyii-erp24%2F.git ыыы --- diff --git a/erp24/controllers/AutoPlannogrammaController.php b/erp24/controllers/AutoPlannogrammaController.php index 577ec8fe..38f87910 100644 --- a/erp24/controllers/AutoPlannogrammaController.php +++ b/erp24/controllers/AutoPlannogrammaController.php @@ -289,8 +289,8 @@ class AutoPlannogrammaController extends BaseController $service = new AutoPlannogrammaService(); - $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters); - $data = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date'], $filters); + $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); + $data = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date'], $filters['type']); $flatData = array_filter($data, function ($row) use ($filters) { foreach ($filters as $key => $value) { @@ -388,11 +388,18 @@ class AutoPlannogrammaController extends BaseController $service = new AutoPlannogrammaService(); - $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); - $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date'], $filters); - $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); + $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters); + $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date']); + $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters); $data = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal); + if ($filters['type'] == AutoPlannogrammaService::TYPE_WRITE_OFFS) { + $monthCategoryWriteOffsShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); + $monthCategoryWriteOffsGoal = $service->getMonthCategoryGoal($monthCategoryWriteOffsShare, $filters['plan_date'], $filters['type']); + $monthSubcategoryWriteOffsShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); + $data = $service->getMonthSubcategoryGoal($monthSubcategoryWriteOffsShare, $monthCategoryWriteOffsGoal, $filters['type'], $data); + } + $flatData = array_filter($data, function ($row) use ($filters) { foreach ($filters as $key => $value) { if (empty($value)) continue; @@ -491,13 +498,22 @@ class AutoPlannogrammaController extends BaseController $filters['plan_date'] = $filters['year'] . '-' . str_pad($filters['month'], 2, '0', STR_PAD_LEFT) . '-01'; $service = new AutoPlannogrammaService(); - $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); - $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date'], $filters); - $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); + $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters); + $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date']); + $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters); $monthSubcategoryGoal = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal); - $monthSpeciesShare = $service->getMonthSpeciesShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); + $monthSpeciesShare = $service->getMonthSpeciesShareOrWriteOff($filters['plan_date'], $filters); $data = $service->getMonthSpeciesGoalDirty($monthSpeciesShare, $monthSubcategoryGoal); + if ($filters['type'] == AutoPlannogrammaService::TYPE_WRITE_OFFS) { + $monthCategoryWriteOffsShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); + $monthCategoryWriteOffsGoal = $service->getMonthCategoryGoal($monthCategoryWriteOffsShare, $filters['plan_date'], $filters['type']); + $monthSubcategoryWriteOffsShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); + $monthSubcategoryWriteOffsGoals = $service->getMonthSubcategoryGoal($monthSubcategoryWriteOffsShare, $monthCategoryWriteOffsGoal, $filters['type']); + $monthSpeciesWriteOffShare = $service->getMonthSpeciesShareOrWriteOff($filters['plan_date'], $filters, $filters['type']); + $data = $service->getMonthSpeciesGoalDirty($monthSpeciesWriteOffShare, $monthSubcategoryWriteOffsGoals, $filters['type'], $data); + } + $flatData = array_filter($data, function ($row) use ($filters) { foreach ($filters as $key => $value) { if (empty($value)) continue; @@ -510,8 +526,6 @@ class AutoPlannogrammaController extends BaseController return true; }); - - $dataProvider = new ArrayDataProvider([ 'allModels' => $flatData, 'pagination' => ['pageSize' => 100], diff --git a/erp24/services/AutoPlannogrammaService.php b/erp24/services/AutoPlannogrammaService.php index 4645a0d9..3a3bf27d 100644 --- a/erp24/services/AutoPlannogrammaService.php +++ b/erp24/services/AutoPlannogrammaService.php @@ -10,8 +10,8 @@ use yii_app\records\SalesWriteOffsPlan; class AutoPlannogrammaService { - private const TYPE_SALES = 'sales'; // Тип операции: продажи - private const TYPE_WRITE_OFFS = 'writeOffs'; // Тип операции: списания + public const TYPE_SALES = 'sales'; // Тип операции: продажи + public const TYPE_WRITE_OFFS = 'writeOffs'; // Тип операции: списания private const CATEGORY_LOOKBACK_MONTHS = 3; // Период для анализа категорий (месяцы) private const LOOKBACK_MONTHS = 2; // Отступаемый шаг от плановой даты перед расчетами @@ -24,21 +24,20 @@ class AutoPlannogrammaService return CityStore::findAll(['visible' => CityStore::IS_VISIBLE]); } - /** Корректировка процента списаний, если он превышает 10% от процента продаж. - * @param float $currentPercent Текущий процент списаний. - * @param float $salesPercent Процент продаж для того же магазина, категории и подкатегории. - * @return float Скорректированный процент списаний. + /** + * Корректировка цели списаний, если она превышает 10% от цели продаж. + * @param float|null $writeOffGoal Текущая цель списаний + * @param float|null $salesGoal Цель продаж для того же магазина, категории и подкатегории + * @return float Скорректированная цель списаний */ - private function adjustWriteOffPercent( - float $currentPercent, - float $salesPercent - ): float { - if ($currentPercent > ($salesPercent * 0.1)) { - return $currentPercent * 0.1; + private function adjustWriteOffPercent(?float $writeOffGoal, ?float $salesGoal): float + { + if ($writeOffGoal === null || $salesGoal === null || $salesGoal <= 0) { + return $writeOffGoal ?? 0.0; } - return $currentPercent; - } + return ($writeOffGoal / $salesGoal >= 0.1) ? $salesGoal * 0.1 : $writeOffGoal; + } /** * Получение доли категорий или списаний за месяц @@ -140,7 +139,8 @@ class AutoPlannogrammaService ->andWhere(['>=', "$alias.date", (new \DateTime($month1 . '-01'))->format('Y-m-d')]) ->andWhere(['<=', "$alias.date", (new \DateTime($month3 . '-01'))->modify('last day of this month')->format('Y-m-d')]) ->groupBy(['ex.entity_id']), - ], 'main.ex_entity_id = totals.store_id'); + ], 'main.ex_entity_id = totals.store_id') + ->orderBy('category'); // Выполнение запроса и форматирование $rows = $query->all(); @@ -166,12 +166,13 @@ class AutoPlannogrammaService * @param array $filters Фильтры * @return array Массив с целями по категориям */ - public function getMonthCategoryGoal(array $categoryShare, string $datePlan, array $filters): array + public function getMonthCategoryGoal(array $categoryShare, string $datePlan, string $type = self::TYPE_SALES): array { $timestamp = strtotime($datePlan); $year = date('Y', $timestamp); $month = date('m', $timestamp); + $plans = SalesWriteOffsPlan::find() ->where(['year' => $year, 'month' => $month]) ->asArray() @@ -189,7 +190,7 @@ class AutoPlannogrammaService $result[] = [ 'category' => $item['category'], 'store_id' => $storeId, - 'goal' => round($item['percent'] * ($filters['type'] === self::TYPE_WRITE_OFFS ? $plan['write_offs_plan'] : $plan['total_sales_plan']), 2), + 'goal' => round($item['percent'] * ($type === self::TYPE_WRITE_OFFS ? $plan['write_offs_plan'] : $plan['total_sales_plan']), 2), ]; } } @@ -255,7 +256,7 @@ class AutoPlannogrammaService ->leftJoin('products_1c_nomenclature p1c', "p1c.id = $productJoinCondition") ->leftJoin('export_import_table ex', $storeJoinCondition) ->andWhere(['ex.entity_id' => $storeIds]) - ->andWhere(['<>', 'p1c.subcategory', '']) + ->andWhere(['<>', 'p1c.category', '']) ->andWhere(['or', ...$months]) ->groupBy(['ex.entity_id', 'p1c.category', 'p1c.subcategory']), ]) @@ -263,6 +264,7 @@ class AutoPlannogrammaService ['totals' => (new Query()) ->select([ 'store_id' => 'ex.entity_id', + 'category' => 'p1c.category', 'total' => new Expression($sumExpression), ]) ->from($fromTable) @@ -270,41 +272,14 @@ class AutoPlannogrammaService ->leftJoin('products_1c_nomenclature p1c', "p1c.id = $productJoinCondition") ->leftJoin('export_import_table ex', $storeJoinCondition) ->andWhere(['ex.entity_id' => $storeIds]) - ->andWhere(['<>', 'p1c.subcategory', '']) + ->andWhere(['<>', 'p1c.category', '']) ->andWhere(['or', ...$months]) - ->groupBy(['ex.entity_id'])], - 'main.ex_entity_id = totals.store_id' - ); - - $rows = $query->all(); - $result = []; - $salesPercents = []; - - // Сначала вычисляем проценты для продаж (они понадобятся для сравнения) - foreach ($rows as $row) { - $key = "{$row['store_id']}_{$row['category']}_{$row['subcategory']}"; - if ($row['type'] === self::TYPE_SALES) { - $salesPercents[$key] = $row['percent']; - } - } + ->groupBy(['ex.entity_id', 'p1c.category'])], + 'main.ex_entity_id = totals.store_id AND main.category = totals.category' + ) + ->orderBy('category, subcategory'); - foreach ($rows as $row) { - $key = "{$row['store_id']}_{$row['category']}_{$row['subcategory']}"; - $percent = $row['percent']; - - if ($row['type'] === self::TYPE_WRITE_OFFS) { - $percent = $this->adjustWriteOffPercent($percent, $salesPercents[$key] ?? 0); - } - - $result[] = [ - 'store_id' => $row['store_id'], - 'category' => $row['category'], - 'subcategory' => $row['subcategory'], - 'total_sum' => $row['total_sum'], - 'percent' => $percent, - 'type' => $row['type'], - ]; - } + $result = $query->all(); return $result; } @@ -313,9 +288,10 @@ class AutoPlannogrammaService * Получение целей по подкатегориям за месяц * @param array $subcategoryShare Доли подкатегорий * @param array $categoryGoals Цели по категориям + * @param string $type Тип операции * @return array Массив с целями по подкатегориям */ - public function getMonthSubcategoryGoal(array $subcategoryShare, array $categoryGoals): array + public function getMonthSubcategoryGoal(array $subcategoryShare, array $categoryGoals, string $type = self::TYPE_SALES, array $salesGoals = []): array { $indexedGoals = []; foreach ($categoryGoals as $goal) { @@ -334,6 +310,22 @@ class AutoPlannogrammaService ]; } } + + if ($type == self::TYPE_WRITE_OFFS) { + foreach ($result as &$row) { + foreach ($salesGoals as $salesGoal) { + if ($row['category'] === $salesGoal['category'] + && $row['subcategory'] === $salesGoal['subcategory'] + && $row['store_id'] === $salesGoal['store_id']) { + $row['old_value'] = $row['goal']; + $row['sales_goal'] = $salesGoal['goal']; + $row['goal'] = $this->adjustWriteOffPercent($row['goal'], $salesGoal['goal']); + } + } + } + unset($row); + } + return $result; } @@ -406,18 +398,23 @@ class AutoPlannogrammaService ['totals' => (new Query()) ->select([ 'store_id' => 'ex.entity_id', + 'category' => 'p1c.category', + 'subcategory' => 'p1c.subcategory', 'total' => new Expression($sumExpression), ]) ->from($fromTable) ->leftJoin($productTableJoin, $productTableJoinCondition) ->leftJoin('products_1c_nomenclature p1c', "p1c.id = $productJoinCondition") ->leftJoin('export_import_table ex', $storeJoinCondition) - ->andWhere(['or', ...$months]) ->andWhere(['ex.entity_id' => $storeIds]) ->andWhere(['<>', 'p1c.species', '']) - ->groupBy(['ex.entity_id'])], - 'main.ex_entity_id = totals.store_id' - ); + ->andWhere(['or', ...$months]) + ->groupBy(['ex.entity_id', 'p1c.category', 'p1c.subcategory'])], + 'main.ex_entity_id = totals.store_id + AND main.category = totals.category + AND main.subcategory = totals.subcategory' + ) + ->orderBy('category, subcategory, species'); $rows = $query->all(); $result = []; @@ -456,9 +453,10 @@ class AutoPlannogrammaService * Получение целей по видам за месяц * @param array $speciesShare Доли видов * @param array $subcategoryGoals Цели по подкатегориям + * @param string $type Тип операции * @return array Массив с целями по видам */ - public function getMonthSpeciesGoalDirty(array $speciesShare, array $subcategoryGoals): array + public function getMonthSpeciesGoalDirty(array $speciesShare, array $subcategoryGoals, $type = self::TYPE_SALES, $salesGoals = []): array { $indexedGoals = []; foreach ($subcategoryGoals as $goal) { @@ -479,6 +477,22 @@ class AutoPlannogrammaService } } + if ($type == self::TYPE_WRITE_OFFS) { + foreach ($result as &$row) { + foreach ($salesGoals as $salesGoal) { + if ($row['category'] === $salesGoal['category'] + && $row['subcategory'] === $salesGoal['subcategory'] + && $row['species'] === $salesGoal['species'] + && $row['store_id'] === $salesGoal['store_id']) { + $row['old_value'] = $row['goal']; + $row['sales_goal'] = $salesGoal['goal']; + $row['goal'] = $this->adjustWriteOffPercent($row['goal'], $salesGoal['goal']); + } + } + } + unset($row); + } + return $result; } diff --git a/erp24/views/auto-plannogramma/4.php b/erp24/views/auto-plannogramma/4.php index 4ab49e21..a5d0d6e4 100644 --- a/erp24/views/auto-plannogramma/4.php +++ b/erp24/views/auto-plannogramma/4.php @@ -81,15 +81,26 @@ + 'store_id', 'label' => 'Магазин', 'value' => function ($data) { + return CityStore::findOne($data['store_id'])->name ?? null; + }], + ['attribute' => 'category', 'label' => 'Категория'], + ['attribute' => 'subcategory', 'label' => 'Подкатегория'], + ['attribute' => 'goal', 'label' => 'Сумма План', 'format' => ['decimal', 2]], +]; + +if ($filters['type'] == 'writeOffs') { + $columns = array_merge($columns, [ + ['attribute' => 'old_value', 'label' => 'Сумма до сверки', 'format' => ['decimal', 2]], + ['attribute' => 'sales_goal', 'label' => 'Сумма продаж', 'format' => ['decimal', 2]], + ]); +} +?> + $dataProvider, - 'columns' => [ - ['attribute' => 'store_id', 'label' => 'Магазин', 'value' => function ($data) { - return CityStore::findOne($data['store_id'])->name ?? null; - }], - ['attribute' => 'category', 'label' => 'Категория'], - ['attribute' => 'subcategory', 'label' => 'Подкатегория'], - ['attribute' => 'goal', 'label' => 'Сумма План', 'format' => ['decimal', 2]], - ], + 'columns' => $columns, ]); ?> diff --git a/erp24/views/auto-plannogramma/6.php b/erp24/views/auto-plannogramma/6.php index c49498d1..b3513621 100644 --- a/erp24/views/auto-plannogramma/6.php +++ b/erp24/views/auto-plannogramma/6.php @@ -92,15 +92,27 @@ + + + 'store_id', 'label' => 'Магазин', 'value' => function ($data) { + return CityStore::findOne($data['store_id'])->name ?? null; + }], + ['attribute' => 'category', 'label' => 'Категория'], + ['attribute' => 'subcategory', 'label' => 'Подкатегория'], + ['attribute' => 'species', 'label' => 'Тип'], + ['attribute' => 'goal', 'label' => 'Сумма План', 'format' => ['decimal', 2]], +]; + +if ($filters['type'] == 'writeOffs') { + $columns = array_merge($columns, [ + ['attribute' => 'old_value', 'label' => 'Сумма до сверки', 'format' => ['decimal', 2]], + ['attribute' => 'sales_goal', 'label' => 'Сумма продаж', 'format' => ['decimal', 2]], + ]); +} +?> $dataProvider, - 'columns' => [ - ['attribute' => 'store_id', 'label' => 'Магазин', 'value' => function ($data) { - return CityStore::findOne($data['store_id'])->name ?? null; - }], - ['attribute' => 'category', 'label' => 'Категория'], - ['attribute' => 'subcategory', 'label' => 'Подкатегория'], - ['attribute' => 'species', 'label' => 'Тип'], - ['attribute' => 'goal', 'label' => 'Сумма План', 'format' => ['decimal', 2]], - ], + 'columns' => $columns, ]); ?>