Путь заявки из всех источников: сделка, QUIK, события DEPO (с обработкой/ошибкой), поручение 16 и документы НРД (регистрация, GS036, GS116 сквитовано, MS010); «Обновлена» — последнее событие; статус учитывает сквитовку (GS116), время MS010 в строке статуса

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-29 12:44:52 +03:00
parent e123eda691
commit 340fca7bd7
7 changed files with 405 additions and 46 deletions
+4 -40
View File
@@ -627,6 +627,9 @@ func (a *admin) renderClaim(w http.ResponseWriter, r *http.Request, svc *Service
return
}
view.Timeline = buildClaimTimeline(r.Context(), view)
if last := timelineLast(view.Timeline); last.After(view.UpdatedAt) {
view.UpdatedAt = last // «Обновлена» — последнее событие по заявке, а не последняя смена состояния сделки
}
var depo *OutgoingDeal
if view.M2MGUID != "" && globalOutgoingStore != nil {
if d, ok := scanForm16Deal(globalOutgoingStore, string(view.M2MGUID)); ok {
@@ -689,46 +692,7 @@ func buildClaimTimeline(ctx context.Context, v ClaimView) []TimelineEvent {
}
}
// Происхождение из ЛК ЕСИА Финанс (путь напрямую через коннектор, минуя
// Fancy): показываем стартовый шаг с номером заявки в ЛК.
if v.M2MGUID != "" {
if lkID, ok := LKClaimIDByGUID(string(v.M2MGUID)); ok {
add("Заявка из ЛК ЕСИА Финанс", "db",
fmt.Sprintf("Забрана коннектором из личного кабинета (заявка ЛК #%d).", lkID),
v.CreatedAt, time.Time{})
}
}
// Отправлена в шлюз НРД (Deal создаётся в момент отправки).
add("Отправлена в интеграционный шлюз НРД", "gateway", "Подписана ключом и передана в ИШ.", v.CreatedAt, time.Time{})
// Ответ НРД (если получен).
if v.M2MDecision != nil {
conf, rej := 0, 0
for _, s := range v.M2MDecision.Securities {
if s.Outcome == "confirmed" {
conf++
} else {
rej++
}
}
title := "Получено решение контрагента (НРД)"
if devMode(globalRC) {
title = "Получено решение НРД (робот)"
}
add(title, "response",
fmt.Sprintf("Принято %d, отклонено %d.", conf, rej), v.UpdatedAt, v.CreatedAt)
} else if v.M2MResponse != nil {
var codes string
for _, e := range v.M2MResponse.Responses {
if e.Code != "" {
codes += e.Code + " "
}
}
add("Ответ сервиса МОСТ (НРД)", "response",
"Статус: "+v.M2MResponse.StatusCode+". "+strings.TrimSpace(codes), v.UpdatedAt, v.CreatedAt)
}
return tl
return claimTimelineFull(ctx, v)
}
// formatSince — человекочитаемая длительность между шагами таймлайна.