212 lines
8.8 KiB
Markdown
212 lines
8.8 KiB
Markdown
|
|
# Анализ workflow 8ZVMTsuH7Cmw7snw и предложения
|
|||
|
|
|
|||
|
|
## Текущая структура
|
|||
|
|
|
|||
|
|
### Основные ноды PostgreSQL:
|
|||
|
|
|
|||
|
|
1. **`claimsave`** (строка 190-210)
|
|||
|
|
- Использует обновленный SQL с `$2::text` (строка claim_id)
|
|||
|
|
- **ПРОБЛЕМА**: SQL запрос не использует `claim_final` CTE, который я добавил в исправленной версии
|
|||
|
|
- Это основная нода для сохранения данных визарда
|
|||
|
|
|
|||
|
|
2. **`claimsave_final`** (строка 428-450)
|
|||
|
|
- Использует другой SQL запрос с `$2::uuid`
|
|||
|
|
- Используется после конвертации файлов в PDF
|
|||
|
|
- **ПРОБЛЕМА**: Ожидает UUID, но может получать строку
|
|||
|
|
|
|||
|
|
3. **`claimsave1`** (строка 634-655)
|
|||
|
|
- Использует старый SQL запрос с `$2::uuid`
|
|||
|
|
- **ПРОБЛЕМА**: Не работает со строковым claim_id
|
|||
|
|
|
|||
|
|
## Проблемы
|
|||
|
|
|
|||
|
|
### 1. SQL запрос в `claimsave` неполный
|
|||
|
|
|
|||
|
|
Текущий SQL в ноде `claimsave`:
|
|||
|
|
- ✅ Использует `$2::text` (правильно)
|
|||
|
|
- ✅ Имеет `claim_lookup` и `claim_created` CTE
|
|||
|
|
- ❌ **НЕ использует `claim_final` CTE** (который я добавил в исправленной версии)
|
|||
|
|
- ❌ Использует `claim_lookup.claim_uuid` напрямую, что может не работать, если запись была создана в `claim_created`
|
|||
|
|
|
|||
|
|
### 2. Несоответствие типов данных
|
|||
|
|
|
|||
|
|
- `claimsave` ожидает строку (`$2::text`)
|
|||
|
|
- `claimsave_final` ожидает UUID (`$2::uuid`)
|
|||
|
|
- `claimsave1` ожидает UUID (`$2::uuid`)
|
|||
|
|
|
|||
|
|
Но везде передается `claim_id` как строка `"CLM-2025-11-18-GEQ3KL"`.
|
|||
|
|
|
|||
|
|
### 3. Проблема с `existing` CTE
|
|||
|
|
|
|||
|
|
В текущем SQL запросе `existing` может не найти запись, если она была создана в `claim_created`, потому что:
|
|||
|
|
- `claim_lookup` выполняется ДО `claim_created`
|
|||
|
|
- `existing` использует `claim_lookup.claim_uuid`, но запись может быть создана в `claim_created`
|
|||
|
|
|
|||
|
|
## Решения
|
|||
|
|
|
|||
|
|
### Решение 1: Обновить SQL в ноде `claimsave`
|
|||
|
|
|
|||
|
|
Заменить SQL запрос на исправленную версию из `FIXED_SQL_QUERY.md`:
|
|||
|
|
|
|||
|
|
**Ключевые изменения:**
|
|||
|
|
1. Добавить `claim_final` CTE для получения правильного UUID
|
|||
|
|
2. Использовать `claim_final.claim_uuid` вместо `claim_lookup.claim_uuid`
|
|||
|
|
3. Исправить `old` CTE, чтобы он всегда возвращал строку
|
|||
|
|
|
|||
|
|
### Решение 2: Унифицировать типы данных
|
|||
|
|
|
|||
|
|
**Вариант A**: Все ноды используют строку `claim_id`
|
|||
|
|
- Изменить `claimsave_final` и `claimsave1` на `$2::text`
|
|||
|
|
- Добавить логику поиска UUID по строке `claim_id`
|
|||
|
|
|
|||
|
|
**Вариант B**: Все ноды используют UUID
|
|||
|
|
- Перед SQL запросами добавить Code Node, который:
|
|||
|
|
- Находит запись в `clpr_claims` по `payload->>'claim_id'`
|
|||
|
|
- Извлекает её `id` (UUID)
|
|||
|
|
- Передает UUID в SQL запрос
|
|||
|
|
|
|||
|
|
**Рекомендую Вариант A** (использовать строку везде), т.к.:
|
|||
|
|
- Проще реализовать
|
|||
|
|
- Меньше изменений в workflow
|
|||
|
|
- `claim_id` в формате `CLM-YYYY-MM-DD-XXXXXX` - это основной идентификатор
|
|||
|
|
|
|||
|
|
### Решение 3: Упростить логику
|
|||
|
|
|
|||
|
|
Можно упростить SQL запрос, убрав сложную логику слияния:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
WITH partial AS (
|
|||
|
|
SELECT $1::jsonb AS p, $2::text AS claim_id_str
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Находим или создаем запись
|
|||
|
|
claim_final AS (
|
|||
|
|
SELECT
|
|||
|
|
COALESCE(
|
|||
|
|
(SELECT id FROM clpr_claims WHERE payload->>'claim_id' = partial.claim_id_str LIMIT 1),
|
|||
|
|
gen_random_uuid()
|
|||
|
|
) AS claim_uuid
|
|||
|
|
FROM partial
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Создаем запись, если её нет
|
|||
|
|
claim_created AS (
|
|||
|
|
INSERT INTO clpr_claims (
|
|||
|
|
id, session_token, channel, type_code, status_code, payload, created_at, updated_at, expires_at
|
|||
|
|
)
|
|||
|
|
SELECT
|
|||
|
|
claim_final.claim_uuid,
|
|||
|
|
COALESCE(partial.p->>'session_id', 'sess-' || gen_random_uuid()::text),
|
|||
|
|
'web_form',
|
|||
|
|
COALESCE(partial.p->>'type_code', 'consumer'),
|
|||
|
|
'draft',
|
|||
|
|
jsonb_build_object(
|
|||
|
|
'claim_id', partial.claim_id_str,
|
|||
|
|
'answers', COALESCE(partial.p->'answers', '{}'::jsonb),
|
|||
|
|
'documents_meta', COALESCE(partial.p->'documents_meta', '[]'::jsonb),
|
|||
|
|
'wizard_plan', partial.p->'wizard_plan',
|
|||
|
|
'wizard_answers', partial.p->'wizard_answers',
|
|||
|
|
'form_data', partial.p
|
|||
|
|
),
|
|||
|
|
now(), now(), now() + interval '14 days'
|
|||
|
|
FROM partial, claim_final
|
|||
|
|
WHERE NOT EXISTS (SELECT 1 FROM clpr_claims WHERE id = claim_final.claim_uuid)
|
|||
|
|
ON CONFLICT (id) DO NOTHING
|
|||
|
|
RETURNING id
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Сохраняем документы
|
|||
|
|
inserted_docs AS (
|
|||
|
|
INSERT INTO clpr_claim_documents
|
|||
|
|
(claim_id, field_name, file_id, uploaded_at, file_name, original_file_name)
|
|||
|
|
SELECT
|
|||
|
|
claim_final.claim_uuid::text,
|
|||
|
|
doc.field_name, doc.file_id,
|
|||
|
|
(doc.uploaded_at)::timestamptz,
|
|||
|
|
doc.file_name, doc.original_file_name
|
|||
|
|
FROM partial, claim_final
|
|||
|
|
CROSS JOIN LATERAL jsonb_to_recordset(
|
|||
|
|
COALESCE(partial.p->'documents_meta','[]'::jsonb)
|
|||
|
|
) AS doc(field_name text, file_id text, file_name text, original_file_name text, uploaded_at text)
|
|||
|
|
ON CONFLICT (claim_id, field_name) DO UPDATE
|
|||
|
|
SET file_id = EXCLUDED.file_id,
|
|||
|
|
uploaded_at = EXCLUDED.uploaded_at,
|
|||
|
|
file_name = EXCLUDED.file_name,
|
|||
|
|
original_file_name = EXCLUDED.original_file_name
|
|||
|
|
RETURNING id, claim_id, field_name, file_id
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Обновляем запись (простое слияние)
|
|||
|
|
upd AS (
|
|||
|
|
UPDATE clpr_claims c
|
|||
|
|
SET
|
|||
|
|
payload = COALESCE(c.payload, '{}'::jsonb) || partial.p,
|
|||
|
|
status_code = CASE
|
|||
|
|
WHEN (partial.p->'answers'->>'docs_exist' = 'true') THEN 'in_work'
|
|||
|
|
ELSE COALESCE(c.status_code, 'draft')
|
|||
|
|
END,
|
|||
|
|
updated_at = now(),
|
|||
|
|
expires_at = now() + interval '14 days'
|
|||
|
|
FROM partial, claim_final
|
|||
|
|
WHERE c.id = claim_final.claim_uuid
|
|||
|
|
RETURNING c.id, c.status_code, c.payload
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
SELECT
|
|||
|
|
(SELECT jsonb_build_object(
|
|||
|
|
'claim_id', u.id::text,
|
|||
|
|
'claim_id_str', (u.payload->>'claim_id'),
|
|||
|
|
'status_code', u.status_code,
|
|||
|
|
'payload', u.payload
|
|||
|
|
) FROM upd u LIMIT 1) AS claim,
|
|||
|
|
(SELECT jsonb_agg(jsonb_build_object(
|
|||
|
|
'id', id,
|
|||
|
|
'field_name', field_name,
|
|||
|
|
'file_id', file_id
|
|||
|
|
)) FROM inserted_docs) AS documents;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Рекомендации
|
|||
|
|
|
|||
|
|
### Немедленные действия:
|
|||
|
|
|
|||
|
|
1. **Обновить SQL в ноде `claimsave`**
|
|||
|
|
- Заменить на исправленную версию из `FIXED_SQL_QUERY.md`
|
|||
|
|
- Или использовать упрощенную версию выше
|
|||
|
|
|
|||
|
|
2. **Проверить параметры**
|
|||
|
|
- Убедиться, что `queryReplacement` правильный: `={{ $json.payload_partial_json }}, {{ $json.claim_id }}`
|
|||
|
|
- `payload_partial_json` должен быть JSON объектом
|
|||
|
|
- `claim_id` должен быть строкой
|
|||
|
|
|
|||
|
|
3. **Протестировать**
|
|||
|
|
- Запустить workflow с тестовыми данными
|
|||
|
|
- Проверить, что `claim` не возвращает `null`
|
|||
|
|
- Проверить, что документы сохраняются правильно
|
|||
|
|
|
|||
|
|
### Долгосрочные улучшения:
|
|||
|
|
|
|||
|
|
1. **Унифицировать все SQL запросы**
|
|||
|
|
- Привести `claimsave_final` и `claimsave1` к единому формату
|
|||
|
|
- Использовать строковый `claim_id` везде
|
|||
|
|
|
|||
|
|
2. **Добавить обработку ошибок**
|
|||
|
|
- Проверять результат SQL запроса
|
|||
|
|
- Логировать ошибки
|
|||
|
|
- Возвращать понятные сообщения об ошибках
|
|||
|
|
|
|||
|
|
3. **Оптимизировать workflow**
|
|||
|
|
- Упростить логику слияния payload
|
|||
|
|
- Использовать транзакции для атомарности операций
|
|||
|
|
|
|||
|
|
## Готовый SQL для копирования
|
|||
|
|
|
|||
|
|
Полный исправленный SQL запрос находится в файле `FIXED_SQL_QUERY.md`.
|
|||
|
|
|
|||
|
|
Основные изменения:
|
|||
|
|
- ✅ Использует `claim_final` CTE для правильного получения UUID
|
|||
|
|
- ✅ `old` CTE всегда возвращает строку (даже если запись не найдена)
|
|||
|
|
- ✅ Все подзапросы используют `LIMIT 1` для гарантии одной строки
|
|||
|
|
- ✅ Правильное слияние `answers` и `documents_meta`
|
|||
|
|
|