Кабинет: оценка портфеля по ценам QUIK и карточка бумаги из справочника депозитария
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+97
-5
@@ -53,6 +53,40 @@ func New(cfg Config) (*Server, error) {
|
||||
}
|
||||
return strconv.FormatFloat(f, 'f', -1, 64)
|
||||
},
|
||||
"fmtmoney": func(f float64) string { // 1 234 567,89 — с разделителем разрядов
|
||||
neg := f < 0
|
||||
if neg {
|
||||
f = -f
|
||||
}
|
||||
whole := int64(f)
|
||||
cents := int64((f-float64(whole))*100 + 0.5)
|
||||
if cents >= 100 {
|
||||
whole, cents = whole+1, 0
|
||||
}
|
||||
d := strconv.FormatInt(whole, 10)
|
||||
var b strings.Builder
|
||||
for i, c := range d {
|
||||
if i > 0 && (len(d)-i)%3 == 0 {
|
||||
b.WriteByte(' ')
|
||||
}
|
||||
b.WriteRune(c)
|
||||
}
|
||||
out := b.String()
|
||||
if cents > 0 {
|
||||
out += "," + fmt.Sprintf("%02d", cents)
|
||||
}
|
||||
if neg {
|
||||
out = "−" + out
|
||||
}
|
||||
return out
|
||||
},
|
||||
"fmtpct": func(f float64) string {
|
||||
s := strconv.FormatFloat(f, 'f', 2, 64)
|
||||
if f > 0 {
|
||||
s = "+" + s
|
||||
}
|
||||
return strings.ReplaceAll(s, ".", ",") + " %"
|
||||
},
|
||||
"shortid": func(s string) string {
|
||||
if len(s) > 8 {
|
||||
return s[:8] + "…"
|
||||
@@ -126,6 +160,9 @@ type position struct {
|
||||
Available float64 `json:"available"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
Transferable bool `json:"transferable"`
|
||||
Price float64 `json:"price"`
|
||||
Value float64 `json:"value"`
|
||||
ChangePct float64 `json:"change_pct"`
|
||||
Note string `json:"note"`
|
||||
}
|
||||
|
||||
@@ -175,11 +212,42 @@ func claimsView(rows []claimRow) (active, done int) {
|
||||
|
||||
// portfolioResp — ответ /api/lk/portfolio.
|
||||
type portfolioResp struct {
|
||||
Contract string `json:"contract"`
|
||||
FullName string `json:"full_name"`
|
||||
Positions []position `json:"positions"`
|
||||
Source string `json:"source"`
|
||||
ReadOnly bool `json:"read_only"`
|
||||
Contract string `json:"contract"`
|
||||
FullName string `json:"full_name"`
|
||||
Positions []position `json:"positions"`
|
||||
Source string `json:"source"`
|
||||
ReadOnly bool `json:"read_only"`
|
||||
TotalValue float64 `json:"total_value"`
|
||||
Priced int `json:"priced"`
|
||||
}
|
||||
|
||||
// securityCard — карточка бумаги из ядра.
|
||||
type securityCard struct {
|
||||
ISIN string `json:"isin"`
|
||||
Name string `json:"name"`
|
||||
Kind string `json:"kind"`
|
||||
Issuer string `json:"issuer"`
|
||||
RegNumber string `json:"reg_number"`
|
||||
CFI string `json:"cfi"`
|
||||
Face float64 `json:"face"`
|
||||
Maturity string `json:"maturity"`
|
||||
Accepted bool `json:"accepted"`
|
||||
QualOnly bool `json:"qual_only"`
|
||||
QualNote string `json:"qual_note"`
|
||||
Price float64 `json:"price"`
|
||||
PriceIn string `json:"price_in"`
|
||||
Board string `json:"board"`
|
||||
ChangePct float64 `json:"change_pct"`
|
||||
Position *position `json:"position"`
|
||||
Payments []struct {
|
||||
Date string `json:"date"`
|
||||
Kind string `json:"kind"`
|
||||
Amount float64 `json:"amount"`
|
||||
Percent float64 `json:"percent"`
|
||||
FixDate string `json:"fix_date"`
|
||||
Paid bool `json:"paid"`
|
||||
} `json:"payments"`
|
||||
Note string `json:"note"`
|
||||
}
|
||||
|
||||
// portfolio — реестр клиента из ядра.
|
||||
@@ -324,6 +392,7 @@ func (s *Server) Handler() http.Handler {
|
||||
"Nav": "b", "Contract": pf.Contract, "FullName": pf.FullName,
|
||||
"Positions": pos, "Claims": claims, "Flash": r.URL.Query().Get("m"),
|
||||
"Total": total, "Free": free, "Blocked": blocked, "Active": active,
|
||||
"Value": pf.TotalValue, "Priced": pf.Priced,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -349,9 +418,32 @@ func (s *Server) Handler() http.Handler {
|
||||
"Positions": pf.Positions, "Flash": r.URL.Query().Get("m"),
|
||||
"Source": pf.Source, "ReadOnly": pf.ReadOnly, "UpdatedAt": updated,
|
||||
"Total": total, "Free": free, "Blocked": blocked,
|
||||
"Value": pf.TotalValue, "Priced": pf.Priced,
|
||||
})
|
||||
})
|
||||
|
||||
// Карточка бумаги
|
||||
mux.HandleFunc("/security", func(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionW(w, r)
|
||||
if sess == "" {
|
||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
isin := strings.ToUpper(strings.TrimSpace(r.URL.Query().Get("isin")))
|
||||
if isin == "" {
|
||||
http.Redirect(w, r, "/portfolio", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
var out struct {
|
||||
Security securityCard `json:"security"`
|
||||
}
|
||||
if err := bj.call(r.Context(), http.MethodGet, "/api/lk/security?isin="+url.QueryEscape(isin), sess, nil, &out); err != nil {
|
||||
s.render(w, r, "security", map[string]any{"Nav": "p", "Error": err.Error(), "ISIN": isin})
|
||||
return
|
||||
}
|
||||
s.render(w, r, "security", map[string]any{"Nav": "p", "S": out.Security, "ISIN": isin})
|
||||
})
|
||||
|
||||
// Профиль: договор, счета депо, доступ
|
||||
mux.HandleFunc("/profile", func(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionW(w, r)
|
||||
|
||||
+23
-3
@@ -28,8 +28,8 @@ func fakeBJ(t *testing.T) *httptest.Server {
|
||||
})
|
||||
mux.HandleFunc("/api/lk/portfolio", func(w http.ResponseWriter, r *http.Request) {
|
||||
if keyOK(w, r) && r.Header.Get("X-BJ-Session") == "sess-1" {
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"full_name": "Мостовиков Тест", "contract": "4519", "source": "депозитарный учёт", "positions": []any{
|
||||
map[string]any{"isin": "RU0009029540", "security_name": "Сбербанк, ао", "account_id": "ВТНКЦ00000001", "quantity": 400, "blocked": 100, "available": 300, "transferable": true, "updated_at": "17.09.2026 21:58"},
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"full_name": "Мостовиков Тест", "contract": "4519", "source": "депозитарный учёт", "total_value": 110268.0, "priced": 1, "positions": []any{
|
||||
map[string]any{"isin": "RU0009029540", "security_name": "Сбербанк, ао", "account_id": "ВТНКЦ00000001", "quantity": 400, "blocked": 100, "available": 300, "transferable": true, "updated_at": "17.09.2026 21:58", "price": 275.67, "value": 110268, "change_pct": -1.53},
|
||||
map[string]any{"isin": "US0378331005", "security_name": "Apple Inc.", "account_id": "В000000044", "quantity": 12, "blocked": 0, "available": 0, "transferable": false, "note": "иностранная бумага — перевод через M2M недоступен"},
|
||||
}})
|
||||
}
|
||||
@@ -42,6 +42,17 @@ func fakeBJ(t *testing.T) *httptest.Server {
|
||||
}})
|
||||
}
|
||||
})
|
||||
mux.HandleFunc("/api/lk/security", func(w http.ResponseWriter, r *http.Request) {
|
||||
if keyOK(w, r) && r.Header.Get("X-BJ-Session") == "sess-1" {
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"security": map[string]any{
|
||||
"isin": "RU0009029540", "name": "Сбербанк РФ-АО3", "kind": "акция", "issuer": "ПАО Сбербанк",
|
||||
"reg_number": "10301481B", "cfi": "ESVXFR", "face": 3, "accepted": true, "price": 275.67, "price_in": "₽ за штуку",
|
||||
"board": "TQBR", "change_pct": -1.53,
|
||||
"position": map[string]any{"isin": "RU0009029540", "quantity": 400, "available": 300, "value": 110268, "transferable": true},
|
||||
"payments": []any{map[string]any{"date": "18.10.2026", "kind": "дивиденды", "amount": 34.5}},
|
||||
}})
|
||||
}
|
||||
})
|
||||
mux.HandleFunc("/api/lk/ping", func(w http.ResponseWriter, r *http.Request) {
|
||||
if keyOK(w, r) {
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"ok": true})
|
||||
@@ -154,11 +165,14 @@ func TestBoardPages(t *testing.T) {
|
||||
return rec.Body.String()
|
||||
}
|
||||
board := get("/")
|
||||
for _, want := range []string{"Бумаг в реестре", "Новое поручение", "Сбербанк, ао", "Отправлено в НРД", "Поручений в работе"} {
|
||||
for _, want := range []string{"Стоимость бумаг", "Новое поручение", "Сбербанк, ао", "Отправлено в НРД", "Поручений в работе"} {
|
||||
if !strings.Contains(board, want) {
|
||||
t.Errorf("на табло нет %q", want)
|
||||
}
|
||||
}
|
||||
if !strings.Contains(board, "110 268 ₽") {
|
||||
t.Errorf("на табло нет оценки портфеля")
|
||||
}
|
||||
reg := get("/portfolio")
|
||||
for _, want := range []string{"ВТНКЦ00000001", "иностранный выпуск", "депозитарный учёт", "перевести"} {
|
||||
if !strings.Contains(reg, want) {
|
||||
@@ -175,6 +189,12 @@ func TestBoardPages(t *testing.T) {
|
||||
t.Errorf("в бланке поручения нет %q", want)
|
||||
}
|
||||
}
|
||||
card := get("/security?isin=RU0009029540")
|
||||
for _, want := range []string{"ПАО Сбербанк", "Код CFI", "275,67", "дивиденды", "Перевести эту бумагу"} {
|
||||
if !strings.Contains(card, want) {
|
||||
t.Errorf("в карточке бумаги нет %q", want)
|
||||
}
|
||||
}
|
||||
prof := get("/profile")
|
||||
if !strings.Contains(prof, "Счета депо") || !strings.Contains(prof, "ВТНКЦ00000001") {
|
||||
t.Errorf("профиль: %s", prof)
|
||||
|
||||
+66
-8
@@ -88,6 +88,8 @@ input[type=checkbox]{width:20px;min-height:20px;height:20px}
|
||||
@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">
|
||||
@@ -138,9 +140,9 @@ input[type=checkbox]{width:20px;min-height:20px;height:20px}
|
||||
{{define "board"}}{{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">{{.Total}}</div>
|
||||
<div class="n" style="font-size:13px;color:var(--dim);margin-top:6px">{{with .FullName}}{{.}} · {{end}}договор {{.Contract}}</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>
|
||||
@@ -168,12 +170,13 @@ input[type=checkbox]{width:20px;min-height:20px;height:20px}
|
||||
<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>Состояние</th></tr></thead>
|
||||
<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><b>{{.SecurityName}}</b><div class="n" style="font-size:12.5px;color:var(--mut)">{{.ISIN}}</div></td>
|
||||
<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}}
|
||||
@@ -183,7 +186,8 @@ input[type=checkbox]{width:20px;min-height:20px;height:20px}
|
||||
{{define "portfolio"}}{{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">{{.Source}}{{with .UpdatedAt}} · {{.}}{{end}}</div></div>
|
||||
{{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>
|
||||
@@ -196,13 +200,15 @@ input[type=checkbox]{width:20px;min-height:20px;height:20px}
|
||||
{{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>Состояние</th><th></th></tr></thead>
|
||||
<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><b>{{.SecurityName}}</b><div class="n" style="font-size:12.5px;color:var(--mut)">{{.ISIN}}{{with .SecurityCode}} · {{.}}{{end}}</div></td>
|
||||
<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>
|
||||
@@ -364,4 +370,56 @@ input[type=checkbox]{width:20px;min-height:20px;height:20px}
|
||||
|
||||
<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}}
|
||||
`
|
||||
|
||||
Reference in New Issue
Block a user