]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
ERP-302 Редактирование букета
authormarina <m.zozirova@gmail.com>
Mon, 24 Feb 2025 10:32:13 +0000 (13:32 +0300)
committermarina <m.zozirova@gmail.com>
Mon, 24 Feb 2025 10:32:13 +0000 (13:32 +0300)
erp24/records/BouquetComposition.php
erp24/records/BouquetCompositionProducts.php
erp24/views/bouquet/_product_list.php

index 28e751f1601ddfc4a4c29623ae4529de58021c33..fceb1aa30b428c9106698c16ea23b0635e3b3964 100644 (file)
@@ -176,7 +176,7 @@ class BouquetComposition extends ActiveRecord
 
         BouquetCompositionMatrixTypeHistory::updateMatrixType(
             $this->id,
-            isset($data['matrix_type_id']) ? (int) $data['matrix_type_id'] : null
+            isset($data['matrix_type_id']) ? (int)$data['matrix_type_id'] : null
         );
 
         $this->processFiles();
@@ -413,7 +413,7 @@ class BouquetComposition extends ActiveRecord
             }
 
             sort($prices);
-            $middle = (int) ($count / 2);
+            $middle = (int)($count / 2);
             $median = ($count % 2 === 0)
                 ? ($prices[$middle - 1] + $prices[$middle]) / 2
                 : $prices[$middle];
index 14179d593f7569b2d92710396e19078c7111e19b..4156da4898c9df5d3e5744cd6188a926c66b636b 100644 (file)
@@ -176,4 +176,125 @@ class BouquetCompositionProducts extends ActiveRecord
     {
         return $this->hasOne(Products1c::class, ['id' => 'product_guid']);
     }
