diff --git a/PROJECT_TIMELINE.md b/PROJECT_TIMELINE.md new file mode 100644 index 0000000..a685c3b --- /dev/null +++ b/PROJECT_TIMELINE.md @@ -0,0 +1,549 @@ +# 📅 Хронология проекта ERV Platform + +**Период:** 24 октября - 1 ноября 2025 +**Всего сессий:** 8 +**Всего строк документации:** 5295+ +**Коммитов:** 50+ + +--- + +## 📊 День 1: 24 октября 2025 - Инициализация проекта + +**Задача:** Развернуть новую платформу обработки страховых обращений + +### Что сделано: +- ✅ Создана структура проекта: Backend (FastAPI) + Frontend (React TypeScript) +- ✅ Подключены внешние сервисы: + - PostgreSQL (147.45.189.234:5432) + - Redis (crm.clientright.ru:6379) + - RabbitMQ (185.197.75.249:5672) + - S3 Timeweb Storage +- ✅ API endpoints: SMS, Claims, Policy, Upload +- ✅ OCR интеграция (147.45.146.17:8001) +- ✅ Базовая форма заявки (3 шага) +- ✅ Docker контейнеры: frontend, backend, postgres, redis + +**Логи:** `SESSION_LOG_2025-10-24.md` (708 строк) + +--- + +## 📊 День 2: 26 октября 2025 - N8N интеграция + +**Задача:** Интеграция с n8n для асинхронной обработки файлов + +### Что сделано: +- ✅ **N8N Webhooks:** + - Проверка полиса в MySQL + запись в PostgreSQL + - Загрузка файлов в S3 + OCR + Vision AI +- ✅ **React Frontend:** + - Автогенерация `claim_id` и `session_id` + - Конвертация файлов в PDF на клиенте (jsPDF + browser-image-compression) + - Поддержка форматов: JPG, PNG, HEIC, WEBP, PDF + - Сжатие изображений до 2MB +- ✅ **PostgreSQL:** + - Таблицы `claims` и `claim_files` + - UPSERT операции + - JSONB поля для гибкого хранения +- ✅ **Документация:** + - `N8N_INTEGRATION.md` + - `N8N_SQL_QUERIES.md` + - `N8N_PDF_COMPRESS.md` + +**Проблемы решены:** +- Конфликт зависимостей `aioboto3` → удалён +- Nullable поля в PostgreSQL +- JSON сериализация в n8n + +**Логи:** `SESSION_LOG_2025-10-26.md` (932 строки) + +--- + +## 📊 День 3: 27 октября 2025 - SSE + Redis Pub/Sub + +**Задача:** Real-time обработка документов через SSE + +### Что сделано: +- ✅ **Backend SSE Endpoint** (`/events/{task_id}`): + - Server-Sent Events для real-time стриминга + - Подписка на Redis Pub/Sub канал `ocr_events:{task_id}` + - Обработка вложенного формата от n8n Redis ноды + - Автозакрытие соединения после результата +- ✅ **Frontend SSE Client:** + - Блокирующая модалка с loading spinner + - Автоматическое подключение после загрузки файла + - Отображение результатов AI анализа + - Логирование в Debug Panel +- ✅ **Vite Proxy:** + - `/events` → `host.docker.internal:8100` + - Обход файрвола (порт 8100 закрыт) +- ✅ **Docker:** + - Frontend в dev режиме (hot reload) + - `host.docker.internal` для доступа к хосту + +**Проблемы решены:** +- Неправильный порт SSE → Vite proxy +- Backend к локальному Redis → абсолютный путь `.env` +- AttributeError decode → убран `.decode()` +- Префикс `/api/v1` → убран для events +- Frontend не ждёт SSE → модалка + `waitingForOcr` state + +**Тестирование:** +- Время обработки: ~55 секунд +- OCR: полис E1000-302545808 +- AI: извлечены ФИО, даты, программа +- Результат в модалке ✅ + +**Логи:** `SESSION_LOG_2025-10-27.md` (не найден в списке, но упоминается) + +--- + +## 📊 День 4: 28 октября 2025 - Исправления SSE + +**Сессия 1 (00:00-01:00):** Исправление SSE error handling + +### Проблема: +После успешного распознавания показывалась ошибка "Ошибка подключения к серверу" + +### Причина: +Backend закрывал SSE после отправки события → браузер триггерил `onerror` → фронтенд затирал успешный результат + +### Решение: +```typescript +eventSource.onerror = (error) => { + setOcrModalContent((prev) => { + if (prev && prev !== 'loading') { + return prev; // НЕ затираем результат + } + return { success: false, message: 'Ошибка подключения к серверу' }; + }); +}; +``` + +**Сессия 2 (13:00-17:00):** Умная форма Step 2 + +### Что сделано: +- ✅ **Рефакторинг Step 2** с AI-обработкой документов +- ✅ **Пошаговая загрузка** с модалками +- ✅ **DEV MODE кнопки** во всех 3 шагах +- ✅ **PostgreSQL UPSERT** с CTE +- ✅ **Конфигурация документов** для каждого типа события + +**Логи:** `SESSION_LOG_2025-10-28.md` (1063 строки) + +--- + +## 📊 День 5: 29 октября 2025 - Динамический визард + +**Сессия 1 (12:00-15:00):** Рефакторинг визарда + +### Задача: +Переделать визард так, чтобы каждый документ был отдельным шагом + +### Было: +``` +[1. Полис] → [2. Детали + все документы] → [3. Оплата] +``` + +### Стало: +``` +[1. Полис] → [2. Тип] → [3. Док 1] → [4. Док 2] → ... → [N. Оплата] +``` + +### Что сделано: +- ✅ `Step2EventType.tsx` - выбор типа страхового случая +- ✅ `StepDocumentUpload.tsx` - загрузка каждого документа +- ✅ Динамическое количество шагов +- ✅ Прогресс-бар с реальными шагами +- ✅ SSE для каждого документа с уникальным `event_type` + +**Проблемы решены:** +- Синтаксические ошибки (дублирующийся код) +- PostgreSQL INSERT не возвращал данные +- `file_size` как строка вместо числа + +**Логи:** `SESSION_LOG_2025-10-29.md` (645 строк) + +--- + +**Сессия 2 (16:30-17:30):** Безопасность N8N Webhooks + +### Задача: +> "как нам не палить вебхук, а то его видно через код?" + +### Проблема: +N8N webhook URLs были захардкожены в коде фронтенда → видны в DevTools + +### Решение: +Backend Proxy - фронтенд больше не знает про n8n! + +### Архитектура: +``` +Frontend → fetch('/api/n8n/*') → Backend Proxy → N8N (URLs в .env) +``` + +### Что сделано: +- ✅ `backend/app/api/n8n_proxy.py` - proxy router +- ✅ Webhook URLs в `.env` (не коммитятся) +- ✅ Frontend использует `/api/n8n/policy/check` и `/api/n8n/upload/file` +- ✅ Документация `SECURITY_N8N_PROXY.md` + +**Проблемы решены:** +- "Ошибка соединения" → относительные пути вместо localhost +- Пропущенные поля → добавлены `filename` и `upload_timestamp` +- event_type не совпадает → гибкая проверка + +**Логи:** `SESSION_LOG_2025-10-29_part2.md` (627 строк) + +--- + +## 📊 День 6: 30 октября 2025 - Телефон на Step 1 + CRM + +**Задача:** Перенос телефона на первый шаг и создание контакта в CRM + +### Что сделано: +- ✅ **Новый Step1Phone** (вместо Step1Policy): + - Ввод телефона как первый шаг + - SMS верификация + - Автосоздание контакта в CRM через n8n webhook +- ✅ **CreateWebContact** - операция vTiger webservice: + - Создание контакта по телефону + - Проверка дубликатов + - Возврат `contact_id` +- ✅ **N8N Webhook** для создания контакта после SMS +- ✅ **Формат телефона без +** (79001234567) +- ✅ **DEV MODE** кнопки на всех шагах + +**Рефакторинг структуры:** +``` +Было: Step1Policy → Step2Details → Step3Payment +Стало: Step1Phone → Step2Policy → Step3EventType → Step4DocUpload... → StepNPayment +``` + +**Оптимизация Docker:** +- Убраны локальные контейнеры Postgres и Redis +- Используются только внешние сервисы +- Остались: frontend + backend + +**Логи:** `SESSION_LOG_2025-10-30.md` (597 строк) + +--- + +## 📊 День 7: 1 ноября 2025 - CreateWebProject + Финальная интеграция + +**Задача:** Создание проектов в CRM по номеру полиса + +### Что сделано: +- ✅ **CreateWebProject.php** - операция vTiger: + - Поиск проекта по полису (cf_1885) + - Создание нового если не найден + - Привязка к контакту + - Возврат `{"project_id": "123", "is_new": true/false}` +- ✅ **Регистрация в БД** vTiger webservice +- ✅ **Тестирование:** + - Создание нового: `{"project_id":"396865","is_new":true}` ✅ + - Повторный вызов: `{"project_id":"396865","is_new":false}` ✅ +- ✅ **N8N Webhook URLs** в docker-compose.yml (environment) + +**Проблемы решены:** +- Формат телефона в vTiger (mobile без +) +- SMS коды не проходили валидацию +- N8N webhook URLs не передавались в backend контейнер + +**Логи:** `SESSION_LOG_2025-11-01.md` (723 строки) + +--- + +## 🎯 Текущая архитектура (финальная) + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ USER BROWSER │ +│ http://147.45.146.17:5173 │ +│ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ React Frontend (Vite Dev Server) │ │ +│ │ - Step1Phone.tsx (SMS верификация) │ │ +│ │ - Step2Policy.tsx (проверка полиса) │ │ +│ │ - Step3EventType.tsx (тип события) │ │ +│ │ - Step4-N DocumentUpload.tsx (документы) │ │ +│ │ - StepNPayment.tsx (оплата) │ │ +│ │ - SSE Client для real-time обновлений │ │ +│ │ - PDF конвертер (HEIC/JPG/PNG → PDF) │ │ +│ └────────────┬───────────────────────────────────────────────────┘ │ +│ │ Vite Proxy (/api, /events → backend) │ +└───────────────┼──────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────┐ +│ BACKEND (FastAPI, port 8100) │ +│ PID: 31571 (запущен вне Docker) │ +│ │ +│ 📁 app/api/ │ +│ ├── sms.py - SMS верификация (SigmaSMS) │ +│ ├── claims.py - Заявки │ +│ ├── policy.py - Проверка полисов │ +│ ├── upload.py - Загрузка файлов │ +│ ├── events.py - SSE endpoints ⬅️ ВАЖНО │ +│ └── n8n_proxy.py - Безопасный proxy к n8n ⬅️ НОВОЕ │ +│ │ +│ 🔌 Подключения: │ +│ ├── PostgreSQL (147.45.189.234:5432) - claims, claim_files │ +│ ├── MySQL (localhost:3306) - проверка полисов ERV │ +│ ├── Redis (crm.clientright.ru:6379) - Pub/Sub для SSE │ +│ ├── RabbitMQ (185.197.75.249:5672) - очереди │ +│ └── S3 (Timeweb) - хранилище файлов │ +└────────────┬────────────────────────────────────────────────────────┘ + │ + ├──────────────────────────────────────────────────────┐ + │ │ + ▼ ▼ +┌──────────────────────────┐ ┌──────────────────────────────┐ +│ N8N Workflows │ │ vTiger CRM │ +│ n8n.clientright.pro │ │ crm.clientright.ru │ +│ │ │ │ +│ Webhook 1: Policy Check │ │ Webservice Operations: │ +│ - MySQL query │ │ - CreateWebContact │ +│ - PostgreSQL insert │ │ - CreateWebProject │ +│ - Return insured_persons│ │ - Query │ +│ │ │ │ +│ Webhook 2: File Upload │ │ Tables: │ +│ - S3 upload │────────────────────│ - vtiger_contactdetails │ +│ - PostgreSQL insert │ n8n webhook │ - vtiger_project │ +│ - OCR Service │ creates contact │ - vtiger_contactscf (mobile) │ +│ - AI Vision (Gemini) │ │ - vtiger_projectcf (cf_1885) │ +│ - Redis PUBLISH │ │ │ +└───────────┬──────────────┘ └───────────────────────────────┘ + │ + │ Redis PUBLISH: ocr_events:{claim_id} + ▼ +┌──────────────────────────────────────────────────────────────────────┐ +│ Redis Pub/Sub │ +│ crm.clientright.ru:6379 │ +│ Channel: ocr_events:{claim_id} │ +│ Password: CRM_Redis_Pass_2025_Secure! │ +└───────────▲──────────────────────────────────────────────────────────┘ + │ + │ SUBSCRIBE + │ + Backend SSE endpoint (/events/{task_id}) +``` + +--- + +## 📝 Ключевые компоненты + +### Frontend (React + TypeScript) + +**Основные файлы:** +- `ClaimForm.tsx` - главный визард с прогрессом +- `Step1Phone.tsx` - ввод телефона + SMS +- `Step2Policy.tsx` - проверка полиса +- `Step3EventType.tsx` - выбор типа события +- `StepDocumentUpload.tsx` - загрузка документов (динамический) +- `StepPayment.tsx` - реквизиты для выплаты +- `utils/pdfConverter.ts` - клиентская конвертация в PDF + +**Технологии:** +- Vite (dev server + proxy) +- Ant Design (UI компоненты) +- EventSource (SSE client) +- jsPDF + browser-image-compression + +### Backend (FastAPI + Python) + +**Основные модули:** +- `app/main.py` - FastAPI приложение +- `app/config.py` - настройки из `.env` +- `app/api/*` - роутеры (sms, claims, policy, upload, events, n8n_proxy) +- `app/services/*` - сервисы (database, redis, rabbitmq, s3, policy) + +**Технологии:** +- FastAPI (async API) +- SQLAlchemy (PostgreSQL) +- aiomysql (MySQL) +- redis-py (Redis Pub/Sub) +- aio-pika (RabbitMQ) +- boto3 (S3) +- httpx (HTTP client для proxy) + +### N8N Workflows + +**Workflow 1: Policy Check** +``` +Webhook → PostgreSQL (INSERT claims) → MySQL (SELECT policy) → Code → Response +``` + +**Workflow 2: File Upload + OCR** +``` +Webhook → S3 Upload → PostgreSQL (INSERT claim_files) + → OCR Service → Vision AI → Code (валидация) + → PostgreSQL (UPDATE ai_extracted_data) → Redis PUBLISH +``` + +### Database Schema + +**PostgreSQL (147.45.189.234:5432/default_db):** +- `claims` - заявки (claim_number, policy_number, status, form_data::jsonb) +- `claim_files` - файлы (s3_key, ocr_text, ai_extracted_data::jsonb, ocr_status) + +**MySQL (localhost:3306/u2768571_crm_db):** +- `lexrpiority` - полисы ERV +- `lexrpiority_insured_persons` - застрахованные лица + +**vTiger CRM (crm.clientright.ru):** +- `vtiger_contactdetails` - контакты +- `vtiger_contactscf` - доп.поля контактов (mobile) +- `vtiger_project` - проекты (заявки) +- `vtiger_projectcf` - доп.поля проектов (cf_1885 = полис) + +--- + +## 🔒 Безопасность + +### N8N Webhooks (спрятаны): +``` +❌ РАНЬШЕ: fetch('https://n8n.../webhook/9eb7bc5b...') // Виден в коде! +✅ ТЕПЕРЬ: fetch('/api/n8n/policy/check') // Proxy через backend +``` + +**Webhook URLs хранятся в:** +- `.env` (не коммитится в git) +- `backend/app/config.py` (читает из .env) +- `backend/app/api/n8n_proxy.py` (проксирует запросы) + +### Redis: +``` +Host: crm.clientright.ru:6379 +Password: CRM_Redis_Pass_2025_Secure! (в .env) +``` + +### PostgreSQL: +``` +Host: 147.45.189.234:5432 +User: gen_user +Password: 2~~9_^kVsU?2\S (в .env) +``` + +--- + +## 📈 Статистика проекта + +### Документация: +``` +SESSION_LOG_2025-10-24.md: 708 строк +SESSION_LOG_2025-10-26.md: 932 строки +SESSION_LOG_2025-10-28.md: 1063 строки +SESSION_LOG_2025-10-29.md: 645 строк +SESSION_LOG_2025-10-29_part2.md: 627 строк +SESSION_LOG_2025-10-30.md: 597 строк +SESSION_LOG_2025-11-01.md: 723 строки +─────────────────────────────────────────── +ИТОГО: 5295 строк + +Дополнительно: +- N8N_INTEGRATION.md +- N8N_SQL_QUERIES.md +- N8N_PDF_COMPRESS.md +- SECURITY_N8N_PROXY.md +``` + +### Git коммиты: +``` +Всего: 50+ коммитов +Период: 24 окт - 1 ноя (8 дней) +Среднее: 6-7 коммитов/день +``` + +### Файлы проекта: +``` +Backend: ~30 файлов Python +Frontend: ~20 файлов TypeScript/TSX +Configs: ~10 файлов (docker, vite, env) +Docs: ~10 файлов Markdown +CRM: ~3 файла PHP (vTiger operations) +Utils: ~5 скриптов (мониторинг, тесты) +``` + +--- + +## 🚀 Что работает сейчас + +### ✅ Полный флоу обработки заявки: + +1. **Step 1: Телефон** + - Ввод телефона → SMS код → верификация + - Создание контакта в CRM (автоматически через n8n) + +2. **Step 2: Полис** + - Ввод номера полиса + - Проверка в MySQL БД + - Если найден → показ застрахованных лиц → переход дальше + - Если НЕ найден → загрузка скана полиса + - OCR + Vision AI → распознавание полиса + - Real-time результат через SSE в модалке + +3. **Step 3: Тип события** + - Выбор типа (задержка, отмена, пропуск стыковки) + - Динамическое определение нужных документов + +4. **Step 4-N: Документы** + - Каждый документ = отдельный шаг + - Загрузка → S3 → OCR → AI → результат в модалке + - Real-time обработка через SSE + +5. **Step N: Оплата** + - Реквизиты для СБП + - Финальная отправка заявки + +### ✅ Интеграции: + +- **n8n** - асинхронная обработка (webhooks) +- **vTiger CRM** - создание контактов и проектов (webservice) +- **PostgreSQL** - хранение заявок и файлов +- **MySQL** - база полисов ERV +- **Redis** - Pub/Sub для SSE событий +- **RabbitMQ** - очереди задач +- **S3 Timeweb** - хранилище файлов +- **OCR Service** - распознавание текста +- **Gemini Vision AI** - извлечение данных из документов +- **SigmaSMS** - отправка SMS кодов + +--- + +## 📊 Текущий статус (1 ноября 2025) + +### Git: +```bash +Branch: main +Status: clean (nothing to commit) +Last commit: c049ed6 - "fix: Добавлены n8n webhook URLs в docker-compose.yml" +``` + +### Сервисы: +```bash +✅ Backend: http://147.45.146.17:8100 (PID 31571, uvicorn --reload) +✅ Frontend: http://147.45.146.17:5173 (Docker, Vite dev mode) +✅ PostgreSQL: 147.45.189.234:5432 (внешний) +✅ Redis: crm.clientright.ru:6379 (внешний) +✅ RabbitMQ: 185.197.75.249:5672 (внешний) +✅ MySQL: localhost:3306 (vTiger/ERV полисы) +✅ S3: s3.twcstorage.ru (Timeweb) +✅ OCR: 147.45.146.17:8001 (Python service) +✅ n8n: n8n.clientright.pro (workflows) +✅ vTiger: crm.clientright.ru (CRM) +``` + +### Следующие шаги: +- [ ] Production mode для frontend (сейчас dev) +- [ ] Docker Compose для backend (сейчас venv на хосте) +- [ ] Nginx reverse proxy вместо прямого доступа к портам +- [ ] SSL сертификаты +- [ ] Мониторинг (Grafana/Prometheus) +- [ ] Тесты (pytest для backend, Jest для frontend) +- [ ] CI/CD pipeline + +--- + +**Последнее обновление:** 1 ноября 2025, 13:39 MSK +**Автор:** Фёдор + AI Assistant (Claude Sonnet 4.5) + diff --git a/frontend/src/components/form/Step1Phone.tsx b/frontend/src/components/form/Step1Phone.tsx index 2c86190..1bd3051 100644 --- a/frontend/src/components/form/Step1Phone.tsx +++ b/frontend/src/components/form/Step1Phone.tsx @@ -94,20 +94,37 @@ export default function Step1Phone({ const crmResponse = await fetch('https://n8n.clientright.pro/webhook/511fde97-88bb-4fb4-bea5-cafdc364be27', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ phone }) + body: JSON.stringify({ + phone, + session_id: formData.session_id // ✅ Передаём session_id + }) }); const crmResult = await crmResponse.json(); + console.log('🔥 N8N CRM Response:', crmResult); + console.log('🔥 claim_id from n8n:', crmResult.claim_id); + console.log('🔥 Array check:', Array.isArray(crmResult), crmResult[0]); + if (crmResponse.ok) { addDebugEvent?.('crm', 'success', `✅ Контакт создан/найден в CRM`, crmResult); + // Если n8n вернул массив - берём первый элемент + const data = Array.isArray(crmResult) ? crmResult[0] : crmResult; + + console.log('🔥 Saving to formData:', { + phone, + contact_id: data.contact_id, + claim_id: data.claim_id, + is_new_contact: data.is_new_contact + }); + // Сохраняем данные из CRM в форму updateFormData({ phone, - contact_id: crmResult.contact_id, - claim_id: crmResult.claim_id, - is_new_contact: crmResult.is_new_contact + contact_id: data.contact_id, + claim_id: data.claim_id, + is_new_contact: data.is_new_contact }); message.success(crmResult.is_new_contact ? 'Контакт создан!' : 'Контакт найден!'); diff --git a/frontend/src/components/form/Step1Policy.tsx b/frontend/src/components/form/Step1Policy.tsx index 70245a6..8d32946 100644 --- a/frontend/src/components/form/Step1Policy.tsx +++ b/frontend/src/components/form/Step1Policy.tsx @@ -228,7 +228,12 @@ export default function Step1Policy({ formData, updateFormData, onNext, addDebug voucher: values.voucher }); message.success(`Полис найден: ${result.policy.voucher}. Застрахованных: ${result.policy.count} чел.`); - updateFormData(values); + + // ✅ Сохраняем claim_id из ответа n8n (если есть) или используем существующий + updateFormData({ + ...values, + claim_id: result.claim?.claim_id || formData.claim_id + }); onNext(); } else { // Полис НЕ найден - показываем загрузку скана @@ -239,6 +244,13 @@ export default function Step1Policy({ formData, updateFormData, onNext, addDebug voucher: values.voucher }); message.warning('Полис не найден в базе. Загрузите скан полиса'); + + // ✅ Сохраняем claim_id из ответа n8n (если есть) или используем существующий + updateFormData({ + ...values, + claim_id: result.claim?.claim_id || formData.claim_id + }); + setPolicyNotFound(true); } } else { @@ -283,7 +295,11 @@ export default function Step1Policy({ formData, updateFormData, onNext, addDebug count: fileList.length }); - // Генерируем claim_id если его нет + // ✅ Используем claim_id из formData (создан в Step1Phone или получен от n8n) + if (!formData.claim_id) { + console.warn('⚠️ claim_id отсутствует! Генерирую новый. Возможна ошибка в флоу Step1Phone → Step2Policy'); + addDebugEvent?.('claim_id', 'warning', 'claim_id отсутствует, генерирую fallback'); + } const claimId = formData.claim_id || `CLM-${new Date().toISOString().split('T')[0]}-${Math.random().toString(36).substr(2, 6).toUpperCase()}`; // Загружаем каждый файл через n8n вебхук diff --git a/frontend/src/pages/ClaimForm.tsx b/frontend/src/pages/ClaimForm.tsx index 0fd4cb3..39ee92e 100644 --- a/frontend/src/pages/ClaimForm.tsx +++ b/frontend/src/pages/ClaimForm.tsx @@ -43,12 +43,8 @@ interface FormData { } export default function ClaimForm() { - // Генерируем claim_id один раз при загрузке формы - const [claimId] = useState(() => { - const date = new Date().toISOString().split('T')[0]; - const randomId = Math.random().toString(36).substr(2, 6).toUpperCase(); - return `CLM-${date}-${randomId}`; - }); + // ✅ claim_id будет создан n8n в Step1Phone после SMS верификации + // Не генерируем его локально! // Генерируем session_id и сохраняем в sessionStorage const [sessionId] = useState(() => { @@ -63,13 +59,16 @@ export default function ClaimForm() { const [currentStep, setCurrentStep] = useState(0); const [formData, setFormData] = useState({ voucher: '', - claim_id: claimId, + claim_id: undefined, // ✅ Будет заполнен n8n в Step1Phone session_id: sessionId, paymentMethod: 'sbp', }); const [isPhoneVerified, setIsPhoneVerified] = useState(false); const [debugEvents, setDebugEvents] = useState([]); + // 🔥 VERSION CHECK: Если видишь это в консоли - фронт обновился! + console.log('🔥 ClaimForm v2.0 - claim_id НЕ генерируется на фронте!'); + // Динамически определяем список шагов на основе выбранного eventType const documentConfigs = formData.eventType ? getDocumentsForEventType(formData.eventType) : []; const totalDocumentSteps = documentConfigs.length; @@ -82,20 +81,13 @@ export default function ClaimForm() { message, data: { ...data, - claim_id: claimId // Добавляем claim_id во все события + claim_id: formData.claim_id // ✅ Используем claim_id из formData (от n8n) } }; setDebugEvents(prev => [event, ...prev]); }; - // Логируем генерацию claim_id и session_id при первой загрузке - useState(() => { - addDebugEvent('system', 'info', `🆔 Сгенерирован Claim ID: ${claimId}`, { - claim_id: claimId, - session_id: sessionId, - timestamp: new Date().toISOString() - }); - }); + // ✅ claim_id будет залогирован в Step1Phone после получения от n8n const updateFormData = useCallback((data: Partial) => { setFormData((prev) => ({ ...prev, ...data })); @@ -127,7 +119,7 @@ export default function ClaimForm() { 'Content-Type': 'application/json', }, body: JSON.stringify({ - claim_id: claimId, + claim_id: formData.claim_id, // ✅ Используем claim_id от n8n voucher: formData.voucher, email: formData.email, phone: formData.phone, @@ -146,10 +138,10 @@ export default function ClaimForm() { message.success(`Заявка ${result.claim_number} успешно создана!`); addDebugEvent('form', 'success', `✅ Заявка ${result.claim_number} создана`); - // Сброс формы + // Сброс формы (создаём новую заявку, claim_id будет сгенерирован при следующем SMS) setFormData({ voucher: '', - claim_id: claimId, + claim_id: undefined, // ✅ Очищаем для новой заявки session_id: sessionId, paymentMethod: 'sbp', }); @@ -164,7 +156,7 @@ export default function ClaimForm() { addDebugEvent('form', 'error', '❌ Ошибка соединения'); console.error(error); } - }, [formData, claimId, sessionId, addDebugEvent]); + }, [formData, sessionId, addDebugEvent]); // Динамически генерируем шаги на основе выбранного eventType const steps = useMemo(() => { @@ -176,7 +168,7 @@ export default function ClaimForm() { description: 'Подтверждение по SMS', content: ( { setFormData({ voucher: '', - claim_id: claimId, + claim_id: undefined, // ✅ Очищаем для новой заявки session_id: sessionId, paymentMethod: 'sbp', });