]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Добавление источников и чистка кода origin/feature_fomichev_erp-489_mp_sales_report
authorVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 7 Nov 2025 09:21:45 +0000 (12:21 +0300)
committerVladimir Fomichev <vladimir.fomichev@erp-flowers.ru>
Fri, 7 Nov 2025 09:21:45 +0000 (12:21 +0300)
erp24/services/MarketplaceSalesMatchingService.php
erp24/views/dashboard/marketplace-sales-report.php
erp24/views/dashboard/sales-detail.php
erp24/views/dashboard/sales.php
erp24/web/css/dashboard/sales.css [new file with mode: 0644]

index 8815353be772dfc2184cfc6b4e5707d57b402fdd..85d5927e4e8eed47ad886f4fc401ad44eb87e02c 100644 (file)
@@ -489,8 +489,10 @@ class MarketplaceSalesMatchingService
                 's.operation',
                 'cc.marketplace_order_id',
                 'cc.is_marketplace',
+                'COALESCE(cc.marketplace_name, mo.marketplace_name, \'Неизвестный МП\') as marketplace_name',
             ])
             ->innerJoin('create_checks cc', 's.id = cc.guid')
+            ->leftJoin('marketplace_orders mo', 'cc.marketplace_order_id = mo.marketplace_order_id')
             ->andWhere(['cc.is_marketplace' => 1])
             ->andWhere(['>=', 's.date', DateHelper::getDateTimeStartDay($dateFrom, true)])
             ->andWhere(['<=', 's.date', DateHelper::getDateTimeEndDay($dateTo, true)])
@@ -532,6 +534,8 @@ class MarketplaceSalesMatchingService
                 'operation' => Sales::OPERATION_SALE,
                 'marketplace_order_id' => $order->marketplace_order_id,
                 'is_marketplace' => 1,
+                'marketplace_name' => $order->marketplace_name ?? 'Неизвестный МП',
+                'marketplace_id' => $order->marketplace_id,
             ];
         }
         
