]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Разделение продаж на типы для подкатегорий и видов
authorfomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 27 Jun 2025 08:14:48 +0000 (11:14 +0300)
committerfomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 27 Jun 2025 08:14:48 +0000 (11:14 +0300)
erp24/controllers/AutoPlannogrammaController.php
erp24/services/AutoPlannogrammaService.php
erp24/views/auto-plannogramma/2.php
erp24/views/auto-plannogramma/3.php
erp24/views/auto-plannogramma/4.php
erp24/views/auto-plannogramma/5.php
erp24/views/auto-plannogramma/6.php

index 72787a0d9c7f5e6f95bddf22cc387f7413e7b6bc..f6c78ad3b00be0d4b71fcb620091fd65947c87c1 100644 (file)
@@ -480,6 +480,7 @@ class AutoPlannogrammaController extends BaseController
             'year' => $request->get('year'),
             'month' => $request->get('month'),
             'type' => $request->get('type'),
+            'sales_type' => $request->get('sales_type'),
         ];
 
         $dataProvider = new ArrayDataProvider([
@@ -493,7 +494,7 @@ class AutoPlannogrammaController extends BaseController
             $service = new AutoPlannogrammaService();
 
             $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters, $filters['type']);
-            $data = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date'], $filters['type']);
+            $data = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date'], $filters['type'], $filters['sales_type']);
 
             $flatData = array_filter($data, function ($row) use ($filters) {
                 foreach ($filters as $key => $value) {
@@ -530,6 +531,7 @@ class AutoPlannogrammaController extends BaseController
             'year' => $request->get('year'),
             'month' => $request->get('month'),
             'type' => $request->get('type'),
+            'sales_type' => $request->get('sales_type'),
         ];
 
         $dataProvider = new ArrayDataProvider([
@@ -581,6 +583,7 @@ class AutoPlannogrammaController extends BaseController
             'year' => $request->get('year'),
             'month' => $request->get('month'),
             'type' => $request->get('type'),
+            'sales_type' => $request->get('sales_type'),
         ];
 
         $dataProvider = new ArrayDataProvider([
@@ -594,7 +597,7 @@ class AutoPlannogrammaController extends BaseController
             $service = new AutoPlannogrammaService();
 
             $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters);
-            $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date']);
+            $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date'], $filters['type'], $filters['sales_type']);
             $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters);
             $data = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal);
 
@@ -640,6 +643,7 @@ class AutoPlannogrammaController extends BaseController
             'year' => $request->get('year'),
             'month' => $request->get('month'),
             'type' => $request->get('type'),
+            'sales_type' => $request->get('sales_type'),
         ];
 
         $dataProvider = new ArrayDataProvider([
@@ -690,6 +694,7 @@ class AutoPlannogrammaController extends BaseController
             'year' => $request->get('year'),
             'month' => $request->get('month'),
             'type' => $request->get('type'),
+            'sales_type' => $request->get('sales_type'),
         ];
 
         $dataProvider = new ArrayDataProvider([
@@ -704,7 +709,7 @@ class AutoPlannogrammaController extends BaseController
             $service = new AutoPlannogrammaService();
 
             $monthCategoryShare = $service->getMonthCategoryShareOrWriteOff($filters['plan_date'], $filters);
-            $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date']);
+            $monthCategoryGoal = $service->getMonthCategoryGoal($monthCategoryShare, $filters['plan_date'], $filters['type'], $filters['sales_type']);
             $monthSubcategoryShare = $service->getMonthSubcategoryShareOrWriteOff($filters['plan_date'], $filters);
             $monthSubcategoryGoal = $service->getMonthSubcategoryGoal($monthSubcategoryShare, $monthCategoryGoal);
             $monthSpeciesShare = $service->getMonthSpeciesShareOrWriteOff($filters['plan_date'], $filters);
index a83dc2cd5ae62e6c70752c6c8e15d4cfa164e03b..0f56cfb30c3bc6bbd0a0a819152812e791d51498 100644 (file)
@@ -269,7 +269,7 @@ class AutoPlannogrammaService
      * @param array $filters Фильтры
      * @return array Массив с целями по категориям
      */
-    public function getMonthCategoryGoal(array $categoryShare, string $datePlan, string $type = self::TYPE_SALES): array
+    public function getMonthCategoryGoal(array $categoryShare, string $datePlan, string $type = self::TYPE_SALES, string $sales_type = null): array
     {
         $timestamp = strtotime($datePlan);
         $year = date('Y', $timestamp);
@@ -288,12 +288,17 @@ class AutoPlannogrammaService
             if (!isset($categoryShare[$storeId])) {
                 continue;
             }
+            $goal = match ($sales_type) {
+                'offline'   => $plan['offline_sales_plan'],
+                'online'    => (int)$plan['online_sales_shop_plan'] + (int)$plan['online_sales_marketplace_plan'],
+                default     => ($type === self::TYPE_WRITE_OFFS ? $plan['write_offs_plan'] : $plan['total_sales_plan']),
+            };
 
             foreach ($categoryShare[$storeId] as $item) {
                 $result[] = [
                     'category' => $item['category'],
                     'store_id' => $storeId,
-                    'goal' => round($item['percent'] * ($type === self::TYPE_WRITE_OFFS ? $plan['write_offs_plan'] : $plan['total_sales_plan']), 2),
+                    'goal' => round($item['percent'] * $goal, 2),
                 ];
             }
         }
@@ -315,6 +320,18 @@ class AutoPlannogrammaService
             $storeIds = array_intersect($storeIds, [(int)$filters['store_id']]);
         }
 
+        $mode = null;
+
+        if (!empty($filters['sales_type'])) {
+            $mode = $filters['sales_type'];
+        }
+        $orderCondition = [];
+        if ($mode === 'offline') {
+            $orderCondition = ['order_id' => ['', '0']];
+        } elseif ($mode === 'online') {
+            $orderCondition = ['not in', 'order_id', ['', '0']];
+        }
+
         $sumExpression = $type === self::TYPE_WRITE_OFFS
             ? 'SUM(wp.summ)'
             : "SUM(CASE 
@@ -370,6 +387,7 @@ class AutoPlannogrammaService
                     ->leftJoin('export_import_table ex', $storeJoinCondition)
                     ->leftJoin('products_1c p1', "p1.id = $productJoinCondition")
                     ->andWhere(['ex.entity_id' => $storeIds])
+                    ->andFilterWhere($orderCondition)
                     ->andWhere(['p1.components' => ''])
                     ->andWhere(['not in', 'p1c.category', ['', 'букет', 'сборка', 'сервис']])
                     ->andWhere(['or', ...$months])
@@ -388,6 +406,7 @@ class AutoPlannogrammaService
                     ->leftJoin('export_import_table ex', $storeJoinCondition)
                     ->leftJoin('products_1c p1', "p1.id = $productJoinCondition")
                     ->andWhere(['ex.entity_id' => $storeIds])
+                    ->andFilterWhere($orderCondition)
                     ->andWhere(['p1.components' => ''])
                     ->andWhere(['not in', 'p1c.category', ['', 'букет', 'сборка', 'сервис']])
                     ->andWhere(['or', ...$months])
@@ -403,7 +422,7 @@ class AutoPlannogrammaService
         ];
         $componentAdds = [];
         $componentAddsSumAll = [];
-        $allComponentsProdIds = [];
+        $allComponentsProductIds = [];
 
         foreach ($storeIds as $sid) {
             foreach ($periods as $dt) {
@@ -417,13 +436,20 @@ class AutoPlannogrammaService
                     continue;
                 }
 
-                foreach ($items as $it) {
-                    $allComponentsProdIds[$sid][] = $it['product_id'];
-                }
+                $filtered = match ($mode) {
+                    'offline'   => array_filter($items, fn($it) => in_array($it['order_id'], ['', '0'], true)),
+                    'online'    => array_filter($items, fn($it) => !in_array($it['order_id'], ['', '0'], true)),
+                    default     => $items,  // для writeOffs — всё
+                };
+
+                $allComponentsProductIds[$sid] = array_merge(
+                    $allComponentsProductIds[$sid] ?? [],
+                    array_column($filtered, 'product_id')
+                );
 
+                $sums = $this->sumProductsComponentsByGroup($filtered, $type, 'subcategory');
 
-                $sums = $this->sumProductsComponentsByGroup($items, $type, 'subcategory');
-                $allComponentsProdIds[$sid] = array_unique($allComponentsProdIds[$sid]);
+                $allComponentsProductIds[$sid] = array_values(array_unique($allComponentsProductIds[$sid]));
 
                 foreach ($sums as $sr) {
                     $cat = $sr['category'];
@@ -472,7 +498,8 @@ class AutoPlannogrammaService
                 'type' => $type,
                 'new_total_store' => $newCatTotal,
                 'base_total_store' => $catTotal,
-                'products_components_list' => implode(',', $allComponentsProdIds[$sid] ?? []),
+                'products_components_list' => implode(',', $allComponentsProductIds[$sid] ?? []),
+                'mode' => $mode
             ];
         }
 
@@ -539,6 +566,18 @@ class AutoPlannogrammaService
             $storeIds = array_intersect($storeIds, [(int)$filters['store_id']]);
         }
 
+        $mode = null;
+
+        if (!empty($filters['sales_type'])) {
+            $mode = $filters['sales_type'];
+        }
+        $orderCondition = [];
+        if ($mode === 'offline') {
+            $orderCondition = ['order_id' => ['', '0']];
+        } elseif ($mode === 'online') {
+            $orderCondition = ['not in', 'order_id', ['', '0']];
+        }
+
         $sumExpression = $type === self::TYPE_WRITE_OFFS
             ? 'SUM(wp.summ)'
             : "SUM(CASE 
@@ -595,6 +634,7 @@ class AutoPlannogrammaService
                     ->leftJoin('export_import_table ex', $storeJoinCondition)
                     ->leftJoin('products_1c p1', "p1.id = $productJoinCondition")
                     ->andWhere(['ex.entity_id' => $storeIds])
+                    ->andFilterWhere($orderCondition)
                     ->andWhere(['p1.components' => ''])
                     ->andWhere(['not in', 'p1c.category', ['', 'букет', 'сборка', 'сервис']])
                     ->andWhere(['or', ...$months])
@@ -614,6 +654,7 @@ class AutoPlannogrammaService
                     ->leftJoin('export_import_table ex', $storeJoinCondition)
                     ->leftJoin('products_1c p1', "p1.id = $productJoinCondition")
                     ->andWhere(['ex.entity_id' => $storeIds])
+                    ->andFilterWhere($orderCondition)
                     ->andWhere(['p1.components' => ''])
                     ->andWhere(['not in', 'p1c.category', ['', 'букет', 'сборка', 'сервис']])
                     ->andWhere(['or', ...$months])
@@ -663,7 +704,7 @@ class AutoPlannogrammaService
         $finalResult = [];
         $componentAdds = [];
         $componentAddsSumAll = [];
-        $allComponentsProdIds = [];
+        $allComponentsProductIds = [];
 
         foreach ($storeIds as $sid) {
             foreach ($periods as $dt) {
@@ -677,13 +718,20 @@ class AutoPlannogrammaService
                     continue;
                 }
 
-                foreach ($items as $it) {
-                    $allComponentsProdIds[$sid][] = $it['product_id'];
-                }
+                $filtered = match ($mode) {
+                    'offline'   => array_filter($items, fn($it) => in_array($it['order_id'], ['', '0'], true)),
+                    'online'    => array_filter($items, fn($it) => !in_array($it['order_id'], ['', '0'], true)),
+                    default     => $items,  // для writeOffs — всё
+                };
+
+                $allComponentsProductIds[$sid] = array_merge(
+                    $allComponentsProductIds[$sid] ?? [],
+                    array_column($filtered, 'product_id')
+                );
 
+                $sums = $this->sumProductsComponentsByGroup($filtered, $type, 'species');
 
-                $sums = $this->sumProductsComponentsByGroup($items, $type, 'species');
-                $allComponentsProdIds[$sid] = array_unique($allComponentsProdIds[$sid]);
+                $allComponentsProductIds[$sid] = array_values(array_unique($allComponentsProductIds[$sid]));
 
                 foreach ($sums as $sr) {
                     $cat = $sr['category'];
@@ -734,7 +782,8 @@ class AutoPlannogrammaService
                 'type' => $type,
                 'new_total_store' => $newSubcatTotal,
                 'base_total_store' => $subcatTotal,
-                'products_components_list' => implode(',', $allComponentsProdIds[$sid] ?? []),
+                'products_components_list' => implode(',', $allComponentsProductIds[$sid] ?? []),
+                'mode' => $mode
             ];
         }
 
index d6c7118670963e37acd8d1cff1ebef853aca68b7..2a75680343c1f228d738d367618bb0324ea4f5c7 100644 (file)
                 'pluginOptions' => ['allowClear' => true],
             ])->label('По дефолту продажи!') ?>
         </div>
