From a8de3f0fc9d7f0b404d5d81137c703f4b0e3e34a Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Mon, 24 Nov 2025 17:02:29 +0300 Subject: [PATCH] fix: Add claim_lookup CTE to search by both ID and payload claim_id Problem: - Original query only searched by ID: WHERE c.id = partial.cid - If record exists with different ID but same claim_id in payload, it wasn't found and documents weren't updated Solution: - Added claim_lookup CTE that searches both by ID and payload->>'claim_id': WHERE id::text = claim_id_str OR payload->>'claim_id' = claim_id_str - Uses found ID from claim_lookup instead of partial.cid - This ensures correct record is always used Changes: - partial now accepts $2::text (instead of $2::uuid) - Added claim_lookup CTE for record lookup - upd_claim uses claim_lookup.id instead of partial.cid - docs uses claim_lookup.id instead of partial.cid Files: - docs/SQL_CLAIMSAVE_FINAL_FIXED.sql: Fixed version with claim_lookup --- docs/SQL_CLAIMSAVE_FINAL_FIXED.sql | 133 +++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 docs/SQL_CLAIMSAVE_FINAL_FIXED.sql diff --git a/docs/SQL_CLAIMSAVE_FINAL_FIXED.sql b/docs/SQL_CLAIMSAVE_FINAL_FIXED.sql new file mode 100644 index 0000000..d9888fb --- /dev/null +++ b/docs/SQL_CLAIMSAVE_FINAL_FIXED.sql @@ -0,0 +1,133 @@ +-- Исправленный SQL для сохранения документов (claimsave_final) +-- ✅ ИСПРАВЛЕНО: Ищем запись и по ID, и по payload->>'claim_id', чтобы избежать дубликатов +-- $1 = payload_partial_json (jsonb) +-- $2 = claim_id (text или uuid в виде строки) + +WITH partial AS ( + SELECT $1::jsonb AS p, $2::text AS claim_id_str +), + +-- ✅ ИСПРАВЛЕНО: Ищем запись и по ID, и по payload->>'claim_id' +claim_lookup AS ( + SELECT + id, + payload + FROM clpr_claims + WHERE id::text = partial.claim_id_str + OR payload->>'claim_id' = partial.claim_id_str + ORDER BY + CASE WHEN id::text = partial.claim_id_str THEN 1 ELSE 2 END, + updated_at DESC + LIMIT 1 +), + +docs AS ( + SELECT + claim_lookup.id::text AS claim_id, -- uuid -> text для clpr_claim_documents + doc.field_name::text AS field_name, + doc.file_id::text AS file_id, + doc.file_name::text AS file_name, + doc.original_file_name::text AS original_file_name, + (doc.uploaded_at)::timestamptz AS uploaded_at, + doc.file_url::text AS file_url + FROM partial, claim_lookup + 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, file_url text + ) +), + +upsert_docs AS ( + INSERT INTO clpr_claim_documents + (claim_id, field_name, file_id, uploaded_at) + SELECT claim_id, field_name, file_id, uploaded_at + FROM docs + ON CONFLICT (claim_id, field_name) DO UPDATE + SET file_id = EXCLUDED.file_id, + uploaded_at = EXCLUDED.uploaded_at + RETURNING id, claim_id, field_name, file_id +), + +-- ✅ ИСПРАВЛЕНО: Используем ID из claim_lookup вместо partial.cid +upd_claim AS ( + UPDATE clpr_claims c + SET payload = jsonb_set( + COALESCE(c.payload, '{}'::jsonb), + '{documents_meta}', + COALESCE((SELECT p->'documents_meta' FROM partial), '[]'::jsonb), + true + ), + updated_at = now(), + expires_at = now() + interval '14 days' + FROM partial, claim_lookup + WHERE c.id = claim_lookup.id + RETURNING c.id, c.payload +) + +SELECT + (SELECT jsonb_build_object('claim_id', u.id, 'payload', u.payload) FROM upd_claim u) AS claim, + ( + SELECT jsonb_agg( + jsonb_build_object( + 'id', u.id, + 'field_name', u.field_name, + 'file_id', u.file_id, + 'file_url', d.file_url, + 'file_name', d.file_name, + 'original_file_name', d.original_file_name, + 'uploaded_at', d.uploaded_at, + -- имя, которое безопасно отдавать во внешний API + 'filename_for_upload', + COALESCE( + NULLIF(d.original_file_name, ''), + NULLIF(d.file_name, ''), + regexp_replace(d.file_id, '^.*/', '') -- хвост пути как запасной + ) + ) + ) + FROM upsert_docs u + JOIN docs d + ON d.claim_id = u.claim_id + AND d.field_name = u.field_name + WHERE d.file_url IS NOT NULL AND d.file_url <> '' -- не показываем без URL + ) AS documents; + +/* +============================================================================ +ИСПРАВЛЕНИЯ (2025-11-24): +============================================================================ + +ПРОБЛЕМА: Запрос искал запись только по ID (WHERE c.id = partial.cid) + Если запись была создана с другим ID, но с тем же claim_id в payload, + она не находилась и не обновлялась. + +РЕШЕНИЕ: +1. Добавлен CTE claim_lookup - ищет запись и по ID, и по payload->>'claim_id': + WHERE id::text = claim_id_str OR payload->>'claim_id' = claim_id_str +2. Используется найденный ID из claim_lookup вместо partial.cid +3. Это гарантирует, что всегда используется правильная запись + +ИЗМЕНЕНИЯ: +- partial теперь принимает $2::text (вместо $2::uuid) +- Добавлен claim_lookup CTE для поиска записи +- upd_claim использует claim_lookup.id вместо partial.cid +- docs использует claim_lookup.id вместо partial.cid + +============================================================================ +ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ: +============================================================================ + +1. С claim_id как UUID строкой: + $1 = '{"documents_meta": [...]}'::jsonb + $2 = '0eb051ec-23a6-4e06-8b98-f02d20d35f68'::text + +2. С claim_id как UUID из payload: + $1 = '{"documents_meta": [...]}'::jsonb + $2 = '0eb051ec-23a6-4e06-8b98-f02d20d35f68'::text + (запрос найдет запись по payload->>'claim_id', если ID не совпадает) + +============================================================================ +*/ +