DEPO: строчные события по депо-поручениям (частичное исполнение пакета)

По ответам программиста Fancy (В. Кокин, 21.09.2026) на 8 вопросов из
docs/fancy-events-partial-m2m.md. Одно депо-поручение (MF010) = одна бумага
пакета, поэтому подача и исход теперь пишутся в DEPO ПО СТРОКАМ с REFERENCE и
сразу по MS010 этой строки, не дожидаясь остальных: пакет может исполниться
частично (Сбер — да, Т-Технологии — отказ). События на весь GUID (пустой
REFERENCE) больше не пишем — переход одновременно с bj2depo.

- BJ_ORDER_SENT / BJ_ORDER_ACCEPTED / BJ_EXECUTED / BJ_ORDER_REJECTED /
  BJ_ORDER_LATE / BJ_CANCELLED — по строке (depoOnOrderLineSent/Result);
  contr_d_id кладём в COMMENT (джобе связка не нужна — по REFERENCE найдёт).
- OrderWatch.Lines — состояние по строкам (contr_d_id → REFERENCE/ISIN/MS010/
  отказ/истечение); объект закрыт, когда MS010 по всем строкам; 30 дней —
  BJ_CANCELLED по каждой незакрытой строке, QUIK-блок снимается по её ISIN.
- Входящий 16/1 хранит ВСЕ contr_d_id (OrderLines) — раньше только первый
  (дефект «входящие отслеживают только первый contr_d_id»). Исходящий 16:
  REFERENCE по ISIN из бумаг M2MTR (outgoingLineRefs, кэш по GUID; svc в deps).
- Карточка: «исполнено частично: N из M» (StatusRu), бейдж warn — как статус
  «частично» в DEPO. Backfill и эмуляция — тоже по строкам.
- Попутно: EXEC процедуры обработчика DEPO — через execProc с проверкой имени
  (sqlident.go), чтобы значение из настроек не стало произвольным T-SQL.

Тесты: TestOrderWatchLinesPartial, TestIncomingOrderLines,
TestOutgoingLineRefsNoRepo; весь пакет зелёный.

РАЗВЁРТЫВАНИЕ — только одновременно с bj2depo (п. 8 ответов Fancy).

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 16:27:52 +03:00
parent e16d4454ce
commit 0c081a7857
9 changed files with 488 additions and 87 deletions
+21 -8
View File
@@ -63,11 +63,15 @@ type IncomingTransfer struct {
Auto bool `json:"auto,omitempty"` // отвечено автоматически (дубль)
Fingerprint string `json:"fingerprint,omitempty"` // отпечаток для детекта дублей
// Подача депозитарного поручения 16/1 (ORDXM) в НРД.
OrderSubmitted bool `json:"order_submitted,omitempty"`
OrderContrDID string `json:"order_contr_did,omitempty"` // contr_d_id поручения (связь с ответами НРД)
OrderPkgs string `json:"order_pkgs,omitempty"` // id пакетов ИШ
OrderAt time.Time `json:"order_at,omitempty"`
OrderXML string `json:"order_xml,omitempty"` // что мы реально отправили (поручение 16/1)
OrderSubmitted bool `json:"order_submitted,omitempty"`
OrderContrDID string `json:"order_contr_did,omitempty"` // contr_d_id ПЕРВОГО поручения (совместимость карточек/выгрузок)
// OrderLines — все поданные депо-поручения 16/1: одно на бумагу (contr_d_id ↔ ISIN ↔
// REFERENCE строки пакета). Нужны, чтобы исход каждой бумаги (MS010) писать в DEPO
// по своей строке — пакет может исполниться частично.
OrderLines []IncomingOrderLine `json:"order_lines,omitempty"`
OrderPkgs string `json:"order_pkgs,omitempty"` // id пакетов ИШ
OrderAt time.Time `json:"order_at,omitempty"`
OrderXML string `json:"order_xml,omitempty"` // что мы реально отправили (поручение 16/1)
// Сверка с DEPO (эмуляция ответа, ничего не отправляется) — для бейджа в списке.
DepoRecommend string `json:"depo_recommend,omitempty"` // confirm | reject | mixed
DepoSummary string `json:"depo_summary,omitempty"` // «принять» / «отказ M2M04» / …
@@ -296,14 +300,23 @@ func (s *IncomingStore) MarkAuto(id, note string) {
s.save()
}
// SetOrderSubmitted помечает, что подано поручение депо 16/1 (ORDXM) в НРД, и
// сохраняет отправленный XML (что именно мы отправили).
func (s *IncomingStore) SetOrderSubmitted(id, contrDID, pkgs, orderXML string) {
// IncomingOrderLine — одно депо-поручение 16/1 по одной бумаге пакета.
type IncomingOrderLine struct {
ContrDID string `json:"contr_did"`
ISIN string `json:"isin,omitempty"`
Ref string `json:"ref,omitempty"` // REFERENCE бумаги в пакете (Security/ReferenceId)
}
// SetOrderSubmitted помечает, что поданы поручения депо 16/1 (ORDXM) в НРД, и
// сохраняет отправленный XML (что именно мы отправили). lines — по одному на бумагу;
// OrderContrDID остаётся первым из них для совместимости.
func (s *IncomingStore) SetOrderSubmitted(id, contrDID, pkgs, orderXML string, lines []IncomingOrderLine) {
s.mu.Lock()
defer s.mu.Unlock()
if it, ok := s.items[id]; ok {
it.OrderSubmitted = true
it.OrderContrDID = contrDID
it.OrderLines = append([]IncomingOrderLine(nil), lines...)
it.OrderPkgs = pkgs
it.OrderXML = orderXML
it.OrderAt = time.Now().UTC()