4f4f70c530
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
424 lines
33 KiB
HTML
424 lines
33 KiB
HTML
{{define "content"}}
|
||
{{$answered := eq .It.Status "answered"}}
|
||
<style>
|
||
.in-tl{position:fixed;right:18px;top:84px;width:230px;max-height:84vh;overflow:auto;
|
||
background:var(--card,#fff);border:1px solid var(--border,#e3e3e8);border-radius:14px;
|
||
padding:14px 16px;box-shadow:var(--shadow-lg,0 8px 30px rgba(0,0,0,.10));z-index:40}
|
||
.in-tl h3{margin:0 0 12px;font-size:13px}
|
||
.in-tl .st{position:relative;padding:0 0 12px 20px}
|
||
.in-tl .st::before{content:'';position:absolute;left:3px;top:3px;width:10px;height:10px;border-radius:50%;
|
||
background:var(--c,#2563eb);box-shadow:0 0 0 3px color-mix(in srgb, var(--c,#2563eb) 20%, transparent)}
|
||
.in-tl .st::after{content:'';position:absolute;left:7px;top:15px;bottom:0;width:2px;background:var(--border,#e3e3e8)}
|
||
.in-tl .st:last-child::after{display:none}
|
||
.in-tl .tm{font-size:10.5px;color:var(--muted,#888);font-variant-numeric:tabular-nums}
|
||
.in-tl .ti{font-size:12.5px;font-weight:600;margin:1px 0;line-height:1.3}
|
||
.in-tl .de{font-size:10.5px;color:var(--muted,#888);line-height:1.4}
|
||
.st-req{--c:#2563eb}.st-gw{--c:#7c3aed}.st-resp{--c:#0891b2}.st-rej{--c:#dc2626}.st-ord{--c:#16a34a}.st-nrd{--c:#0891b2}
|
||
@media (max-width:1500px){.in-tl{position:static;width:auto;max-height:none;margin-top:16px;box-shadow:none}}
|
||
</style>
|
||
<p style="margin:0 0 12px"><a href="/admin/incoming" class="btn" onclick="if(history.length>1){history.back();return false}">← Назад</a></p>
|
||
<div class="card">
|
||
<h2>Входящий перевод <code>{{short 8 .It.GUID}}</code>
|
||
{{if $answered}}<span class="badge confirmed">отвечено</span>{{else}}<span class="badge awaiting_decision">ждёт решения</span>{{end}}
|
||
</h2>
|
||
{{$l := liveIn .It}}<div class="live live-big live-{{$l.Kind}}" data-live="in:{{.It.ID}}"{{if $l.Active}} data-active="1"{{else}} title="Завершено: состояние больше не проверяется"{{end}}>{{$l.Text}}</div>
|
||
<table>
|
||
<tr><td style="width:220px" class="muted">Запрос сформирован (отправитель)</td><td>{{msk .It.RequestCreated}}</td></tr>
|
||
<tr><td class="muted">Забрали из шлюза (получено нами)</td><td>{{msk .It.ReceivedAt}}{{if not .It.RequestCreated.IsZero}} <span class="muted" style="font-size:12px">· прохождение: {{transit .It.RequestCreated .It.ReceivedAt}}</span>{{end}}</td></tr>
|
||
{{if $answered}}<tr><td class="muted">Ответ отправлен</td><td>{{msk .It.AnsweredAt}}{{if not .It.ReceivedAt.IsZero}} <span class="muted" style="font-size:12px">· обработка: {{transit .It.ReceivedAt .It.AnsweredAt}}</span>{{end}}</td></tr>{{end}}
|
||
<tr><td class="muted">GUID перевода</td><td><code>{{.It.GUID}}</code> <span class="muted">(в нашем решении используется этот же GUID)</span></td></tr>
|
||
<tr><td class="muted">От кого (передающий)</td><td>{{$nm := m2mParty .It.SenderCode}}{{if not $nm}}{{$nm = m2mParty .It.SenderINN}}{{end}}{{if $nm}}<strong>{{$nm}}</strong> · {{end}}<code>{{.It.SenderCode}}</code>{{if .It.SenderINN}} · ИНН {{.It.SenderINN}}{{end}}</td></tr>
|
||
<tr><td class="muted">Кому (мы)</td><td>{{$rn := m2mParty .It.ReceiverCode}}{{if not $rn}}{{$rn = m2mParty .It.ReceivingINN}}{{end}}{{if $rn}}<strong>{{$rn}}</strong> · {{end}}<code>{{.It.ReceiverCode}}</code>{{if .It.ReceivingINN}} · ИНН {{.It.ReceivingINN}}{{end}}</td></tr>
|
||
<tr><td class="muted">Инвестор (ФИО)</td><td><strong>{{.It.InvestorLast}} {{.It.InvestorFirst}} {{.It.InvestorMiddle}}</strong></td></tr>
|
||
<tr><td class="muted">Документ</td><td>{{docType .It.DocType}}{{if .It.DocSeries}} · серия {{.It.DocSeries}}{{end}}{{if .It.DocNumber}} · № {{.It.DocNumber}}{{end}}</td></tr>
|
||
{{if .It.AnswerNote}}<tr><td class="muted">Результат</td><td>{{if .It.Auto}}<span class="badge confirmed">авто</span> {{end}}{{.It.AnswerNote}}</td></tr>{{end}}
|
||
</table>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<style>
|
||
.dc-tbl td{vertical-align:top}
|
||
.dc-ok{color:var(--ok,#12813f);font-weight:700}.dc-bad{color:var(--err,#b3261e);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.mixed{background:var(--warn-weak,#fff4e0);color:var(--warn,#9a6b12)}
|
||
</style>
|
||
<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap">
|
||
<h2 style="margin:0">Сверка с DEPO — {{if devOn}}эмуляция ответа{{else}}рекомендация по ответу{{end}}</h2>
|
||
{{if .Depo.Ran}}<span class="dc-rec {{.Depo.Recommend}}">рекомендуем: {{.Depo.Summary}}</span>{{end}}
|
||
</div>
|
||
<p class="muted" style="font-size:12.5px;margin:6px 0 0">Проверки по регламенту депозитария (инвестор, торговый счёт депо, бумага на обслуживании, договор не ИИС, блокировки). <b>Ответ контрагенту НЕ отправлен</b> — это только рекомендация; она подставлена в форму ниже, проверьте и нажмите «Отправить решение».</p>
|
||
{{if not .Depo.Ran}}
|
||
<p class="muted" style="margin-top:10px">Сверка не выполнена: {{.Depo.Err}}</p>
|
||
{{else}}
|
||
<table style="margin-top:10px">
|
||
<tr><td class="muted" style="width:220px">Инвестор в картотеке</td><td>{{if .Depo.Investor}}<b>{{.Depo.Investor}}</b>{{else}}<span class="dc-bad">не найден</span>{{end}}</td></tr>
|
||
<tr><td class="muted">Торговый счёт депо</td><td>{{if .Depo.Account}}<code>{{.Depo.Account}}</code> — открыт{{else}}<span class="dc-bad">открытого ВТНКЦ-счёта нет</span>{{end}}</td></tr>
|
||
</table>
|
||
{{range .Depo.Secs}}
|
||
<span class="depo-rec" data-ref="{{.ReferenceID}}" data-rec="{{.Recommend}}" data-code="{{.RejectCode}}" hidden></span>
|
||
<h3 style="font-size:13.5px;margin:14px 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}}</h3>
|
||
<table class="dc-tbl">
|
||
<thead><tr><th style="width:36px"></th><th style="width:250px">Проверка</th><th>Результат</th></tr></thead>
|
||
<tbody>
|
||
{{range .Checks}}
|
||
<tr><td>{{if .OK}}<span class="dc-ok">🟢</span>{{else}}<span class="dc-bad">🔴</span>{{end}}</td><td>{{.Name}}{{if not .OK}} <span class="muted" style="font-size:11px">→ {{.Code}}</span>{{end}}</td><td style="font-size:12.5px">{{.Detail}}</td></tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
{{end}}
|
||
{{end}}
|
||
</div>
|
||
|
||
<div class="card">
|
||
<h2>Решение по бумагам ({{len .It.Securities}})</h2>
|
||
{{if $answered}}
|
||
<p class="muted">Решение уже отправлено {{if devOn}}роботу{{else}}контрагенту через НРД{{end}}. Ниже — что было выбрано по каждой бумаге.</p>
|
||
<table>
|
||
<thead><tr><th>ReferenceId</th><th>Код НРД / ISIN</th><th>Кол-во</th><th>Счёт зачисления</th><th>Решение</th></tr></thead>
|
||
<tbody>
|
||
{{range .It.Securities}}
|
||
<tr>
|
||
<td><code>{{.ReferenceID}}</code></td>
|
||
<td><code>{{.SecurityCode}}</code>{{if .ISIN}} / {{.ISIN}}{{end}}</td>
|
||
<td>{{.Quantity}}</td>
|
||
<td style="font-size:12px">{{if .DeponentCode}}депонент <code>{{.DeponentCode}}</code>{{end}}{{if .AccountID}}<br>счёт <code>{{.AccountID}}</code>{{end}}{{if .SectionID}} / раздел <code>{{.SectionID}}</code>{{end}}{{if .SettleINN}}<br>расч.деп. ИНН {{.SettleINN}}{{end}}</td>
|
||
<td>{{if eq .Decision "confirmed"}}<span class="badge confirmed">принято</span>{{else if eq .Decision "rejected"}}<span class="badge rejected">отказ</span> <span class="muted" style="font-size:12px">{{m2mCode .RejectCode}}</span>{{else}}—{{end}}</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
{{else}}
|
||
<p class="muted">По каждой бумаге выберите: <b>принять</b> (зачислим на наш депо-счёт из настроек НРД) или <b>отказать</b> (с кодом отказа). Решение уйдёт {{if devOn}}роботу{{else}}контрагенту через НРД{{end}} одним сообщением M2MTransferDecision.</p>
|
||
|
||
{{if devOn}}{{/* подсказки по сценариям робота НРД — только в режиме разработки */}}
|
||
<div style="padding:10px 14px;background:var(--accent-weak,#e7f0fb);border-radius:10px;margin:6px 0 14px">
|
||
<label style="font-size:13px;font-weight:600">Сценарий тестирования:
|
||
<select id="m2m-scen" style="margin-left:8px;padding:5px 8px;border-radius:7px;border:1px solid var(--border);background:var(--card);color:var(--text)">
|
||
<option value="">— выберите кейс —</option>
|
||
</select>
|
||
</label>
|
||
<div id="m2m-guide" style="margin-top:8px;font-size:13px;color:var(--text)">Выберите кейс — подскажу, что нужно сделать (принять или отклонить с кодом). Автоматически ничего не меняется.</div>
|
||
</div>
|
||
<script>
|
||
(function(){
|
||
var H = {{m2mHints}};
|
||
var sel = document.getElementById('m2m-scen'), g = document.getElementById('m2m-guide');
|
||
if(!sel||!Array.isArray(H)) return;
|
||
H.forEach(function(h){ var o=document.createElement('option'); o.value=h.id; o.textContent=h.title; sel.appendChild(o); });
|
||
sel.addEventListener('change', function(){
|
||
var h = null; for(var i=0;i<H.length;i++){ if(H[i].id===sel.value){h=H[i];break;} }
|
||
if(!h){ g.textContent='Выберите кейс — подскажу, что нужно сделать.'; return; }
|
||
var color = h.action==='confirm' ? '#1a7f37' : '#b3261e';
|
||
g.innerHTML = '<b style="color:'+color+'">Что делать: </b>'+h.text.replace(/</g,'<');
|
||
});
|
||
})();
|
||
</script>
|
||
{{end}}
|
||
|
||
<form method="post" action="/admin/incoming/{{.It.ID}}/answer">
|
||
<table>
|
||
<thead><tr><th>ReferenceId</th><th>Код НРД / ISIN</th><th>Кол-во</th><th>Счёт зачисления</th><th>Принять</th><th>Отказать</th><th>Код отказа</th></tr></thead>
|
||
<tbody>
|
||
{{range .It.Securities}}
|
||
<tr>
|
||
<td><code>{{.ReferenceID}}</code></td>
|
||
<td><code>{{.SecurityCode}}</code>{{if .ISIN}} / {{.ISIN}}{{end}}</td>
|
||
<td>{{.Quantity}}</td>
|
||
<td style="font-size:12px">{{if .DeponentCode}}депонент <code>{{.DeponentCode}}</code>{{end}}{{if .AccountID}}<br>счёт <code>{{.AccountID}}</code>{{end}}{{if .SectionID}} / раздел <code>{{.SectionID}}</code>{{end}}{{if .SettleINN}}<br>расч.деп. ИНН {{.SettleINN}}{{end}}</td>
|
||
<td style="text-align:center"><input type="radio" class="dec" data-ref="{{.ReferenceID}}" name="decision_{{.ReferenceID}}" value="confirm" checked></td>
|
||
<td style="text-align:center"><input type="radio" class="dec" data-ref="{{.ReferenceID}}" name="decision_{{.ReferenceID}}" value="reject"></td>
|
||
<td>
|
||
<span class="reject-dash" data-ref="{{.ReferenceID}}" style="color:var(--muted)">—</span>
|
||
<span class="reject-box" data-ref="{{.ReferenceID}}" style="display:none">
|
||
<select name="reject_{{.ReferenceID}}" style="max-width:280px">
|
||
{{range rejectOptions}}<option value="{{.Code}}">{{.Label}}</option>{{end}}
|
||
</select>
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
<p class="muted" style="font-size:12.5px;margin:10px 0 0">Пакет принимается только целиком: при отказе по одной бумаге отказ ставится всем бумагам с тем же кодом (так и будет отправлено).</p>
|
||
<div style="display:flex;gap:8px;margin-top:14px;flex-wrap:wrap">
|
||
<button type="submit" class="btn btn-ok">Отправить решение{{if devOn}} роботу{{end}}</button>
|
||
<button type="button" class="btn" onclick="m2mSetAll('confirm')">Принять все</button>
|
||
<button type="button" class="btn" onclick="m2mSetAll('reject')">Отказать все</button>
|
||
</div>
|
||
</form>
|
||
<script>
|
||
(function(){
|
||
function toggle(ref){
|
||
var rej = document.querySelector('input[name="decision_'+ref+'"][value="reject"]');
|
||
var box = document.querySelector('.reject-box[data-ref="'+ref+'"]');
|
||
var dash = document.querySelector('.reject-dash[data-ref="'+ref+'"]');
|
||
var show = rej && rej.checked;
|
||
if(box) box.style.display = show ? '' : 'none';
|
||
if(dash) dash.style.display = show ? 'none' : '';
|
||
}
|
||
document.querySelectorAll('input.dec').forEach(function(r){
|
||
r.addEventListener('change', function(){
|
||
toggle(r.getAttribute('data-ref'));
|
||
// Пакет целиком: отказ по одной бумаге — отказ по всем с тем же кодом.
|
||
if(r.value === 'reject' && r.checked){
|
||
var src = document.querySelector('select[name="reject_'+r.getAttribute('data-ref')+'"]');
|
||
document.querySelectorAll('input.dec[value="reject"]').forEach(function(o){
|
||
if(o.checked) return;
|
||
o.checked = true; toggle(o.getAttribute('data-ref'));
|
||
var sel = document.querySelector('select[name="reject_'+o.getAttribute('data-ref')+'"]');
|
||
if(sel && src) sel.value = src.value;
|
||
});
|
||
}
|
||
});
|
||
});
|
||
window.m2mSetAll = function(val){
|
||
document.querySelectorAll('input.dec[value="'+val+'"]').forEach(function(r){
|
||
r.checked = true; toggle(r.getAttribute('data-ref'));
|
||
});
|
||
};
|
||
})();
|
||
</script>
|
||
<script>
|
||
// Подставляем рекомендацию сверки с DEPO в форму: только предзаполнение,
|
||
// отправка — по кнопке оператора.
|
||
(function(){
|
||
var recs = document.querySelectorAll('.depo-rec');
|
||
if(!recs.length) return;
|
||
recs.forEach(function(el){
|
||
var ref = el.getAttribute('data-ref'), rec = el.getAttribute('data-rec'), code = el.getAttribute('data-code');
|
||
var r = document.querySelector('input[name="decision_'+ref+'"][value="'+rec+'"]');
|
||
if(r){ r.checked = true; r.dispatchEvent(new Event('change')); }
|
||
if(rec === 'reject' && code){
|
||
var sel = document.querySelector('select[name="reject_'+ref+'"]');
|
||
if(sel) sel.value = code;
|
||
}
|
||
});
|
||
})();
|
||
</script>
|
||
{{end}}
|
||
</div>
|
||
|
||
{{if .It.RawXML}}
|
||
<div class="card">
|
||
<details>
|
||
<summary style="cursor:pointer;font-weight:600">Данные запроса — поля и сырой XML</summary>
|
||
<p class="muted" style="font-size:12px;margin:6px 0">Слева — те же данные из XML, разобранные по полям для удобного просмотра; ниже — исходный XML дословно.</p>
|
||
{{xmlFields .It.RawXML}}
|
||
<div style="margin-top:12px;font-weight:600;font-size:13px">Сырой XML:</div>
|
||
<pre style="white-space:pre-wrap;word-break:break-all;background:var(--surface-2,#f5f5f7);padding:12px;border-radius:8px;font-size:12px;overflow:auto;max-height:340px;margin-top:4px">{{.It.RawXML}}</pre>
|
||
</details>
|
||
</div>
|
||
{{end}}
|
||
|
||
<div class="card">
|
||
<style>
|
||
.ord-steps{display:flex;gap:12px;margin:12px 0 14px;flex-wrap:wrap}
|
||
.ord-step{flex:1 1 190px;display:flex;gap:12px;align-items:flex-start;padding:14px 16px;border-radius:13px;border:2px solid var(--border);background:var(--card)}
|
||
.ord-step .dot{width:30px;height:30px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;font-size:15px;font-weight:800;background:var(--border);color:var(--muted)}
|
||
.ord-step .t{font-size:14px;font-weight:700;line-height:1.2}
|
||
.ord-step .s{font-size:11.5px;margin-top:3px;font-weight:600;color:var(--muted)}
|
||
.ord-step.done{border-color:#16a34a;background:color-mix(in srgb,#16a34a 13%,var(--card))}
|
||
.ord-step.done .dot{background:#16a34a;color:#fff}
|
||
.ord-step.done .s{color:#0f7a37}
|
||
.ord-step.wait{border-color:#f59e0b;background:color-mix(in srgb,#f59e0b 15%,var(--card))}
|
||
.ord-step.wait .dot{background:#f59e0b;color:#fff;box-shadow:0 0 0 4px color-mix(in srgb,#f59e0b 28%,transparent)}
|
||
.ord-step.wait .s{color:#b45309}
|
||
.ord-step.todo{opacity:.55}
|
||
.ord-step.bad{border-color:#dc2626;background:color-mix(in srgb,#dc2626 12%,var(--card))}
|
||
.ord-step.bad .dot{background:#dc2626;color:#fff}
|
||
.ord-step.bad .s{color:#b3261e}
|
||
.ord-dl.bad{border-color:#dc2626;color:#b3261e}
|
||
.ord-dl{display:inline-block;margin-top:9px;font-size:11.5px;font-weight:700;padding:4px 10px;border-radius:8px;background:var(--card);border:1px solid #16a34a;color:#0f7a37;text-decoration:none;white-space:nowrap}
|
||
.ord-dl:hover{background:color-mix(in srgb,#16a34a 12%,var(--card))}
|
||
</style>
|
||
|
||
{{if .Rejected}}
|
||
<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap">
|
||
<h2 style="margin:0">Депозитарное поручение 16/1</h2>
|
||
<span class="badge rejected">не требуется — перевод отклонён</span>
|
||
</div>
|
||
<div class="ord-steps">
|
||
<div class="ord-step bad">
|
||
<span class="dot">✕</span>
|
||
<div><div class="t">Операция завершена отказом</div>
|
||
<div class="s">Отказ {{.RejectCodes}}{{with .RejectCodes}} ({{m2mCode .}}){{end}} отправлен {{msk .It.AnsweredAt}}{{if .It.Auto}} автоматически{{end}}. Бумаги не зачисляются, поручение 16/1 не подаётся — со стороны депозитария действий не требуется.</div></div>
|
||
</div>
|
||
</div>
|
||
{{else}}
|
||
<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap">
|
||
<h2 style="margin:0">Депозитарное поручение 16/1</h2>
|
||
{{if .OrderDone}}<span class="badge confirmed">проведено · MS010</span>
|
||
{{else if .It.OrderSubmitted}}<span class="badge awaiting_decision">подано, ждём MS010</span>
|
||
{{else if not $answered}}<span class="badge" style="background:var(--card-2);color:var(--muted)">после решения по переводу</span>
|
||
{{else if .AutoMode}}<span class="badge awaiting_decision">подаст bj автоматически</span>
|
||
{{else}}<span class="badge" style="background:var(--card-2);color:var(--muted)">не подано</span>{{end}}
|
||
</div>
|
||
{{if .Watch}}<div style="margin:8px 0 0;padding:8px 12px;border-radius:9px;font-size:13px;font-weight:600;{{if eq .Watch.Kind "ok"}}background:color-mix(in srgb,#16a34a 12%,var(--card));color:#0f7a37{{else if eq .Watch.Kind "warn"}}background:color-mix(in srgb,#d97706 14%,var(--card));color:#9a6b12{{else if eq .Watch.Kind "bad"}}background:color-mix(in srgb,#dc2626 12%,var(--card));color:#b3261e{{else}}background:var(--card-2);color:var(--muted){{end}}">⏱ Срок по регламенту: {{.Watch.StatusRu}}</div>{{end}}
|
||
|
||
|
||
<div class="ord-steps">
|
||
<div class="ord-step {{if .DraftReceived}}done{{else if $answered}}wait{{else}}todo{{end}}">
|
||
<span class="dot">{{if .DraftReceived}}✓{{else}}1{{end}}</span>
|
||
<div><div class="t">Черновик получен</div><div class="s">{{if .DraftReceived}}{{.DraftReceived}}{{else if $answered}}ждём черновик MF010 от НРД{{else}}после нашего согласия{{end}}</div>
|
||
{{if .DraftReceived}}<a class="ord-dl" href="/admin/incoming/{{.It.ID}}/draft.zip">⬇ Черновик от НРД</a>{{end}}</div>
|
||
</div>
|
||
<div class="ord-step {{if .It.OrderSubmitted}}done{{else if .DraftReceived}}wait{{else}}todo{{end}}">
|
||
<span class="dot">{{if .It.OrderSubmitted}}✓{{else}}2{{end}}</span>
|
||
<div><div class="t">Поручение подано в НРД</div><div class="s">{{if .It.OrderSubmitted}}{{msk .It.OrderAt}}{{else if .AutoMode}}bj подаст автоматически по черновику{{else if .DraftReceived}}нужно подать{{else}}после черновика{{end}}</div>
|
||
{{if .It.OrderXML}}<a class="ord-dl" href="/admin/incoming/{{.It.ID}}/order.xml">⬇ Отправленная форма 16/1</a>{{end}}</div>
|
||
</div>
|
||
<div class="ord-step {{if and .OrderDone .OrderRejected}}bad{{else if .OrderDone}}done{{else if .It.OrderSubmitted}}wait{{else}}todo{{end}}">
|
||
<span class="dot">{{if and .OrderDone .OrderRejected}}✕{{else if .OrderDone}}✓{{else}}3{{end}}</span>
|
||
<div><div class="t">{{if and .OrderDone .OrderRejected}}Операция завершена отказом · MS010{{else}}Проведено · MS010{{end}}</div><div class="s">{{if and .OrderDone .OrderRejected}}НРД отказал в исполнении{{if .OrderDoneAt}} · {{.OrderDoneAt}}{{end}}{{else if .OrderDone}}{{if .OrderDoneAt}}{{.OrderDoneAt}}{{else}}отчёт получен от НРД{{end}}{{else if .It.OrderSubmitted}}ждём MS010 от НРД{{else}}после подачи{{end}}</div>
|
||
{{if .OrderResponses}}<a class="ord-dl" href="/admin/incoming/{{.It.ID}}/ms010.zip">⬇ Ответ НРД (MS010)</a>{{end}}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center">
|
||
{{if and (not .It.OrderSubmitted) .DraftReceived}}
|
||
<form method="post" action="/admin/incoming/{{.It.ID}}/submit-order" onsubmit="return confirm('Подать поручение 16/1 (тип ЭД ORDXM) в НРД (TEST3)?');">
|
||
<button type="submit" class="btn btn-ok">▶ Подать поручение 16/1 в НРД</button>
|
||
</form>
|
||
{{end}}
|
||
</div>
|
||
|
||
{{if .It.OrderSubmitted}}
|
||
<div class="muted" style="font-size:12px;margin-top:10px">Подано {{msk .It.OrderAt}} · пакет ИШ <code>{{.It.OrderPkgs}}</code>{{if .It.OrderContrDID}} · № поручения <code>{{.It.OrderContrDID}}</code>{{end}}</div>
|
||
{{if .OrderResponses}}
|
||
<table style="margin-top:8px">
|
||
<thead><tr><th style="width:150px">Время</th><th>Ответ НРД</th></tr></thead>
|
||
<tbody>
|
||
{{range .OrderResponses}}<tr><td style="white-space:nowrap">{{.Time}}</td><td{{if .Rejected}} style="color:#b3261e;font-weight:600"{{end}}>{{.Kind}}</td></tr>{{end}}
|
||
</tbody>
|
||
</table>
|
||
{{else}}
|
||
<p class="muted" style="font-size:12px;margin-top:8px">Ответ НРД (квитанция → принятие → отчёт MS010) появится здесь. Обновите страницу.</p>
|
||
{{end}}
|
||
{{if .It.OrderXML}}
|
||
<details style="margin-top:8px"><summary style="cursor:pointer;font-size:12px;color:var(--muted)">Посмотреть отправленный XML поручения</summary>
|
||
<pre style="white-space:pre-wrap;word-break:break-all;background:var(--card-2);padding:12px;border-radius:8px;font-size:12px;overflow:auto;max-height:300px;margin-top:6px">{{.It.OrderXML}}</pre>
|
||
</details>
|
||
{{end}}
|
||
{{end}}
|
||
|
||
<details style="margin-top:12px"><summary style="cursor:pointer;font-size:12px;color:var(--muted)">Как это работает</summary>
|
||
<p class="muted" style="font-size:12px;margin-top:6px">После нашего согласия на прием НРД формирует <b>черновик поручения 16/1</b> (MF010). Депозитарий подаёт его в НРД (тип ЭД <code>ORDXM</code>) — НРД сматчит со встречным поручением 16 контрагента, проведёт зачисление и выпустит отчёт <code>XMLRP</code> = <b>MS010</b>. Кнопка «Подать» отправляет черновик через ИШ (подпись ГОСТ ставит ИШ); пока Fancy-DEPO не подключена, можно скачать черновик и обработать вручную.</p>
|
||
</details>
|
||
{{end}}
|
||
</div>
|
||
|
||
|
||
<p style="margin-top:16px">
|
||
<a href="/admin/incoming" class="muted">← Все входящие</a>
|
||
·
|
||
<a href="/admin/incoming/{{.It.ID}}/export.zip" class="btn">⬇ Выгрузка для регулятора (ZIP: отчёт + request.xml + decision.xml)</a>
|
||
</p>
|
||
|
||
<aside class="in-tl">
|
||
<h3>Путь сообщения</h3>
|
||
<div class="st st-req">
|
||
<div class="tm">{{msk .It.RequestCreated}}</div>
|
||
<div class="ti">Запрос сформирован</div>
|
||
<div class="de">отправитель (контрагент)</div>
|
||
</div>
|
||
<div class="st st-gw">
|
||
<div class="tm">{{msk .It.ReceivedAt}}</div>
|
||
<div class="ti">Получено нами</div>
|
||
<div class="de">забрали из шлюза ИШ{{if not .It.RequestCreated.IsZero}} · прохождение {{transit .It.RequestCreated .It.ReceivedAt}}{{end}}</div>
|
||
</div>
|
||
{{if .DraftReceived}}
|
||
<div class="st st-gw">
|
||
<div class="tm">{{.DraftReceived}}</div>
|
||
<div class="ti">Черновик 16/1 получен</div>
|
||
<div class="de">НРД прислал MF010 в INBOX</div>
|
||
</div>
|
||
{{end}}
|
||
{{if $answered}}
|
||
<div class="st st-resp">
|
||
<div class="tm">{{msk .It.AnsweredAt}}</div>
|
||
<div class="ti">Ответ отправлен{{if .It.Auto}} (авто){{end}}</div>
|
||
<div class="de">M2MTransferDecision{{if not .It.ReceivedAt.IsZero}} · {{transit .It.ReceivedAt .It.AnsweredAt}}{{end}}</div>
|
||
</div>
|
||
{{end}}
|
||
{{if .It.OrderSubmitted}}
|
||
<div class="st st-ord">
|
||
<div class="tm">{{msk .It.OrderAt}}</div>
|
||
<div class="ti">Поручение 16/1 подано</div>
|
||
<div class="de">тип ORDXM · пакет ИШ {{.It.OrderPkgs}}</div>
|
||
</div>
|
||
{{end}}
|
||
{{range .OrderResponses}}
|
||
<div class="st st-nrd">
|
||
<div class="tm">{{.Time}}</div>
|
||
<div class="ti">Ответ НРД</div>
|
||
<div class="de"{{if .Rejected}} style="color:#b3261e;font-weight:600"{{end}}>{{.Kind}}</div>
|
||
</div>
|
||
{{end}}
|
||
</aside>
|
||
|
||
{{/* ===== QUIK МНП: зачисление клиенту ===== */}}
|
||
{{$back := printf "/admin/incoming/%s" .It.ID}}
|
||
|
||
{{if devOn}}{{/* прогон копии в DEPO — служебный инструмент режима разработки */}}
|
||
<div class="card">
|
||
<h2 style="margin:0">Тестовый прогон в DEPO с реальным клиентом</h2>
|
||
<p class="muted" style="font-size:12.5px;margin:6px 0 8px">Копия этого входящего (те же бумаги и решения) записывается в трансферные таблицы DEPO под новым GUID на реального клиента из картотеки — по паспорту. Джоба bj2depo создаёт по нему документ; в НРД ничего не уходит. Полный сценарий приёма: получен → приняли → подали 16/1 → НРД принял → исполнено.</p>
|
||
<form method="post" action="/admin/incoming/depo-sim" style="display:flex;gap:8px;flex-wrap:wrap;align-items:center" onsubmit="return confirm('Записать копию перевода в трансферные таблицы DEPO на клиента с этим паспортом?')">
|
||
<input type="hidden" name="id" value="{{.It.ID}}">
|
||
<label style="margin:0;font-size:12.5px">серия <input type="text" name="ser" value="" placeholder="0000" required style="width:70px"></label>
|
||
<label style="margin:0;font-size:12.5px">номер <input type="text" name="num" value="" placeholder="000000" required style="width:90px"></label>
|
||
<button type="submit" class="btn">🗂 Прогнать в DEPO с реальным клиентом</button>
|
||
<span class="muted" style="font-size:12px">паспорт клиента из картотеки DEPO</span>
|
||
</form>
|
||
</div>
|
||
{{end}}
|
||
<div class="card">
|
||
<style>
|
||
.qk-steps{display:flex;gap:8px;flex-wrap:wrap;margin:8px 0}
|
||
.qk-step{padding:6px 10px;border-radius:9px;border:1.5px solid var(--border);font-size:12.5px;background:var(--card-2)}
|
||
.qk-step.ok{border-color:color-mix(in srgb,#16a34a 45%,transparent);background:color-mix(in srgb,#16a34a 12%,var(--card));color:#0f7a37;font-weight:600}
|
||
.qk-step.bad{border-color:color-mix(in srgb,#dc2626 45%,transparent);background:color-mix(in srgb,#dc2626 10%,var(--card));color:#b3261e;font-weight:600}
|
||
.qk-state{display:inline-block;padding:3px 10px;border-radius:999px;font-size:12px;font-weight:700}
|
||
.qk-state.registered{background:color-mix(in srgb,#d97706 15%,var(--card));color:#9a6b12}
|
||
.qk-state.signed,.qk-state.deposited{background:color-mix(in srgb,#16a34a 15%,var(--card));color:#0f7a37}
|
||
.qk-state.denied{background:var(--card-2);color:var(--muted)}
|
||
.qk-state.error{background:color-mix(in srgb,#dc2626 15%,var(--card));color:#b3261e}
|
||
.qk-state.manual{background:color-mix(in srgb,#2563eb 12%,var(--card));color:#1d4ed8}
|
||
</style>
|
||
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap">
|
||
<h2 style="margin:0">QUIK МНП — зачисление бумаг клиенту</h2>
|
||
<a href="/admin/quik" class="muted" style="font-size:12px">все поручения →</a>
|
||
</div>
|
||
{{if .DepoL}}<div style="margin:8px 0 0;padding:8px 12px;border-radius:9px;font-size:13px;{{if .DepoL.Errors}}background:color-mix(in srgb,#dc2626 12%,var(--card));color:#b3261e{{else}}background:var(--card-2){{end}}">🗂 DEPO (bj2depo): {{if .DepoL.DocNo}}поручение <b>№{{.DepoL.DocNo}}</b> создано {{msk .DepoL.DocAt}}{{if .DepoL.DocState}} · состояние в DEPO: <b>{{.DepoL.DocState}}</b>{{end}}{{else}}поручение ещё не создано{{end}}{{range .DepoL.Errors}}<div>ошибка: {{.}}</div>{{end}}</div>{{end}}
|
||
{{if .Rejected}}
|
||
<p class="muted" style="font-size:12.5px;margin:10px 0 0">Зачисление в QUIK не требуется — перевод отклонён ({{.RejectCodes}}), бумаги клиенту не поступают.</p>
|
||
{{else}}
|
||
|
||
<p class="muted" style="font-size:12.5px;margin:6px 0 0">Когда НРД принимает наше поручение 16/1 (отчёт MS010), bj регистрирует в Модуле неторговых поручений «Ввод ЦБ (M2M)» по ISIN — оно исполняется сразу, бумаги появляются на позиции клиента в QUIK.{{if not .QuikOn}} <b>Записи в МНП сейчас выключены</b> (Настройка → QUIK МНП).{{end}}</p>
|
||
{{if not .Quik}}<div style="margin-top:8px;display:flex;gap:8px;flex-wrap:wrap;align-items:center"><span class="muted">Зачислений по этому переводу ещё нет.</span>
|
||
{{range .It.Securities}}{{if eq .Decision "confirmed"}}
|
||
<form method="post" action="/admin/quik/op" style="margin:0;display:inline"><input type="hidden" name="guid" value="{{$.It.GUID}}"><input type="hidden" name="isin" value="{{.ISIN}}"><input type="hidden" name="op" value="deposit"><input type="hidden" name="back" value="{{$back}}"><button class="btn" style="font-size:12px" onclick="return confirm('Зачислить {{.ISIN}} × {{.Quantity}} клиенту в QUIK? Исполняется сразу.')">⊕ Зачислить {{.ISIN}} × {{.Quantity}}</button></form>
|
||
{{end}}{{end}}</div>{{end}}
|
||
|
||
{{range .Quik}}
|
||
<div style="border:1px solid var(--border);border-radius:10px;padding:10px 12px;margin-top:10px">
|
||
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap">
|
||
<b><code>{{.ISIN}}</code> × {{.Qty}}</b>
|
||
<span class="muted" style="font-size:12px">клиент QUIK <code>{{.ClientID}}</code>{{if .Contract}} · {{.Contract}}{{end}}{{if .InstrNo}} · поручение МНП <b>№{{.InstrNo}}</b>{{end}}</span>
|
||
<span class="qk-state {{.State}}">{{.StateRu}}</span>
|
||
</div>
|
||
{{if .Err}}<div style="color:#b3261e;font-size:12.5px;margin-top:4px">{{.Err}}</div>{{end}}
|
||
{{if .Steps}}<div class="qk-steps">{{range .Steps}}<span class="qk-step {{if .OK}}ok{{else}}bad{{end}}" title="{{.Reply}}">{{msk .At}} · {{.Action}}{{if .ActionID}} #{{.ActionID}}{{end}}: {{.Reply}}</span>{{end}}</div>{{end}}
|
||
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:6px">
|
||
{{if or (eq .State "error") (eq .State "manual") (not .InstrNo)}}
|
||
<form method="post" action="/admin/quik/op" style="margin:0;display:inline"><input type="hidden" name="guid" value="{{.GUID}}"><input type="hidden" name="isin" value="{{.ISIN}}"><input type="hidden" name="op" value="deposit"><input type="hidden" name="back" value="{{$back}}"><button class="btn btn-ok" style="font-size:12px" onclick="return confirm('Зачислить бумаги клиенту в QUIK («Ввод ЦБ (M2M)»)? Исполняется сразу.')">⊕ Зачислить в QUIK</button></form>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
{{end}}
|
||
</div>
|
||
{{end}}
|