package lkgateway // Префикс торгового счёта клиента в учёте DEPO (OD_CLIENTS.NUMBER). У Фонтвьель — «ВТНКЦ…»; у другого // депозитария счета могут называться иначе, поэтому префикс — настройка (Fancy.AccountPrefix), и запросы // к учёту берут его через accSQL. Подсказка — какие префиксы у открытых счетов этого учёта. import ( "context" "net/http" "regexp" "strings" "time" "git.zetit.ru/zuevav/Bridge-and-Join-s/internal/lkgateway/fsql" ) const defaultAccPrefix = "ВТНКЦ" // accPrefixRe — только буквы, цифры и «_»: префикс подставляется в текст запроса. var accPrefixRe = regexp.MustCompile(`^[\p{L}\p{N}_]{1,20}$`) func cleanAccPrefix(p string) string { p = strings.TrimSpace(p) if accPrefixRe.MatchString(p) { return p } return "" } // depoAccPrefix — префикс торговых счетов из настроек (по умолчанию «ВТНКЦ»). func depoAccPrefix() string { if globalRC != nil { if p := cleanAccPrefix(globalRC.Snapshot().Fancy.AccountPrefix); p != "" { return p } } return defaultAccPrefix } // accSQL — запрос к учёту с подставленным префиксом торгового счёта. func accSQL(q string) string { return strings.ReplaceAll(q, "{ACC}", depoAccPrefix()) } type accPrefixCount struct { Prefix string `json:"prefix"` Count int `json:"count"` } // depoAccPrefixInfo — сколько открытых счетов с текущим префиксом и какие префиксы вообще есть. func depoAccPrefixInfo(ctx context.Context, f FancyMSSQLSettings) (cur int, cands []accPrefixCount, err error) { if f.IsPostgres() { return 0, nil, nil } db, err := fancyOpen(f, f.DepoDB()) if err != nil { return 0, nil, err } defer db.Close() if err := db.QueryRowContext(ctx, accSQL(fsql.Acc02)).Scan(&cur); err != nil { return 0, nil, err } rows, err := db.QueryContext(ctx, fsql.Acc01) if err != nil { return cur, nil, err } defer rows.Close() for rows.Next() { var c accPrefixCount if rows.Scan(&c.Prefix, &c.Count) == nil { cands = append(cands, c) } } return cur, cands, rows.Err() } // GET /admin/setup/fancy/acc-prefix — текущий префикс и подсказка; POST — сохранить. func (h *setupHandlers) accPrefix(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost { p := strings.TrimSpace(r.FormValue("account_prefix")) if p != "" && cleanAccPrefix(p) == "" { jsonOut(w, map[string]any{"ok": false, "error": "префикс — только буквы и цифры, до 20 знаков"}) return } s := h.rc.Snapshot().Fancy s.AccountPrefix = p if err := h.rc.UpdateFancy(s); err != nil { jsonOut(w, map[string]any{"ok": false, "error": err.Error()}) return } } s := h.rc.Snapshot().Fancy out := map[string]any{"ok": true, "prefix": depoAccPrefix(), "set": cleanAccPrefix(s.AccountPrefix) != ""} if strings.TrimSpace(s.Server) != "" { ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second) defer cancel() cur, cands, err := depoAccPrefixInfo(ctx, s) if err != nil { out["error"] = quikErrorDetail(err) } out["count"], out["candidates"] = cur, cands } jsonOut(w, out) }