]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Вычисление долей списания товара в виде
authorVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Wed, 18 Jun 2025 11:54:59 +0000 (14:54 +0300)
committerVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Wed, 18 Jun 2025 11:54:59 +0000 (14:54 +0300)
erp24/controllers/AutoPlannogrammaController.php
erp24/services/AutoPlannogrammaService.php

index 5a39e992dd0d469b4fb5570d8d2ea2a9d6d07299..138aaa824ba7824eb23b01a4fa5ec2642bb8e5df 100644 (file)
@@ -1761,9 +1761,8 @@ class AutoPlannogrammaController extends BaseController
         }
 
         $service = new AutoPlannogrammaService();
-        //$result = $service->getWeeklyBouquetProductsForecast($monthRequest, $yearRequest, $storeIdRequest);
-        $writeOffs = $service->getWeeklyProductsWriteoffsForecast($monthRequest, $yearRequest, $storeIdRequest);
-        var_dump($writeOffs); die();
+        $result = $service->getWeeklyBouquetProductsForecast($monthRequest, $yearRequest, $storeIdRequest);
+
         if (!is_array($result)) {
             return ['success' => false, 'message' => 'Ошибка структуры данных'];
         }
index 4587c0b1807c4b5fbc72249a609edb48ff169a34..6f03a63f0d31855bd227bfa6399a3690fbca0750 100644 (file)
@@ -2938,7 +2938,7 @@ class AutoPlannogrammaService
         return $grouped;
     }
 
-    public function getWeeklyProductsWriteoffsForecast($month, $year, $storeId = null, $weekNumber = null)
+    public function getWeeklyProductsWriteoffsForecast($month, $year, $weeklySalesForecast, $storeId = null, $weekNumber = null)
     {
         $weeksProductForecast = [];
         $filters = [];
@@ -2957,6 +2957,11 @@ class AutoPlannogrammaService
             [$monthSpeciesGoal['subcategory']]
             [$monthSpeciesGoal['species']] = $monthSpeciesGoal['goal'];
         }
+        $productsWriteoffsShare = $this->calculateWriteOffShareByMonth($weeklySalesForecast, $month, $year);
+        $productsWriteoffsShareMap = [];
+        foreach ($productsWriteoffsShare as $productWriteoffs) {
+            $productsWriteoffsShareMap[$productWriteoffs['store_id']][$productWriteoffs['product_id']] = $productWriteoffs['share'];
+            }
 
         $weeksShareResult = $this->getHistoricalWeeklySpeciesShare($monthYear, $filters, null, 'writeOffs');
         $weeksData = $this->calculateWeeklySpeciesGoals($weeksShareResult, $monthSpeciesGoals);
@@ -2965,6 +2970,8 @@ class AutoPlannogrammaService
             $forecasts = $this->calculateWeekForecastSpeciesProducts($r['category'], $r['subcategory'], $r['species'], $r['store_id'], $r['weekly_goal']);
 
             foreach ($forecasts as $forecast) {
+                $productWriteoffsForecastSpeciesShare = $productsWriteoffsShareMap[$r['store_id']][$forecast['product_id']] ?? 0;
+                $productWriteoffsForecast = $productWriteoffsForecastSpeciesShare * $forecast['forecast'];
                 $weeksProductForecast[] = [
                     'category' => $forecast['category'] ?? '',
                     'subcategory' => $forecast['subcategory'] ?? '',
@@ -2973,7 +2980,7 @@ class AutoPlannogrammaService
                     'name' => $forecast['name'] ?? '',
                     'price' => $forecast['price'] ?? '',
                     'goal' => $forecast['goal'] ?? 0,
-                    'forecast' => $forecast['forecast'] ?? 0,
+                    'forecast' => $productWriteoffsForecast ?? 0,
                     'week' => $r['week'],
                 ];
             }
@@ -2982,4 +2989,137 @@ class AutoPlannogrammaService
         return $weeksProductForecast;
     }
 
