QUIK МНП: новый получатель M2M — повтор регистрации вывода (3×30 с), пока модуль не подхватит справочник; имя получателя из справочника НРД; опрос ЛК — до 4 мин на проход
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -279,7 +279,8 @@ func (s *Server) pollLKClaims(ctx context.Context) {
|
|||||||
if !moduleAllowed(s.rc, "esia-finance") {
|
if !moduleAllowed(s.rc, "esia-finance") {
|
||||||
continue // ЕСИА Финанс — отдельный модуль лицензии
|
continue // ЕСИА Финанс — отдельный модуль лицензии
|
||||||
}
|
}
|
||||||
cctx, cancel := context.WithTimeout(ctx, 50*time.Second)
|
// до 4 мин: блокировка в QUIK МНП может ждать, пока модуль подхватит нового получателя
|
||||||
|
cctx, cancel := context.WithTimeout(ctx, 4*time.Minute)
|
||||||
res, err := PullLKClaims(cctx, s.rc, s.svc)
|
res, err := PullLKClaims(cctx, s.rc, s.svc)
|
||||||
cancel()
|
cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -491,6 +491,12 @@ func quikStep(action string, aid int64, r QuikActionResult, ok bool) QuikStep {
|
|||||||
return QuikStep{At: time.Now(), Action: action, ActionID: aid, Status: r.QueryStatus, Reply: r.ReplyText, OK: ok}
|
return QuikStep{At: time.Now(), Action: action, ActionID: aid, Status: r.QueryStatus, Reply: r.ReplyText, OK: ok}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Повтор регистрации, пока модуль МНП не подхватил нового получателя из M2MDepoRecipients.
|
||||||
|
var (
|
||||||
|
quikRecipientRetries = 3
|
||||||
|
quikRecipientWait = 30 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
// QuikOutRegister — исходящий перевод: зарегистрировать «Вывод ЦБ (M2M)» (QUIK блокирует бумаги).
|
// QuikOutRegister — исходящий перевод: зарегистрировать «Вывод ЦБ (M2M)» (QUIK блокирует бумаги).
|
||||||
func QuikOutRegister(ctx context.Context, rc *RuntimeConfig, guid, clientID, contract, isin string, qty float64, recipientINN, recipientName string, passExpenses bool) (*QuikLink, error) {
|
func QuikOutRegister(ctx context.Context, rc *RuntimeConfig, guid, clientID, contract, isin string, qty float64, recipientINN, recipientName string, passExpenses bool) (*QuikLink, error) {
|
||||||
s := quikSettingsFor(rc, guid)
|
s := quikSettingsFor(rc, guid)
|
||||||
@@ -500,14 +506,33 @@ func QuikOutRegister(ctx context.Context, rc *RuntimeConfig, guid, clientID, con
|
|||||||
if s.Emulate {
|
if s.Emulate {
|
||||||
return quikEmulated(rc, guid, isin, "register", "registered", "вывод зарегистрирован, бумаги заблокированы"), nil
|
return quikEmulated(rc, guid, isin, "register", "registered", "вывод зарегистрирован, бумаги заблокированы"), nil
|
||||||
}
|
}
|
||||||
|
if strings.TrimSpace(recipientName) == "" {
|
||||||
|
recipientName = m2mPartyName(recipientINN) // наименование из справочника НРД
|
||||||
|
}
|
||||||
if err := quikEnsureRecipient(ctx, s, recipientINN, recipientName); err != nil {
|
if err := quikEnsureRecipient(ctx, s, recipientINN, recipientName); err != nil {
|
||||||
return quikFail(rc, guid, isin, "register", err), err
|
return quikFail(rc, guid, isin, "register", err), err
|
||||||
}
|
}
|
||||||
aid, err := quikExecNewInstr(ctx, s, true, shortGUID(guid), clientID, isin, qty, recipientINN, passExpenses, "M2M bj: перевод "+shortGUID(guid))
|
var aid int64
|
||||||
if err != nil {
|
var r QuikActionResult
|
||||||
return quikFail(rc, guid, isin, "register", err), err
|
// Нового получателя (только что добавлен в M2MDepoRecipients) модуль МНП подхватывает не сразу —
|
||||||
|
// «Неизвестный депозитарий получателя»: ждём и повторяем, а не отклоняем заявку клиента.
|
||||||
|
for attempt := 1; ; attempt++ {
|
||||||
|
var err error
|
||||||
|
aid, err = quikExecNewInstr(ctx, s, true, shortGUID(guid), clientID, isin, qty, recipientINN, passExpenses, "M2M bj: перевод "+shortGUID(guid))
|
||||||
|
if err != nil {
|
||||||
|
return quikFail(rc, guid, isin, "register", err), err
|
||||||
|
}
|
||||||
|
r = quikWaitAction(ctx, s, aid, quikActionWait)
|
||||||
|
if attempt > quikRecipientRetries || !strings.Contains(strings.ToLower(r.ReplyText), "неизвестный депозитарий получателя") {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Printf("quik: %s: МНП ещё не знает получателя ИНН %s — повтор через %s (попытка %d из %d)", shortGUID(guid), recipientINN, quikRecipientWait, attempt, quikRecipientRetries)
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return quikFail(rc, guid, isin, "register", ctx.Err()), ctx.Err()
|
||||||
|
case <-time.After(quikRecipientWait):
|
||||||
|
}
|
||||||
}
|
}
|
||||||
r := quikWaitAction(ctx, s, aid, quikActionWait)
|
|
||||||
if r.QueryStatus != 2 || r.InstrNo == "" || r.InstrNo == "0" {
|
if r.QueryStatus != 2 || r.InstrNo == "" || r.InstrNo == "0" {
|
||||||
err := fmt.Errorf("МНП отверг регистрацию: %s", r.ReplyText)
|
err := fmt.Errorf("МНП отверг регистрацию: %s", r.ReplyText)
|
||||||
globalQuikLinks.update(guid, isin, func(l *QuikLink) { l.Steps = append(l.Steps, quikStep("register", aid, r, false)) })
|
globalQuikLinks.update(guid, isin, func(l *QuikLink) { l.Steps = append(l.Steps, quikStep("register", aid, r, false)) })
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
//go:build live
|
||||||
|
|
||||||
|
package lkgateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Только чтение: справочник депозитариев-получателей МНП.
|
||||||
|
func TestQuikRecipientsLive(t *testing.T) {
|
||||||
|
rc, err := NewRuntimeConfig("/var/lib/bj/.bj/setup.json")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
conn, err := quikOpen(rc.Snapshot().Quik)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
rows, err := conn.QueryContext(context.Background(), "SELECT Id, INN, Name FROM M2MDepoRecipients ORDER BY Id")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
var id int
|
||||||
|
var inn, name string
|
||||||
|
_ = rows.Scan(&id, &inn, &name)
|
||||||
|
fmt.Println(id, inn, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user