Автоматический режим M2M и имитация QUIK МНП

Автоматический режим (Настройка → НРД, выключен по умолчанию): входящие переводы — решение по свежей
сверке с DEPO без оператора (пакет только целиком; бумага для квал. инвесторов при неполной или
непрочитанной квалификации — отказ M2M08), поручение 16/1 — как только пришёл черновик MF010,
поручение 16 по исходящим — по черновику. Нет сверки или ИШ — повтор каждые 3 минуты и оповещение,
без сверки ничего не принимается. Обрабатывается только появившееся не раньше суток до включения
(старые черновики в INBOX не подаются). Решение не отправляется повторно по уже отвеченному переводу.

Имитация QUIK МНП (Настройка → QUIK МНП → цикл): регистрация, подпись, снятие и зачисление проходят
как выполненные с пометкой «имитация», в МНП ничего не пишется; события в DEPO — как обычно.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
zuevav
2026-09-16 14:59:23 +03:00
parent 4b62d00ac2
commit d47229c9a5
12 changed files with 486 additions and 30 deletions
+25 -16
View File
@@ -64,10 +64,27 @@ func submitDepoOrder(w http.ResponseWriter, r *http.Request, deps incomingDeps,
redirect := func(msg string) {
http.Redirect(w, r, "/admin/incoming/"+id+"?flash="+url.QueryEscape(msg), http.StatusSeeOther)
}
if deps.igwClient == nil || deps.igwChan == "" {
redirect("ИШ не настроен — нельзя отправить поручение")
ctx, cancel := context.WithTimeout(r.Context(), 40*time.Second)
defer cancel()
sent, firstErr, err := submitIncomingOrderFor(ctx, deps, it)
if err != nil {
redirect(err.Error())
return
}
note := fmt.Sprintf("Поручение 16/1 (тип ЭД ORDXM) отправлено в НРД: пакет(ы) ИШ %s. "+
"Ждём отчёт по поручению депо (XMLRP) = «MS010». Ответ появится ниже на странице.", strings.Join(sent, ", "))
if firstErr != "" {
note += " ⚠ часть файлов не ушла: " + firstErr
}
redirect(note)
}
// submitIncomingOrderFor — подать поручение 16/1 (ORDXM) по черновику MF010 из INBOX ИШ (кнопка в
// карточке и автоматический режим). firstErr — если часть файлов не ушла.
func submitIncomingOrderFor(ctx context.Context, deps incomingDeps, it *IncomingTransfer) (sent []string, firstErr string, err error) {
if deps.igwClient == nil || deps.igwChan == "" {
return nil, "", fmt.Errorf("ИШ не настроен — нельзя отправить поручение")
}
// только .xml (без .SGN) — подпись НРД нам не нужна, ИШ подпишет своей ГОСТ.
var xmls []string
for _, p := range findMF010Files(it.GUID) {
@@ -76,13 +93,11 @@ func submitDepoOrder(w http.ResponseWriter, r *http.Request, deps incomingDeps,
}
}
if len(xmls) == 0 {
redirect("Черновик поручения 16/1 (MF010) по этому переводу в INBOX ИШ не найден")
return
return nil, "", fmt.Errorf("Черновик поручения 16/1 (MF010) по этому переводу в INBOX ИШ не найден")
}
ctx, cancel := context.WithTimeout(r.Context(), 40*time.Second)
defer cancel()
var sent, sentXML []string
var firstErr, contrDID string
id := it.ID
var sentXML []string
var contrDID string
for _, p := range xmls {
raw, e := os.ReadFile(p) // windows-1251, шлём как есть
if e != nil {
@@ -116,15 +131,9 @@ func submitDepoOrder(w http.ResponseWriter, r *http.Request, deps incomingDeps,
if firstErr != "" {
msg = firstErr
}
redirect("Поручение 16/1 (ORDXM): отправка в НРД не удалась: " + msg)
return
return nil, "", fmt.Errorf("Поручение 16/1 (ORDXM): отправка в НРД не удалась: %s", msg)
}
note := fmt.Sprintf("Поручение 16/1 (тип ЭД ORDXM) отправлено в НРД: пакет(ы) ИШ %s. "+
"Ждём отчёт по поручению депо (XMLRP) = «MS010». Ответ появится ниже на странице.", strings.Join(sent, ", "))
if firstErr != "" {
note += " ⚠ часть файлов не ушла: " + firstErr
}
redirect(note)
return sent, firstErr, nil
}
// writeOrderResponseZip отдаёт на скачивание ZIP с сырыми файлами ответа НРД