From a62db0aa0e385c2fb680ec51d6aa0819ea2e9251 Mon Sep 17 00:00:00 2001 From: zuevav Date: Tue, 29 Sep 2026 15:56:19 +0300 Subject: [PATCH] =?UTF-8?q?FTV=5FM2M=5FEVENTS.PARAMETERS:=20=D0=BD=D0=BE?= =?UTF-8?q?=D0=BC=D0=B5=D1=80=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D0=B0=20?= =?UTF-8?q?=D0=9D=D0=A0=D0=94=20(MS010=20BizMsgIdr)=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20BJ=5FORDER=5FACCEPTED/BJ=5FEXECUTED/BJ=5FORDER=5FREJECTED,?= =?UTF-8?q?=20=D0=B2=20=D1=82.=D1=87.=20=D0=BF=D1=80=D0=B8=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B5=20=D0=B8=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi --- internal/lkgateway/depoevents.go | 25 +++++++++++++++---------- internal/lkgateway/incoming_order.go | 3 +++ internal/lkgateway/nocounter_test.go | 11 +++++++++++ internal/lkgateway/orderwatch.go | 19 +++++++++++++++---- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/internal/lkgateway/depoevents.go b/internal/lkgateway/depoevents.go index eacb40a..4c5f780 100644 --- a/internal/lkgateway/depoevents.go +++ b/internal/lkgateway/depoevents.go @@ -441,13 +441,18 @@ func depoOnOrderLineSent(rc *RuntimeConfig, guid, ref, contrDID string) { // depoOnOrderLineResult — исход по строке: accepted | rejected | late | expired. // accepted → BJ_ORDER_ACCEPTED + BJ_EXECUTED; rejected → BJ_ORDER_REJECTED; // late → BJ_ORDER_LATE (5 мин без MS010); expired → BJ_CANCELLED (30 дней по бумаге). -func depoOnOrderLineResult(rc *RuntimeConfig, guid, ref, kind, text string) { +// nsdNo — номер ответа НРД (отчёт MS010, BizMsgIdr): PARAMETERS событий по исполнению (29.09.2026). +func depoOnOrderLineResult(rc *RuntimeConfig, guid, ref, kind, text, nsdNo string) { switch kind { case "accepted": - depoEvent(rc, guid, ref, "BJ_ORDER_ACCEPTED", "", "") - depoEvent(rc, guid, ref, "BJ_EXECUTED", "", "") + depoEvent(rc, guid, ref, "BJ_ORDER_ACCEPTED", "", nsdNo) + depoEvent(rc, guid, ref, "BJ_EXECUTED", "", nsdNo) case "rejected": - depoEvent(rc, guid, ref, "BJ_ORDER_REJECTED", "", text) + params := nsdNo + if params == "" { + params = text + } + depoEvent(rc, guid, ref, "BJ_ORDER_REJECTED", "", params) case "late": depoEvent(rc, guid, ref, "BJ_ORDER_LATE", "", "") case "expired": @@ -942,10 +947,10 @@ func depoReplayHistory(ctx context.Context, rc *RuntimeConfig, svc *Service, onl if done, rejected, text := orderRespVerdict(resps); done { at := orderRespAt(resps) if rejected { - ev(at, it.GUID, ln.Ref, "BJ_ORDER_REJECTED", "", text) + ev(at, it.GUID, ln.Ref, "BJ_ORDER_REJECTED", "", pickStr(orderRespNo(resps), text)) } else { - ev(at, it.GUID, ln.Ref, "BJ_ORDER_ACCEPTED", "", "") - ev(at, it.GUID, ln.Ref, "BJ_EXECUTED", "", "") + ev(at, it.GUID, ln.Ref, "BJ_ORDER_ACCEPTED", "", orderRespNo(resps)) + ev(at, it.GUID, ln.Ref, "BJ_EXECUTED", "", orderRespNo(resps)) } } } @@ -1020,10 +1025,10 @@ func depoReplayHistory(ctx context.Context, rc *RuntimeConfig, svc *Service, onl if done, rejected, text := orderRespVerdict(resps); done { at := orderRespAt(resps) if rejected { - ev(at, guid, ref, "BJ_ORDER_REJECTED", "", text) + ev(at, guid, ref, "BJ_ORDER_REJECTED", "", pickStr(orderRespNo(resps), text)) } else { - ev(at, guid, ref, "BJ_ORDER_ACCEPTED", "", "") - ev(at, guid, ref, "BJ_EXECUTED", "", "") + ev(at, guid, ref, "BJ_ORDER_ACCEPTED", "", orderRespNo(resps)) + ev(at, guid, ref, "BJ_EXECUTED", "", orderRespNo(resps)) } } } diff --git a/internal/lkgateway/incoming_order.go b/internal/lkgateway/incoming_order.go index cec49fb..da1e432 100644 --- a/internal/lkgateway/incoming_order.go +++ b/internal/lkgateway/incoming_order.go @@ -216,6 +216,8 @@ type orderResponse struct { Done bool // true — это отчёт MS010 (операция проведена или завершена отказом) // Rejected — MS010 с отказом: операция завершилась, но не исполнена. Показывается красным. Rejected bool + // No — номер документа НРД (BizMsgIdr), для отчёта MS010 — «номер ответа НРД» в PARAMETERS событий DEPO. + No string } // findOrderResponses ищет в INBOX ИШ ответы НРД по нашему поручению (по contr_d_id). @@ -242,6 +244,7 @@ func findOrderResponses(contrDID string) []orderResponse { Pkg: dir, Kind: kind, Done: done, Rejected: done && respTextRejected(body), Time: mt.In(time.FixedZone("МСК", 3*3600)).Format("02.01.2006 15:04:05"), Text: orderRespSummary(body), + No: strings.TrimSpace(xmlTag(body, "BizMsgIdr")), }, mt}) } sort.Slice(tmp, func(i, j int) bool { return tmp[i].mt.Before(tmp[j].mt) }) diff --git a/internal/lkgateway/nocounter_test.go b/internal/lkgateway/nocounter_test.go index fe1d1b8..07765b9 100644 --- a/internal/lkgateway/nocounter_test.go +++ b/internal/lkgateway/nocounter_test.go @@ -52,3 +52,14 @@ func TestNoCounterNotice(t *testing.T) { t.Fatalf("сквитовано, ждём: %q", s) } } + +// Номер ответа НРД для PARAMETERS — из отчёта MS010 (BizMsgIdr), не из промежуточных документов. +func TestOrderRespNo(t *testing.T) { + resps := []orderResponse{{Kind: "GS036", No: "50878765"}, {Kind: "MS010", Done: true, No: "50878767"}} + if got := orderRespNo(resps); got != "50878767" { + t.Fatalf("номер ответа: %q", got) + } + if got := orderRespNo(resps[:1]); got != "" { + t.Fatalf("без MS010 — пусто: %q", got) + } +} diff --git a/internal/lkgateway/orderwatch.go b/internal/lkgateway/orderwatch.go index da986ac..fd00a72 100644 --- a/internal/lkgateway/orderwatch.go +++ b/internal/lkgateway/orderwatch.go @@ -319,10 +319,11 @@ func orderWatchCheck(ctx context.Context, rc *RuntimeConfig, guid, direction str w.Rejected = true } }) + no := orderRespNo(resps) if rejected { - go depoOnOrderLineResult(rc, guid, ln.Ref, "rejected", text) + go depoOnOrderLineResult(rc, guid, ln.Ref, "rejected", text, no) } else { - go depoOnOrderLineResult(rc, guid, ln.Ref, "accepted", "") + go depoOnOrderLineResult(rc, guid, ln.Ref, "accepted", "", no) } } w = globalOrderWatch.Get(guid) @@ -351,7 +352,7 @@ func orderWatchCheck(ctx context.Context, rc *RuntimeConfig, guid, direction str globalOrderWatch.update(guid, func(w *OrderWatch) { w.LateAt = now }) for _, ln := range lines { if !w.Lines[ln.ContrDID].lineDone() { - go depoOnOrderLineResult(rc, guid, ln.Ref, "late", "") + go depoOnOrderLineResult(rc, guid, ln.Ref, "late", "", "") } } if fresh { @@ -381,7 +382,7 @@ func orderWatchCheck(ctx context.Context, rc *RuntimeConfig, guid, direction str } w.Lines[ln.ContrDID] = &OrderLineWatch{Ref: ln.Ref, ISIN: ln.ISIN, ExpiredAt: now} }) - go depoOnOrderLineResult(rc, guid, ln.Ref, "expired", "") + go depoOnOrderLineResult(rc, guid, ln.Ref, "expired", "", "") if direction == "out" { for _, l := range globalQuikLinks.ForGUID(guid) { if l.State == "registered" && (ln.ISIN == "" || strings.EqualFold(l.ISIN, ln.ISIN)) { @@ -571,3 +572,13 @@ func findMatchedNotice(contrDID string) (time.Time, bool) { } return time.Time{}, false } + +// orderRespNo — номер ответа НРД (BizMsgIdr) из отчёта MS010 по строке. +func orderRespNo(resps []orderResponse) string { + for _, r := range resps { + if r.Done && r.No != "" { + return r.No + } + } + return "" +}