feat: Получение cf_2624 из MySQL и блокировка полей при подтверждении данных

- Добавлен сервис CrmMySQLService для прямого подключения к MySQL CRM
- Обновлён метод get_draft() для получения cf_2624 напрямую из БД
- Реализована блокировка полей (readonly) при contact_data_confirmed = true
- Добавлен выбор банка для СБП выплат с динамической загрузкой из API
- Обновлена документация по работе с cf_2624 и MySQL
- Добавлен network_mode: host в docker-compose для доступа к MySQL
- Обновлены компоненты формы для поддержки блокировки полей
This commit is contained in:
AI Assistant
2025-12-04 12:22:23 +03:00
parent 64385c430d
commit 080e7ec105
69 changed files with 17034 additions and 1439 deletions

View File

@@ -0,0 +1,86 @@
-- ============================================================================
-- Упрощённый SQL запрос для обновления upload_description
-- ============================================================================
-- Параметры:
-- $1 :: uuid -- claim_document_id (ID документа из таблицы clpr_claim_documents)
-- $2 :: text -- upload_description (новое описание документа)
-- ============================================================================
-- Этот запрос обновляет описание в payload.body['uploads_descriptions[i]']
-- Это самый приоритетный способ хранения, который проверяется первым при чтении
-- ============================================================================
WITH
-- Находим документ и извлекаем нужные данные
doc_info AS (
SELECT
cd.id AS claim_document_id,
cd.claim_id::text AS claim_id_text,
cd.field_name,
-- Извлекаем индекс i из field_name (например, uploads[0][0] -> 0)
NULLIF((regexp_match(cd.field_name, 'uploads\[(\d+)\]'))[1], '')::int AS upload_index,
c.id AS claim_uuid,
c.payload
FROM clpr_claim_documents cd
JOIN clpr_claims c ON c.id::text = cd.claim_id::text
WHERE cd.id = $1
LIMIT 1
),
-- Обновляем payload: обновляем описание в body (самый приоритетный и надёжный способ)
updated_claim AS (
UPDATE clpr_claims c
SET
payload = (
-- Сохраняем весь payload кроме body
COALESCE(c.payload, '{}'::jsonb) - 'body'
) || jsonb_build_object(
-- Обновляем body: берём существующий body (или пустой объект) и добавляем/обновляем ключ
'body',
COALESCE(c.payload->'body', '{}'::jsonb) ||
jsonb_build_object('uploads_descriptions[' || di.upload_index::text || ']', $2::text)
),
updated_at = now()
FROM doc_info di
WHERE c.id = di.claim_uuid
RETURNING c.id, c.payload
)
-- Возвращаем обновлённые данные
SELECT
di.claim_document_id,
di.claim_id_text AS claim_id,
di.field_name,
di.upload_index,
-- Проверяем, где сохранилось описание (приоритет: body > корень > массив)
COALESCE(
uc.payload->'body'->>('uploads_descriptions[' || di.upload_index::text || ']'),
uc.payload->>('uploads_descriptions[' || di.upload_index::text || ']'),
uc.payload->'edit_fields_parsed'->'uploads_descriptions'->>di.upload_index::text,
NULL
) AS upload_description,
-- ✅ Диагностика: длина сохранённого значения
length(
COALESCE(
uc.payload->'body'->>('uploads_descriptions[' || di.upload_index::text || ']'),
uc.payload->>('uploads_descriptions[' || di.upload_index::text || ']'),
uc.payload->'edit_fields_parsed'->'uploads_descriptions'->>di.upload_index::text,
''
)
) AS description_length,
-- ✅ Диагностика: длина переданного значения
length($2::text) AS input_length,
-- ✅ Диагностика: проверяем, что значение сохранилось полностью
CASE
WHEN length($2::text) = length(
COALESCE(
uc.payload->'body'->>('uploads_descriptions[' || di.upload_index::text || ']'),
uc.payload->>('uploads_descriptions[' || di.upload_index::text || ']'),
uc.payload->'edit_fields_parsed'->'uploads_descriptions'->>di.upload_index::text,
''
)
) THEN 'OK'
ELSE 'TRUNCATED'
END AS status
FROM doc_info di
JOIN updated_claim uc ON uc.id = di.claim_uuid;