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
This commit is contained in:
AI Assistant
2025-11-24 17:02:29 +03:00
parent 33de3955ac
commit a8de3f0fc9

View File

@@ -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 не совпадает)
============================================================================
*/