DEPO: справочник и событие HANDBOOK — только при изменении состава

Справочник переписывался в DEPO (DELETE + ~90 INSERT + событие HANDBOOK)
при каждом запуске bj и раз в 6 часов, даже без изменений — Fancy каждый
раз заново сверял участников. Теперь отпечаток состава (без даты) и
куда записан хранятся в depo-handbook-written.json: без изменений — один
COUNT для проверки и ничего не пишется; не записанное прежде событие
HANDBOOK дописывается одно.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
fontvielle
2026-10-22 13:44:13 +03:00
parent fbcc859289
commit a799847ccc
+64
View File
@@ -11,7 +11,9 @@ package lkgateway
import (
"context"
"crypto/sha256"
"database/sql"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
@@ -20,6 +22,7 @@ import (
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"sync"
@@ -660,6 +663,27 @@ func depoWriteHandbookCtx(pctx context.Context, rc *RuntimeConfig) error {
log.Printf("depo-events: таблица FTV_M2M_HANDBOOK создана в %s", rc.Snapshot().Fancy.DepoDB())
}
hbAt, _ := time.Parse(time.RFC3339, hb.At)
// Без изменений — базу не трогаем: тот же состав (отпечаток без даты справочника) уже записан в эту базу
// и строк в таблице столько же. Событие HANDBOOK, не записанное в прошлый раз, — дописываем одно.
sum := depoHandbookSum(hb.Participants, hb.Places)
target := rc.Snapshot().Fancy.Server + "/" + rc.Snapshot().Fancy.DepoDB()
if st := depoHandbookStateLoad(); st.Sum == sum && st.Target == target {
var rows int
if db.QueryRowContext(ctx, "SELECT COUNT(*) FROM dbo.FTV_M2M_HANDBOOK").Scan(&rows) == nil && rows == len(hb.Participants)+len(hb.Places) {
depoHandbookWritten = time.Now()
if st.Event {
return nil
}
if _, err := db.ExecContext(ctx, fsql.QEv10); err != nil {
log.Printf("depo-events: справочник без изменений, событие HANDBOOK по-прежнему не записывается: %v — примените скрипты DEPO", err)
return nil
}
st.Event = true
depoHandbookStateSave(st)
log.Printf("depo-events: справочник без изменений; записано отложенное событие HANDBOOK")
return nil
}
}
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
@@ -706,9 +730,11 @@ func depoWriteHandbookCtx(pctx context.Context, rc *RuntimeConfig) error {
// переносит справочник в юрлица Fancy (FTV_M2M_UPDATE_HANDBOOK). Отдельно от записи справочника: не
// записалось (в старой таблице GUID NOT NULL) — справочник всё равно в DEPO, а событие ждёт скриптов.
if _, err := db.ExecContext(ctx, fsql.QEv10); err != nil {
depoHandbookStateSave(depoHandbookState{Sum: sum, Target: target, Event: false})
log.Printf("depo-events: справочник записан в FTV_M2M_HANDBOOK (%d строк), но событие HANDBOOK — нет: %v — примените скрипты DEPO (плашка «Обновление bj требует применить скрипты»)", n, err)
return nil
}
depoHandbookStateSave(depoHandbookState{Sum: sum, Target: target, Event: true})
log.Printf("depo-events: справочник участников записан в FTV_M2M_HANDBOOK: %d строк + событие HANDBOOK", n)
return nil
}
@@ -1572,3 +1598,41 @@ func depoProcsMissing(ctx context.Context, db *sql.DB, f FancyMSSQLSettings) str
}
return ""
}
// depoHandbookState — что записано в DEPO в последний раз: отпечаток состава справочника, куда (сервер/база)
// и записано ли событие HANDBOOK. Без изменений справочник в DEPO не переписывается.
type depoHandbookState struct {
Sum string `json:"sum"`
Target string `json:"target"`
Event bool `json:"event"`
}
const depoHandbookStateFile = "/var/lib/bj/.bj/depo-handbook-written.json"
func depoHandbookStateLoad() depoHandbookState {
var st depoHandbookState
if b, err := os.ReadFile(depoHandbookStateFile); err == nil {
_ = json.Unmarshal(b, &st)
}
return st
}
func depoHandbookStateSave(st depoHandbookState) {
if b, err := json.Marshal(st); err == nil {
_ = os.WriteFile(depoHandbookStateFile, b, 0o640)
}
}
// depoHandbookSum — отпечаток состава справочника (участники и места расчётов, без даты справочника).
func depoHandbookSum(parts, places []HandbookEntry) string {
var lines []string
for _, e := range parts {
lines = append(lines, strings.Join([]string{"P", e.INN, e.Code, e.Kind, e.Name, e.FullName, e.DisplayName, e.EngName}, "|"))
}
for _, e := range places {
lines = append(lines, strings.Join([]string{"S", e.INN, e.Code, e.Name, e.FullName, e.DisplayName, e.EngName}, "|"))
}
sort.Strings(lines)
h := sha256.Sum256([]byte(strings.Join(lines, "\n")))
return hex.EncodeToString(h[:12])
}