From 56068af89763922ec2cacb1f623acf621cbefb35 Mon Sep 17 00:00:00 2001 From: zuevav Date: Wed, 7 Oct 2026 08:15:06 +0300 Subject: [PATCH] =?UTF-8?q?QUIK=20=D0=B8=20=D0=9D=D0=A0=D0=94=20=D0=B2=20?= =?UTF-8?q?=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE=D0=B9=D0=BA=D0=B0=D1=85=20?= =?UTF-8?q?=E2=80=94=20=D0=BF=D1=80=D0=BE=D1=81=D1=82=D0=BE=D0=B9=20=D0=B2?= =?UTF-8?q?=D0=B8=D0=B4=20=D0=B8=20=D1=80=D0=B0=D1=81=D1=88=D0=B8=D1=80?= =?UTF-8?q?=D0=B5=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BF=D0=BE=D0=B4=20=D1=80?= =?UTF-8?q?=D0=B0=D1=81=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B5=D0=BC;=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B1=D0=BE=D1=80=20=C2=AB=D0=9A=D1=82=D0=BE=20?= =?UTF-8?q?=D0=BE=D1=82=D0=B2=D0=B5=D1=87=D0=B0=D0=B5=D1=82=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B2=D0=BE=D0=B4=D1=8B=20M2M=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - QUIK: в карточке режима — одна галочка «Клиенты подают поручения из QUIK (терминал и мобильное приложение)», сохраняется сразу; предупреждение, если режим изменён в расширенных; «Расширенные настройки» (отдельно исходящие/входящие, инструменты МНП, коды клиентов) свёрнуты, без дубля счёта и галочки терминала; формы цикла не сбрасывают поля, которых не прислали. - НРД: организация — код, ИНН, наименование в ряд; реквизиты в НРД — общий блок с мастером (nsdRequisites), «Определить из DEPO» видна (была белым по белому); блок шлюза из мастера (контуры, доступ к папкам по сети) — и в настройках; ручная настройка шлюза — под «Расширенными настройками». - Автоматический режим M2M: вместо галочки с «Сохранить» — выбор плиткой «bj сам — автоматически / Оператор», сохраняется сразу (m2mAutoCard); тот же выбор — в мастере на шаге «Проверка»; подробности — под раскрытием. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi --- internal/lkgateway/admin.go | 1 + internal/lkgateway/m2mauto.go | 20 +++++-- internal/lkgateway/quikdb_handlers.go | 30 ++++++++++- .../lkgateway/web/templates/admin_setup.html | 36 ++++--------- .../lkgateway/web/templates/admin_wizard.html | 15 +----- internal/lkgateway/web/templates/layout.html | 6 +++ .../lkgateway/web/templates/part_nsd.html | 52 +++++++++++++++++++ .../lkgateway/web/templates/part_org.html | 13 +++-- .../lkgateway/web/templates/part_quik.html | 29 ++++++----- 9 files changed, 137 insertions(+), 65 deletions(-) create mode 100644 internal/lkgateway/web/templates/part_nsd.html diff --git a/internal/lkgateway/admin.go b/internal/lkgateway/admin.go index e0b654b..937efd4 100644 --- a/internal/lkgateway/admin.go +++ b/internal/lkgateway/admin.go @@ -93,6 +93,7 @@ var templateFuncs = template.FuncMap{ } return "?" }, + "quikModeCustom": quikModeCustom, "adDraft": adDraftForView, // неудачная попытка подключить домен — форма открывается заполненной "withRet": func(d any, ret string) map[string]any { return map[string]any{"D": d, "Ret": ret} }, "whForm": func(w WorkHoursSettings, ret string) map[string]any { return map[string]any{"W": w, "Ret": ret} }, diff --git a/internal/lkgateway/m2mauto.go b/internal/lkgateway/m2mauto.go index cedcc96..761d874 100644 --- a/internal/lkgateway/m2mauto.go +++ b/internal/lkgateway/m2mauto.go @@ -285,8 +285,20 @@ func (h *setupHandlers) saveM2MAuto(w http.ResponseWriter, r *http.Request) { } cur := h.rc.Snapshot().M2MAuto on := r.FormValue("enabled") != "" + if m := r.FormValue("mode"); m != "" { // карточка «Кто отвечает на переводы M2M»: выбор плиткой + on = m == "auto" + } + ajax := r.Header.Get("X-BJ-Ajax") != "" + reply := func(msg string) { + if ajax { + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + _, _ = w.Write([]byte(msg)) + return + } + setupFlash(w, r, "Автоматический режим M2M: "+msg) + } if on == cur.Enabled { - setupFlash(w, r, "Автоматический режим M2M: без изменений") + reply("без изменений") return } s := M2MAutoSettings{Enabled: on, ChangedAt: time.Now()} @@ -294,14 +306,14 @@ func (h *setupHandlers) saveM2MAuto(w http.ResponseWriter, r *http.Request) { s.ChangedBy = u.Login } if err := h.rc.UpdateM2MAuto(s); err != nil { - setupFlash(w, r, "Автоматический режим M2M: ошибка сохранения: "+err.Error()) + reply("ошибка сохранения: " + err.Error()) return } if on { log.Printf("m2m-auto: автоматический режим ВКЛЮЧЁН (%s)", s.ChangedBy) - setupFlash(w, r, "Автоматический режим M2M включён: решения по входящим, поручения 16/1 и 16 bj отправляет сам (первый проход — в течение 30 секунд).") + reply("включён — решения по входящим, поручения 16/1 и 16 bj отправляет сам (первый проход — в течение 30 секунд)") return } log.Printf("m2m-auto: автоматический режим выключен (%s)", s.ChangedBy) - setupFlash(w, r, "Автоматический режим M2M выключен — решения и поручения снова отправляет оператор.") + reply("выключен — решения и поручения отправляет оператор") } diff --git a/internal/lkgateway/quikdb_handlers.go b/internal/lkgateway/quikdb_handlers.go index 1b08363..e5fec95 100644 --- a/internal/lkgateway/quikdb_handlers.go +++ b/internal/lkgateway/quikdb_handlers.go @@ -92,8 +92,12 @@ func (h *setupHandlers) saveQuikCycle(w http.ResponseWriter, r *http.Request) { } s.AutoOut = r.FormValue("auto_out") != "" s.AutoIn = r.FormValue("auto_in") != "" - s.PollTerminal = r.FormValue("poll_terminal") != "" - s.Account = strings.TrimSpace(r.FormValue("account")) + if r.PostForm.Has("poll_terminal_set") { // галочка теперь в простой карточке режима; здесь — только если форма её прислала + s.PollTerminal = r.FormValue("poll_terminal") != "" + } + if r.PostForm.Has("account") { // счёт задаётся в карточке режима; здесь — только если форма его прислала + s.Account = strings.TrimSpace(r.FormValue("account")) + } s.SecOut = strings.TrimSpace(r.FormValue("sec_out")) s.SecIn = strings.TrimSpace(r.FormValue("sec_in")) m := map[string]string{} @@ -142,6 +146,9 @@ func (h *setupHandlers) saveQuikMode(w http.ResponseWriter, r *http.Request) { if r.PostForm.Has("account") { s.Account = strings.TrimSpace(r.FormValue("account")) } + if r.PostForm.Has("terminal_set") { // галочка «клиенты подают поручения из QUIK» — в той же карточке + s.PollTerminal = r.FormValue("terminal") != "" + } msg := "только чтение — bj ничего в QUIK не меняет" if auto { msg = "чтение и запись — боевая работа: bj сам блокирует, списывает и зачисляет в QUIK" @@ -149,6 +156,9 @@ func (h *setupHandlers) saveQuikMode(w http.ResponseWriter, r *http.Request) { msg += "; укажите торговый счёт" } } + if s.PollTerminal { + msg += "; поручения клиентов из QUIK (терминал и мобильное приложение) bj замечает и сообщает оператору" + } if err := h.rc.UpdateQuik(s); err != nil { msg = "не сохранилось: " + err.Error() } @@ -314,3 +324,19 @@ func dfltDB(db string) string { } return db } + +// quikModeCustom — режим отличается от двух простых вариантов (записи включены, но исходящие или входящие +// выключены; или наоборот): карточка режима говорит об этом, а «Расширенные настройки» открыты. +func quikModeCustom(q QuikMNPSettings) string { + switch { + case q.WritesEnabled && !q.AutoOut && !q.AutoIn: + return "Запись в QUIK разрешена, но исходящие и входящие ведутся вручную" + case q.WritesEnabled && !q.AutoOut: + return "Исходящие переводы ведутся вручную" + case q.WritesEnabled && !q.AutoIn: + return "Входящие переводы зачисляются вручную" + case !q.WritesEnabled && (q.AutoOut || q.AutoIn): + return "Автоматика включена, но запись в QUIK запрещена главным выключателем" + } + return "" +} diff --git a/internal/lkgateway/web/templates/admin_setup.html b/internal/lkgateway/web/templates/admin_setup.html index 259da17..858b6f2 100644 --- a/internal/lkgateway/web/templates/admin_setup.html +++ b/internal/lkgateway/web/templates/admin_setup.html @@ -335,20 +335,19 @@

