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) // Приём ИИС по умолчанию ВЫКЛ → отказ по всему переводу (всё-или-ничего). // Бумага A (была к приёму) получает код ИИС M2M06, бумага B сохраняет свою причину M2M05. if d[0].Confirm || d[1].Confirm { t.Fatalf("ИИС выключен — принимать нельзя: %+v", d) } if d[0].RejectCode != "M2M06" || d[1].RejectCode != "M2M05" { t.Fatalf("коды отказа ИИС: A=M2M06, B сохраняет M2M05: %+v", d) } legacy := &IncomingTransfer{RawXML: ""} 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", false) { if strings.HasPrefix(c.Name, "Квал") { t.Fatalf("общая жёлтая строка квалификации больше не нужна: %+v", c) } } }