Files
Bridge-and-Join-s/internal/lkgateway/web/templates/admin_m2mtest.html
T

200 lines
15 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"}}
<style>
.m2m-chips{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0}
.m2m-chips span{padding:4px 12px;border-radius:20px;font-size:13px;font-weight:600;background:var(--card-2);border:1px solid var(--border)}
.m2m-chips .ok{background:var(--ok-weak,#e6f4ea);color:#1a7f37;border-color:#bfe3c9}
.m2m-chips .err{background:var(--err-weak,#fbe9e9);color:#b3261e;border-color:#f0c2bf}
.m2m-chips .prog{background:var(--warn-weak,#fbf3d9);color:#8a6d00;border-color:#ecd9a1}
.cpf{display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;margin-top:8px}
.cpf label{font-size:12px;color:var(--muted);display:flex;flex-direction:column;gap:3px}
.cpf input{padding:6px 8px;border:1px solid var(--border);border-radius:7px;background:var(--card);color:var(--text);min-width:150px}
main{max-width:min(1680px,100%)} /* таблица сценариев широкая: страница шире общих 1200px, чтобы не было прокрутки вбок */
table.m2m{width:100%;border-collapse:collapse;font-size:13px}
table.m2m td{overflow-wrap:anywhere}
table.m2m th,table.m2m td{padding:6px 8px;border-bottom:1px solid var(--border);text-align:left;vertical-align:top}
table.m2m th{position:sticky;top:0;background:var(--card-2);font-size:11px;text-transform:uppercase;letter-spacing:.03em;color:var(--muted)}
table.m2m tr.st-passed{background:var(--ok-weak,#e6f4ea)}
table.m2m tr.st-failed{background:var(--err-weak,#fbe9e9)}
table.m2m tr.st-in_progress{background:var(--warn-weak,#fbf3d9)}
table.m2m tr.st-excluded{opacity:.45}
table.m2m tr.st-excluded td{color:var(--muted)}
.live{font-size:11px;margin-top:3px;font-weight:600}
table.m2m .i{color:var(--accent,#1f6feb);cursor:help;font-size:12px}
table.m2m tr:hover{outline:1px solid var(--accent-weak,#cfe0fb)}
.role-we{font-weight:700;color:var(--accent-strong,#1f4e79)}
.code{font-family:monospace;font-weight:700;color:#b3261e}
.small{font-size:11px}
.stf{display:inline-flex;gap:3px}
.stf button{border:1px solid var(--border);background:var(--card);border-radius:6px;padding:3px 7px;cursor:pointer;font-size:13px;line-height:1}
.stf button.b-ok:hover{background:#e6f4ea}
.stf button.b-err:hover{background:#fbe9e9}
.b-init{border:1px solid #1f4e79;background:var(--accent-weak,#e7f0fb);color:#1f4e79;border-radius:7px;padding:5px 10px;cursor:pointer;font-weight:600;font-size:12px;white-space:nowrap}
.b-init:hover{background:#d7e6fb}
.scen-row td{background:var(--card-2);font-weight:700;color:var(--text);font-size:12px}
.noteinp{width:100%;margin-top:3px;padding:3px 5px;border:1px solid var(--border);border-radius:5px;font-size:11px;background:var(--card);color:var(--text)}
</style>
<div class="card">
<h2>Тестирование M2M — с контрагентом (МБ / НРД)</h2>
<div style="padding:10px 14px;background:var(--accent-weak,#e7f0fb);border-radius:10px;margin:6px 0 10px;font-size:14px">
<strong>{{if .CounterpartyName}}{{.CounterpartyName}}{{else}}Контрагент 1{{end}}</strong> — <em>списывающий</em> (Контрагент 1) &nbsp;→&nbsp; <strong>Фонтвьель</strong> — <em>зачисляющий</em> (Контрагент 2, мы).
</div>
<p class="muted">По кейсам, где мы <em>Списывающий</em>, жмём «Инициировать отправку»; где <em>Зачисляющий</em> — отвечаем на странице <a href="/admin/incoming">Входящие</a> (для негативных кейсов — с кодом отказа). По инициированным кейсам статус и исход НРД <strong>подтягиваются автоматически</strong>. Статусы сохраняются между перезапусками.</p>
<div class="m2m-chips">
<span>Всего: {{.Total}}</span>
<span class="ok">✓ Успех: {{.Passed}}</span>
<span class="err">✗ Провал: {{.Failed}}</span>
<span class="prog">● В процессе: {{.Prog}}</span>
<span>○ Не начато: {{.Pending}}</span>
{{if .Excluded}}<span style="opacity:.6">⊘ Не тестируем: {{.Excluded}}</span>{{end}}
</div>
{{if or .Passed .Prog .Failed}}
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:10px 0 4px">
<a href="/admin/m2m-testing/report-bundle.zip" class="btn btn-ok" download title="ZIP: сводка + доказательства по каждому пройденному кейсу">⬇ Отчёты по тестам</a>
<a href="/admin/m2m-testing/fancy-bundle.zip" class="btn" download title="ZIP: входящие и исходящие обмены с контрагентом + наши решения — для программиста Fancy">⬇ Эталон для Fancy</a>
<form method="post" action="/admin/m2m-testing/depo-replay" style="margin:0;display:inline-flex;gap:6px;align-items:center" onsubmit="return confirm('Выгрузить проведённые переводы с выбранным контрагентом (решения, поручения 16/16-1, отчёты MS010) в трансферные таблицы DEPO? Джоба bj2depo создаст по ним поручения в тестовой базе депозитария. Повторный запуск ничего не дублирует.')"><input type="text" name="cp" value="{{.CounterpartyCode}}" title="код контрагента МОСТ (пусто = все)" style="width:130px;font-size:12px"><button type="submit" class="btn" title="FTV_M2M + FTV_M2M_LINES + FTV_M2M_EVENTS в нашей копии DEPO — чтобы увидеть, как тесты выглядят внутри депозитария">🗂 Выгрузить историю в DEPO</button></form>
<a href="/admin/m2m-testing/process" target="_blank" class="btn" title="Наглядная схема процесса M2M (16 / 16.1) для программиста">🔄 Как работает процесс</a>
<a href="/admin/m2m-testing/depo-sim" class="btn" title="Песочница: выбрать клиента/бумагу из DEPO, изменить поля и посмотреть, как ответит сверка (ничего не отправляется)">🧪 Имитация сверки с DEPO</a>
<a href="/admin/m2m-testing/spravka" target="_blank" class="btn" title="Расшифровка кодов ошибок M2M">📖 Коды ошибок</a>
<span class="muted" style="font-size:12px;flex-basis:100%;margin-top:2px">Архивы для отправки контрагенту / программисту Fancy. Наведите на кнопку — подсказка, что внутри.</span>
</div>
{{end}}
<form method="post" action="/admin/m2m-testing/counterparty" class="cpf" id="cpForm">
<label style="min-width:340px">Контрагент (из справочника M2M)
<input id="cp-search" list="cp-list" autocomplete="off" placeholder="начните вводить наименование или код…"
value="{{if .CounterpartyName}}{{.CounterpartyName}} ({{.CounterpartyCode}}){{end}}">
<datalist id="cp-list"></datalist>
</label>
<div class="muted small" id="cp-info" style="align-self:center">
{{if .CounterpartyCode}}Код: <code>{{.CounterpartyCode}}</code> · ИНН: {{if .CounterpartyINN}}{{.CounterpartyINN}}{{else}}—{{end}}{{else}}— выберите контрагента из списка —{{end}}
</div>
<input type="hidden" name="counterparty_name" id="cp-name" value="{{.CounterpartyName}}">
<input type="hidden" name="counterparty_code" id="cp-code" value="{{.CounterpartyCode}}">
<input type="hidden" name="counterparty_inn" id="cp-inn" value="{{.CounterpartyINN}}">
<input type="hidden" name="our_inn" value="{{.OurINN}}">
<button class="b-init" style="background:var(--card);border-color:var(--border);color:var(--text)">Сохранить</button>
</form>
<div style="margin-top:10px"><a href="/admin/m2m-testing/plan.html" class="btn" title="Самостоятельный HTML: участники, тестовые клиенты, остатки, кейсы с ожидаемыми ответами — для отправки команде контрагента">📄 План для контрагента (HTML)</a> <a href="/admin/m2m-testing/plan.html?inline=1" target="_blank" class="muted small">открыть в браузере</a></div>
<div class="muted small" style="margin-top:6px">Наш депозитарий: <strong>{{if .OurName}}{{.OurName}}{{else}}Фонтвьель{{end}}</strong> · код <code>{{.OurCode}}</code>{{if .OurINN}} · ИНН {{.OurINN}}{{end}} <span style="opacity:.7">(из справочника)</span></div>
</div>
<script>
(function(){
var HB = {{m2mHandbook}};
var dl = document.getElementById('cp-list'), search = document.getElementById('cp-search');
if(!Array.isArray(HB)||!dl||!search) return;
var byLabel = {};
HB.forEach(function(p){
var label = p.name + ' — ' + p.code + (p.inn?(' (ИНН '+p.inn+')'):'');
var o=document.createElement('option'); o.value=label; dl.appendChild(o);
byLabel[label]=p;
});
function resolve(){
var p = byLabel[search.value];
if(!p){
var v = search.value.trim().toLowerCase();
for(var i=0;i<HB.length;i++){ var x=HB[i];
if((x.code&&x.code.toLowerCase()===v)
||(x.inn&&x.inn.toLowerCase()===v)
||(x.name&&x.name.toLowerCase()===v)
||(x.name&&(x.name+' ('+x.code+')').toLowerCase()===v)){ p=x; break; } }
}
if(!p) return false;
document.getElementById('cp-name').value=p.name;
document.getElementById('cp-code').value=p.code;
document.getElementById('cp-inn').value=p.inn||'';
document.getElementById('cp-info').innerHTML='Код: <code>'+p.code+'</code> · ИНН: '+(p.inn||'—');
search.value=p.name+' ('+p.code+')';
return true;
}
search.addEventListener('change', resolve);
// на всякий случай резолвим и перед сохранением формы
document.getElementById('cpForm').addEventListener('submit', function(e){
if(search.value.trim()!=='' && !document.getElementById('cp-code').value){ resolve(); }
});
})();
</script>
<div class="card">
<h3 style="margin:0 0 8px">Данные для занесения в учётную систему</h3>
<div style="display:flex;gap:24px;flex-wrap:wrap">
<div>
<div class="muted small" style="text-transform:uppercase;letter-spacing:.05em;margin-bottom:4px">Тестовые клиенты</div>
<table class="m2m" style="font-size:12px">
<tr><th></th><th>ФИО</th><th>ДУЛ</th></tr>
<tr><td><strong>К1</strong></td><td>Бубликов Павел Иванович</td><td>паспорт 3453 № 289090</td></tr>
<tr><td><strong>К2</strong></td><td>Баранкин Сергей Сергеевич</td><td>паспорт 3763 № 290089 <span class="muted">(кейсы M2M04)</span></td></tr>
</table>
</div>
<div>
<div class="muted small" style="text-transform:uppercase;letter-spacing:.05em;margin-bottom:4px">Бумаги</div>
<table class="m2m" style="font-size:12px">
<tr><th>ISIN</th><th>Код НРД</th><th>Наименование</th></tr>
<tr><td>RU0009029540</td><td>SBER/03</td><td>Акции об. ПАО Сбербанк</td></tr>
<tr><td>RU000A0JUR61</td><td>RU000A0JUR61</td><td>Пай ИПИФ «КОНСЕРВАТОРия»</td></tr>
<tr><td>RU000A102QL3</td><td>RU000A102QL3</td><td>Облигация суборд. ВТБ (СУБ-Т1-2)</td></tr>
<tr><td>RU0007661625</td><td>RU0007661625</td><td>Акции об. ПАО «Газпром» <span class="muted">(M2M05)</span></td></tr>
<tr><td>XS0088543193</td><td>XS0088543193</td><td>Минфин РФ (USD) <span class="muted">(M2M01, не-RU)</span></td></tr>
</table>
</div>
</div>
</div>
<div class="card" style="overflow-x:auto">
<table class="m2m">
<thead><tr>
<th>#</th><th>Списывающий</th><th>Зачисляющий</th><th>Наша роль</th>
<th>Клиент</th><th>Расч.депо</th><th>Бумаги</th><th>Ожидание</th>
<th>Статус</th><th>Действие</th>
</tr></thead>
<tbody>
{{$scen := ""}}
{{range .Rows}}
{{if ne .Scenario $scen}}
<tr class="scen-row"><td colspan="10">Сценарий {{.Scenario}}</td></tr>
{{$scen = .Scenario}}
{{end}}
<tr class="st-{{.StatusClass}}" title="{{.Desc}}">
<td><strong>{{.ID}}</strong> <span class="i" title="{{.Desc}}">ⓘ</span></td>
<td>{{.Debit}}</td>
<td>{{.Credit}}</td>
<td class="{{if .WeInitiate}}role-we{{else}}role-we{{end}}">{{.OurRole}}</td>
<td>{{.Client}}</td>
<td>{{.SettleDeb}}→{{.SettleCred}}</td>
<td class="small">{{.SecList}}</td>
<td>{{if .Expect}}<span class="code">{{.Expect}}</span>{{else}}<span class="ok" style="color:#1a7f37">успех</span>{{end}}<div class="muted small">{{.Note}}</div></td>
<td>
{{if .Excluded}}
<span class="muted small">⊘ не тестируем</span>
{{else}}
<form method="post" action="/admin/m2m-testing/status" class="stf">
<input type="hidden" name="id" value="{{.ID}}">
<button class="b-ok" name="status" value="passed" title="Успех">✓</button>
<button class="b-err" name="status" value="failed" title="Провал">✗</button>
<button name="status" value="reset" title="Сброс">○</button>
</form>
{{if .Live}}<div class="live {{if eq .StatusClass "passed"}}ok{{else if eq .StatusClass "failed"}}err{{else}}muted{{end}}" style="{{if eq .StatusClass "passed"}}color:#1a7f37{{else if eq .StatusClass "failed"}}color:#b3261e{{end}}">⟳ {{.Live}}</div>{{end}}
{{if .State.Note}}<div class="muted small">{{.State.Note}}</div>{{end}}
{{if .State.GUID}}<div class="muted small">GUID: {{.State.GUID}}</div>{{end}}
{{end}}
</td>
<td>
{{if .Excluded}}
<span class="muted small">—</span>
{{else if .WeInitiate}}
{{if .Secs}}
<a href="/admin/m2m-testing/preview?id={{.ID}}" class="b-init" style="text-decoration:none;display:inline-block">▶ Инициировать</a>
{{else}}<span class="muted small">Сценарий 2 — формируется вручную</span>{{end}}
{{else}}
<a href="/admin/incoming" class="muted small">Ответить во «Входящих»{{if .Expect}}<br>код <span class="code">{{.Expect}}</span>{{end}}</a>
{{end}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{end}}