From 90f2b5e4f3330e145d0aba07c032ba354286704e Mon Sep 17 00:00:00 2001 From: marina Date: Mon, 17 Nov 2025 10:33:34 +0300 Subject: [PATCH] =?utf8?q?ERP-453=20=D1=8D=D0=BD=D0=B4=D0=BF=D0=BE=D0=B8?= =?utf8?q?=D0=BD=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82=D0=B7?= =?utf8?q?=D1=8B=D0=B2=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- erp24/api2/controllers/ClientController.php | 225 ++++++++++++++++++ ...51114_000000_create_table_user_reviews.php | 50 ++++ erp24/records/UserReviews.php | 72 ++++++ 3 files changed, 347 insertions(+) create mode 100644 erp24/migrations/m251114_000000_create_table_user_reviews.php create mode 100644 erp24/records/UserReviews.php diff --git a/erp24/api2/controllers/ClientController.php b/erp24/api2/controllers/ClientController.php index c7f338a7..af6de708 100644 --- a/erp24/api2/controllers/ClientController.php +++ b/erp24/api2/controllers/ClientController.php @@ -23,6 +23,7 @@ use yii_app\records\Users; use yii_app\records\UsersBonus; use yii_app\records\UsersBonusLevels; use yii_app\records\UsersEvents; +use yii_app\records\UserReviews; use yii_app\services\LogService; class ClientController extends BaseController @@ -1486,4 +1487,228 @@ class ClientController extends BaseController return $this->asJson(['response' => $mess]); } + + /** + * Сохранение данных опроса пользователя + * Принимает объект (один отзыв) или массив отзывов + * @return array + */ + public function actionSaveSurvey() + { + Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; + + $request = Yii::$app->request->getRawBody(); + + try { + $data = Json::decode($request); + } catch (\Exception $ex) { + LogService::apiErrorLog(json_encode([ + 'error' => 'Json body invalid', + 'exception' => $ex->getMessage() + ], JSON_UNESCAPED_UNICODE)); + return $this->asJson(['error' => ['code' => 400, 'message' => 'Json body invalid']]); + } + + if (empty($data)) { + return $this->asJson(['error' => ['code' => 400, 'message' => 'Empty data received']]); + } + + // Если пришёл объект (один отзыв) - оборачиваем в массив + $isSingle = false; + if (!isset($data[0])) { + $data = [$data]; + $isSingle = true; + } + + $requiredFields = ['survey_id', 'sale_date', 'survey_date', 'receipt_number', 'store_id', + 'rating_florist', 'rating_cleanliness', 'rating_assortment', 'rating_quality', 'phone']; + + $results = []; + $successCount = 0; + $errorCount = 0; + $existsCount = 0; + + // Обрабатываем каждый отзыв + foreach ($data as $index => $reviewData) { + // Валидация обязательных полей + $hasError = false; + foreach ($requiredFields as $field) { + if (!isset($reviewData[$field]) || $reviewData[$field] === '') { + LogService::apiErrorLog(json_encode([ + 'error' => "$field is required", + 'index' => $index, + 'data' => $reviewData + ], JSON_UNESCAPED_UNICODE)); + + $results[] = [ + 'index' => $index, + 'status' => 'error', + 'message' => "$field is required", + 'receipt_number' => $reviewData['receipt_number'] ?? null, + 'phone' => $reviewData['phone'] ?? null + ]; + $errorCount++; + $hasError = true; + break; + } + } + + if ($hasError) { + continue; + } + + // Очистка номера телефона + $phone = ClientHelper::phoneClear($reviewData['phone']); + if (!ClientHelper::phoneVerify($phone)) { + LogService::apiErrorLog(json_encode([ + 'error' => 'Invalid phone number', + 'index' => $index, + 'phone' => $reviewData['phone'] + ], JSON_UNESCAPED_UNICODE)); + + $results[] = [ + 'index' => $index, + 'status' => 'error', + 'message' => 'Invalid phone number', + 'receipt_number' => $reviewData['receipt_number'], + 'phone' => $reviewData['phone'] + ]; + $errorCount++; + continue; + } + + // Проверка на дубликат по номеру телефона и номеру чека + $existingReview = UserReviews::find() + ->where(['phone' => $phone]) + ->andWhere(['receipt_number' => $reviewData['receipt_number']]) + ->one(); + + if ($existingReview) { + LogService::apiLogs(1, json_encode([ + 'message' => 'Review already exists', + 'index' => $index, + 'phone' => $phone, + 'receipt_number' => $reviewData['receipt_number'], + 'existing_review_id' => $existingReview->id + ], JSON_UNESCAPED_UNICODE)); + + $results[] = [ + 'index' => $index, + 'status' => 'exists', + 'message' => 'Отзыв уже существует', + 'receipt_number' => $reviewData['receipt_number'], + 'phone' => $phone, + 'review_id' => $existingReview->id + ]; + $existsCount++; + continue; + } + + // Создание новой записи + $review = new UserReviews(); + $review->survey_id = $reviewData['survey_id']; + $review->sale_date = $reviewData['sale_date']; + $review->survey_date = $reviewData['survey_date']; + $review->receipt_number = $reviewData['receipt_number']; + $review->store_id = $reviewData['store_id']; + $review->admin_id = $reviewData['admin_id'] ?? null; + $review->rating_florist = (int)$reviewData['rating_florist']; + $review->rating_cleanliness = (int)$reviewData['rating_cleanliness']; + $review->rating_assortment = (int)$reviewData['rating_assortment']; + $review->rating_quality = (int)$reviewData['rating_quality']; + $review->phone = $phone; + + if (!$review->save()) { + LogService::apiErrorLog(json_encode([ + 'error' => 'Failed to save review', + 'index' => $index, + 'validation_errors' => $review->getErrors(), + 'data' => $reviewData + ], JSON_UNESCAPED_UNICODE)); + + $results[] = [ + 'index' => $index, + 'status' => 'error', + 'message' => 'Ошибка при сохранении', + 'receipt_number' => $reviewData['receipt_number'], + 'phone' => $phone, + 'details' => $review->getErrors() + ]; + $errorCount++; + continue; + } + + LogService::apiLogs(1, json_encode([ + 'message' => 'Review saved successfully', + 'index' => $index, + 'review_id' => $review->id, + 'phone' => $phone + ], JSON_UNESCAPED_UNICODE)); + + $results[] = [ + 'index' => $index, + 'status' => 'success', + 'message' => 'Отзыв успешно сохранен', + 'receipt_number' => $reviewData['receipt_number'], + 'phone' => $phone, + 'review_id' => $review->id + ]; + $successCount++; + } + + LogService::apiLogs(1, json_encode([ + 'message' => 'Processing completed', + 'is_single' => $isSingle, + 'total' => count($data), + 'success' => $successCount, + 'exists' => $existsCount, + 'errors' => $errorCount + ], JSON_UNESCAPED_UNICODE)); + + // Если был один отзыв - возвращаем его результат напрямую + if ($isSingle) { + $result = $results[0]; + + if ($result['status'] === 'success') { + return $this->asJson([ + 'response' => [ + 'code' => 200, + 'status' => 'success', + 'message' => $result['message'], + 'review_id' => $result['review_id'] + ] + ]); + } elseif ($result['status'] === 'exists') { + return $this->asJson([ + 'response' => [ + 'code' => 200, + 'status' => 'exists', + 'message' => $result['message'], + 'review_id' => $result['review_id'] + ] + ]); + } else { + return $this->asJson([ + 'error' => [ + 'code' => 400, + 'message' => $result['message'], + 'details' => $result['details'] ?? null + ] + ]); + } + } + + // Если массив - возвращаем детальную статистику + return $this->asJson([ + 'response' => [ + 'code' => 200, + 'message' => 'Обработка завершена', + 'total' => count($data), + 'success' => $successCount, + 'exists' => $existsCount, + 'errors' => $errorCount, + 'results' => $results + ] + ]); + } } diff --git a/erp24/migrations/m251114_000000_create_table_user_reviews.php b/erp24/migrations/m251114_000000_create_table_user_reviews.php new file mode 100644 index 00000000..dd5c7890 --- /dev/null +++ b/erp24/migrations/m251114_000000_create_table_user_reviews.php @@ -0,0 +1,50 @@ +db->getTableSchema(self::TABLE_NAME); + if (!isset($tableSchema)) { + $this->createTable(self::TABLE_NAME, [ + 'id' => $this->primaryKey(), + 'survey_id' => $this->string()->notNull()->comment('ID опроса'), + 'sale_date' => $this->timestamp()->notNull()->comment('Дата продажи'), + 'survey_date' => $this->timestamp()->notNull()->comment('Дата опроса'), + 'receipt_number' => $this->string()->notNull()->comment('Номер чека'), + 'store_id' => $this->string()->notNull()->comment('ID магазина'), + 'admin_id' => $this->string()->null()->comment('ID администратора'), + 'rating_florist' => $this->integer()->notNull()->comment('Оценка работы флориста'), + 'rating_cleanliness' => $this->integer()->notNull()->comment('Оценка чистоты и комфорта в магазине'), + 'rating_assortment' => $this->integer()->notNull()->comment('Оценка ассортимента цветов'), + 'rating_quality' => $this->integer()->notNull()->comment('Оценка выбора и качества букетов'), + 'phone' => $this->string()->notNull()->comment('Номер телефона клиента'), + 'created_at' => $this->timestamp()->defaultExpression('CURRENT_TIMESTAMP')->comment('Дата создания записи'), + 'updated_at' => $this->timestamp()->defaultExpression('CURRENT_TIMESTAMP')->comment('Дата обновления записи'), + ]); + } + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $tableSchema = $this->db->getTableSchema(self::TABLE_NAME); + + if (isset($tableSchema)) { + $this->dropTable(self::TABLE_NAME); + } + } +} + diff --git a/erp24/records/UserReviews.php b/erp24/records/UserReviews.php new file mode 100644 index 00000000..fe02b73e --- /dev/null +++ b/erp24/records/UserReviews.php @@ -0,0 +1,72 @@ + 1, 'max' => 5], + [['survey_id', 'receipt_number', 'store_id', 'admin_id', 'phone'], 'string', 'max' => 255], + ]; + } + + /** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'survey_id' => 'ID опроса', + 'sale_date' => 'Дата продажи', + 'survey_date' => 'Дата опроса', + 'receipt_number' => 'Номер чека', + 'store_id' => 'ID магазина', + 'admin_id' => 'ID администратора', + 'rating_florist' => 'Оценка работы флориста', + 'rating_cleanliness' => 'Оценка чистоты и комфорта в магазине', + 'rating_assortment' => 'Оценка ассортимента цветов', + 'rating_quality' => 'Оценка выбора и качества букетов', + 'phone' => 'Номер телефона клиента', + 'created_at' => 'Дата создания записи', + 'updated_at' => 'Дата обновления записи', + ]; + } +} + -- 2.39.5