diff --git a/internal/lkgateway/depo_check.go b/internal/lkgateway/depo_check.go index 558c43c..61e0bfe 100644 --- a/internal/lkgateway/depo_check.go +++ b/internal/lkgateway/depo_check.go @@ -268,13 +268,15 @@ func depoSecurityQualOnly(ctx context.Context, db *sql.DB, valID int64) (bool, s return false, "ограничений по обращению нет (опция DEPO)" } -// qualOnlyCheck — бумага только для квал. инвесторов против квалификации инвестора. +// qualOnlyCheck — ЗАЧИСЛЕНИЕ: бумага только для квал. инвесторов против квалификации инвестора у нас +// (не квалифицирован — отказ M2M08; бумага без ограничений — квалификация не требуется). func qualOnlyCheck(found, qualOnly bool, qdet string, p depoParty) depoCheck { c := depoCheck{Name: "Бумага только для квал. инвесторов", OK: true, Code: "M2M08", Detail: qdet} switch { case !found: c.Detail = "не проверяется — бумаги нет в справочнике" case !qualOnly: + c.Detail += " — квалификация клиента не требуется" case !p.faceOK: c.Detail += " — инвестор не найден, квалификация не проверялась" case p.qualAll: @@ -289,6 +291,26 @@ func qualOnlyCheck(found, qualOnly bool, qdet string, p depoParty) depoCheck { return c } +// outQualCheck — СПИСАНИЕ: бумага только для квал. инвесторов, а наш клиент у нас не квалифицирован — +// предупреждение, не отказ: у принимающего депозитария клиент может быть квалифицирован, решает он. +func outQualCheck(found, qualOnly bool, qdet string, p depoParty) depoCheck { + c := depoCheck{Name: "Бумага только для квал. инвесторов", OK: true, Code: "M2M08", Detail: qdet} + switch { + case !found: + c.Detail = "не проверяется — бумаги нет в справочнике" + case !qualOnly: + c.Detail += " — квалификация клиента не требуется" + case !p.faceOK: + c.Detail += " — инвестор не найден, квалификация не проверялась" + case p.qualAll: + c.Detail += " — клиент квалифицированный по всем видам бумаг" + default: + c.Warn = true + c.Detail += " — у нас клиент не квалифицирован полностью (" + p.qualDet + "); принимающий депозитарий проверит квалификацию у себя и может отказать M2M08" + } + return c +} + // depoBlocking — есть ли блокировка бумаги на счёте (BLOCK_DATE либо остаток на 98070.05/.07/.08/.09). func depoBlocking(ctx context.Context, db *sql.DB, valID, clientID int64) (ok bool, det string) { var blockDate sql.NullTime @@ -370,7 +392,6 @@ func partyChecks(p depoParty, ser, num, fio string) []depoCheck { {Name: "Статус счёта строго «открыт»", OK: p.accOpen != "", Code: "M2M02", Detail: pick3(p.accAny == "", "не проверяется — счёта нет", pick3(p.accOpen != "", p.accOpen+" — открыт (STATE=0, без даты закрытия)", p.accAny+" — НЕ открыт (закрыт или STATE≠0)"))}, {Name: "Счёт не ИИС", OK: p.iisOK, Code: "M2M08", Detail: p.iisDet}, - {Name: "Квал-инвестор (если бумага только для квал.)", OK: p.qualOK, Warn: p.qualWarn, Code: "M2M08", Detail: p.qualDet}, } } @@ -535,6 +556,11 @@ func runDepoCheckOutAccount(last, first, middle, ser, num, birth string, secs [] valID, vname, found, _ := depoSecurity(ctx, db, isin) sr.Checks = append(sr.Checks, depoCheck{Name: "Бумага есть в справочнике", OK: found, Code: "M2M05", Detail: pick3(found, vname+" (ID "+fmt.Sprint(valID)+")", "ISIN "+isin+" в справочнике OD_VALUES нет")}) + qualOnly, qdet := false, "" + if found { + qualOnly, qdet = depoSecurityQualOnly(ctx, db, valID) + } + sr.Checks = append(sr.Checks, outQualCheck(found, qualOnly, qdet, p)) sr.Checks = append(sr.Checks, partyChecks(p, ser, num, fio)...) if birthCheck != nil { sr.Checks = append(sr.Checks, *birthCheck) diff --git a/internal/lkgateway/depo_package_test.go b/internal/lkgateway/depo_package_test.go index 0fc18a7..19633bf 100644 --- a/internal/lkgateway/depo_package_test.go +++ b/internal/lkgateway/depo_package_test.go @@ -71,3 +71,23 @@ func TestQualOnlyCheck(t *testing.T) { 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) + } + } +}