+
+    public function getProfitability(): float
+    {
+        // Получаем среднюю себестоимость за последние 2 недели
+        $averageCost = SelfCostProduct::find()
+            ->where(['product_guid' => $this->product_guid])
+            ->andWhere(['>=', 'date', date('Y-m-d', strtotime('-14 days'))])
+            ->average('price');
+
+        if ($averageCost === null) {
+            return 0;
+        }
+
+        // Получаем актуальные розничные цены (РЦ) за последние 2 недели
+        $retailPrices = PricesDynamic::find()
+            ->where(['product_id' => $this->product_guid])
+            ->andWhere(['active' => 1]) // Только активные цены
+            ->andWhere(['<=', 'date_from', date('Y-m-d')]) // Цена начала действия
+            ->andWhere(['>', 'date_to', date('Y-m-d')]) // Цена еще актуальна
+            ->orderBy('date_from ASC')
+            ->asArray()
+            ->all();
+
+        if (empty($retailPrices)) {
+            return 0;
+        }
+
+        $profitMargins = [];
+
+        foreach ($retailPrices as $price) {
+            if ($price['price'] > 0) {
+                $grossProfit = $price['price'] - $averageCost;
+                $profitability = ($grossProfit / $price['price']) * 100;
+                $profitMargins[] = $profitability;
+            }
+        }
+
+        if (empty($profitMargins)) {
+            return 0;
+        }
+
+        // Сортируем массив рентабельности для вычисления медианы
+        sort($profitMargins);
+        $count = count($profitMargins);
+
+        // Вычисляем медиану рентабельности
+        $medianProfitability = ($count % 2) ?
+            $profitMargins[floor($count / 2)] :
+            (($profitMargins[$count / 2 - 1] + $profitMargins[$count / 2]) / 2);
+
+        return round($medianProfitability, 2);
+    }
+
+    public function getBuildPercentage(): float
+    {
+        $totalAssemblies = BouquetCompositionProducts::find()->count();
+        $assembliesWithProduct = BouquetCompositionProducts::find()
+            ->where(['product_guid' => $this->product_guid])
+            ->count();
+
+        return $totalAssemblies ? round(($assembliesWithProduct / $totalAssemblies) * 100, 2) : 0;
+    }
+
+    public function getAverageNumberOfPieces(): float
+    {
+        $totalCount = BouquetCompositionProducts::find()
+            ->where(['product_guid' => $this->product_guid])
+            ->sum('count');
+
+        $assembliesWithProduct = BouquetCompositionProducts::find()
+            ->where(['product_guid' => $this->product_guid])
+            ->count();
+
+        return $assembliesWithProduct ? round($totalCount / $assembliesWithProduct, 2) : 0;
+    }
+
+    public function getWriteOffPercentage(): float
+    {
+        // Получаем GUID продуктов из состава букетов
+        $productGuids = BouquetCompositionProducts::find()
+            ->select('product_guid')
+            ->where(['product_guid' => $this->product_guid])
+            ->column();
+
+        if (empty($productGuids)) {
+            return 0;
+        }
+
+        // Находим ID номенклатуры по полученным GUID
+        $productIds = Products1cNomenclature::find()
+            ->select('id')
+            ->where(['id' => $productGuids]) // Исправлено: в номенклатуре ID = product_guid из букетов
+            ->column();
+
+        if (empty($productIds)) {
+            return 0;
+        }
+
+        // Считаем сумму списаний за последний месяц по найденным товарам
+        $writeOffs = WriteOffs::find()
+            ->where(['>=', 'date', date('Y-m-01', strtotime('-1 month'))])
+            ->andWhere(new Expression("
+        EXISTS (
+            SELECT 1 FROM jsonb_array_elements(items::jsonb) item 
+            WHERE item->>'product_id' IN (:productIds)
+        )
+    ", [':productIds' => implode("','", $productIds)]))
+            ->sum('summ');
+
+
+        $sales = SalesProducts::find()
+            ->alias('sp')
+            ->innerJoin('sales s', 'CAST(s.id AS VARCHAR) = sp.check_id') // Приведение типов в другую сторону
+            ->where(['>=', 's.date', date('Y-m-01', strtotime('-1 month'))]) // Фильтр по дате
+            ->andWhere(['sp.product_id' => $productIds]) // Фильтр по продукту
+            ->sum('sp.summ');
+
+        return $sales ? round(($writeOffs / $sales) * 100, 2) : 0;
+    }
+
+
 }
\ No newline at end of file
index bc12b4c53b97de053ff5162426f38dad45de8465..dd5c89d3901558229fc4bd8966f5fb713e1465b8 100644 (file)
@@ -2,7 +2,7 @@
     <div class="col-md-4 text-center font-weight-bold">Название</div>
     <div class="col-md-2 text-center font-weight-bold">Кол-во</div>
     <div class="col-md-1 text-center font-weight-bold">% списания</div>
-    <div class="col-md-2 text-center font-weight-bold">мрж-ть</div>
+    <div class="col-md-2 text-center font-weight-bold">рен-ть</div>
     <div class="col-md-1 text-center font-weight-bold">% в сборке</div>
     <div class="col-md-2 text-center font-weight-bold">ср.шт. в сборке</div>
 </div>
     use yii\helpers\Html;
     use yii\helpers\Url;
     use yii_app\records\BouquetComposition;
+    use yii_app\records\BouquetCompositionProducts;
 
     foreach ($bouquetCompositionProducts as $product) { ?>
         <div class="d-flex border-bottom ms-1 py-2" style="gap: 0;">
-            <div class="text-center" style="width: 33.33%;"><?= $product->product->name ?></div>
-            <div class="text-center" style="width: 16.66%;"><?= $product->count ?></div>
-            <div class="text-center" style="width: 8.33%;">10%</div>
-            <div class="text-center" style="width: 16.66%;">30%</div>
-            <div class="text-center" style="width: 8.33%;">10%</div>
-            <div class="text-center" style="width: 16.66%;">3.2%</div>
+            <div class="text-center" style="width: 33.33%;"><?= Html::encode($product->product->name) ?></div>
+            <div class="text-center" style="width: 16.66%;"><?= Html::encode($product->count) ?></div>
+            <div class="text-center" style="width:  8.33%;"><?= Html::encode($product->getWriteOffPercentage()) ?></div>
+            <div class="text-center" style="width: 16.66%;"><?= Html::encode($product->getProfitability())?> </div>
+            <div class="text-center" style="width: 16.66%;"><?= Html::encode($product->getBuildPercentage()) ?>%</div>
+            <div class="text-center" style="width: 8.33%;"><?= Html::encode($product->getAverageNumberOfPieces()) ?></div>
         </div>
     <?php } ?>
 </div>