eaf7fed6ae
Решение депозитария 07.10.2026: по ИИС отвечаем M2M06 «Приостановление операций по счёту депо зачисления». Код — константа iisRejectCode: отказ по всему переводу на ИИС (iisDecisions, авто и ручной режим), проверки «Перевод не на ИИС» и «Счёт не ИИС» (было M2M08); тексты в настройках, карточке входящего и справочнике кодов. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
97 lines
4.8 KiB
Go
97 lines
4.8 KiB
Go
package lkgateway
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Частичный приём (решение 25.09.2026): каждая бумага решается сама по себе.
|
|
func TestFinishResultPartial(t *testing.T) {
|
|
res := depoResult{Secs: []depoSecResult{
|
|
{Security: "RU0009029540", Recommend: "confirm"},
|
|
{Security: "RU0007661625", Recommend: "reject", RejectCode: "M2M05"},
|
|
{Security: "RU000A0JUR61", Recommend: "confirm"},
|
|
}}
|
|
finishResult(&res)
|
|
if res.Recommend != "partial" || !strings.Contains(res.Summary, "принять 2, отказ 1") {
|
|
t.Fatalf("итог: %s %q", res.Recommend, res.Summary)
|
|
}
|
|
if res.Secs[0].Recommend != "confirm" || res.Secs[2].Recommend != "confirm" || res.Secs[1].RejectCode != "M2M05" {
|
|
t.Fatalf("бумаги решаются отдельно: %+v", res.Secs)
|
|
}
|
|
ok := depoResult{Secs: []depoSecResult{{Recommend: "confirm"}, {Recommend: "confirm"}}}
|
|
finishResult(&ok)
|
|
if ok.Recommend != "confirm" {
|
|
t.Fatalf("все бумаги прошли: %s", ok.Recommend)
|
|
}
|
|
no := depoResult{Secs: []depoSecResult{{Recommend: "reject", RejectCode: "M2M01"}, {Recommend: "reject", RejectCode: "M2M05"}}}
|
|
finishResult(&no)
|
|
if no.Recommend != "reject" || no.Summary != "отказ M2M01" {
|
|
t.Fatalf("все отклонены: %s %q", no.Recommend, no.Summary)
|
|
}
|
|
}
|
|
|
|
// Автоответ: частичное согласие уходит как есть; перевод на ИИС — отказ M2M06 по всем бумагам.
|
|
func TestAutoDecisionsPartialAndIIS(t *testing.T) {
|
|
it := &IncomingTransfer{Securities: []IncomingSecurity{{ReferenceID: "A"}, {ReferenceID: "B"}}}
|
|
r := depoResult{Secs: []depoSecResult{{ReferenceID: "A", Recommend: "confirm"}, {ReferenceID: "B", Recommend: "reject", RejectCode: "M2M05"}}}
|
|
d, _ := autoDecisions(it, r)
|
|
if !d[0].Confirm || d[1].Confirm || d[1].RejectCode != "M2M05" {
|
|
t.Fatalf("частичное согласие: %+v", d)
|
|
}
|
|
it.IIS = true
|
|
d, _ = autoDecisions(it, r)
|
|
for _, x := range d {
|
|
if x.Confirm || x.RejectCode != "M2M06" {
|
|
t.Fatalf("ИИС не принимаем: %+v", d)
|
|
}
|
|
}
|
|
legacy := &IncomingTransfer{RawXML: "<x><IIAAgreementDetails/></x>"}
|
|
if !incomingIsIIS(legacy) {
|
|
t.Fatal("ИИС у сохранённого раньше перевода — по исходному XML")
|
|
}
|
|
}
|
|
|
|
func TestQualOnlyCheck(t *testing.T) {
|
|
notQual := depoParty{faceOK: true, qualWarn: true, qualDet: "инвестор НЕ квалифицированный"}
|
|
qualAll := depoParty{faceOK: true, qualAll: true}
|
|
partial := depoParty{faceOK: true, qualDet: "инвестор — квалифицированный (опция DEPO): облигации"}
|
|
const q = "бумага предназначена для квалифицированных инвесторов (опция DEPO)"
|
|
|
|
if c := qualOnlyCheck(true, true, q, notQual); c.OK || c.Code != "M2M08" {
|
|
t.Fatalf("неквал + бумага для квал: %+v", c)
|
|
}
|
|
if c := qualOnlyCheck(true, true, q, qualAll); !c.OK || c.Warn {
|
|
t.Fatalf("квал по всем видам: %+v", c)
|
|
}
|
|
if c := qualOnlyCheck(true, true, q, partial); !c.OK || !c.Warn {
|
|
t.Fatalf("квал по части видов — решает оператор: %+v", c)
|
|
}
|
|
if c := qualOnlyCheck(true, false, "ограничений по обращению нет (опция DEPO)", notQual); !c.OK || c.Warn {
|
|
t.Fatalf("бумага без ограничений: %+v", c)
|
|
}
|
|
if c := qualOnlyCheck(true, true, q, depoParty{}); !c.OK {
|
|
t.Fatalf("инвестор не найден — отказ даёт M2M04, не эта проверка: %+v", c)
|
|
}
|
|
}
|
|
|
|
// Списание: бумага для квал. инвесторов у неквалифицированного у нас клиента — предупреждение, не отказ.
|
|
func TestOutQualCheck(t *testing.T) {
|
|
const q = "бумага предназначена для квалифицированных инвесторов (опция DEPO)"
|
|
notQual := depoParty{faceOK: true, qualWarn: true, qualDet: "инвестор НЕ квалифицированный"}
|
|
if c := outQualCheck(true, true, q, notQual); !c.OK || !c.Warn || c.Strict {
|
|
t.Fatalf("неквал у нас отправляет бумагу для квал: %+v", c)
|
|
}
|
|
if c := outQualCheck(true, true, q, depoParty{faceOK: true, qualAll: true}); !c.OK || c.Warn {
|
|
t.Fatalf("квал по всем видам: %+v", c)
|
|
}
|
|
if c := outQualCheck(true, false, "ограничений по обращению нет (опция DEPO)", notQual); !c.OK || c.Warn {
|
|
t.Fatalf("бумага без ограничений — зелёный: %+v", c)
|
|
}
|
|
for _, c := range partyChecks(notQual, "1", "2", "x") {
|
|
if strings.HasPrefix(c.Name, "Квал") {
|
|
t.Fatalf("общая жёлтая строка квалификации больше не нужна: %+v", c)
|
|
}
|
|
}
|
|
}
|