Files
Bridge-and-Join-s/docs/fancy-events-partial-m2m.md
zuevav 0c081a7857 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
2026-09-22 16:27:52 +03:00

8.7 KiB
Raw Permalink Blame History

Вопросы программисту Fancy: частичное исполнение пакета M2M

Контекст. По входящему переводу M2M на несколько бумаг НРД после нашего согласия формирует отдельное депо-поручение 16/1 на каждую бумагу (черновики MF010 приходят по одному на бумагу). Дальше каждое поручение исполняется независимо: по одному может прийти MS010 «исполнено», по другому — MS010 с отказом (не сквитовалось со встречным 16 контрагента, GS116 «не сквитовано», истёк срок 30 дней). Пример: пакет «10 Сбер + 10 Т-Технологии», Сбер зачислен, Т-Технологии — нет. То же возможно по исходящим (поручения 16 по каждой бумаге).

Сейчас bj пишет в FTV_M2M_EVENTS события на весь перевод (REFERENCE пустой): BJ_ORDER_ACCEPTED + BJ_EXECUTED либо BJ_ORDER_REJECTED. При частичном исполнении это неверно. bj готов писать события по строке пакета (REFERENCE = Security/ReferenceId из FTV_M2M_LINES).

Вопросы

  1. События по строке. Умеет ли bj2depo обрабатывать событие с заполненным REFERENCE (одна бумага пакета): создать проводку зачисления/списания только по ней и не трогать другие строки? Или джоба работает только с событием на весь GUID?

  2. Набор событий для частичного исхода. Какой вариант удобен джобе:

    • (а) по каждой строке своё событие: BJ_EXECUTED (REFERENCE=Сбер) и BJ_ORDER_REJECTED (REFERENCE=Т-Технологии, PARAMETERS — текст отказа НРД); события на весь GUID при этом не пишутся;
    • (б) одно событие на GUID BJ_EXECUTED_PARTIAL с перечнем в PARAMETERS (executed: ISIN…; rejected: ISIN… — причина), проводки делает оператор Fancy вручную;
    • (в) оба: строчные события для проводок и сводное на GUID для статуса документа.
  3. Порядок во времени. MS010 по разным бумагам приходят в разное время (минуты — дни). Можно ли писать событие по строке сразу при получении её MS010, не дожидаясь остальных (документ в DEPO будет какое-то время «частично исполнен»)? Или ждать, пока ответят по всем, и писать пакетом?

  4. Состояние документа DEPO. Какое STATE/COMMENT bj2depo поставит документу, у которого часть строк исполнена, часть отказана? Есть ли в DEPO статус «исполнено частично», или документ разделяется на два?

  5. Отказ после исполнения. Если по бумаге сначала пришло REORD/принятие, а затем отказ (MS010 с отказом) — нужно ли отдельное событие отмены ранее созданной проводки, или BJ_ORDER_REJECTED по строке этого достаточно?

  6. Срок 30 дней. Поручение без MS010 через 30 дней считается отменённым. Сейчас bj пишет BJ_CANCELLED на весь GUID. По строке — тем же событием с REFERENCE?

  7. Поручения без строки. BJ_ORDER_SENT сейчас несёт номера всех поданных поручений (contr_d_id) в PARAMETERS. Нужно ли джобе соответствие contr_d_id ↔ REFERENCE (в каком поле)?

  8. Обратная совместимость. Пока джоба не умеет строки — можем ли мы продолжать писать события на GUID при полном исполнении/полном отказе и переходить на строчные только при частичном исходе? Или переключаться целиком?

Что сделает bj после ответа

  • хранить по каждому поручению 16/16-1 связку contr_d_id ↔ ISIN ↔ REFERENCE;
  • вердикт по каждому поручению; статус перевода «исполнен» только когда исполнены все, «отказ» — когда отказ по всем, иначе «исполнен частично» с ожиданием остальных;
  • события в FTV_M2M_EVENTS в согласованном формате (п. 2);
  • в карточке перевода — статус по каждой бумаге, оповещение оператору о частичном исполнении.

Ответы Fancy (В. Кокин, письмо 21.09.2026) и что реализовано в bj

# Вопрос Ответ В bj
1 Событие с REFERENCE по одной бумаге — провести только её Да события исходов пишутся по строкам с REFERENCE
2 Формат при частичном исходе (а) отдельные события по строкам — они приходят в разное время BJ_EXECUTED/BJ_ORDER_REJECTED по каждой строке
3 Писать по строке сразу при её MS010 или ждать все Сразу orderWatchCheck пишет исход строки в момент её MS010
4 Состояние документа DEPO при частичном исполнении есть статус «частично», документ не делится карточка bj: «исполнено частично: N из M» (StatusRu/Kind=warn)
5 Отказ после принятия (REORD) — событие отмены проводки? Такого не может быть; экстремальный казус — руками отдельного события отмены нет
6 30 дней по одной бумаге → BJ_CANCELLED с REFERENCE Да истечение по строке → BJ_CANCELLED с REFERENCE, QUIK-блок снимается по ISIN
7 Связка contr_d_id ↔ REFERENCE джобе Не нужна — по REFERENCE найдёт всё contr_d_id кладём в COMMENT для разбора
8 Совместимость: строчные только при частичном? Сразу везде, но одновременно на bj и bj2depo все BJ_ORDER_*/BJ_EXECUTED/BJ_CANCELLED — строчные; события на весь GUID больше не пишем

Реализация в bj (orderwatch.go, depoevents.go, incoming*.go, outgoing_order.go):

  • одно депо-поручение (MF010) = одна бумага; входящий 16/1 теперь хранит все contr_d_id (OrderLines: contr_d_id ↔ ISIN ↔ REFERENCE) — раньше только первый;
  • исходящий 16: REFERENCE берётся из бумаг M2MTR по ISIN (outgoingLineRefs, кэш по GUID);
  • OrderWatch.Lines — состояние по строкам; объект закрыт, когда MS010 по всем строкам;
  • BJ_ORDER_SENT — по строке (COMMENT = contr_d_id); BJ_ORDER_LATE — по каждой незакрытой строке при просрочке 5 мин.

Развёртывание — только одновременно с bj2depo (п. 8): до подтверждения Вадима, что джоба читает строчные события, bj на стенд/бой не выкатывается.

Предложение Вадима: прогнать тесты с реальным контрагентом на функционале вендора (есть компания с потребностью тестировать).