Сверка DEPO: квалификация по признаку бумаги — входящие: зелёный/отказ M2M08, исходящие: зелёный/предупреждение (решает получатель); общая жёлтая строка убрана
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user