From: Vladimir Fomichev Date: Wed, 5 Nov 2025 15:04:20 +0000 (+0300) Subject: Детальный отчет по магазинам X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=af622e72dfe8133c552f29bc2fb5197a872e245f;p=erp24_rep%2Fyii-erp24%2F.git Детальный отчет по магазинам --- diff --git a/erp24/actions/dashboard/SalesDetailAction.php b/erp24/actions/dashboard/SalesDetailAction.php new file mode 100644 index 00000000..118e034c --- /dev/null +++ b/erp24/actions/dashboard/SalesDetailAction.php @@ -0,0 +1,214 @@ +getRequest(); + + $date1 = date("Y-m-d", time()); + $date2 = date("Y-m-d", time()); + + $daysSearchForm = new DaysSearchForm(); + + if (Yii::$app->request->isAjax && $daysSearchForm->load(Yii::$app->request->post())) { + Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + return ActiveForm::validate($daysSearchForm); + } + + if ($request->isPost && !empty($this->controller->request->post())) { + $daysSearchForm->load($this->controller->request->post()); + $daysSearchForm->validate(); + } + + if (empty($daysSearchForm->dateFrom)) { + $daysSearchForm->dateFrom = $date1; + } + + if (empty($daysSearchForm->dateTo)) { + $daysSearchForm->dateTo = $date2; + } + + $getDate1 = $daysSearchForm->dateFrom; + + if (!empty($getDate1)) { + $date_s = htmlentities($getDate1); + $date1 = "$date_s"; + $date2 = "$date_s"; + } + + $getDate2 = $daysSearchForm->dateTo; + + if (!empty($getDate2)) { + $date_s = htmlentities($getDate2); + $date2 = "$date_s"; + } + + $entityByCityStore = ExportImportService::getEntityByCityStore(); + $exportData = ExportImportService::getExportData($entityByCityStore); + + $export = ArrayHelper::getValue($exportData, 'export'); + $export_revers = ArrayHelper::getValue($exportData, 'export_revers'); + + $storeIds = array_values($export_revers); + + $cityStores = CityStore::find() + ->select(['id', 'name', 'export_val']) + ->joinWith('storeGuid') + ->andWhere(['id' => $storeIds]) + ->indexBy('id') + ->asArray() + ->all(); + + $city_stores = Products1c::find() + ->select(['name', 'id']) + ->indexBy('id') + ->andWhere('tip=:tip', [':tip' => 'city_store']) + ->column(); + + // Получение продаж без доставки (офлайн) + $salesOffline = $this->getSalesDetailRecords($date1, $date2, false); + + // Получение продаж с доставкой + $salesDelivery = $this->getSalesDetailRecords($date1, $date2, true); + + // Группировка по магазинам + $salesOfflineByStore = $this->groupSalesByStore($salesOffline); + $salesDeliveryByStore = $this->groupSalesByStore($salesDelivery); + + $params = [ + 'date1' => $date1, + 'date2' => $date2, + 'daysSearchForm' => $daysSearchForm, + 'cityStores' => $cityStores, + 'city_stores' => $city_stores, + 'export_revers' => $export_revers, + 'salesOfflineByStore' => $salesOfflineByStore, + 'salesDeliveryByStore' => $salesDeliveryByStore, + ]; + + return $this->controller->render('/dashboard/sales-detail.php', $params); + } + + /** + * Получить детальные записи о продажах + * + * @param string $dateFrom + * @param string $dateTo + * @param bool $withDelivery - true для доставки, false для офлайн + * @return array + * @throws \Exception + */ + private function getSalesDetailRecords(string $dateFrom, string $dateTo, bool $withDelivery = false): array + { + $query = Sales::find() + ->alias('s') + ->select([ + 's.id', + 's.date', + 's.summ', + 's.skidka', + 's.operation', + 's.order_id', + 's.store_id_1c', + 's.store_id', + 's.number', + ]) + ->joinWith('saleCheck') + ->andWhere(['>=', 's.date', DateHelper::getDateTimeStartDay($dateFrom, true)]) + ->andWhere(['<=', 's.date', DateHelper::getDateTimeEndDay($dateTo, true)]) + ->orderBy(['s.date' => SORT_DESC, 's.id' => SORT_DESC]); + + if (!$withDelivery) { + // Офлайн продажи - без заказов + $query->andWhere([ + 'and', + ['s.order_id' => ['', '0']], + [ + 'or', + 'sc.order_id IS NULL', + ['sc.order_id' => ['', '0']] + ] + ]); + } else { + // Продажи с доставкой - с заказами + $query->leftJoin('create_checks cc', 'CAST(cc.order_id AS TEXT) = s.order_id') + ->andFilterWhere(['or', + ['not in', 's.order_id', ['', '0']], + ['not in', 'sc.order_id', ['', '0']] + ]) + ->andWhere(['or', + ['cc.date' => null], + ['DATE(cc.date)' => new \yii\db\Expression('DATE(s.date)')] + ]); + } + + return $query->asArray()->all(); + } + + /** + * Группировка продаж по магазинам + * + * @param array $sales + * @return array + */ + private function groupSalesByStore(array $sales): array + { + $grouped = []; + + foreach ($sales as $sale) { + $storeId1c = $sale['store_id_1c']; + + if (!isset($grouped[$storeId1c])) { + $grouped[$storeId1c] = [ + 'store_id_1c' => $storeId1c, + 'sales' => [], + 'total_summ' => 0, + 'total_skidka' => 0, + ]; + } + + $saleAmount = $sale['summ'] - $sale['skidka']; + + // Применяем операцию (продажа или возврат) + if ($sale['operation'] === Sales::OPERATION_SALE) { + $grouped[$storeId1c]['total_summ'] += $saleAmount; + } elseif ($sale['operation'] === Sales::OPERATION_RETURN) { + $grouped[$storeId1c]['total_summ'] -= $saleAmount; + } + + $grouped[$storeId1c]['sales'][] = $sale; + } + + // Сортировка магазинов по сумме продаж (убывание) + uasort($grouped, function ($a, $b) { + return $b['total_summ'] <=> $a['total_summ']; + }); + + return $grouped; + } +} + diff --git a/erp24/controllers/DashboardController.php b/erp24/controllers/DashboardController.php index bb880b04..052c9e65 100755 --- a/erp24/controllers/DashboardController.php +++ b/erp24/controllers/DashboardController.php @@ -12,6 +12,7 @@ class DashboardController extends \yii\web\Controller return [ 'index' => \yii_app\actions\dashboard\IndexAction::class, 'sales' => \yii_app\actions\dashboard\SalesAction::class, + 'sales-detail' => \yii_app\actions\dashboard\SalesDetailAction::class, 'commercial' => \yii_app\actions\dashboard\CommercialAction::class, 'commercial-detail-info' => \yii_app\actions\dashboard\CommercialDetailInfoAction::class, 'commercial-sales-info' => \yii_app\actions\dashboard\CommercialSalesInfoAction::class, diff --git a/erp24/views/dashboard/sales-detail.php b/erp24/views/dashboard/sales-detail.php new file mode 100644 index 00000000..2c74689b --- /dev/null +++ b/erp24/views/dashboard/sales-detail.php @@ -0,0 +1,278 @@ + + +

