# Инструкция: запуск и тестирование

Тестируем «снизу вверх» — от проверки токена до прода. Каждый уровень добавляет
инфраструктуру; первые три проходят на любом ноутбуке без МИС и Б24.

---

## 0. Требования

- **PHP 8.1+** с расширениями: `curl`, `mbstring`, `json`.
  Проверка:
  ```bash
  php -v
  php -r 'echo function_exists("curl_init")?"curl OK\n":"curl НЕТ\n";
          echo function_exists("mb_substr")?"mbstring OK\n":"mbstring НЕТ\n";'
  ```
  Если чего-то нет: `apt install php-cli php-curl php-mbstring` (Debian/Ubuntu).
- **Токен бота**: MAX (business.max.ru/self → Чат-боты → Настроить) и/или
  Telegram (@BotFather → `/newbot`).
- Для полного цикла: доступ к Медиалогу `api_v2.php` (VPN/разрешённый IP) и,
  опционально, Bitrix24.

---

## 1. Настройка

Пропиши токены — через переменные окружения (предпочтительно) или прямо в `config.php`:
```bash
export MAX_BOT_TOKEN="токен_из_MAX"
export TG_BOT_TOKEN="токен_из_BotFather"
```
В `config.php` при необходимости поправь: адрес Медиалога, данные клиники,
`webhook_url` для MAX и Telegram. Б24 пока можно не трогать — пустой `bitrix24.webhook`
означает, что передача оператору пишется в лог, а бот работает.

---

## 2. Уровень 1 — токены живые?

```bash
php cli.php max:me     # должен вернуть user_id/username бота MAX
php cli.php tg:me      # должен вернуть данные бота Telegram
```
Если вернулась ошибка 401/Unauthorized — токен неверный. Тестируй только ту
платформу, для которой есть токен.

---

## 3. Уровень 2 — диалог локально (без МИС и Б24)

Long polling не требует ни домена, ни сертификата. Запусти приёмник:

**MAX:**
```bash
php cli.php max:poll
```
**Telegram:** (webhook и polling несовместимы — сначала сними webhook)
```bash
php cli.php tg:delwebhook
php cli.php tg:poll
```

Теперь в приложении MAX/Telegram открой своего бота и нажми «Старт» (`/start`).
Бот ответит приветствием и кнопкой «Поделиться контактом». Поделись контактом.

Что проверяем:
- бот прислал приветствие и запросил контакт;
- после контакта — ответ о привязке (если Медиалог недоступен, бот скажет
  «пациент не найден» — это нормально для этого уровня);
- в `bot.log` появились события.

**Узнай свой chat_id** (понадобится дальше) — он в `bot.log`:
```bash
tail -n 20 bot.log
# ищи "chat_id": <число>  (для MAX это твой user_id, для TG — id чата)
```

---

## 4. Уровень 3 — напоминание и 4 кнопки (без МИС)

Самый важный тест UX. Нужны **два терминала**.

**Терминал 1** — оставь приёмник запущенным (`max:poll` или `tg:poll`).

**Терминал 2** — отправь себе напоминание вручную, подставив платформу и свой chat_id:
```bash
# Telegram:
php send_reminder.php manual tg <твой_chat_id> 500 "21.05.2026" "11:30" "гинеколога" "Ковалёва Е. И." "Натощак"
# MAX:
php send_reminder.php manual max <твой_chat_id> 500 "21.05.2026" "11:30" "гинеколога" "Ковалёва Е. И." "Натощак"
```
В мессенджере придёт напоминание ровно по ТЗ с 4 кнопками. Жми кнопки и смотри
терминал 1 / `bot.log`:

| Кнопка | Что произойдёт на этом уровне |
|---|---|
| Перенести запись | в `bot.log` строка `HANDOFF ... Прошу перенести запись`, бот ответит «соединяю с оператором» |
| Соединение с оператором | то же, сообщение «Нужна консультация» |
| Подтвердить / Отменить | бот попытается сходить в Медиалог. Без доступа к МИС будет ошибка — это ожидаемо, эти две кнопки проверяются на уровне 4 |

