Раздел «Ручной ввод M2M» по бумажным поручениям; тестовые тексты и имитации убраны из клиентского интерфейса

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
zuevav
2026-09-17 18:26:59 +03:00
parent 627dbca6af
commit e4de1ab4d8
38 changed files with 2014 additions and 132 deletions
@@ -13,7 +13,7 @@
<button data-sec="crypto"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg></span>Криптография<span class="ind {{if .Settings.Crypto.Profile}}ok{{else}}warn{{end}}"></span></button>
<button data-sec="nsd"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M3 21h18M4 21V10M20 21V10M3 10l9-6 9 6M8 21v-7M12 21v-7M16 21v-7"/></svg></span>НРД<span class="ind {{if .Settings.NSD.IGWBaseURL}}ok{{else}}warn{{end}}"></span></button>
<button data-sec="lk"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="5" width="18" height="14" rx="2"/><circle cx="9" cy="11" r="2"/><path d="M6 16c.4-1.4 1.6-2.2 3-2.2s2.6.8 3 2.2"/><path d="M15 10h4M15 13h3"/></svg></span>Личный кабинет <span class="muted" style="font-size:10px;font-weight:500">ЕСИА Финанс</span><span class="ind {{if .Settings.LK.PublicURL}}ok{{else}}warn{{end}}"></span></button>
<button data-sec="tests"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3h6M10 3v6l-5 8.5A2 2 0 0 0 6.7 21h10.6a2 2 0 0 0 1.7-3.5L14 9V3"/><path d="M8 15h8"/></svg></span>Тесты</button>
<button data-sec="tests"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M9 3h6M10 3v6l-5 8.5A2 2 0 0 0 6.7 21h10.6a2 2 0 0 0 1.7-3.5L14 9V3"/><path d="M8 15h8"/></svg></span>Диагностика</button>
<button data-sec="alerts"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.7 21a2 2 0 0 1-3.4 0"/></svg></span>Оповещения<span class="ind {{if or .Settings.Alerts.SMTP.Enabled .Settings.Alerts.Zabbix.Enabled}}ok{{end}}"></span></button>
<button data-sec="update"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20V8M6 12l6-6 6 6"/><path d="M5 4h14"/></svg></span>Обновления{{if .Settings.Update.Available}}<span class="ind warn"></span>{{end}}</button>
<button data-sec="license"><span class="nico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="12" r="4"/><path d="M12 12h9M18 12v3M15 12v2"/></svg></span>Лицензия{{if .License.Present}}<span class="ind {{if .License.Valid}}ok{{else}}err{{end}}"></span>{{end}}</button>
@@ -195,7 +195,7 @@
{{template "verline" (.Versions.Get "quik-mnp")}}
<div class="card">
<h2><span class="dot {{if .Settings.Quik.Verified}}ok{{else if .Settings.Quik.Server}}warn{{else}}err{{end}}"></span>Подключение к БД МНП QUIK (MSSQL)</h2>
<p class="muted">При выводе бумаг клиентом bj блокирует их количество в QUIK через API Модуля неторговых поручений (хранимые процедуры). БД <strong>боевая</strong> — тест только на чтение (версия + наличие M2M-объектов), без записи. Подключение под логином с ролью <code>InstrEu</code>.<br>
<p class="muted">При выводе бумаг клиентом bj блокирует их количество в QUIK через API Модуля неторговых поручений (хранимые процедуры). БД <strong>боевая</strong> — проверка только на чтение (версия + наличие M2M-объектов), без записи. Подключение под логином с ролью <code>InstrEu</code>.<br>
<a href="/admin/help/quik"><strong>Инструкция для администратора QUIK</strong></a> — что настроить в QuikAdmin для M2M · <a href="/admin/docs/">документы ARQA</a>.</p>
<form method="post" action="/admin/setup/quik" style="margin-top:12px;display:grid;gap:10px;max-width:560px">
<label>Сервер (host или host\instance)
@@ -228,7 +228,7 @@
<div class="card" id="sec-quik-cycle">
<h2><span class="dot {{if .Settings.Quik.Emulate}}warn{{else if not .Settings.Quik.WritesEnabled}}warn{{else if or .Settings.Quik.AutoOut .Settings.Quik.AutoIn}}ok{{else}}warn{{end}}"></span>Автоматический цикл M2M в МНП{{if .Settings.Quik.Emulate}} <span class="hero-status warn">{{if .DevMode}}имитация{{else}}остановлен{{end}}</span>{{end}}</h2>
<p class="muted">Что делает bj в Модуле неторговых поручений по ходу перевода: <strong>исходящий</strong> — при отправке в НРД регистрирует «Вывод ЦБ (M2M)» (QUIK блокирует бумаги), по подтверждению подписывает (списание), по отказу снимает с причиной; <strong>входящий</strong> — после приёма нашего поручения НРД регистрирует «Ввод ЦБ (M2M)» (зачисление сразу). Проверено на боевом МНП 09.09.2026. Каждый шаг виден в карточке перевода и на странице <a href="/admin/quik">QUIK МНП</a>.</p>
<p class="muted">Что делает bj в Модуле неторговых поручений по ходу перевода: <strong>исходящий</strong> — при отправке в НРД регистрирует «Вывод ЦБ (M2M)» (QUIK блокирует бумаги), по подтверждению подписывает (списание), по отказу снимает с причиной; <strong>входящий</strong> — после приёма нашего поручения НРД регистрирует «Ввод ЦБ (M2M)» (зачисление сразу). Каждый шаг виден в карточке перевода и на странице <a href="/admin/quik">QUIK МНП</a>.</p>
<form method="post" action="/admin/setup/quik/cycle" style="margin-top:12px;display:grid;gap:10px;max-width:640px">
<input type="hidden" name="section" value="sec-quik-cycle">
<label style="display:flex;gap:8px;align-items:center;font-weight:600">
@@ -262,9 +262,9 @@
{{if .Settings.Quik.LastReport}}
<div class="card">
<h2>Полный ответ сервера (последний тест)</h2>
<h2>Полный ответ сервера (последняя проверка)</h2>
<p class="muted">Можно выделить и скопировать целиком — для отправки коллегам/аутсорсеру QUIK.
{{if not .Settings.Quik.LastAt.IsZero}}Тест от {{.Settings.Quik.LastAt.Format "02.01.2006 15:04:05"}} UTC.{{end}}</p>
{{if not .Settings.Quik.LastAt.IsZero}}Проверка от {{.Settings.Quik.LastAt.Format "02.01.2006 15:04:05"}} UTC.{{end}}</p>
<div style="display:flex;gap:8px;margin:8px 0">
<button type="button" class="btn" onclick="var t=document.getElementById('quik-report').textContent;navigator.clipboard&&navigator.clipboard.writeText(t);this.textContent='Скопировано ✓';setTimeout(()=>this.textContent='Скопировать отчёт',1500)">Скопировать отчёт</button>
</div>
@@ -397,10 +397,10 @@
<div class="card">
<h2><span class="dot {{if .Settings.Crypto.Profile}}ok{{else}}warn{{end}}"></span>СКЗИ «Валидата Клиент L»</h2>
<p class="muted">Активный профиль: <code>{{if .Settings.Crypto.Profile}}{{.Settings.Crypto.Profile}}{{else}}—{{end}}</code> · провайдер <code>{{.Settings.Crypto.Provider}}</code>. Подробно — <a href="/admin/help/crypto">справка</a>.</p>
<p class="muted">Активный профиль: <code>{{if .Settings.Crypto.Profile}}{{.Settings.Crypto.Profile}}{{else}}—{{end}}</code> · провайдер {{if and (not .DevMode) (or (eq .Settings.Crypto.Provider "stub") (eq .Settings.Crypto.Provider ""))}}<code>не настроен</code>{{else}}<code>{{.Settings.Crypto.Provider}}</code>{{end}}. Подробно — <a href="/admin/help/crypto">справка</a>.</p>
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:12px">
<form method="post" action="/admin/setup/crypto/check" style="margin:0"><button type="submit" class="btn btn-ok">✓ Проверить СКЗИ</button></form>
<form method="post" action="/admin/setup/crypto/test-sign" style="margin:0"><button type="submit" class="btn">✎ Тестовая подпись</button></form>
<form method="post" action="/admin/setup/crypto/test-sign" style="margin:0"><button type="submit" class="btn">✎ Пробная подпись</button></form>
<form method="post" action="/admin/setup/restart-crypto" style="margin:0" onsubmit="return confirm('Перезапустить crypto-service? Поднимется через ~5 сек.');"><button type="submit" class="btn btn-warn">↻ crypto-service</button></form>
<form method="post" action="/admin/setup/restart-server" style="margin:0" onsubmit="return confirm('Перезапустить bj-server? Через 5-10 сек страница вернётся.');"><button type="submit" class="btn btn-secondary">↻ bj-server</button></form>
</div>
@@ -409,7 +409,7 @@
<form method="post" action="/admin/setup/crypto" style="margin-top:12px;display:grid;gap:10px;max-width:640px">
<label>Провайдер</label>
<select name="provider">
<option value="stub" {{if eq .Settings.Crypto.Provider "stub"}}selected{{end}}>stub — без криптографии (демо)</option>
{{if .DevMode}} <option value="stub" {{if eq .Settings.Crypto.Provider "stub"}}selected{{end}}>stub — без криптографии (демо)</option>{{end}}
<option value="validata" {{if eq .Settings.Crypto.Provider "validata"}}selected{{end}}>Валидата Клиент L</option>
</select>
<label>Путь к модулю PKCS#11</label>
@@ -480,21 +480,22 @@
<label style="display:flex;gap:8px;align-items:center;font-weight:600;margin:0"><input type="checkbox" name="enabled" value="1" {{if .Settings.M2MAuto.Enabled}}checked{{end}}> Автоматический режим включён</label>
<button type="submit" class="btn btn-ok">Сохранить</button>
</form>
{{if not .Settings.M2MAuto.ChangedAt.IsZero}}<p class="muted" style="font-size:12px;margin-top:8px">{{if .Settings.M2MAuto.Enabled}}Включён{{else}}Выключен{{end}} {{msk .Settings.M2MAuto.ChangedAt}}{{with .Settings.M2MAuto.ChangedBy}} · {{.}}{{end}}.{{if .Settings.Quik.Emulate}} Шаги QUIK МНП — в режиме имитации.{{end}}</p>{{end}}
{{if not .Settings.M2MAuto.ChangedAt.IsZero}}<p class="muted" style="font-size:12px;margin-top:8px">{{if .Settings.M2MAuto.Enabled}}Включён{{else}}Выключен{{end}} {{msk .Settings.M2MAuto.ChangedAt}}{{with .Settings.M2MAuto.ChangedBy}} · {{.}}{{end}}.{{if .Settings.Quik.Emulate}}{{if .DevMode}} Шаги QUIK МНП — в режиме имитации.{{else}} Записи в QUIK МНП сейчас не выполняются.{{end}}{{end}}</p>{{end}}
</div>
<div class="card">
<h2><span class="dot {{if .Settings.NSD.IGWBaseURL}}ok{{else}}warn{{end}}"></span>Интеграционный шлюз (ИШ)</h2>
<p class="muted">{{if not .Settings.NSD.IGWBaseURL}}<code>mock-режим</code> — без реального ИШ.{{else}}Профиль <code>{{.Settings.NSD.Profile}}</code>, ИШ <code>{{.Settings.NSD.IGWBaseURL}}</code>.{{end}} Стенды и установка — <a href="/admin/help/systems">справка</a>.</p>
<p class="muted">{{if not .Settings.NSD.IGWBaseURL}}{{if .DevMode}}<code>mock-режим</code> — без реального ИШ.{{else}}ИШ не настроен — обмен с НРД не выполняется.{{end}}{{else}}Профиль <code>{{.Settings.NSD.Profile}}</code>, ИШ <code>{{.Settings.NSD.IGWBaseURL}}</code>.{{end}} Стенды и установка — <a href="/admin/help/systems">справка</a>.</p>
<form method="post" action="/admin/setup/nsd" style="margin-top:12px;display:grid;gap:10px;max-width:680px">
<label>Профиль / контур</label>
<select name="profile" id="nsd-profile">
<option value="" {{if eq .Settings.NSD.Profile ""}}selected{{end}}>— mock (демо) —</option>
<option value="guest-gost" {{if eq .Settings.NSD.Profile "guest-gost"}}selected{{end}}>guest-gost — GUEST, ГОСТ</option>
<option value="guest-rsa" {{if eq .Settings.NSD.Profile "guest-rsa"}}selected{{end}}>guest-rsa — GUEST, RSA</option>
<option value="test3-gost" {{if eq .Settings.NSD.Profile "test3-gost"}}selected{{end}}>test3-gost — TEST3, ГОСТ</option>
<option value="test3-rsa" {{if eq .Settings.NSD.Profile "test3-rsa"}}selected{{end}}>test3-rsa — TEST3, RSA</option>
<option value="prod-gost" {{if eq .Settings.NSD.Profile "prod-gost"}}selected{{end}}>prod-gost — ПРОМ, ГОСТ</option>
<option value="prod-rsa" {{if eq .Settings.NSD.Profile "prod-rsa"}}selected{{end}}>prod-rsa — ПРОМ, RSA</option>
{{/* mock и GUEST — для разработчиков; у клиента — только контуры НРД */}}
<option value="" {{if eq .Settings.NSD.Profile ""}}selected{{end}}>{{if .DevMode}}— mock (демо) —{{else}}— не выбран —{{end}}</option>
{{if or .DevMode (eq .Settings.NSD.Profile "guest-gost") (eq .Settings.NSD.Profile "guest-rsa")}} <option value="guest-gost" {{if eq .Settings.NSD.Profile "guest-gost"}}selected{{end}}>guest-gost — GUEST, ГОСТ</option>
<option value="guest-rsa" {{if eq .Settings.NSD.Profile "guest-rsa"}}selected{{end}}>guest-rsa — GUEST, RSA</option>{{end}}
<option value="test3-gost" {{if eq .Settings.NSD.Profile "test3-gost"}}selected{{end}}>test3-gost — тестовый контур НРД (TEST3), ГОСТ</option>
<option value="test3-rsa" {{if eq .Settings.NSD.Profile "test3-rsa"}}selected{{end}}>test3-rsa — тестовый контур НРД (TEST3), RSA</option>
<option value="prod-gost" {{if eq .Settings.NSD.Profile "prod-gost"}}selected{{end}}>prod-gost — боевой контур НРД, ГОСТ</option>
<option value="prod-rsa" {{if eq .Settings.NSD.Profile "prod-rsa"}}selected{{end}}>prod-rsa — боевой контур НРД, RSA</option>
</select>
<label>URL ONYX (WSL) НРД</label>
<input type="text" name="igw_base_url" id="nsd-url" value="{{.Settings.NSD.IGWBaseURL}}" placeholder="автозаполнится по профилю">
@@ -551,7 +552,7 @@
<input type="text" name="lk_public_url" value="{{.Settings.LK.PublicURL}}" placeholder="https://fontvielle.ef.winr.pro" style="flex:1">
{{if .Settings.LK.PublicURL}}<a class="btn btn-secondary" href="{{.Settings.LK.PublicURL}}" target="_blank" rel="noopener">Открыть →</a>{{end}}
</div>
<span class="muted" style="font-size:12px">Показывается ссылкой на дашборде для первичного теста.</span>
<span class="muted" style="font-size:12px">{{if .DevMode}}Показывается ссылкой на дашборде для первичного теста.{{else}}Адрес, по которому клиенты входят в личный кабинет.{{end}}</span>
</div>
<div>
<label>Callback URL <span class="muted" style="font-weight:400">(куда bj шлёт статус заявки)</span></label>
@@ -661,15 +662,15 @@
<div class="card">
<h2>Забрать заявки из ЛК</h2>
<p class="muted">Коннектор bj вычитывает заявки <code>depo_m2m</code> активного окружения в статусах «В очереди» и «В работе», которые ещё не обрабатывал, для каждой собирает M2M-пакет, отправляет в НРД и переводит заявку в статус <strong>«В работе»</strong>. По ответу НРД статус в ЛК замыкается автоматически (Исполнена / Отклонена). В режиме имитации НРД перед отправкой идёт сверка с DEPO: отказ сразу уходит в ЛК с кодом и причиной, одобренная заявка блокируется в QUIK и через 30 с получает имитированный ответ контрагента. Штатно это делает фоновый поллер раз в минуту — кнопка для ручного запуска.</p>
<p class="muted">Коннектор bj вычитывает заявки <code>depo_m2m</code> активного окружения в статусах «В очереди» и «В работе», которые ещё не обрабатывал, для каждой собирает M2M-пакет, отправляет в НРД и переводит заявку в статус <strong>«В работе»</strong>. По ответу НРД статус в ЛК замыкается автоматически (Исполнена / Отклонена).{{if .DevMode}} В режиме имитации НРД перед отправкой идёт сверка с DEPO: отказ сразу уходит в ЛК с кодом и причиной, одобренная заявка блокируется в QUIK и через 30 с получает имитированный ответ контрагента.{{end}} Штатно это делает фоновый поллер раз в минуту — кнопка для ручного запуска.</p>
<form method="post" action="/admin/setup/lk-pull" style="margin-top:12px"><button type="submit" class="btn">Забрать заявки сейчас</button></form>
<p class="muted" style="font-size:12px;margin-top:10px">Итог (сколько получено / отправлено, ошибки) появится вверху страницы.</p>
</div>
</section>
{{/* ============ ТЕСТЫ ============ */}}
{{/* ============ ДИАГНОСТИКА (id sec-tests сохранён для ссылок) ============ */}}
<section class="settings-section" id="sec-tests">
<h1>Тесты</h1>
<h1>Диагностика</h1>
<div class="card">
<h2>Здоровье сервиса</h2>
@@ -765,7 +766,7 @@
</div>
<div style="margin-top:16px;display:flex;gap:8px;flex-wrap:wrap;align-items:center">
<button type="submit" class="btn">Сохранить</button>
<button type="submit" formaction="/admin/setup/alerts-smtp-test" class="btn btn-secondary">Отправить тестовое письмо</button>
<button type="submit" formaction="/admin/setup/alerts-smtp-test" class="btn btn-secondary">Отправить проверочное письмо</button>
</div>
</form>
{{if .Settings.Alerts.SMTP.LastMsg}}<p class="muted" style="font-size:12px;margin-top:10px">Последняя проверка: {{.Settings.Alerts.SMTP.LastMsg}}</p>{{end}}
@@ -784,7 +785,7 @@
</div>
<div style="margin-top:16px;display:flex;gap:8px;flex-wrap:wrap;align-items:center">
<button type="submit" class="btn">Сохранить</button>
<button type="submit" formaction="/admin/setup/alerts-zabbix-test" class="btn btn-secondary">Отправить тестовое значение</button>
<button type="submit" formaction="/admin/setup/alerts-zabbix-test" class="btn btn-secondary">Отправить проверочное значение</button>
</div>
</form>
{{if .Settings.Alerts.Zabbix.LastMsg}}<p class="muted" style="font-size:12px;margin-top:10px">Последняя проверка: {{.Settings.Alerts.Zabbix.LastMsg}}</p>{{end}}
@@ -935,7 +936,7 @@
<h1>Оформление отчётов</h1>
<div class="card">
<h2>Логотип организации в шапке отчётов</h2>
<p class="muted">Логотип показывается <b>справа</b> в шапке всех отчётов для регулятора (слева — логотип MOEX МОСТ / НРД) и на титульной сводке пакета тестов. Встраивается прямо в HTML — отчёт остаётся автономным. Если не загружать — используется стандартный логотип «Фонтвьель».</p>
<p class="muted">Логотип показывается <b>справа</b> в шапке всех отчётов для регулятора (слева — логотип MOEX МОСТ / НРД){{if .DevMode}} и на титульной сводке пакета тестов{{end}}. Встраивается прямо в HTML — отчёт остаётся автономным. Если не загружать — используется стандартный логотип «Фонтвьель».</p>
<div style="display:flex;align-items:center;gap:18px;flex-wrap:wrap;margin:14px 0;padding:14px;background:var(--card-2);border-radius:12px">
<div>