Загрузка данных


Нужно доработать **SQL-процедуру `dbo.WR_mtsCertificate_v12`**: после сохранения сертификата заполнять пустое `sb_reports.manFIO` из `dat_mts_certificates.manFIO`.

Python уже передаёт `issuerName`, и у всех 136 проблемных записей ФИО сохранено в таблице сертификатов. Поэтому дополнительный запрос к API не нужен.

Вставьте этот блок **внутри существующей транзакции, непосредственно перед `COMMIT;`**:

```sql
-- Заполняем только пустое ФИО отчёта.
-- Непустые значения и применённые исправления сохраняем.
UPDATE r
SET r.manFIO = c.manFIO
FROM dbo.sb_reports AS r
JOIN dbo.dat_members AS m
    ON m.kod = r.kodMember
JOIN dbo.dat_activity AS a
    ON a.kod = m.kodMerop
JOIN dbo.dat_mts_certificates AS c
    ON c.kodReport = r.kod
   AND c.kodMember = m.kod
   AND c.kodMerop = a.kod
WHERE r.kod = @kodReport
  AND m.kod = @kodMember
  AND a.kod = @kodMerop
  AND c.sessionId = @sessionId
  AND c.participantId = @participantId

  AND r.a1 LIKE N'otzyvMTS[_]%'
  AND ISNULL(r.correctionApplied, 0) = 0
  AND ISNULL(r.processingStatus, N'') = N''
  AND c.fallbackAt IS NULL
  AND c.internalSentAt IS NULL

  AND NULLIF(LTRIM(RTRIM(r.manFIO)), N'') IS NULL
  AND NULLIF(LTRIM(RTRIM(c.manFIO)), N'') IS NOT NULL
  AND NULLIF(LTRIM(RTRIM(c.mtsCertNumber)), N'') IS NOT NULL

  -- Не выбираем произвольный источник при дублировании.
  AND NOT EXISTS (
      SELECT 1
      FROM dbo.dat_mts_certificates AS other
      WHERE other.kodReport = r.kod
        AND other.kod <> c.kod
  )

  -- Дополнительная защита от перезаписи исправленной версии.
  AND NOT EXISTS (
      SELECT 1
      FROM dbo.mts_daemon_mail_v12 AS j
      WHERE j.kodReport = r.kod
        AND j.kind IN ('correction', 'fallback_certificate')
        AND (
            j.appliedAt IS NOT NULL
            OR j.state IN ('QUEUED', 'SENT')
        )
  );
```

Здесь **`LTRIM/RTRIM` используются только для проверки пустоты**. В отчёт записывается полное исходное `c.manFIO`, без обрезки и изменения текста. Проверка допуска со строгим `>` остаётся в существующей части процедуры.

Также в этой же процедуре замените текущую строку:

```sql
SET manFIO = COALESCE(
    manFIO,
    NULLIF(JSON_VALUE(@formData, '$.issuerName'), N'')
),
```

на:

```sql
SET manFIO = CASE
    WHEN NULLIF(LTRIM(RTRIM(manFIO)), N'') IS NULL
         AND NULLIF(
             LTRIM(RTRIM(JSON_VALUE(@formData, '$.issuerName'))),
             N''
         ) IS NOT NULL
    THEN JSON_VALUE(@formData, '$.issuerName')
    ELSE manFIO
END,
```

Это исправит ещё один случай: прежний `COALESCE` сохраняет пустую строку или пробелы, поскольку они не являются `NULL`.

**Что произойдёт с существующими 136 записями**

После изменения процедуры следующий цикл, повторно обрабатывающий эти сертификаты, заполнит подходящие отчёты. По последней выгрузке сертификаты повторно проверяются, поэтому отдельный массовый UPDATE сначала не нужен. Исключённые защитными условиями записи останутся для ручного разбора.

После полного цикла проверьте остаток:

```sql
SELECT
    c.kodMerop,
    COUNT_BIG(*) AS missingReportFIO
FROM dbo.dat_mts_certificates AS c
JOIN dbo.sb_reports AS r
    ON r.kod = c.kodReport
   AND r.kodMember = c.kodMember
WHERE NULLIF(LTRIM(RTRIM(c.mtsCertNumber)), N'') IS NOT NULL
  AND NULLIF(LTRIM(RTRIM(c.manFIO)), N'') IS NOT NULL
  AND NULLIF(LTRIM(RTRIM(r.manFIO)), N'') IS NULL
GROUP BY c.kodMerop
ORDER BY missingReportFIO DESC;
```

**Не заменяйте процедуру целиком старой версией из выгрузки:** добавьте изменения в её текущую серверную версию, сохранив уже расширенные строковые параметры. Этот патч устраняет отсутствие переноса ФИО; правильность самого имени, введённого участником, он не меняет.