Files

128 lines
4.6 KiB
Go

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", "0000"), Num: v("num", "000000"),
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)
})
}