@@ -568,7 +572,7 @@ class MarketplaceSalesMatchingService
     }
 
     /**
-     * Группировка продаж МП по магазинам
+     * Группировка продаж МП по магазинам и маркетплейсам
      * 
      * @param array $sales
      * @param string $source
@@ -580,25 +584,40 @@ class MarketplaceSalesMatchingService
         
         foreach ($sales as $sale) {
             $storeId1c = $sale['store_id_1c'];
+            $marketplaceName = $sale['marketplace_name'] ?? 'Неизвестный МП';
             
+            // Инициализируем структуру для магазина, если её нет
             if (!isset($grouped[$storeId1c])) {
                 $grouped[$storeId1c] = [
                     'store_id_1c' => $storeId1c,
                     'total_orders' => 0,
                     'total_summ' => 0,
                     'source' => $source,
+                    'marketplaces' => [],
                     'sales' => [],
                 ];
             }
             
+            // Инициализируем структуру для маркетплейса в этом магазине, если её нет
+            if (!isset($grouped[$storeId1c]['marketplaces'][$marketplaceName])) {
+                $grouped[$storeId1c]['marketplaces'][$marketplaceName] = [
+                    'name' => $marketplaceName,
+                    'orders' => 0,
+                    'summ' => 0,
+                ];
+            }
+            
             $saleAmount = $sale['summ'] - $sale['skidka'];
             
             // Применяем операцию (продажа или возврат)
             if ($sale['operation'] === Sales::OPERATION_SALE) {
                 $grouped[$storeId1c]['total_summ'] += $saleAmount;
                 $grouped[$storeId1c]['total_orders']++;
+                $grouped[$storeId1c]['marketplaces'][$marketplaceName]['summ'] += $saleAmount;
+                $grouped[$storeId1c]['marketplaces'][$marketplaceName]['orders']++;
             } elseif ($sale['operation'] === Sales::OPERATION_RETURN) {
                 $grouped[$storeId1c]['total_summ'] -= $saleAmount;
+                $grouped[$storeId1c]['marketplaces'][$marketplaceName]['summ'] -= $saleAmount;
             }
             
             $grouped[$storeId1c]['sales'][] = $sale;
index 97c257e971220307543a9de3a927a33285c1086b..9958b5ddb98a1c38d6b7f999017d59130ed026f2 100644 (file)
 
 use yii\helpers\Html;
 use yii\widgets\ActiveForm;
+use yii\helpers\Url;
+
+$this->registerCssFile('/css/dashboard/sales.css');
 ?>
 
-<h2>Отчет по заказам маркетплейсов и чекам продаж</h2>
+<div class="d-flex justify-content-between align-items-center mb-3">
+    <h2 class="mb-0">Отчет по заказам маркетплейсов и чекам продаж</h2>
+    <a href="<?= Url::to(['dashboard/sales']) ?>" class="btn btn-secondary">
+        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
+            <path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/>
+        </svg> Назад к продажам
+    </a>
+</div>
 
 <?php $searchForm = ActiveForm::begin([
     'id' => 'days-search-form-marketplace',
@@ -340,72 +350,3 @@ use yii\widgets\ActiveForm;
     <?php endif; ?>
 </div>
 
-<?php
-// CSS для оформления
-$this->registerCss('
-.marketplace-report-container {
-    padding: 15px;
-}
-
-.accordion-button {
-    padding: 12px 15px;
-    font-size: 14px;
-}
-
-.accordion-button:not(.collapsed) {
-    background-color: #f8f9fa;
-    color: #000;
-}
-
-.card {
-    box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
-}
-
-.card-header {
-    font-weight: 500;
-    padding: 10px 15px;
-}
-
-.table-hover tbody tr:hover {
-    background-color: #f5f5f5;
-}
-
-.badge {
-    margin-left: 5px;
-    padding: 5px 8px;
-    font-size: 11px;
-}
-
-.text-muted {
-    color: #999;
-}
-
-.text-success {
-    color: #28a745;
-}
-
-.text-danger {
-    color: #dc3545;
-}
-
-.text-warning {
-    color: #ffc107;
-}
-
-.text-info {
-    color: #17a2b8;
-}
-
-h5 {
-    border-bottom: 2px solid #e0e0e0;
-    padding-bottom: 10px;
-    margin-bottom: 15px;
-}
-
-h6 {
-    font-weight: 600;
-    color: #333;
-}
-');
-?>
-
index 9373ed57ec1f0cfb732ce6f662fd7a3ec62cd70b..52712ad5b6dfeaec739d52cac7d55ce662c51b7a 100644 (file)
 
 use yii\helpers\Html;
 use yii\widgets\ActiveForm;
+use yii\helpers\Url;
+
+$this->registerCssFile('/css/dashboard/sales.css');
 ?>
 
-<h2>Детальный просмотр продаж</h2>
+<div class="d-flex justify-content-between align-items-center mb-3">
+    <h2 class="mb-0">Детальный просмотр продаж</h2>
+    <a href="<?= Url::to(['dashboard/sales']) ?>" class="btn btn-secondary">
+        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-left" viewBox="0 0 16 16">
+            <path fill-rule="evenodd" d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z"/>
+        </svg> Назад к продажам
+    </a>
+</div>
 
 <?php $searchForm = ActiveForm::begin([
     'id' => 'days-search-form-detail',
@@ -236,43 +246,3 @@ use yii\widgets\ActiveForm;
     <?php endif; ?>
 </div>
 
-<?php
-// CSS для оформления
-$this->registerCss('
-.sales-detail-container {
-    padding: 15px;
-}
-
-.accordion-button {
-    padding: 12px 15px;
-    font-size: 14px;
-}
-
-.accordion-button:not(.collapsed) {
-    background-color: #f8f9fa;
-    color: #000;
-}
-
-.table-hover tbody tr:hover {
-    background-color: #f5f5f5;
-}
-
-.badge {
-    margin-left: 5px;
-    padding: 5px 8px;
-}
-
-.text-muted {
-    color: #999;
-}
-
-.text-success {
-    color: #28a745;
-}
-
-.text-danger {
-    color: #dc3545;
-}
-');
-?>
-
index aa46d4c8c809cfa748f1ae8b391ae86826fcada3..6d0c45b160617c1b67ebb4f3719c83ea0b3ea1ce 100755 (executable)
 
 use yii_app\helpers\AppArrayHelper;
 
+$this->registerCssFile('/css/dashboard/sales.css');
 $this->registerCssFile('/azea/assets/plugins/time-picker/jquery.timepicker.css');
 $this->registerJsFile('/azea/assets/plugins/time-picker/jquery.timepicker.js', ['position' => \yii\web\View::POS_END]);
 $this->registerJsFile('/js/dashboard/index.js', ['position' => \yii\web\View::POS_END]);
-$this->registerCss('
-.ui-timepicker-wrapper {
-    z-index: 99999999; /* show timepicker over popup fix */
-}
-
-th, .line>td {
-    border-right: 1px solid #e8d5d5;
-    padding: 0px 4px 0 4px;
-}
-tr.line.bg-danger>td>a.btn {
-    border: 1px solid #e8d5d5;
-}
-');
 
 ?>
 <div class="d-flex justify-content-between align-items-center mb-3">
@@ -325,6 +313,7 @@ echo"</tbody></table>
         <thead>
             <tr>
                 <th>Магазин</th>
+                <th>Маркетплейс</th>
                 <th>Количество заказов</th>
                 <th>Сумма продаж</th>
                 <th>Источник данных</th>
@@ -336,24 +325,37 @@ echo"</tbody></table>
         $totalMpOrders = 0;
         foreach ($marketplaceSales as $storeId1c => $data): 
             $storeName = $city_stores[$storeId1c] ?? 'Неизвестный магазин';
