Мониторинг связи с НРД: участки Шлюз/НРД/M2M/Отправка, сквозная проверка справочником раз в 10 мин, история за сутки на «Статусе», цепочка в шапке (30 с), автоповтор недоставленных до 24 ч, баннер и статус «ожидает отправки» в кабинете клиента

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
zuevav
2026-09-25 16:17:25 +03:00
parent a0f6ce9f7b
commit 4cbefa41d5
18 changed files with 1075 additions and 62 deletions
+16
View File
@@ -42,6 +42,8 @@ type Client struct {
retryWait time.Duration
// confirmWait — сколько ждать от ИШ итога передачи пакета в НРД (SENT/ERROR). 0 — не ждать.
confirmWait time.Duration
// onDelivery — итог передачи каждого пакета в НРД (SENT | ERROR | NEW — не дождались), для мониторинга.
onDelivery func(packageID, status, code string)
}
// Option настраивает Client.
@@ -63,6 +65,11 @@ func WithConfirmWait(d time.Duration) Option {
return func(cl *Client) { cl.confirmWait = d }
}
// WithDeliveryHook — сообщать итог передачи каждого пакета в НРД (для мониторинга связи).
func WithDeliveryHook(f func(packageID, status, code string)) Option {
return func(cl *Client) { cl.onDelivery = f }
}
// NotDeliveredError — ИШ принял пакет, но передать его в НРД не смог (статус ERROR): например,
// контур НРД недоступен (ERRORXML_UPLOAD_FAILED). Пакет в НРД не ушёл — отправку нужно повторить.
type NotDeliveredError struct {
@@ -171,6 +178,12 @@ func (c *Client) SendPackage(ctx context.Context, channel, packageType string, z
return id, nil
}
func (c *Client) delivered(id, status, code string) {
if c.onDelivery != nil {
c.onDelivery(id, status, code)
}
}
// waitDelivered — ИШ отвечает id сразу, а в НРД передаёт пакет следом (обычно за доли секунды).
// Ждём итог: SENT — доставлен; ERROR — не доставлен (*NotDeliveredError). Если статус узнать
// не удалось или пакет всё ещё в очереди ИШ — считаем отправленным, как раньше.
@@ -186,13 +199,16 @@ func (c *Client) waitDelivered(ctx context.Context, id string) error {
}
switch strings.ToUpper(st.Status) {
case StatusSent:
c.delivered(id, StatusSent, "")
return nil
case StatusError:
c.delivered(id, StatusError, st.Error)
return &NotDeliveredError{PackageID: id, Code: st.Error}
case "": // ИШ не сообщает статус — ждать нечего
return nil
}
if time.Now().Add(wait).After(deadline) {
c.delivered(id, StatusNew, "")
return nil
}
select {