package lkgateway // outgoing_export.go — выгрузка для регулятора по исходящему переводу (списание): // отчёт-доказательство с хронологией депозитарного исполнения (черновик 16 → // поручение 16 подано → отчёт MS010 о списании) + дословный XML отправленного 16. import ( "archive/zip" "fmt" "html" "net/http" "strings" "time" ) func exportOutgoing(w http.ResponseWriter, r *http.Request, deps outgoingDeps, guid string) { deal, ok := scanForm16Deal(deps.store, guid) if !ok { http.Error(w, "исходящая сделка не найдена", http.StatusNotFound) return } w.Header().Set("Content-Type", "application/zip") w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="ishodyaschiy-%s.zip"`, shortID(guid))) zw := zip.NewWriter(w) defer zw.Close() if f, e := zw.Create("otchet.html"); e == nil { _, _ = f.Write(outgoingReportHTML(deal)) } if deal.OrderXML != "" { if f, e := zw.Create("poruchenie-16.xml"); e == nil { _, _ = f.Write(faithfulXMLBytes(deal.OrderXML)) } } // Ответ НРД по поручению (отчёт MS010 + квитанции) — сырые файлы из INBOX. for _, rf := range collectOutgoingResponseRaw(deal.ContrDIDs) { if f, e := zw.Create("otvet-nrd/" + rf.Name); e == nil { _, _ = f.Write(rf.Data) } } } func outgoingReportHTML(d *OutgoingDeal) []byte { esc := html.EscapeString msk := func(t time.Time) string { if t.IsZero() { return "—" } return t.In(time.FixedZone("МСК", 3*3600)).Format("02.01.2006 15:04:05") + " МСК" } var b strings.Builder b.WriteString(``) b.WriteString(`Отчёт об исходящем переводе M2M (списание)`) b.WriteString(`
` + moexMostLogoSVG + `Сервис быстрых переводов ценных бумаг
MOEX МОСТ · НКО АО НРД
` + orgLogoIMG() + `
`) b.WriteString(`

Отчёт об исходящем переводе ценных бумаг (списание, M2M / MOEX МОСТ)

`) b.WriteString(`
Доказательство для контролирующих органов. GUID сделки: ` + esc(d.GUID) + ` · Сформировано: ` + time.Now().In(time.FixedZone("МСК", 3*3600)).Format("02.01.2006 15:04:05") + ` МСК
`) row := func(k, v string) { b.WriteString(`` + k + `` + v + ``) } b.WriteString(`

Реквизиты перевода

`) row("GUID сделки", ``+esc(d.GUID)+``) if d.DealRef != "" { row("Референс сделки (deal_reference)", esc(d.DealRef)) } to := esc(d.CounterpartyCode) if n := handbookNameByCode(d.CounterpartyCode); n != "" { to = `` + esc(n) + ` · ` + to } row("Принимающий депозитарий (контрагент)", to) b.WriteString(`
`) var ms010At string for _, rp := range d.Responses { if rp.Done { ms010At = rp.Time } } b.WriteString(`

Депозитарное исполнение (поручение 16 — списание) — хронология

`) row("Черновик 16 получен от НРД (MF010)", msk(d.DraftAt)) if d.Submitted { row("Поручение 16 подано в НРД", msk(d.OrderAt)) row("Тип ЭД / пакет(ы) ИШ", "ORDXM · "+esc(d.Pkgs)) if len(d.ContrDIDs) > 0 { row("Номера поручений (contr_d_id)", esc(strings.Join(d.ContrDIDs, ", "))) } } else { row("Поручение 16 подано в НРД", `— (ещё не подано)`) } if ms010At != "" { row("Отчёт MS010 получен (списание проведено)", esc(ms010At)+` МСК — бумага списана и передана контрагенту`) } else { row("Отчёт MS010 получен", `— (ещё не получен)`) } b.WriteString(`
`) b.WriteString(`

Ценные бумаги

`) for _, s := range d.Secs { code := esc(s.SecurityCode) if s.ISIN != "" && s.ISIN != s.SecurityCode { code += ` / ` + esc(s.ISIN) } b.WriteString(``) } b.WriteString(`
Код НРД / ISINКол-во№ поручения
` + code + `` + esc(s.Quantity) + `` + esc(s.ContrDID) + `
`) if len(d.Responses) > 0 { b.WriteString(`

Ответы НРД по поручению

`) for _, rp := range d.Responses { b.WriteString(``) } b.WriteString(`
Время полученияТип ответаПакет
` + esc(rp.Time) + ` МСК` + esc(rp.Kind) + `` + esc(rp.Pkg) + `
`) } if d.OrderXML != "" { b.WriteString(`

Отправленное поручение 16 (дословно)

` + esc(d.OrderXML) + `
`) } b.WriteString(`

Отчёт сформирован автоматически системой Bridge-and-Join-s (bj). Логотип MOEX МОСТ — собственность НКО АО НРД.

`) b.WriteString(``) return []byte(b.String()) }