Автоматический режим M2M и имитация QUIK МНП
Автоматический режим (Настройка → НРД, выключен по умолчанию): входящие переводы — решение по свежей сверке с DEPO без оператора (пакет только целиком; бумага для квал. инвесторов при неполной или непрочитанной квалификации — отказ M2M08), поручение 16/1 — как только пришёл черновик MF010, поручение 16 по исходящим — по черновику. Нет сверки или ИШ — повтор каждые 3 минуты и оповещение, без сверки ничего не принимается. Обрабатывается только появившееся не раньше суток до включения (старые черновики в INBOX не подаются). Решение не отправляется повторно по уже отвеченному переводу. Имитация QUIK МНП (Настройка → QUIK МНП → цикл): регистрация, подпись, снятие и зачисление проходят как выполненные с пометкой «имитация», в МНП ничего не пишется; события в DEPO — как обычно. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package lkgateway
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestAutoDecisions(t *testing.T) {
|
||||
it := &IncomingTransfer{Securities: []IncomingSecurity{{ReferenceID: "A"}, {ReferenceID: "B"}}}
|
||||
|
||||
// Всё прошло — согласие по всем.
|
||||
r := depoResult{Summary: "принять", Secs: []depoSecResult{{ReferenceID: "A", Recommend: "confirm"}, {ReferenceID: "B", Recommend: "confirm"}}}
|
||||
dec, _ := autoDecisions(it, r)
|
||||
if !dec[0].Confirm || !dec[1].Confirm {
|
||||
t.Fatalf("согласие: %+v", dec)
|
||||
}
|
||||
|
||||
// Отказ по одной — отказ всем пакетом с её кодом.
|
||||
r = depoResult{Summary: "отказ пакетом M2M05", Secs: []depoSecResult{{ReferenceID: "A", Recommend: "confirm"}, {ReferenceID: "B", Recommend: "reject", RejectCode: "M2M05"}}}
|
||||
dec, _ = autoDecisions(it, r)
|
||||
for _, d := range dec {
|
||||
if d.Confirm || d.RejectCode != "M2M05" {
|
||||
t.Fatalf("пакет целиком: %+v", dec)
|
||||
}
|
||||
}
|
||||
|
||||
// Бумага для квал. инвесторов при неполной квалификации — отказ M2M08 всем.
|
||||
r = depoResult{Summary: "принять", Secs: []depoSecResult{
|
||||
{ReferenceID: "A", Security: "RU000A10F5K6", Recommend: "confirm", Checks: []depoCheck{{Name: "Бумага только для квал. инвесторов", OK: true, Warn: true, Strict: true, Code: "M2M08"}}},
|
||||
{ReferenceID: "B", Recommend: "confirm", Checks: []depoCheck{{Name: "Квал-инвестор (если бумага только для квал.)", OK: true, Warn: true, Code: "M2M08"}}},
|
||||
}}
|
||||
dec, why := autoDecisions(it, r)
|
||||
for _, d := range dec {
|
||||
if d.Confirm || d.RejectCode != "M2M08" {
|
||||
t.Fatalf("строгое предупреждение: %+v", dec)
|
||||
}
|
||||
}
|
||||
if !strings.Contains(why, "RU000A10F5K6") {
|
||||
t.Fatalf("пояснение: %q", why)
|
||||
}
|
||||
|
||||
// Обычное предупреждение (клиент не квал, бумага без ограничений) отказа не даёт.
|
||||
r = depoResult{Secs: []depoSecResult{
|
||||
{ReferenceID: "A", Recommend: "confirm", Checks: []depoCheck{{OK: true, Warn: true, Code: "M2M08"}}},
|
||||
{ReferenceID: "B", Recommend: "confirm"},
|
||||
}}
|
||||
if dec, _ = autoDecisions(it, r); !dec[0].Confirm || !dec[1].Confirm {
|
||||
t.Fatalf("информационное предупреждение не должно отказывать: %+v", dec)
|
||||
}
|
||||
|
||||
// Бумага без результата сверки — не принимаем.
|
||||
r = depoResult{Secs: []depoSecResult{{ReferenceID: "A", Recommend: "confirm"}}}
|
||||
if dec, _ = autoDecisions(it, r); dec[0].Confirm || dec[1].Confirm {
|
||||
t.Fatalf("без сверки по бумаге: %+v", dec)
|
||||
}
|
||||
}
|
||||
|
||||
func TestM2MAutoState(t *testing.T) {
|
||||
st := &m2mAutoState{next: map[string]time.Time{}, alerted: map[string]time.Time{}}
|
||||
now := time.Now()
|
||||
if !st.due("k", now) {
|
||||
t.Fatal("новый шаг должен выполняться сразу")
|
||||
}
|
||||
st.retry("k", now)
|
||||
if st.due("k", now.Add(time.Minute)) || !st.due("k", now.Add(m2mAutoRetry)) {
|
||||
t.Fatal("повтор через m2mAutoRetry")
|
||||
}
|
||||
st.done("k")
|
||||
if !st.due("k", now) {
|
||||
t.Fatal("после выполнения ключ сбрасывается")
|
||||
}
|
||||
}
|
||||
|
||||
// Выключенный режим ничего не делает (и не трогает сторы).
|
||||
func TestM2MAutoDisabled(t *testing.T) {
|
||||
rc, err := NewRuntimeConfig(t.TempDir() + "/setup.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
saved := globalIncomingDeps
|
||||
globalIncomingDeps = nil
|
||||
defer func() { globalIncomingDeps = saved }()
|
||||
m2mAutoTickOnce(t.Context(), rc, time.Now())
|
||||
}
|
||||
Reference in New Issue
Block a user