Справочник участников: показывать результат обработки джобой Fancy
На странице «Справочник участников M2M» теперь выводится итог обработки справочника джобой bj2depo — STATE/COMMENT последнего события HANDBOOK из FTV_M2M_EVENTS (поле COMMENT пишет Fancy). Расхождения/предупреждения выделяются цветом и значком: КРИТИЧ/ОШИБКА — красным, ПРЕДУПРЕЖДЕНИЕ — жёлтым, «изменений нет» — зелёным, чтобы оператор видел, что проверить. Только чтение (fsql.QEv11, TOP 1 по EVENT_DATE), короткий таймаут 4с, страница не висит если DEPO недоступна. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -846,6 +846,7 @@ type handbookData struct {
|
||||
At string
|
||||
Participants []HandbookEntry
|
||||
CodesHTML template.HTML // справка по кодам ошибок/отказов M2M
|
||||
Result HandbookResult // итог обработки справочника джобой Fancy bj2depo
|
||||
}
|
||||
|
||||
// renderHandbook показывает сохранённый справочник участников M2M с поиском.
|
||||
@@ -853,6 +854,7 @@ type handbookData struct {
|
||||
func (a *admin) renderHandbook(w http.ResponseWriter, _ *http.Request) {
|
||||
data := handbookData{page: nowPage("Справочник участников", "handbook")}
|
||||
data.CodesHTML = template.HTML(m2mSpravkaHTML(false)) // справка по кодам ошибок
|
||||
data.Result = depoHandbookResult(globalRC)
|
||||
if raw, err := readHandbook(); err == nil {
|
||||
var hb struct {
|
||||
At string `json:"at"`
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/lkgateway/fsql"
|
||||
"log"
|
||||
@@ -551,6 +552,77 @@ func depoPollOrders(ctx context.Context, db *sql.DB, rc *RuntimeConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// HandbookResult — результат обработки справочника участников джобой Fancy bj2depo
|
||||
// (STATE/COMMENT последнего события HANDBOOK в FTV_M2M_EVENTS). bj только читает.
|
||||
type HandbookResult struct {
|
||||
Found bool
|
||||
At time.Time
|
||||
AtText string
|
||||
State string
|
||||
Comment string
|
||||
Severity string // ok | warn | err
|
||||
Err string
|
||||
}
|
||||
|
||||
// handbookSeverity — важность результата обработки справочника по STATE/COMMENT.
|
||||
func handbookSeverity(state, comment string) string {
|
||||
s := strings.ToUpper(state)
|
||||
u := strings.ToUpper(comment)
|
||||
switch {
|
||||
case strings.Contains(s, "ERROR") || strings.Contains(u, "ОШИБКА") || strings.Contains(u, "КРИТИЧ"):
|
||||
return "err"
|
||||
case strings.Contains(s, "WARN") || strings.Contains(u, "ПРЕДУПРЕЖД"):
|
||||
return "warn"
|
||||
default:
|
||||
return "ok"
|
||||
}
|
||||
}
|
||||
|
||||
// depoHandbookResult читает результат последней обработки справочника участников: событие
|
||||
// HANDBOOK, в COMMENT/STATE которого джоба Fancy bj2depo пишет итог сверки своего справочника
|
||||
// юрлиц с данными НРД (расхождения, предупреждения). Только чтение, короткий таймаут.
|
||||
func depoHandbookResult(rc *RuntimeConfig) HandbookResult {
|
||||
var res HandbookResult
|
||||
if rc == nil {
|
||||
res.Err = "настройки недоступны"
|
||||
return res
|
||||
}
|
||||
fs := rc.Snapshot().Fancy
|
||||
if strings.TrimSpace(fs.Server) == "" {
|
||||
res.Err = "подключение к DEPO (Обмен Fancy) не настроено"
|
||||
return res
|
||||
}
|
||||
db, err := fancyOpen(fs, fs.DepoDB())
|
||||
if err != nil {
|
||||
res.Err = "DEPO недоступна: " + err.Error()
|
||||
return res
|
||||
}
|
||||
defer db.Close()
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)
|
||||
defer cancel()
|
||||
if !depoTableExists(ctx, db, "FTV_M2M_EVENTS") {
|
||||
res.Err = "таблицы FTV_M2M_EVENTS нет"
|
||||
return res
|
||||
}
|
||||
var at time.Time
|
||||
var state, comment string
|
||||
err = db.QueryRowContext(ctx, fsql.QEv11).Scan(&at, &state, &comment)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return res // событий HANDBOOK ещё нет
|
||||
}
|
||||
res.Err = err.Error()
|
||||
return res
|
||||
}
|
||||
res.Found = true
|
||||
res.At = at
|
||||
res.AtText = at.Format("02.01.2006 15:04")
|
||||
res.State = strings.TrimSpace(state)
|
||||
res.Comment = strings.TrimSpace(comment)
|
||||
res.Severity = handbookSeverity(res.State, res.Comment)
|
||||
return res
|
||||
}
|
||||
|
||||
// ---- справочник участников → FTV_M2M_HANDBOOK (полная перезапись) ----
|
||||
|
||||
var depoHandbookWritten time.Time
|
||||
|
||||
@@ -23,3 +23,7 @@ var QEv09 = "SELECT REFERENCE FROM dbo.FTV_M2M_LINES WHERE GUID=@g AND (@i = ''
|
||||
// FTV_M2M_HANDBOOK (в той же транзакции), без GUID/REFERENCE. По нему джоба bj2depo узнаёт, что
|
||||
// справочник обновился от НРД, и может перезагрузить его в своих структурах.
|
||||
var QEv10 = "INSERT INTO dbo.FTV_M2M_EVENTS (EVENT_TYPE, EVENT_DATE) VALUES ('HANDBOOK', GETDATE())"
|
||||
|
||||
// QEv11 — результат последней обработки справочника участников джобой bj2depo: STATE/COMMENT
|
||||
// последнего события HANDBOOK. bj только читает (COMMENT/STATE пишет Fancy).
|
||||
var QEv11 = "SELECT TOP 1 EVENT_DATE, ISNULL(STATE,''), ISNULL(COMMENT,'') FROM dbo.FTV_M2M_EVENTS WHERE EVENT_TYPE='HANDBOOK' ORDER BY EVENT_DATE DESC"
|
||||
|
||||
@@ -12,6 +12,24 @@
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{if or .Result.Found .Result.Err}}
|
||||
<div class="card">
|
||||
<h2 style="margin-top:0">Результат обработки в Fancy</h2>
|
||||
<p class="muted" style="margin-top:0">Итог сверки справочника юрлиц Fancy с данными НРД (джоба bj2depo, поле COMMENT последнего события HANDBOOK).</p>
|
||||
{{if .Result.Err}}
|
||||
<p class="muted">Результат пока недоступен: {{.Result.Err}}.</p>
|
||||
{{else}}
|
||||
<div style="padding:12px 14px;border-radius:10px;background:{{if eq .Result.Severity "err"}}var(--err-weak,#f7dede){{else if eq .Result.Severity "warn"}}var(--warn-weak,#f6eed8){{else}}var(--ok-weak,#e3f2e3){{end}}">
|
||||
<div style="font-weight:600;margin-bottom:6px">
|
||||
{{if eq .Result.Severity "err"}}⛔ Обнаружены ошибки — проверьте и исправьте{{else if eq .Result.Severity "warn"}}⚠ Есть предупреждения — проверьте{{else}}✓ Справочник обработан, расхождений нет{{end}}
|
||||
<span class="muted" style="font-weight:400;font-size:12px">· обработано {{.Result.AtText}}{{with .Result.State}} · статус {{.}}{{end}}</span>
|
||||
</div>
|
||||
{{with .Result.Comment}}<pre style="white-space:pre-wrap;word-break:break-word;margin:0;font-size:13px;line-height:1.5;font-family:inherit">{{.}}</pre>{{else}}<span class="muted">джоба отработала, но COMMENT пуст</span>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .Participants}}
|
||||
<div class="card">
|
||||
<div style="display:flex;gap:12px;flex-wrap:wrap;align-items:center;justify-content:space-between">
|
||||
|
||||
Reference in New Issue
Block a user