BUG-017: Legal details — поля не маппятся + GET 404 вместо пустого объекта

Описание

Два связанных бага в юридических деталях сотрудника:

  1. GET возвращает 404 если у сотрудника ещё нет юр. деталей — фронтенд видит ошибку вместо пустой формы
  2. PUT возвращает 500 — фронтенд отправляет поля с другими именами чем ожидает бэкенд

Запрос 1: GET

GET https://erp-test.nirbi.ru/api/v1/admin/employees/84737600-38e1-45fb-874f-46755dc31a21/legal-details
Status: 404 Not Found
{
  "error": {
    "code": "LEGAL_DETAILS_NOT_FOUND",
    "message": "Legal details not found for employee 84737600-38e1-45fb-874f-46755dc31a21"
  }
}

Запрос 2: PUT

PUT https://erp-test.nirbi.ru/api/v1/admin/employees/84737600-38e1-45fb-874f-46755dc31a21/legal-details
Status: 500 Internal Server Error
{
  "inn": "1234432123",
  "passport": "1234 234521",
  "driver_license": "1234 34322",
  "snils": "123-872-872 89"
}
{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "Internal server error"
  }
}

Анализ

Баг 1: GET 404

LegalDetailsService.get() бросает LEGAL_DETAILS_NOT_FOUND (404) если запись не существует. Но по UX юр. детали — необязательная секция. При первом открытии вкладки запись ещё не создана.

Решение: GET должен возвращать 200 с пустым/null объектом, а не 404. Или фронтенд должен обрабатывать 404 как “нет данных, покажи пустую форму”.

Баг 2: PUT 500 — несовпадение полей фронтенда и бэкенда

Фронтенд отправляетБэкенд ожидает (DTO)Проблема
inninn✅ Маппится, но 10 цифр → validation fail (нужно 12)
passportpassport_series + passport_number❌ Фронт шлёт одно поле, бэкенд ждёт два
driver_licensedriver_license_number❌ Другое имя поля
snilssnils✅ Маппится, но формат “123-872-872 89” vs regex ^\d{3}-\d{3}-\d{3} \d{2}$ — OK

Фронтенд (ViewPage.tsx вкладка “Юридические детали”) использует:

  • passport (одно поле “серия + номер”) → бэкенд ожидает passport_series (4 цифры) + passport_number (6 цифр) раздельно
  • driver_license → бэкенд ожидает driver_license_number

Jackson игнорирует неизвестные поля → все null → сервис создаёт пустую запись или падает.

Причина 500: скорее всего inn = “1234432123” (10 цифр) проходит через @ValidMethodArgumentNotValidException → должен вернуть 400. Если 500 — значит ошибка в другом месте (возможно entity save с null в NOT NULL field, или exception при сериализации).

Затронутые сервисы

СервисПроблема
User ServiceGET возвращает 404 вместо пустого объекта
Admin WebViewPage: неправильные имена полей (passport, driver_license), паспорт не разделён на серию/номер
Shared TypesUpsertLegalDetailsRequest использует правильные поля, но фронт не следует им