+    /**
+     * Рассчитывает долю списания (write-offs) каждого товара за заданный месяц
+     * на основании исторических данных за два предыдущих года.
+     *
+     * @param array  $productList  Список товаров:
+     *                             [
+     *                               [
+     *                                 'week'             => int,
+     *                                 'store_id'         => int,
+     *                                 'category'         => string,
+     *                                 'subcategory'      => string,
+     *                                 'species'          => string,
+     *                                 'product_id'       => string,
+     *                                 'forecast_month_pieces' => float,
+     *                                 'forecast_week_pieces'  => float,
+     *                               ], …
+     *                             ]
+     * @param string $monthYear    Формат 'YYYY-MM'
+     * @return array               [
+     *                               [
+     *                                 'store_id'   => int,
+     *                                 'month'      => int,
+     *                                 'year'       => int,
+     *                                 'category'   => string,
+     *                                 'subcategory'=> string,
+     *                                 'species'    => string,
+     *                                 'product_id' => string,
+     *                                 'writeoff_qty'   => float,
+     *                                 'species_qty'    => float,
+     *                                 'share'          => float, // доля
+     *                               ], …
+     *                             ]
+     */
+    public function calculateWriteOffShareByMonth(array $productList, int $month, int $year ): array
+    {
+        $year  = $year ?? (int)date("Y");
+        $month = $month ?? (int)date("m",  strtotime( "+ 2 month" . date('Y-m-01')));
+
+        $storeIds = array_unique(array_column($productList, 'store_id'));
+        if (empty($storeIds)) {
+            return [];
+        }
+
+        $productQtyMap        = []; // [store][cat][sub][spec][pid] => qty
+        $speciesQtyMap        = []; // [store][cat][sub][spec] => total qty
+
+        $storeJoinCondition = 'ex.export_val = w.store_id';
+
+        for ($offset = 2; $offset >= 1; $offset--) {
+            $histYear = $year - $offset;
+            $start = sprintf('%04d-%02d-01 00:00:00', $histYear, $month);
+            $end   = date('Y-m-d 23:59:59', strtotime("$start +1 month -1 second"));
+
+            $productsWriteOffs = (new Query())
+                ->select([
+                    'store_id'    => 'ex.entity_id',
+                    'category'    => 'p1c.category',
+                    'subcategory' => 'p1c.subcategory',
+                    'species'     => 'p1c.species',
+                    'product_id'  => 'wp.product_id',
+                    'qty'         => new \yii\db\Expression('SUM(wp.quantity)'),
+                ])
+                ->from(['w' => 'write_offs'])
+                ->innerJoin(['wp' => 'write_offs_products'], 'wp.write_offs_id = w.id')
+                ->leftJoin('export_import_table ex', $storeJoinCondition)
+                ->leftJoin('products_1c_nomenclature p1c', 'p1c.id = wp.product_id')
+                ->leftJoin('products_1c p1', 'p1.id = wp.product_id')
+
+                ->andWhere(['ex.entity_id' => $storeIds])
+                ->andWhere(['>=', 'w.date', $start])
+                ->andWhere(['<=', 'w.date', $end])
+
+                ->andWhere(['p1.components' => ''])
+                ->andWhere(['not in', 'p1c.category', ['', 'букет', 'сборка', 'сервис']])
+                ->groupBy(['ex.entity_id','p1c.category','p1c.subcategory','p1c.species','wp.product_id'])
+                ->all();
+
+            foreach ($productsWriteOffs as $productsWriteOffsItem) {
+                $sid  = (int)$productsWriteOffsItem['store_id'];
+                $cat  = $productsWriteOffsItem['category'];
+                $sub  = $productsWriteOffsItem['subcategory'];
+                $spec = $productsWriteOffsItem['species'];
+                $pid  = $productsWriteOffsItem['product_id'];
+                $qty  = (float)$productsWriteOffsItem['qty'];
+
+
+                $productQtyMap[$sid][$cat][$sub][$spec][$pid] =
+                    ($productQtyMap[$sid][$cat][$sub][$spec][$pid] ?? 0.0) + $qty;
+
+                $speciesQtyMap[$sid][$cat][$sub][$spec] =
+                    ($speciesQtyMap[$sid][$cat][$sub][$spec] ?? 0.0) + $qty;
+            }
+        }
+
+        $seen = [];
+        $result = [];
+        foreach ($productList as $item) {
+            $pid  = $item['product_id'];
+            $sid  = $item['store_id'];
+            $cat  = $item['category'];
+            $sub  = $item['subcategory'];
+            $spec = $item['species'];
+
+            $key = "{$sid}|{$cat}|{$sub}|{$spec}|{$pid}";
+            if (isset($seen[$key])) {
+                continue;
+            }
+            $seen[$key] = true;
+
+            $productsQty = $productQtyMap[$sid][$cat][$sub][$spec][$pid] ?? 0.0;
+            $speciesQty = $speciesQtyMap[$sid][$cat][$sub][$spec] ??  0.0;
+            $share = $speciesQty > 0
+                ? round($productsQty / $speciesQty, 4)
+                : 0.0;
+
+            $result[] = [
+                'store_id'        => $sid,
+                'month'           => $month,
+                'year'            => $year,
+                'category'        => $cat,
+                'subcategory'     => $sub,
+                'species'         => $spec,
+                'product_id'      => $pid,
+                'writeoff_qty'    => $productsQty,
+                'species_qty'     => $speciesQty,
+                'share'           => $share,
+            ];
+        }
+
+        return $result;
+    }
+
+
 }
\ No newline at end of file