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
134 lines
5.0 KiB
SQL
134 lines
5.0 KiB
SQL
-- Исправленный 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 не совпадает)
|
||
|
||
============================================================================
|
||
*/
|
||
|