109 lines
5.5 KiB
Markdown
109 lines
5.5 KiB
Markdown
---
|
||
title: Анонимная запись на приём через MIS (Backend)
|
||
---
|
||
|
||
# Сценарий 3.1: Анонимная запись (**Anonymous Reserve**)
|
||
|
||
## Бизнес-цель
|
||
|
||
Посетитель сайта может **записаться на приём**, указав контактные данные и выбранный слот, **без обязательной регистрации** в Laravel/Next-сенсах личного кабинета: запись фиксируется в **МИС (Инфоклиника)**.
|
||
|
||
## Точки входа
|
||
|
||
| Тип | Метод + URL | Класс |
|
||
| --- | --- | --- |
|
||
| HTTP | `POST /reservation/anonymous-reserve` | `InfoclinicaController::bookingAnonymous` |
|
||
|
||
Внутренне вызывается Messenger-сообщение **`GetAnonymousReserveRequestMessage`** (транспорт `sync` по `messenger.yaml`).
|
||
|
||
## Входной контракт (DTO)
|
||
|
||
`App\Dto\AnonymousReserveRequestDto` валидирует:
|
||
|
||
- ФИО, email, телефон в формате `+7(999)999-99-99`;
|
||
- `workDate` — 8 цифр `YYYYMMDD`;
|
||
- `time` — интервал `HH:MM-HH:MM`;
|
||
- `filial`, `schedident`, `rnum`, `specialist` (dcode), `accept`, `captcha` и т.д.
|
||
|
||
Метод `toArray()` формирует тело для MIS:
|
||
|
||
- поле `reserve` — **JSON-строка** с деталями слота (`date`, `st`, `en`, `services`, `filial`, `timezone`, `schedident`, `rnum`, `dcode`).
|
||
|
||
Пример упрощённой структуры тела:
|
||
|
||
```json
|
||
{
|
||
"accept": true,
|
||
"fio": "Иванов Иван",
|
||
"captcha": "...",
|
||
"email": "user@example.com",
|
||
"phone": "+7(903)123-45-67",
|
||
"reserve": "{\"date\":\"20260520\",\"st\":\"10:00\",\"en\":\"10:30\", ... }"
|
||
}
|
||
```
|
||
|
||
## Пошаговый алгоритм
|
||
|
||
1. `InfoclinicaController::bookingAnonymous` десериализует JSON в `AnonymousReserveRequestDto`, валидирует.
|
||
2. `SpecialistService::createAnonymousReserve($dto)` создаёт `GetAnonymousReserveRequestMessage` и диспатчит через `MessageBusInterface` (sync).
|
||
3. `GetAnonymousReserveRequestMessageHandler::__invoke`:
|
||
- логирует старт;
|
||
- вызывает `InfoclinicaClientService::anonymousReserve($dto)`;
|
||
- выполняет `POST` на путь **`/api/reservation/anonymous-reserve`** MIS с `json_encode($dto->toArray())`;
|
||
- возвращает массив ответа `toArray()` HTTP-клиента Symfony;
|
||
- при `HttpExceptionInterface` — лог и массив с `status_code`, телом ответа MIS.
|
||
|
||
4. Контроллер делает `$this->json($reserve, $reserve['status_code'] ?? 200)` — **если в ответе есть числовой `status_code`, он подставляется как HTTP-код ответа API**.
|
||
|
||
## Создание строки `Record` в PostgreSQL
|
||
|
||
В текущем дереве `apps/backend/src` **не найдено** кода `persist(new Record(...))` или использования `RecordRepository` в связке с этим эндпоинтом. Сущность `Record` и таблица описаны в модели данных, но **локальное сохранение факта записи вместе с анонимным reserve в этом HTTP-сценарии не реализовано** (или перенесено в другой сервис).
|
||
|
||
## Mermaid
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant C as Клиент
|
||
participant IC as InfoclinicaController
|
||
participant SS as SpecialistService
|
||
participant BUS as MessageBus
|
||
participant H as GetAnonymousReserveRequestMessageHandler
|
||
participant CL as InfoclinicaClientService
|
||
participant MIS as Инфоклиника API
|
||
|
||
C->>IC: POST /reservation/anonymous-reserve
|
||
IC->>SS: createAnonymousReserve(dto)
|
||
SS->>BUS: dispatch(GetAnonymousReserveRequestMessage)
|
||
BUS->>H: __invoke
|
||
H->>CL: anonymousReserve(dto)
|
||
CL->>MIS: POST /api/reservation/anonymous-reserve
|
||
MIS-->>CL: JSON
|
||
CL-->>H: массив
|
||
H-->>IC: результат
|
||
IC-->>C: HTTP код из status_code или 200
|
||
```
|
||
|
||
## Внешние зависимости
|
||
|
||
| Система | Роль |
|
||
| --- | --- |
|
||
| Инфоклиника | создание записи |
|
||
| PostgreSQL | **не задействуется** для `Record` в этом сценарии (по текущему коду) |
|
||
|
||
## Обработка ошибок и edge cases
|
||
|
||
- **`InvalidArgumentException` в контроллере** — `400` с текстом валидации.
|
||
- **Ошибки десериализации JSON в DTO** — должны обрабатываться обработчиком исключений приложения (в контроллере явного try/catch на `ExceptionInterface` нет).
|
||
- **Ответ MIS с ошибкой**: может прийти как `200` с полем `status_code` внутри JSON — клиентский код фронта должен учитывать оба уровня (HTTP и вложенный).
|
||
|
||
## Ссылки на классы
|
||
|
||
- `apps/backend/src/Controller/InfoclinicaController.php`
|
||
- `apps/backend/src/Service/Specialist/SpecialistService.php`
|
||
- `apps/backend/src/Message/GetAnonymousReserveRequestMessage.php`
|
||
- `apps/backend/src/MessageHandler/GetAnonymousReserveRequestMessageHandler.php`
|
||
- `apps/backend/src/Service/Client/InfoclinicaClientService.php`
|
||
- `apps/backend/src/Dto/AnonymousReserveRequestDto.php`
|
||
|
||
См. [sms-record.md](./sms-record.md), [backend-ddd.md](../backend-ddd.md).
|