-            $totalMpSumm += $data['total_summ'];
-            $totalMpOrders += $data['total_orders'];
+            $isFirstRow = true;
+            $rowCount = count($data['marketplaces']);
+            
+            foreach ($data['marketplaces'] as $marketplaceName => $mpData):
+                $totalMpSumm += $mpData['summ'];
+                $totalMpOrders += $mpData['orders'];
         ?>
             <tr>
-                <td><?= $storeName ?></td>
-                <td><?= $data['total_orders'] ?></td>
-                <td><?= number_format($data['total_summ'], 2, '.', ' ') ?> руб</td>
-                <td>
-                    <span class="badge bg-<?= $data['source'] === 'checks' ? 'success' : 'warning' ?>">
-                        <?= $data['source'] === 'checks' ? 'Чеки (1С)' : 'Заказы МП' ?>
-                    </span>
-                </td>
+                <?php if ($isFirstRow): ?>
+                    <td rowspan="<?= $rowCount ?>"><?= $storeName ?></td>
+                <?php endif; ?>
+                <td><?= htmlspecialchars($marketplaceName) ?></td>
+                <td><?= $mpData['orders'] ?></td>
+                <td><?= number_format($mpData['summ'], 2, '.', ' ') ?> руб</td>
+                <?php if ($isFirstRow): ?>
+                    <td rowspan="<?= $rowCount ?>">
+                        <span class="badge bg-<?= $data['source'] === 'checks' ? 'success' : 'warning' ?>">
+                            <?= $data['source'] === 'checks' ? 'Чеки (1С)' : 'Заказы МП' ?>
+                        </span>
+                    </td>
+                <?php endif; ?>
             </tr>
-        <?php endforeach; ?>
+        <?php 
+                $isFirstRow = false;
+            endforeach; 
+        endforeach; 
+        ?>
         </tbody>
         <tfoot>
             <tr class="bg-success">
-                <th>Итого</th>
+                <th colspan="2">Итого</th>
                 <th><?= $totalMpOrders ?></th>
                 <th><?= number_format($totalMpSumm, 2, '.', ' ') ?> руб</th>
                 <th></th>
diff --git a/erp24/web/css/dashboard/sales.css b/erp24/web/css/dashboard/sales.css
new file mode 100644 (file)
index 0000000..ac758e5
--- /dev/null
@@ -0,0 +1,115 @@
+/* Стили для страницы продаж (sales.php) */
+.ui-timepicker-wrapper {
+    z-index: 99999999; /* show timepicker over popup fix */
+}
+
+th, .line>td {
+    border-right: 1px solid #e8d5d5;
+    padding: 0px 4px 0 4px;
+}
+
+tr.line.bg-danger>td>a.btn {
+    border: 1px solid #e8d5d5;
+}
+
+/* Стили для детального просмотра продаж (sales-detail.php) */
+.sales-detail-container {
+    padding: 15px;
+}
+
+.sales-detail-container .accordion-button {
+    padding: 12px 15px;
+    font-size: 14px;
+}
+
+.sales-detail-container .accordion-button:not(.collapsed) {
+    background-color: #f8f9fa;
+    color: #000;
+}
+
+.sales-detail-container .table-hover tbody tr:hover {
+    background-color: #f5f5f5;
+}
+
+.sales-detail-container .badge {
+    margin-left: 5px;
+    padding: 5px 8px;
+}
+
+.sales-detail-container .text-muted {
+    color: #999;
+}
+
+.sales-detail-container .text-success {
+    color: #28a745;
+}
+
+.sales-detail-container .text-danger {
+    color: #dc3545;
+}
+
+/* Стили для отчета по маркетплейсам (marketplace-sales-report.php) */
+.marketplace-report-container {
+    padding: 15px;
+}
+
+.marketplace-report-container .accordion-button {
+    padding: 12px 15px;
+    font-size: 14px;
+}
+
+.marketplace-report-container .accordion-button:not(.collapsed) {
+    background-color: #f8f9fa;
+    color: #000;
+}
+
+.marketplace-report-container .card {
+    box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+}
+
+.marketplace-report-container .card-header {
+    font-weight: 500;
+    padding: 10px 15px;
+}
+
+.marketplace-report-container .table-hover tbody tr:hover {
+    background-color: #f5f5f5;
+}
+
+.marketplace-report-container .badge {
+    margin-left: 5px;
+    padding: 5px 8px;
+    font-size: 11px;
+}
+
+.marketplace-report-container .text-muted {
+    color: #999;
+}
+
+.marketplace-report-container .text-success {
+    color: #28a745;
+}
+
+.marketplace-report-container .text-danger {
+    color: #dc3545;
+}
+
+.marketplace-report-container .text-warning {
+    color: #ffc107;
+}
+
+.marketplace-report-container .text-info {
+    color: #17a2b8;
+}
+
+.marketplace-report-container h5 {
+    border-bottom: 2px solid #e0e0e0;
+    padding-bottom: 10px;
+    margin-bottom: 15px;
+}
+
+.marketplace-report-container h6 {
+    font-weight: 600;
+    color: #333;
+}
+