Files
Bridge-and-Join-s/internal/lkgateway/web/templates/admin_help_fancy_events.html
T
zuevav b4b4788035 Баннер режима разработки в шапке с личным выключателем
Пока лицензия разрешает режим разработки, в шапке висит баннер; нажатие выключает режим визуально для этого пользователя и включает обратно. В шаблонах .DevMode заменён на devOn.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
2026-09-18 11:18:27 +03:00

248 lines
41 KiB
HTML
Raw 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.
{{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/&lt;раздел&gt;</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-&gt;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>АО АКБ &quot;ЦентроКредит&quot;</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>АО &quot;СПБ Банк&quot;</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 &lt;логин bj&gt;</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}}