Справка: технические страницы только в нашей сборке (build-tag internaldocs)
Из клиентской сборки убрана проектная документация, читавшаяся прямым `strings`:
архитектура обмена с НРД, протокол событий bj↔bj2depo (FTV_M2M, 41 КБ), схема
базы, криптография, QUIK МНП. Это самая крупная и самая дешёвая утечка знаний —
её не нужно было даже декомпилировать.
Файлы перенесены в web/templates/internal/ (выпадают из общего embed-глоба) и
встраиваются только при `go build -tags internaldocs` (internaldocs_on.go).
По умолчанию (клиентский релиз, build-release.sh) страницы заменяются заглушкой
«доступно на портале» (internaldocs_off.go); ссылки на них в индексе справки
показываются под {{if internalDocs}}. Операторские страницы (ручной ввод, робот,
внешние системы, API ЛК) остаются — они нужны на месте.
Клиентская сборка: -27 тыс. символов внутренней документации, «Согласовано
10.09», «Для программиста Fancy», «как устроен обмен» → 0 совпадений.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
{{define "content"}}
|
||||
<p style="margin-bottom:16px"><a href="/admin/help">← все инструкции</a></p>
|
||||
|
||||
<div class="card">
|
||||
<h2>Архитектура: как устроен обмен с НРД</h2>
|
||||
<p class="muted">Документ-источник: <code>DOC/ruk_install_ish_2025_11_10.pdf</code> (Руководство по установке ИШ от 10.11.2025), <code>DOC/instr-ish-rest-api.pdf</code> (REST API ИШ).</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Схема обмена (полная)</h2>
|
||||
<pre style="font-size:12px;line-height:1.4;background:var(--bg);padding:16px;border-radius:6px;overflow:auto">
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ НАША СТОРОНА │
|
||||
│ │
|
||||
│ Linux ВМ (РЕД ОС 8) Astra Linux ВМ │
|
||||
│ ────────────────── ────────────────── │
|
||||
│ ┌──────────────────┐ REST API ┌──────────────────┐ │
|
||||
│ │ bj-server │ ────POST/GET──> │ ИШ (igate) │ │
|
||||
│ │ (наше ПО) │ <───────────── │ (получаем у НРД)│ │
|
||||
│ │ │ │ │ │
|
||||
│ │ • стейт-машина │ │ Делает САМ: │ │
|
||||
│ │ • PostgreSQL │ │ • подпись │ │
|
||||
│ │ • админка :8080 │ │ • упаковку ЭДО │ │
|
||||
│ │ {{if devOn}}• lk-emulator {{else}}• коннектор ЛК {{end}}│ │ • проверку │ │
|
||||
│ │ │ │ подписей НРД │ │
|
||||
│ └──────────────────┘ │ • БД PostgreSQL │ │
|
||||
│ │ (history) │ │
|
||||
│ └──────┬───────────┘ │
|
||||
│ │ │
|
||||
│ АПК «Валидата Клиент L» │ АПК «Валидата │
|
||||
│ (PKCS#11) — общий для всех │ Клиент L» │
|
||||
│ компонентов │ │
|
||||
└──────────────────────────────────────────────┼─────────────────┘
|
||||
│
|
||||
SOAP/REST/HTTPS │ Web-сервис ONYX
|
||||
▼
|
||||
┌────────────────────────────┐
|
||||
│ СТОРОНА НРД │
|
||||
│ │
|
||||
│ GUEST: gost-gt.nsd.ru │
|
||||
│ TEST3: gost.nsd.ru │
|
||||
│ PROM: edog.nsd.ru │
|
||||
│ │
|
||||
│ /onyxgs/WslService │
|
||||
│ /onyxt3/WslService │
|
||||
│ /onyxpr/WslService │
|
||||
│ │
|
||||
│ ↓ внутрь НРД │
|
||||
{{if devOn}} │ • робот-автотест │
|
||||
│ MC0012500000 │
|
||||
{{end}} │ • реальные депозитарии │
|
||||
│ • биржевые системы │
|
||||
└────────────────────────────┘
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Компоненты — кто на чьей стороне</h2>
|
||||
<table>
|
||||
<thead><tr><th>Компонент</th><th>Сторона</th><th>ОС</th><th>СКЗИ</th><th>Назначение</th></tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>bj-server</strong></td>
|
||||
<td>наша</td>
|
||||
<td>Astra Linux SE 1.7 / Linux</td>
|
||||
<td>АПК «Валидата Клиент L» (PKCS#11)</td>
|
||||
<td>Стейт-машина, журнал в БД, веб-админка{{if devOn}}, lk-emulator{{end}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>ИШ (igate)</strong></td>
|
||||
<td>наша <span class="muted">(но дистрибутив даёт НРД)</span></td>
|
||||
<td>Astra Linux SE 1.6/1.7</td>
|
||||
<td>АПК «Валидата Клиент L»</td>
|
||||
<td>Подписывает наш XML сертификатом УЦ МБ, упаковывает в пакет ЭДО, отправляет в НРД</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>ONYX (WSL)</strong></td>
|
||||
<td>НРД</td>
|
||||
<td>—</td>
|
||||
<td>—</td>
|
||||
<td>Web-сервис НРД — принимает пакеты от ИШ всех клиентов</td>
|
||||
</tr>
|
||||
{{if devOn}}<tr>
|
||||
<td><strong>Робот-автотест</strong></td>
|
||||
<td>НРД</td>
|
||||
<td>—</td>
|
||||
<td>—</td>
|
||||
<td>Контрагент-эмулятор внутри НРД. Адресуется кодом <code>MC0012500000</code> в TEST3</td>
|
||||
</tr>{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Часто задаваемые вопросы</h2>
|
||||
|
||||
<h3>Q: ИШ — это сервер НРД, к которому мы подключаемся?</h3>
|
||||
<p>Нет. <strong>ИШ — это наша программа, поставленная у нас.</strong> НРД даёт дистрибутив (<code>igate_100.0-765_amd64.deb</code>, 117 МБ), но ставим у себя. ИШ — это «персональный почтовый клиент к НРД» с подписью.</p>
|
||||
|
||||
<h3>Q: ИШ можно поставить на ту же ВМ, что и bj-server?</h3>
|
||||
<p>Да, если ВМ — Astra Linux. И bj-server, и ИШ работают на Astra Linux SE 1.6/1.7 и используют одно и то же СКЗИ — АПК «Валидата Клиент L». Можно собрать всё на одной ВМ или разнести по отдельным.</p>
|
||||
|
||||
<h3>Q: Мы перекладываем файлы между bj-server и ИШ?</h3>
|
||||
<p>Нет. Мы используем <strong>REST API</strong> ИШ (раздел 2.5 инструкции). bj-server делает HTTP-запросы: <code>POST /api/package/{channel}/file</code> с ZIP в теле. Никаких разделяемых папок. (Альтернативный режим «обменные папки» в ИШ есть — мы его не используем.)</p>
|
||||
|
||||
<h3>Q: Где брать Валидату?</h3>
|
||||
<p>Дистрибутив для Astra Linux SE опубликован на сайте Московской Биржи: <a href="https://fs.moex.com/cdp/po/ClientL_ALSE.zip" target="_blank" rel="noopener">fs.moex.com/cdp/po/ClientL_ALSE.zip</a>. На Linux отдельной лицензии и регистрационных данных не требует — пакеты <code>zpki</code>/<code>zsdk</code> ставятся через <code>dpkg -i</code> и работают сразу.</p>
|
||||
|
||||
<h3>Q: Какой сертификат нужен?</h3>
|
||||
<p>Только от <strong>УЦ Московской Биржи</strong> (<code>ca.moex.com</code>). Сертификаты других УЦ ИШ не примет. УЦ МБ выпускает сертификаты только для организаций, подключённых к ЭДО НРД (по договору).</p>
|
||||
|
||||
{{if devOn}}
|
||||
<h3>Q: Что делать, чтобы протестировать на роботе НРД на TEST3?</h3>
|
||||
<ol>
|
||||
<li>Получить сертификат УЦ МБ для нашей организации.</li>
|
||||
<li>Подать <a href="https://www.nsd.ru/workflow/zayavka-na-testirovanie/" target="_blank">заявку на тестирование</a> в НРД (инструкция в <code>DOC/instr_int_sh_01072025.pdf</code>).</li>
|
||||
<li>Получить от НРД код депонента-тестера и доступ к TEST3.</li>
|
||||
<li>Поднять Astra Linux ВМ, поставить ИШ + Валидату, импортировать сертификат.</li>
|
||||
<li>В нашем <a href="/admin/setup">/admin/setup</a> → «Интеграционный шлюз НРД» указать URL ИШ (например <code>http://10.10.10.23:8080</code>) и имя канала из ИШ.</li>
|
||||
<li>Отправить тестовую заявку с <code>ReceiverCode = MC0012500000</code> и <code>DocumentSeries = 2001</code> — робот ответит «Принять все бумаги».</li>
|
||||
</ol>
|
||||
|
||||
<h3>Q: Сколько времени нужно от старта подключения до прогона на TEST3?</h3>
|
||||
<p>Оптимистично — <strong>1-2 недели</strong> (если все ответы НРД быстрые и УЦ МБ не задерживает). Реалистично — <strong>3-4 недели</strong>. На нашей стороне всё уже готово; задержка только во внешних шагах.</p>
|
||||
{{else}}
|
||||
<h3>Q: Что нужно, чтобы начать обмен с НРД?</h3>
|
||||
<ol>
|
||||
<li>Получить сертификат УЦ МБ для организации.</li>
|
||||
<li>Оформить в НРД подключение к ЭДО и сервису MOEX МОСТ (M2M), получить доступ к нужному контуру.</li>
|
||||
<li>Поднять Astra Linux ВМ, поставить ИШ + Валидату, импортировать сертификат.</li>
|
||||
<li>В <a href="/admin/setup">Настройке</a> → «НРД» указать профиль, URL ИШ и ключевой контейнер, затем проверить подключения на странице <a href="/admin/status">«Статус»</a>.</li>
|
||||
</ol>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{if devOn}}
|
||||
<div class="card">
|
||||
<h2>Что у нас уже готово</h2>
|
||||
<ul>
|
||||
<li><strong>REST-клиент ИШ</strong> в <code>internal/nsdadapter/igw/</code> — все 4 endpoint'а по спецификации, упаковщик/распаковщик ZIP, 10 тестов PASS</li>
|
||||
<li><strong>Робот-эмулятор</strong> в <code>internal/nsdadapter/mock/</code> — позволяет проверить нашу логику до получения реального ИШ</li>
|
||||
<li><strong>Конфигурация в админке</strong> — поля <code>igw_base_url</code> и <code>channel</code> в /admin/setup; авто-определение профилей GUEST/TEST3/PROD</li>
|
||||
<li><strong>Подбор URL контуров</strong> — при выборе профиля URL ONYX заполняется автоматически</li>
|
||||
<li><strong>Полная документация ИШ</strong> в <code>DOC/</code> и дистрибутив в <code>dist/ish/</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -0,0 +1,136 @@
|
||||
{{define "content"}}
|
||||
<div class="card">
|
||||
<h2>Криптография (АПК «Валидата Клиент L»)</h2>
|
||||
<p class="muted">bj-server общается с СКЗИ «Валидата Клиент L» через сайдкар <code>bj-crypto</code> по UDS <code>/run/bj/crypto.sock</code>. Чтобы подпись и проверка квитанций НРД заработали, нужен <strong>ключевой профиль</strong> — папка с тремя сущностями: <code>local.pse</code> (зашифрованный контейнер), <code>local.gdbm</code> (база сертификатов) и <code>vdkeys/*.vdk</code> (сам ключ).</p>
|
||||
<p class="muted"><strong>Архив от MOEX/НРД содержит «резервную копию», а не готовый профиль.</strong> На Linux рабочий <code>local.gdbm</code> нельзя восстановить headless — Валидата Linux требует GUI-операции «Восстановить справочники из резервной копии». Поэтому профиль готовится один раз на Windows и переносится на сервер через USB.</p>
|
||||
</div>
|
||||
|
||||
<div class="card" style="background:var(--accent-weak)">
|
||||
<h2>Почему профиль готовится на Windows, а не на сервере</h2>
|
||||
<p>Боевой Astra Linux SE-сервер с ГОСТ-криптографией <strong>обязан быть headless</strong>: чем меньше пакетов и поверхности атаки, тем проще сертификация ФСТЭК и тем меньше нарушений требований к контуру ЭДО НРД. Установка GUI (X-сервер, GTK, шрифты, VNC/RDP) тянет 50+ пакетов, расширяет surface attack и усложняет аудит — поэтому отказались.</p>
|
||||
<p>Это <strong>стандартная практика</strong> в фин-секторе: на admin-станции (под Windows или отдельной защищённой ВМ) генерируются и обновляются профили; на боевые серверы они доставляются готовыми через выделенный USB или защищённый канал. Все инструкции MOEX/НРД написаны именно под Windows — этот путь поддерживается официально.</p>
|
||||
<p class="muted">Альтернативный путь — Linux GUI через X11-forwarding или VNC на дев-стенды — допустим только в песочнице, не в проде. На боевых серверах <code>zcs</code>/<code>vdcsp_cfg</code> не должны запускаться.</p>
|
||||
</div>
|
||||
|
||||
<div class="card" style="background:var(--ok-weak)">
|
||||
<h2>Подготовка профиля (Windows → USB → bj-server)</h2>
|
||||
|
||||
<h3 style="margin-top:14px">Шаг A — на компьютере под Windows</h3>
|
||||
<ol>
|
||||
<li><strong>Установите СКЗИ Валидата CSP для Windows</strong>.<br>
|
||||
Скачайте дистрибутив с <a href="https://www.moex.com/s1292" target="_blank" rel="noopener">moex.com/s1292</a> (раздел «СКЗИ для Windows», файл «Валидата CSP v.6.0.482.0 64bit»). Внутри архива есть <code>Readme.txt</code> с регистрационными данными — введите их во время установки.
|
||||
</li>
|
||||
|
||||
<li><strong>Распакуйте архив-профиль от MOEX/НРД</strong>.<br>
|
||||
Например <code>PrUser985.7z</code> с паролем <code>11</code> в папку <code>C:\moex-src\</code>. Получится структура:
|
||||
<pre style="font-size:12px">C:\moex-src\
|
||||
spr985\
|
||||
local.pse
|
||||
local.gdbm ← это «резервная копия», на Linux не работает напрямую
|
||||
vdkeys\
|
||||
XXXXXXXXXXXXXXXX.vdk
|
||||
key.reg</pre>
|
||||
</li>
|
||||
|
||||
<li><strong>Зарегистрируйте ключ в системе Windows</strong>.<br>
|
||||
Двойной клик по <code>key.reg</code> → «Да» на запрос о записи в реестр. Это нужно, чтобы Валидата увидела ключ при восстановлении справочников.
|
||||
</li>
|
||||
|
||||
<li><strong>Откройте «Справочник сертификатов x64»</strong> из меню «Пуск» → «АПК Валидата Клиент».</li>
|
||||
|
||||
<li><strong>Создайте профиль на флешке</strong>:
|
||||
<ul>
|
||||
<li>Вставьте чистую USB-флешку, запомните её букву (например <code>E:</code>).</li>
|
||||
<li>В Справочнике: меню <em>Профили</em> → <em>Настройка профилей</em> → <em>Добавить</em>.</li>
|
||||
<li>Имя профиля: например <code>moex</code>.</li>
|
||||
<li><strong>Каталог профиля</strong>: создайте новую пустую папку <strong>на флешке</strong>, например <code>E:\moex\</code>. Это путь, куда Валидата положит рабочую копию.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><strong>Восстановите справочники из резервной копии</strong>:<br>
|
||||
Меню <em>Сервис</em> → <em>Восстановить справочники из резервной копии</em>. В диалоге укажите папку <code>C:\moex-src\spr985\</code>. Дождитесь сообщения «Справочники восстановлены».<br>
|
||||
После этого в <code>E:\moex\</code> появятся <code>local.pse</code> и <strong>рабочий</strong> <code>local.gdbm</code> (отличается от исходной резервной копии).
|
||||
</li>
|
||||
|
||||
<li><strong>Скопируйте папку <code>vdkeys</code> на корень флешки</strong>.<br>
|
||||
Скопируйте папку <code>C:\moex-src\vdkeys\</code> в корень флешки. Итоговая структура:
|
||||
<pre style="font-size:12px">E:\
|
||||
moex\ ← рабочий профиль, созданный Валидатой
|
||||
local.pse
|
||||
local.gdbm ← теперь правильный
|
||||
vdkeys\
|
||||
XXXXXXXXXXXXXXXX.vdk</pre>
|
||||
</li>
|
||||
|
||||
<li><strong>Безопасно извлеките флешку</strong> через значок в системном трее Windows.</li>
|
||||
</ol>
|
||||
|
||||
<h3 style="margin-top:18px">Шаг B — на сервере (этот веб-интерфейс)</h3>
|
||||
<ol>
|
||||
<li><strong>Вставьте флешку в сервер</strong> (физический USB-порт или прокинутая через гипервизор виртуальная флешка).</li>
|
||||
|
||||
<li>Откройте <a href="/admin/setup">/admin/setup</a>. Через 2-3 секунды (автодетект монтирования) в блоке <strong>«Носители ключей»</strong> появится строка <code>USB /run/media/...</code>. Внутри неё — сабблок <strong>«Профиль Валидаты»</strong> с тремя строками: <code>local.pse</code> / <code>local.gdbm</code> / <code>*.vdk</code>.</li>
|
||||
|
||||
<li>В поле <strong>«Имя профиля»</strong> введите осмысленное имя (например <code>moex</code>) и нажмите <strong>«Импортировать профиль в Валидату»</strong>.<br>
|
||||
Сервер скопирует файлы в <code>/var/lib/bj/profiles/<имя>/</code>, допишет секцию в <code>/opt/Validata/VDCSP/etc/pki1.conf</code>. Toast подтвердит: «Секция дописана в pki1.conf».</li>
|
||||
|
||||
<li>В таблице <strong>«Импортированные профили Валидаты»</strong> ниже — нажмите <strong>«Активировать»</strong> в строке вашего профиля.<br>
|
||||
Toast: «Валидата: контекст с профилем <имя> инициализирован» → готово.</li>
|
||||
|
||||
<li>Можно извлекать флешку — все нужные файлы уже скопированы в <code>/var/lib/bj/profiles/</code>.</li>
|
||||
</ol>
|
||||
|
||||
<h3 style="margin-top:18px">Проверка</h3>
|
||||
<ol>
|
||||
<li>В блоке «СКЗИ» нажмите зелёную кнопку <strong>«✓ Проверить подключение СКЗИ»</strong>.</li>
|
||||
<li>Toast должен показать что-то вроде: <code>СКЗИ validata: 0.1.0 (Валидата: контекст с профилем «moex» инициализирован)</code>.</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Что делать если профиль на флешке не виден</h2>
|
||||
<ul>
|
||||
<li><strong>USB не монтируется автоматически в Astra Linux SE.</strong> Подключите вручную: посмотрите <code>lsblk</code>, потом <code>sudo mount /dev/sdb1 /mnt</code>. Через секунду «Носители ключей» подхватит точку монтирования.</li>
|
||||
<li><strong>Файлы лежат не в корне флешки.</strong> Сканер ищет в глубину 4 уровня — если поместили в <code>E:\very\deep\folder\moex\</code>, должно тоже найтись.</li>
|
||||
<li><strong>На флешке нет <code>vdkeys\</code>.</strong> Без неё профиль не работает — ключ <code>.vdk</code> обязателен.</li>
|
||||
<li><strong>«Ни контейнеров, ни сертификатов, ни профиля Валидаты не найдено».</strong> Это значит на носителе нет <em>одновременно</em> <code>.pse</code> и <code>.vdk</code> файлов. Перепроверьте Шаг 6-7 на Windows.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Альтернатива: загрузка как ZIP-архив</h2>
|
||||
<p>Если USB-доступ к серверу неудобен — можно собрать содержимое флешки в обычный <code>.zip</code> на Windows и загрузить через web-форму.</p>
|
||||
<ol>
|
||||
<li>После шага A.7 (когда на флешке готовая структура <code>moex\</code> + <code>vdkeys\</code>) — выделите обе папки, правый клик → <em>Отправить</em> → <em>Сжатая ZIP-папка</em>.</li>
|
||||
<li>На сервере: <a href="/admin/setup">/admin/setup</a> → «Носители ключей» → форма «Загрузить образ или архив» → выберите ZIP, поле «Пароль» оставьте пустым.</li>
|
||||
<li>Дальше как в Шаге B со 2-го пункта.</li>
|
||||
</ol>
|
||||
<p class="muted">Под капотом сервер распаковывает архив через <code>7z</code> в <code>/var/lib/bj/media/iso/</code>, сканирует на профиль Валидаты — далее всё то же самое, что с USB.</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Справочные команды (диагностика)</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><td><code>systemctl status bj-crypto</code></td><td>Состояние Java-сайдкара (UDS-сокет, провайдер).</td></tr>
|
||||
<tr><td><code>sudo journalctl -u bj-crypto -n 50</code></td><td>Последние строки лога сайдкара.</td></tr>
|
||||
<tr><td><code>cat /opt/Validata/VDCSP/etc/pki1.conf</code></td><td>Список профилей, которые видит Валидата (наши секции помечены <code># --- bj-server: профиль ...</code>).</td></tr>
|
||||
<tr><td><code>sudo ls -la /var/lib/bj/profiles/</code></td><td>Импортированные профили на сервере.</td></tr>
|
||||
<tr><td><code>/opt/Validata/VDCSP/bin/amd64/testcsp -silent</code></td><td>Базовая проверка провайдера CSP.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Установка Валидаты на сервер (если её ещё нет)</h2>
|
||||
<p class="muted">Если этот раздел вам не показывает «✓ ready» — повторите установку:</p>
|
||||
<pre>curl -fsSL https://fs.moex.com/cdp/po/ClientL_ALSE.zip -o ClientL_ALSE.zip
|
||||
unzip ClientL_ALSE.zip
|
||||
sudo apt-get install -y libccid pcscd execstack
|
||||
sudo dpkg -i ClientL_ALSE/zpki-*.deb ClientL_ALSE/zsdk-*.deb
|
||||
sudo apt-get -f install -y
|
||||
sudo execstack -c /opt/Validata/VDCSP/lib/amd64/libvdcsp.so
|
||||
sudo systemctl enable --now pcscd</pre>
|
||||
<p class="muted">Дистрибутив для Astra Linux SE — <a href="https://fs.moex.com/cdp/po/ClientL_ALSE.zip" target="_blank" rel="noopener">fs.moex.com/cdp/po/ClientL_ALSE.zip</a>. Linux-версия отдельной лицензии не требует.</p>
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -0,0 +1,126 @@
|
||||
{{define "content"}}
|
||||
<p style="margin-bottom:16px"><a href="/admin/help">← все инструкции</a></p>
|
||||
|
||||
<div class="card">
|
||||
<h2>База данных</h2>
|
||||
<p class="muted">PostgreSQL 16 (или PostgreSQL Pro Certified). Хранит сделки, журнал событий, справочники и данные, поступающие из внешних систем через ETL.</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>1. Подключение</h2>
|
||||
<p>DSN указывается в разделе <a href="/admin/setup">Настройка → PostgreSQL</a>. Формат:</p>
|
||||
<pre>postgres://USER:PASSWORD@HOST:PORT/DBNAME?sslmode=disable</pre>
|
||||
<p>Локальный дев-стенд:</p>
|
||||
<pre>postgres://bj:bj_dev@127.0.0.1:5432/bj?sslmode=disable</pre>
|
||||
<p class="muted">При сохранении выполняется <code>pgx.Connect</code> и <code>Ping</code>. Если БД недоступна, форма покажет ошибку.</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>2. Схемы</h2>
|
||||
<table>
|
||||
<thead><tr><th>Схема</th><th>Назначение</th><th>Кто пишет</th><th>Кто читает</th></tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>fansy_staging</code></td>
|
||||
<td>Промежуточные таблицы для ETL Fansy</td>
|
||||
<td>Команда Fansy (роль <code>fansy_etl</code>)</td>
|
||||
<td>Наша процедура перелива в <code>fansy</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>fansy</code></td>
|
||||
<td>Рабочие данные: клиенты, документы, ИИС, депо-счета, портфели, справочники ЦБ и участников</td>
|
||||
<td>Наша процедура перелива (после валидации)</td>
|
||||
<td>Наша система (роль <code>bj_reader</code>): m2m-core при формировании заявок</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>m2m_core</code></td>
|
||||
<td>Сделки M2M, журнал событий FSM</td>
|
||||
<td>bj-server</td>
|
||||
<td>bj-server, admin-ui</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>3. Что подгружается из внешних систем</h2>
|
||||
<p>Команда Fansy через инкрементный <strong>UPSERT в staging-таблицы</strong>:</p>
|
||||
<table>
|
||||
<thead><tr><th>Таблица staging</th><th>SLA свежести</th><th>Что в ней</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>clients</code></td><td>≤ 5 минут</td><td>Анкеты инвесторов (ФИО, дата рождения, ИНН)</td></tr>
|
||||
<tr><td><code>client_documents</code></td><td>≤ 5 минут</td><td>Документы (паспорт, ИНН и др.)</td></tr>
|
||||
<tr><td><code>iia_contracts</code></td><td>≤ 5 минут</td><td>Договоры ИИС (тип T12/T03, номер, дата, ИНН брокера)</td></tr>
|
||||
<tr><td><code>depo_accounts</code></td><td>≤ 5 минут</td><td>Депо-счета и разделы у разных депозитариев</td></tr>
|
||||
<tr><td><code>portfolios</code></td><td>≤ 1 минута</td><td>Остатки ЦБ (целое/дробное количество, статус обособления)</td></tr>
|
||||
<tr><td><code>securities</code> / <code>participants</code></td><td>раз в сутки</td><td>Справочники ЦБ и участников MOST</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="muted" style="margin-top:8px">Полный data-dictionary: <code>docs/fansy-contract/v1/data-dictionary.md</code>. Требования к ETL: <code>docs/fansy-contract/v1/etl-requirements.md</code>.</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>4. Что пишет сама система</h2>
|
||||
<p>Только в схему <code>m2m_core</code>:</p>
|
||||
<ul>
|
||||
<li><code>deals</code> — корневая запись сделки. Уникальность по <code>guid</code> = идемпотентность приёма заявок.</li>
|
||||
<li><code>deal_events</code> — журнал FSM-событий (event sourcing).</li>
|
||||
</ul>
|
||||
<p>Старт сделки происходит при <code>POST /api/v1/back_office/claims/</code>. FSM проходит этапы:</p>
|
||||
<pre>draft → validated → submitted_to_nsd → awaiting_decision →
|
||||
confirmed → awaiting_sub16 → done
|
||||
↘ rejected
|
||||
↘ timed_out
|
||||
↘ manual_approval</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>5. Учётные записи и роли</h2>
|
||||
<table>
|
||||
<thead><tr><th>Роль</th><th>Права</th><th>Создаёт</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>fansy_etl</code></td><td>SELECT/INSERT/UPDATE на <code>fansy_staging.*</code></td><td>миграция <code>000__roles.sql</code></td></tr>
|
||||
<tr><td><code>bj_reader</code></td><td>SELECT на <code>fansy.*</code></td><td>миграция <code>000__roles.sql</code></td></tr>
|
||||
<tr><td><code>bj_migrator</code></td><td>Владелец схем, DDL-права</td><td>миграция <code>000__roles.sql</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="muted">Пароли проставляются администратором БД через <code>ALTER ROLE</code>, в репозиторий не попадают.</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>6. Накатывание миграций</h2>
|
||||
<p>Файлы лежат в <code>migrations/fansy-store/</code> и <code>migrations/m2m-core/</code>. Применить локально:</p>
|
||||
<pre>cd /home/fontvielle/Bridge-and-Join-s
|
||||
for f in migrations/fansy-store/*.sql migrations/m2m-core/*.sql; do
|
||||
podman exec -i bj-postgres psql -U bj -d bj -v ON_ERROR_STOP=1 < "$f"
|
||||
done</pre>
|
||||
<p>Порядок:</p>
|
||||
<ol>
|
||||
<li><code>fansy-store/000__roles.sql</code> — роли</li>
|
||||
<li><code>fansy-store/001__schemas.sql</code> — схемы и гранты</li>
|
||||
<li><code>fansy-store/002__working.sql</code> — рабочая схема</li>
|
||||
<li><code>fansy-store/003__staging.sql</code> — staging</li>
|
||||
<li><code>fansy-store/004__seed_participants.sql</code> — справочник участников (НРД, БКС, Ренессанс, Альфа-Банк)</li>
|
||||
<li><code>m2m-core/001__deals.sql</code> — сделки M2M</li>
|
||||
<li><code>m2m-core/002__stages.sql</code> — jsonb-колонка истории FSM</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>7. Полезные запросы</h2>
|
||||
<pre>-- Состояние сделок за последний час
|
||||
SELECT state, count(*) FROM m2m_core.deals
|
||||
WHERE created_at > now() - interval '1 hour'
|
||||
GROUP BY state;
|
||||
|
||||
-- Журнал событий по сделке
|
||||
SELECT created_at, type, actor, payload
|
||||
FROM m2m_core.deal_events
|
||||
WHERE deal_id = '...'
|
||||
ORDER BY created_at;
|
||||
|
||||
-- Свежесть данных Fansy
|
||||
SELECT 'portfolios' AS t, max(loaded_at) FROM fansy_staging.portfolios
|
||||
UNION ALL SELECT 'clients', max(loaded_at) FROM fansy_staging.clients;</pre>
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -0,0 +1,247 @@
|
||||
{{define "content"}}
|
||||
<div class="doc-header">
|
||||
<h1>bj ↔ bj2depo: трансферные таблицы FTV_M2M и события</h1>
|
||||
<p class="lede">Для разработчика Fancy (сервис bj2depo). Как bj заполняет FTV_M2M / FTV_M2M_LINES, какими идентификаторами располагает, какие события пишет в FTV_M2M_EVENTS и какие ожидает в ответ. <strong>Согласовано 10.09.2026 и реализовано в bj:</strong> события BJ_* пишутся, читаются DEPO_ORDER_CREATED и DEPO_ERROR, справочник участников перезаписывается при каждом получении.</p>
|
||||
</div>
|
||||
|
||||
<div class="doc">
|
||||
<nav class="doc-toc" id="toc">
|
||||
<div class="toc-group">Основа</div>
|
||||
<a href="#roles">Кто что делает</a>
|
||||
<a href="#ids">Идентификаторы у bj</a>
|
||||
<a href="#tables">Таблицы</a>
|
||||
<div class="toc-group">События</div>
|
||||
<a href="#rules">Правила</a>
|
||||
<a href="#bj-events">События от bj</a>
|
||||
<a href="#depo-events">События от bj2depo</a>
|
||||
<a href="#timeline">Порядок по этапам</a>
|
||||
<a href="#actions">Действия джобы по событиям</a>
|
||||
<a href="#handbook">Справочник участников</a>
|
||||
<a href="#runmode">Кто запускает обработку</a>
|
||||
{{if devOn}}<a href="#replay">Выгрузка истории тестов</a>{{end}}
|
||||
<div class="toc-group">Практика</div>
|
||||
<a href="#sql">Примеры SQL</a>
|
||||
<a href="#questions">Открытые вопросы</a>
|
||||
</nav>
|
||||
|
||||
<article class="doc-body">
|
||||
|
||||
<h2 id="roles">Кто что делает</h2>
|
||||
<table>
|
||||
<thead><tr><th style="width:130px">Сервис</th><th>Роль</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><strong>bj</strong> (Bridge-and-Join-s)</td><td>обмен с НРД по MOEX МОСТ (M2MTR / M2MTD / M2MER, депо-поручения 16 и 16/1, отчёты MS010), сверка с DEPO/SPECTRE, блокировка и движение бумаг в QUIK МНП, личный кабинет. Пишет поручения и события в трансферные таблицы, читает события от DEPO.</td></tr>
|
||||
<tr><td><strong>bj2depo</strong> (джоба Fancy)</td><td>читает FTV_M2M / FTV_M2M_LINES → создаёт и меняет сущности DEPO (M2M-поручения D_CLISER_M2M, строки D_CLISER_M2M_DOL); обрабатывает события FTV_M2M_EVENTS от bj; пишет свои события для bj.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="muted">Работаем только с НРД (MOEX МОСТ), СПБ нет. Переводятся только выпуски с ISIN, начинающимся на RU. База — наша копия DEPO на SQL002 (<code>BJ_DEPO_DATA</code>); джобу bj2depo нужно поднять на ней (сейчас она работает на SQL001/UPD_DE_DATA, и записи в нашей базе никто не забирает).</p>
|
||||
|
||||
<h2 id="ids">Какими идентификаторами располагает bj</h2>
|
||||
<table>
|
||||
<thead><tr><th style="width:190px">Сущность</th><th>Что есть у bj</th><th style="width:260px">Что можем передавать в таблицы</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Депонент</td><td>ФИО + серия/номер паспорта из сообщения НРД. bj сам находит лицо в DEPO по паспорту (серия без пробелов, <code>OD_FACES.DOC_SER/DOC_NUM</code>).</td><td><code>DEPONENT_NAME</code>, <code>DEPONENT_DOC</code> и <code>DEPONENT_ID = OD_FACES.SELF_ID</code> (мастер-ID лица; у дублей указывает на основную запись).</td></tr>
|
||||
<tr><td>Контрагент (депозитарий)</td><td>код участника МОСТ (<code>MC…</code>, 12 знаков), депозитарный код НРД (<code>HL…</code>), ИНН, наименование из справочника участников M2M. В <code>OD_FACES</code> депозитариев-контрагентов нет (проверено по ИНН), есть только сам НКО АО НРД (ID 18174).</td><td><code>CONTRAGENT_M2M_CODE</code>; при желании ИНН и наименование — доп. поля.</td></tr>
|
||||
<tr><td>Бумага</td><td>ISIN + код НРД (напр. <code>SBER/03</code>); bj находит <code>OD_VALUES.ID</code> по ISIN (<code>IS_IN=1</code> = принята на обслуживание).</td><td><code>ISIN</code>, <code>SEC_CODE</code> и <code>SHARE = OD_VALUES.ID</code>.</td></tr>
|
||||
<tr><td>Счёт клиента</td><td>bj находит открытый торговый счёт <code>ВТНКЦ…</code> (<code>OD_CLIENTS</code>, <code>STATE=0</code>). При нескольких договорах берётся самый ранний (правило депозитария).</td><td><code>OD_CLIENTS.ID</code> и <code>NUMBER</code>.</td></tr>
|
||||
<tr><td>Счёт депозитария (место хранения)</td><td>наш счёт в НРД <code>HL171004001C</code> + раздел <code>36MC04136…</code>. В DEPO это запись <code>OD_CLIENTS</code> с NUMBER <code>HL171004001C/253400M18U5TB02TW421/253400_X1A47/<раздел></code> (например ID 79 для раздела 36MC0413600000F00). <code>OD_CLIENTS_REC.LINK_NUMBER</code> у нас пустой везде.</td><td><code>PLACE_NUMBER</code> = раздел (или ID записи OD_CLIENTS, если удобнее).</td></tr>
|
||||
<tr><td>Причины отказа</td><td>коды M2M01…M2M10 по каждой бумаге (может быть несколько), при отказе НРД по поручению 16/16-1 — код и текст из MS010.</td><td><code>M2M_REJECT_CODE</code> через <code>;</code>, текст — в <code>PARAMETERS</code>.</td></tr>
|
||||
<tr><td>Ключи</td><td><code>GUID</code> перевода (из M2MTR) и <code>REFERENCE</code> строки (референс бумаги из M2MTR, <code>M2M…</code>).</td><td>как ключи FTV_M2M / FTV_M2M_LINES / FTV_M2M_EVENTS.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="tables">Таблицы (как согласовано, поля, которые заполняет bj)</h2>
|
||||
<table>
|
||||
<thead><tr><th style="width:170px">Таблица</th><th>Поля от bj</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>FTV_M2M</code></td><td><code>GUID</code>, <code>DIRECTION</code> (IN — к нам зачисляют, OUT — мы списываем), <code>CONTRAGENT_M2M_CODE</code>, <code>DEPONENT_NAME</code>, <code>DEPONENT_DOC</code>, <code>DEPONENT_ID</code> (если нашли). Вставка вместе со строками в одной транзакции.</td></tr>
|
||||
<tr><td><code>FTV_M2M_LINES</code></td><td><code>GUID</code>, <code>REFERENCE</code>, <code>ISIN</code>, <code>SEC_CODE</code>, <code>SHARE</code> (если нашли), <code>AMOUNT</code> (штуки, дробные для паёв), <code>PLACE_NUMBER</code>, <code>DEPO_NUMBER</code> — номер торгового счёта клиента <code>ВТНКЦ…</code> (джоба находит по нему <code>DEPO</code>).</td></tr>
|
||||
<tr><td><code>FTV_M2M_EVENTS</code></td><td><code>GUID</code>, <code>REFERENCE</code> (пусто = по поручению целиком), <code>EVENT_TYPE</code>, <code>EVENT_DATE</code> (фактическое время события в bj), <code>M2M_REJECT_CODE</code>, <code>PARAMETERS</code> (параметры события, см. таблицу событий).</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><strong><code>COMMENT</code> и <code>STATE</code> во всех таблицах заполняет только bj2depo</strong> (17.09.2026): bj их не пишет, <code>STATE</code> при вставке получает значение по умолчанию <code>TODO</code>. Номер документа DEPO bj2depo ставит в <code>FTV_M2M.DOC</code> (строки — <code>DOL</code>).</p>
|
||||
<p class="muted">Поручение создаётся в DEPO на самом раннем этапе: сразу после записи в FTV_M2M (для входящих — как только пришёл M2MTR; для исходящих — как только наш M2MTR ушёл в НРД).</p>
|
||||
|
||||
<h2 id="rules">Правила для событий</h2>
|
||||
<ul>
|
||||
<li><strong>Одно событие — одна строка.</strong> Ключ идемпотентности: <code>GUID + REFERENCE + EVENT_TYPE</code>; повтор не пишется.</li>
|
||||
<li><strong>Мастер — bj</strong> (17.09.2026): события пишет только bj (<code>BJ_*</code>); bj2depo событий не пишет, результат обработки отражает в <code>STATE</code> (<code>SUCCESS</code> / <code>ERROR</code>), <code>COMMENT</code>, <code>TimeBeg/TimeEnd</code> события и в <code>FTV_M2M.DOC</code>.</li>
|
||||
<li><strong><code>STATE</code> и <code>COMMENT</code> пишет только bj2depo</strong>; bj при вставке их не заполняет.</li>
|
||||
<li><strong>Параметры события</strong> — в <code>PARAMETERS</code>: номер депо-поручения НРД (CONTR_D_ID), номер поручения МНП, текст причины отказа.</li>
|
||||
<li><strong><code>EVENT_DATE</code></strong> — фактическое время события в bj (МСК), не время вставки.</li>
|
||||
<li><strong>Порядок:</strong> события одного GUID обрабатываются по <code>ID</code>. Событие по строке (<code>REFERENCE</code> задан) относится к одной бумаге; без <code>REFERENCE</code> — ко всему поручению.</li>
|
||||
<li><strong>Коды отказа</strong> в <code>M2M_REJECT_CODE</code> через <code>;</code>, как их даёт НРД (M2M01…M2M10); человекочитаемый текст — в <code>PARAMETERS</code>.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="bj-events">События от bj (обрабатывает bj2depo)</h2>
|
||||
<table>
|
||||
<thead><tr><th style="width:230px">EVENT_TYPE</th><th>Когда bj пишет</th><th>Уровень</th><th>Что ожидаем от bj2depo</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>BJ_RECEIVED</code></td><td>пришёл входящий M2MTR от другого депозитария (мы зачисляем); одновременно вставлены FTV_M2M + LINES</td><td>поручение</td><td>создать M2M-поручение в DEPO, вернуть <code>DEPO_ORDER_CREATED</code></td></tr>
|
||||
<tr><td><code>BJ_SENT</code></td><td>наш исходящий M2MTR ушёл в НРД (мы списываем)</td><td>поручение</td><td>то же для списания</td></tr>
|
||||
<tr><td><code>BJ_DECISION_CONFIRM</code> / <code>BJ_DECISION_REJECT</code></td><td>мы ответили контрагенту по бумаге (M2MTD); при отказе — коды</td><td>строка</td><td>проставить статус строки: принято / отказано с кодами</td></tr>
|
||||
<tr><td><code>BJ_CP_CONFIRM</code> / <code>BJ_CP_REJECT</code></td><td>контрагент ответил по нашему исходящему (M2MTD)</td><td>строка</td><td>то же для списания</td></tr>
|
||||
<tr><td><code>BJ_SERVICE_ERROR</code></td><td>сервис МОСТ отверг перевод (M2MER ERROR), код M2Mxx</td><td>поручение</td><td>закрыть поручение как отклонённое</td></tr>
|
||||
<tr><td><code>BJ_ORDER_SENT</code></td><td>подано депо-поручение 16 (списание) или 16/1 (зачисление) в НРД; в PARAMETERS — CONTR_D_ID (несколько — через <code>;</code>)</td><td>поручение</td><td>привязать номер поручения НРД</td></tr>
|
||||
<tr><td><code>BJ_ORDER_ACCEPTED</code> / <code>BJ_ORDER_REJECTED</code></td><td>НРД принял (отчёт MS010) или отверг наше депо-поручение; при отказе — код и текст</td><td>поручение</td><td>проставить результат; при принятии — провести движение по счёту, если DEPO делает это по нашему сигналу (см. вопросы)</td></tr>
|
||||
<tr><td><code>BJ_ORDER_LATE</code></td><td>MS010 не получен за 5 минут после подачи (регламент)</td><td>поручение</td><td>для информации / контроля</td></tr>
|
||||
<tr><td><code>BJ_EXECUTED</code></td><td>перевод исполнен (по отчёту НРД)</td><td>поручение</td><td>закрыть как исполненное</td></tr>
|
||||
<tr><td><code>BJ_CANCELLED</code></td><td>перевод отозван / аннулирован / истёк срок 30 дней без исполнения</td><td>поручение</td><td>закрыть как отменённое</td></tr>
|
||||
<tr><td><code>BJ_GATEWAY_REJECT</code></td><td>шлюз bj отказал в исходящем переводе из ЛК до отправки в НРД (сверка: лицо, счёт, бумага, остаток, место хранения, блокировки; либо данные заявки некорректны). Код в M2M_REJECT_CODE (M2Mxx или QTY/PLACE/QUIK), причина в PARAMETERS; одновременно вставлены FTV_M2M (OUT) + LINES</td><td>строка</td><td>закрыть строку и документ как отклонённые (см. «Действия джобы»); <strong>пометить событие SUCCESS или ERROR</strong> — только после этого bj ставит заявке в ЛК «Отклонена»</td></tr>
|
||||
<tr><td><code>BJ_PING</code></td><td>проверка готовности обработчика из настроек bj (GUID случайный, без шапки в FTV_M2M)</td><td>служебное</td><td><strong>ничего не делать, только пометить SUCCESS</strong> — bj ждёт отметку до 40 с и удаляет строку</td></tr>
|
||||
<tr><td><code>BJ_QUIK_BLOCKED</code> / <code>BJ_QUIK_RELEASED</code> / <code>BJ_QUIK_SIGNED</code> / <code>BJ_QUIK_DEPOSITED</code></td><td>блокировка / снятие / списание / зачисление в QUIK МНП; номер поручения МНП в PARAMETERS</td><td>строка</td><td>только для сверки QUIK ↔ DEPO, в DEPO ничего не менять</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="depo-events">События от bj2depo</h2>
|
||||
<p><strong>Не используются</strong> (17.09.2026, программист Fancy: «мастером является bj»). Прежние <code>DEPO_ORDER_CREATED</code> / <code>DEPO_ERROR</code> отменены. bj узнаёт результат так:</p>
|
||||
<ul>
|
||||
<li>документ DEPO создан — номер в <code>FTV_M2M.DOC</code>, строки — <code>FTV_M2M_LINES.DOL</code>; состояние документа bj читает в <code>OD_DOCS.STATE</code>;</li>
|
||||
<li>событие обработано — <code>STATE = SUCCESS</code> / <code>ERROR</code> и <code>COMMENT</code> у самого события <code>BJ_*</code>; по <code>ERROR</code> оператор bj получает оповещение.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="timeline">Порядок событий по этапам</h2>
|
||||
<table>
|
||||
<thead><tr><th style="width:280px">Входящий перевод (мы зачисляем)</th><th>Исходящий перевод (мы списываем)</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>1. bj: FTV_M2M + LINES, <code>BJ_RECEIVED</code></td><td>1. bj: QUIK блокирует бумаги (<code>BJ_QUIK_BLOCKED</code>), M2MTR в НРД, FTV_M2M + LINES, <code>BJ_SENT</code></td></tr>
|
||||
<tr><td>2. bj2depo: документ DEPO (<code>FTV_M2M.DOC</code>); bj сверяет строки с DEPO</td><td>2. bj2depo: документ DEPO (<code>FTV_M2M.DOC</code>)</td></tr>
|
||||
<tr><td>3. bj: ответ контрагенту — <code>BJ_DECISION_CONFIRM</code> / <code>BJ_DECISION_REJECT</code></td><td>3. bj: ответ контрагента — <code>BJ_CP_CONFIRM</code> / <code>BJ_CP_REJECT</code> (при отказе QUIK снимает блокировку: <code>BJ_QUIK_RELEASED</code>)</td></tr>
|
||||
<tr><td>4. bj: подача 16/1 — <code>BJ_ORDER_SENT</code></td><td>4. bj: подача 16 — <code>BJ_ORDER_SENT</code></td></tr>
|
||||
<tr><td>5. bj: <code>BJ_ORDER_ACCEPTED</code> (MS010) или <code>BJ_ORDER_REJECTED</code>; QUIK зачисляет — <code>BJ_QUIK_DEPOSITED</code></td><td>5. bj: <code>BJ_ORDER_ACCEPTED</code> / <code>BJ_ORDER_REJECTED</code>; QUIK списывает — <code>BJ_QUIK_SIGNED</code></td></tr>
|
||||
<tr><td>6. bj2depo: по <code>BJ_ORDER_ACCEPTED</code> / <code>BJ_EXECUTED</code> — <code>FTV_M2M_PROCESS_WIRING</code>, документ «Обработано (ожидание формирования отчёта)»; 7. «Формирование отчёта» — сотрудник депозитария (по рассылке) или автомат документооборота</td><td>6–7. то же для списания</td></tr>
|
||||
<tr><td colspan="2">Отклонения: <code>BJ_GATEWAY_REJECT</code> (шлюз bj отказал до отправки в НРД; статус в ЛК — после обработки джобой), <code>BJ_SERVICE_ERROR</code>, <code>BJ_ORDER_LATE</code> (5 мин без MS010), <code>BJ_CANCELLED</code> (30 дней без исполнения), <code>DEPO_ERROR</code>.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<h2 id="actions">Действия джобы по событиям: что делать с документом DEPO</h2>
|
||||
<p>Сейчас джоба создаёт документ по шапке и помечает события обработанными, но документ и его строки не меняются: после отказа документ остаётся в состоянии «Начальный ввод» и его приходится отменять руками, а после приёма остаток на счёте появляется, но документ в конечное состояние не переходит (проверено 14.09.2026 на документах 75070271 и 75070273). Ниже — что джобе нужно делать по каждому событию. Документ всегда находится по <code>GUID</code>, строка — по <code>GUID + REFERENCE</code>; событие без <code>REFERENCE</code> относится ко всему документу.</p>
|
||||
<table>
|
||||
<thead><tr><th style="width:230px">Событие</th><th style="width:70px">Уровень</th><th>Что сделать в DEPO</th><th style="width:230px">Конечное состояние</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>BJ_RECEIVED</code>, <code>BJ_SENT</code></td><td>документ</td><td>документ уже создан по шапке; ничего не делать, пометить SUCCESS</td><td>«Начальный ввод» (0) → можно «Начало обработки» (1)</td></tr>
|
||||
<tr><td><code>BJ_DECISION_REJECT</code> (входящий: мы отказали), <code>BJ_CP_REJECT</code> (исходящий: отказал контрагент)</td><td>строка</td><td>в <code>D_CLISER_M2M_DOL</code> строки записать код из <code>M2M_REJECT_CODE</code> в <code>M2M_STATUS</code>/<code>M2M_TEXT</code> (текст из PARAMETERS). Если отказаны все строки документа — выполнить шаг «Отмена» (тип шага 0→REJ), как это делает оператор вручную</td><td>строка «отказ, M2Mxx»; документ «Отмена обработки» (3)</td></tr>
|
||||
<tr><td><code>BJ_DECISION_CONFIRM</code>, <code>BJ_CP_CONFIRM</code></td><td>строка</td><td>отметить строку как принятую (<code>M2M_STATUS</code> «принято»); движения по счёту пока нет — ждём поручение НРД</td><td>строка «принято»; документ «Начало обработки» (1)</td></tr>
|
||||
<tr><td><code>BJ_ORDER_SENT</code></td><td>документ</td><td>записать номер депо-поручения НРД (CONTR_D_ID из PARAMETERS); состояние — ожидание</td><td>«Ожидание доставки (ответа)» (10) или «Ожидание исполнения операции» (127)</td></tr>
|
||||
<tr><td><code>BJ_ORDER_ACCEPTED</code> + <code>BJ_EXECUTED</code></td><td>документ</td><td><strong>реализовано 17.09.2026:</strong> bj2depo вызывает <code>[dbo].[FTV_M2M_PROCESS_WIRING] @OPER_ID</code> (ID документа) — директива «Обработать» для списания / зачисления; bj процедуру не вызывает. Дальше директива «Формирование отчёта»: сотрудники депозитария по почтовой рассылке или автомат документооборота (нужна лицензия) — средствами SQL отчёт не формируется</td><td>«Обработано (ожидание формирования отчёта)» → после отчёта — конечное</td></tr>
|
||||
<tr><td><code>BJ_GATEWAY_REJECT</code></td><td>строка</td><td>в <code>D_CLISER_M2M_DOL</code> строки записать код из <code>M2M_REJECT_CODE</code> и причину из PARAMETERS; если отказаны все строки — шаг «Отмена». Документ мог не создаться (например, бумаги с таким ISIN нет в OD_VALUES) — тогда достаточно пометить событие ERROR с текстом причины</td><td>строка «отказ шлюза»; документ «Отмена обработки» (3)</td></tr>
|
||||
<tr><td><code>BJ_ORDER_REJECTED</code>, <code>BJ_SERVICE_ERROR</code>, <code>BJ_CANCELLED</code></td><td>документ</td><td>записать причину (PARAMETERS / код) в документ, выполнить шаг «Отмена»</td><td>«Отмена обработки» (3)</td></tr>
|
||||
<tr><td><code>BJ_ORDER_LATE</code></td><td>документ</td><td>только пометка/комментарий («отчёт НРД не получен за 5 минут»); состояние не менять</td><td>без изменений</td></tr>
|
||||
<tr><td><code>BJ_QUIK_*</code>, <code>BJ_PING</code></td><td>служебные</td><td>ничего не делать, пометить SUCCESS</td><td>без изменений</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="muted">Названия и коды состояний — из справочника <code>OD_DOC_STATES</code> (D_CAT=0): 0 «Начальный ввод», 1 «Начало обработки (зарегистрирован)», 2 «Конец обработки (в архиве)», 3 «Отмена обработки», 10 «Ожидание доставки (ответа)», 127 «Ожидание исполнения операции». Шаг отмены, который выполнял оператор: <code>OD_STEP_TYPES</code> ID 75069472 «Отмена» (SYS_NAME <code>0->REJ</code>, OUT_STATE 3).</p>
|
||||
<p>Запрос, которым джоба находит отказы вместе с документом и строкой:</p>
|
||||
<pre class="copyable">SELECT e.ID, e.GUID, e.REFERENCE, e.M2M_REJECT_CODE, e.PARAMETERS, m.DOC, l.DOL
|
||||
FROM dbo.FTV_M2M_EVENTS e
|
||||
JOIN dbo.FTV_M2M m ON m.GUID = e.GUID
|
||||
JOIN dbo.FTV_M2M_LINES l ON l.GUID = e.GUID AND l.REFERENCE = e.REFERENCE
|
||||
WHERE e.STATE = 'TODO' AND e.EVENT_TYPE IN ('BJ_DECISION_REJECT', 'BJ_CP_REJECT')
|
||||
ORDER BY e.ID;</pre>
|
||||
<p>Для событий по документу целиком (REFERENCE пуст) джойн со строками не нужен:</p>
|
||||
<pre class="copyable">SELECT e.ID, e.GUID, e.EVENT_TYPE, e.M2M_REJECT_CODE, e.PARAMETERS, m.DOC
|
||||
FROM dbo.FTV_M2M_EVENTS e
|
||||
JOIN dbo.FTV_M2M m ON m.GUID = e.GUID
|
||||
WHERE e.STATE = 'TODO' AND e.REFERENCE IS NULL
|
||||
ORDER BY e.ID;</pre>
|
||||
<p><strong>Обратная связь в bj.</strong> bj сам читает состояние документа по номеру (<code>OD_DOCS.STATE</code> по <code>FTV_M2M.DOC</code>) и показывает его в карточке перевода; при ручной отмене в DEPO оператор bj получает оповещение. Поэтому отдельные события от джобы о смене состояния не требуются — достаточно, чтобы документ переходил в состояния из таблицы выше.</p>
|
||||
|
||||
<h2 id="handbook">Справочник участников M2M (M2MTH) → таблица FTV_M2M_HANDBOOK</h2>
|
||||
<p>НРД ведёт справочник участников переводов по MOEX МОСТ: кто депозитарий, кто брокер, их коды участника и ИНН, плюс места расчётов. bj получает его от НРД (сообщение M2MTransferHandbook) при старте и обновляет раз в сутки; по нему bj определяет контрагента по ИНН из перевода и наполняет справочник депозитариев в QUIK МНП. Предлагаем отдавать его в DEPO целиком в отдельную таблицу — тогда <code>CONTRAGENT_M2M_CODE</code> из FTV_M2M раскрывается в ИНН и наименование, и по нему можно заводить контрагентов в DEPO.</p>
|
||||
<p class="muted">Сейчас в справочнике 158 участников и 2 мест расчётов (получено 2026-09-09).</p>
|
||||
<table>
|
||||
<thead><tr><th style="width:190px">Поле таблицы</th><th style="width:130px">Тип</th><th>Откуда у bj / что означает</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>INN</code></td><td>varchar(12)</td><td>ИНН организации. Вместе с <code>PARTICIPANT_CODE</code> и <code>KIND</code> — ключ строки.</td></tr>
|
||||
<tr><td><code>PARTICIPANT_CODE</code></td><td>varchar(12)</td><td>код участника МОСТ (<code>MC…</code>, 12 знаков) — тот самый <code>CONTRAGENT_M2M_CODE</code>. У мест расчётов пусто.</td></tr>
|
||||
<tr><td><code>KIND</code></td><td>varchar(8)</td><td><code>DEPO</code> — депозитарий, <code>BROKER</code> — брокер (одна организация может быть в обоих качествах — две строки), <code>PLACE</code> — место расчётов.</td></tr>
|
||||
<tr><td><code>NAME_FULL</code></td><td>nvarchar(255)</td><td>полное наименование (рус.)</td></tr>
|
||||
<tr><td><code>NAME_SHORT</code></td><td>nvarchar(128)</td><td>краткое наименование (рус.)</td></tr>
|
||||
<tr><td><code>NAME_DISPLAY</code></td><td>nvarchar(255)</td><td>отображаемое наименование (рус.) — то, что показываем в интерфейсах</td></tr>
|
||||
<tr><td><code>NAME_ENG</code></td><td>nvarchar(255)</td><td>наименование на английском (есть не у всех)</td></tr>
|
||||
<tr><td><code>HANDBOOK_AT</code></td><td>datetime</td><td>дата/время версии справочника НРД (CreationTimestamp)</td></tr>
|
||||
<tr><td><code>UPDATED_AT</code></td><td>datetime</td><td>когда bj записал строку</td></tr>
|
||||
<tr><td><code>ACTIVE</code></td><td>bit</td><td>всегда 1 (история не ведётся, таблица перезаписывается целиком)</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><strong>Обновление (согласовано).</strong> История не нужна: при каждом получении справочника от НРД bj удаляет все строки и записывает содержимое заново одной транзакцией (DEPO не видит пустую таблицу; DELETE вместо TRUNCATE, потому что TRUNCATE требует права ALTER) — аналог нового HANDBOOK.xml. Дополнительно перезапись повторяется при старте bj и раз в 6 часов. <strong>Просьба создать таблицу по скрипту ниже</strong> (создаёт наша сторона: у логина bj нет права CREATE TABLE в BJ_DEPO_DATA). Поля — как в описании; bj2depo использует <code>INN</code>, <code>PARTICIPANT_CODE</code>, <code>NAME_SHORT</code>. Английские наименования и места расчётов bj пишет, джоба их не использует.</p>
|
||||
<p>Примеры реальных строк:</p>
|
||||
<table><thead><tr><th>INN</th><th>PARTICIPANT_CODE</th><th>KIND</th><th>NAME_DISPLAY</th></tr></thead><tbody><tr><td><code>7707025725</code></td><td><code>MC0005600000</code></td><td>DEPO</td><td>АО АКБ "ЦентроКредит"</td></tr><tr><td><code>9714012520</code></td><td><code>MC0418000000</code></td><td>DEPO</td><td>ИК ФИАНИТ</td></tr><tr><td><code>7831000034</code></td><td>—</td><td>PLACE</td><td>АО "СПБ Банк"</td></tr>
|
||||
</tbody></table>
|
||||
<p class="muted">Как это связано с остальным: в FTV_M2M поле <code>CONTRAGENT_M2M_CODE</code> = <code>PARTICIPANT_CODE</code> строки с <code>KIND=DEPO</code>; ИНН отправителя/получателя в сообщениях НРД (<code>TransferringDepository/ReceivingDepository INN</code>) = <code>INN</code>. Тот же справочник bj загружает в QUIK МНП (таблица <code>M2MDepoRecipients</code>: ИНН + наименование).</p>
|
||||
|
||||
<h2 id="runmode">Кто запускает обработку: джоба SQL Agent или bj</h2>
|
||||
<p>Обработка трансферных таблиц — это вызов процедуры <code>FTV_M2M_JOB</code> в базе DEPO. Есть два равноценных способа её запускать:</p>
|
||||
<table>
|
||||
<thead><tr><th style="width:230px">Способ</th><th>Что нужно на сервере клиента</th><th>Плюсы / минусы</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><strong>A. Джоба SQL Agent</strong> <code>bj2depo</code> (как сейчас у нас: шаг <code>exec FTV_M2M_JOB</code>, каждые 10 с)</td><td>SQL Agent запущен; права на создание джобы (SQLAgentOperatorRole / sysadmin); учётка Agent с правами на BJ_DEPO_DATA</td><td>работает независимо от bj; но у каждого клиента нужно заводить джобу и права, а bj не видит её состояние без доступа к msdb</td></tr>
|
||||
<tr><td><strong>B. bj вызывает процедуру сам</strong> (Настройка → Обмен Fancy → «Обработка трансферных таблиц DEPO»)</td><td>только <code>GRANT EXECUTE ON dbo.FTV_M2M_JOB TO <логин bj></code></td><td>одна настройка на все внедрения, состояние и ошибки видны в bj; обработка идёт, только пока работает bj</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="muted">Включать нужно один вариант, иначе процедура будет вызываться параллельно из двух мест. Просьба к разработчику: сделать <code>FTV_M2M_JOB</code> безопасной при повторном/параллельном вызове (обработка только строк со <code>STATE='TODO'</code>, блокировка строки на время обработки) — тогда случайное двойное включение не навредит.</p>
|
||||
|
||||
|
||||
{{if devOn}}{{/* отчёт о выгрузке истории тестирования — только в режиме разработки */}}
|
||||
<h2 id="replay">Результат выгрузки истории тестов (14.09.2026)</h2>
|
||||
<p>Кнопкой «Выгрузить историю в DEPO» на вкладке «Тестирование» bj записал в трансферные таблицы все переводы, проведённые на TEST3 (робот НРД и банк Зенит): 78 переводов, 252 события с реальными датами. Джоба bj2depo создала по каждому документ в DEPO (D_CLISER_M2M + строки), сама определила контрагента, депонента, бумагу и место хранения. Что при этом выяснилось:</p>
|
||||
<ul>
|
||||
<li><strong>События по строкам</strong> (<code>BJ_DECISION_*</code>, <code>BJ_CP_*</code>, с REFERENCE) джоба обрабатывает — SUCCESS.</li>
|
||||
<li><strong>События по поручению целиком</strong> (REFERENCE пуст: <code>BJ_SENT</code>, <code>BJ_RECEIVED</code>, <code>BJ_SERVICE_ERROR</code>, <code>BJ_ORDER_SENT</code>, <code>BJ_ORDER_ACCEPTED</code>, <code>BJ_EXECUTED</code>) джоба отвергает с текстом «Не найдена строка M2M-поручение по GUID + REFERENCE». <strong>Просьба:</strong> для событий без REFERENCE применять действие к документу (или ко всем его строкам).</li>
|
||||
<li>После обработки событий статусы в DEPO не меняются: у всех документов <code>DOC_STATUS=0</code>, у строк <code>M2M_STATUS=0</code>, <code>DEP_STATUS=0</code>. <strong>Просьба согласовать отображение</strong>, например: <code>BJ_CP_REJECT</code> / <code>BJ_DECISION_REJECT</code> → строка «отказ» с кодом в M2M_TEXT; <code>BJ_CP_CONFIRM</code> / <code>BJ_DECISION_CONFIRM</code> → «принято»; <code>BJ_ORDER_ACCEPTED</code> / <code>BJ_EXECUTED</code> → документ «исполнен»; <code>BJ_SERVICE_ERROR</code> / <code>BJ_CANCELLED</code> → документ «отклонён / отменён». Тогда историю тестов можно будет просмотреть в DEPO с настоящими статусами.</li>
|
||||
<li>Событие <code>BJ_PING</code> сейчас помечается ERROR — достаточно помечать SUCCESS без действий.</li>
|
||||
</ul>
|
||||
{{end}}
|
||||
|
||||
<h2 id="sql">Примеры SQL</h2>
|
||||
<p>Так bj заведёт входящий перевод (одна транзакция):</p>
|
||||
<pre class="copyable">BEGIN TRAN;
|
||||
INSERT INTO dbo.FTV_M2M (GUID, DIRECTION, CONTRAGENT_M2M_CODE, DEPONENT_NAME, DEPONENT_DOC)
|
||||
VALUES ('5325B860-3265-49B6-986D-FA84FB41FE27', 'IN', 'MC0034900000', N'Иванов Иван Иванович', '0000 000000');
|
||||
INSERT INTO dbo.FTV_M2M_LINES (GUID, REFERENCE, ISIN, SEC_CODE, SHARE, AMOUNT, PLACE_NUMBER, DEPO_NUMBER)
|
||||
VALUES ('5325B860-3265-49B6-986D-FA84FB41FE27', 'M2M0000002675550', 'RU000A107UL4', 'RU000A107UL4', 18824, 1, '36MC0000000000F00', N'ВТНКЦ00000001');
|
||||
INSERT INTO dbo.FTV_M2M_EVENTS (GUID, REFERENCE, EVENT_TYPE, EVENT_DATE)
|
||||
VALUES ('5325B860-3265-49B6-986D-FA84FB41FE27', NULL, 'BJ_RECEIVED', '2026-09-17T09:21:26.000'); -- время получения M2MTR в bj
|
||||
COMMIT;
|
||||
-- параметры события — в PARAMETERS, например подача поручения 16/1:
|
||||
INSERT INTO dbo.FTV_M2M_EVENTS (GUID, REFERENCE, EVENT_TYPE, EVENT_DATE, PARAMETERS)
|
||||
VALUES ('5325B860-3265-49B6-986D-FA84FB41FE27', NULL, 'BJ_ORDER_SENT', '2026-09-17T09:22:24.000', N'20608');</pre>
|
||||
<p>Так bj читает результат обработки (событий от bj2depo нет):</p>
|
||||
<pre class="copyable">SELECT CAST(GUID AS varchar(36)) GUID, STATE, COMMENT, DOC FROM dbo.FTV_M2M WHERE GUID = @guid;
|
||||
SELECT ID, EVENT_TYPE, REFERENCE, STATE, COMMENT, TimeBeg, TimeEnd FROM dbo.FTV_M2M_EVENTS WHERE GUID = @guid ORDER BY ID;</pre>
|
||||
|
||||
<p>Структура таблицы справочника и то, как bj её перезаписывает:</p>
|
||||
<pre class="copyable">CREATE TABLE dbo.FTV_M2M_HANDBOOK (
|
||||
ID int IDENTITY(1,1) PRIMARY KEY, INN varchar(12) NOT NULL, PARTICIPANT_CODE varchar(12) NULL, KIND varchar(8) NOT NULL,
|
||||
NAME_FULL nvarchar(255) NULL, NAME_SHORT nvarchar(128) NULL, NAME_DISPLAY nvarchar(255) NULL, NAME_ENG nvarchar(255) NULL,
|
||||
HANDBOOK_AT datetime NULL, UPDATED_AT datetime NOT NULL DEFAULT GETDATE(), ACTIVE bit NOT NULL DEFAULT 1);
|
||||
-- при каждом получении справочника от НРД (одна транзакция):
|
||||
BEGIN TRAN;
|
||||
DELETE FROM dbo.FTV_M2M_HANDBOOK;
|
||||
INSERT INTO dbo.FTV_M2M_HANDBOOK (INN, PARTICIPANT_CODE, KIND, NAME_FULL, NAME_SHORT, NAME_DISPLAY, NAME_ENG, HANDBOOK_AT, UPDATED_AT, ACTIVE)
|
||||
VALUES ('7707025725', 'MC0005600000', 'DEPO', N'…', N'АО АКБ "ЦентроКредит"', N'…', N'…', @hb_at, GETDATE(), 1); -- и так по всем участникам
|
||||
COMMIT;</pre>
|
||||
|
||||
<h2 id="questions">Открытые вопросы</h2>
|
||||
<p class="muted">Закрыто 17.09.2026 (ответ программиста Fancy):</p>
|
||||
<ul>
|
||||
<li>таблица <code>FTV_M2M_HANDBOOK</code> создана и заполняется bj; обработка справочника джобой — на последнем этапе проекта (директива вендора переносится с Fancy-скриптов на SQL);</li>
|
||||
<li><code>BJ_ORDER_ACCEPTED</code> / <code>BJ_EXECUTED</code> — процедура <code>FTV_M2M_PROCESS_WIRING</code> (вызывает bj2depo), документ «Обработано (ожидание формирования отчёта)»;</li>
|
||||
<li><code>COMMENT</code> и <code>STATE</code> заполняет только bj2depo; параметры — в <code>PARAMETERS</code>; <code>EVENT_DATE</code> — фактическое время события (в bj сделано 17.09);</li>
|
||||
<li>событий от bj2depo нет, мастер — bj (<code>DEPO_ORDER_CREATED</code> / <code>DEPO_ERROR</code> отменены);</li>
|
||||
<li>счёт клиента — <code>FTV_M2M_LINES.DEPO_NUMBER</code> (bj пишет номер ВТНКЦ… с 16.09).</li>
|
||||
</ul>
|
||||
<p class="muted">Закрыто 15.09.2026: <code>REFERENCE</code> для всех исходящих присваивает bj (<code>M2M…</code>); джоба <code>bj2depo</code> на SQL002 / <code>BJ_DEPO_DATA</code> работает; <code>BJ_QUIK_*</code> — для истории, без действий.</p>
|
||||
<p>Остаётся:</p>
|
||||
<ol>
|
||||
<li><strong>События без <code>REFERENCE</code></strong> (по документу целиком: <code>BJ_RECEIVED</code>, <code>BJ_SENT</code>, <code>BJ_ORDER_SENT</code>, <code>BJ_ORDER_ACCEPTED</code>, <code>BJ_EXECUTED</code>, <code>BJ_QUIK_*</code>) джоба помечает ERROR «Не найдена строка M2M-поручение по GUID + REFERENCE // FTV_M2M_PROCESS_EVENTS // 69» — на 17.09 (перевод D744A410) так же. Для них строку искать не нужно: документ — по <code>GUID</code>.</li>
|
||||
<li>Запись отказов в строки и шаг «Отмена» — в работе у программиста.</li>
|
||||
<li>Создание документа «Списание / Зачисление» — доработка у программиста.</li>
|
||||
<li>«Формирование отчёта» после «Обработано»: вручную по рассылке или лицензия на автомат документооборота — решение депозитария.</li>
|
||||
<li>Место хранения: <code>PLACE</code> по <code>PLACE_NUMBER</code> = <code>36MC0413600000F00</code> не проставляется; в DEPO запись называется <code>HL171004001C/…/36MC0413600000F00</code> — в каком виде передавать?</li>
|
||||
</ol>
|
||||
</article>
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -0,0 +1,163 @@
|
||||
{{define "content"}}
|
||||
<div class="doc-header">
|
||||
<h1>QUIK МНП: подготовка к переводам M2M</h1>
|
||||
<p class="lede">Инструкция для администратора сервера QUIK. Что открыть в QUIK Administrator, что создать и включить, какие права выдать, чтобы bj мог блокировать, списывать и зачислять бумаги клиентов через Модуль неторговых поручений (МНП) при переводах по MOEX МОСТ. Каждый шаг со ссылкой на раздел и страницу документа ARQA.</p>
|
||||
</div>
|
||||
|
||||
<div class="doc">
|
||||
<nav class="doc-toc" id="toc">
|
||||
<div class="toc-group">Зачем</div>
|
||||
<a href="#why">Как это работает</a>
|
||||
<div class="toc-group">Чек-лист</div>
|
||||
<a href="#s1">1. Классы на сервере QUIK</a>
|
||||
<a href="#s2">2. Классы в плагине МНП</a>
|
||||
<a href="#s3">3. Инструменты МНП</a>
|
||||
<a href="#s4">4. Типы поручений</a>
|
||||
<a href="#s5">5. Технологический пользователь</a>
|
||||
<a href="#s6">6. Права клиентов и менеджеров</a>
|
||||
<a href="#s7">7. Перезапуск модуля</a>
|
||||
<a href="#s8">8. База данных МНП</a>
|
||||
<div class="toc-group">Контроль</div>
|
||||
<a href="#bj">Что bj делает сам</a>
|
||||
<a href="#verify">Как проверить</a>
|
||||
<a href="#errors">Типичные ошибки</a>
|
||||
<a href="#report">Что сообщить нам</a>
|
||||
<div class="toc-group">Документы</div>
|
||||
<a href="#docs">Скачать документы</a>
|
||||
</nav>
|
||||
|
||||
<article class="doc-body">
|
||||
|
||||
<h2 id="why">Как это работает</h2>
|
||||
<p>bj не подключается к серверу QUIK напрямую. Он работает с <strong>базой данных Модуля неторговых поручений</strong> (МНП): вызывает хранимые процедуры и читает экспортные таблицы. Модуль сам передаёт поручения на сервер QUIK, проверяет позицию клиента, блокирует бумаги, исполняет или снимает поручение. Поэтому всё, что должен сделать администратор, находится в двух местах: <strong>QUIK Administrator</strong> (справочник «Классы», «Пользователи») и <strong>плагин МНП</strong> в нём же (меню «Модули»).</p>
|
||||
<table>
|
||||
<thead><tr><th style="width:190px">Ситуация</th><th>Что делает bj в МНП</th><th style="width:210px">Тип поручения в МНП</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Клиент переводит бумаги <strong>из нас</strong> в другой депозитарий</td><td>регистрирует поручение (QUIK блокирует бумаги) → отправляет перевод в НРД → по успеху подписывает поручение (бумаги списываются), по отказу снимает его с причиной (блокировка снимается, клиент видит причину в терминале)</td><td><strong>Вывод ЦБ (M2M)</strong>, класс <code>INSTROUTM2M</code></td></tr>
|
||||
<tr><td>Бумаги приходят <strong>к нам</strong> из другого депозитария</td><td>после зачисления в НРД регистрирует поручение по ISIN — оно исполняется сразу, бумаги появляются на позиции клиента</td><td><strong>Ввод ЦБ (M2M)</strong>, класс <code>INSTRINM2M</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="muted">Эти два типа появились в МНП версии 21.4.0 и по умолчанию <strong>выключены</strong>, а нужные им классы и инструменты нужно создать вручную. Именно это и описано ниже. Основной документ — «Перевод ЦБ в MOEX МОСТ» (ARQA, v1.1, 2026), далее «МОСТ», страницы указаны по нему.</p>
|
||||
|
||||
<h2 id="s1">Шаг 1. Создать классы на сервере QUIK</h2>
|
||||
<p><em>Где:</em> QUIK Administrator → справочник <strong>«Классы»</strong> (это база самого сервера QUIK, не плагин). <em>Документ:</em> МОСТ п. 4.1, стр. 11.</p>
|
||||
<p>Создайте два класса с параметрами:</p>
|
||||
<table>
|
||||
<thead><tr><th>Параметр</th><th>Класс 1</th><th>Класс 2</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Код</td><td><code>INSTROUTM2M</code></td><td><code>INSTRINM2M</code></td></tr>
|
||||
<tr><td>Наименование (рус)</td><td>Поручения на Вывод ЦБ M2M</td><td>Поручения на Ввод ЦБ M2M</td></tr>
|
||||
<tr><td>Код позиции</td><td><code>|EQTV|</code></td><td><code>|EQTV|</code></td></tr>
|
||||
<tr><td>Тип класса</td><td>Поручения</td><td>Поручения</td></tr>
|
||||
<tr><td>Активные операции</td><td>Включено</td><td>Включено</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="muted">Альтернатива из руководства администратора МНП (шаг 5, стр. 10): применить к базе сервера QUIK (<code>QUIK_DB</code>) скрипт из дистрибутива модуля <code>scripts/mssql/add_classes_instructions_ms.sql</code>. Важно применять его именно к базе сервера QUIK, а не к <code>master</code>.</p>
|
||||
|
||||
<h2 id="s2">Шаг 2. Добавить классы в плагин МНП</h2>
|
||||
<p><em>Где:</em> QUIK Administrator → Модули → МНП → справочник <strong>«Классы инструментов»</strong>. <em>Документ:</em> МОСТ п. 4.1, шаг 2, стр. 11.</p>
|
||||
<p>Добавьте оба класса, созданных на шаге 1, и на каждом выберите фирму, по которой будет меняться позиция клиента, — код участника вашей организации (Фондовый рынок).</p>
|
||||
|
||||
<h2 id="s3">Шаг 3. Создать инструменты МНП</h2>
|
||||
<p><em>Где:</em> QUIK Administrator → Модули → МНП → справочник <strong>«Инструменты»</strong>. <em>Документ:</em> МОСТ п. 4.2, стр. 14.</p>
|
||||
<table>
|
||||
<thead><tr><th>Код инструмента</th><th>Привязать к классу</th><th>Назначение</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>RUROUTM2M</code></td><td><code>INSTROUTM2M</code></td><td>псевдоинструмент поручений на вывод; через него списывается комиссия депозитария</td></tr>
|
||||
<tr><td><code>RURINM2M</code></td><td><code>INSTRINM2M</code></td><td>псевдоинструмент поручений на ввод</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Коды берите <strong>ровно такие</strong>, как в документе: bj передаёт их в вызовах процедур. Если инструменты уже созданы под другими кодами (например, по имени класса), сообщите нам коды — мы подставим их в настройках.</p>
|
||||
<p>Затем на <strong>сервере QUIK</strong> в настройках Библиотеки расчёта лимитов по фирме вашей организации добавьте эти инструменты и привяжите к валюте (рубли) и тегу расчётов, с которого списывается комиссия депозитария: раздел «Инструменты» / «Параметры учёта неторговых поручений» (МОСТ п. 4.2, стр. 14, второй абзац).</p>
|
||||
|
||||
<h2 id="s4">Шаг 4. Включить типы поручений M2M</h2>
|
||||
<p><em>Где:</em> QUIK Administrator → Модули → МНП → справочник <strong>«Типы поручений»</strong>. <em>Документ:</em> МОСТ п. 4.3, стр. 16–22.</p>
|
||||
<ol>
|
||||
<li>Найдите типы <strong>«Ввод ЦБ М2М»</strong> и <strong>«Вывод ЦБ М2М»</strong> (созданы модулем автоматически, ID 101 и 100). Откройте каждый и установите флажок <strong>«Тип поручения доступен»</strong> — по умолчанию он снят.</li>
|
||||
<li>У «Вывод ЦБ М2М» в списке классов, для которых доступен тип, выберите режим <strong>«Только выбранные»</strong> и класс <code>INSTROUTM2M</code>.</li>
|
||||
<li>У «Ввод ЦБ М2М» — то же самое с классом <code>INSTRINM2M</code>.</li>
|
||||
<li>У всех <em>остальных</em> типов на Вывод / Поставку ЦБ переключите классы на «Только выбранные» и убедитесь, что класс <code>INSTROUTM2M</code> у них <strong>выключен</strong>. Иначе по этому классу можно будет зарегистрировать обычное поручение вместо M2M.</li>
|
||||
<li>Подписи: у «Вывод ЦБ М2М» по умолчанию одна подпись — <strong>Депозитарий</strong>. Её ставит bj после ответа НРД. Дополнительные подписи не добавляйте без согласования с нами. У «Ввод ЦБ М2М» подписей нет — поручение исполняется сразу.</li>
|
||||
<li>Поля формы менять не нужно. Если в «Вывод ЦБ М2М» не требуется привязка к номеру договора и проверка ИИС, поля «Договор обслуживания» и «Согласие на закрытие счёта ИИС» можно скрыть (МОСТ, стр. 21).</li>
|
||||
</ol>
|
||||
|
||||
<h2 id="s5">Шаг 5. Права технологического пользователя модуля</h2>
|
||||
<p><em>Где:</em> QUIK Administrator → справочник <strong>«Пользователи»</strong>. <em>Документ:</em> МОСТ п. 5.1, стр. 24; руководство администратора МНП, раздел 2, шаг 6, стр. 10.</p>
|
||||
<p><strong>Кто это.</strong> Служебный пользователь QUIK, от имени которого модуль МНП подключается к серверу QUIK. Его логин записан в файле модуля <code>instructions.ini</code>, секция <code>[QuikApi]</code>, параметр <code>User</code>. У него уже есть права на классы МНП (INSTR и другие); нужно добавить такие же на новые классы.</p>
|
||||
<ol>
|
||||
<li>Выдайте пользователю <strong>полные права</strong> на классы <code>INSTROUTM2M</code> и <code>INSTRINM2M</code>: «Просмотр поручений», «Активные операции», «Создание поручений», «Просмотр поручений по всем брокерам», все флажки «Виды поручений», все флажки «Право подписи».</li>
|
||||
<li>В правах по классу «Поручения» по всем классам МНП установите флажок <strong>«Специальные операции»</strong>.</li>
|
||||
</ol>
|
||||
<p class="muted">Без этих прав модуль не получает новые классы от сервера QUIK и на любое поручение M2M отвечает «Неверный тип поручения», хотя в базе всё включено.</p>
|
||||
|
||||
<h2 id="s6">Шаг 6. Права клиентов и менеджеров</h2>
|
||||
<p><em>Документ:</em> МОСТ п. 5.2–5.3, стр. 25–27. Для работы bj этот шаг не обязателен, но без него клиенты не смогут сами подавать «Вывод ЦБ (M2M)» из терминала и не увидят исполненные вводы.</p>
|
||||
<ul>
|
||||
<li>Клиентам на класс <code>INSTROUTM2M</code>: «Просмотр поручений», «Клиент фирмы», «Активные операции», «Создание поручений», «Вывод бумаг», «Коды клиентов у дилера».</li>
|
||||
<li>Клиентам на класс <code>INSTRINM2M</code> (без «Активных операций»): «Просмотр поручений», «Клиент фирмы», «Ввод бумаг», «Коды клиентов у дилера».</li>
|
||||
<li>Менеджерам (только просмотр): «Просмотр поручений», «Просмотр поручений по всем брокерам», «Ввод бумаг», «Вывод бумаг».</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="s7">Шаг 7. Перезапустить модуль МНП</h2>
|
||||
<p>Типы поручений, классы и права модуль читает <strong>при старте</strong> и при подключении к серверу QUIK. Справочники (клиенты, инструменты, депозитарии) он перечитывает на ходу, а вот настройки шагов 1–5 — нет. После завершения настройки перезапустите службу МНП (обычно это делается ночью по регламенту аутсорсера). Пока модуль не перезапущен, поручения M2M отвергаются с текстом «Неверный тип поручения».</p>
|
||||
|
||||
<h2 id="s8">Шаг 8. База данных МНП</h2>
|
||||
<p>Со стороны базы всё уже настроено, менять ничего не нужно. Для справки:</p>
|
||||
<ul>
|
||||
<li>Логин bj состоит в ролях <code>InstrEuImport</code> (справочники), <code>InstrEuBroker</code> (регистрация, подпись, снятие), <code>InstrEx</code> (экспортные таблицы) — руководство администратора, стр. 13 и 16.</li>
|
||||
<li>Справочник депозитариев M2M (<code>M2MDepoRecipients</code>) и депо-счета клиентов bj заполняет сам процедурами импорта; в QUIK Administrator этот справочник не виден (МОСТ п. 6.1, стр. 29).</li>
|
||||
<li>Справочник инструментов заполняется автоматически с сервера QUIK (опция <code>AutoFillQuikSecurities=1</code> в <code>instructions.ini</code>, руководство администратора, стр. 45) — для этого технологическому пользователю нужно право «Класс доступен» на биржевые классы, например <code>TQBR</code> (МОСТ п. 6.3, стр. 30).</li>
|
||||
<li>По желанию: опция <code>[General].AllowReverseExecutedInstruction=1</code> в <code>instructions.ini</code> разрешает отменять уже исполненные поручения (по умолчанию запрещено, руководство администратора, стр. 48).</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="bj">Что bj делает в МНП автоматически</h2>
|
||||
<p>После настройки цикл включается в bj: <a href="/admin/setup#sec-quik-cycle">Настройка → QUIK МНП → «Автоматический цикл M2M в МНП»</a> (главный предохранитель «Разрешить записи в МНП» и три переключателя). Что происходит при включённых переключателях:</p>
|
||||
<table>
|
||||
<thead><tr><th style="width:230px">Событие в bj</th><th>Действие в МНП</th><th style="width:230px">Что видит клиент в QUIK</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Исходящий перевод отправляется в НРД</td><td>регистрация «Вывод ЦБ (M2M)» <em>до</em> отправки; если QUIK отказал (нет позиции) — перевод в НРД не отправляется</td><td>поручение «Активно», бумаги заблокированы</td></tr>
|
||||
<tr><td>Принимающий депозитарий отказал по бумаге / сервис МОСТ отклонил</td><td>снятие поручения с текстом причины</td><td>поручение «Снято», причина в комментарии, блокировка снята</td></tr>
|
||||
<tr><td>НРД принял наше поручение 16 (отчёт MS010)</td><td>подпись «Депозитарий» → исполнение</td><td>поручение «Исполнено», бумаги списаны</td></tr>
|
||||
<tr><td>НРД принял наше поручение 16/1 по входящему переводу</td><td>регистрация «Ввод ЦБ (M2M)» по ISIN — исполняется сразу</td><td>поручение «Исполнено», бумаги на позиции</td></tr>
|
||||
<tr><td>Клиент сам подал «Вывод ЦБ (M2M)» из QUIK</td><td>bj видит его в экспорте, оповещает оператора; после создания заявки поручение привязывается в карточке, дальше — как обычный исходящий</td><td>своё поручение «Активно», затем исполнено или снято с причиной</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="muted">Код клиента QUIK bj берёт из номера портфеля клиента в DEPO: «БР-001» → «BR001». Исключения задаются в той же форме настроек. Каждый шаг с ответом модуля виден в карточке перевода и на странице <a href="/admin/quik">QUIK МНП</a>; при ошибке приходит оповещение и есть кнопки для ручного повтора.</p>
|
||||
|
||||
<h2 id="verify">Как проверить, что всё готово</h2>
|
||||
<ol>
|
||||
<li>В bj: <a href="/admin/setup#sec-quik">Настройка → QUIK МНП</a> → «Проверить подключение». В отчёте должны быть видны процедуры <code>sp_NewInstrSec</code>, <code>sp_SignInstrSec</code>, <code>cancel_instruction</code> и таблица <code>M2MDepoRecipients</code>.</li>
|
||||
<li>Скажите нам «проверяйте». Мы на согласованном клиенте для проверки регистрируем «Ввод ЦБ (M2M)» на 1 штуку (должно исполниться сразу, позиция +1), затем «Вывод ЦБ (M2M)» на 1 штуку с подписью депозитария (позиция −1). Весь цикл занимает две минуты, клиент видит оба поручения в терминале.</li>
|
||||
<li>Признак готовности в самой базе МНП: у типов 100 и 101 снят признак Disabled, у классов INSTROUTM2M / INSTRINM2M есть фирма, инструменты привязаны к классам. Это мы проверяем сами.</li>
|
||||
</ol>
|
||||
|
||||
<h2 id="errors">Типичные ошибки модуля и что они значат</h2>
|
||||
<table>
|
||||
<thead><tr><th style="width:320px">Ответ модуля</th><th>Причина</th><th>Что сделать</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>Неверный тип поручения.</td><td>Модуль не знает тип «Ввод/Вывод ЦБ М2М» или у технологического пользователя нет прав на класс</td><td>Шаги 1, 5, 7: классы на сервере QUIK, права техпользователя, перезапуск модуля</td></tr>
|
||||
<tr><td>Не найдено описание фирмы.</td><td>Поручение подано типом «Перевод ЦБ», у которого поля «Фирма списания / зачисления» берутся из «Описания» фирмы, а оно пустое</td><td>Для M2M этот тип не используется. Если нужен — заполнить «Описание» в справочнике «Фирмы» плагина МНП</td></tr>
|
||||
<tr><td>Поле 'ISIN' не поддержано для поручений с заполненным биржевым кодом класса.</td><td>В вызове одновременно код класса и ISIN</td><td>Ошибка вызова на нашей стороне, к настройке не относится</td></tr>
|
||||
<tr><td>Указан несуществующий счет ДЕПО поставщика-получателя.</td><td>Обычный (не M2M) тип «Получение ЦБ» требует депо-счёт получателя в формате, который принимает только терминал</td><td>Для зачислений использовать «Ввод ЦБ (M2M)», ему депо-реквизиты не нужны</td></tr>
|
||||
<tr><td>Транзакция проверяется на сервере Quik.</td><td>Не ошибка: промежуточный статус, модуль ждёт ответ сервера QUIK (до минуты)</td><td>Ничего</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2 id="report">Что сообщить нам после настройки</h2>
|
||||
<ul>
|
||||
<li>Что классы созданы на сервере QUIK и в плагине МНП (шаги 1–2).</li>
|
||||
<li>Точные коды инструментов, если они отличаются от <code>RUROUTM2M</code> / <code>RURINM2M</code> (шаг 3).</li>
|
||||
<li>Что типы 100/101 включены и привязаны к классам (шаг 4), права техпользователю выданы (шаг 5).</li>
|
||||
<li>Время перезапуска модуля (шаг 7).</li>
|
||||
<li>Код клиента QUIK, на котором разрешено проводить проверку, и что у него есть хотя бы одна бумага на позиции.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="docs">Документы ARQA</h2>
|
||||
<ul>
|
||||
<li><a href="/admin/docs/Perevod-CB-v-MOEX-MOST.pdf">Перевод ЦБ в MOEX МОСТ</a> — основной документ: п. 4.1 (стр. 11), 4.2 (стр. 14), 4.3 (стр. 16), 5.1–5.3 (стр. 24–27), 6 (стр. 27), 8.6 (стр. 58–63).</li>
|
||||
<li><a href="/admin/docs/MNP-Rukovodstvo-administratora.pdf">МНП — Руководство по администрированию</a> — раздел 2 «Установка и настройка» (технологический пользователь: шаги 5–7, стр. 10–11), справочники плагина (раздел 3), настройки <code>instructions.ini</code> (раздел 4).</li>
|
||||
<li><a href="/admin/docs/MNP-Tablicy-i-procedury-BD.pdf">МНП — Таблицы и процедуры БД</a> — для разработчика: хранимые процедуры (раздел 3), экспортные таблицы (2.50), импорт справочников (3.19).</li>
|
||||
</ul>
|
||||
</article>
|
||||
</div>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user