Files
Bridge-and-Join-s/internal/lkgateway/web/templates/admin_claim.html
T
zuevav b4b4788035 Баннер режима разработки в шапке с личным выключателем
Пока лицензия разрешает режим разработки, в шапке висит баннер; нажатие выключает режим визуально для этого пользователя и включает обратно. В шаблонах .DevMode заменён на devOn.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
2026-09-18 11:18:27 +03:00

358 lines
26 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>
/* Основной контент — в обычном потоке (широкий, по центру). Таймлайн —
отдельной узкой панелью, прижатой к правому краю экрана (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 devOn}}{{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}}