FTV_M2M_EVENTS.PARAMETERS: номер ответа НРД (MS010 BizMsgIdr) для BJ_ORDER_ACCEPTED/BJ_EXECUTED/BJ_ORDER_REJECTED, в т.ч. при выгрузке истории
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -441,13 +441,18 @@ func depoOnOrderLineSent(rc *RuntimeConfig, guid, ref, contrDID string) {
|
|||||||
// depoOnOrderLineResult — исход по строке: accepted | rejected | late | expired.
|
// depoOnOrderLineResult — исход по строке: accepted | rejected | late | expired.
|
||||||
// accepted → BJ_ORDER_ACCEPTED + BJ_EXECUTED; rejected → BJ_ORDER_REJECTED;
|
// accepted → BJ_ORDER_ACCEPTED + BJ_EXECUTED; rejected → BJ_ORDER_REJECTED;
|
||||||
// late → BJ_ORDER_LATE (5 мин без MS010); expired → BJ_CANCELLED (30 дней по бумаге).
|
// 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 {
|
switch kind {
|
||||||
case "accepted":
|
case "accepted":
|
||||||
depoEvent(rc, guid, ref, "BJ_ORDER_ACCEPTED", "", "")
|
depoEvent(rc, guid, ref, "BJ_ORDER_ACCEPTED", "", nsdNo)
|
||||||
depoEvent(rc, guid, ref, "BJ_EXECUTED", "", "")
|
depoEvent(rc, guid, ref, "BJ_EXECUTED", "", nsdNo)
|
||||||
case "rejected":
|
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":
|
case "late":
|
||||||
depoEvent(rc, guid, ref, "BJ_ORDER_LATE", "", "")
|
depoEvent(rc, guid, ref, "BJ_ORDER_LATE", "", "")
|
||||||
case "expired":
|
case "expired":
|
||||||
@@ -942,10 +947,10 @@ func depoReplayHistory(ctx context.Context, rc *RuntimeConfig, svc *Service, onl
|
|||||||
if done, rejected, text := orderRespVerdict(resps); done {
|
if done, rejected, text := orderRespVerdict(resps); done {
|
||||||
at := orderRespAt(resps)
|
at := orderRespAt(resps)
|
||||||
if rejected {
|
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 {
|
} else {
|
||||||
ev(at, it.GUID, ln.Ref, "BJ_ORDER_ACCEPTED", "", "")
|
ev(at, it.GUID, ln.Ref, "BJ_ORDER_ACCEPTED", "", orderRespNo(resps))
|
||||||
ev(at, it.GUID, ln.Ref, "BJ_EXECUTED", "", "")
|
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 {
|
if done, rejected, text := orderRespVerdict(resps); done {
|
||||||
at := orderRespAt(resps)
|
at := orderRespAt(resps)
|
||||||
if rejected {
|
if rejected {
|
||||||
ev(at, guid, ref, "BJ_ORDER_REJECTED", "", text)
|
ev(at, guid, ref, "BJ_ORDER_REJECTED", "", pickStr(orderRespNo(resps), text))
|
||||||
} else {
|
} else {
|
||||||
ev(at, guid, ref, "BJ_ORDER_ACCEPTED", "", "")
|
ev(at, guid, ref, "BJ_ORDER_ACCEPTED", "", orderRespNo(resps))
|
||||||
ev(at, guid, ref, "BJ_EXECUTED", "", "")
|
ev(at, guid, ref, "BJ_EXECUTED", "", orderRespNo(resps))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,6 +216,8 @@ type orderResponse struct {
|
|||||||
Done bool // true — это отчёт MS010 (операция проведена или завершена отказом)
|
Done bool // true — это отчёт MS010 (операция проведена или завершена отказом)
|
||||||
// Rejected — MS010 с отказом: операция завершилась, но не исполнена. Показывается красным.
|
// Rejected — MS010 с отказом: операция завершилась, но не исполнена. Показывается красным.
|
||||||
Rejected bool
|
Rejected bool
|
||||||
|
// No — номер документа НРД (BizMsgIdr), для отчёта MS010 — «номер ответа НРД» в PARAMETERS событий DEPO.
|
||||||
|
No string
|
||||||
}
|
}
|
||||||
|
|
||||||
// findOrderResponses ищет в INBOX ИШ ответы НРД по нашему поручению (по contr_d_id).
|
// findOrderResponses ищет в INBOX ИШ ответы НРД по нашему поручению (по contr_d_id).
|
||||||
@@ -242,6 +244,7 @@ func findOrderResponses(contrDID string) []orderResponse {
|
|||||||
Pkg: dir, Kind: kind, Done: done, Rejected: done && respTextRejected(body),
|
Pkg: dir, Kind: kind, Done: done, Rejected: done && respTextRejected(body),
|
||||||
Time: mt.In(time.FixedZone("МСК", 3*3600)).Format("02.01.2006 15:04:05"),
|
Time: mt.In(time.FixedZone("МСК", 3*3600)).Format("02.01.2006 15:04:05"),
|
||||||
Text: orderRespSummary(body),
|
Text: orderRespSummary(body),
|
||||||
|
No: strings.TrimSpace(xmlTag(body, "BizMsgIdr")),
|
||||||
}, mt})
|
}, mt})
|
||||||
}
|
}
|
||||||
sort.Slice(tmp, func(i, j int) bool { return tmp[i].mt.Before(tmp[j].mt) })
|
sort.Slice(tmp, func(i, j int) bool { return tmp[i].mt.Before(tmp[j].mt) })
|
||||||
|
|||||||
@@ -52,3 +52,14 @@ func TestNoCounterNotice(t *testing.T) {
|
|||||||
t.Fatalf("сквитовано, ждём: %q", s)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -319,10 +319,11 @@ func orderWatchCheck(ctx context.Context, rc *RuntimeConfig, guid, direction str
|
|||||||
w.Rejected = true
|
w.Rejected = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
no := orderRespNo(resps)
|
||||||
if rejected {
|
if rejected {
|
||||||
go depoOnOrderLineResult(rc, guid, ln.Ref, "rejected", text)
|
go depoOnOrderLineResult(rc, guid, ln.Ref, "rejected", text, no)
|
||||||
} else {
|
} else {
|
||||||
go depoOnOrderLineResult(rc, guid, ln.Ref, "accepted", "")
|
go depoOnOrderLineResult(rc, guid, ln.Ref, "accepted", "", no)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w = globalOrderWatch.Get(guid)
|
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 })
|
globalOrderWatch.update(guid, func(w *OrderWatch) { w.LateAt = now })
|
||||||
for _, ln := range lines {
|
for _, ln := range lines {
|
||||||
if !w.Lines[ln.ContrDID].lineDone() {
|
if !w.Lines[ln.ContrDID].lineDone() {
|
||||||
go depoOnOrderLineResult(rc, guid, ln.Ref, "late", "")
|
go depoOnOrderLineResult(rc, guid, ln.Ref, "late", "", "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if fresh {
|
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}
|
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" {
|
if direction == "out" {
|
||||||
for _, l := range globalQuikLinks.ForGUID(guid) {
|
for _, l := range globalQuikLinks.ForGUID(guid) {
|
||||||
if l.State == "registered" && (ln.ISIN == "" || strings.EqualFold(l.ISIN, ln.ISIN)) {
|
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
|
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 ""
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user