]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
ERP-360 Сборка страницы автопм
authormarina <m.zozirova@gmail.com>
Tue, 17 Jun 2025 07:50:50 +0000 (10:50 +0300)
committermarina <m.zozirova@gmail.com>
Tue, 17 Jun 2025 07:50:50 +0000 (10:50 +0300)
erp24/controllers/AutoPlannogrammaController.php
erp24/services/AutoPlannogrammaService.php

index 42aed70eef33c34c82d08c10c5df13abda4c9455..7a3dc18b25ff0a347ff9dbcdd76c12c8e47fc89d 100644 (file)
@@ -1784,17 +1784,7 @@ return $forecast;
 
         $grouped = [];
 
-        foreach ($result as $item) {
-            $weekItem = (int)$item['week'];
-            $storeItem = (int)$item['store_id'];
-            $guid = (string)$item['product_guid'];
-            $group = (string)$item['matrix_group'];
-            $type = (string)$item['type'];
-            $forecastValue = (float)$item['week_forecast'];
-
-            $grouped[$weekItem][$storeItem][$guid][$type][$group] = $forecastValue;
-        }
-
+    
 
         if ($week !== null) {
             $week = (int)$week;
index 17eff12bc781d88530da17eb7f74a91cdd4c6255..810fc9b5b4589826851b203a455cb9cb2a6d98cd 100644 (file)
@@ -125,7 +125,7 @@ class AutoPlannogrammaService
                 'percent' => new Expression('ROUND(CAST(main.total_sum AS DECIMAL) / NULLIF(totals.total, 0), 4)'),
                 'type' => new Expression(':type', ['type' => $type]),
                 'totals_total' => 'totals.total',
-                'products_list'=> 'main.products_list',
+                'products_list' => 'main.products_list',
             ])
             ->from([
                 'main' => (new Query())
@@ -188,7 +188,7 @@ class AutoPlannogrammaService
                     $type
                 );
 
-                if(!$items) {
+                if (!$items) {
                     continue;
                 }
                 foreach ($items as $it) {
@@ -231,7 +231,7 @@ class AutoPlannogrammaService
                 'new_total_store' => $newDenominator,
                 'base_total_store' => $baseTotal,
                 'products_list' => $r['products_list'],
-                'products_components_list' => implode(',',$allComponentsProductIds[$sid] ?? []),
+                'products_components_list' => implode(',', $allComponentsProductIds[$sid] ?? []),
             ];
         }
 
@@ -305,7 +305,7 @@ class AutoPlannogrammaService
         $productTableJoinCondition = $type === self::TYPE_WRITE_OFFS ? 'wp.write_offs_id = w.id' : 'sp.check_id = s.id';
 
         $field = $type === self::TYPE_WRITE_OFFS ? 'w.date' : 's.date';
-        $base  = new \DateTime($dateFrom);
+        $base = new \DateTime($dateFrom);
 
         $months = [
             [
@@ -377,8 +377,8 @@ class AutoPlannogrammaService
             (clone $base)->modify('-2 year'),
             (clone $base)->modify('-1 year'),
         ];
-        $componentAdds        = [];
-        $componentAddsSumAll  = [];
+        $componentAdds = [];
+        $componentAddsSumAll = [];
         $allComponentsProdIds = [];
 
         foreach ($storeIds as $sid) {
@@ -402,9 +402,9 @@ class AutoPlannogrammaService
                 $allComponentsProdIds[$sid] = array_unique($allComponentsProdIds[$sid]);
 
                 foreach ($sums as $sr) {
-                    $cat    = $sr['category'];
+                    $cat = $sr['category'];
                     $subcat = $sr['subcategory'];
-                    $val    = $sr['sum'];
+                    $val = $sr['sum'];
 
                     $componentAdds[$sid][$cat][$subcat] =
                         ($componentAdds[$sid][$cat][$subcat] ?? 0) + $val;
@@ -417,17 +417,17 @@ class AutoPlannogrammaService
         $result = [];
 
         foreach ($rows as $r) {
-            $sid       = $r['store_id'];
-            $cat       = $r['category'];
-            $subcat    = $r['subcategory'];
+            $sid = $r['store_id'];
+            $cat = $r['category'];
+            $subcat = $r['subcategory'];
 
 
-            $subTotal  = (float)$r['total_sum'];
-            $catTotal  = (float)$r['totals_total'];
+            $subTotal = (float)$r['total_sum'];
+            $catTotal = (float)$r['totals_total'];
 
 
-            $addCat    = $componentAddsSumAll[$sid][$cat] ?? 0.0;
-            $addSubcat = $componentAdds[$sid][$cat][$subcat]   ?? 0.0;
+            $addCat = $componentAddsSumAll[$sid][$cat] ?? 0.0;
+            $addSubcat = $componentAdds[$sid][$cat][$subcat] ?? 0.0;
 
 
             $newCatTotal = $catTotal + $addCat;
@@ -439,15 +439,15 @@ class AutoPlannogrammaService
                 : 0.0;
 
             $result[] = [
-                'store_id'                 => $sid,
-                'category'                 => $cat,
-                'subcategory'              => $subcat,
-                'old_total_sum'            => $subTotal,
-                'total_sum'                => $newSubTotal,
-                'percent'                  => $percent,
-                'type'                     => $type,
-                'new_total_store'          => $newCatTotal,
-                'base_total_store'         => $catTotal,
+                'store_id' => $sid,
+                'category' => $cat,
+                'subcategory' => $subcat,
+                'old_total_sum' => $subTotal,
+                'total_sum' => $newSubTotal,
+                'percent' => $percent,
+                'type' => $type,
+                'new_total_store' => $newCatTotal,
+                'base_total_store' => $catTotal,
                 'products_components_list' => implode(',', $allComponentsProdIds[$sid] ?? []),
             ];
         }
@@ -529,7 +529,7 @@ class AutoPlannogrammaService
         $productTableJoinCondition = $type === self::TYPE_WRITE_OFFS ? 'wp.write_offs_id = w.id' : 'sp.check_id = s.id';
 
         $field = $type === self::TYPE_WRITE_OFFS ? 'w.date' : 's.date';
-        $base  = new \DateTime($dateFrom);
+        $base = new \DateTime($dateFrom);
         $months = [
             [
                 'between',
@@ -636,9 +636,9 @@ class AutoPlannogrammaService
             (clone $base)->modify('-1 year'),
         ];
 
-        $finalResult          = [];
-        $componentAdds        = [];
-        $componentAddsSumAll  = [];
+        $finalResult = [];
+        $componentAdds = [];
+        $componentAddsSumAll = [];
         $allComponentsProdIds = [];
 
         foreach ($storeIds as $sid) {
@@ -662,10 +662,10 @@ class AutoPlannogrammaService
                 $allComponentsProdIds[$sid] = array_unique($allComponentsProdIds[$sid]);
 
                 foreach ($sums as $sr) {
-                    $cat    = $sr['category'];
+                    $cat = $sr['category'];
                     $subcat = $sr['subcategory'];
                     $spec = $sr['species'];
-                    $val    = $sr['sum'];
+                    $val = $sr['sum'];
 
                     $componentAdds[$sid][$cat][$subcat][$spec] =
                         ($componentAdds[$sid][$cat][$subcat][$spec] ?? 0) + $val;
@@ -678,17 +678,17 @@ class AutoPlannogrammaService
 
 
         foreach ($result as $r) {
-            $sid       = $r['store_id'];
-            $cat       = $r['category'];
-            $subcat    = $r['subcategory'];
-            $spec      = $r['species'];
+            $sid = $r['store_id'];
+            $cat = $r['category'];
+            $subcat = $r['subcategory'];
+            $spec = $r['species'];
 
-            $specTotal  = (float)$r['total_sum'];
-            $subcatTotal  = (float)$r['totals_total'];
+            $specTotal = (float)$r['total_sum'];
+            $subcatTotal = (float)$r['totals_total'];
 
 
-            $addSubcat    = $componentAddsSumAll[$sid][$cat][$subcat] ?? 0.0;
-            $addSpecies = $componentAdds[$sid][$cat][$subcat][$spec]   ?? 0.0;
+            $addSubcat = $componentAddsSumAll[$sid][$cat][$subcat] ?? 0.0;
+            $addSpecies = $componentAdds[$sid][$cat][$subcat][$spec] ?? 0.0;
 
 
             $newSubcatTotal = $subcatTotal + $addSubcat;
@@ -700,16 +700,16 @@ class AutoPlannogrammaService
                 : 0.0;
 
             $finalResult[] = [
-                'store_id'                 => $sid,
-                'category'                 => $cat,
-                'subcategory'              => $subcat,
-                'species'                  => $spec ,
-                'old_total_sum'            => $specTotal,
-                'total_sum'                => $newSpecTotal,
-                'percent'                  => $percent,
-                'type'                     => $type,
-                'new_total_store'          => $newSubcatTotal,
-                'base_total_store'         => $subcatTotal,
+                'store_id' => $sid,
+                'category' => $cat,
+                'subcategory' => $subcat,
+                'species' => $spec,
+                'old_total_sum' => $specTotal,
+                'total_sum' => $newSpecTotal,
+                'percent' => $percent,
+                'type' => $type,
+                'new_total_store' => $newSubcatTotal,
+                'base_total_store' => $subcatTotal,
                 'products_components_list' => implode(',', $allComponentsProdIds[$sid] ?? []),
             ];
         }
@@ -816,10 +816,10 @@ 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'
+     * @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<int, array>         массив строк: [
      *    ['week'=>1,'store_id'=>...,'category'=>...,'subcategory'=>...,'species'=>...,'sum'=>...],
      *    ...
@@ -830,16 +830,17 @@ class AutoPlannogrammaService
         ?array $filters = null,
         ?array $productFilter = null,
         string $type = 'sales'
-    ): array {
-        [$yearStr, $monthStr ] = explode('-', $monthYear);
+    ): array
+    {
+        [$yearStr, $monthStr] = explode('-', $monthYear);
         $month = (int)$monthStr;
-        $year  = (int)$yearStr;
+        $year = (int)$yearStr;
 
         $dateFrom = strtotime(sprintf('%04d-%02d-01 00:00:00', $year, $month));
-        $dateTo   = strtotime('+1 month -1 second', $dateFrom);
+        $dateTo = strtotime('+1 month -1 second', $dateFrom);
 
-        $stores   = $this->getVisibleStores();
-        $storeIds = array_map(fn($s)=>$s->id, $stores);
+        $stores = $this->getVisibleStores();
+        $storeIds = array_map(fn($s) => $s->id, $stores);
         if (!empty($filters['store_id'])) {
             $storeIds = array_intersect($storeIds, [(int)$filters['store_id']]);
         }
@@ -860,13 +861,13 @@ class AutoPlannogrammaService
                 $wkEnd = $dateTo;
             }
             $periodStart = max($wkStart, $dateFrom);
-            $periodEnd   = min($wkEnd, $dateTo);
-            $daysInMonth   = floor(($periodEnd - $periodStart) / 86400) + 1;
+            $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),
+                    'end' => date('Y-m-d 23:59:59', $wkEnd),
                 ];
             }
         }
@@ -876,12 +877,12 @@ class AutoPlannogrammaService
         foreach ($weekRanges as $range) {
             $exprWeek = new Expression((string)$range['index']);
             $query = (new Query())->select([
-                'week'        => $exprWeek,
-                'store_id'    => 'ex.entity_id',
-                'category'    => 'p1c.category',
+                'week' => $exprWeek,
+                'store_id' => 'ex.entity_id',
+                'category' => 'p1c.category',
                 'subcategory' => 'p1c.subcategory',
-                'species'     => 'p1c.species',
-                'total_sum'   => new Expression(
+                'species' => 'p1c.species',
+                'total_sum' => new Expression(
                     $type === 'writeOffs'
                         ? 'SUM(CAST(wop.summ AS NUMERIC))'
                         : 'SUM(sp.summ)'
@@ -889,10 +890,10 @@ class AutoPlannogrammaService
             ]);
 
             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')
+                $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) {
@@ -900,9 +901,9 @@ class AutoPlannogrammaService
                 }
             } 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')
+                    ->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) {
@@ -912,17 +913,17 @@ class AutoPlannogrammaService
 
             $query->andWhere(['ex.entity_id' => $storeIds])
                 ->andWhere(['<>', 'p1c.species', ''])
-                ->groupBy(['week','ex.entity_id','p1c.category','p1c.subcategory','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'],
+                    'week' => $row['week'],
+                    'store_id' => $row['store_id'],
+                    'category' => $row['category'],
                     'subcategory' => $row['subcategory'],
-                    'species'     => $row['species'],
-                    'sum'         => (float)$row['total_sum'],
+                    'species' => $row['species'],
+                    'sum' => (float)$row['total_sum'],
                 ];
             }
         }
@@ -934,16 +935,16 @@ class AutoPlannogrammaService
      * Возвращает диапазоны недель (index, start, end) для указанного года и месяца,
      * взятые по правилу «неделя считается, если в неё входит ≥4 дня из этого месяца».
      *
-     * @param int $year  Год (например, 2025)
+     * @param int $year Год (например, 2025)
      * @param int $month Месяц (1–12)
      * @return array<array{index:int, start:string, end:string}>
      */
     public function getWeekRangesForMonth(int $year, int $month): array
     {
         $dateFrom = strtotime(sprintf('%04d-%02d-01 00:00:00', $year, $month));
-        $dateTo   = strtotime('+1 month -1 second', $dateFrom);
+        $dateTo = strtotime('+1 month -1 second', $dateFrom);
 
-        $dayOfWeek   = (int)date('N', $dateFrom);
+        $dayOfWeek = (int)date('N', $dateFrom);
         $firstMonday = $dayOfWeek === 1
             ? $dateFrom
             : strtotime('next monday', $dateFrom);
@@ -953,14 +954,14 @@ class AutoPlannogrammaService
             $wkEnd = $wkStart + 6 * 86400;
 
             $periodStart = max($wkStart, $dateFrom);
-            $periodEnd   = min($wkEnd,   $dateTo);
+            $periodEnd = min($wkEnd, $dateTo);
             $daysInMonth = floor(($periodEnd - $periodStart) / 86400) + 1;
 
             if ($daysInMonth >= 4) {
                 $ranges[] = [
                     'index' => (int)date('W', $wkStart),              // ISO-неделя от $wkStart
                     'start' => date('Y-m-d H:i:s', $wkStart),         // “год-месяц-день 00:00:00”
-                    'end'   => date('Y-m-d 23:59:59', $wkEnd),        // “год-месяц-день 23:59:59”
+                    'end' => date('Y-m-d 23:59:59', $wkEnd),        // “год-месяц-день 23:59:59”
                 ];
             }
         }
@@ -969,15 +970,16 @@ class AutoPlannogrammaService
     }
 
     public function getHistoricalSpeciesShareByWeek(
-        string     $monthYear,
-        ?array     $filters = null,
-        string     $type    = self::TYPE_SALES
-    ): array {
+        string $monthYear,
+        ?array $filters = null,
+        string $type = self::TYPE_SALES
+    ): array
+    {
         [$yearStr, $monthStr, $day] = explode('-', $monthYear);
-        $year  = (int)$yearStr;
+        $year = (int)$yearStr;
         $month = (int)$monthStr;
 
-        $stores   = $this->getVisibleStores();
+        $stores = $this->getVisibleStores();
         $storeIds = array_map(fn($s) => $s->id, $stores);
         if (!empty($filters['store_id'])) {
             $storeIds = array_intersect($storeIds, [(int)$filters['store_id']]);
@@ -991,30 +993,30 @@ class AutoPlannogrammaService
             : 'SUM(sp.quantity)';
 
         // Таблицы и условия join
-        $fromTable  = $type === self::TYPE_WRITE_OFFS ? ['w' => 'write_offs'] : ['s' => 'sales'];
-        $alias      = key($fromTable);
+        $fromTable = $type === self::TYPE_WRITE_OFFS ? ['w' => 'write_offs'] : ['s' => 'sales'];
+        $alias = key($fromTable);
 
-        $productTableJoin               = $type === self::TYPE_WRITE_OFFS ? ['wp' => 'write_offs_products'] : ['sp' => 'sales_products'];
-        $productAlias                   = key($productTableJoin); // 'wp' или 'sp'
-        $productTableJoinCondition      = $type === self::TYPE_WRITE_OFFS ? 'wp.write_offs_id = w.id' : 'sp.check_id = s.id';
-        $storeJoinCondition             = $type === self::TYPE_WRITE_OFFS ? 'ex.export_val = w.store_id' : 'ex.export_val = s.store_id_1c';
+        $productTableJoin = $type === self::TYPE_WRITE_OFFS ? ['wp' => 'write_offs_products'] : ['sp' => 'sales_products'];
+        $productAlias = key($productTableJoin); // 'wp' или 'sp'
+        $productTableJoinCondition = $type === self::TYPE_WRITE_OFFS ? 'wp.write_offs_id = w.id' : 'sp.check_id = s.id';
+        $storeJoinCondition = $type === self::TYPE_WRITE_OFFS ? 'ex.export_val = w.store_id' : 'ex.export_val = s.store_id_1c';
 
 
         $monthQtyBySpecies = [];
-        $weekQtyByPos      = [];
+        $weekQtyByPos = [];
 
         foreach ([$year - 2, $year - 1] as $histYear) {
 
             $histMonthStart = sprintf('%04d-%02d-01 00:00:00', $histYear, $month);
-            $histMonthEnd   = date('Y-m-d 23:59:59', strtotime("$histMonthStart +1 month -1 second"));
+            $histMonthEnd = date('Y-m-d 23:59:59', strtotime("$histMonthStart +1 month -1 second"));
 
             $monthQuery = (new Query())
                 ->select([
-                    'store_id'    => 'ex.entity_id',
-                    'category'    => 'p1c.category',
+                    'store_id' => 'ex.entity_id',
+                    'category' => 'p1c.category',
                     'subcategory' => 'p1c.subcategory',
-                    'species'     => 'p1c.species',
-                    'month_sum'   => new Expression($sumExpression),
+                    'species' => 'p1c.species',
+                    'month_sum' => new Expression($sumExpression),
                 ])
                 ->from($fromTable)
                 ->leftJoin($productTableJoin, $productTableJoinCondition)
@@ -1030,11 +1032,11 @@ class AutoPlannogrammaService
 
             $monthRows = $monthQuery->all();
             foreach ($monthRows as $row) {
-                $sid      = $row['store_id'];
-                $cat      = $row['category'];
-                $sub      = $row['subcategory'];
-                $spec     = $row['species'];
-                $qty      = (float)$row['month_sum'];
+                $sid = $row['store_id'];
+                $cat = $row['category'];
+                $sub = $row['subcategory'];
+                $spec = $row['species'];
+                $qty = (float)$row['month_sum'];
 
                 $monthQtyBySpecies[$sid][$cat][$sub][$spec] =
                     ($monthQtyBySpecies[$sid][$cat][$sub][$spec] ?? 0.0) + $qty;
@@ -1061,11 +1063,11 @@ class AutoPlannogrammaService
 
                 $weekQuery = (new Query())
                     ->select([
-                        'store_id'    => 'ex.entity_id',
-                        'category'    => 'p1c.category',
+                        'store_id' => 'ex.entity_id',
+                        'category' => 'p1c.category',
                         'subcategory' => 'p1c.subcategory',
-                        'species'     => 'p1c.species',
-                        'week_sum'    => new Expression($sumExpression),
+                        'species' => 'p1c.species',
+                        'week_sum' => new Expression($sumExpression),
                     ])
                     ->from($fromTable)
                     ->leftJoin($productTableJoin, $productTableJoinCondition)
@@ -1079,18 +1081,18 @@ class AutoPlannogrammaService
                         "{$alias}.date BETWEEN :wstart AND :wend",
                         [
                             ':wstart' => $startDt->format('Y-m-d H:i:s'),
-                            ':wend'   => $endDt->format('Y-m-d H:i:s'),
+                            ':wend' => $endDt->format('Y-m-d H:i:s'),
                         ]
                     ))
                     ->groupBy(['ex.entity_id', 'p1c.category', 'p1c.subcategory', 'p1c.species']);
 
                 $weekRows = $weekQuery->all();
                 foreach ($weekRows as $row) {
-                    $sid      = $row['store_id'];
-                    $cat      = $row['category'];
-                    $sub      = $row['subcategory'];
-                    $spec     = $row['species'];
-                    $qty      = (float)$row['week_sum'];
+                    $sid = $row['store_id'];
+                    $cat = $row['category'];
+                    $sub = $row['subcategory'];
+                    $spec = $row['species'];
+                    $qty = (float)$row['week_sum'];
 
                     if (!isset($weekQtyByPos[$weekPos])) {
                         $weekQtyByPos[$weekPos] = [];
@@ -1124,7 +1126,7 @@ class AutoPlannogrammaService
 
         $result = [];
         foreach ($targetRanges as $posIndex => $range) {
-            $weekPos       = $posIndex + 1;
+            $weekPos = $posIndex + 1;
             $isoWeekNumber = $range['index'];
 
             if (!isset($shareByPos[$weekPos])) {
@@ -1135,12 +1137,12 @@ class AutoPlannogrammaService
                     foreach ($bySub as $sub => $bySpec) {
                         foreach ($bySpec as $spec => $share) {
                             $result[] = [
-                                'store_id'    => $sid,
-                                'category'    => $cat,
+                                'store_id' => $sid,
+                                'category' => $cat,
                                 'subcategory' => $sub,
-                                'species'     => $spec,
-                                'week'        => $isoWeekNumber,
-                                'share'       => $share,
+                                'species' => $spec,
+                                'week' => $isoWeekNumber,
+                                'share' => $share,
                                 'sumMonth' => $monthQtyBySpecies[$sid][$cat][$sub][$spec] ?? 0.0,
                                 'sumWeek' => $weekQtyByPos[$weekPos][$sid][$cat][$sub][$spec] ?? 0.0
                             ];
@@ -1176,15 +1178,16 @@ class AutoPlannogrammaService
     public function calculateWeeklyProductForecastPieces(
         array $productForecastSpecies,
         array $weeklySales
-    ): array {
+    ): array
+    {
 
         $forecastMap = [];
         foreach ($productForecastSpecies as $item) {
-            $sid       = $item['store_id'];
-            $cat       = $item['category'];
-            $sub       = $item['subcategory'];
-            $spec      = $item['species'];
-            $pid       = $item['product_id'];
+            $sid = $item['store_id'];
+            $cat = $item['category'];
+            $sub = $item['subcategory'];
+            $spec = $item['species'];
+            $pid = $item['product_id'];
             $piecesMon = (float)$item['product_sales_pieces'];
 
             $forecastMap[$sid][$cat][$sub][$spec][$pid] = $piecesMon;
@@ -1193,15 +1196,15 @@ class AutoPlannogrammaService
         $result = [];
 
         foreach ($weeklySales as $w) {
-            $sid   = $w['store_id'];
-            $cat   = $w['category'];
-            $sub   = $w['subcategory'];
-            $spec  = $w['species'];
-            $week  = $w['week'];
+            $sid = $w['store_id'];
+            $cat = $w['category'];
+            $sub = $w['subcategory'];
+            $spec = $w['species'];
+            $week = $w['week'];
             $wShare = (float)$w['share'];
 
             if (
-                ! isset(
+                !isset(
                     $forecastMap[$sid],
                     $forecastMap[$sid][$cat],
                     $forecastMap[$sid][$cat][$sub],
@@ -1217,12 +1220,12 @@ class AutoPlannogrammaService
                 $forecastWeekPieces = round($piecesMon * $wShare, 2);
 
                 $result[] = [
-                    'week'                 => $week,
-                    'store_id'             => $sid,
-                    'category'             => $cat,
-                    'subcategory'          => $sub,
-                    'species'              => $spec,
-                    'product_id'           => $pid,
+                    'week' => $week,
+                    'store_id' => $sid,
+                    'category' => $cat,
+                    'subcategory' => $sub,
+                    'species' => $spec,
+                    'product_id' => $pid,
                     'forecast_month_pieces' => $piecesMon,
                     'forecast_week_pieces' => $forecastWeekPieces,
                 ];
@@ -1248,16 +1251,16 @@ class AutoPlannogrammaService
 
             if (!isset($grouped[$key])) {
                 $grouped[$key] = [
-                    'store_id'               => $row['store_id'],
-                    'category'               => $row['category'],
-                    'subcategory'            => $row['subcategory'],
-                    'species'                => $row['species'],
-                    'product_id'             => $row['product_id'],
-                    'forecast_month_pieces'  => $row['forecast_month_pieces'],
+                    'store_id' => $row['store_id'],
+                    'category' => $row['category'],
+                    'subcategory' => $row['subcategory'],
+                    'species' => $row['species'],
+                    'product_id' => $row['product_id'],
+                    'forecast_month_pieces' => $row['forecast_month_pieces'],
                 ];
             }
 
-            $weekNum   = (int)$row['week'];
+            $weekNum = (int)$row['week'];
             $fieldName = 'week' . $weekNum;
 
             $grouped[$key][$fieldName] = (float)$row['forecast_week_pieces'];
@@ -1269,9 +1272,9 @@ class AutoPlannogrammaService
         }
         $allWeekFields = array_keys($allWeekFields);
 
-          foreach ($grouped as &$group) {
+        foreach ($grouped as &$group) {
             foreach ($allWeekFields as $fieldName) {
-                if (! isset($group[$fieldName])) {
+                if (!isset($group[$fieldName])) {
                     $group[$fieldName] = 0.0;
                 }
             }
@@ -1285,10 +1288,10 @@ class AutoPlannogrammaService
     /**
      * Исторический недельный отчёт и доли по видам с учётом store_id.
      *
-     * @param string      $monthYear     месяц-год в формате MM-YYYY
-     * @param array|null  $filters
-     * @param array|null  $productFilter
-     * @param string      $type
+     * @param string $monthYear месяц-год в формате MM-YYYY
+     * @param array|null $filters
+     * @param array|null $productFilter
+     * @param string $type
      * @return array{ 'weeksData': array<int, array> }
      *   возвращает плоский список строк:
      *   [
@@ -1301,30 +1304,31 @@ class AutoPlannogrammaService
         ?array $filters = null,
         ?array $productFilter = null,
         string $type = 'sales'
-    ): array {
+    ): array
+    {
         [$monthStr, $yearStr] = explode('-', $monthYear);
         $month = (int)$monthStr;
-        $year  = (int)$yearStr;
+        $year = (int)$yearStr;
         $yearData = [];
         $historical = [];
         for ($yr = $year - 2; $yr < $year; $yr++) {
-            $mYear = sprintf('%04d-%02d',$yr, $month);
+            $mYear = sprintf('%04d-%02d', $yr, $month);
 
             $weeklyData = $this->getWeeklySpeciesDataForMonth(
                 $mYear, $filters, $productFilter, $type
             );
             $yearData[$mYear] = $weeklyData;
             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]   ??= [];
+                $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;
@@ -1332,21 +1336,21 @@ class AutoPlannogrammaService
         }
 
         $dateFrom = sprintf('%04d-%02d-01 00:00:00', $year, $month);
-        $dateTo   = date('Y-m-d H:i:s', strtotime("$dateFrom +1 month -1 second"));
+        $dateTo = date('Y-m-d H:i:s', strtotime("$dateFrom +1 month -1 second"));
         $monthWeighted = $this->getMonthSpeciesShareOrWriteOff(
             $dateFrom, $filters, $type
         );
         $monthMap = [];
         foreach ($monthWeighted as $m) {
-            $sid      = $m['store_id'];
-            $cat      = $m['category'];
-            $sub      = $m['subcategory'];
-            $spec     = $m['species'];
+            $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] ??= [];
+            $monthMap[$sid][$cat] ??= [];
+            $monthMap[$sid][$cat][$sub] ??= [];
             $monthMap[$sid][$cat][$sub][$spec] =
                 ($monthMap[$sid][$cat][$sub][$spec] ?? 0) + $sumMonth;
         }
@@ -1360,7 +1364,7 @@ class AutoPlannogrammaService
             foreach ($byCat as $cat => $bySub) {
                 foreach ($bySub as $sub => $bySpec) {
                     foreach ($bySpec as $spec => $value) {
-                        $speciesList[] = compact('sid','cat','sub','spec');
+                        $speciesList[] = compact('sid', 'cat', 'sub', 'spec');
                     }
                 }
             }
@@ -1369,9 +1373,9 @@ class AutoPlannogrammaService
 
         $rows = [];
         foreach ($speciesList as $comb) {
-            $sid  = $comb['sid'];
-            $cat  = $comb['cat'];
-            $sub  = $comb['sub'];
+            $sid = $comb['sid'];
+            $cat = $comb['cat'];
+            $sub = $comb['sub'];
             $spec = $comb['spec'];
 
             $sumMonth = $monthMap[$sid][$cat][$sub][$spec] ?? 0;
@@ -1384,13 +1388,13 @@ class AutoPlannogrammaService
                 $percent = $sumWeek > 0 ? round($sumWeek / $sumMonth, 4) : null;
 
                 $rows[] = [
-                    'week'        => $week,
-                    'store_id'    => $sid,
-                    'category'    => $cat,
+                    'week' => $week,
+                    'store_id' => $sid,
+                    'category' => $cat,
                     'subcategory' => $sub,
-                    'species'     => $spec,
-                    'sumWeek'    => $sumWeek,
-                    'percent'     => $percent,
+                    'species' => $spec,
+                    'sumWeek' => $sumWeek,
+                    'percent' => $percent,
                     'sumMonth' => $sumMonth
                 ];
             }
@@ -1416,7 +1420,7 @@ class AutoPlannogrammaService
             }
         }
 
-        return  $rows;
+        return $rows;
     }
 
 
@@ -1432,39 +1436,40 @@ class AutoPlannogrammaService
     public function calculateWeeklySpeciesGoals(
         array $weeksShareData,
         array $monthSpeciesGoals
-    ): array {
+    ): array
+    {
         $monthSpeciesGoalsMap = [];
         foreach ($monthSpeciesGoals as $monthSpeciesGoal) {
             $monthSpeciesGoalsMap[$monthSpeciesGoal['store_id']]
             [$monthSpeciesGoal['category']]
             [$monthSpeciesGoal['subcategory']]
-            [$monthSpeciesGoal['species']] = $monthSpeciesGoal['goal'] ;
+            [$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'];
+            $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);
+                $weeklyGoal = round($percent * $monthlyGoal, 4);
             }
 
             $result[] = [
-                'week'         => $week,
-                'store_id'     => $sid,
-                'category'     => $cat,
-                'subcategory'  => $sub,
-                'species'      => $spec,
-                'percent'      => $percent,
+                'week' => $week,
+                'store_id' => $sid,
+                'category' => $cat,
+                'subcategory' => $sub,
+                'species' => $spec,
+                'percent' => $percent,
                 'monthly_goal' => $monthlyGoal,
-                'weekly_goal'  => $weeklyGoal,
+                'weekly_goal' => $weeklyGoal,
             ];
         }
         return $result;
@@ -1473,8 +1478,8 @@ class AutoPlannogrammaService
     /**
      * Возвращает дату понедельника ISO-недели в формате YYYY-MM-DD
      *
-     * @param int $year  ISO-год (может отличаться от календарного в границах года)
-     * @param int $week  номер ISO-недели (1–53)
+     * @param int $year ISO-год (может отличаться от календарного в границах года)
+     * @param int $week номер ISO-недели (1–53)
      * @return string    дата понедельника, например '2025-03-10'
      */
     public static function getIsoWeekStart(int $year, int $week): string
@@ -1510,7 +1515,7 @@ class AutoPlannogrammaService
                 : BouquetComposition::REGION_NN;
         }
 
-        $pricesMap =  self::buildPricesMap($productsIds, $region);
+        $pricesMap = self::buildPricesMap($productsIds, $region);
 
         foreach ($pricesMap as $id => $price) {
             if ($goal == 0 || (float)$price == 0) {
@@ -1539,8 +1544,8 @@ class AutoPlannogrammaService
     /**
      * Общий расчёт плана для заданной категории товаров без истории.
      *
-     * @param int    $storeId
-     * @param string $yearMonth   строка "YYYY-MM", например "2025-03"
+     * @param int $storeId
+     * @param string $yearMonth строка "YYYY-MM", например "2025-03"
      * @param string $category
      * @param string|null $subcategory
      * @param string|null $species
@@ -1676,7 +1681,8 @@ class AutoPlannogrammaService
         return $result;
     }
 
-    public function mapGoalsBySpecies(array $rows): array {
+    public function mapGoalsBySpecies(array $rows): array
+    {
         $mapped = [];
         foreach ($rows as $row) {
             $mapped[$row['store_id']][$row['category']][$row['subcategory']][$row['species']] = $row['goal'];
@@ -1684,7 +1690,8 @@ class AutoPlannogrammaService
         return $mapped;
     }
 
-    public function subtractSpeciesGoals(array $data, array $bouquetForecast, array $noHistory): array {
+    public function subtractSpeciesGoals(array $data, array $bouquetForecast, array $noHistory): array
+    {
         $bouquetForecastMap = $this->mapGoalsBySpecies($bouquetForecast);
         $noHistoryMap = $this->mapGoalsBySpecies($noHistory);
         $result = [];
@@ -1724,7 +1731,8 @@ class AutoPlannogrammaService
         string $year,
         array  $speciesGoals,
         array  $productSalesShare
-    ): array {
+    ): array
+    {
         $result = [];
 
         if (empty($speciesGoals)) {
@@ -1746,7 +1754,7 @@ class AutoPlannogrammaService
                 : BouquetComposition::REGION_NN;
         }
 
-        $pricesMap =  self::buildPricesMap(array_keys($productSalesShare), $region);
+        $pricesMap = self::buildPricesMap(array_keys($productSalesShare), $region);
 
         foreach ($productSalesShare as $productId => $data) {
             $share = $data['share'] ?? 0.0;
@@ -1760,12 +1768,12 @@ class AutoPlannogrammaService
             }
 
             $storeId = $data['store_id'];
-            $cat     = $data['category'];
-            $sub     = $data['subcategory'];
-            $spec    = $data['species'];
-            $price   = $pricesMap[$productId];
+            $cat = $data['category'];
+            $sub = $data['subcategory'];
+            $spec = $data['species'];
+            $price = $pricesMap[$productId];
             if (
-                ! isset(
+                !isset(
                     $goalsMap[$storeId],
                     $goalsMap[$storeId][$cat],
                     $goalsMap[$storeId][$cat][$sub],
@@ -1804,25 +1812,26 @@ class AutoPlannogrammaService
      *
      * Объединяет прогнозы без истории и с историей для полного списка товаров.
      *
-     * @param array $pieciesForecastProductsNoHistyory  Результат calculateSpeciesForecastForProductsWithoutHistory
+     * @param array $pieciesForecastProductsNoHistyory Результат calculateSpeciesForecastForProductsWithoutHistory
      * @param array $pieciesForecastProductWithHistory Результат calculateProductForecastInPiecesProductsWithHistory
      * @return array
      */
     public function calculateProductForecastShare(
         array $pieciesForecastProductsNoHistyory,
         array $pieciesForecastProductWithHistory
-    ): array {
+    ): array
+    {
         $groupedForecasts = [];
 
         // Обработка товаров без истории
         foreach ($pieciesForecastProductsNoHistyory as $group) {
             $base = [
-                'store_id'    => $group['store_id'],
-                'month'       => $group['month'],
-                'year'        => $group['year'],
-                'category'    => $group['category'],
+                'store_id' => $group['store_id'],
+                'month' => $group['month'],
+                'year' => $group['year'],
+                'category' => $group['category'],
                 'subcategory' => $group['subcategory'],
-                'species'     => $group['species'],
+                'species' => $group['species'],
             ];
 
             foreach ($group['forecasts'] as $productId => $forecast) {
@@ -1832,9 +1841,9 @@ class AutoPlannogrammaService
 
                 $groupedForecasts[$key]['meta'] = $base;
                 $groupedForecasts[$key]['products'][$productId] = [
-                    'product_id'       => $productId,
-                    'forecast_pieces'  => (float)$forecast,
-                    'history_status'   => 'No history',
+                    'product_id' => $productId,
+                    'forecast_pieces' => (float)$forecast,
+                    'history_status' => 'No history',
                 ];
             }
         }
@@ -1846,18 +1855,18 @@ class AutoPlannogrammaService
             ]);
 
             $groupedForecasts[$key]['meta'] = [
-                'store_id'    => $item['store_id'],
-                'month'       => $item['month'],
-                'year'        => $item['year'],
-                'category'    => $item['category'],
+                'store_id' => $item['store_id'],
+                'month' => $item['month'],
+                'year' => $item['year'],
+                'category' => $item['category'],
                 'subcategory' => $item['subcategory'],
-                'species'     => $item['species'],
+                'species' => $item['species'],
             ];
 
             $groupedForecasts[$key]['products'][$item['product_id']] = [
-                'product_id'      => $item['product_id'],
+                'product_id' => $item['product_id'],
                 'forecast_pieces' => (float)$item['forecast_pieces'],
-                'history_status'  => 'With history',
+                'history_status' => 'With history',
             ];
         }
 
@@ -1877,10 +1886,10 @@ class AutoPlannogrammaService
                 $share = round($product['forecast_pieces'] / $totalForecast, 4);
 
                 $result[] = array_merge($meta, [
-                    'product_id'      => $product['product_id'],
+                    'product_id' => $product['product_id'],
                     'forecast_pieces' => $product['forecast_pieces'],
-                    'share'           => $share,
-                    'history_status'  => $product['history_status'],
+                    'share' => $share,
+                    'history_status' => $product['history_status'],
                 ]);
             }
         }
@@ -1891,14 +1900,15 @@ class AutoPlannogrammaService
     /**
      * Рассчитывает продажи по каждому товару внутри вида на основе долей и очищенной цели вида.
      *
-     * @param array $productShares  Результат calculateProductForecastShare
-     * @param array $speciesGoals   Массив целей по видам с ключом 'goal'
+     * @param array $productShares Результат calculateProductForecastShare
+     * @param array $speciesGoals Массив целей по видам с ключом 'goal'
      * @return array
      */
     public static function calculateProductSalesBySpecies(
         array $productShares,
         array $speciesGoals
-    ): array {
+    ): array
+    {
         $result = [];
         $goalsMap = [];
         foreach ($speciesGoals as $item) {
@@ -1919,7 +1929,7 @@ class AutoPlannogrammaService
             ->all();
         $products = ArrayHelper::getColumn($productShares, 'product_id');
 
-        $pricesMap =  self::buildPricesMap($products);
+        $pricesMap = self::buildPricesMap($products);
 
         foreach ($productShares as $shareItem) {
             $storeId = $shareItem['store_id'];
@@ -1939,21 +1949,21 @@ class AutoPlannogrammaService
                 $shareItem['species']
             ]);
 
-            $cleanGoal     = $goalsMap[$key] ?? 0;
+            $cleanGoal = $goalsMap[$key] ?? 0;
             $productSales = $shareItem['share'] * $cleanGoal;
 
             $productSalesPieces = round($productSales / $price, 2);
 
             $result[] = [
-                'store_id'      => $shareItem['store_id'],
-                'month'         => $shareItem['month'] ?? null,
-                'year'          => $shareItem['year'] ?? null,
-                'category'      => $shareItem['category'],
-                'subcategory'   => $shareItem['subcategory'],
-                'species'       => $shareItem['species'],
-                'product_id'    => $shareItem['product_id'],
+                'store_id' => $shareItem['store_id'],
+                'month' => $shareItem['month'] ?? null,
+                'year' => $shareItem['year'] ?? null,
+                'category' => $shareItem['category'],
+                'subcategory' => $shareItem['subcategory'],
+                'species' => $shareItem['species'],
+                'product_id' => $shareItem['product_id'],
                 'forecast_pieces' => $shareItem['forecast_pieces'],
-                'share'          => round($shareItem['share'], 4),
+                'share' => round($shareItem['share'], 4),
                 'history_status' => $shareItem['history_status'],
                 'cleanGoal' => $cleanGoal,
                 'product_sales' => round($productSales, 2),
@@ -1993,7 +2003,7 @@ class AutoPlannogrammaService
 
         $monthStart = sprintf('%04d-%02d-01 00:00:00', $year, $month);
         $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);
-        $monthEnd   = sprintf('%04d-%02d-%02d 23:59:59', $year, $month, $daysInMonth);
+        $monthEnd = sprintf('%04d-%02d-%02d 23:59:59', $year, $month, $daysInMonth);
         $componentProducts = [];
 
         if ($type == self::TYPE_SALES) {
@@ -2021,8 +2031,8 @@ class AutoPlannogrammaService
                     ['nom' => Products1cNomenclature::tableName()],
                     'nom.id = sp.product_id'
                 )
-                ->andWhere(['s.store_id'   => $storeId])
-                ->andWhere(['not', ['s.operation'   => ['Удален', 'Удаление']]])
+                ->andWhere(['s.store_id' => $storeId])
+                ->andWhere(['not', ['s.operation' => ['Удален', 'Удаление']]])
                 ->andWhere(['between', 's.date', $monthStart, $monthEnd])
                 ->andWhere(['not', ['p1c.components' => '']])
                 ->asArray()
@@ -2066,7 +2076,7 @@ class AutoPlannogrammaService
         }
 
         $componentGuids = [];
-        $componentDataRecords       = [];
+        $componentDataRecords = [];
         foreach ($componentProducts as $cp) {
             $js = trim($cp['components']);
             if ($js === '' || $js[0] !== '{') {
@@ -2083,15 +2093,15 @@ class AutoPlannogrammaService
                 }
                 $componentGuids[$guid] = true;
                 $componentDataRecords[] = [
-                    'record_id'        => $cp['id'] ?? $cp['write_off_id'],
-                    'sale_date'        => $cp['date'] ?? $cp['write_off_date'],
-                    'product_id'       => $cp['product_id'],
-                    'product_name'     => $cp['name'] ?? $cp['product_name'],
+                    'record_id' => $cp['id'] ?? $cp['write_off_id'],
+                    'sale_date' => $cp['date'] ?? $cp['write_off_date'],
+                    'product_id' => $cp['product_id'],
+                    'product_name' => $cp['name'] ?? $cp['product_name'],
                     'quantity_product' => $cp['quantity_product'],
-                    'component_guid'   => $guid,
-                    'quantity'         => $qty,
-                    'type'             => $type,
-                    'operation'        => $cp['operation'] ?? '',
+                    'component_guid' => $guid,
+                    'quantity' => $qty,
+                    'type' => $type,
+                    'operation' => $cp['operation'] ?? '',
                 ];
             }
         }
@@ -2111,7 +2121,7 @@ class AutoPlannogrammaService
             ->andWhere(['region_id' => $region])
             ->andWhere(['product_id' => array_values(ArrayHelper::getColumn($nomenclatures, 'id'))])
             ->andWhere(['<=', 'date_from', $monthEnd])
-            ->andWhere(['>=', 'date_to',   $monthStart])
+            ->andWhere(['>=', 'date_to', $monthStart])
             ->orderBy(['date_from' => SORT_DESC])
             ->all();
 
@@ -2123,16 +2133,16 @@ class AutoPlannogrammaService
         $result = [];
 
         foreach ($componentDataRecords as $componentDataRecord) {
-            $guid  = $componentDataRecord['component_guid'];
-            $nomenclatureData     = $nomenclatures[$guid] ?? null;
-            $productId   = $nomenclatureData?->id;
+            $guid = $componentDataRecord['component_guid'];
+            $nomenclatureData = $nomenclatures[$guid] ?? null;
+            $productId = $nomenclatureData?->id;
             $price = 0;
             $dailyPrices = [];
             foreach ($pricesByProduct[$productId] ?? [] as $priceRecordForProduct) {
                 if (defined($heliumConstant) && $productId == constant($heliumConstant)) {
                     $saleDay = (new \DateTime($componentDataRecord['sale_date']))->format('Y-m-d');
                     $fromDay = (new \DateTime($priceRecordForProduct->date_from))->modify('-1 day')->format('Y-m-d');
-                    $toDay   = (new \DateTime($priceRecordForProduct->date_to  ))->modify('+1 day')->format('Y-m-d');
+                    $toDay = (new \DateTime($priceRecordForProduct->date_to))->modify('+1 day')->format('Y-m-d');
 
                     if ($fromDay <= $saleDay && $saleDay <= $toDay) {
                         $dailyPrices[] = (float)$priceRecordForProduct->price;
@@ -2152,23 +2162,23 @@ class AutoPlannogrammaService
             $costComponent = $componentDataRecord['quantity'] * $price;
 
             $result[] = [
-                'store_id'             => $storeId,
-                'record_id'            => $componentDataRecord['record_id'],
-                'sale_date'            => $componentDataRecord['sale_date'],
-                'product_id'           => $componentDataRecord['product_id'],
-                'product_name'         => $componentDataRecord['product_name'],
-                'quantity_product'     => $componentDataRecord['quantity_product'],
-                'component_guid'       => $guid,
-                'component_name'       => $nomenclatureData?->name,
-                'component_category'   => $nomenclatureData?->category,
-                'component_subcategory'=> $nomenclatureData?->subcategory,
-                'component_species'    => $nomenclatureData?->species,
-                'quantity'             => $componentDataRecord['quantity'],
-                'price'                => $price,
-                'cost'                 => $cost,
-                'component_cost'       => $costComponent,
-                'type'                 => $type,
-                'operation'            => $componentDataRecord['operation'],
+                'store_id' => $storeId,
+                'record_id' => $componentDataRecord['record_id'],
+                'sale_date' => $componentDataRecord['sale_date'],
+                'product_id' => $componentDataRecord['product_id'],
+                'product_name' => $componentDataRecord['product_name'],
+                'quantity_product' => $componentDataRecord['quantity_product'],
+                'component_guid' => $guid,
+                'component_name' => $nomenclatureData?->name,
+                'component_category' => $nomenclatureData?->category,
+                'component_subcategory' => $nomenclatureData?->subcategory,
+                'component_species' => $nomenclatureData?->species,
+                'quantity' => $componentDataRecord['quantity'],
+                'price' => $price,
+                'cost' => $cost,
+                'component_cost' => $costComponent,
+                'type' => $type,
+                'operation' => $componentDataRecord['operation'],
             ];
         }
 
@@ -2176,17 +2186,16 @@ class AutoPlannogrammaService
     }
 
 
-
     public function sumProductsComponentsByGroup(array $items, string $type, string $group = 'category'): array
     {
         $aggregated = [];
 
         foreach ($items as $row) {
-            $storeId     = $row['store_id'];
-            $category    = $row['component_category'];
+            $storeId = $row['store_id'];
+            $category = $row['component_category'];
             $subcategory = $row['component_subcategory'];
-            $species     = $row['component_species'];
-            $operation   = $row['operation'] ?? null;
+            $species = $row['component_species'];
+            $operation = $row['operation'] ?? null;
 
             $cost = (float)$row['cost'];
 
@@ -2214,10 +2223,10 @@ class AutoPlannogrammaService
             if (!isset($aggregated[$key])) {
                 // базовая структура
                 $aggregated[$key] = [
-                    'store_id'  => $storeId,
-                    'category'  => $category,
-                    'sum'       => 0.0,
-                    'type'      => $type,
+                    'store_id' => $storeId,
+                    'category' => $category,
+                    'sum' => 0.0,
+                    'type' => $type,
                 ];
 
                 if ($group === 'subcategory' || $group === 'species') {
@@ -2250,7 +2259,7 @@ class AutoPlannogrammaService
         $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 ($speciesData as $store_id => $categoryData) {
             foreach ($categoryData as $category => $subcategoryData) {
                 foreach ($subcategoryData as $subcategory => $species) {
                     foreach ($species as $speciesInd => $row) {
@@ -2280,10 +2289,6 @@ class AutoPlannogrammaService
     }
 
 
-
-
-
-
     /**
      * Считает взвешенную долю категорий за целевой месяц:
      * берёт три предыдущих к «месяцу-цели» месяца (пропуская сразу предыдущий),
@@ -2334,7 +2339,6 @@ class AutoPlannogrammaService
             $end = date('Y-m-t 23:59:59', strtotime($start));
 
 
-
             $q = (new Query())
                 ->select([
                     'store_id' => 'ex.entity_id',
@@ -2416,9 +2420,9 @@ class AutoPlannogrammaService
             return [];
         }
         $month = (int)$dt->format('m');
-        $year  = (int)$dt->format('Y');
+        $year = (int)$dt->format('Y');
 
-        $stores  = $this->getVisibleStores();
+        $stores = $this->getVisibleStores();
         $storeIds = array_map(fn($s) => $s->id, $stores);
         if (!empty($filters['store_id'])) {
             $storeIds = array_intersect($storeIds, [(int)$filters['store_id']]);
@@ -2431,10 +2435,10 @@ class AutoPlannogrammaService
 
         $query = (new Query())
             ->select([
-                'store_id'     => 'ex.entity_id',
-                'subcategory'  => 'p1c.subcategory',
-                'category'     => 'p1c.category',
-                'total_sum'    => new Expression(
+                'store_id' => 'ex.entity_id',
+                'subcategory' => 'p1c.subcategory',
+                'category' => 'p1c.category',
+                'total_sum' => new Expression(
                     $type === 'writeOffs'
                         ? 'SUM(CAST(wop.summ AS NUMERIC))'
                         : 'SUM(sp.summ)'
@@ -2443,10 +2447,9 @@ class AutoPlannogrammaService
 
         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')
-
+                ->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(['in', new Expression('EXTRACT(YEAR FROM w.date)'), $years])
                 ->andWhere(['=', new Expression('EXTRACT(MONTH FROM w.date)'), $month]);
             if ($productFilter !== null) {
@@ -2454,9 +2457,9 @@ class AutoPlannogrammaService
             }
         } 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')
+                ->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(['in', new Expression('EXTRACT(YEAR FROM s.date)'), $years])
                 ->andWhere(['=', new Expression('EXTRACT(MONTH FROM s.date)'), $month]);
             if ($productFilter !== null) {
@@ -2483,14 +2486,14 @@ class AutoPlannogrammaService
 
         $result = [];
         foreach ($rows as $r) {
-            $sid   = $r['store_id'];
-            $cat   = $r['category'];
+            $sid = $r['store_id'];
+            $cat = $r['category'];
             $total = $sumByStoreCategory[$sid][$cat] ?: 1;
             $result[] = [
-                'store_id'         => $sid,
-                'category'         => $cat,
-                'subcategory'      => $r['subcategory'],
-                'total_sum'        => $r['total_sum'],
+                'store_id' => $sid,
+                'category' => $cat,
+                'subcategory' => $r['subcategory'],
+                'total_sum' => $r['total_sum'],
                 'percent_of_month' => round($r['total_sum'] / $total, 4),
             ];
         }
@@ -2507,14 +2510,14 @@ class AutoPlannogrammaService
     ): array
     {
         try {
-            $dt    = new \DateTime($dateFrom);
+            $dt = new \DateTime($dateFrom);
         } catch (\Exception $e) {
             return [];
         }
         $month = (int)$dt->format('m');
-        $year  = (int)$dt->format('Y');
+        $year = (int)$dt->format('Y');
 
-        $stores   = $this->getVisibleStores();
+        $stores = $this->getVisibleStores();
         $storeIds = array_map(fn($s) => $s->id, $stores);
         if (!empty($filters['store_id'])) {
             $storeIds = array_intersect($storeIds, [(int)$filters['store_id']]);
@@ -2526,11 +2529,11 @@ class AutoPlannogrammaService
         $years = [$year - 2, $year - 1];
 
         $query = (new Query())->select([
-            'store_id'   => 'ex.entity_id',
-            'category'   => 'p1c.category',
-            'subcategory'=> 'p1c.subcategory',
-            'species'    => 'p1c.species',
-            'total_sum'  => new Expression(
+            '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)'
@@ -2539,21 +2542,21 @@ class AutoPlannogrammaService
 
         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')
+                ->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(['IN', new Expression('EXTRACT(YEAR FROM w.date)'), $years])
-                ->andWhere(['=',  new Expression('EXTRACT(MONTH FROM w.date)'), $month]);
+                ->andWhere(['=', new Expression('EXTRACT(MONTH FROM w.date)'), $month]);
             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')
+                ->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(['IN', new Expression('EXTRACT(YEAR FROM s.date)'), $years])
-                ->andWhere(['=',  new Expression('EXTRACT(MONTH FROM s.date)'), $month]);
+                ->andWhere(['=', new Expression('EXTRACT(MONTH FROM s.date)'), $month]);
             if ($productFilter !== null) {
                 $query->andWhere(['sp.product_id' => $productFilter]);
             }
@@ -2583,15 +2586,15 @@ class AutoPlannogrammaService
 
         $result = [];
         foreach ($rows as $r) {
-            $sid   = $r['store_id'];
-            $sub   = $r['subcategory'];
+            $sid = $r['store_id'];
+            $sub = $r['subcategory'];
             $total = $sumByStoreSubcategory[$sid][$sub] ?: 1;
             $result[] = [
-                'store_id'         => $sid,
-                'category'         => $r['category'],
-                'subcategory'      => $sub,
-                'species'          => $r['species'],
-                'total_sum'        => (float)$r['total_sum'],
+                'store_id' => $sid,
+                'category' => $r['category'],
+                'subcategory' => $sub,
+                'species' => $r['species'],
+                'total_sum' => (float)$r['total_sum'],
                 'percent_of_month' => round($r['total_sum'] / $total, 4),
             ];
         }
@@ -2602,8 +2605,6 @@ class AutoPlannogrammaService
     // Недельные расчеты
 
 
-
-
     // альтернативные методы расчета списаний
 
     public function calculateFullGoalChainWeighted(array $filters): array
@@ -2620,8 +2621,8 @@ class AutoPlannogrammaService
 
         $monthSpeciesShare = $this->getMonthSpeciesShareOrWriteOff($datePlan, $filters);
         if ($filters['type'] === 'writeOffs') {
-            $salesSubShare        = $this->getMonthSubcategoryShareOrWriteOffWeighted($datePlan, $filters, null, 'sales');
-            $salesSubGoal         = $this->getMonthSubcategoryGoal($salesSubShare, $monthCategoryGoal);
+            $salesSubShare = $this->getMonthSubcategoryShareOrWriteOffWeighted($datePlan, $filters, null, 'sales');
+            $salesSubGoal = $this->getMonthSubcategoryGoal($salesSubShare, $monthCategoryGoal);
 
             $catGoalMap = [];
             foreach ($monthCategoryGoal as $row) {
@@ -2639,8 +2640,8 @@ class AutoPlannogrammaService
 
                 $writeShare = $row['percent_of_month'];
 
-                $writeGoal  = ($catGoalMap[$cat] ?? 0) * $writeShare;
-                $saleGoal   = $salesSubGoalMap[$cat][$sub] ?? 0;
+                $writeGoal = ($catGoalMap[$cat] ?? 0) * $writeShare;
+                $saleGoal = $salesSubGoalMap[$cat][$sub] ?? 0;
 
                 if ($saleGoal > 0 && $writeGoal > 0.1 * $saleGoal) {
                     $row['share'] = 0.1;
@@ -2654,7 +2655,7 @@ class AutoPlannogrammaService
         $monthSpeciesGoal = $this->getMonthSpeciesGoalDirty($monthSpeciesShare, $monthSubcategoryGoal);
         if ($filters['type'] === 'writeOffs') {
             $salesSpecShare = $this->getMonthSpeciesShareOrWriteOffWeighted($datePlan, $datePlan, $filters, null, 'sales');
-            $salesSpecGoal  = $this->getMonthSpeciesGoalDirty($salesSpecShare, $monthSubcategoryGoal);
+            $salesSpecGoal = $this->getMonthSpeciesGoalDirty($salesSpecShare, $monthSubcategoryGoal);
 
             $subGoalMap = [];
             foreach ($monthSubcategoryGoal as $row) {
@@ -2666,13 +2667,13 @@ class AutoPlannogrammaService
             }
 
             foreach ($monthSpeciesShare as &$row) {
-                $cat  = $row['category'];
-                $sub  = $row['subcategory'];
+                $cat = $row['category'];
+                $sub = $row['subcategory'];
                 $spec = $row['species'];
 
                 $writeShare = $row['percent_of_month'];
-                $writeGoal  = ($subGoalMap[$cat][$sub] ?? 0) * $writeShare;
-                $saleGoal   = $salesSpecGoalMap[$cat][$sub][$spec] ?? 0;
+                $writeGoal = ($subGoalMap[$cat][$sub] ?? 0) * $writeShare;
+                $saleGoal = $salesSpecGoalMap[$cat][$sub][$spec] ?? 0;
 
                 if ($saleGoal > 0 && $writeGoal > 0.1 * $saleGoal) {
                     $row['share'] = 0.1;
@@ -2713,16 +2714,17 @@ class AutoPlannogrammaService
     /**
      * Строит карту цен за последние 20 дней.
      *
-     * @param array      $productIds        Список product_id для выборки
-     * @param int|null   $regionId          Если указан — один регион, иначе — несколько
+     * @param array $productIds Список product_id для выборки
+     * @param int|null $regionId Если указан — один регион, иначе — несколько
      * @return array
      */
     public static function buildPricesMap(
-        array  $productIds,
-        ?int   $regionId = null
-    ): array {
+        array $productIds,
+        ?int  $regionId = null
+    ): array
+    {
         $heliumGuid = '2b72702a-792f-11e8-9edd-1c6f659fb563';
-        $periodEnd   = (new \DateTime())->format('Y-m-d H:i:s');
+        $periodEnd = (new \DateTime())->format('Y-m-d H:i:s');
         $periodStart = (new \DateTime())->modify('-20 days')->format('Y-m-d H:i:s');
 
 
@@ -2730,7 +2732,7 @@ class AutoPlannogrammaService
             ->select(['product_id', 'region_id', 'price', 'active', 'date_from', 'date_to'])
             ->where(['product_id' => $productIds])
             ->andWhere(['<=', 'date_from', $periodEnd])
-            ->andWhere(['>=', 'date_to',   $periodStart])
+            ->andWhere(['>=', 'date_to', $periodStart])
             ->orderBy(['date_from' => SORT_ASC]);
 
         if ($regionId !== null) {
@@ -2742,10 +2744,10 @@ class AutoPlannogrammaService
         $multiRegion = $regionId === null;
 
         foreach ($priceRecords as $priceRecord) {
-            $productId   = $priceRecord['product_id'];
+            $productId = $priceRecord['product_id'];
             $price = (float)$priceRecord['price'];
 
-            $regionId   = $multiRegion
+            $regionId = $multiRegion
                 ? $priceRecord['region_id']
                 : null;
 
@@ -2831,22 +2833,34 @@ class AutoPlannogrammaService
                 }
 
                 $weeklyForecasts[] = [
-                    'store_id'       => $item['store_id'],
-                    'category'       => $item['category'],
-                    'subcategory'    => $item['subcategory'],
-                    'species'        => $item['species'],
-                    'type'           => $item['type'],
-                    'product_guid'   => $item['product_guid'],
-                    'week_forecast'  => round($item['full_forecast'] * $weekShare['share'], 2),
-                    'full_forecast'  => $item['full_forecast'],
-                    'week'           => $weekShare['week'],
-                    'matrix_group'   => $item['matrix_group'],
-                    'month'          => $item['month'],
-                    'year'           => $item['year'],
+                    'store_id' => $item['store_id'],
+                    'category' => $item['category'],
+                    'subcategory' => $item['subcategory'],
+                    'species' => $item['species'],
+                    'type' => $item['type'],
+                    'product_guid' => $item['product_guid'],
+                    'week_forecast' => round($item['full_forecast'] * $weekShare['share'], 2),
+                    'full_forecast' => $item['full_forecast'],
+                    'week' => $weekShare['week'],
+                    'matrix_group' => $item['matrix_group'],
+                    'month' => $item['month'],
+                    'year' => $item['year'],
                 ];
             }
         }
 
-        return $weeklyForecasts;
+        $grouped = [];
+        foreach ($weeklyForecasts as $item) {
+            $weekItem = (int)$item['week'];
+            $storeItem = (int)$item['store_id'];
+            $guid = (string)$item['product_guid'];
+            $group = (string)$item['matrix_group'];
+            $type = (string)$item['type'];
+            $forecastValue = (float)$item['week_forecast'];
+
+            $grouped[$weekItem][$storeItem][$guid][$type][$group] = $forecastValue;
+        }
+
+        return $grouped;
     }
 }
\ No newline at end of file