То есть кнопки «перенести/оператор» полностью тестируются здесь, а
«подтвердить/отменить» — когда появится доступ к Медиалогу.

---

## 5. Уровень 4 — интеграция с Медиалогом

Запускать с хоста, у которого есть доступ к `api_v2.php` (VPN/разрешённый IP).

1. Посмотри сырой ответ по реальной записи и сверь имена полей:
   ```bash
   php send_reminder.php dump <planning_id>
   ```
   Если поля называются не `DATE_CONS` / `HEURE` / `PATIENTS_ID` / `MEDECINS_ID` /
   `PLANNING_ID` — поправь единственную функцию `mapAppointment()` в `send_reminder.php`.

   **Проверка поиска по телефону** (в МИС номера лежат в разных форматах — бот
   ищет по нескольким вариантам и сверяет по последним 10 цифрам):
   ```bash
   php send_reminder.php findphone 79990000000   # какие варианты пробуются и кто найден
   php send_reminder.php searchraw "9990000000"  # сырой ответ searchPacients — увидеть имена полей телефона
   ```
   Если телефонное поле в вашей базе называется необычно — бот всё равно поймает
   его эвристикой по имени поля (`*tel*/*phone*/*mobil*/*тел*/*моб*`), но можно
   дописать точное имя в `patientPhoneMatches()` в `src/MedialogApi.php`.

2. Привяжи себя как пациента: пройди уровень 2 (поделись контактом) с номера,
   который есть в Медиалоге. Бот найдёт тебя через `searchPacients` и свяжет
   chat_id ↔ PATIENTS_ID.

3. Боевая отправка по записи (платформа выберется автоматически):
   ```bash
   php send_reminder.php <planning_id>
   ```

4. Проверь «Подтвердить» и «Отменить»: нажми и убедись по `bot.log`, что вызовы
   `updateCall` / `editStatus` ушли с кодом 200, и что статус в Медиалоге изменился.
   ⚠️ Уточни значение `medialog.status_confirmed` в `config.php` — в БД может быть
   код, а не строка «Запись подтверждена».

---

## 6. Уровень 5 — прод через webhook

Нужен публичный HTTPS с доверенным сертификатом (MAX с 25.05.2026 — обязательно;
Telegram — всегда). Залей проект на сервер, укажи в `config.php` реальные
`max.webhook_url` и `tg.webhook_url`, затем:

```bash
php cli.php max:subscribe     # подписать MAX на webhook.php
php cli.php max:subs          # проверить подписку
php cli.php tg:setwebhook     # подключить webhook_tg.php
```

После этого приёмник (`*:poll`) не нужен — события идут на `webhook.php` /
`webhook_tg.php`. Напоминания шли по cron:
```cron
*/5 * * * * php /путь/max-mis-bot/send_reminder.php <planning_id>   # пример
```
(реальную логику «кого и когда напоминать» подвяжешь к выборке записей из Медиалога —
например, `getTodayAppointment` за завтрашний день).

> Для локального теста webhook без сервера можно поднять туннель (ngrok/cloudflared) —
> они дают доверенный HTTPS. Но для разработки проще long polling (уровни 2–4).

---

## 7. Включение Bitrix24 (когда будет коннектор)

В `config.php → bitrix24` заполни `webhook` портала и для каждого мессенджера свои
`connector_id` / `line_id`. Как только `webhook` непустой, `bootstrap.php` сам
подключит `Bitrix24Handoff` вместо лог-заглушки. Сверь метод/поток с тем, как у
тебя поднят коннектор открытой линии (каркас — на `imconnector.send.messages`).

---

## 8. Чек-лист готовности

- [ ] `max:me` / `tg:me` возвращают бота
- [ ] `/start` → приветствие + запрос контакта
- [ ] контакт принимается, привязка пишется в `patients.json`
- [ ] `send_reminder.php manual` присылает напоминание с 4 кнопками
- [ ] «перенести»/«оператор» → запись в `bot.log` (или сессия в Б24)
- [ ] `dump <planning_id>` отдаёт запись, поля совпадают с `mapAppointment()`
- [ ] «подтвердить»/«отменить» меняют статус в Медиалоге
- [ ] (прод) webhook подписан, события приходят