НРД

{{template "verline" (.Versions.Get "ish")}} {{template "orgSection" .}} -
-

Автоматический режим M2M

-

Без участия оператора, чтобы соблюдать сроки: ответ на входящие переводы по свежей сверке с DEPO (решение по каждой бумаге отдельно — возможен частичный приём; переводы на ИИС — отказ M2M06; бумага для квалифицированных инвесторов при неполной или непрочитанной квалификации клиента — отказ M2M08), подача поручения 16/1, как только НРД пришлёт черновик после нашего согласия, и подача поручения 16 по исходящим после согласия контрагента. Если DEPO или ИШ недоступны — bj повторяет каждые 3 минуты и шлёт оповещение; без сверки ничего не принимается. Обрабатывается только то, что пришло не раньше чем за сутки до включения. Кнопки в карточках остаются для ручной работы.

-
- - - -
- {{if not .Settings.M2MAuto.ChangedAt.IsZero}}

{{if .Settings.M2MAuto.Enabled}}Включён{{else}}Выключен{{end}} {{msk .Settings.M2MAuto.ChangedAt}}{{with .Settings.M2MAuto.ChangedBy}} · {{.}}{{end}}.{{if .Settings.Quik.Emulate}}{{if devOn}} Шаги QUIK МНП — в режиме имитации.{{else}} Записи в QUIK МНП сейчас не выполняются.{{end}}{{end}}

