From 6807235fcc8b53fdea3d94eeafb47c8e50600df1 Mon Sep 17 00:00:00 2001 From: Vladimir Fomichev Date: Mon, 3 Nov 2025 13:31:23 +0300 Subject: [PATCH] =?utf8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F=D0=B5?= =?utf8?q?=D0=BC=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20=D0=B4=D0=BB?= =?utf8?q?=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D1=8F?= =?utf8?q?=20=D0=BC=D0=B0=D0=B3=D0=B0=D0=B7=D0=B8=D0=BD=D0=BE=D0=B2=20?= =?utf8?q?=D0=B8=20=D1=87=D0=B5=D0=BA=D0=BE=D0=B2=20=D0=BF=D1=80=D0=BE?= =?utf8?q?=D0=B4=D0=B0=D0=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- erp24/api2/controllers/DataTestController.php | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/erp24/api2/controllers/DataTestController.php b/erp24/api2/controllers/DataTestController.php index 33858cda..81e81971 100644 --- a/erp24/api2/controllers/DataTestController.php +++ b/erp24/api2/controllers/DataTestController.php @@ -93,4 +93,220 @@ class DataTestController extends BaseController { return $this->asJson(['response' => true]); } + + /** + * Возвращает JSON со списком магазинов (id, name) + * GET /api2/data-test/get-stores + */ + public function actionGetStores() { + Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + + try { + $stores = \yii_app\records\CityStore::find() + ->select(['id', 'name']) + ->orderBy(['name' => SORT_ASC]) + ->asArray() + ->all(); + + return $this->asJson([ + 'success' => true, + 'data' => $stores + ]); + } catch (Exception $e) { + return $this->asJson([ + 'success' => false, + 'error' => $e->getMessage() + ]); + } + } + + /** + * Возвращает JSON с агрегированными покупками по дате, смене и магазину + * POST /api2/data-test/get-sales + * + * Тело запроса: + * { + * "date": "2025-10-10", + * "shift_type": 1, + * "store_id": 5 (опционально) + * } + * + * shift_type: + * 0 = с 8:00 до 8:00 следующего дня (все) + * 1 = с 8:00 до 20:00 (день) + * 2 = с 20:00 до 8:00 (ночь) + */ + public function actionGetSales() { + set_time_limit(300); + Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + + $request = Yii::$app->request->getRawBody(); + + try { + $input = Json::decode($request); + } catch (Exception $ex) { + return $this->asJson([ + 'success' => false, + 'error' => 'Invalid JSON body' + ]); + } + + // Валидация обязательных параметров + if (empty($input['date'])) { + return $this->asJson([ + 'success' => false, + 'error' => 'Date is required' + ]); + } + + $date = $input['date']; + $shiftType = $input['shift_type'] ?? 0; + $storeIdFilter = $input['store_id'] ?? null; + + try { + // Определяем диапазон времени для смены + $dateObj = new \DateTime($date); + $currentDateStr = $dateObj->format('Y-m-d'); + + // Получаем дату следующего дня + $nextDateObj = clone $dateObj; + $nextDateStr = $nextDateObj->modify('+1 day')->format('Y-m-d'); + + $dayStart = $currentDateStr . ' 08:00:00'; + $dayEnd = $currentDateStr . ' 20:00:00'; + $nightStart = $currentDateStr . ' 20:00:00'; + $nightEnd = $currentDateStr . ' 23:59:59'; + $nextDayStart = $nextDateStr . ' 00:00:00'; + $nextDayEnd = $nextDateStr . ' 08:00:00'; + + // Построение базового запроса продаж + $query = \yii_app\records\Sales::find() + ->where(['or', ['order_id' => ''], ['order_id' => 0]]) // Только офлайн продажи + ->orderBy(['store_id' => SORT_ASC, 'date' => SORT_ASC]); + + // Фильтр по смене + if ($shiftType === 1) { + // День: 8:00 - 20:00 + $query->andWhere(['between', 'date', $dayStart, $dayEnd]); + } elseif ($shiftType === 2) { + // Ночь: 20:00 - 8:00 следующего дня + $query->andWhere(['OR', + ['between', 'date', $nightStart, $nightEnd], + ['between', 'date', $nextDayStart, $nextDayEnd] + ]); + } else { + // Все смены (вся дата) + $query->andWhere(['between', 'date', $currentDateStr . ' 00:00:00', $currentDateStr . ' 23:59:59']); + } + + // Фильтр по магазину если задан + if (!empty($storeIdFilter)) { + $query->andWhere(['store_id' => $storeIdFilter]); + } + + $sales = $query->with('products')->asArray()->all(); + + if (empty($sales)) { + return $this->asJson([ + 'success' => true, + 'data' => [] + ]); + } + + // Агрегируем данные и присоединяем информацию о товарах + $aggregated = []; + $storeRegions = []; + + foreach ($sales as $sale) { + $saleStoreId = $sale['store_id']; + + // Кэшируем регион магазина + if (!isset($storeRegions[$saleStoreId])) { + $storeParams = \yii_app\records\CityStoreParams::findOne(['store_id' => $saleStoreId]); + $storeRegions[$saleStoreId] = $storeParams ? $storeParams->address_region : null; + } + + $saleKey = $saleStoreId . '_' . $sale['date']; // Ключ для агрегации + + if (!isset($aggregated[$saleKey])) { + $aggregated[$saleKey] = [ + 'id' => $sale['id'], + 'date' => $sale['date'], + 'store_id' => (int)$saleStoreId, + 'summ' => (float)$sale['summ'], + 'operation' => $sale['operation'], + 'status' => $sale['status'], + 'skidka' => (float)$sale['skidka'], + 'products' => [] + ]; + } else { + // Суммируем значения + $aggregated[$saleKey]['summ'] += (float)$sale['summ']; + $aggregated[$saleKey]['skidka'] += (float)$sale['skidka']; + } + + // Получаем товары из этого чека + $products = \yii_app\records\SalesProducts::find() + ->where(['check_id' => $sale['id']]) + ->asArray() + ->all(); + + foreach ($products as $product) { + // Получаем информацию о товаре + $productInfo = \yii_app\records\Products1c::find() + ->where(['id' => $product['product_id']]) + ->select(['id', 'name']) + ->asArray() + ->one(); + + // Получаем актуальную цену товара + $regionId = $storeRegions[$saleStoreId]; + $priceQuery = \yii_app\records\PricesDynamic::find() + ->where(['product_id' => $product['product_id']]) + ->andWhere(['active' => \yii_app\records\PricesDynamic::ACTIVE]); + + // Приоритет: сначала ищем с регионом, потом без + if ($regionId) { + $priceQuery->andWhere(['region_id' => $regionId]); + } + + $priceData = $priceQuery->select(['price']) + ->orderBy(['date_from' => SORT_DESC]) + ->asArray() + ->one(); + + $productData = [ + 'product_id' => $product['product_id'], + 'name' => $productInfo['name'] ?? 'Unknown', + 'quantity' => (float)$product['quantity'], + 'price' => $priceData ? (float)$priceData['price'] : (float)$product['price'], + 'discount' => (float)$product['discount'], + 'summ' => (float)$product['summ'] + ]; + + $aggregated[$saleKey]['products'][] = $productData; + } + } + + // Группируем по магазину + $grouped = []; + foreach ($aggregated as $sale) { + $storeId = $sale['store_id']; + // Убираем store_id из объекта продажи, так как он будет в ключе + unset($sale['store_id']); + $grouped[$storeId][] = $sale; + } + + return $this->asJson([ + 'success' => true, + 'data' => $grouped + ]); + + } catch (Exception $e) { + return $this->asJson([ + 'success' => false, + 'error' => $e->getMessage() + ]); + } + } } -- 2.39.5