Files
Bridge-and-Join-s/internal/lkgateway/participant_reg.go
T
fontvielle 60b4d46277 Списки: период, сортировка, подгрузка; анкета участника — строкой исходящих
«Исходящие», «Входящие», «Журнал обмена»: быстрые периоды (сегодня, 7, 30
дней, всё время), даты с–по, сортировка (время, инвестор/контрагент,
направление, статус), первые 50 строк и подгрузка при прокрутке
(part=rows&offset=N). Раньше показывались только последние 200/100.

Анкета участника — исходящий пакет в НРД: строка в «Исходящих» и
«Журнале» с ответом НРД (принята / отклонена с кодом / ждёт), вместо
плашки над списком. Отправки копятся в participant-regs.json (прежний
participant-reg.json подхватывается). userTemplate — функции текущего
пользователя и для порций строк.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
2026-10-22 10:50:43 +03:00

141 lines
4.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package lkgateway
// participant_reg.go — учёт регистрации участника M2M: что и когда отправили
// анкетой (#M2MPF) и какой ответ дал НРД (сервис МОСТ, M2MTransferResponse с
// нулевым GUID — он не относится к переводу). Показывается на странице анкеты.
import (
"encoding/json"
"os"
"strings"
"sync"
"time"
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/m2m"
)
const participantRegFile = "/var/lib/bj/.bj/participant-reg.json"
// participantReg — последняя отправка анкеты и ответ НРД на неё.
type participantReg struct {
SentAt time.Time `json:"sent_at,omitempty"`
PkgID string `json:"pkg_id,omitempty"`
Name string `json:"name,omitempty"` // отправленное полное наименование
Channel string `json:"channel,omitempty"`
RespAt time.Time `json:"resp_at,omitempty"`
Status string `json:"status,omitempty"` // OK | ERROR
Codes []string `json:"codes,omitempty"`
RespText string `json:"resp_text,omitempty"`
RawFile string `json:"raw_file,omitempty"`
}
var participantRegMu sync.Mutex
// participantRegsFile — все отправки анкеты (строки в «Исходящих» и «Журнале»); participantRegFile —
// прежний файл с одной последней отправкой, из него история начинается при первом чтении.
const participantRegsFile = "/var/lib/bj/.bj/participant-regs.json"
func readParticipantRegs() []participantReg {
var list []participantReg
if b, err := os.ReadFile(participantRegsFile); err == nil {
_ = json.Unmarshal(b, &list)
return list
}
var r participantReg
if b, err := os.ReadFile(participantRegFile); err == nil && json.Unmarshal(b, &r) == nil && !r.SentAt.IsZero() {
list = append(list, r)
}
return list
}
func writeParticipantRegs(list []participantReg) {
b, err := json.MarshalIndent(list, "", " ")
if err != nil {
return
}
tmp := participantRegsFile + ".tmp"
if os.WriteFile(tmp, b, 0o640) == nil {
_ = os.Rename(tmp, participantRegsFile)
}
}
// loadParticipantRegs — все отправки анкеты, старые первыми.
func loadParticipantRegs() []participantReg {
participantRegMu.Lock()
defer participantRegMu.Unlock()
return readParticipantRegs()
}
// loadParticipantReg — последняя отправка анкеты.
func loadParticipantReg() participantReg {
list := loadParticipantRegs()
if len(list) == 0 {
return participantReg{}
}
return list[len(list)-1]
}
// addParticipantReg — новая отправка анкеты.
func addParticipantReg(r participantReg) {
participantRegMu.Lock()
defer participantRegMu.Unlock()
writeParticipantRegs(append(readParticipantRegs(), r))
}
// saveParticipantReg — изменить последнюю отправку (ответ НРД приходит на неё).
func saveParticipantReg(mut func(*participantReg)) {
participantRegMu.Lock()
defer participantRegMu.Unlock()
list := readParticipantRegs()
if len(list) == 0 {
list = append(list, participantReg{})
}
mut(&list[len(list)-1])
writeParticipantRegs(list)
}
// StatusClass, StatusText — статус отправки анкеты для строк списков (класс бейджа и текст).
func (r participantReg) StatusClass() string {
switch {
case r.RespAt.IsZero():
return "awaiting_decision"
case strings.EqualFold(r.Status, "ERROR"):
return "rejected"
}
return "confirmed"
}
func (r participantReg) StatusText() string {
switch {
case r.RespAt.IsZero():
return "Ждёт ответа НРД"
case strings.EqualFold(r.Status, "ERROR"):
if len(r.Codes) > 0 {
return "Отклонена НРД · " + strings.Join(r.Codes, ", ")
}
return "Отклонена НРД"
}
return "Принята НРД"
}
// recordParticipantReply сохраняет ответ НРД на анкету (статус, коды, тексты, файл XML).
func recordParticipantReply(status string, resp *m2m.M2MTransferResponse, rawFile string) {
var codes []string
seen := map[string]bool{}
for _, rr := range resp.Responses {
c := strings.TrimSpace(rr.Code)
if c != "" && !seen[c] {
seen[c] = true
codes = append(codes, c)
}
}
text := strings.Join(serviceErrorTexts(resp), "; ")
saveParticipantReg(func(r *participantReg) {
r.RespAt = time.Now()
r.Status = status
r.Codes = codes
r.RespText = text
r.RawFile = rawFile
})
}