Files

491 lines
42 KiB
Go
Raw Permalink 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.
package lk
// pageTemplates — встроенные страницы Личного кабинета (без внешних зависимостей,
// чтобы модуль был одним файлом и ставился на любой веб-сервер).
//
// Визуальный мир — «Табло» (см. DESIGN.md, раздел «Личный кабинет клиента»):
// графитовая доска состояния сверху, светлая бумага реестра, янтарь — «в пути»
// и первичное действие, все величины моноширинные табличные. Шрифты грузятся с
// Google Fonts, при недоступности сети подхватываются системные аналоги.
const pageTemplates = `
{{define "head"}}<!DOCTYPE html><html lang="ru"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{{.Title}}</title>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Golos+Text:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap">
<style>
:root{--paper:#edebe4;--sheet:#f7f5ef;--ink:#191a1c;--ink-2:#45403a;--mut:#6a6357;
--line:#ded8ca;--line-2:#c9c3b4;--board:#191a1c;--board-2:#1f2124;--board-3:#2b2d31;
--dim:#a49b8a;--amber:#e8a33d;--amber-bg:#f6e2c0;--amber-tx:#7a4e07;
--ok-bg:#dcefe2;--ok-tx:#1f6b3e;--err-bg:#f7dedb;--err-tx:#a32d22;--neu-bg:#e3e0d6;
--acc:#2c46c0;--mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
*{box-sizing:border-box}
body{margin:0;font-family:"Golos Text",system-ui,-apple-system,"Segoe UI",sans-serif;background:var(--paper);color:var(--ink);line-height:1.5}
a{color:var(--acc)}a:hover{color:#1e3395}
.lbl{font-family:var(--mono);font-size:10.5px;font-weight:500;letter-spacing:.1em;text-transform:uppercase}
.n{font-family:var(--mono);font-variant-numeric:tabular-nums}
.top{background:var(--board);color:#f3f0e7;padding:0 20px;min-height:58px;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.brand{display:flex;align-items:center;gap:10px;white-space:nowrap}
.top nav{display:flex;gap:2px;flex-grow:1;overflow-x:auto;scrollbar-width:none}
.top nav::-webkit-scrollbar{display:none}
.top nav a{color:var(--dim);text-decoration:none;padding:8px 12px;border-radius:3px;white-space:nowrap}
.top nav a:hover{background:var(--board-3);color:#f3f0e7}
.top nav a.on{background:var(--board-3);color:#f3f0e7}
.top .who{color:var(--dim);font-size:12px;white-space:nowrap}
.top .exit{color:var(--dim);text-decoration:none}
.cta{display:inline-flex;align-items:center;gap:8px;min-height:38px;padding:0 14px;background:var(--amber);color:var(--ink);text-decoration:none;border:0;border-radius:3px;cursor:pointer;font:inherit}
.cta:hover{filter:brightness(1.05);color:var(--ink)}
.board{background:var(--board-2);color:#f3f0e7;border-bottom:3px solid var(--amber);padding:22px 20px}
.board .big{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:40px;font-weight:700;letter-spacing:-.02em;line-height:1;position:relative;display:inline-block}
.board .big::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:rgba(0,0,0,.28)}
.board-row{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:20px;max-width:1180px;margin:0 auto}
.stats{display:flex;gap:28px;flex-wrap:wrap}
.stat{display:flex;flex-direction:column;gap:3px}
.stat .v{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:22px}
.imp{background:var(--board);color:#f3f0e7;padding:10px 20px;font-size:13px;display:flex;gap:10px;align-items:center;flex-wrap:wrap}
main{max-width:1180px;margin:0 auto;padding:22px 20px 34px}
h1{font-size:23px;margin:0 0 6px;letter-spacing:-.01em}h2{font-size:15px;margin:0 0 12px;letter-spacing:-.005em}
.sec{margin-bottom:28px}
.sec-h{display:flex;align-items:baseline;justify-content:space-between;gap:12px;margin-bottom:10px}
.tw{overflow-x:auto;-webkit-overflow-scrolling:touch}
table{width:100%;border-collapse:collapse;font-size:14px}
th{font-family:var(--mono);font-size:10.5px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--mut);text-align:left;padding:0 12px 9px 0;border-bottom:1px solid var(--line-2);white-space:nowrap}
td{padding:12px 12px 12px 0;border-bottom:1px solid var(--line);vertical-align:middle}
td.num,th.num{text-align:right;padding-right:0;font-family:var(--mono);font-variant-numeric:tabular-nums}
tr.grp td{background:#e4e1d8;border-bottom:1px solid var(--line-2);padding:7px 0 7px 8px}
.sheet{background:var(--sheet);border:1px solid var(--line-2);padding:20px}
.chip{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:3px;font-family:var(--mono);font-size:11px;font-weight:500;letter-spacing:.08em;text-transform:uppercase;background:var(--neu-bg);color:var(--ink-2)}
.chip.go{background:var(--amber-bg);color:var(--amber-tx)}
.chip.ok{background:var(--ok-bg);color:var(--ok-tx)}
.chip.err{background:var(--err-bg);color:var(--err-tx)}
.chip.dark{background:var(--board);color:#f3f0e7}
@keyframes flip{from{transform:rotateX(-88deg)}to{transform:rotateX(0)}}
.live{animation:flip 420ms cubic-bezier(.2,.9,.25,1) 1;transform-origin:50% 0}
@media(prefers-reduced-motion:reduce){.live{animation:none}}
label{display:block;font-family:var(--mono);font-size:10.5px;font-weight:500;letter-spacing:.1em;text-transform:uppercase;color:var(--mut);margin-bottom:6px}
input,select,textarea{width:100%;min-height:44px;padding:10px 12px;border:1px solid var(--line-2);border-radius:2px;background:#fff;color:var(--ink);font:inherit;font-size:16px}
input:focus,select:focus,textarea:focus{outline:2px solid var(--acc);outline-offset:1px}
input[type=checkbox]{width:20px;min-height:20px;height:20px}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:46px;padding:0 18px;border:1px solid var(--line-2);border-radius:3px;background:#fff;color:var(--ink);font:inherit;font-size:14px;font-weight:600;cursor:pointer;text-decoration:none}
.btn:hover{border-color:var(--ink);color:var(--ink)}
.btn.main{background:var(--amber);border-color:var(--amber);color:var(--ink)}
.btn.dark{background:var(--board);border-color:var(--board);color:#f3f0e7}
.btn.sm{min-height:38px;font-size:13px;font-weight:500}
.msg{padding:12px 14px;border-radius:3px;margin-bottom:16px;font-size:14px}
.msg.err{background:var(--err-bg);color:var(--err-tx)}
.msg.ok{background:var(--ok-bg);color:var(--ok-tx)}
.mut{color:var(--ink-2);font-size:12.5px;line-height:1.65}
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:22px}
.rows{display:flex;flex-direction:column}
.row{display:flex;justify-content:space-between;gap:14px;padding:11px 0;border-bottom:1px solid var(--line);font-size:14px}
.empty{padding:26px 0;color:var(--ink-2);font-size:14px}
.login{min-height:100vh;display:grid;grid-template-columns:minmax(0,460px) 1fr}
.login .side{background:var(--board);color:#d9d3c6;padding:40px 36px;display:flex;flex-direction:column;justify-content:space-between;gap:30px}
.login .side h1{color:#f3f0e7;font-size:30px;line-height:1.2;margin:0}
.login .form{display:flex;align-items:center;justify-content:center;padding:36px 20px}
.login form{width:100%;max-width:380px;display:flex;flex-direction:column;gap:16px}
@media(max-width:820px){.login{grid-template-columns:1fr}.login .side{padding:26px 20px}.login .side h1{font-size:24px}}
@media(max-width:600px){main{padding:18px 14px 28px}.board{padding:18px 14px}.board .big{font-size:32px}.top{padding:0 14px}.sheet{padding:16px 14px}}
</style></head><body>{{end}}
{{define "money"}}{{if gt . 0.0}}{{fmtmoney .}} ₽{{else}}—{{end}}{{end}}
{{define "mark"}}<svg viewBox="0 0 28 28" width="21" height="21" fill="none" stroke="#e8a33d" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><circle cx="6" cy="14" r="3"/><circle cx="22" cy="14" r="3"/><path d="M9 14h10"/><path d="M11 10.5h6M11 17.5h6"/></svg>{{end}}
{{define "nav"}}<header class="top">
<span class="brand">{{template "mark" .}}<span class="lbl" style="font-size:12px;letter-spacing:.14em">{{.Title}}</span></span>
<nav>
{{if .IsAdmin}}<a href="/clients" class="lbl {{if eq .Nav "a"}}on{{end}}">Клиенты</a>{{end}}
<a href="/" class="lbl {{if eq .Nav "b"}}on{{end}}">Табло</a>
<a href="/portfolio" class="lbl {{if eq .Nav "p"}}on{{end}}">Реестр</a>
<a href="/orders" class="lbl {{if eq .Nav "c"}}on{{end}}">Поручения</a>
<a href="/operations" class="lbl {{if eq .Nav "o"}}on{{end}}">Операции</a>
<a href="/income" class="lbl {{if eq .Nav "i"}}on{{end}}">Доходы</a>
<a href="/profile" class="lbl {{if eq .Nav "u"}}on{{end}}">Профиль</a>
</nav>
<a href="/order" class="cta lbl"><svg viewBox="0 0 16 16" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M8 3v10M3 8h10"/></svg>Новое поручение</a>
<span class="who">{{with .FullName}}{{.}}{{end}}{{with .Contract}} · {{.}}{{end}}</span>
<a href="/logout" class="exit lbl">Выход</a>
</header>
{{if .AsClient}}<div class="imp">
<svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="#e8a33d" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><circle cx="8" cy="8" r="6.5"/><path d="M8 5v4M8 11h.01"/></svg>
<span>Вы в кабинете клиента <b>{{.AsClient}}</b> от имени сотрудника. Поручение можно подготовить, подписывает его клиент.</span>
<a href="/back-to-admin" style="color:#e8a33d">вернуться к списку клиентов</a></div>{{end}}{{end}}
{{define "login"}}{{template "head" .}}
<div class="login">
<section class="side">
<span class="brand">{{template "mark" .}}<span class="lbl" style="font-size:12px;letter-spacing:.14em;color:#f3f0e7">{{.Title}}</span></span>
<div>
<h1>Ваши бумаги, поручения и выплаты — на одном табло</h1>
<div style="display:flex;flex-direction:column;gap:12px;margin-top:22px;font-size:14.5px">
<span style="display:flex;gap:12px"><span class="n" style="color:#e8a33d">01</span><span>Реестр бумаг по счетам депо и остаток, свободный к переводу</span></span>
<span style="display:flex;gap:12px"><span class="n" style="color:#e8a33d">02</span><span>Поручения депозитарию и их состояние по шагам</span></span>
<span style="display:flex;gap:12px"><span class="n" style="color:#e8a33d">03</span><span>Перевод бумаг в другой депозитарий через сервис MOEX МОСТ</span></span>
</div>
</div>
<p class="mut" style="color:#8e8879;margin:0">Кабинет работает на сервере депозитария и обращается к учётной системе по защищённому каналу. Данные о вас хранятся в учётной системе, а не в кабинете.</p>
</section>
<section class="form">
<form method="post" action="/login">
<h1 style="margin:0">Вход</h1>
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
<div><label for="login">Логин или номер договора</label><input id="login" name="login" autocomplete="username" autofocus></div>
<div><label for="password">Пароль</label><input id="password" name="password" type="password" autocomplete="current-password"></div>
<button class="btn main" type="submit">Войти</button>
<p class="mut" style="margin:0">Логин выдаёт депозитарий. Сотрудник входит под своей учётной записью и не знает пароль клиента.</p>
</form>
</section>
</div>
</body></html>{{end}}
{{define "board"}}{{template "head" .}}{{template "nav" .}}
<section class="board"><div class="board-row">
<div>
<span class="lbl" style="color:var(--dim)">{{if gt .Value 0.0}}Стоимость бумаг{{else}}Бумаг в реестре{{end}}</span>
<div class="big" style="margin-top:8px">{{if gt .Value 0.0}}{{fmtmoney .Value}} ₽{{else}}{{.Total}}{{end}}</div>
<div class="n" style="font-size:13px;color:var(--dim);margin-top:6px">{{with .FullName}}{{.}} · {{end}}договор {{.Contract}}{{if gt .Value 0.0}} · оценка по {{.Priced}} из {{.Total}} бумаг{{end}}</div>
</div>
<div class="stats">
<span class="stat"><span class="lbl" style="color:var(--dim)">Свободно к переводу</span><span class="v">{{.Free}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">С ограничением</span><span class="v" style="color:var(--amber)">{{.Blocked}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">Поручений в работе</span><span class="v">{{.Active}}</span></span>
</div>
</div></section>
<main>
{{if .Flash}}<div class="msg ok">{{.Flash}}</div>{{end}}
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
<section class="sec">
<div class="sec-h"><h1 class="lbl" style="font-size:12px;letter-spacing:.14em">Последние поручения</h1><a href="/orders" style="font-size:13px;text-decoration:none">все поручения</a></div>
{{if .Claims}}<div class="tw"><table>
<thead><tr><th>Номер</th><th>Дата</th><th>Вид поручения</th><th class="num">Бумаг</th><th>Состояние</th></tr></thead>
<tbody>{{range .Claims}}<tr>
<td class="n">{{shortid .GUID}}</td>
<td class="n">{{.CreatedAt}}</td>
<td>Перевод в другой депозитарий</td>
<td class="num">{{.Securit}}</td>
<td><span class="chip {{if eq .Status "done"}}ok{{else if eq .Status "rejected"}}err{{else if eq .Status "declined"}}err{{else if eq .Status "error"}}err{{else}}go{{end}}">{{.StatusRu}}</span>{{with .Reason}}<div class="mut">{{.}}</div>{{end}}</td>
</tr>{{end}}</tbody></table></div>
{{else}}<p class="empty">Поручений пока нет. Нажмите «Новое поручение», чтобы перевести бумаги в другой депозитарий.</p>{{end}}
</section>
<section class="sec">
<div class="sec-h"><h2 class="lbl" style="font-size:12px;letter-spacing:.14em">Реестр бумаг</h2><a href="/portfolio" style="font-size:13px;text-decoration:none">весь реестр</a></div>
{{if .Positions}}<div class="tw"><table>
<thead><tr><th>Выпуск</th><th>Счёт депо</th><th class="num">Количество</th><th class="num">Свободно</th><th class="num">Оценка</th><th>Состояние</th></tr></thead>
<tbody>{{range .Positions}}<tr>
<td><a href="/security?isin={{.ISIN}}" style="text-decoration:none;font-weight:600">{{.SecurityName}}</a><div class="n" style="font-size:12.5px;color:var(--mut)">{{.ISIN}}</div></td>
<td class="n" style="font-size:13px">{{if .AccountID}}{{.AccountID}}{{else}}—{{end}}</td>
<td class="num">{{fmtnum .Quantity}}</td>
<td class="num">{{fmtnum .Available}}</td>
<td class="num">{{template "money" .Value}}</td>
<td>{{if not .Transferable}}<span class="chip">не переводится</span>{{else if gt .Blocked 0.0}}<span class="chip go">{{fmtnum .Blocked}} с ограничением</span>{{else}}<span class="chip ok">свободно</span>{{end}}</td>
</tr>{{end}}</tbody></table></div>
{{else}}<p class="empty">Бумаг на счетах депо не найдено. Если это ошибка — напишите в депозитарий.</p>{{end}}
</section>
</main></body></html>{{end}}
{{define "portfolio"}}{{template "head" .}}{{template "nav" .}}
<section class="board"><div class="board-row">
<div><span class="lbl" style="color:var(--dim)">Реестр бумаг</span>
{{if gt .Value 0.0}}<div class="big" style="margin-top:8px;font-size:32px">{{fmtmoney .Value}} ₽</div>{{end}}
<div class="n" style="font-size:13px;color:var(--dim);margin-top:6px">{{.Source}}{{with .UpdatedAt}} · {{.}}{{end}}{{if gt .Value 0.0}} · цены торговой системы{{end}}</div></div>
<div class="stats">
<span class="stat"><span class="lbl" style="color:var(--dim)">Выпусков</span><span class="v">{{.Total}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">Свободно к переводу</span><span class="v">{{.Free}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">С ограничением</span><span class="v" style="color:var(--amber)">{{.Blocked}}</span></span>
</div>
</div></section>
<main>
{{if .Flash}}<div class="msg ok">{{.Flash}}</div>{{end}}
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
{{if .ReadOnly}}<div class="msg">Кабинет открыт в режиме просмотра: подача поручений по этому договору выключена депозитарием.</div>{{end}}
{{if .Positions}}
<div class="tw"><table>
<thead><tr><th>Выпуск</th><th>Счёт депо</th><th class="num">Количество</th><th class="num">С ограничением</th><th class="num">Свободно</th><th class="num">Цена</th><th class="num">Оценка</th><th>Состояние</th><th></th></tr></thead>
<tbody>{{range .Positions}}<tr>
<td><a href="/security?isin={{.ISIN}}" style="text-decoration:none;font-weight:600">{{.SecurityName}}</a><div class="n" style="font-size:12.5px;color:var(--mut)">{{.ISIN}}{{with .SecurityCode}} · {{.}}{{end}}</div></td>
<td class="n" style="font-size:13px">{{if .AccountID}}{{.AccountID}}{{else}}—{{end}}</td>
<td class="num">{{fmtnum .Quantity}}</td>
<td class="num">{{if gt .Blocked 0.0}}<span style="color:var(--amber-tx)">{{fmtnum .Blocked}}</span>{{else}}—{{end}}</td>
<td class="num">{{fmtnum .Available}}</td>
<td class="num">{{if gt .Price 0.0}}{{fmtmoney .Price}}{{if ne .ChangePct 0.0}}<div style="font-size:12px;{{if gt .ChangePct 0.0}}color:var(--ok-tx){{else}}color:var(--err-tx){{end}}">{{fmtpct .ChangePct}}</div>{{end}}{{else}}—{{end}}</td>
<td class="num">{{template "money" .Value}}</td>
<td>{{if not .Transferable}}<span class="chip">иностранный выпуск</span>{{else if gt .Blocked 0.0}}<span class="chip go">частично ограничено</span>{{else}}<span class="chip ok">свободно</span>{{end}}{{with .Note}}<div class="mut">{{.}}</div>{{end}}</td>
<td style="text-align:right">{{if and .Transferable (gt .Available 0.0) (not $.ReadOnly)}}<a href="/order?isin={{.ISIN}}" class="lbl" style="text-decoration:none">перевести</a>{{end}}</td>
</tr>{{end}}</tbody></table></div>
<p class="mut" style="margin-top:18px"><b>С ограничением</b> — бумаги в расчётах по сделке, под обременением или ограниченные в обращении: перевести их нельзя, пока ограничение не снято.
<b>Иностранный выпуск</b> — перевод между депозитариями по MOEX МОСТ работает только с российскими выпусками, код ISIN начинается на RU.</p>
{{else}}<p class="empty">Бумаг на счетах депо не найдено.</p>{{end}}
</main></body></html>{{end}}
{{define "transfer"}}{{template "head" .}}{{template "nav" .}}
<main>
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
<form method="post" action="/order" id="orderForm">
<div class="sheet">
<div style="display:flex;align-items:flex-end;justify-content:space-between;gap:20px;border-bottom:2px solid var(--ink);padding-bottom:14px;flex-wrap:wrap">
<div><h1 style="margin:0">Поручение депозитарию</h1>
<span class="lbl" style="color:var(--mut);margin-top:6px;display:block">Заполняется по видам, как и другие поручения кабинета</span></div>
<div style="text-align:right"><span class="lbl" style="color:var(--mut);display:block">Черновик</span>
<span class="n" style="font-size:16px;font-weight:700">{{.Today}}</span></div>
</div>
<div style="margin-top:20px">
<span class="lbl" style="display:block;margin-bottom:10px;color:var(--ink)">1. Вид поручения</span>
<select name="kind" aria-label="Вид поручения">
<option value="m2m">Перевод бумаг в другой депозитарий</option>
<option value="other" disabled>Другие виды — подаются в депозитарии, скоро появятся здесь</option>
</select>
</div>
<div style="margin-top:20px">
<span class="lbl" style="display:block;margin-bottom:10px;color:var(--ink)">2. Что переводим</span>
{{if .Positions}}<div class="tw"><table>
<thead><tr><th style="width:40px"></th><th>Выпуск</th><th class="num">Свободно</th><th style="width:180px">Количество</th></tr></thead>
<tbody>{{range .Positions}}<tr>
<td>{{if and .Transferable (gt .Available 0.0)}}<input type="checkbox" name="isin" value="{{.ISIN}}" id="c{{.ISIN}}"{{if eq $.PickISIN .ISIN}} checked{{end}}>{{end}}</td>
<td><label for="c{{.ISIN}}" style="font-family:inherit;font-size:14px;letter-spacing:0;text-transform:none;color:var(--ink);margin:0;font-weight:600">{{.SecurityName}}</label>
<div class="n" style="font-size:12.5px;color:var(--mut)">{{.ISIN}}{{if not .Transferable}} · иностранный выпуск, перевод недоступен{{else if eq .Available 0.0}} · свободного остатка нет{{end}}</div></td>
<td class="num">{{fmtnum .Available}}</td>
<td>{{if and .Transferable (gt .Available 0.0)}}<input class="n" name="qty_{{.ISIN}}" inputmode="decimal" style="min-height:40px;text-align:right" aria-label="Количество {{.SecurityName}}">{{else}}<span class="lbl" style="color:var(--mut)">недоступно</span>{{end}}</td>
</tr>{{end}}</tbody></table></div>
{{else}}<p class="empty">Свободных бумаг для перевода нет.</p>{{end}}
</div>
<div style="margin-top:20px">
<span class="lbl" style="display:block;margin-bottom:10px;color:var(--ink)">3. Куда переводим</span>
<div class="grid2">
<div><label for="inn">ИНН принимающего депозитария</label>
<input id="inn" name="receiving_inn" inputmode="numeric" maxlength="12" required aria-describedby="innh">
<span id="innh" class="mut" style="display:block;margin-top:6px">10 цифр для организации. ИНН можно спросить у депозитария, куда переводите бумаги.</span></div>
<div><label for="rname">Наименование</label><input id="rname" name="receiving_name" placeholder="как в договоре"></div>
<div><label for="racc">Ваш счёт депо у принимающего</label><input id="racc" name="account_at_recv" placeholder="если знаете"></div>
<div><label for="cmt">Комментарий депозитарию</label><input id="cmt" name="comment" placeholder="необязательно"></div>
</div>
</div>
<div style="display:flex;gap:12px;flex-wrap:wrap;margin-top:22px">
<button class="btn main" type="submit">Подать поручение</button>
<a class="btn" href="/">Отмена</a>
</div>
<p class="mut" style="margin-top:14px">Переводятся только российские выпуски. Бумаги для квалифицированных инвесторов принимающая сторона может не принять. После отправки в НРД отменить поручение нельзя — состояние будет видно в разделе «Поручения».</p>
</div>
</form>
</main></body></html>{{end}}
{{define "claims"}}{{template "head" .}}{{template "nav" .}}
<section class="board"><div class="board-row">
<div><span class="lbl" style="color:var(--dim)">Поручения депозитарию</span>
<div class="n" style="font-size:13px;color:var(--dim);margin-top:6px">все виды поручений кабинета</div></div>
<div class="stats">
<span class="stat"><span class="lbl" style="color:var(--dim)">Всего</span><span class="v">{{.Total}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">В работе</span><span class="v" style="color:var(--amber)">{{.Active}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">Исполнено</span><span class="v">{{.Done}}</span></span>
</div>
</div></section>
<main>
{{if .Flash}}<div class="msg ok">{{.Flash}}</div>{{end}}
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
{{if .Claims}}<div class="tw"><table>
<thead><tr><th>Номер</th><th>Дата</th><th>Вид поручения</th><th class="num">Бумаг</th><th>Состояние</th><th>Примечание</th></tr></thead>
<tbody>{{range .Claims}}<tr>
<td class="n">{{shortid .GUID}}</td>
<td class="n">{{.CreatedAt}}</td>
<td>Перевод в другой депозитарий</td>
<td class="num">{{.Securit}}</td>
<td><span class="chip {{if eq .Status "done"}}ok{{else if eq .Status "rejected"}}err{{else if eq .Status "declined"}}err{{else if eq .Status "error"}}err{{else}}go{{end}}">{{.StatusRu}}</span></td>
<td class="mut">{{if .Reason}}{{.Reason}}{{else}}—{{end}}</td>
</tr>{{end}}</tbody></table></div>
<p class="mut" style="margin-top:18px">Пока поручение в работе, бумаги остаются на счёте, но перевести их повторно нельзя. Если принимающая сторона откажет, бумаги освободятся в тот же день, а причина появится в примечании.</p>
{{else}}<p class="empty">Поручений пока нет.</p>{{end}}
</main></body></html>{{end}}
{{define "profile"}}{{template "head" .}}{{template "nav" .}}
<section class="board"><div class="board-row">
<div><span class="lbl" style="color:var(--dim)">Профиль</span>
<div style="font-size:23px;font-weight:700;margin-top:8px">{{if .FullName}}{{.FullName}}{{else}}Клиент депозитария{{end}}</div></div>
<div class="stats">
<span class="stat"><span class="lbl" style="color:var(--dim)">Договор</span><span class="v">{{.Contract}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">Счетов депо</span><span class="v">{{.Accounts}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">Подача поручений</span><span class="v">{{if .ReadOnly}}выключена{{else}}доступна{{end}}</span></span>
</div>
</div></section>
<main>
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
<div class="grid2">
<section class="sec">
<h2 class="lbl" style="font-size:12px;letter-spacing:.14em">Счета депо</h2>
<div class="rows">{{range .AccountList}}<div class="row"><span class="n">{{.}}</span><span class="chip ok">открыт</span></div>{{else}}<p class="empty">Счета не найдены.</p>{{end}}</div>
</section>
<section class="sec">
<h2 class="lbl" style="font-size:12px;letter-spacing:.14em">Доступ и безопасность</h2>
<div class="rows">
<div class="row"><span>Вход в кабинет</span><span class="n">{{.Login}}</span></div>
<div class="row"><span>Подача поручений</span><span>{{if .ReadOnly}}выключена депозитарием{{else}}доступна{{end}}</span></div>
{{if .AsClient}}<div class="row"><span>Сейчас в кабинете</span><span>сотрудник депозитария</span></div>{{end}}
<div class="row"><span>Завершить работу</span><a href="/logout">выйти</a></div>
</div>
<p class="mut" style="margin-top:14px">Контакты, паспортные данные и реквизиты для выплат меняет депозитарий: обратитесь к своему менеджеру, изменения появятся в кабинете после внесения в анкету.</p>
</section>
</div>
</main></body></html>{{end}}
{{define "clients"}}{{template "head" .}}{{template "nav" .}}
<section class="board"><div class="board-row">
<div><span class="lbl" style="color:var(--dim)">Режим сотрудника</span>
<div style="font-size:23px;font-weight:700;margin-top:8px">Клиенты депозитария</div></div>
<div class="stats">
<span class="stat"><span class="lbl" style="color:var(--dim)">Учётных записей</span><span class="v">{{len .Clients}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">Договоров в учёте</span><span class="v">{{len .Depo}}</span></span>
</div>
</div></section>
<main>
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
<section class="sec">
<h2 class="lbl" style="font-size:12px;letter-spacing:.14em">Учётные записи кабинета</h2>
{{if .Clients}}<div class="tw"><table>
<thead><tr><th>Клиент</th><th>Логин</th><th>Договор</th><th>Состояние</th><th></th></tr></thead>
<tbody>{{range .Clients}}<tr>
<td><b>{{.FullName}}</b></td><td class="n">{{.Login}}</td><td class="n">{{.Contract}}</td>
<td>{{if .Active}}<span class="chip ok">активна</span>{{else}}<span class="chip err">заблокирована</span>{{end}}</td>
<td style="text-align:right"><form method="post" action="/impersonate" style="margin:0"><input type="hidden" name="login" value="{{.Login}}"><button class="btn sm" type="submit">Открыть кабинет</button></form></td>
</tr>{{end}}</tbody></table></div>
{{else}}<p class="empty">Учётных записей кабинета пока нет.</p>{{end}}
</section>
<section class="sec">
<div class="sec-h"><h2 class="lbl" style="font-size:12px;letter-spacing:.14em">Клиенты депозитария</h2></div>
<form method="get" action="/clients" style="display:flex;gap:10px;align-items:flex-end;max-width:560px;margin-bottom:14px">
<div style="flex-grow:1"><label for="s">Поиск</label><input id="s" name="search" value="{{.Search}}" placeholder="фамилия или номер договора"></div>
<button class="btn" type="submit">Найти</button>
</form>
{{if .DepoError}}<div class="msg err">{{.DepoError}}</div>{{end}}
{{if .Depo}}<div class="tw"><table>
<thead><tr><th>Клиент</th><th>Договор</th><th class="num">Бумаг</th><th></th></tr></thead>
<tbody>{{range .Depo}}<tr>
<td><b>{{.Name}}</b></td><td class="n">{{.Contract}}</td><td class="num">{{.Securities}}</td>
<td style="text-align:right"><form method="post" action="/impersonate" style="margin:0"><input type="hidden" name="contract" value="{{.Contract}}"><button class="btn sm" type="submit">Открыть кабинет</button></form></td>
</tr>{{end}}</tbody></table></div>
{{else}}<p class="empty">Ничего не найдено.</p>{{end}}
</section>
<p class="mut">В кабинете клиента сотрудник готовит поручение, подписывает его клиент. Каждый вход сотрудника записывается в журнал.</p>
</main></body></html>{{end}}
{{define "security"}}{{template "head" .}}{{template "nav" .}}
{{$s := .S}}
<section class="board"><div class="board-row">
<div>
<a href="/portfolio" class="lbl" style="color:var(--dim);text-decoration:none">← Реестр</a>
<div style="font-size:23px;font-weight:700;margin-top:8px">{{if $s.Name}}{{$s.Name}}{{else}}{{.ISIN}}{{end}}</div>
<div class="n" style="font-size:13px;color:var(--dim);margin-top:6px">{{.ISIN}}{{with $s.Kind}} · {{.}}{{end}}{{with $s.RegNumber}} · {{.}}{{end}}</div>
</div>
<div class="stats">
{{with $s.Position}}<span class="stat"><span class="lbl" style="color:var(--dim)">В портфеле</span><span class="v">{{fmtnum .Quantity}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">Свободно</span><span class="v">{{fmtnum .Available}}</span></span>{{end}}
{{if gt $s.Price 0.0}}<span class="stat"><span class="lbl" style="color:var(--dim)">Цена</span><span class="v">{{fmtmoney $s.Price}}</span></span>{{end}}
{{with $s.Position}}{{if gt .Value 0.0}}<span class="stat"><span class="lbl" style="color:var(--dim)">Оценка</span><span class="v">{{fmtmoney .Value}} ₽</span></span>{{end}}{{end}}
</div>
</div></section>
<main>
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
{{with $s.Note}}<div class="msg">{{.}}</div>{{end}}
<div class="grid2">
<section class="sec">
<h2 class="lbl" style="font-size:12px;letter-spacing:.14em">Выпуск</h2>
<div class="rows">
{{with $s.Issuer}}<div class="row"><span>Эмитент</span><span style="text-align:right">{{.}}</span></div>{{end}}
{{with $s.Kind}}<div class="row"><span>Вид бумаги</span><span>{{.}}</span></div>{{end}}
{{if gt $s.Face 0.0}}<div class="row"><span>Номинал</span><span class="n">{{fmtmoney $s.Face}} ₽</span></div>{{end}}
{{with $s.Maturity}}<div class="row"><span>Погашение</span><span class="n">{{.}}</span></div>{{end}}
{{with $s.RegNumber}}<div class="row"><span>Государственная регистрация</span><span class="n">{{.}}</span></div>{{end}}
{{with $s.CFI}}<div class="row"><span>Код CFI</span><span class="n">{{.}}</span></div>{{end}}
<div class="row"><span>Обслуживание в депозитарии</span><span>{{if $s.Accepted}}принята{{else}}не принята{{end}}</span></div>
<div class="row"><span>Для квалифицированных инвесторов</span><span>{{if $s.QualOnly}}да{{else}}ограничений нет{{end}}</span></div>
{{if gt $s.Price 0.0}}<div class="row"><span>Цена{{with $s.Board}} · {{.}}{{end}}</span><span class="n">{{fmtmoney $s.Price}}{{with $s.PriceIn}} <span style="color:var(--mut)">{{.}}</span>{{end}}</span></div>{{end}}
</div>
{{with $s.Position}}{{if and .Transferable (gt .Available 0.0)}}
<a href="/order?isin={{$s.ISIN}}" class="btn main" style="margin-top:16px">Перевести эту бумагу</a>{{end}}{{end}}
</section>
<section class="sec">
<h2 class="lbl" style="font-size:12px;letter-spacing:.14em">График выплат и событий</h2>
{{if $s.Payments}}<div class="tw"><table>
<thead><tr><th>Дата</th><th>Событие</th><th class="num">На бумагу</th><th class="num">Ставка</th><th>Состояние</th></tr></thead>
<tbody>{{range $s.Payments}}<tr>
<td class="n">{{.Date}}</td>
<td>{{.Kind}}{{with .FixDate}}<div class="mut">фиксация {{.}}</div>{{end}}</td>
<td class="num">{{if gt .Amount 0.0}}{{fmtmoney .Amount}} ₽{{else}}—{{end}}</td>
<td class="num">{{if gt .Percent 0.0}}{{fmtpct .Percent}}{{else}}—{{end}}</td>
<td>{{if .Paid}}<span class="chip ok">выплачено</span>{{else}}<span class="chip">ожидается</span>{{end}}</td>
</tr>{{end}}</tbody></table></div>
{{else}}<p class="empty">Выплат по этой бумаге в справочнике депозитария нет.</p>{{end}}
<p class="mut" style="margin-top:14px">Суммы приведены на одну бумагу по данным справочника депозитария. Фактическая выплата и удержанный налог появятся в операциях по счёту.</p>
</section>
</div>
</main></body></html>{{end}}
{{define "operations"}}{{template "head" .}}{{template "nav" .}}
<section class="board"><div class="board-row">
<div><span class="lbl" style="color:var(--dim)">Операции по счетам депо</span>
<div class="big" style="margin-top:8px;font-size:32px">{{.Total}}</div>
<div class="n" style="font-size:13px;color:var(--dim);margin-top:6px">за период {{.From}} — {{.To}}</div></div>
<div class="stats">
<span class="stat"><span class="lbl" style="color:var(--dim)">Зачислений</span><span class="v">{{.In}}</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">Списаний</span><span class="v">{{.Out}}</span></span>
</div>
</div></section>
<main>
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
<form method="get" action="/operations" style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;margin-bottom:18px">
<div><label for="from">Период с</label><input id="from" type="date" name="from" value="{{.From}}" style="width:auto"></div>
<div><label for="to">по</label><input id="to" type="date" name="to" value="{{.To}}" style="width:auto"></div>
<button class="btn" type="submit">Показать</button>
</form>
{{if .Operations}}<div class="tw"><table>
<thead><tr><th>Дата</th><th>Операция</th><th>Выпуск</th><th>Счёт депо</th><th class="num">Количество</th><th>Состояние</th><th>Основание</th></tr></thead>
<tbody>{{range .Operations}}<tr>
<td class="n">{{.Date}}{{if and .DoneAt (ne .DoneAt .Date)}}<div class="mut">проведено {{.DoneAt}}</div>{{end}}</td>
<td>{{.Kind}}{{with .Number}}<div class="n mut">№ {{.}}</div>{{end}}</td>
<td>{{if .ISIN}}<a href="/security?isin={{.ISIN}}" style="text-decoration:none">{{.Security}}</a><div class="n mut">{{.ISIN}}</div>{{else}}{{.Security}}{{end}}</td>
<td class="n" style="font-size:13px">{{.Account}}</td>
<td class="num">{{if lt .Quantity 0.0}}<span style="color:var(--err-tx)">{{fmtnum .Quantity}}</span>{{else}}<span style="color:var(--ok-tx)">+{{fmtnum .Quantity}}</span>{{end}}</td>
<td>{{if eq .State "исполнено"}}<span class="chip ok">исполнено</span>{{else if eq .State "отменено"}}<span class="chip err">отменено</span>{{else}}<span class="chip go">{{.State}}</span>{{end}}</td>
<td class="mut">{{if .Note}}{{.Note}}{{else}}—{{end}}</td>
</tr>{{end}}</tbody></table></div>
<p class="mut" style="margin-top:18px">Показаны зачисления, списания и переводы между вашими счетами депо по данным учёта депозитария. Выписку за период можно заказать у депозитария.</p>
{{else}}<p class="empty">За выбранный период операций по счетам депо нет.</p>{{end}}
</main></body></html>{{end}}
{{define "income"}}{{template "head" .}}{{template "nav" .}}
<section class="board"><div class="board-row">
<div><span class="lbl" style="color:var(--dim)">Выплачено дохода</span>
<div class="big" style="margin-top:8px">{{fmtmoney .Paid}} ₽</div>
<div class="n" style="font-size:13px;color:var(--dim);margin-top:6px">за период {{.From}} — {{.To}}</div></div>
<div class="stats">
<span class="stat"><span class="lbl" style="color:var(--dim)">Начислено</span><span class="v">{{fmtmoney .Accrued}} ₽</span></span>
<span class="stat"><span class="lbl" style="color:var(--dim)">Удержан налог</span><span class="v" style="color:var(--amber)">{{fmtmoney .Tax}} ₽</span></span>
</div>
</div></section>
<main>
{{if .Error}}<div class="msg err">{{.Error}}</div>{{end}}
<form method="get" action="/income" style="display:flex;gap:12px;align-items:flex-end;flex-wrap:wrap;margin-bottom:18px">
<div><label for="from">Период с</label><input id="from" type="date" name="from" value="{{.From}}" style="width:auto"></div>
<div><label for="to">по</label><input id="to" type="date" name="to" value="{{.To}}" style="width:auto"></div>
<button class="btn" type="submit">Показать</button>
</form>
{{if .Income}}<div class="tw"><table>
<thead><tr><th>Дата</th><th>Выпуск</th><th>Вид дохода</th><th class="num">Бумаг</th><th class="num">Начислено</th><th class="num">Налог</th><th class="num">К выплате</th></tr></thead>
<tbody>{{range .Income}}<tr>
<td class="n">{{.Date}}</td>
<td>{{if .ISIN}}<a href="/security?isin={{.ISIN}}" style="text-decoration:none">{{.Security}}</a><div class="n mut">{{.ISIN}}</div>{{else}}{{.Security}}{{end}}</td>
<td>{{.Kind}}</td>
<td class="num">{{if gt .Quantity 0.0}}{{fmtnum .Quantity}}{{else}}—{{end}}</td>
<td class="num">{{fmtmoney .Accrued}}</td>
<td class="num">{{if gt .Tax 0.0}}{{fmtmoney .Tax}}{{else}}—{{end}}</td>
<td class="num" style="font-weight:700">{{fmtmoney .Paid}} ₽</td>
</tr>{{end}}</tbody></table></div>
<p class="mut" style="margin-top:18px">Суммы и удержанный налог — по данным учёта депозитария как налогового агента по выплатам эмитентов. По купонам государственных облигаций налог может удерживать брокер при выплате, тогда здесь он нулевой. Справку о доходах можно запросить у депозитария.</p>
{{else}}<p class="empty">За выбранный период выплат дохода нет.</p>{{end}}
</main></body></html>{{end}}
`