e4de1ab4d8
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
358 lines
26 KiB
HTML
358 lines
26 KiB
HTML
{{define "content"}}
|
||
<style>
|
||
/* Основной контент — в обычном потоке (широкий, по центру). Таймлайн —
|
||
отдельной узкой панелью, прижатой к правому краю экрана (fixed) на широких
|
||
мониторах; на узких уходит под контент. */
|
||
.claim-grid { display:block }
|
||
.claim-main { min-width:0 }
|
||
.claim-tl { position: fixed; right: 18px; top: 84px; width: 216px; 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; }
|
||
.claim-tl h3 { margin:0 0 12px; font-size:13px }
|
||
.tl-step { position:relative; padding:0 0 2px 20px }
|
||
.tl-step::before { content:''; position:absolute; left:3px; top:3px; width:10px; height:10px; border-radius:50%;
|
||
background:var(--c); box-shadow:0 0 0 3px color-mix(in srgb, var(--c) 20%, transparent); }
|
||
.tl-time { font-size:10.5px; color:var(--muted,#888); font-variant-numeric:tabular-nums }
|
||
.tl-title { font-size:12.5px; font-weight:600; margin:1px 0; line-height:1.3 }
|
||
.tl-detail { font-size:10.5px; color:var(--muted,#888); line-height:1.4; margin-top:2px }
|
||
/* стрелка-коннектор: вертикальная линия + ровный CSS-треугольник + длительность */
|
||
.tl-arrow { position:relative; min-height:20px; margin:1px 0 1px 0; padding-left:20px; display:flex; align-items:center }
|
||
.tl-arrow .ln { position:absolute; left:7px; top:0; width:2px; height:20px; background:var(--c); opacity:.5 }
|
||
.tl-arrow .ar { position:absolute; left:3px; top:11px; width:0; height:0;
|
||
border-left:5px solid transparent; border-right:5px solid transparent; border-top:7px solid var(--c) }
|
||
.tl-arrow .dt { font-size:10.5px; color:var(--muted,#999) }
|
||
.tl-db{--c:#2563eb} .tl-crane{--c:#16a34a} .tl-gateway{--c:#7c3aed} .tl-response{--c:#0891b2} .tl-reject{--c:#dc2626}
|
||
/* нет места справа (узкие/средние экраны) — таймлайн в потоке под контентом */
|
||
@media (max-width:1640px){ .claim-tl{ position:static; width:auto; max-height:none; margin-top:16px; box-shadow:none } }
|
||
</style>
|
||
<div class="claim-grid">
|
||
<div class="claim-main">
|
||
<p style="margin:0 0 12px"><a href="/admin/claims" class="btn" onclick="if(history.length>1){history.back();return false}">← Назад</a></p>
|
||
{{if .Flash}}<div class="card" style="background:var(--accent-weak,#e7f0fb)">{{.Flash}}</div>{{end}}
|
||
<div class="card">
|
||
<h2>Заявка <code>{{slice .Claim.ID 0 8}}</code> · <span class="badge {{.Claim.Status}}">{{ruState .Claim.Status}}</span></h2>
|
||
<table>
|
||
<tr><td style="width:200px" class="muted">Создана</td><td>{{.Claim.CreatedAt.Format "02.01.2006 15:04:05"}}</td></tr>
|
||
<tr><td class="muted">Обновлена</td><td>{{.Claim.UpdatedAt.Format "02.01.2006 15:04:05"}}</td></tr>
|
||
<tr><td class="muted">M2M GUID</td><td><code>{{.Claim.M2MGUID}}</code></td></tr>
|
||
<tr><td class="muted">Инвестор</td><td>{{.Claim.Investor.LastName}} {{.Claim.Investor.FirstName}} {{.Claim.Investor.MiddleName}}</td></tr>
|
||
<tr><td class="muted">Документ</td><td>тип {{.Claim.Investor.Document.DocumentType}}, серия {{.Claim.Investor.Document.Series}}, номер {{.Claim.Investor.Document.Number}}</td></tr>
|
||
<tr><td class="muted">Передающий депозитарий</td><td><code>ИНН {{.Claim.TransferringDepositoryINN}}</code></td></tr>
|
||
<tr><td class="muted">Принимающий депозитарий</td><td><code>ИНН {{.Claim.ReceivingDepositoryINN}}</code></td></tr>
|
||
{{if .Claim.IIAAgreement}}
|
||
<tr><td class="muted">ИИС</td><td>{{.Claim.IIAAgreement.AgreementType}} № {{.Claim.IIAAgreement.AgreementNumber}} от {{.Claim.IIAAgreement.AgreementDate}}, брокер ИНН {{.Claim.IIAAgreement.BrokerINN}}</td></tr>
|
||
{{end}}
|
||
</table>
|
||
<div style="margin-top:14px">
|
||
<a class="btn btn-ok" href="/admin/claims/{{.Claim.ID}}/export.zip" download>⤓ Выгрузить путь заявки (для регулятора)</a>
|
||
</div>
|
||
<p class="muted" style="font-size:12px;margin-top:8px">ZIP: отчёт-доказательство (хронология пути) + дословные XML запроса и ответа НРД (windows-1251).</p>
|
||
{{if .Claim.Investor.ID}}
|
||
<form method="get" action="/admin/claims-export" style="margin-top:14px;padding-top:14px;border-top:1px solid var(--border);display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end">
|
||
<input type="hidden" name="investor" value="{{.Claim.Investor.ID}}">
|
||
<div><label style="font-size:12px">Заявки клиента с</label><input type="date" name="from" style="margin-top:3px"></div>
|
||
<div><label style="font-size:12px">по</label><input type="date" name="to" style="margin-top:3px"></div>
|
||
<button type="submit" class="btn">⤓ Выгрузить за период</button>
|
||
<span class="muted" style="font-size:12px">Пусто = без ограничения. ZIP: сводка CSV + комплект по каждой заявке.</span>
|
||
</form>
|
||
{{end}}
|
||
</div>
|
||
|
||
{{if .DevMode}}{{with .Claim.TestResult}}
|
||
<div class="card" style="background:{{if eq .Status "ok"}}var(--ok-weak){{else if eq .Status "mismatch"}}var(--err-weak){{else if eq .Status "error"}}var(--err-weak){{else}}var(--warn-weak){{end}}">
|
||
<h2>
|
||
{{if eq .Status "ok"}}<span style="color:var(--ok)">✓ Тест пройден</span>
|
||
{{else if eq .Status "mismatch"}}<span style="color:var(--err)">Результат не совпал</span>
|
||
{{else if eq .Status "error"}}<span style="color:var(--err)">Ошибка сервиса НРД</span>
|
||
{{else}}<span style="color:var(--warn)">⏳ Ожидание ответа</span>{{end}}
|
||
· сценарий {{.Scenario}} «{{.Title}}»
|
||
</h2>
|
||
<table>
|
||
<tr><td style="width:200px" class="muted">Ожидали</td><td>{{.Expected}}</td></tr>
|
||
<tr><td class="muted">Получили</td><td><b>{{.Got}}</b></td></tr>
|
||
{{if .Note}}<tr><td class="muted">Вывод</td><td>{{.Note}}</td></tr>{{end}}
|
||
</table>
|
||
</div>
|
||
{{end}}{{end}}
|
||
|
||
<div class="card">
|
||
<h2>Ценные бумаги ({{len .Claim.Securities}})</h2>
|
||
<table>
|
||
<thead><tr><th>Код</th><th>ISIN / описание</th><th>Количество</th><th>Счетов депо</th></tr></thead>
|
||
<tbody>
|
||
{{range .Claim.Securities}}
|
||
<tr>
|
||
<td><code>{{.SecurityCode}}</code></td>
|
||
<td>{{if .SecurityDetails.ISIN}}<code>{{.SecurityDetails.ISIN}}</code>{{else if .SecurityDetails.SecurityInfo}}{{.SecurityDetails.SecurityInfo.Classification}} / {{.SecurityDetails.SecurityInfo.Category}}{{if .SecurityDetails.SecurityInfo.IdentificationDetails.FundShares}} · ПИФ {{.SecurityDetails.SecurityInfo.IdentificationDetails.FundShares.RegNumber}} класс {{.SecurityDetails.SecurityInfo.IdentificationDetails.FundShares.Class}}{{end}}{{end}}</td>
|
||
<td>{{if .Quantity.Whole}}{{.Quantity.Whole}}{{else}}{{.Quantity.Fractional}}{{end}}</td>
|
||
<td>{{len .SettlementAccounts}}</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
|
||
{{/* ===== QUIK МНП: поручение «Вывод ЦБ (M2M)» ===== */}}
|
||
{{$back := printf "/admin/claims/%s" .Claim.ID}}
|
||
<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}}
|
||
|
||
<p class="muted" style="font-size:12.5px;margin:6px 0 0">При отправке в НРД bj регистрирует в Модуле неторговых поручений «Вывод ЦБ (M2M)» — QUIK блокирует бумаги на позиции клиента. Отказ контрагента или НРД → поручение снимается с причиной (клиент видит её в терминале). Приём НРД нашего поручения 16 → подпись депозитария, бумаги списываются.</p>
|
||
{{if not .Quik}}<p class="muted" style="margin-top:10px">Поручений МНП по этой заявке нет{{if .Claim.M2MGUID}} — можно зарегистрировать вручную:
|
||
<form method="post" action="/admin/quik/op" style="margin:6px 0 0;display:flex;gap:8px;flex-wrap:wrap;align-items:center">
|
||
<input type="hidden" name="guid" value="{{.Claim.M2MGUID}}"><input type="hidden" name="op" value="register"><input type="hidden" name="back" value="{{$back}}">
|
||
<select name="isin" style="font-size:12.5px">{{range .Claim.Securities}}<option value="{{.SecurityDetails.ISIN}}">{{.SecurityDetails.ISIN}} — {{.SecurityCode}}</option>{{end}}</select>
|
||
<button class="btn" style="font-size:12px" onclick="return confirm('Зарегистрировать «Вывод ЦБ (M2M)» в QUIK? Бумаги будут заблокированы.')">⊕ Зарегистрировать в QUIK</button>
|
||
<span class="muted" style="font-size:12px">или привязать поручение, поданное клиентом из терминала:</span>
|
||
<input type="text" name="instr_no" placeholder="№ поручения" style="font-size:12px;width:130px" form="qk-link">
|
||
</form>
|
||
<form id="qk-link" method="post" action="/admin/quik/op" style="margin:4px 0 0"><input type="hidden" name="guid" value="{{.Claim.M2MGUID}}"><input type="hidden" name="op" value="link"><input type="hidden" name="back" value="{{$back}}"><select name="isin" style="font-size:12.5px">{{range .Claim.Securities}}<option value="{{.SecurityDetails.ISIN}}">{{.SecurityDetails.ISIN}}</option>{{end}}</select> <button class="btn" style="font-size:12px">⛓ Привязать</button></form>{{end}}</p>{{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 eq .State "registered"}}
|
||
<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="sign"><input type="hidden" name="back" value="{{$back}}"><button class="btn btn-ok" style="font-size:12px" onclick="return confirm('Подписать поручение МНП №{{.InstrNo}}? Бумаги будут СПИСАНЫ с позиции клиента в QUIK.')">✎ Подписать (исполнить)</button></form>
|
||
<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="deny"><input type="hidden" name="back" value="{{$back}}"><input type="text" name="reason" placeholder="причина для клиента" style="font-size:12px;width:200px"><button class="btn" style="font-size:12px" onclick="return confirm('Снять поручение №{{.InstrNo}}? Блокировка в QUIK будет снята, клиент увидит причину.')">✕ Снять</button></form>
|
||
{{else 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="register"><input type="hidden" name="back" value="{{$back}}"><button class="btn" style="font-size:12px" onclick="return confirm('Зарегистрировать «Вывод ЦБ (M2M)» в QUIK? Бумаги будут заблокированы на позиции клиента.')">⊕ Зарегистрировать (заблокировать)</button></form>
|
||
<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="link"><input type="hidden" name="back" value="{{$back}}"><input type="text" name="instr_no" placeholder="№ поручения из QUIK" style="font-size:12px;width:150px"><button class="btn" style="font-size:12px">⛓ Привязать</button></form>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
{{if .Depo}}
|
||
<div class="card">
|
||
<style>
|
||
.ord-steps{display:flex;gap:12px;margin:14px 0 6px;flex-wrap:wrap}
|
||
.ord-step{flex:1 1 190px;position:relative;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-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>
|
||
<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap">
|
||
<h2 style="margin:0">Депозитарное поручение 16 (списание)</h2>
|
||
{{if .Depo.Done}}<span class="badge confirmed">проведено · MS010</span>
|
||
{{else if .Depo.Submitted}}<span class="badge awaiting_decision">подано, ждём MS010</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}}
|
||
|
||
<p class="muted" style="font-size:12.5px;margin:6px 0 0">Мы — списывающий депозитарий. НРД прислал черновик формы 16; подайте его — НРД сматчит со встречным 16/1 контрагента и пришлёт отчёт <b>MS010</b> о проведённом списании (бумага ушла контрагенту).</p>
|
||
|
||
<div class="ord-steps">
|
||
<div class="ord-step done">
|
||
<span class="dot">✓</span>
|
||
<div><div class="t">Черновик 16 получен</div><div class="s">{{msk .Depo.DraftAt}}</div>
|
||
<a class="ord-dl" href="/admin/outgoing/{{.Depo.GUID}}/draft.zip">⬇ Черновик от НРД</a></div>
|
||
</div>
|
||
<div class="ord-step {{if .Depo.Submitted}}done{{else}}wait{{end}}">
|
||
<span class="dot">{{if .Depo.Submitted}}✓{{else}}2{{end}}</span>
|
||
<div><div class="t">Поручение 16 подано</div><div class="s">{{if .Depo.Submitted}}{{msk .Depo.OrderAt}}{{else}}нужно подать в НРД{{end}}</div>
|
||
{{if .Depo.OrderXML}}<a class="ord-dl" href="/admin/outgoing/{{.Depo.GUID}}/order.xml">⬇ Отправленная форма 16</a>{{end}}</div>
|
||
</div>
|
||
<div class="ord-step {{if .Depo.Done}}done{{else if .Depo.Submitted}}wait{{else}}todo{{end}}">
|
||
<span class="dot">{{if .Depo.Done}}✓{{else}}3{{end}}</span>
|
||
<div><div class="t">Списание проведено · MS010</div><div class="s">{{if .Depo.Done}}отчёт получен от НРД{{else if .Depo.Submitted}}ждём встречный 16/1 + MS010{{else}}после подачи{{end}}</div>
|
||
{{if .Depo.Responses}}<a class="ord-dl" href="/admin/outgoing/{{.Depo.GUID}}/ms010.zip">⬇ Ответ НРД (MS010)</a>{{end}}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-top:8px">
|
||
{{if not .Depo.Submitted}}
|
||
<form method="post" action="/admin/outgoing/{{.Depo.GUID}}/submit-order?back=/admin/claims/{{.Claim.ID}}" onsubmit="return confirm('Подать поручение 16 (списание, тип ЭД ORDXM) в НРД?');">
|
||
<button type="submit" class="btn btn-ok">▶ Подать поручение 16 в НРД</button>
|
||
</form>
|
||
{{end}}
|
||
<a href="/admin/outgoing/{{.Depo.GUID}}/export.zip" class="btn">⬇ Выгрузка 16 для регулятора (весь пакет)</a>
|
||
</div>
|
||
|
||
{{if .Depo.Submitted}}
|
||
<div class="muted" style="font-size:12px;margin-top:10px">Подано {{msk .Depo.OrderAt}} · пакет ИШ <code>{{.Depo.Pkgs}}</code></div>
|
||
{{if .Depo.Responses}}
|
||
<table style="margin-top:8px">
|
||
<thead><tr><th style="width:150px">Время</th><th>Ответ НРД</th></tr></thead>
|
||
<tbody>{{range .Depo.Responses}}<tr><td style="white-space:nowrap">{{.Time}}</td><td>{{.Kind}}</td></tr>{{end}}</tbody>
|
||
</table>
|
||
{{else}}
|
||
<p class="muted" style="font-size:12px;margin-top:8px">Ответ НРД (квитанция → принятие → отчёт MS010 о списании) появится здесь. Обновите страницу.</p>
|
||
{{end}}
|
||
{{end}}
|
||
</div>
|
||
{{end}}
|
||
|
||
<div class="card">
|
||
<h2>История FSM</h2>
|
||
<table>
|
||
<thead><tr><th>Состояние</th><th>Вошли</th><th>Вышли</th><th>Причина</th></tr></thead>
|
||
<tbody>
|
||
{{range .Claim.Stages}}
|
||
<tr>
|
||
<td><span class="badge {{.State}}">{{ruState .State}}</span></td>
|
||
<td>{{.EnteredAt.Format "15:04:05.000"}}</td>
|
||
<td>{{if .LeftAt}}{{.LeftAt.Format "15:04:05.000"}}{{else}}<span class="muted">сейчас</span>{{end}}</td>
|
||
<td class="muted">{{.Reason}}</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
{{if .Claim.RequestRawXML}}
|
||
<div class="card">
|
||
<h2>Отправленный пакет (M2MTransferRequest)</h2>
|
||
<p class="muted">Точный XML, который bj-server сформировал и ИШ подписал ключом и отправил в НРД. Тип пакета <code>#M2MTR</code>.</p>
|
||
<a class="btn btn-ok" href="/admin/claims/{{.Claim.ID}}/request.xml" download style="margin-right:8px">⤓ Скачать XML запроса</a>
|
||
<button type="button" class="btn" onclick="copyReq(this)">Скопировать</button>
|
||
<pre id="raw-request" 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">{{.Claim.RequestRawXML}}</pre>
|
||
<script>
|
||
function copyReq(btn){
|
||
var t=document.getElementById('raw-request').innerText;
|
||
navigator.clipboard.writeText(t).then(function(){
|
||
var o=btn.textContent; btn.textContent='Скопировано ✓';
|
||
setTimeout(function(){btn.textContent=o;},1500);
|
||
});
|
||
}
|
||
</script>
|
||
</div>
|
||
{{end}}
|
||
|
||
{{if .Claim.M2MResponse}}
|
||
<div class="card">
|
||
<h2>Ответ сервиса МОСТ (M2MTransferResponse)</h2>
|
||
<p>
|
||
{{if eq .Claim.M2MResponse.StatusCode "ERROR"}}
|
||
<span class="badge err">● ERROR — заявка отклонена сервисом НРД</span>
|
||
{{else}}
|
||
<span class="badge ok">● {{.Claim.M2MResponse.StatusCode}} — принято в обработку</span>
|
||
{{end}}
|
||
</p>
|
||
<p class="muted">GUID <code>{{.Claim.M2MResponse.GUID}}</code></p>
|
||
<table>
|
||
<thead><tr><th>ReferenceID</th><th>Код</th><th>Текст ответа НРД</th></tr></thead>
|
||
<tbody>
|
||
{{range .Claim.M2MResponse.Responses}}
|
||
<tr><td><code>{{.ReferenceID}}</code></td><td><code>{{.Code}}</code></td><td>{{if .Text}}{{.Text}}{{else}}{{m2mCode .Code}}{{end}}</td></tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
{{if eq .Claim.M2MResponse.StatusCode "ERROR"}}
|
||
<p class="muted" style="margin-top:10px">
|
||
Это отказ на сервисном уровне — запрос не дошёл до контрагента. Решение
|
||
(M2MTransferDecision) по такой заявке не придёт. Устраните причину по коду
|
||
выше и отправьте новую заявку.
|
||
</p>
|
||
{{end}}
|
||
{{if .Claim.M2MResponse.RawXML}}
|
||
<details style="margin-top:12px">
|
||
<summary style="cursor:pointer;font-weight:600">
|
||
Сырой ответ НРД (для техподдержки M2MOST@nsd.ru)
|
||
</summary>
|
||
<p class="muted" style="margin:8px 0">
|
||
Точные байты ответа сервиса МОСТ. Можно дословно переслать в поддержку НРД.
|
||
</p>
|
||
<a class="btn btn-ok" href="/admin/claims/{{.Claim.ID}}/response.xml" download style="margin-right:8px">⤓ Скачать XML ответа</a>
|
||
<button type="button" class="btn" onclick="copyRaw(this)">Скопировать</button>
|
||
<pre id="raw-response" 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">{{.Claim.M2MResponse.RawXML}}</pre>
|
||
</details>
|
||
<script>
|
||
function copyRaw(btn){
|
||
var t=document.getElementById('raw-response').innerText;
|
||
navigator.clipboard.writeText(t).then(function(){
|
||
var o=btn.textContent; btn.textContent='Скопировано ✓';
|
||
setTimeout(function(){btn.textContent=o;},1500);
|
||
});
|
||
}
|
||
</script>
|
||
{{end}}
|
||
</div>
|
||
{{end}}
|
||
|
||
{{if .Claim.M2MDecision}}
|
||
<div class="card">
|
||
<h2>Решение принимающей стороны (M2MTransferDecision)</h2>
|
||
<p class="muted">GUID <code>{{.Claim.M2MDecision.GUID}}</code></p>
|
||
<table>
|
||
<thead><tr><th>ReferenceID</th><th>Решение</th><th>Коды отказа</th></tr></thead>
|
||
<tbody>
|
||
{{range .Claim.M2MDecision.Securities}}
|
||
<tr>
|
||
<td><code>{{.ReferenceID}}</code></td>
|
||
<td><span class="badge {{if eq .Outcome "confirmed"}}confirmed{{else}}rejected{{end}}">{{ruOutcome .Outcome}}</span></td>
|
||
<td>{{range .RejectCodes}}{{m2mCode .}}<br>{{end}}</td>
|
||
</tr>
|
||
{{end}}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{{end}}
|
||
|
||
{{if .Claim.LastCallback}}
|
||
<div class="card">
|
||
<h2>Последний callback в ЛК</h2>
|
||
<table>
|
||
<tr><td style="width:160px" class="muted">Статус</td><td><span class="badge {{.Claim.LastCallback.NewStatus}}">{{ruState .Claim.LastCallback.NewStatus}}</span></td></tr>
|
||
{{if .Claim.LastCallback.ReasonCode}}
|
||
<tr><td class="muted">Код причины</td><td><code>{{.Claim.LastCallback.ReasonCode}}</code> {{.Claim.LastCallback.ReasonText}}</td></tr>
|
||
{{end}}
|
||
<tr><td class="muted">Время</td><td>{{.Claim.LastCallback.UpdatedAt.Format "02.01.2006 15:04:05"}}</td></tr>
|
||
</table>
|
||
</div>
|
||
{{end}}
|
||
</div>{{/* /claim-main */}}
|
||
|
||
{{if .Claim.Timeline}}
|
||
<aside class="claim-tl">
|
||
<h3>Путь заявки</h3>
|
||
{{range $i, $e := .Claim.Timeline}}
|
||
{{if $i}}
|
||
<div class="tl-arrow tl-{{$e.Kind}}">
|
||
<span class="ln"></span><span class="ar"></span>
|
||
{{if $e.Since}}<span class="dt">через {{$e.Since}}</span>{{end}}
|
||
</div>
|
||
{{end}}
|
||
<div class="tl-step tl-{{$e.Kind}}">
|
||
<div class="tl-time">{{if $e.Time.IsZero}}ожидание{{else}}{{$e.Time.Format "02.01 15:04:05"}} МСК{{end}}</div>
|
||
<div class="tl-title">{{$e.Title}}</div>
|
||
{{if $e.Detail}}<div class="tl-detail">{{$e.Detail}}</div>{{end}}
|
||
</div>
|
||
{{end}}
|
||
</aside>
|
||
{{end}}
|
||
</div>{{/* /claim-grid */}}
|
||
{{end}}
|