+        <div class="col-md">
+            <?= $form->field(new \yii\base\DynamicModel(['sales_type' => $filters['sales_type'] ?? '']), 'sales_type')->widget(Select2::class, [
+                'data' => [
+                    'offline' => 'оффлайн',
+                    'online' => 'онлайн'
+                ],
+                'options' => ['placeholder' => 'Тип продаж', 'name' => 'sales_type'],
+                'pluginOptions' => ['allowClear' => true],
+            ])->label('Только для типа Продажи!') ?>
+        </div>
         <div class="col-md">
             <?= Html::submitButton('Фильтровать', ['class' => 'btn btn-primary']) ?>
         </div>
 
 <?= GridView::widget([
     'dataProvider' => $dataProvider,
+    'showPageSummary' => true,
     'columns' => [
         ['attribute' => 'store_id', 'label' => 'Магазин', 'value' => function ($data) {
             return CityStore::findOne($data['store_id'])->name ?? null;
         }],
         ['attribute' => 'category', 'label' => 'Категория'],
-        ['attribute' => 'goal', 'label' => 'Сумма план'],
+        ['attribute' => 'goal', 'label' => 'Сумма план','pageSummary' => true,],
     ],
     ]); ?>
index c3fa44f44d1ab76b8ce8aa46bafd73de6f89f390..e602eec02f06f406e8c5ba4ddbd09e26772369de 100644 (file)
                 'pluginOptions' => ['allowClear' => true],
             ])->label('По дефолту продажи!') ?>
         </div>
