Эмуляция НРД: один переключатель Выключена/Подмена/Полная имитация; контур отдельно

Было: правило «боевой ЛК + тестовый профиль → принудительно имитатор» не давало выключить
эмуляцию, а подмена личности жила отдельным тумблером на другой странице — пользователь не мог
понять состояние и выключить.

Стало — явная модель (контур НРД и режим эмуляции независимы):
- «Выключена» — заявки идут в выбранный контур (NSD.Profile) с реальными данными клиента;
- «Подмена личности» — уходят в контур, но у клиентов из списка блок инвестора заменяется на
  тест-инвестора (Бубликов/Баранкин); DEPO и QUIK — по реальному клиенту;
- «Полная имитация» — в НРД ничего не уходит, bj сам отвечает (внутренний имитатор).
Режимы взаимоисключающие (ведутся флагами EmulateNSD/RealNSDTest.Enabled), принудительное
правило убрано. Единый 3-радио на /admin/emulators (как у QUIK), с показом контура, тест-инвестора
и списка паспортов; карточка на /admin/m2m-testing — статус + ссылка на «Эмуляторы».
Тесты обновлены под новую модель.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
fontvielle
2026-10-13 16:02:06 +03:00
parent 6ca556c2fc
commit cd6e2c424f
7 changed files with 140 additions and 91 deletions
+27 -6
View File
@@ -45,6 +45,9 @@ func registerEmulators(mux *http.ServeMux, a *admin, rc *RuntimeConfig) {
NSDEmuOn bool
NSDEmuWhy string
NSDFlag bool
NSDMode string
Profile string
ProfileTest bool
NSD NSDEmuSettings
RejectCodes []emuRejectOption
RealNSDOn bool
@@ -60,6 +63,9 @@ func registerEmulators(mux *http.ServeMux, a *admin, rc *RuntimeConfig) {
NSDEmuOn: nsdOn,
NSDEmuWhy: nsdWhy,
NSDFlag: s.LK.EmulateNSD,
NSDMode: nsdEmuMode(rc),
Profile: s.NSD.Profile,
ProfileTest: strings.HasPrefix(strings.ToLower(s.NSD.Profile), "test"),
RealNSDOn: s.LK.RealNSDTest.Enabled,
RealNSDDocs: s.LK.RealNSDTest.Docs,
RealNSDAs: realNSDAsText(),
@@ -80,7 +86,18 @@ func registerEmulators(mux *http.ServeMux, a *admin, rc *RuntimeConfig) {
return
}
lk := rc.Snapshot().LK
lk.EmulateNSD = r.FormValue("emulate") != ""
// Режим эмуляции НРД — взаимоисключающий: off | substitute | imitate.
switch r.FormValue("mode") {
case "imitate":
lk.EmulateNSD, lk.RealNSDTest.Enabled = true, false
case "substitute":
lk.EmulateNSD, lk.RealNSDTest.Enabled = false, true
if d := strings.TrimSpace(r.FormValue("docs")); d != "" {
lk.RealNSDTest.Docs = d
}
default: // off
lk.EmulateNSD, lk.RealNSDTest.Enabled = false, false
}
delay, err := strconv.Atoi(strings.TrimSpace(r.FormValue("delay_sec")))
if err != nil && strings.TrimSpace(r.FormValue("delay_sec")) != "" {
emuAjaxReply(w, r, http.StatusBadRequest, "Эмулятор НРД: задержка — целое число секунд")
@@ -100,13 +117,17 @@ func registerEmulators(mux *http.ServeMux, a *admin, rc *RuntimeConfig) {
return
}
applyNSDEmuSettings(rc)
msg := "выключен — заявки ЛК идут в НРД по обычному пути"
if on, why := lkEmulateNSD(rc); on {
prof := rc.Snapshot().NSD.Profile
msg := "выключена — заявки идут в выбранный контур НРД (" + prof + ") с реальными данными клиента"
switch nsdEmuMode(rc) {
case "imitate":
eff := rc.Snapshot().NSDEmu.Defaults()
msg = fmt.Sprintf("включён (%s) — в НРД ничего не отправляется; решение контрагента: %s через %d сек",
why, emuOutcomeRu(eff.Outcome), eff.DelaySec)
msg = fmt.Sprintf("полная имитация — в НРД ничего не отправляется; ответ bj: %s через %d сек",
emuOutcomeRu(eff.Outcome), eff.DelaySec)
case "substitute":
msg = "подмена личности — в НРД (" + prof + ") вместо клиента из списка уходит тест-инвестор " + realNSDAsText()
}
emuAjaxReply(w, r, http.StatusOK, "Эмулятор НРД: "+msg)
emuAjaxReply(w, r, http.StatusOK, "Эмуляция НРД: "+msg)
})
mux.HandleFunc("/admin/emulators/quik", func(w http.ResponseWriter, r *http.Request) {