DEPO: события по ответу программиста bj2depo — без COMMENT/STATE, параметры в PARAMETERS, время события из bj
COMMENT и STATE в трансферных таблицах заполняет только bj2depo: bj их больше не пишет (шапка, события, BJ_PING). Параметры событий — в PARAMETERS (CONTR_D_ID поручения НРД, номер поручения МНП, текст причины отказа), EVENT_DATE — фактическое время события в bj. Событий от bj2depo нет: bj не читает и не помечает DEPO_*, номер документа берёт из FTV_M2M.DOC. Страница «bj ↔ bj2depo» обновлена: поля, правила, FTV_M2M_PROCESS_WIRING по BJ_ORDER_ACCEPTED/BJ_EXECUTED, примеры SQL, закрытые и оставшиеся вопросы. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,11 +2,12 @@ package lkgateway
|
||||
|
||||
// Обмен с DEPO (Fancy) через трансферные таблицы в нашей копии базы
|
||||
// (BJ_DEPO_DATA): FTV_M2M / FTV_M2M_LINES / FTV_M2M_EVENTS / FTV_M2M_HANDBOOK.
|
||||
// Согласовано с программистом Fancy 09–10.09.2026 (страница /admin/help/fancy-events):
|
||||
// - bj пишет поручения и события BJ_*; джоба bj2depo создаёт сущности DEPO и
|
||||
// пишет в ответ только DEPO_ORDER_CREATED / DEPO_ERROR;
|
||||
// - справочник участников — TRUNCATE + полная перезапись при каждом получении;
|
||||
// - STATE: TODO при записи → SUCCESS/ERROR после обработки получателем.
|
||||
// Согласовано с программистом Fancy (страница /admin/help/fancy-events), уточнено 17.09.2026:
|
||||
// - bj — мастер: пишет поручения и события BJ_*; джоба bj2depo создаёт сущности DEPO, событий от
|
||||
// себя не пишет — результат bj читает в FTV_M2M.DOC и в STATE/COMMENT своих событий;
|
||||
// - COMMENT и STATE заполняет только bj2depo (STATE по умолчанию TODO); параметры события bj пишет
|
||||
// в PARAMETERS; EVENT_DATE — фактическое время события в bj;
|
||||
// - справочник участников — TRUNCATE + полная перезапись при каждом получении.
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -124,13 +125,15 @@ func depoTableExists(ctx context.Context, db *sql.DB, name string) bool {
|
||||
|
||||
var depoTablesWarned time.Time
|
||||
|
||||
// depoEvent — одна строка FTV_M2M_EVENTS (идемпотентно по GUID+REFERENCE+EVENT_TYPE), дата = сейчас.
|
||||
func depoEvent(rc *RuntimeConfig, guid, ref, typ, codes, comment string) {
|
||||
depoEventAt(rc, time.Time{}, guid, ref, typ, codes, comment)
|
||||
// depoEvent — одна строка FTV_M2M_EVENTS (идемпотентно по GUID+REFERENCE+EVENT_TYPE), время события — сейчас.
|
||||
// params — параметры события для bj2depo (PARAMETERS): номер поручения НРД, номер поручения МНП, текст причины отказа.
|
||||
func depoEvent(rc *RuntimeConfig, guid, ref, typ, codes, params string) {
|
||||
depoEventAt(rc, time.Now(), guid, ref, typ, codes, params)
|
||||
}
|
||||
|
||||
// depoEventAt — то же с явной датой события (для выгрузки истории).
|
||||
func depoEventAt(rc *RuntimeConfig, at time.Time, guid, ref, typ, codes, comment string) {
|
||||
// depoEventAt — то же с явным временем события (выгрузка истории). COMMENT и STATE не пишем:
|
||||
// их заполняет bj2depo (STATE по умолчанию TODO).
|
||||
func depoEventAt(rc *RuntimeConfig, at time.Time, guid, ref, typ, codes, params string) {
|
||||
guid = strings.ToUpper(strings.TrimSpace(guid))
|
||||
if !uuidRe.MatchString(guid) {
|
||||
return // тестовые/служебные идентификаторы в DEPO не отдаём
|
||||
@@ -149,8 +152,11 @@ func depoEventAt(rc *RuntimeConfig, at time.Time, guid, ref, typ, codes, comment
|
||||
}
|
||||
return
|
||||
}
|
||||
if len([]rune(comment)) > 4000 {
|
||||
comment = string([]rune(comment)[:4000])
|
||||
if at.IsZero() {
|
||||
at = time.Now()
|
||||
}
|
||||
if len([]rune(params)) > 4000 {
|
||||
params = string([]rune(params)[:4000])
|
||||
}
|
||||
var n int
|
||||
_ = db.QueryRowContext(ctx, "SELECT COUNT(*) FROM dbo.FTV_M2M_EVENTS WHERE GUID=@g AND ISNULL(REFERENCE,'')=@r AND EVENT_TYPE=@t",
|
||||
@@ -158,17 +164,18 @@ func depoEventAt(rc *RuntimeConfig, at time.Time, guid, ref, typ, codes, comment
|
||||
if n > 0 {
|
||||
return
|
||||
}
|
||||
// Параметр даты — типизированный NULL: при нетипизированном nil драйвер шлёт nvarchar(1),
|
||||
// ISNULL берёт тип первого аргумента и GETDATE() обрезается до одного символа.
|
||||
evDate := sql.NullTime{Time: at, Valid: !at.IsZero()}
|
||||
_, err = db.ExecContext(ctx, `INSERT INTO dbo.FTV_M2M_EVENTS (GUID, REFERENCE, STATE, EVENT_TYPE, EVENT_DATE, M2M_REJECT_CODE, COMMENT)
|
||||
VALUES (@g, @r, 'TODO', @t, COALESCE(@at, GETDATE()), @c, @cm)`,
|
||||
sql.Named("g", guid), sql.Named("r", nullStr(ref)), sql.Named("t", typ), sql.Named("at", evDate), sql.Named("c", nullStr(codes)), sql.Named("cm", nullStr(comment)))
|
||||
q := `INSERT INTO dbo.FTV_M2M_EVENTS (GUID, REFERENCE, EVENT_TYPE, EVENT_DATE, M2M_REJECT_CODE) VALUES (@g, @r, @t, @at, @c)`
|
||||
if depoHasColumn(ctx, db, "FTV_M2M_EVENTS", "PARAMETERS") {
|
||||
q = `INSERT INTO dbo.FTV_M2M_EVENTS (GUID, REFERENCE, EVENT_TYPE, EVENT_DATE, M2M_REJECT_CODE, PARAMETERS) VALUES (@g, @r, @t, @at, @c, @p)`
|
||||
}
|
||||
_, err = db.ExecContext(ctx, q,
|
||||
sql.Named("g", guid), sql.Named("r", nullStr(ref)), sql.Named("t", typ), sql.Named("at", at.In(time.FixedZone("МСК", 3*3600)).Format("2006-01-02T15:04:05.000")),
|
||||
sql.Named("c", nullStr(codes)), sql.Named("p", nullStr(params)))
|
||||
if err != nil {
|
||||
log.Printf("depo-events: %s %s/%s: %v", typ, shortGUID(guid), ref, err)
|
||||
return
|
||||
}
|
||||
log.Printf("depo-events: %s %s %s %s", typ, shortGUID(guid), ref, codes)
|
||||
log.Printf("depo-events: %s %s %s %s %s", typ, shortGUID(guid), ref, codes, params)
|
||||
}
|
||||
|
||||
type depoLine struct {
|
||||
@@ -223,9 +230,10 @@ func depoUpsertOrder(rc *RuntimeConfig, guid, direction, cpCode, deponentName, d
|
||||
log.Printf("depo-events: FTV_M2M %s: %v", shortGUID(guid), err)
|
||||
return false
|
||||
}
|
||||
head := `INSERT INTO dbo.FTV_M2M (GUID, DIRECTION, CONTRAGENT_M2M_CODE, DEPONENT_NAME, DEPONENT_DOC, COMMENT) VALUES (@g, @d, @cp, @nm, @doc, @cm)`
|
||||
// COMMENT не пишем — его заполняет bj2depo (17.09.2026); comment остаётся только для журнала bj.
|
||||
head := `INSERT INTO dbo.FTV_M2M (GUID, DIRECTION, CONTRAGENT_M2M_CODE, DEPONENT_NAME, DEPONENT_DOC) VALUES (@g, @d, @cp, @nm, @doc)`
|
||||
if hasDeponentID {
|
||||
head = `INSERT INTO dbo.FTV_M2M (GUID, DIRECTION, CONTRAGENT_M2M_CODE, DEPONENT_NAME, DEPONENT_DOC, DEPONENT_ID, COMMENT) VALUES (@g, @d, @cp, @nm, @doc, @did, @cm)`
|
||||
head = `INSERT INTO dbo.FTV_M2M (GUID, DIRECTION, CONTRAGENT_M2M_CODE, DEPONENT_NAME, DEPONENT_DOC, DEPONENT_ID) VALUES (@g, @d, @cp, @nm, @doc, @did)`
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx, head,
|
||||
sql.Named("g", guid), sql.Named("d", direction), sql.Named("cp", nullStr(cpCode)), sql.Named("nm", nullStr(deponentName)), sql.Named("doc", nullStr(deponentDoc)),
|
||||
@@ -310,7 +318,7 @@ func depoOnIncomingReceived(rc *RuntimeConfig, it *IncomingTransfer) {
|
||||
name := strings.TrimSpace(strings.Join([]string{it.InvestorLast, it.InvestorFirst, it.InvestorMiddle}, " "))
|
||||
doc := strings.TrimSpace(it.DocSeries + " " + it.DocNumber)
|
||||
if depoUpsertOrder(rc, it.GUID, "IN", it.SenderCode, name, doc, it.DocSeries, it.DocNumber, lines, "входящий перевод M2M от "+it.SenderCode) {
|
||||
depoEvent(rc, it.GUID, "", "BJ_RECEIVED", "", "входящий перевод получен, ждёт решения")
|
||||
depoEvent(rc, it.GUID, "", "BJ_RECEIVED", "", "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +343,7 @@ func depoOnOutgoingSent(rc *RuntimeConfig, req *m2m.M2MTransferRequest) {
|
||||
name := strings.TrimSpace(strings.Join([]string{inv.LastName, inv.FirstName, inv.MiddleName}, " "))
|
||||
guid := string(req.Header.GUID)
|
||||
if depoUpsertOrder(rc, guid, "OUT", cp, name, strings.TrimSpace(ser+" "+num), ser, num, lines, "исходящий перевод M2M, получатель ИНН "+inn) {
|
||||
depoEvent(rc, guid, "", "BJ_SENT", "", "запрос на перевод отправлен в НРД")
|
||||
depoEvent(rc, guid, "", "BJ_SENT", "", "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,9 +354,9 @@ func depoOnIncomingDecision(rc *RuntimeConfig, it *IncomingTransfer, decisions [
|
||||
}
|
||||
for _, d := range decisions {
|
||||
if d.Confirm {
|
||||
depoEvent(rc, it.GUID, d.ReferenceID, "BJ_DECISION_CONFIRM", "", "приём бумаги подтверждён контрагенту")
|
||||
depoEvent(rc, it.GUID, d.ReferenceID, "BJ_DECISION_CONFIRM", "", "")
|
||||
} else {
|
||||
depoEvent(rc, it.GUID, d.ReferenceID, "BJ_DECISION_REJECT", d.RejectCode, "отказ контрагенту: "+m2mCodeLabel(d.RejectCode))
|
||||
depoEvent(rc, it.GUID, d.ReferenceID, "BJ_DECISION_REJECT", d.RejectCode, m2mCodeLabel(d.RejectCode))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -363,33 +371,33 @@ func depoOnCounterpartyDecision(rc *RuntimeConfig, decision *m2m.M2MTransferDeci
|
||||
ref := string(sec.ReferenceID)
|
||||
if sec.TransferDecision.Rejection != nil {
|
||||
codes := strings.Join(sec.TransferDecision.Rejection.Codes, ";")
|
||||
depoEvent(rc, guid, ref, "BJ_CP_REJECT", codes, "отказ принимающего депозитария: "+rejectCodesLabel(sec.TransferDecision.Rejection.Codes))
|
||||
depoEvent(rc, guid, ref, "BJ_CP_REJECT", codes, rejectCodesLabel(sec.TransferDecision.Rejection.Codes))
|
||||
} else if sec.TransferDecision.Confirmation != nil {
|
||||
depoEvent(rc, guid, ref, "BJ_CP_CONFIRM", "", "принимающий депозитарий подтвердил")
|
||||
depoEvent(rc, guid, ref, "BJ_CP_CONFIRM", "", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func depoOnServiceError(rc *RuntimeConfig, guid, codes, reason string) {
|
||||
depoEvent(rc, guid, "", "BJ_SERVICE_ERROR", strings.ReplaceAll(strings.TrimSpace(codes), " ", ";"), "отклонено сервисом MOEX МОСТ: "+reason)
|
||||
depoEvent(rc, guid, "", "BJ_SERVICE_ERROR", strings.ReplaceAll(strings.TrimSpace(codes), " ", ";"), reason)
|
||||
}
|
||||
|
||||
func depoOnOrderSent(rc *RuntimeConfig, guid string, contrDIDs []string, form string) {
|
||||
depoEvent(rc, guid, "", "BJ_ORDER_SENT", "", "подано депо-поручение "+form+" в НРД, CONTR_D_ID "+strings.Join(contrDIDs, ", "))
|
||||
depoEvent(rc, guid, "", "BJ_ORDER_SENT", "", strings.Join(contrDIDs, ";"))
|
||||
}
|
||||
|
||||
// результат по депо-поручению: accepted | rejected | late | expired
|
||||
func depoOnOrderResult(rc *RuntimeConfig, guid, kind, text string) {
|
||||
switch kind {
|
||||
case "accepted":
|
||||
depoEvent(rc, guid, "", "BJ_ORDER_ACCEPTED", "", "НРД принял депо-поручение (отчёт MS010)")
|
||||
depoEvent(rc, guid, "", "BJ_EXECUTED", "", "перевод исполнен (MS010)")
|
||||
depoEvent(rc, guid, "", "BJ_ORDER_ACCEPTED", "", "")
|
||||
depoEvent(rc, guid, "", "BJ_EXECUTED", "", "")
|
||||
case "rejected":
|
||||
depoEvent(rc, guid, "", "BJ_ORDER_REJECTED", "", "НРД отверг депо-поручение: "+text)
|
||||
depoEvent(rc, guid, "", "BJ_ORDER_REJECTED", "", text)
|
||||
case "late":
|
||||
depoEvent(rc, guid, "", "BJ_ORDER_LATE", "", "отчёт MS010 не получен за 5 минут")
|
||||
depoEvent(rc, guid, "", "BJ_ORDER_LATE", "", "")
|
||||
case "expired":
|
||||
depoEvent(rc, guid, "", "BJ_CANCELLED", "", "истёк срок 30 дней без исполнения — перевод считается отменённым")
|
||||
depoEvent(rc, guid, "", "BJ_CANCELLED", "", "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -398,7 +406,7 @@ func depoOnQuik(rc *RuntimeConfig, guid, isin, evt, instrNo string) {
|
||||
if typ == "" {
|
||||
return
|
||||
}
|
||||
depoEvent(rc, guid, "", typ, "", "QUIK МНП: поручение №"+instrNo+", "+isin)
|
||||
depoEvent(rc, guid, "", typ, "", instrNo)
|
||||
}
|
||||
|
||||
// ---- чтение событий DEPO ----
|
||||
@@ -414,55 +422,10 @@ func depoPollEvents(ctx context.Context, rc *RuntimeConfig) {
|
||||
if !depoTableExists(cctx, db, "FTV_M2M_EVENTS") {
|
||||
return
|
||||
}
|
||||
docCol := "NULL"
|
||||
if depoHasColumn(cctx, db, "FTV_M2M", "DOC") {
|
||||
docCol = "(SELECT TOP 1 CAST(m.DOC AS varchar(32)) FROM dbo.FTV_M2M m WHERE m.GUID=e.GUID)"
|
||||
} else if depoHasColumn(cctx, db, "FTV_M2M", "FANSY_DOC") {
|
||||
docCol = "(SELECT TOP 1 CAST(m.FANSY_DOC AS varchar(32)) FROM dbo.FTV_M2M m WHERE m.GUID=e.GUID)"
|
||||
}
|
||||
// Событий от bj2depo нет (17.09.2026: мастер — bj): номер документа — FTV_M2M.DOC, результат
|
||||
// обработки — STATE/COMMENT наших событий и шапки.
|
||||
depoPollOrders(cctx, db, rc)
|
||||
depoAlertEventFailures(cctx, db, rc)
|
||||
rows, err := db.QueryContext(cctx, `SELECT TOP 100 e.ID, CAST(e.GUID AS varchar(36)), ISNULL(e.REFERENCE,''), e.EVENT_TYPE, ISNULL(e.COMMENT,''), ISNULL(e.M2M_REJECT_CODE,''),
|
||||
ISNULL(`+docCol+`,'')
|
||||
FROM dbo.FTV_M2M_EVENTS e WHERE e.EVENT_TYPE LIKE 'DEPO[_]%' AND ISNULL(e.STATE,'TODO')='TODO' ORDER BY e.ID`)
|
||||
if err != nil {
|
||||
log.Printf("depo-events: чтение: %v", err)
|
||||
return
|
||||
}
|
||||
type ev struct {
|
||||
id int64
|
||||
guid, ref, typ, comment, codes, doc string
|
||||
}
|
||||
var list []ev
|
||||
for rows.Next() {
|
||||
var e ev
|
||||
if rows.Scan(&e.id, &e.guid, &e.ref, &e.typ, &e.comment, &e.codes, &e.doc) == nil {
|
||||
list = append(list, e)
|
||||
}
|
||||
}
|
||||
rows.Close()
|
||||
for _, e := range list {
|
||||
state, note := "SUCCESS", "применено в bj"
|
||||
switch e.typ {
|
||||
case "DEPO_ORDER_CREATED":
|
||||
doc := strings.TrimSpace(e.comment)
|
||||
if e.doc != "" && e.doc != "0" {
|
||||
doc = e.doc
|
||||
}
|
||||
globalDepoLinks.update(e.guid, func(l *DepoLink) { l.DocNo, l.DocAt, l.LastEvent = doc, time.Now(), e.typ })
|
||||
log.Printf("depo-events: DEPO создала поручение по %s: %s", shortGUID(e.guid), doc)
|
||||
case "DEPO_ERROR":
|
||||
globalDepoLinks.update(e.guid, func(l *DepoLink) {
|
||||
l.Errors = append(l.Errors, time.Now().Format("02.01 15:04")+" "+e.comment)
|
||||
l.LastEvent = e.typ
|
||||
})
|
||||
raiseSystemAlert(rc, "DEPO: ошибка обработки перевода "+shortGUID(e.guid), e.comment)
|
||||
default:
|
||||
state, note = "ERROR", "тип события не поддерживается bj"
|
||||
}
|
||||
_, _ = db.ExecContext(cctx, "UPDATE dbo.FTV_M2M_EVENTS SET STATE=@s, TimeBeg=ISNULL(TimeBeg,GETDATE()), TimeEnd=GETDATE(), COMMENT=ISNULL(COMMENT,'')+@n WHERE ID=@id",
|
||||
sql.Named("s", state), sql.Named("n", " | bj: "+note), sql.Named("id", e.id))
|
||||
}
|
||||
}
|
||||
|
||||
// depoPollOrders — джоба bj2depo ставит номер поручения DEPO прямо в FTV_M2M.DOC (и DOL по строкам),
|
||||
@@ -745,7 +708,7 @@ ALTER ROLE SQLAgentOperatorRole ADD MEMBER %[1]s;
|
||||
|
||||
func depoJobPing(ctx context.Context, db *sql.DB, wait time.Duration) (bool, string) {
|
||||
guid := strings.ToUpper(fmt.Sprintf("%08x-0000-4000-8000-%012x", time.Now().Unix()&0xFFFFFFFF, time.Now().UnixNano()&0xFFFFFFFFFFFF))
|
||||
if _, err := db.ExecContext(ctx, "INSERT INTO dbo.FTV_M2M_EVENTS (GUID, REFERENCE, STATE, EVENT_TYPE, EVENT_DATE, COMMENT) VALUES (@g, NULL, 'TODO', 'BJ_PING', GETDATE(), N'проверка обработчика из bj')", sql.Named("g", guid)); err != nil {
|
||||
if _, err := db.ExecContext(ctx, "INSERT INTO dbo.FTV_M2M_EVENTS (GUID, REFERENCE, EVENT_TYPE, EVENT_DATE) VALUES (@g, NULL, 'BJ_PING', GETDATE())", sql.Named("g", guid)); err != nil {
|
||||
return false, "не удалось записать проверочное событие: " + quikErrorDetail(err)
|
||||
}
|
||||
defer db.ExecContext(context.Background(), "DELETE FROM dbo.FTV_M2M_EVENTS WHERE GUID=@g", sql.Named("g", guid))
|
||||
@@ -898,27 +861,27 @@ func depoReplayHistory(ctx context.Context, rc *RuntimeConfig, svc *Service, onl
|
||||
cp := handbookNameByCode(it.SenderCode)
|
||||
depoUpsertOrder(rc, it.GUID, "IN", it.SenderCode, name, strings.TrimSpace(it.DocSeries+" "+it.DocNumber), it.DocSeries, it.DocNumber, lines, "TEST3: входящий от "+it.SenderCode+" "+cp)
|
||||
nIn++
|
||||
ev(it.ReceivedAt, it.GUID, "", "BJ_RECEIVED", "", "входящий перевод получен от "+it.SenderCode+" "+cp)
|
||||
ev(it.ReceivedAt, it.GUID, "", "BJ_RECEIVED", "", "")
|
||||
if it.Status == "answered" {
|
||||
for _, s := range it.Securities {
|
||||
switch s.Decision {
|
||||
case "confirmed":
|
||||
ev(it.AnsweredAt, it.GUID, s.ReferenceID, "BJ_DECISION_CONFIRM", "", "приём подтверждён контрагенту")
|
||||
ev(it.AnsweredAt, it.GUID, s.ReferenceID, "BJ_DECISION_CONFIRM", "", "")
|
||||
case "rejected":
|
||||
ev(it.AnsweredAt, it.GUID, s.ReferenceID, "BJ_DECISION_REJECT", s.RejectCode, "отказ контрагенту: "+m2mCodeLabel(s.RejectCode))
|
||||
ev(it.AnsweredAt, it.GUID, s.ReferenceID, "BJ_DECISION_REJECT", s.RejectCode, m2mCodeLabel(s.RejectCode))
|
||||
}
|
||||
}
|
||||
}
|
||||
if it.OrderSubmitted {
|
||||
ev(it.OrderAt, it.GUID, "", "BJ_ORDER_SENT", "", "подано депо-поручение 16/1 (зачисление), CONTR_D_ID "+it.OrderContrDID)
|
||||
ev(it.OrderAt, it.GUID, "", "BJ_ORDER_SENT", "", it.OrderContrDID)
|
||||
resps := findOrderResponses(it.OrderContrDID)
|
||||
if done, rejected, text := orderRespVerdict(resps); done {
|
||||
at := orderRespAt(resps)
|
||||
if rejected {
|
||||
ev(at, it.GUID, "", "BJ_ORDER_REJECTED", "", "НРД отверг депо-поручение: "+text)
|
||||
ev(at, it.GUID, "", "BJ_ORDER_REJECTED", "", text)
|
||||
} else {
|
||||
ev(at, it.GUID, "", "BJ_ORDER_ACCEPTED", "", "НРД принял депо-поручение (отчёт MS010)")
|
||||
ev(at, it.GUID, "", "BJ_EXECUTED", "", "перевод исполнен (MS010)")
|
||||
ev(at, it.GUID, "", "BJ_ORDER_ACCEPTED", "", "")
|
||||
ev(at, it.GUID, "", "BJ_EXECUTED", "", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -957,14 +920,14 @@ func depoReplayHistory(ctx context.Context, rc *RuntimeConfig, svc *Service, onl
|
||||
name := strings.TrimSpace(strings.Join([]string{inv.LastName, inv.FirstName, inv.MiddleName}, " "))
|
||||
depoUpsertOrder(rc, guid, "OUT", cp, name, strings.TrimSpace(ser+" "+num), ser, num, lines, "TEST3: исходящий, получатель "+cp+" "+handbookNameByCode(cp))
|
||||
nOut++
|
||||
ev(d.CreatedAt, guid, "", "BJ_SENT", "", "запрос на перевод отправлен в НРД")
|
||||
ev(d.CreatedAt, guid, "", "BJ_SENT", "", "")
|
||||
if d.Decision != nil {
|
||||
for _, sec := range d.Decision.Data.Securities {
|
||||
ref := string(sec.ReferenceID)
|
||||
if sec.TransferDecision.Rejection != nil {
|
||||
ev(d.UpdatedAt, guid, ref, "BJ_CP_REJECT", strings.Join(sec.TransferDecision.Rejection.Codes, ";"), "отказ принимающего депозитария: "+rejectCodesLabel(sec.TransferDecision.Rejection.Codes))
|
||||
ev(d.UpdatedAt, guid, ref, "BJ_CP_REJECT", strings.Join(sec.TransferDecision.Rejection.Codes, ";"), rejectCodesLabel(sec.TransferDecision.Rejection.Codes))
|
||||
} else if sec.TransferDecision.Confirmation != nil {
|
||||
ev(d.UpdatedAt, guid, ref, "BJ_CP_CONFIRM", "", "принимающий депозитарий подтвердил")
|
||||
ev(d.UpdatedAt, guid, ref, "BJ_CP_CONFIRM", "", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -973,19 +936,19 @@ func depoReplayHistory(ctx context.Context, rc *RuntimeConfig, svc *Service, onl
|
||||
for _, rr := range d.Response.Responses {
|
||||
codes = append(codes, string(rr.Code))
|
||||
}
|
||||
ev(d.UpdatedAt, guid, "", "BJ_SERVICE_ERROR", strings.Join(codes, ";"), "отклонено сервисом MOEX МОСТ: "+rejectCodesLabel(codes))
|
||||
ev(d.UpdatedAt, guid, "", "BJ_SERVICE_ERROR", strings.Join(codes, ";"), rejectCodesLabel(codes))
|
||||
}
|
||||
if globalOutgoingStore != nil {
|
||||
if od, ok := scanForm16Deal(globalOutgoingStore, guid); ok && od.Submitted {
|
||||
ev(od.OrderAt, guid, "", "BJ_ORDER_SENT", "", "подано депо-поручение 16 (списание), CONTR_D_ID "+strings.Join(od.ContrDIDs, ", "))
|
||||
ev(od.OrderAt, guid, "", "BJ_ORDER_SENT", "", strings.Join(od.ContrDIDs, ";"))
|
||||
resps, _ := outgoingResponses(od.ContrDIDs)
|
||||
if done, rejected, text := orderRespVerdict(resps); done {
|
||||
at := orderRespAt(resps)
|
||||
if rejected {
|
||||
ev(at, guid, "", "BJ_ORDER_REJECTED", "", "НРД отверг депо-поручение: "+text)
|
||||
ev(at, guid, "", "BJ_ORDER_REJECTED", "", text)
|
||||
} else {
|
||||
ev(at, guid, "", "BJ_ORDER_ACCEPTED", "", "НРД принял депо-поручение (отчёт MS010)")
|
||||
ev(at, guid, "", "BJ_EXECUTED", "", "перевод исполнен (MS010)")
|
||||
ev(at, guid, "", "BJ_ORDER_ACCEPTED", "", "")
|
||||
ev(at, guid, "", "BJ_EXECUTED", "", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1028,24 +991,24 @@ func depoSimulateIncoming(ctx context.Context, rc *RuntimeConfig, it *IncomingTr
|
||||
return "", fmt.Errorf("не удалось записать шапку в FTV_M2M")
|
||||
}
|
||||
now := time.Now()
|
||||
depoEventAt(rc, now, guid, "", "BJ_RECEIVED", "", "входящий перевод получен от "+it.SenderCode+" "+cp+" (тест по образцу "+shortGUID(it.GUID)+")")
|
||||
depoEventAt(rc, now, guid, "", "BJ_RECEIVED", "", "")
|
||||
anyConfirmed := false
|
||||
for _, s := range it.Securities {
|
||||
switch s.Decision {
|
||||
case "confirmed":
|
||||
anyConfirmed = true
|
||||
depoEventAt(rc, now.Add(time.Minute), guid, s.ReferenceID, "BJ_DECISION_CONFIRM", "", "приём подтверждён контрагенту")
|
||||
depoEventAt(rc, now.Add(time.Minute), guid, s.ReferenceID, "BJ_DECISION_CONFIRM", "", "")
|
||||
case "rejected":
|
||||
depoEventAt(rc, now.Add(time.Minute), guid, s.ReferenceID, "BJ_DECISION_REJECT", s.RejectCode, "отказ контрагенту: "+m2mCodeLabel(s.RejectCode))
|
||||
depoEventAt(rc, now.Add(time.Minute), guid, s.ReferenceID, "BJ_DECISION_REJECT", s.RejectCode, m2mCodeLabel(s.RejectCode))
|
||||
default:
|
||||
anyConfirmed = true
|
||||
depoEventAt(rc, now.Add(time.Minute), guid, s.ReferenceID, "BJ_DECISION_CONFIRM", "", "приём подтверждён контрагенту (тест)")
|
||||
depoEventAt(rc, now.Add(time.Minute), guid, s.ReferenceID, "BJ_DECISION_CONFIRM", "", "")
|
||||
}
|
||||
}
|
||||
if anyConfirmed {
|
||||
depoEventAt(rc, now.Add(2*time.Minute), guid, "", "BJ_ORDER_SENT", "", "подано депо-поручение 16/1 (зачисление) в НРД (тест)")
|
||||
depoEventAt(rc, now.Add(3*time.Minute), guid, "", "BJ_ORDER_ACCEPTED", "", "НРД принял депо-поручение (отчёт MS010) (тест)")
|
||||
depoEventAt(rc, now.Add(3*time.Minute), guid, "", "BJ_EXECUTED", "", "перевод исполнен (MS010) (тест)")
|
||||
depoEventAt(rc, now.Add(2*time.Minute), guid, "", "BJ_ORDER_SENT", "", "")
|
||||
depoEventAt(rc, now.Add(3*time.Minute), guid, "", "BJ_ORDER_ACCEPTED", "", "")
|
||||
depoEventAt(rc, now.Add(3*time.Minute), guid, "", "BJ_EXECUTED", "", "")
|
||||
}
|
||||
return guid, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user