+        <div class="col-md">
+            <?= $form->field(new \yii\base\DynamicModel(['sales_type' => $filters['sales_type'] ?? '']), 'sales_type')->widget(Select2::class, [
+                'data' => [
+                    'offline' => 'оффлайн',
+                    'online' => 'онлайн'
+                ],
+                'options' => ['placeholder' => 'Тип продаж', 'name' => 'sales_type'],
+                'pluginOptions' => ['allowClear' => true],
+            ])->label('Только для типа Продажи!') ?>
+        </div>
         <div class="col-md">
             <?= Html::submitButton('Фильтровать', ['class' => 'btn btn-primary']) ?>
         </div>
         ['attribute' => 'subcategory', 'label' => 'Подкатегория'],
         ['attribute' => 'old_total_sum', 'label' => 'Сумма', 'format' => ['decimal', 2], 'pageSummary' => true,],
         ['attribute' => 'total_sum', 'label' => 'Сумма с раскрытием', 'format' => ['decimal', 2], 'pageSummary' => true,],
-        ['attribute' => 'percent', 'label' => 'Доля', 'format' => ['percent', 2]],
+        ['attribute' => 'percent', 'label' => 'Доля', 'format' => ['percent', 2], 'pageSummary' => true,],
     ],
 ]); ?>
