92afdd2868
- finishResult: итог confirm / reject / partial, без отказа всем пакетом; - autoDecisions и ручной ответ: без правила «целиком», квал-предупреждение — отказ только по своей бумаге; - признак ИИС из заголовка запроса (IIAAgreementDetails), у сохранённых раньше — по исходному XML; - форма оператора: без автоматического «отказ всем», подсказка про ИИС; тексты и тесты. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
151 lines
12 KiB
HTML
151 lines
12 KiB
HTML
{{define "content"}}
|
||
<style>
|
||
.pv-legend{display:flex;gap:16px;flex-wrap:wrap;font-size:12.5px;margin:4px 0 2px}
|
||
.pill{display:inline-flex;align-items:center;gap:6px;padding:2px 10px;border-radius:999px;font-size:12px;font-weight:700}
|
||
.pill-ok{background:color-mix(in srgb,#16a34a 15%,var(--card));color:#0f7a37;border:1px solid color-mix(in srgb,#16a34a 40%,transparent)}
|
||
.pill-bad{background:color-mix(in srgb,#dc2626 15%,var(--card));color:#b3261e;border:1px solid color-mix(in srgb,#dc2626 45%,transparent)}
|
||
.pv table{width:100%;border-collapse:collapse;margin:8px 0;font-size:13.5px}
|
||
.pv td,.pv th{border:1px solid var(--border);padding:9px 12px;text-align:left;vertical-align:top}
|
||
.pv th{background:var(--card-2);font-size:12px;color:var(--muted)}
|
||
.pv td.k{width:230px;color:var(--muted)}
|
||
.row-ok{background:color-mix(in srgb,#16a34a 8%,var(--card))}
|
||
.row-bad{background:color-mix(in srgb,#dc2626 9%,var(--card))}
|
||
.banner{padding:12px 15px;border-radius:12px;margin:10px 0;font-size:13.5px}
|
||
.banner-ok{background:color-mix(in srgb,#16a34a 13%,var(--card));border:1px solid color-mix(in srgb,#16a34a 35%,transparent)}
|
||
.banner-bad{background:color-mix(in srgb,#dc2626 12%,var(--card));border:1px solid color-mix(in srgb,#dc2626 38%,transparent)}
|
||
</style>
|
||
|
||
<p style="margin:0 0 12px"><a href="/admin/m2m-testing" class="btn" onclick="if(history.length>1){history.back();return false}">← Назад к плану</a></p>
|
||
|
||
<div class="card pv">
|
||
<h2 style="margin:0 0 4px">Проверка данных перед отправкой · кейс <code>{{.Case.ID}}</code></h2>
|
||
<div class="muted" style="font-size:13px">{{.Case.Debit}} → {{.Case.Credit}} · клиент {{.ClientKey}} · {{.Case.Note}}</div>
|
||
|
||
<div class="pv-legend" style="margin-top:10px">
|
||
<span class="pill pill-ok">🟢 корректные данные</span>
|
||
<span class="pill pill-bad">🔴 намеренно неверно (по плану сценария)</span>
|
||
</div>
|
||
|
||
{{if .AlreadySent}}
|
||
<div class="banner banner-bad">⚠ <b>По этому кейсу уже отправлялся запрос</b> (GUID <code>{{.SentGUID}}</code>, {{.SentWhen}}).
|
||
Повторная отправка создаст <b>новую заявку с новым GUID</b> — НРД примет её как новую (ошибки о дубле GUID <b>не будет</b>). Это правильный способ переотправить кейс, если контрагент ответил неверно.
|
||
Контрагент увидит ещё один перевод по тому же инвестору и бумагам — поэтому отправляйте осознанно.</div>
|
||
{{end}}
|
||
{{if .Positive}}
|
||
<div class="banner banner-ok">✓ <b>Позитивный кейс.</b> Все данные корректны — ожидаем <b>успешный перевод</b>. Ничего не подменяем.</div>
|
||
{{else}}
|
||
<div class="banner banner-bad">🔴 <b>Негативный кейс, ожидаем код {{.Case.Expect}}.</b> {{.DefectDesc}}<br>
|
||
<span class="muted" style="font-size:12.5px">Неверный реквизит выделен красным — отправляем именно его, чтобы отказ был настоящим.</span></div>
|
||
{{end}}
|
||
|
||
<h3 style="font-size:14px;margin:16px 0 4px">Инвестор (владелец бумаг)</h3>
|
||
<table>
|
||
<tr class="{{if .ClientBad}}row-bad{{else}}row-ok{{end}}">
|
||
<td class="k">ФИО · документ {{if .ClientBad}}<span class="pill pill-bad">🔴</span>{{else}}<span class="pill pill-ok">🟢</span>{{end}}</td>
|
||
<td><b>{{.ClientFIO}}</b> ({{.ClientKey}})<br>{{.ClientDUL}}
|
||
{{if .ClientBad}}<div class="muted" style="font-size:12px;color:#b3261e">Этот клиент не заведён у зачисляющего — сработает M2M04.</div>{{end}}</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<h3 style="font-size:14px;margin:16px 0 4px">Депозитарии</h3>
|
||
<table>
|
||
<tr class="row-ok">
|
||
<td class="k">Списывающий (мы) <span class="pill pill-ok">🟢</span></td>
|
||
<td>{{if .OurName}}<b>{{.OurName}}</b> · {{end}}<code>{{.OurCode}}</code>{{if .OurINN}} · ИНН {{.OurINN}}{{end}}</td>
|
||
</tr>
|
||
<tr class="{{if eq .DefectField "account"}}row-bad{{else}}row-ok{{end}}">
|
||
<td class="k">Счёт списания (место расчётов) {{if eq .DefectField "account"}}<span class="pill pill-bad">🔴</span>{{else}}<span class="pill pill-ok">🟢</span>{{end}}</td>
|
||
<td><code>{{.OurAccount}}</code>
|
||
{{if eq .DefectField "account"}}<div class="muted" style="font-size:12px;color:#b3261e">{{.DefectDesc}}</div>{{end}}</td>
|
||
</tr>
|
||
<tr class="row-ok">
|
||
<td class="k">Зачисляющий (контрагент) <span class="pill pill-ok">🟢</span></td>
|
||
<td>{{if .CpName}}<b>{{.CpName}}</b> · {{end}}<code>{{.CpCode}}</code>{{if .CpINN}} · ИНН {{.CpINN}}{{end}}</td>
|
||
</tr>
|
||
</table>
|
||
|
||
{{if .Secs}}
|
||
<h3 style="font-size:14px;margin:16px 0 4px">Ценные бумаги ({{len .Secs}})</h3>
|
||
<table>
|
||
<thead><tr><th style="width:60px"></th><th>ISIN / код НРД</th><th>Наименование</th><th>Кол-во</th></tr></thead>
|
||
<tbody>
|
||
{{range .Secs}}
|
||
<tr class="{{if .Bad}}row-bad{{else}}row-ok{{end}}">
|
||
<td>{{if .Bad}}<span class="pill pill-bad">🔴</span>{{else}}<span class="pill pill-ok">🟢</span>{{end}}</td>
|
||
<td><code>{{.ISIN}}</code>{{if ne .Code .ISIN}} · {{.Code}}{{end}}</td>
|
||
<td>{{.Name}}{{if .Bad}} <span class="muted" style="font-size:12px;color:#b3261e">— неверная для этого кейса</span>{{end}}</td>
|
||
<td>{{if $.WeInitiate}}<input type="text" name="qty_{{.ISIN}}" value="{{.Qty}}" data-checked="{{.Qty}}" class="m2m-qty-in" form="m2m-qty" inputmode="decimal" style="width:90px">{{else}}{{.Qty}}{{end}}</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
{{if .WeInitiate}}
|
||
<form id="m2m-qty" method="get" action="/admin/m2m-testing/preview" style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-top:8px">
|
||
<input type="hidden" name="id" value="{{.Case.ID}}">
|
||
<button type="submit" class="btn">↻ Пересчитать сверку с этим количеством</button>
|
||
<span class="muted" style="font-size:12px">Количество можно изменить; сверка DEPO и отправка берут то, что указано здесь после пересчёта.</span>
|
||
</form>
|
||
<div id="m2m-qty-stale" hidden style="margin-top:8px;padding:8px 12px;border-radius:9px;font-size:13px;font-weight:600;background:color-mix(in srgb,#d97706 14%,var(--card));color:#9a6b12">Количество изменено — нажмите «Пересчитать сверку». Отправка заблокирована, пока сверка DEPO не пересчитана с новым количеством.</div>
|
||
<script>
|
||
(function(){
|
||
var ins = document.querySelectorAll('.m2m-qty-in');
|
||
function stale(){
|
||
var changed = false;
|
||
ins.forEach(function(i){ if(i.value.trim() !== i.getAttribute('data-checked')) changed = true; });
|
||
var b = document.getElementById('m2m-qty-stale'); if(b) b.hidden = !changed;
|
||
document.querySelectorAll('.m2m-send-btn').forEach(function(btn){ btn.disabled = changed; });
|
||
}
|
||
ins.forEach(function(i){ i.addEventListener('input', stale); });
|
||
})();
|
||
</script>
|
||
{{end}}
|
||
{{end}}
|
||
|
||
{{if .WeInitiate}}
|
||
<style>
|
||
.dc-ok{color:var(--ok,#12813f);font-weight:700}.dc-bad{color:var(--err,#b3261e);font-weight:700}.dc-warn{color:var(--warn,#9a6b12);font-weight:700}
|
||
.dc-rec{display:inline-block;padding:4px 12px;border-radius:999px;font-weight:700;font-size:13px}
|
||
.dc-rec.confirm{background:var(--ok-weak,#e6f4ea);color:var(--ok,#12813f)}
|
||
.dc-rec.reject{background:var(--err-weak,#fbe9e7);color:var(--err,#b3261e)}
|
||
.dc-rec.partial,.dc-rec.mixed{background:var(--warn-weak,#fff4e0);color:var(--warn,#9a6b12)}
|
||
.dc-rec.mixed{background:var(--warn-weak,#fff4e0);color:var(--warn,#9a6b12)}
|
||
</style>
|
||
<div style="margin-top:18px;padding:12px 14px;border:1px solid var(--border);border-radius:12px;background:var(--card)">
|
||
<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap">
|
||
<h3 style="margin:0;font-size:14px">Сверка списания с DEPO — эмуляция</h3>
|
||
{{if .Depo.Ran}}<span class="dc-rec {{.Depo.Recommend}}">{{.Depo.Summary}}</span>{{end}}
|
||
</div>
|
||
<p class="muted" style="font-size:12px;margin:6px 0 0">Как Fancy-DEPO оценила бы это списание: клиент, торговый счёт, остаток, место хранения, блокировки, ИИС. Ничего не отправляется — только подсказка перед отправкой.</p>
|
||
{{if not .Depo.Ran}}
|
||
<p class="muted" style="margin-top:8px">Сверка не выполнена: {{.Depo.Err}}</p>
|
||
{{else}}
|
||
<div class="muted" style="font-size:12.5px;margin-top:8px">Инвестор: {{if .Depo.Investor}}<b>{{.Depo.Investor}}</b>{{else}}<span class="dc-bad">не найден в картотеке</span>{{end}} · Торговый счёт: {{if .Depo.Account}}<code>{{.Depo.Account}}</code>{{else}}<span class="dc-bad">нет открытого ВТНКЦ-счёта</span>{{end}}</div>
|
||
{{range .Depo.Secs}}
|
||
<div style="font-size:13px;font-weight:600;margin:10px 0 4px"><code>{{.Security}}</code> → {{if eq .Recommend "confirm"}}<span class="dc-ok">списать можно</span>{{else}}<span class="dc-bad">отказ {{.RejectCode}}</span> <span class="muted" style="font-weight:400">({{m2mCode .RejectCode}})</span>{{end}}</div>
|
||
<table style="font-size:12.5px">
|
||
<tbody>
|
||
{{range .Checks}}
|
||
<tr><td style="width:30px">{{if not .OK}}<span class="dc-bad">🔴</span>{{else if .Warn}}<span class="dc-warn">🟡</span>{{else}}<span class="dc-ok">🟢</span>{{end}}</td><td style="width:270px">{{.Name}}</td><td>{{.Detail}}</td></tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
{{end}}
|
||
{{end}}
|
||
</div>
|
||
{{end}}
|
||
|
||
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-top:18px">
|
||
{{if .WeInitiate}}
|
||
<form method="post" action="/admin/m2m-testing/initiate" onsubmit="return confirm('{{if .AlreadySent}}Отправить кейс {{.Case.ID}} ЗАНОВО? Уйдёт новая заявка с новым GUID (НРД примет как новую). Контрагент увидит ещё один перевод.{{else}}Отправить кейс {{.Case.ID}} контрагенту? Уйдёт реальный пакет в НРД (TEST3).{{end}} Количество: {{range $i, $s := .Secs}}{{if $i}}, {{end}}{{$s.Code}} × {{$s.Qty}}{{end}}.');">
|
||
<input type="hidden" name="id" value="{{.Case.ID}}">
|
||
{{range .Secs}}<input type="hidden" name="qty_{{.ISIN}}" value="{{.Qty}}">{{end}}
|
||
<button type="submit" class="m2m-send-btn btn {{if .AlreadySent}}{{else}}btn-ok{{end}}">{{if .AlreadySent}}▶ Отправить заново (новый GUID){{else}}▶ Подтвердить и отправить в НРД{{end}}</button>
|
||
</form>
|
||
<a href="/admin/m2m-testing" class="btn">Отмена</a>
|
||
{{else}}
|
||
<div class="muted">По этому кейсу мы <b>Зачисляющий</b> — данные не отправляем, а отвечаем на странице <a href="/admin/incoming">Входящие</a>{{if .Case.Expect}} (код <code>{{.Case.Expect}}</code>){{end}}.</div>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
{{end}}
|