Портфель ЛК: под карточкой только последняя ручная заливка

Каждая «Залить сейчас» оставляла строку навсегда (до перезапуска). Теперь
ручная заливка заменяет прежнюю ручную; клиенты постоянного заполнения
остаются. Пропущенные бумаги — свёрнутым списком «пропущено бумаг: N».

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
fontvielle
2026-10-22 12:27:37 +03:00
parent 5c4a12fb0b
commit c6f83e212e
2 changed files with 34 additions and 3 deletions
+33 -2
View File
@@ -20,6 +20,7 @@ import (
"io"
"log"
"net/http"
"sort"
"strings"
"sync"
"time"
@@ -216,6 +217,7 @@ type LKPortfolioSyncState struct {
Skipped []string
Err string
hash string
manual bool // ручная заливка («Залить сейчас»), не постоянное заполнение
}
var lkPortfolioState = struct {
@@ -246,7 +248,7 @@ func lkPortfolioSyncTick(ctx context.Context, rc *RuntimeConfig, force bool) {
s = &LKPortfolioSyncState{LK: pr.LK, Depo: pr.Depo}
lkPortfolioState.m[pr.LK] = s
}
s.Depo, s.CheckedAt = pr.Depo, time.Now()
s.Depo, s.CheckedAt, s.manual = pr.Depo, time.Now(), false
if err != nil {
if s.Err != err.Error() {
log.Printf("lk-portfolio: %s ← %s: %v", pr.LK, pr.Depo, err)
@@ -290,7 +292,8 @@ func lkPortfolioSyncTick(ctx context.Context, rc *RuntimeConfig, force bool) {
}
}
// lkPortfolioStates — состояние синхронизации для страницы настроек.
// lkPortfolioStates — состояние для страницы настроек: последняя ручная заливка сверху, затем клиенты
// постоянного заполнения.
func lkPortfolioStates() []LKPortfolioSyncState {
lkPortfolioState.Lock()
defer lkPortfolioState.Unlock()
@@ -298,9 +301,29 @@ func lkPortfolioStates() []LKPortfolioSyncState {
for _, s := range lkPortfolioState.m {
out = append(out, *s)
}
sort.Slice(out, func(i, j int) bool {
if out[i].manual != out[j].manual {
return out[i].manual
}
return out[i].LK < out[j].LK
})
return out
}
// lkPortfolioInSync — договор в постоянном заполнении (по списку или «для всех»).
func lkPortfolioInSync(rc *RuntimeConfig, lk string) bool {
ps := rc.Snapshot().LK.PortfolioSync
if ps.Enabled && ps.AllClients {
return true
}
for _, p := range ps.pairs() {
if p.LK == lk {
return true
}
}
return false
}
// registerLKPortfolioSync — POST /admin/setup/lk-portfolio: настройки и «синхронизировать сейчас».
func registerLKPortfolioSync(mux *http.ServeMux, rc *RuntimeConfig) {
// GET /admin/setup/lk-portfolio/clients?q= — поиск клиента DEPO для заливки портфеля.
@@ -502,6 +525,14 @@ func lkPortfolioPushPair(ctx context.Context, rc *RuntimeConfig, pr lkPortfolioP
lkPortfolioState.m[pr.LK] = s
}
s.Depo, s.CheckedAt, s.Skipped = pr.Depo, time.Now(), skipped
if !lkPortfolioInSync(rc, pr.LK) {
s.manual = true
for k, o := range lkPortfolioState.m { // от прежних ручных заливок — только последняя
if o.manual && k != pr.LK {
delete(lkPortfolioState.m, k)
}
}
}
lkPortfolioState.Unlock()
msg := ""
if err != nil {
@@ -745,7 +745,7 @@
q.addEventListener('focus',function(){ if(!list.innerHTML) load(); });
})();
</script>
{{range lkPortfolioStates}}<div class="muted" style="font-size:12.5px;margin-top:8px"><b>{{.LK}}</b> ← {{.Depo}}: {{if .Err}}<span style="color:var(--err)">ошибка — {{.Err}}</span>{{else if .PushedAt.IsZero}}сверено {{.CheckedAt.Format "15:04:05"}}, отправки ещё не было{{else}}отправлено {{.PushedAt.Format "02.01 15:04:05"}} ({{.Lines}} бумаг), сверено {{.CheckedAt.Format "15:04:05"}}{{end}}{{range .Skipped}}<br>пропущено: {{.}}{{end}}</div>{{end}}
{{range lkPortfolioStates}}<div class="muted" style="font-size:12.5px;margin-top:8px"><b>{{.LK}}</b> ← {{.Depo}}: {{if .Err}}<span style="color:var(--err)">ошибка — {{.Err}}</span>{{else if .PushedAt.IsZero}}сверено {{.CheckedAt.Format "15:04:05"}}, отправки ещё не было{{else}}отправлено {{.PushedAt.Format "02.01 15:04:05"}} ({{.Lines}} бумаг), сверено {{.CheckedAt.Format "15:04:05"}}{{end}}{{if .Skipped}}<details style="margin-top:2px"><summary style="cursor:pointer">пропущено бумаг: {{len .Skipped}} — без номера гос. регистрации</summary>{{range .Skipped}}<div>{{.}}</div>{{end}}</details>{{end}}</div>{{end}}
</div>
<div id="lk-real-nsd" style="margin-top:14px;padding:12px 14px;border:1px solid var(--border);border-radius:10px;{{if .Settings.LK.RealNSDTest.Enabled}}background:var(--warn-weak){{end}}">
<b>Тест «боевой ЛК → тестовый контур НРД»</b> {{if .Settings.LK.RealNSDTest.Enabled}}<span class="badge awaiting_decision">включён</span>{{else}}<span class="badge draft">выключен</span>{{end}}