Files
Bridge-and-Join-s/internal/lkgateway/m2mauto_test.go
zuevav 92afdd2868 Входящие M2M: частичный приём — каждая бумага решается сама по себе (НРД допускает: по каждой принятой свой черновик 16/1); переводы на ИИС не принимаем — отказ M2M07 по всем бумагам
- finishResult: итог confirm / reject / partial, без отказа всем пакетом;
- autoDecisions и ручной ответ: без правила «целиком», квал-предупреждение — отказ только по своей бумаге;
- признак ИИС из заголовка запроса (IIAAgreementDetails), у сохранённых раньше — по исходному XML;
- форма оператора: без автоматического «отказ всем», подсказка про ИИС; тексты и тесты.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
2026-09-25 15:36:58 +03:00

82 lines
3.7 KiB
Go

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)
}
// Отказ по одной — частичный приём: остальные принимаются (решение 25.09.2026).
r = depoResult{Summary: "частично", Secs: []depoSecResult{{ReferenceID: "A", Recommend: "confirm"}, {ReferenceID: "B", Recommend: "reject", RejectCode: "M2M05"}}}
dec, _ = autoDecisions(it, r)
if !dec[0].Confirm || dec[1].Confirm || dec[1].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)
if dec[0].Confirm || dec[0].RejectCode != "M2M08" || !dec[1].Confirm {
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())
}