---

## 9. Траблшутинг

| Симптом | Причина / решение |
|---|---|
| `Call to undefined function curl_init()` | нет `php-curl` → `apt install php-curl` |
| `Call to undefined function mb_substr()` | нет `php-mbstring` → `apt install php-mbstring` |
| `max:me` → 401 | неверный токен MAX (или передан в query — нужен заголовок, это уже в коде) |
| `SSL certificate problem: unable to get local issuer certificate` на `max:me` | у `platform-api2.max.ru` сертификат Минцифры — поставь его в систему (раздел 10) или укажи `tls.ca_bundle` в config |
| Telegram `getUpdates` ничего не шлёт | висит webhook → `php cli.php tg:delwebhook` |
| MAX webhook не приходит | HTTP или самоподписанный сертификат — нужен HTTPS + доверенный (Минцифры) |
| Контакт «не удалось подтвердить» | подпись hash не сошлась. Сверь на живом payload порядок аргументов HMAC; на время отладки поставь `max.strict_contact_hash = false` |
| «пациент не найден» при верном номере | Медиалог недоступен с этого хоста (VPN/IP) или формат телефона в БД иной |
| Не знаю свой chat_id для `manual` | запусти `*:poll`, напиши боту, возьми `chat_id` из `bot.log` |
| Кнопки «подтвердить/отменить» дают ошибку | нет доступа к Медиалогу — это уровень 4, проверяй с VPN-хоста |

Логи всего — в `bot.log` (события, ошибки, вызовы Медиалога, handoff). При проблеме
смотри его первым: `tail -f bot.log`.

---

## 10. Сертификат Минцифры (ошибка SSL на MAX)

`platform-api2.max.ru` подписан НУЦ Минцифры (Russian Trusted CA), которого нет в
системном хранилище — отсюда `unable to get local issuer certificate`.

### Вариант A (рекомендуется) — поставить сертификаты в систему

Чинит разом cURL/wget/git и весь бот. Debian/Ubuntu:

```bash
# скачиваем корневой и выпускающий (--no-check-certificate, т.к. сам портал тоже на серте Минцифры)
wget --no-check-certificate -P /usr/local/share/ca-certificates/ \
  https://gu-st.ru/content/lending/russian_trusted_root_ca_pem.crt
wget --no-check-certificate -P /usr/local/share/ca-certificates/ \
  https://gu-st.ru/content/lending/russian_trusted_sub_ca_pem.crt

update-ca-certificates        # подхватит новые .crt из /usr/local/share/ca-certificates
```

Проверка:
```bash
curl -sS https://platform-api2.max.ru/ >/dev/null && echo "TLS OK"
php cli.php max:me
```

> CentOS/RHEL/Alma/Rocky: класть в `/usr/share/pki/ca-trust-source/anchors/` и
> выполнять `update-ca-trust` (вместо `update-ca-certificates`).

### Вариант B — без правки системы, указать боту PEM

Если системное хранилище трогать нельзя:
```bash
mkdir -p certs
wget --no-check-certificate -O certs/root.crt https://gu-st.ru/content/lending/russian_trusted_root_ca_pem.crt
wget --no-check-certificate -O certs/sub.crt  https://gu-st.ru/content/lending/russian_trusted_sub_ca_pem.crt
cat certs/root.crt certs/sub.crt > certs/russian_trusted.pem
```
В `config.php` → `tls.ca_bundle` пропиши путь:
```php
'ca_bundle' => __DIR__ . '/certs/russian_trusted.pem',
```

### Вариант C — НЕ для прода

Только чтобы быстро проверить логику: `config.php → tls.insecure => true` отключает
проверку TLS. На бою с данными пациентов так оставлять нельзя (риск MITM).
