Files
docs/apps/online-consultation.md

217 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Онлайн-консультация в личном кабинете
---
# Онлайн-консультация (cabinet)
> Как устроена запись на **онлайн-приём** в `apps/cabinet`: маршруты, MIS/Widget API, оплата и видеоконференция. Связано с [расписанием врачей](./doctor-schedule-sync.md).
---
## TL;DR
| Этап | Где | Внешний ресурс |
|------|-----|----------------|
| Список онлайн-врачей | `GET /online-specialists` (нужен login) | PostgreSQL `location_view` (`online_mode=true`) |
| Слоты | `GET /api/interval?onlineMode=1` | `MIS``widget.sovamed.ru` |
| Запись | `webSDK.scheduleRecReserve({ onlineType: 1 })` | Infoclinica SDK в браузере |
| Оплата / видео | `/case-history` | `webSDK.loadPaymentView`, `openConference` |
Cron `upload:doctors 1` (backend) обновляет **ближайшие даты** для онлайн-локаций, не сами слоты.
---
## 1. Маршруты
| URL | Auth | Назначение |
|-----|------|------------|
| `/online-specialists` | `ROLE_USER` | Список врачей с онлайн-локациями |
| `/specialists` | публичный | Очный приём (`onlineMode=0`) |
| `/api/interval` | публичный | Прокси расписания в MIS |
| `/case-history` | `ROLE_USER` | Записи, оплата, «Онлайн приём», возврат |
| `/refund` | `ROLE_USER` | Форма возврата |
Код: [`SpecialistController.php`](../../apps/cabinet/src/Controller/SpecialistController.php), [`PublicAPIController.php`](../../apps/cabinet/src/Controller/PublicAPIController.php), [`SecurityController.php`](../../apps/cabinet/src/Controller/SecurityController.php).
---
## 2. Поток данных
```mermaid
sequenceDiagram
participant User as Пользователь ЛК
participant Cab as cabinet
participant MIS as widget.sovamed.ru
participant SDK as webSDK браузер
User->>Cab: GET /online-specialists
Cab->>Cab: location_view online_mode=1
User->>Cab: GET /api/interval onlineMode=1
Cab->>MIS: /api/reservation/schedule + /intervals
MIS-->>Cab: intervalsData
User->>SDK: scheduleRecReserve onlineType=1
User->>Cab: GET /case-history
Cab->>SDK: records, payment, conference
```
---
## 3. Отличия online vs offline
| | Offline | Online |
|---|---------|--------|
| Список | `/specialists` | `/online-specialists` + login |
| `onlineMode` в API | `0` | `1` |
| Анонимная запись | да (`/api/anonymous-reserve`) | **нет** |
| Согласия | PD | PD + оферта + ИДС |
| После записи | `#doctor-success` | `#online` + предупреждение об оплате 5 мин |
| Оплата / видео | — | `/case-history` |
---
## 4. Типичные причины поломки
### 4.1. Пустой список `/online-specialists`
- Нет строк в `location_view` с `online_mode = true` (cron `upload:doctors 1` + `update_location()`).
- Врач не привязан к MIS (`dcode`, `department`, `filial`).
**Проверка:** SQL `SELECT * FROM location_view WHERE online_mode = true;`
### 4.2. Нет слотов на карточке
- MIS недоступен (`MIS` env, `widget.sovamed.ru`).
- Неверный `filial`/`department` для онлайн-режима.
- `GET /api/interval?onlineMode=1` возвращает 5xx.
**Проверка:** `curl "https://widget.sovamed.ru/specialists/departments"` и `/api/interval` с prod.
### 4.3. Запись создаётся как очная
- Баг нормализации `onlineMode` в JS/PHP (исправлено: `OnlineMode`, `onlineMode.js`).
- В `scheduleRecReserve` уходит `onlineType: 0` вместо `1`.
### 4.4. Фильтр на онлайн-странице уводит на `/specialists`
- Форма поиска post'ила на `specialist_index` (исправлено → `specialist_online_index`).
### 4.5. Оплата / видео не работает
- Не загружен SDK (`loader.js``widget.sovamed.ru/.../sdk.build.min.js`).
- Запись не оплачена в течение 5 мин (MIS отменяет).
- `webSDK.openConference` — вне окна времени приёма.
### 4.6. Авторизация внутри iframe (`#iframeProtocol`) — не должна появляться
**Симптом:** пользователь уже в ЛК, но в модальном окне «Онлайн приём» или «Оплата» внутри iframe просят войти снова.
**Причина:** две независимые сессии:
| Сессия | Где хранится | За что отвечает |
|--------|--------------|-----------------|
| Symfony (`ROLE_USER`) | cookie `cabinet.sovamed.ru` | `/case-history`, `/online-specialists` |
| MIS / webSDK | cookie `widget.sovamed.ru` + скрытый iframe `/sdk` | `openConference`, `loadPaymentView`, `scheduleRecReserve` |
Symfony может быть активна, а MIS — нет (истёк timeout, другой браузер, блокировка third-party cookies).
**Где iframe:**
| Действие | Метод SDK | Элемент |
|----------|-----------|---------|
| «Онлайн приём» | `openConference()` | `#iframeProtocol` — URL видеоконференции |
| Вход через Госуслуги | `loadLoginView()` | `#iframeProtocol`**ожидаемо** показывает login |
| Оплата | `loadPaymentView()` | виджет ЮKassa в `#popup-body` (не login-iframe) |
**Исправление в коде (cabinet):**
- `assets/components/misSession.js` — проверка `webSDK.data.user.authenticated` / `isLoggedIn()` перед оплатой и конференцией.
- `caseHistory_controller.js``openConference` **без** `container` (DOM-элемент ломал SDK `eval(container)` и пропускал Guest URL); iframe переносится в popup через `mountConferenceInPopup()`.
- При протухшей MIS-сессии — popup «Войти снова» → `/logout`, а не форма login внутри iframe.
**Проверка в браузере (prod):**
```javascript
// на /case-history, до клика «Онлайн приём»
window.webSDK?.data?.user?.authenticated // должно быть true
```
```bash
# Symfony-сессия (smoke-скрипт)
curl -b cookies.txt https://cabinet.sovamed.ru/api/userInfo
# → {"data":"<uid>"} — это НЕ гарантия MIS-сессии
```
**Smoke:**
```bash
make local-online-smoke
# шаги 9–10: UI-маркеры case-history, /api/userInfo, доступность MIS SDK
```
### 4.7. MIS / Infoclinica
Env: `MIS=https://widget.sovamed.ru` в [`apps/cabinet/.env`](../../apps/cabinet/.env).
Публичный DNS: CNAME `production.infoclinica.ru``217.74.42.159` (не путать с внутренними IP вроде `10.34.23.239`).
---
## 5. Тесты
### Shell smoke (Docker local)
```bash
make local-up
make local-online-smoke
```
Скрипт: [`scripts/online-consultation-smoke.sh`](../../scripts/online-consultation-smoke.sh)
### Pytest e2e
```bash
./scripts/run-online-consultation-pytest.sh
```
Каталог: [`tests/e2e/online_consultation/`](../../tests/e2e/online_consultation/)
### PHPUnit (cabinet)
```bash
make cabinet-test
# или
docker exec php82-local php bin/phpunit tests/Unit tests/Controller
```
- `tests/Unit/Support/OnlineModeTest.php` — нормализация `0/1/true/false`
- `tests/Controller/OnlineSpecialistsControllerTest.php` — auth на `/online-specialists`
---
## 6. Чеклист диагностики на prod
1. Пользователь залогинен? `/online-specialists` без login → redirect.
2. Есть онлайн-локации в БД? `location_view.online_mode = true`.
3. `docker exec php84 php bin/console upload:doctors 1` — без ошибок?
4. `/api/interval?...&onlineMode=1` — HTTP 200 и `intervalsData`?
5. В браузере загружен `webSDK`? Console → нет 404 на `sdk.build.min.js`.
6. `/case-history` — запись с `onlineType`, статус оплаты?
7. **До «Онлайн приём»:** `window.webSDK.data.user.authenticated === true`? Если `false` — MIS-сессия протухла (см. §4.6).
8. Iframe `#iframeProtocol`: `src` — URL конференции, а не `/login`?
---
## 7. Ключевые файлы
| Файл | Роль |
|------|------|
| `src/Controller/SpecialistController.php` | `/online-specialists` |
| `src/Controller/PublicAPIController.php` | `/api/interval` |
| `src/Repository/SpecialistViewRepository.php` | фильтр `onlineMode` |
| `src/Support/OnlineMode.php` | нормализация флага |
| `assets/components/record.js` | запись, `onlineType` |
| `assets/components/misSession.js` | проверка MIS-сессии, mount iframe конференции |
| `assets/controllers/caseHistory_controller.js` | оплата, конференция |
| `assets/components/loader.js` | загрузка SDK |
| `templates/specialist/_item.html.twig` | карточка врача |