Тест DEPO: сверка шлюза с DEPO как в бою (иностранные ISIN, остаток, счёт…): зачисление — отказ с кодом, списание — перевод не отправляется; режим «без проверки» для отладки джобы; статус «остановлен»
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -44,6 +44,7 @@ var depoTestOutcomes = []struct{ Code, Title string }{
|
||||
type DepoTestLine struct {
|
||||
Ref, ISIN, Qty, Outcome, Code string
|
||||
Code2 string // код бумаги в НРД, ушедший в SEC_CODE
|
||||
Gate string // проверка шлюза bj (как в бою): пусто — пройдена, иначе причина
|
||||
State, DOL, Comment string // результат джобы по строке FTV_M2M_LINES
|
||||
}
|
||||
|
||||
@@ -63,6 +64,7 @@ type DepoTestRun struct {
|
||||
Status string // running | done | error
|
||||
Doc, HeaderState, HeaderComment string
|
||||
Errors int
|
||||
GateMode string // strict — как в бою | off — без проверки
|
||||
}
|
||||
|
||||
type depoTestStore struct {
|
||||
@@ -187,6 +189,7 @@ func depoTestExec(rc *RuntimeConfig, run *DepoTestRun, pace time.Duration, stopO
|
||||
}
|
||||
})
|
||||
if state == "ERROR" && stopOnError {
|
||||
globalDepoTests.update(id, func(r *DepoTestRun) { r.Status = "stopped" })
|
||||
depoTestFinish(db, id, run.GUID)
|
||||
return
|
||||
}
|
||||
@@ -253,6 +256,10 @@ func depoTestExec(rc *RuntimeConfig, run *DepoTestRun, pace time.Duration, stopO
|
||||
}
|
||||
})
|
||||
if st == "ERROR" && stopOnError {
|
||||
globalDepoTests.update(id, func(r *DepoTestRun) {
|
||||
r.Status = "stopped"
|
||||
r.Steps = append(r.Steps, DepoTestStep{At: time.Now(), Title: "Сценарий остановлен на ошибке джобы (галочка «остановиться на первой ошибке»): оставшиеся шаги не записаны", State: "WARN"})
|
||||
})
|
||||
depoTestFinish(db, id, run.GUID)
|
||||
return
|
||||
}
|
||||
@@ -418,6 +425,35 @@ func registerDepoTest(mux *http.ServeMux, a *admin) {
|
||||
back("Добавьте хотя бы одну бумагу")
|
||||
return
|
||||
}
|
||||
// Проверка шлюза bj — та же сверка с DEPO, что перед настоящей отправкой/решением.
|
||||
run.GateMode = "strict"
|
||||
if r.FormValue("gate") == "off" {
|
||||
run.GateMode = "off"
|
||||
}
|
||||
gate := depoTestGate(run)
|
||||
var blocked []string
|
||||
for i := range run.Lines {
|
||||
l := &run.Lines[i]
|
||||
g, ok := gate[l.Ref]
|
||||
if !ok || g.ok {
|
||||
continue
|
||||
}
|
||||
l.Gate = g.text
|
||||
if run.GateMode != "strict" || l.Outcome == dtDecline {
|
||||
continue
|
||||
}
|
||||
if dir == "in" {
|
||||
// как автоматический режим: отказ с кодом, который дала сверка
|
||||
l.Outcome, l.Code = dtDecline, pick(g.code, "M2M05")
|
||||
} else {
|
||||
blocked = append(blocked, l.ISIN+": "+g.text)
|
||||
}
|
||||
}
|
||||
if len(blocked) > 0 {
|
||||
back("В бою bj не отправил бы этот перевод — сверка списания с DEPO не пройдена: " + strings.Join(blocked, "; ") +
|
||||
". Уберите бумагу или выберите «без проверки шлюза», если нужно проверить именно джобу DEPO.")
|
||||
return
|
||||
}
|
||||
pace, _ := strconv.Atoi(r.FormValue("pace"))
|
||||
stop := r.FormValue("stop") == "1"
|
||||
globalDepoTests.mu.Lock()
|
||||
@@ -436,3 +472,46 @@ func registerDepoTest(mux *http.ServeMux, a *admin) {
|
||||
http.Redirect(w, r, "/admin/depo-test#run-"+run.ID, http.StatusSeeOther)
|
||||
})
|
||||
}
|
||||
|
||||
type depoGateLine struct {
|
||||
ok bool
|
||||
code, text string
|
||||
}
|
||||
|
||||
// depoTestGate — сверка с DEPO для строк сценария (runDepoCheck / runDepoCheckOut, как в бою).
|
||||
func depoTestGate(run *DepoTestRun) map[string]depoGateLine {
|
||||
out := map[string]depoGateLine{}
|
||||
fio := strings.Fields(run.Client)
|
||||
for len(fio) < 3 {
|
||||
fio = append(fio, "")
|
||||
}
|
||||
var res depoResult
|
||||
if run.Direction == "out" {
|
||||
var secs []depoOutSec
|
||||
for _, l := range run.Lines {
|
||||
secs = append(secs, depoOutSec{ReferenceID: l.Ref, ISIN: l.ISIN, Code: l.ISIN, Qty: l.Qty})
|
||||
}
|
||||
nsd := globalRC.Snapshot().NSD
|
||||
res = runDepoCheckOut(fio[0], fio[1], strings.Join(fio[2:], " "), run.Ser, run.Num, secs, nsd.AccountID, nsd.SectionID)
|
||||
} else {
|
||||
it := &IncomingTransfer{GUID: run.GUID, SenderCode: run.CP, ReceivedAt: time.Now(),
|
||||
InvestorLast: fio[0], InvestorFirst: fio[1], InvestorMiddle: strings.Join(fio[2:], " "),
|
||||
DocType: "21", DocSeries: run.Ser, DocNumber: run.Num}
|
||||
for _, l := range run.Lines {
|
||||
it.Securities = append(it.Securities, IncomingSecurity{ReferenceID: l.Ref, ISIN: l.ISIN, SecurityCode: l.ISIN, Quantity: l.Qty})
|
||||
}
|
||||
res = runDepoCheck(it)
|
||||
}
|
||||
for _, s := range res.Secs {
|
||||
g := depoGateLine{ok: s.Recommend != "reject", code: s.RejectCode}
|
||||
var bad []string
|
||||
for _, c := range s.Checks {
|
||||
if !c.OK {
|
||||
bad = append(bad, strings.TrimSpace(c.Name+" "+c.Detail))
|
||||
}
|
||||
}
|
||||
g.text = strings.Join(bad, "; ")
|
||||
out[s.ReferenceID] = g
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user