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
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
+ ]
+ ]);
+ }
}
--- /dev/null
+<?php
+
+use yii\db\Migration;
+
+/**
+ * Class m251114_000000_create_table_user_reviews
+ */
+class m251114_000000_create_table_user_reviews extends Migration
+{
+ const TABLE_NAME = 'erp24.user_reviews';
+
+ /**
+ * {@inheritdoc}
+ */
+ public function safeUp()
+ {
+ $tableSchema = $this->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);
+ }
+ }
+}
+
--- /dev/null
+<?php
+
+namespace yii_app\records;
+
+use Yii;
+
+/**
+ * This is the model class for table "user_reviews".
+ *
+ * @property int $id
+ * @property string $survey_id ID опроса
+ * @property string $sale_date Дата продажи
+ * @property string $survey_date Дата опроса
+ * @property string $receipt_number Номер чека
+ * @property string $store_id ID магазина
+ * @property string|null $admin_id ID администратора
+ * @property int $rating_florist Оценка работы флориста
+ * @property int $rating_cleanliness Оценка чистоты и комфорта в магазине
+ * @property int $rating_assortment Оценка ассортимента цветов
+ * @property int $rating_quality Оценка выбора и качества букетов
+ * @property string $phone Номер телефона клиента
+ * @property string $created_at Дата создания записи
+ * @property string $updated_at Дата обновления записи
+ */
+class UserReviews extends \yii\db\ActiveRecord
+{
+ /**
+ * {@inheritdoc}
+ */
+ public static function tableName()
+ {
+ return 'user_reviews';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rules()
+ {
+ return [
+ [['survey_id', 'sale_date', 'survey_date', 'receipt_number', 'store_id', 'rating_florist', 'rating_cleanliness', 'rating_assortment', 'rating_quality', 'phone'], 'required'],
+ [['sale_date', 'survey_date', 'created_at', 'updated_at'], 'safe'],
+ [['rating_florist', 'rating_cleanliness', 'rating_assortment', 'rating_quality'], 'integer'],
+ [['rating_florist', 'rating_cleanliness', 'rating_assortment', 'rating_quality'], 'integer', 'min' => 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' => 'Дата обновления записи',
+ ];
+ }
+}
+