{{end}} + {{template "nsdRequisites" .}} + {{template "m2mAutoCard" (withRet . "")}} +
+

Шлюз НРД

+

bj сам ставит и настраивает интеграционный шлюз НРД на этом сервере: контуры TEST3 и боевой, переключение между ними, доступ к папкам шлюза по сети.

+ {{template "igateInstall" .}}
-

Интеграционный шлюз (ИШ)

-

{{if not .Settings.NSD.IGWBaseURL}}{{if devOn}}mock-режим — без реального ИШ.{{else}}ИШ не настроен — обмен с НРД не выполняется.{{end}}{{else}}Профиль {{.Settings.NSD.Profile}}, ИШ {{.Settings.NSD.IGWBaseURL}}.{{end}} Стенды и установка — справка.

+
+ Расширенные настройкишлюз вручную: контур, адрес веб-сервиса, ключевой контейнер, версия ИШ — обычно bj задаёт их сам +

{{if not .Settings.NSD.IGWBaseURL}}{{if devOn}}mock-режим — без реального ИШ.{{else}}ИШ не настроен — обмен с НРД не выполняется.{{end}}{{else}}Профиль {{.Settings.NSD.Profile}}, ИШ {{.Settings.NSD.IGWBaseURL}}.{{end}}

+ -
-

Депозитарные реквизиты (откуда списываются бумаги) — из договора/письма НРД. Нужны для формирования заявки на перевод.

- {{if .Settings.Fancy.Server}}
- - Счёт, код и раздел в НРД и карточка организации читаются из базы DEPO (Fancy) и подставляются в пустые поля — проверьте и сохраните. -
{{end}} - {{if .Suggest}}{{if .Suggest.AccountID}}
Найдено в DEPO: счёт {{.Suggest.AccountID}}, код {{.Suggest.DeponentCode}}, раздел {{.Suggest.SectionID}}{{if gt (len .Suggest.Sections) 1}} (открытых разделов: {{len .Suggest.Sections}}){{end}}{{if .Suggest.OrgName}}; организация {{.Suggest.OrgName}}, ИНН {{.Suggest.OrgINN}}{{end}}.{{range .Suggest.Notes}}
⚠ {{.}}{{end}}
{{end}}{{end}} - - - - - - - {{if .Suggest}}{{if gt (len .Suggest.Sections) 1}}{{range .Suggest.Sections}}{{end}}{{end}}
diff --git a/internal/lkgateway/web/templates/admin_wizard.html b/internal/lkgateway/web/templates/admin_wizard.html index f328c32..eead00b 100644 --- a/internal/lkgateway/web/templates/admin_wizard.html +++ b/internal/lkgateway/web/templates/admin_wizard.html @@ -430,19 +430,7 @@

От имени вашей организации bj отправляет и принимает переводы. {{if .DepoLicensed}}Реквизиты bj берёт из DEPO — проверьте и сохраните.{{else}}Найдите себя в справочнике участников НРД.{{end}}

