DEPO: тестовый прогон исходящего (копия сделки на реального клиента, имитация решения контрагента, формы 16 и MS010) + список сделок для прогона

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
zuevav
2026-09-22 21:33:14 +03:00
parent fc9f00a229
commit 79d0d6b76c
2 changed files with 117 additions and 0 deletions
+71
View File
@@ -1053,3 +1053,74 @@ func depoSimulateIncoming(ctx context.Context, rc *RuntimeConfig, it *IncomingTr
}
return guid, nil
}
// depoSimulateOutgoing — копия исходящего перевода (бумаги и решение контрагента как в оригинале)
// на реального клиента DEPO по паспорту: новый GUID, шапка OUT + строки + события полного сценария
// списания (форма 16 и MS010 имитируются). В НРД ничего не отправляется — только трансферные таблицы DEPO.
func depoSimulateOutgoing(ctx context.Context, rc *RuntimeConfig, svc *Service, srcGUID, ser, num string) (string, error) {
if svc == nil {
return "", fmt.Errorf("сервис сделок не запущен")
}
d, err := svc.Repo().GetByGUID(ctx, m2m.UUID(strings.ToLower(strings.TrimSpace(srcGUID))))
if err != nil || d == nil || d.Request == nil {
if d2, e2 := svc.Repo().GetByGUID(ctx, m2m.UUID(strings.ToUpper(strings.TrimSpace(srcGUID)))); e2 == nil && d2 != nil && d2.Request != nil {
d = d2
} else {
return "", fmt.Errorf("исходящая сделка %s не найдена", shortGUID(srcGUID))
}
}
db, err := depoEventsDB(rc)
if err != nil {
return "", err
}
defer db.Close()
serN := strings.ReplaceAll(strings.TrimSpace(ser), " ", "")
numN := strings.TrimSpace(num)
var name string
if err := db.QueryRowContext(ctx, fsql.Ev11, sql.Named("s", serN), sql.Named("n", numN)).Scan(&name); err != nil {
return "", fmt.Errorf("клиент с паспортом %s %s и открытым торговым счётом в DEPO не найден", ser, num)
}
req := d.Request
guid := strings.ToUpper(fmt.Sprintf("%08x-%04x-4000-8000-%012x", time.Now().Unix()&0xFFFFFFFF, time.Now().UnixNano()&0xFFFF, time.Now().UnixNano()&0xFFFFFFFFFFFF))
place := rc.Snapshot().NSD.SectionID
var lines []depoLine
for _, s := range req.Data.TransferredSecurities.Securities {
lines = append(lines, depoLine{Ref: string(s.ReferenceID), ISIN: quikSecISIN(s), Code: string(s.SecurityCode), Amount: quikSecQty(s.Quantity), Place: place})
}
inn := string(req.Data.ReceivingDepository.INN)
cp := handbookCodeByINN(inn)
if !depoUpsertOrder(rc, guid, "OUT", cp, name, strings.TrimSpace(ser+" "+num), ser, num, lines, "ТЕСТ по образцу "+shortGUID(string(d.GUID))+": исходящий, получатель "+cp+" "+handbookNameByCode(cp)) {
return "", fmt.Errorf("не удалось записать шапку в FTV_M2M")
}
now := time.Now()
// решение контрагента по строкам: как в оригинале; без решения — считаем подтверждённым
rejected := map[string]bool{}
if d.Decision != nil {
for _, sec := range d.Decision.Data.Securities {
if sec.TransferDecision.Rejection != nil {
rejected[string(sec.ReferenceID)] = true
}
}
}
for _, s := range req.Data.TransferredSecurities.Securities {
ref := string(s.ReferenceID)
depoEventAt(rc, now, guid, ref, "BJ_SENT", "", "")
if rejected[ref] {
var codes []string
for _, sec := range d.Decision.Data.Securities {
if string(sec.ReferenceID) == ref && sec.TransferDecision.Rejection != nil {
codes = sec.TransferDecision.Rejection.Codes
}
}
depoEventAt(rc, now.Add(time.Minute), guid, ref, "BJ_CP_REJECT", strings.Join(codes, ";"), rejectCodesLabel(codes))
continue
}
depoEventAt(rc, now.Add(time.Minute), guid, ref, "BJ_CP_CONFIRM", "", "")
// форма 16 по бумаге и её MS010 — имитация
depoEventAt(rc, now.Add(2*time.Minute), guid, ref, "BJ_ORDER_SENT", "", "")
depoEventAt(rc, now.Add(3*time.Minute), guid, ref, "BJ_ORDER_ACCEPTED", "", "")
depoEventAt(rc, now.Add(3*time.Minute), guid, ref, "BJ_EXECUTED", "", "")
}
return guid, nil
}