Files
Bridge-and-Join-s/internal/lkgateway/lkmatch_live_test.go
T
zuevav da12a9ec1c 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>
2026-09-15 19:41:12 +03:00

148 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//go:build live
package lkgateway
// Разбор, какие данные пришли из боевого ЛК по заявке и как клиент сопоставлен с DEPO.
// Только чтение: GET из ЛК, SELECT из DEPO. Паспорт и ФИО в выводе маскируются.
// go test -c -tags live -o lkmatch.test ./internal/lkgateway/ && sudo ./lkmatch.test -test.run TestLKMatchLive -test.v
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"os"
"sort"
"strconv"
"strings"
"testing"
)
func mask(s string) string {
r := []rune(strings.TrimSpace(s))
switch {
case len(r) == 0:
return "(пусто)"
case len(r) <= 2:
return strings.Repeat("•", len(r))
}
return string(r[:1]) + strings.Repeat("•", len(r)-2) + string(r[len(r)-1:])
}
func TestLKMatchLive(t *testing.T) {
rc, err := NewRuntimeConfig("/var/lib/bj/.bj/setup.json")
if err != nil {
t.Fatal(err)
}
globalRC = rc
ep, ok := lkActiveEndpoint(rc)
if !ok {
t.Skip("ЛК не настроен")
}
id := 69753
if v := os.Getenv("CLAIM"); v != "" {
id, _ = strconv.Atoi(v)
}
ctx := context.Background()
_, body, err := lkGet(ctx, ep, "/claims/"+strconv.Itoa(id))
if err != nil {
t.Fatal(err)
}
var wrap struct {
Claim map[string]any `json:"claim"`
}
_ = json.Unmarshal(body, &wrap)
cl := wrap.Claim
data, _ := cl["data"].(map[string]any)
fmt.Printf("== Заявка ЛК #%d: kind=%v, user_id=%v, owner=%v/%v\n", id, cl["kind"], cl["user_id"], cl["owner_type"], cl["owner_id"])
keys := make([]string, 0, len(data))
for k := range data {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
b, _ := json.Marshal(data[k])
fmt.Printf(" data.%s = %s\n", k, b)
}
uid := toInt(cl["user_id"])
_, ub, _ := lkGet(ctx, ep, "/users/"+strconv.Itoa(uid))
var uw map[string]any
_ = json.Unmarshal(ub, &uw)
u := pickMap(uw, "user", "data")
if u == nil {
u = uw
}
fmt.Printf("== Пользователь ЛК #%d: поля карточки (значения ФИО и документа замаскированы)\n", uid)
ukeys := make([]string, 0, len(u))
for k := range u {
ukeys = append(ukeys, k)
}
sort.Strings(ukeys)
var present []string
for _, k := range ukeys {
if s := str(u[k]); s != "" && s != "<nil>" {
present = append(present, k)
}
}
fmt.Printf(" заполненные поля: %s\n", strings.Join(present, ", "))
for _, k := range []string{"surname", "name", "patronymic", "document_type", "pass_series", "pass_number", "document_series", "document_number", "birth_date", "inn", "snils"} {
if v, ok := u[k]; ok {
val := str(v)
if k != "document_type" {
val = mask(val)
}
fmt.Printf(" %s = %s\n", k, val)
}
}
req, err := lkClaimToRequest(ctx, rc, ep, cl, data)
if err != nil {
t.Fatal(err)
}
inv := req.Investor
fmt.Printf("== В сверку с DEPO передано: ФИО %s %s %s, документ тип %s серия %s номер %s\n",
mask(inv.LastName), mask(inv.FirstName), mask(inv.MiddleName), inv.Document.DocumentType, mask(inv.Document.Series), mask(inv.Document.Number))
var secs []depoOutSec
acc, section := "", ""
for _, s := range req.Securities {
secs = append(secs, depoOutSec{ISIN: s.SecurityDetails.ISIN, Code: s.SecurityCode, Qty: strconv.FormatUint(s.Quantity.Whole, 10)})
if len(s.SettlementAccounts) > 0 {
acc, section = s.SettlementAccounts[0].SettlementLocation.AccountID, s.SettlementAccounts[0].SettlementLocation.SectionID
}
}
if v := os.Getenv("ACCOUNT"); v != "" {
req.ClientAccount = v // проверка несовпадения: подставить чужой счёт
}
fmt.Printf("== Счёт из заявки: %s\n", req.ClientAccount)
if v := os.Getenv("IIS_ACCOUNT"); v != "" { // признак ИИС по произвольному счёту
fs := rc.Snapshot().Fancy
if db, err := fancyOpen(fs, fs.DepoDB()); err == nil {
var cid int64
_ = db.QueryRowContext(ctx, "SELECT TOP 1 ID FROM OD_CLIENTS WHERE NUMBER=@p1", sql.Named("p1", v)).Scan(&cid)
ok, det := depoAccountIIS(ctx, db, fs, cid)
fmt.Printf("== ИИС по счёту %s: не ИИС=%v — %s\n", v, ok, det)
db.Close()
}
}
if v := os.Getenv("FIO_LAST"); v != "" {
inv.LastName = v // проверка расхождения ФИО
}
if v := os.Getenv("BIRTH"); v != "" {
inv.BirthDate = v // проверка расхождения даты рождения
}
res := runDepoCheckOutAccount(inv.LastName, inv.FirstName, inv.MiddleName, inv.Document.Series, inv.Document.Number, inv.BirthDate, secs, acc, section, req.ClientAccount)
fmt.Printf("== Сверка с DEPO: итог %s; лицо в DEPO: %s; счёт: %s\n", res.Summary, mask(res.Investor), res.Account)
for _, s := range res.Secs {
for _, c := range s.Checks {
mark := "✓"
if !c.OK {
mark = "✗"
} else if c.Warn {
mark = "!"
}
fmt.Printf(" %s %s [%s]: %s\n", mark, c.Name, c.Code, c.Detail)
}
}
}