{{if .Suggest}}{{if .Suggest.OrgName}}{{if not .Done.Org}}
Определено из DEPO: {{.Suggest.OrgName}}, ИНН {{.Suggest.OrgINN}}, код {{.Suggest.OrgCode}}{{if .Suggest.AccountID}}, счёт НРД {{.Suggest.AccountID}}{{end}}. Поля ниже заполнены — проверьте и нажмите «Сохранить».
{{end}}{{end}}{{end}} {{with .Fancy}}{{template "orgSection" .}}{{end}} -
-

Депозитарные реквизиты в НРД

-

Где в НРД учитываются бумаги организации — из договора с НРД{{if .Settings.Fancy.Server}} или кнопкой «Определить из DEPO»{{end}}.

- {{if .Suggest}}{{if .Suggest.AccountID}}
Найдено в DEPO: счёт {{.Suggest.AccountID}}, код {{.Suggest.DeponentCode}}, раздел {{.Suggest.SectionID}}.{{range .Suggest.Notes}}
⚠ {{.}}{{end}}
{{end}}{{end}} -
{{/* поля — в общей форме шага (org-form): одна кнопка «Сохранить» */}} -
- - - -
-
{{if .Settings.Fancy.Server}}{{end}}
-
-
+ {{template "nsdRequisites" .}} {{template "wizNav" .}}
{{end}} @@ -703,6 +691,7 @@ document.getElementById('rd-again').onclick=load; load(); })(); + {{template "m2mAutoCard" (withRet . "/admin/wizard?step=10")}} {{template "chainTest" .}} {{template "wizNav" .}} diff --git a/internal/lkgateway/web/templates/layout.html b/internal/lkgateway/web/templates/layout.html index 389c7cc..348c47e 100644 --- a/internal/lkgateway/web/templates/layout.html +++ b/internal/lkgateway/web/templates/layout.html @@ -373,6 +373,12 @@ label { font-size:13px; font-weight:500; } .adv-box[open]>summary .sum-h::before{content:"▾ "} .adv-box>summary .muted{font-size:13px} .adv-h{font-size:14.5px;font-weight:650;margin:22px 0 8px} +/* карточка «Как bj работает с QUIK»: поручения клиентов из терминала — одной галочкой */ +.quik-term{display:flex;gap:10px;align-items:flex-start;margin:16px 0 0;max-width:680px;line-height:1.45;font-size:13.5px;color:var(--text-2)} +.quik-term b{color:var(--text);font-weight:600} +.quik-term input{margin-top:3px;flex:none} +.org-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr) minmax(0,2fr);gap:10px;max-width:none} +@media (max-width:700px){.org-grid{grid-template-columns:minmax(0,1fr)}} @media (max-width:820px) { .settings { grid-template-columns:1fr; } .settings-nav { flex-direction:row; overflow-x:auto; position:static; padding-bottom:8px; } diff --git a/internal/lkgateway/web/templates/part_nsd.html b/internal/lkgateway/web/templates/part_nsd.html new file mode 100644 index 0000000..dde3669 --- /dev/null +++ b/internal/lkgateway/web/templates/part_nsd.html @@ -0,0 +1,52 @@ +{{/* Раздел «НРД» — общие блоки «Настройки» и мастера (данные — SetupData или данные мастера: нужны .Settings, .Suggest). */}} + +{{/* Депозитарные реквизиты в НРД: поля — в форме организации (org-form), одна кнопка «Сохранить». */}} +{{define "nsdRequisites"}} +
+

Депозитарные реквизиты в НРД

+

Где в НРД учитываются бумаги организации — из договора с НРД{{if .Settings.Fancy.Server}} или кнопкой «Определить из DEPO»{{end}}.

+ {{if .Suggest}}{{if .Suggest.AccountID}}
Найдено в DEPO: счёт {{.Suggest.AccountID}}, код {{.Suggest.DeponentCode}}, раздел {{.Suggest.SectionID}}.{{range .Suggest.Notes}}
⚠ {{.}}{{end}}
{{end}}{{end}} +
{{/* поля — в общей форме шага (org-form): одна кнопка «Сохранить» */}} +
+ + + +
+
{{if .Settings.Fancy.Server}}{{end}}
+
+
+{{end}} + +{{/* Кто отвечает на переводы M2M: bj сам (автоматический режим) или оператор. Вход: withRet <данные> <куда вернуться>. */}} +{{define "m2mAutoCard"}}{{$a := .D.Settings.M2MAuto}} +
+

Кто отвечает на переводы M2M

+ + {{if .Ret}}{{end}} +
+ + +
+

Выбор сохраняется сразу.{{if not $a.ChangedAt.IsZero}} {{if $a.Enabled}}Включён{{else}}Выключен{{end}} {{msk $a.ChangedAt}}{{with $a.ChangedBy}} · {{.}}{{end}}.{{end}}{{if .D.Settings.Quik.Emulate}}{{if devOn}} Шаги QUIK МНП — в режиме имитации.{{else}} Записи в QUIK МНП сейчас не выполняются.{{end}}{{end}}

+ + +
Что bj делает сам в автоматическом режиме +
    +
  • Входящие переводы — отвечает по свежей сверке с DEPO, по каждой бумаге отдельно (возможен частичный приём). Переводы на ИИС — отказ M2M06; бумага для квалифицированных инвесторов, а у клиента нет квалификации, — отказ M2M08.
  • +
  • Поручение 16/1 — подаёт, как только НРД пришлёт черновик после нашего согласия.
  • +
  • Исходящие переводы — поручение 16 подаёт после согласия контрагента.
  • +
  • Если DEPO или шлюз НРД недоступны, bj повторяет каждые 3 минуты и шлёт оповещение; без сверки ничего не принимается.
  • +
  • При включении берутся переводы, пришедшие не раньше чем за сутки до этого. Кнопки в карточках остаются для ручной работы.
  • +
+
+
+ +{{end}} diff --git a/internal/lkgateway/web/templates/part_org.html b/internal/lkgateway/web/templates/part_org.html index 89c6f3a..1c45ea2 100644 --- a/internal/lkgateway/web/templates/part_org.html +++ b/internal/lkgateway/web/templates/part_org.html @@ -70,14 +70,13 @@ function hbBind(inp,box,list,onPick){ } {{if not .Participants}}Справочник участников ещё не получен — запросите его в «Диагностике» или введите данные вручную.{{end}} - - - - - - +
+
+
+
+
{{if and .Suggest (not .InWizard)}}{{if .Suggest.OrgName}}Из DEPO: {{.Suggest.OrgName}}, ИНН {{.Suggest.OrgINN}}, код {{.Suggest.OrgCode}} — подставлено в пустые поля.{{end}}{{end}} - {{if not .InWizard}}
{{end}}{{/* в мастере — одна кнопка внизу шага: организация и реквизиты НРД вместе */}} + {{/* кнопка «Сохранить» — в блоке «Депозитарные реквизиты в НРД» ниже: организация и реквизиты сохраняются вместе */}} {{end}} diff --git a/internal/lkgateway/web/templates/part_quik.html b/internal/lkgateway/web/templates/part_quik.html index 326f7cc..7b1dc3c 100644 --- a/internal/lkgateway/web/templates/part_quik.html +++ b/internal/lkgateway/web/templates/part_quik.html @@ -40,15 +40,17 @@ {{if not .InWizard}}{{/* в мастере вместо этой карточки — выбор «Как bj работает с QUIK» (шаг QUIK) */}} {{if .Settings.Quik.Verified}}{{template "quikModeCard" (withRet . "")}}{{end}} -
Тонкая настройка автоматического цикла (обычно не нужна) +
+
+ Расширенные настройкиотдельно исходящие и входящие, инструменты МНП, коды клиентов — нужны, только если QUIK настроен необычно
-

Автоматический цикл M2M в МНП{{if .Settings.Quik.Emulate}} {{if devOn}}имитация{{else}}остановлен{{end}}{{end}}

-

Что делает bj в Модуле неторговых поручений по ходу перевода: исходящий — при отправке в НРД регистрирует «Вывод ЦБ (M2M)» (QUIK блокирует бумаги), по подтверждению подписывает (списание), по отказу снимает с причиной; входящий — после приёма нашего поручения НРД регистрирует «Ввод ЦБ (M2M)» (зачисление сразу). Каждый шаг виден в карточке перевода и на странице QUIK МНП.

+

Автоматический цикл M2M в МНП{{if .Settings.Quik.Emulate}} {{if devOn}}имитация{{else}}остановлен{{end}}{{end}}

+

Обычно всё задаёт выбор «Только чтение / Чтение и запись» выше. Здесь — если нужно иначе: например, исходящие вести автоматически, а входящие зачислять вручную; или инструменты МНП в QUIK названы не по умолчанию.

+ Разрешить записи в МНП (главный выключатель: без него bj в QUIK ничего не меняет) {{if devOn}} {{end}} @@ -58,23 +60,19 @@ - -
- - + +
-
+
{{end}} {{if .Settings.Quik.LastReport}} @@ -141,6 +139,9 @@
+ + + {{with quikModeCustom .D.Settings.Quik}}

{{.}} — изменено в «Расширенных настройках» ниже.

{{end}}

Выбор сохраняется сразу.{{if .Ret}} Тонкая настройка — инструменты МНП, коды клиентов, поручения из терминала — в «Настройка → QUIK».{{end}}