//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 != "" { 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) } } }