feat(bj): модуль ЛК на PostgreSQL, обмен с DEPO, боевой ЛК с имитатором НРД, QUIK, НПР
- bj_exchange и «кран» Fancy убраны: данные модуля ЛК в PostgreSQL (схема lk) - трансферные таблицы FTV_M2M: создание при установке, события, справочник участников - сверка с DEPO: счёт, ФИО, дата рождения, ИИС по договору, квал-инвестор из опции DEPO - боевой ЛК ЕСИА Финанс при тестовом ИШ: журнал, отказ через DEPO, статусы в ЛК - онлайн-лицензирование в bj, план тестирования M2M для контрагента (интерактивный HTML) - модули QUIK МНП, экспорт QUIK, НПР/УДС; документы и тестовые материалы Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
package lkgateway
|
||||
|
||||
// journal.go — объединённый журнал обмена: входящие + исходящие переводы в одной
|
||||
// хронологической ленте (плюс отдельные виды — «Исходящие» и «Входящие» на своих
|
||||
// страницах). Для быстрого обзора всего потока с контрагентами.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/m2mcore"
|
||||
)
|
||||
|
||||
// journalRow — одна строка объединённого журнала.
|
||||
type journalRow struct {
|
||||
Time time.Time
|
||||
Dir string // "Исходящий" | "Входящий"
|
||||
DirKind string // "out" | "in"
|
||||
Party string // контрагент (наименование + код/ИНН)
|
||||
SecN int
|
||||
Status string // класс бейджа (для цвета)
|
||||
StatusText string // человекочитаемый текст статуса (русский)
|
||||
Outcome string // для входящих: «Принято» / «Отказано» / «Частично …»
|
||||
Href string
|
||||
}
|
||||
|
||||
// incomingJournalStatus — статус входящего для журнала: класс бейджа (цвет),
|
||||
// текст и исход по бумагам (принято/отказано/частично).
|
||||
func incomingJournalStatus(it *IncomingTransfer) (class, text, outcome string) {
|
||||
if it.Status != "answered" {
|
||||
return "pending", "Ждёт решения", ""
|
||||
}
|
||||
conf, rej := 0, 0
|
||||
for _, s := range it.Securities {
|
||||
switch s.Decision {
|
||||
case "confirmed":
|
||||
conf++
|
||||
case "rejected":
|
||||
rej++
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case rej == 0 && conf > 0:
|
||||
return "confirmed", "Отвечено", "Принято"
|
||||
case conf == 0 && rej > 0:
|
||||
return "rejected", "Отвечено", "Отказано"
|
||||
case conf > 0 && rej > 0:
|
||||
return "awaiting_decision", "Отвечено", fmt.Sprintf("Частично: принято %d, отказано %d", conf, rej)
|
||||
}
|
||||
return "confirmed", "Отвечено", ""
|
||||
}
|
||||
|
||||
// incomingStatusVM — статус входящего для шаблонов (класс бейджа + текст + исход).
|
||||
type incomingStatusVM struct{ Class, Text, Outcome string }
|
||||
|
||||
// incomingStatusOf — статус входящего для страницы «Входящие» (template-func).
|
||||
func incomingStatusOf(it *IncomingTransfer) incomingStatusVM {
|
||||
c, t, o := incomingJournalStatus(it)
|
||||
return incomingStatusVM{Class: c, Text: t, Outcome: o}
|
||||
}
|
||||
|
||||
// registerJournal вешает /admin/journal — объединённая лента вход+исход.
|
||||
func registerJournal(mux *http.ServeMux, a *admin, svc *Service, store *IncomingStore) {
|
||||
mux.HandleFunc("/admin/journal", func(w http.ResponseWriter, r *http.Request) {
|
||||
var rows []journalRow
|
||||
|
||||
// Исходящие (наши заявки в НРД).
|
||||
if page, err := svc.ListClaims(r.Context(), m2mcore.Filter{Limit: 100}); err == nil {
|
||||
for _, c := range page.Items {
|
||||
party := m2mPartyName(c.ReceivingDepositoryINN)
|
||||
if party != "" {
|
||||
party += " · ИНН " + c.ReceivingDepositoryINN
|
||||
} else {
|
||||
party = "ИНН " + c.ReceivingDepositoryINN
|
||||
}
|
||||
rows = append(rows, journalRow{
|
||||
Time: c.CreatedAt, Dir: "Исходящий", DirKind: "out",
|
||||
Party: party, SecN: len(c.Securities),
|
||||
Status: c.Status, StatusText: russianState(c.Status),
|
||||
Href: "/admin/claims/" + c.ID,
|
||||
})
|
||||
}
|
||||
}
|
||||
// Входящие (переводы к нам).
|
||||
for _, it := range store.List() {
|
||||
party := m2mPartyName(it.SenderCode)
|
||||
if party == "" {
|
||||
party = m2mPartyName(it.SenderINN)
|
||||
}
|
||||
if party != "" {
|
||||
party += " · " + it.SenderCode
|
||||
} else {
|
||||
party = it.SenderCode
|
||||
}
|
||||
cls, txt, outcome := incomingJournalStatus(it)
|
||||
rows = append(rows, journalRow{
|
||||
Time: it.ReceivedAt, Dir: "Входящий", DirKind: "in",
|
||||
Party: party, SecN: len(it.Securities),
|
||||
Status: cls, StatusText: txt, Outcome: outcome,
|
||||
Href: "/admin/incoming/" + it.ID,
|
||||
})
|
||||
}
|
||||
sort.Slice(rows, func(i, j int) bool { return rows[i].Time.After(rows[j].Time) })
|
||||
|
||||
data := struct {
|
||||
page
|
||||
Rows []journalRow
|
||||
}{nowPage("Журнал обмена", "journal"), rows}
|
||||
render(w, a.journal, data)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user