380 lines
16 KiB
MySQL
380 lines
16 KiB
MySQL
|
|
-- ============================================================================
|
|||
|
|
-- SQL для сохранения claim при пропуске документа (document skip) - НОВЫЙ ФЛОУ
|
|||
|
|
-- ============================================================================
|
|||
|
|
-- Проблема: При пропуске документа нужно обновить documents_skipped и current_doc_index
|
|||
|
|
-- Решение: Добавляем документ в documents_skipped, обновляем current_doc_index и status_code
|
|||
|
|
-- ============================================================================
|
|||
|
|
|
|||
|
|
WITH partial AS (
|
|||
|
|
SELECT
|
|||
|
|
$1::jsonb AS p,
|
|||
|
|
$2::text AS claim_id_str
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
existing_claim AS (
|
|||
|
|
SELECT
|
|||
|
|
id,
|
|||
|
|
session_token,
|
|||
|
|
unified_id,
|
|||
|
|
contact_id,
|
|||
|
|
phone,
|
|||
|
|
payload,
|
|||
|
|
status_code,
|
|||
|
|
created_at
|
|||
|
|
FROM clpr_claims
|
|||
|
|
WHERE id = (SELECT claim_id_str::uuid FROM partial)
|
|||
|
|
OR payload->>'claim_id' = (SELECT claim_id_str FROM partial)
|
|||
|
|
ORDER BY
|
|||
|
|
CASE WHEN id = (SELECT claim_id_str::uuid FROM partial) THEN 1 ELSE 2 END,
|
|||
|
|
updated_at DESC
|
|||
|
|
LIMIT 1
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Парсим информацию о пропущенном документе
|
|||
|
|
skipped_document_info AS (
|
|||
|
|
SELECT
|
|||
|
|
COALESCE(
|
|||
|
|
partial.p->>'document_type',
|
|||
|
|
partial.p->'body'->>'document_type',
|
|||
|
|
partial.p->'edit_fields_raw'->'body'->>'document_type',
|
|||
|
|
partial.p->'edit_fields_parsed'->'body'->>'document_type'
|
|||
|
|
) AS document_type,
|
|||
|
|
COALESCE(
|
|||
|
|
partial.p->>'document_name',
|
|||
|
|
partial.p->'body'->>'document_name',
|
|||
|
|
partial.p->'edit_fields_raw'->'body'->>'document_name',
|
|||
|
|
partial.p->'edit_fields_parsed'->'body'->>'document_name'
|
|||
|
|
) AS document_name,
|
|||
|
|
COALESCE(
|
|||
|
|
(partial.p->>'group_index')::int,
|
|||
|
|
(partial.p->'body'->>'group_index')::int,
|
|||
|
|
(partial.p->'edit_fields_raw'->'body'->>'group_index')::int,
|
|||
|
|
(partial.p->'edit_fields_parsed'->'body'->>'group_index')::int,
|
|||
|
|
NULL
|
|||
|
|
) AS group_index
|
|||
|
|
FROM partial
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Парсим documents_required (или берём из БД)
|
|||
|
|
documents_required_parsed AS (
|
|||
|
|
SELECT
|
|||
|
|
CASE
|
|||
|
|
WHEN partial.p->'documents_required' IS NOT NULL
|
|||
|
|
AND jsonb_typeof(partial.p->'documents_required') = 'array'
|
|||
|
|
THEN partial.p->'documents_required'
|
|||
|
|
WHEN EXISTS (SELECT 1 FROM existing_claim WHERE payload->'documents_required' IS NOT NULL)
|
|||
|
|
THEN (SELECT payload->'documents_required' FROM existing_claim)
|
|||
|
|
ELSE '[]'::jsonb
|
|||
|
|
END AS documents_required
|
|||
|
|
FROM partial
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Парсим documents_uploaded (или берём из БД)
|
|||
|
|
documents_uploaded_parsed AS (
|
|||
|
|
SELECT
|
|||
|
|
CASE
|
|||
|
|
WHEN partial.p->'documents_uploaded' IS NOT NULL
|
|||
|
|
AND jsonb_typeof(partial.p->'documents_uploaded') = 'array'
|
|||
|
|
THEN partial.p->'documents_uploaded'
|
|||
|
|
WHEN EXISTS (SELECT 1 FROM existing_claim WHERE payload->'documents_uploaded' IS NOT NULL)
|
|||
|
|
THEN (SELECT payload->'documents_uploaded' FROM existing_claim)
|
|||
|
|
ELSE '[]'::jsonb
|
|||
|
|
END AS documents_uploaded
|
|||
|
|
FROM partial
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Парсим documents_skipped (или берём из БД) и ДОБАВЛЯЕМ/ОБНОВЛЯЕМ новый пропущенный документ
|
|||
|
|
documents_skipped_parsed AS (
|
|||
|
|
SELECT
|
|||
|
|
CASE
|
|||
|
|
-- Если документ уже есть в списке пропущенных - ОБНОВЛЯЕМ его (добавляем group_index, если его нет)
|
|||
|
|
WHEN EXISTS (
|
|||
|
|
SELECT 1
|
|||
|
|
FROM existing_claim
|
|||
|
|
WHERE payload->'documents_skipped' @> jsonb_build_array(
|
|||
|
|
jsonb_build_object(
|
|||
|
|
'id', (SELECT document_type FROM skipped_document_info)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
THEN (
|
|||
|
|
-- Удаляем старую запись и добавляем новую с group_index
|
|||
|
|
SELECT jsonb_agg(
|
|||
|
|
CASE
|
|||
|
|
WHEN doc->>'id' = (SELECT document_type FROM skipped_document_info)
|
|||
|
|
THEN jsonb_build_object(
|
|||
|
|
'id', (SELECT document_type FROM skipped_document_info),
|
|||
|
|
'name', COALESCE((SELECT document_name FROM skipped_document_info), (SELECT document_type FROM skipped_document_info)),
|
|||
|
|
'group_index', (SELECT group_index FROM skipped_document_info),
|
|||
|
|
'skipped_at', COALESCE(doc->>'skipped_at', now()::text)
|
|||
|
|
)
|
|||
|
|
ELSE doc
|
|||
|
|
END
|
|||
|
|
)
|
|||
|
|
FROM existing_claim,
|
|||
|
|
jsonb_array_elements(payload->'documents_skipped') AS doc
|
|||
|
|
)
|
|||
|
|
-- Добавляем новый пропущенный документ
|
|||
|
|
WHEN EXISTS (SELECT 1 FROM existing_claim WHERE payload->'documents_skipped' IS NOT NULL)
|
|||
|
|
THEN (
|
|||
|
|
SELECT payload->'documents_skipped' || jsonb_build_array(
|
|||
|
|
jsonb_build_object(
|
|||
|
|
'id', (SELECT document_type FROM skipped_document_info),
|
|||
|
|
'name', COALESCE((SELECT document_name FROM skipped_document_info), (SELECT document_type FROM skipped_document_info)),
|
|||
|
|
'group_index', (SELECT group_index FROM skipped_document_info),
|
|||
|
|
'skipped_at', now()::text
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
FROM existing_claim
|
|||
|
|
)
|
|||
|
|
-- Создаём новый массив с пропущенным документом
|
|||
|
|
ELSE jsonb_build_array(
|
|||
|
|
jsonb_build_object(
|
|||
|
|
'id', (SELECT document_type FROM skipped_document_info),
|
|||
|
|
'name', COALESCE((SELECT document_name FROM skipped_document_info), (SELECT document_type FROM skipped_document_info)),
|
|||
|
|
'group_index', (SELECT group_index FROM skipped_document_info),
|
|||
|
|
'skipped_at', now()::text
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
END AS documents_skipped
|
|||
|
|
FROM partial
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Парсим current_doc_index и ОБНОВЛЯЕМ его (увеличиваем на 1 или находим следующий непропущенный)
|
|||
|
|
current_doc_index_parsed AS (
|
|||
|
|
SELECT
|
|||
|
|
CASE
|
|||
|
|
-- Если передан group_index - используем его + 1
|
|||
|
|
WHEN (SELECT group_index FROM skipped_document_info) IS NOT NULL
|
|||
|
|
THEN (SELECT group_index FROM skipped_document_info) + 1
|
|||
|
|
-- Иначе берём из payload и увеличиваем на 1
|
|||
|
|
WHEN partial.p->'current_doc_index' IS NOT NULL
|
|||
|
|
THEN (partial.p->'current_doc_index')::int + 1
|
|||
|
|
WHEN EXISTS (SELECT 1 FROM existing_claim WHERE payload->'current_doc_index' IS NOT NULL)
|
|||
|
|
THEN (SELECT (payload->'current_doc_index')::int FROM existing_claim) + 1
|
|||
|
|
ELSE 1
|
|||
|
|
END AS current_doc_index
|
|||
|
|
FROM partial
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- Определяем правильный статус на основе прогресса документов
|
|||
|
|
status_code_resolved AS (
|
|||
|
|
SELECT
|
|||
|
|
CASE
|
|||
|
|
-- Если есть documents_required - новый флоу
|
|||
|
|
WHEN (SELECT jsonb_array_length(documents_required) FROM documents_required_parsed) > 0
|
|||
|
|
THEN CASE
|
|||
|
|
-- Все документы загружены или пропущены
|
|||
|
|
WHEN (SELECT jsonb_array_length(documents_uploaded) FROM documents_uploaded_parsed) +
|
|||
|
|
(SELECT jsonb_array_length(documents_skipped) FROM documents_skipped_parsed) >=
|
|||
|
|
(SELECT jsonb_array_length(documents_required) FROM documents_required_parsed)
|
|||
|
|
THEN 'draft_docs_complete'
|
|||
|
|
-- Документы обрабатываются (есть загруженные или пропущенные)
|
|||
|
|
WHEN (SELECT jsonb_array_length(documents_uploaded) FROM documents_uploaded_parsed) > 0
|
|||
|
|
OR (SELECT jsonb_array_length(documents_skipped) FROM documents_skipped_parsed) > 0
|
|||
|
|
THEN 'draft_docs_progress'
|
|||
|
|
-- Только описание
|
|||
|
|
ELSE 'draft_new'
|
|||
|
|
END
|
|||
|
|
-- Сохраняем существующий статус, если он новый
|
|||
|
|
WHEN EXISTS (SELECT 1 FROM existing_claim
|
|||
|
|
WHERE status_code IN ('draft_new', 'draft_docs_progress', 'draft_docs_complete', 'draft_claim_ready'))
|
|||
|
|
THEN (SELECT status_code FROM existing_claim)
|
|||
|
|
-- По умолчанию
|
|||
|
|
ELSE 'draft'
|
|||
|
|
END AS status_code
|
|||
|
|
FROM partial
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
-- UPSERT claim
|
|||
|
|
claim_upsert AS (
|
|||
|
|
INSERT INTO clpr_claims (
|
|||
|
|
id,
|
|||
|
|
session_token,
|
|||
|
|
unified_id,
|
|||
|
|
contact_id,
|
|||
|
|
phone,
|
|||
|
|
channel,
|
|||
|
|
type_code,
|
|||
|
|
status_code,
|
|||
|
|
payload,
|
|||
|
|
created_at,
|
|||
|
|
updated_at,
|
|||
|
|
expires_at
|
|||
|
|
)
|
|||
|
|
SELECT
|
|||
|
|
COALESCE((SELECT id FROM existing_claim), partial.claim_id_str::uuid),
|
|||
|
|
COALESCE(
|
|||
|
|
partial.p->>'session_id',
|
|||
|
|
partial.p->'body'->>'session_id',
|
|||
|
|
partial.p->'edit_fields_parsed'->'body'->>'session_id',
|
|||
|
|
partial.p->'edit_fields_raw'->'body'->>'session_id',
|
|||
|
|
(SELECT payload->>'session_id' FROM existing_claim),
|
|||
|
|
'sess-unknown'
|
|||
|
|
),
|
|||
|
|
COALESCE(
|
|||
|
|
partial.p->>'unified_id',
|
|||
|
|
partial.p->'body'->>'unified_id',
|
|||
|
|
partial.p->'edit_fields_parsed'->'body'->>'unified_id',
|
|||
|
|
partial.p->'edit_fields_raw'->'body'->>'unified_id',
|
|||
|
|
(SELECT unified_id FROM existing_claim)
|
|||
|
|
),
|
|||
|
|
COALESCE(
|
|||
|
|
partial.p->>'contact_id',
|
|||
|
|
partial.p->'body'->>'contact_id',
|
|||
|
|
partial.p->'edit_fields_parsed'->'body'->>'contact_id',
|
|||
|
|
partial.p->'edit_fields_raw'->'body'->>'contact_id',
|
|||
|
|
(SELECT contact_id FROM existing_claim)
|
|||
|
|
),
|
|||
|
|
COALESCE(
|
|||
|
|
partial.p->>'phone',
|
|||
|
|
partial.p->'body'->>'phone',
|
|||
|
|
partial.p->'edit_fields_parsed'->'body'->>'phone',
|
|||
|
|
partial.p->'edit_fields_raw'->'body'->>'phone',
|
|||
|
|
(SELECT phone FROM existing_claim)
|
|||
|
|
),
|
|||
|
|
'web_form',
|
|||
|
|
COALESCE(partial.p->>'type_code', 'consumer'),
|
|||
|
|
(SELECT status_code FROM status_code_resolved),
|
|||
|
|
jsonb_build_object(
|
|||
|
|
'claim_id', partial.claim_id_str,
|
|||
|
|
-- Сохраняем существующие поля из payload
|
|||
|
|
'problem_description', COALESCE(
|
|||
|
|
partial.p->>'problem_description',
|
|||
|
|
(SELECT payload->>'problem_description' FROM existing_claim)
|
|||
|
|
),
|
|||
|
|
'answers', COALESCE(
|
|||
|
|
partial.p->'answers',
|
|||
|
|
(SELECT payload->'answers' FROM existing_claim),
|
|||
|
|
'{}'::jsonb
|
|||
|
|
),
|
|||
|
|
'wizard_plan', COALESCE(
|
|||
|
|
partial.p->'wizard_plan',
|
|||
|
|
(SELECT payload->'wizard_plan' FROM existing_claim)
|
|||
|
|
),
|
|||
|
|
-- ✅ Сохраняем documents_meta (если есть)
|
|||
|
|
'documents_meta', COALESCE(
|
|||
|
|
partial.p->'documents_meta',
|
|||
|
|
(SELECT payload->'documents_meta' FROM existing_claim),
|
|||
|
|
'[]'::jsonb
|
|||
|
|
),
|
|||
|
|
-- ✅ НОВЫЙ ФЛОУ: Обновляем documents_required, documents_uploaded, documents_skipped, current_doc_index
|
|||
|
|
'documents_required', (SELECT documents_required FROM documents_required_parsed),
|
|||
|
|
'documents_uploaded', (SELECT documents_uploaded FROM documents_uploaded_parsed),
|
|||
|
|
'documents_skipped', (SELECT documents_skipped FROM documents_skipped_parsed),
|
|||
|
|
'current_doc_index', (SELECT current_doc_index FROM current_doc_index_parsed),
|
|||
|
|
'phone', COALESCE(
|
|||
|
|
partial.p->>'phone',
|
|||
|
|
(SELECT payload->>'phone' FROM existing_claim)
|
|||
|
|
),
|
|||
|
|
'email', COALESCE(
|
|||
|
|
partial.p->>'email',
|
|||
|
|
(SELECT payload->>'email' FROM existing_claim)
|
|||
|
|
)
|
|||
|
|
),
|
|||
|
|
COALESCE((SELECT created_at FROM existing_claim), now()),
|
|||
|
|
now(),
|
|||
|
|
now() + interval '14 days'
|
|||
|
|
FROM partial
|
|||
|
|
ON CONFLICT (id) DO UPDATE SET
|
|||
|
|
session_token = COALESCE(EXCLUDED.session_token, clpr_claims.session_token),
|
|||
|
|
unified_id = COALESCE(EXCLUDED.unified_id, clpr_claims.unified_id),
|
|||
|
|
contact_id = COALESCE(EXCLUDED.contact_id, clpr_claims.contact_id),
|
|||
|
|
phone = COALESCE(EXCLUDED.phone, clpr_claims.phone),
|
|||
|
|
-- ✅ Обновляем status_code на основе прогресса документов
|
|||
|
|
status_code = (SELECT status_code FROM status_code_resolved),
|
|||
|
|
-- ✅ Объединяем payload правильно: аккуратно обновляем критичные поля
|
|||
|
|
payload = jsonb_set(
|
|||
|
|
jsonb_set(
|
|||
|
|
jsonb_set(
|
|||
|
|
jsonb_set(
|
|||
|
|
-- Сначала берём существующий payload и объединяем с новым (без критичных полей)
|
|||
|
|
COALESCE(clpr_claims.payload, '{}'::jsonb) ||
|
|||
|
|
(EXCLUDED.payload - 'documents_required' - 'documents_uploaded' - 'documents_skipped' - 'current_doc_index'),
|
|||
|
|
'{documents_required}',
|
|||
|
|
COALESCE(
|
|||
|
|
EXCLUDED.payload->'documents_required',
|
|||
|
|
clpr_claims.payload->'documents_required',
|
|||
|
|
'[]'::jsonb
|
|||
|
|
),
|
|||
|
|
true
|
|||
|
|
),
|
|||
|
|
'{documents_uploaded}',
|
|||
|
|
COALESCE(
|
|||
|
|
EXCLUDED.payload->'documents_uploaded',
|
|||
|
|
clpr_claims.payload->'documents_uploaded',
|
|||
|
|
'[]'::jsonb
|
|||
|
|
),
|
|||
|
|
true
|
|||
|
|
),
|
|||
|
|
'{documents_skipped}',
|
|||
|
|
-- ✅ ОБЪЕДИНЯЕМ documents_skipped (добавляем новый пропущенный документ или ОБНОВЛЯЕМ существующий)
|
|||
|
|
CASE
|
|||
|
|
-- Если новый документ уже есть в существующем списке - ОБНОВЛЯЕМ его (добавляем group_index)
|
|||
|
|
WHEN clpr_claims.payload->'documents_skipped' @> jsonb_build_array(
|
|||
|
|
jsonb_build_object(
|
|||
|
|
'id', (SELECT document_type FROM skipped_document_info)
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
THEN (
|
|||
|
|
-- Обновляем существующую запись, добавляя group_index
|
|||
|
|
SELECT jsonb_agg(
|
|||
|
|
CASE
|
|||
|
|
WHEN doc->>'id' = (SELECT document_type FROM skipped_document_info)
|
|||
|
|
THEN jsonb_build_object(
|
|||
|
|
'id', (SELECT document_type FROM skipped_document_info),
|
|||
|
|
'name', COALESCE((SELECT document_name FROM skipped_document_info), (SELECT document_type FROM skipped_document_info)),
|
|||
|
|
'group_index', (SELECT group_index FROM skipped_document_info),
|
|||
|
|
'skipped_at', COALESCE(doc->>'skipped_at', now()::text)
|
|||
|
|
)
|
|||
|
|
ELSE doc
|
|||
|
|
END
|
|||
|
|
)
|
|||
|
|
FROM jsonb_array_elements(clpr_claims.payload->'documents_skipped') AS doc
|
|||
|
|
)
|
|||
|
|
-- Добавляем новый пропущенный документ
|
|||
|
|
ELSE COALESCE(clpr_claims.payload->'documents_skipped', '[]'::jsonb) || jsonb_build_array(
|
|||
|
|
jsonb_build_object(
|
|||
|
|
'id', (SELECT document_type FROM skipped_document_info),
|
|||
|
|
'name', COALESCE((SELECT document_name FROM skipped_document_info), (SELECT document_type FROM skipped_document_info)),
|
|||
|
|
'group_index', (SELECT group_index FROM skipped_document_info),
|
|||
|
|
'skipped_at', now()::text
|
|||
|
|
)
|
|||
|
|
)
|
|||
|
|
END,
|
|||
|
|
true
|
|||
|
|
),
|
|||
|
|
'{current_doc_index}',
|
|||
|
|
COALESCE(
|
|||
|
|
EXCLUDED.payload->'current_doc_index',
|
|||
|
|
-- Если не передан, увеличиваем существующий на 1
|
|||
|
|
CASE
|
|||
|
|
WHEN clpr_claims.payload->'current_doc_index' IS NOT NULL
|
|||
|
|
THEN to_jsonb((clpr_claims.payload->'current_doc_index')::int + 1)
|
|||
|
|
ELSE to_jsonb(1)
|
|||
|
|
END
|
|||
|
|
),
|
|||
|
|
true
|
|||
|
|
),
|
|||
|
|
updated_at = now(),
|
|||
|
|
expires_at = now() + interval '14 days'
|
|||
|
|
RETURNING id, status_code, payload, unified_id, contact_id, phone, session_token
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
-- Возвращаем результат
|
|||
|
|
SELECT
|
|||
|
|
jsonb_build_object(
|
|||
|
|
'claim_id', cu.id::text,
|
|||
|
|
'claim_id_str', (cu.payload->>'claim_id'),
|
|||
|
|
'status_code', cu.status_code,
|
|||
|
|
'unified_id', cu.unified_id,
|
|||
|
|
'contact_id', cu.contact_id,
|
|||
|
|
'phone', cu.phone,
|
|||
|
|
'session_token', cu.session_token,
|
|||
|
|
'payload', cu.payload,
|
|||
|
|
'documents_skipped', cu.payload->'documents_skipped',
|
|||
|
|
'current_doc_index', cu.payload->'current_doc_index'
|
|||
|
|
) AS claim
|
|||
|
|
FROM claim_upsert cu;
|
|||
|
|
|