07866526eb
Ответ НРД на анкету приходит как M2MTransferResponse (M2MER) с нулевым GUID — раньше он уходил в обработку перевода, «сделка не найдена», и отбрасывался. Теперь нулевой GUID распознаётся как ответ на регистрацию участника: - сырой XML сохраняется (captureNSDReply → nsd-replies); - отправка анкеты и ответ НРД пишутся в participant-reg.json (время, пакет, наименование, статус, коды, текст НРД); - на странице «Регистрация участника M2M» показываем: когда отправили и вердикт НРД («принял»/«отклонил» с текстом, напр. M2M37 «Некорректно указано наименование участника в анкете»). Текст берётся из самого ответа (serviceErrorTexts) — карту кодов не трогаем. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
83 lines
2.6 KiB
Go
83 lines
2.6 KiB
Go
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
|
||
|
||
func loadParticipantReg() participantReg {
|
||
participantRegMu.Lock()
|
||
defer participantRegMu.Unlock()
|
||
var r participantReg
|
||
if b, err := os.ReadFile(participantRegFile); err == nil {
|
||
_ = json.Unmarshal(b, &r)
|
||
}
|
||
return r
|
||
}
|
||
|
||
// saveParticipantReg читает текущую запись, даёт изменить и атомарно пишет назад.
|
||
func saveParticipantReg(mut func(*participantReg)) {
|
||
participantRegMu.Lock()
|
||
defer participantRegMu.Unlock()
|
||
var r participantReg
|
||
if b, err := os.ReadFile(participantRegFile); err == nil {
|
||
_ = json.Unmarshal(b, &r)
|
||
}
|
||
mut(&r)
|
||
b, err := json.MarshalIndent(&r, "", " ")
|
||
if err != nil {
|
||
return
|
||
}
|
||
tmp := participantRegFile + ".tmp"
|
||
if os.WriteFile(tmp, b, 0o640) == nil {
|
||
_ = os.Rename(tmp, participantRegFile)
|
||
}
|
||
}
|
||
|
||
// 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
|
||
})
|
||
}
|