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,127 @@
|
||||
package lkgateway
|
||||
|
||||
// depo_sim.go — песочница сверки с DEPO («имитация ответа Fancy»).
|
||||
// Два режима: «зачисление» (входящий) и «списание» (исходящий). Оператор берёт
|
||||
// реального клиента и бумагу из DEPO, меняет любые поля и нажимает «Проверить» —
|
||||
// отрабатывают те же runDepoCheck / runDepoCheckOut, что и по настоящим
|
||||
// переводам. В НРД и контрагенту ничего не отправляется.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type depoSimClient struct{ Name, Ser, Num, Account string }
|
||||
type depoSimSec struct{ ISIN, Name string }
|
||||
|
||||
// depoSimLists — реальные клиенты с открытым торговым счётом и бумаги на
|
||||
// обслуживании из DEPO (для выпадающих списков). Ошибки глушим — списки
|
||||
// вспомогательные, форму можно заполнить руками.
|
||||
func depoSimLists() (clients []depoSimClient, secs []depoSimSec) {
|
||||
if globalRC == nil {
|
||||
return
|
||||
}
|
||||
fs := globalRC.Snapshot().Fancy
|
||||
if strings.TrimSpace(fs.Server) == "" {
|
||||
return
|
||||
}
|
||||
db, err := fancyOpen(fs, fs.DepoDB())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second)
|
||||
defer cancel()
|
||||
|
||||
rows, err := db.QueryContext(ctx,
|
||||
`SELECT TOP 25 ISNULL(f.NAME,''), ISNULL(f.DOC_SER,''), ISNULL(f.DOC_NUM,''), ISNULL(c.NUMBER,'')
|
||||
FROM OD_FACES f JOIN OD_CLIENTS c ON c.FACE=f.ID
|
||||
WHERE c.NUMBER LIKE N'ВТНКЦ%' AND c.STATE=0 AND c.D_CLOSE IS NULL
|
||||
AND LEN(ISNULL(f.DOC_SER,''))>0 AND LEN(ISNULL(f.DOC_NUM,''))>0
|
||||
ORDER BY f.NAME`)
|
||||
if err == nil {
|
||||
defer rows.Close()
|
||||
seen := map[string]bool{}
|
||||
for rows.Next() {
|
||||
var c depoSimClient
|
||||
if rows.Scan(&c.Name, &c.Ser, &c.Num, &c.Account) == nil && !seen[c.Name] {
|
||||
seen[c.Name] = true
|
||||
c.Ser = strings.ReplaceAll(c.Ser, " ", "")
|
||||
clients = append(clients, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
rows2, err := db.QueryContext(ctx,
|
||||
`SELECT TOP 20 ISNULL(ISIN,''), ISNULL(NAME,'') FROM OD_VALUES
|
||||
WHERE V_TYPE=2 AND IS_IN=1 AND ISIN LIKE 'RU%' ORDER BY NAME`)
|
||||
if err == nil {
|
||||
defer rows2.Close()
|
||||
for rows2.Next() {
|
||||
var s depoSimSec
|
||||
if rows2.Scan(&s.ISIN, &s.Name) == nil && s.ISIN != "" {
|
||||
secs = append(secs, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// registerDepoSim вешает /admin/m2m-testing/depo-sim (GET — форма, POST — проверка).
|
||||
func registerDepoSim(mux *http.ServeMux, a *admin) {
|
||||
mux.HandleFunc("/admin/m2m-testing/depo-sim", func(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
v := func(k, def string) string {
|
||||
if s := strings.TrimSpace(r.FormValue(k)); s != "" {
|
||||
return s
|
||||
}
|
||||
return def
|
||||
}
|
||||
defAcc, defSec := "HL171004001C", "36MC0413600000F00"
|
||||
if globalRC != nil {
|
||||
nsd := globalRC.Snapshot().NSD
|
||||
defAcc, defSec = pick(nsd.AccountID, defAcc), pick(nsd.SectionID, defSec)
|
||||
}
|
||||
form := struct {
|
||||
Mode, Last, First, Middle, Ser, Num, ISIN, Code, Qty, Account, Section string
|
||||
}{
|
||||
Mode: v("mode", "in"),
|
||||
Last: v("last", "Силаев"), First: v("first", "Михаил"), Middle: v("middle", "Иванович"),
|
||||
Ser: v("ser", "4505"), Num: v("num", "620343"),
|
||||
ISIN: strings.ToUpper(v("isin", "RU0009029540")), Code: v("code", ""), Qty: v("qty", "10"),
|
||||
Account: v("account", defAcc), Section: v("section", defSec),
|
||||
}
|
||||
if form.Mode != "out" {
|
||||
form.Mode = "in"
|
||||
}
|
||||
var res *depoResult
|
||||
if r.Method == http.MethodPost {
|
||||
var rr depoResult
|
||||
if form.Mode == "out" {
|
||||
rr = runDepoCheckOut(form.Last, form.First, form.Middle, form.Ser, form.Num,
|
||||
[]depoOutSec{{ReferenceID: "sim-1", ISIN: form.ISIN, Code: pick(form.Code, form.ISIN), Qty: form.Qty}},
|
||||
form.Account, form.Section)
|
||||
} else {
|
||||
it := &IncomingTransfer{
|
||||
GUID: "SIMULATION", SenderCode: "SIM", ReceivedAt: time.Now(),
|
||||
InvestorLast: form.Last, InvestorFirst: form.First, InvestorMiddle: form.Middle,
|
||||
DocType: "21", DocSeries: form.Ser, DocNumber: form.Num,
|
||||
Securities: []IncomingSecurity{{ReferenceID: "sim-1", ISIN: form.ISIN, SecurityCode: pick(form.Code, form.ISIN), Quantity: form.Qty}},
|
||||
}
|
||||
rr = runDepoCheck(it)
|
||||
}
|
||||
res = &rr
|
||||
}
|
||||
clients, secs := depoSimLists()
|
||||
data := struct {
|
||||
page
|
||||
Form any
|
||||
Result *depoResult
|
||||
Clients []depoSimClient
|
||||
Secs []depoSimSec
|
||||
Posted bool
|
||||
}{nowPage("Имитация сверки с DEPO", "m2mtest"), form, res, clients, secs, r.Method == http.MethodPost}
|
||||
render(w, a.depoSim, data)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user