index a5d0d6e4327165fe4d82d476f5fc16244e573c6f..903903b4e93b1e5f5ccd9eb5f383e00a834cef73 100644 (file)
                 'pluginOptions' => ['allowClear' => true],
             ])->label('По дефолту продажи!') ?>
         </div>
+        <div class="col-md">
+            <?= $form->field(new \yii\base\DynamicModel(['sales_type' => $filters['sales_type'] ?? '']), 'sales_type')->widget(Select2::class, [
+                'data' => [
+                    'offline' => 'оффлайн',
+                    'online' => 'онлайн'
+                ],
+                'options' => ['placeholder' => 'Тип продаж', 'name' => 'sales_type'],
+                'pluginOptions' => ['allowClear' => true],
+            ])->label('Только для типа Продажи!') ?>
+        </div>
         <div class="col-md">
             <?= Html::submitButton('Фильтровать', ['class' => 'btn btn-primary']) ?>
         </div>
index 6903b9b19cbda87804c4c3da2676d83fee1d75f1..0771f77bb2709ae17003f89b9692756a6bda2a23 100644 (file)
                 'pluginOptions' => ['allowClear' => true],
             ])->label('По дефолту продажи!') ?>
         </div>
+        <div class="col-md">
+            <?= $form->field(new \yii\base\DynamicModel(['sales_type' => $filters['sales_type'] ?? '']), 'sales_type')->widget(Select2::class, [
+                'data' => [
+                    'offline' => 'оффлайн',
+                    'online' => 'онлайн'
+                ],
+                'options' => ['placeholder' => 'Тип продаж', 'name' => 'sales_type'],
+                'pluginOptions' => ['allowClear' => true],
+            ])->label('Только для типа Продажи!') ?>
+        </div>
         <div class="col-md">
             <?= Html::submitButton('Фильтровать', ['class' => 'btn btn-primary']) ?>
         </div>
index b35136211d02a9222d6dbacd98a0ac378c85264b..d4ace88581d28ec7344c225bb3cfd70eb6c2250e 100644 (file)
                 'pluginOptions' => ['allowClear' => true],
             ])->label('По дефолту продажи!') ?>
         </div>
+        <div class="col-md">
+            <?= $form->field(new \yii\base\DynamicModel(['sales_type' => $filters['sales_type'] ?? '']), 'sales_type')->widget(Select2::class, [
+                'data' => [
+                    'offline' => 'оффлайн',
+                    'online' => 'онлайн'
+                ],
+                'options' => ['placeholder' => 'Тип продаж', 'name' => 'sales_type'],
+                'pluginOptions' => ['allowClear' => true],
+            ])->label('Только для типа Продажи!') ?>
+        </div>
         <div class="col-md">
             <?= Html::submitButton('Фильтровать', ['class' => 'btn btn-primary']) ?>
         </div>