Входящие 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
This commit is contained in:
zuevav
2026-09-25 15:36:58 +03:00
parent 76b97b0755
commit 92afdd2868
12 changed files with 90 additions and 103 deletions
+22 -22
View File
@@ -339,35 +339,31 @@ func finishSec(sr *depoSecResult) {
}
}
// finishResult — итог по переводу. Пакет принимается только целиком (решение 16.09.2026): если хотя
// бы по одной бумаге отказ, отказ рекомендуется по всем бумагам с кодом первой отказной.
// finishResult — итог по переводу. Частичный приём (решение 25.09.2026): каждая бумага решается сама
// по себе — прошедшие проверки принимаются, остальным отказ со своим кодом. НРД так допускает: по
// каждой принятой бумаге приходит свой черновик 16/1 и подаётся своё поручение. Переводы на ИИС не
// принимаются совсем — это отдельная проверка по каждой бумаге (отказ всем).
func finishResult(res *depoResult) {
first := -1
for i, s := range res.Secs {
if s.Recommend != "confirm" {
first = i
break
conf, rej, code, sec := 0, 0, "", ""
for _, s := range res.Secs {
if s.Recommend == "confirm" {
conf++
continue
}
rej++
if code == "" {
code, sec = s.RejectCode, s.Security
}
}
switch {
case len(res.Secs) == 0:
case first < 0:
case rej == 0:
res.Recommend, res.Summary = "confirm", "принять"
default:
code, sec := res.Secs[first].RejectCode, res.Secs[first].Security
passed := 0
for i := range res.Secs {
if res.Secs[i].Recommend == "confirm" {
passed++
res.Secs[i].Recommend, res.Secs[i].RejectCode = "reject", code
res.Secs[i].Checks = append(res.Secs[i].Checks, depoCheck{Name: "Пакет принимается только целиком", OK: false, Code: code,
Detail: "сама бумага проверку прошла; отказ всем пакетом из-за " + sec + " (" + code + ")"})
}
}
case conf == 0:
res.Recommend, res.Summary = "reject", "отказ "+code
if passed > 0 {
res.Summary = fmt.Sprintf("отказ пакетом %s (из-за %s)", code, sec)
}
default:
res.Recommend = "partial"
res.Summary = fmt.Sprintf("частично: принять %d, отказ %d (первый — %s по %s)", conf, rej, code, sec)
}
}
@@ -418,6 +414,10 @@ func runDepoCheck(it *IncomingTransfer) depoResult {
for _, s := range it.Securities {
isin := strings.ToUpper(strings.TrimSpace(s.ISIN))
sr := depoSecResult{ReferenceID: s.ReferenceID, Security: pick(isin, s.SecurityCode)}
if incomingIsIIS(it) { // решение 25.09.2026: входящие переводы на ИИС не принимаем совсем
sr.Checks = append(sr.Checks, depoCheck{Name: "Перевод не на ИИС", OK: false, Code: "M2M07",
Detail: "перевод на ИИС (в запросе договор ИИС) — входящие переводы на ИИС не принимаем, отказ по всем бумагам"})
}
ruOK := strings.HasPrefix(isin, "RU")
sr.Checks = append(sr.Checks, depoCheck{Name: "Российский выпуск (RU-ISIN)", OK: ruOK, Code: "M2M01",
Detail: pick3(ruOK, "допускается к переводам M2M", "не-RU ISIN — к M2M не допускается")})