Детальный просмотр продаж

+ + 'days-search-form-detail', + 'enableAjaxValidation' => true, + 'validationUrl' => 'validate', + 'options' => ['enctype' => 'multipart/form-data'] +]); ?> + +
+
+ field($daysSearchForm, 'dateFrom', [ + 'inputOptions' => [ + 'class' => 'form-control datetime', + 'type' => 'date', + 'placeholder' => 'начало', + ], + 'options' => ['tag' => null], + ])->label(false)->textInput() ?> +
+
+ field($daysSearchForm, 'dateTo', [ + 'inputOptions' => [ + 'class' => 'form-control datetime', + 'type' => 'date', + 'placeholder' => 'конец', + ], + 'options' => ['tag' => null], + ])->label(false)->textInput() ?> +
+
+
+ + 'btn btn-success']) ?> +
+
+
+ + + +
+ + + +
+

+ Офлайн продажи (без доставки) за +

+ + +
+ $storeData): ?> + +
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
IDДата и времяСуммаОперацияНомерOrder ID
+ + + + + + + + + + + + + + — + +
+
+
+
+ +
+ +
Нет данных об офлайн продажах за выбранный период
+ +
+ + +
+

+ Продажи с доставкой за +

+ + +
+ $storeData): ?> + +
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
IDДата и времяСуммаОперацияНомерOrder ID
+ + + + + + + + + + + + + + — + +
+
+
+
+ +
+ +
Нет данных о доставке за выбранный период
+ +
+ + +
+ Нет данных за выбранный период - +
+ +
+ +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; +} +'); +?> + diff --git a/erp24/views/dashboard/sales.php b/erp24/views/dashboard/sales.php index 0f730805..56332242 100755 --- a/erp24/views/dashboard/sales.php +++ b/erp24/views/dashboard/sales.php @@ -54,7 +54,12 @@ tr.line.bg-danger>td>a.btn { '); ?> -

Продажи

+
+

Продажи

+ + Детальный просмотр + +
'days-search-form',