diff --git a/internal/lkgateway/depo_procs.go b/internal/lkgateway/depo_procs.go index 8f8374c..06e104e 100644 --- a/internal/lkgateway/depo_procs.go +++ b/internal/lkgateway/depo_procs.go @@ -87,9 +87,20 @@ func depoProcOrderText(sep string) string { return strings.Join(parts, sep) } +// depoSchemaFixes — правки структуры трансферных таблиц, которые логин bj сделать не может (нужны права +// администратора БД); выполняются вместе с процедурами. Повторный запуск безопасен. +var depoSchemaFixes = []struct{ Name, SQL string }{ + // 22.10.2026: служебные события (HANDBOOK) — без GUID; в таблицах, созданных bj до этого, GUID NOT NULL + {"FTV_M2M_EVENTS.GUID NULL", `IF EXISTS (SELECT 1 FROM sys.columns WHERE object_id=OBJECT_ID(N'dbo.FTV_M2M_EVENTS') AND name=N'GUID' AND is_nullable=0) + ALTER TABLE dbo.FTV_M2M_EVENTS ALTER COLUMN GUID uniqueidentifier NULL`}, +} + // depoProcsHash — отпечаток набора процедур, который bj установит (с учётом правки под клиента). func depoProcsHash(f FancyMSSQLSettings) string { h := sha256.New() + for _, fx := range depoSchemaFixes { + h.Write([]byte(fx.Name + "\n" + fx.SQL + "\n")) + } for _, p := range depoProcInstallOrder { h.Write([]byte(p.Name + "\n" + strings.TrimSpace(depoProcEffective(f, p.Name)) + "\n")) } @@ -125,6 +136,9 @@ func depoProcsScriptFor(f FancyMSSQLSettings, db, login string) string { b.WriteString(" Порядок " + depoProcOrderText(" -> ") + ". Запуск под sysadmin в SSMS.\n") b.WriteString(" CREATE OR ALTER — повторный запуск безопасен (данные не меняются). */\n") fmt.Fprintf(&b, "USE %s;\nGO\n\n", quoteIdent(db)) + for _, fx := range depoSchemaFixes { + fmt.Fprintf(&b, "/* ===== структура: %s ===== */\n%s;\nGO\n\n", fx.Name, fx.SQL) + } for _, p := range depoProcInstallOrder { body := depoProcEffective(f, p.Name) if strings.TrimSpace(body) == "" { @@ -150,6 +164,11 @@ func depoProcsInstallInto(ctx context.Context, adm, f FancyMSSQLSettings, dbName return err } defer db.Close() + for _, fx := range depoSchemaFixes { + if _, err := db.ExecContext(ctx, fx.SQL); err != nil { + return fmt.Errorf("структура таблиц (%s): %s", fx.Name, quikErrorDetail(err)) + } + } for _, p := range depoProcInstallOrder { body := depoProcEffective(f, p.Name) if strings.TrimSpace(body) == "" { diff --git a/internal/lkgateway/depoevents.go b/internal/lkgateway/depoevents.go index e74bc81..f1d7f65 100644 --- a/internal/lkgateway/depoevents.go +++ b/internal/lkgateway/depoevents.go @@ -698,16 +698,17 @@ func depoWriteHandbookCtx(pctx context.Context, rc *RuntimeConfig) error { } n++ } - // Сигнал Fancy, что справочник обновился: событие HANDBOOK в FTV_M2M_EVENTS (в той же - // транзакции, что и перезапись таблицы) — по нему джоба bj2depo может перечитать справочник. - if _, err := tx.ExecContext(ctx, fsql.QEv10); err != nil { - tx.Rollback() - return err - } if err := tx.Commit(); err != nil { return err } depoHandbookWritten = time.Now() + // Сигнал Fancy, что справочник обновился: событие HANDBOOK в FTV_M2M_EVENTS — по нему джоба bj2depo + // переносит справочник в юрлица Fancy (FTV_M2M_UPDATE_HANDBOOK). Отдельно от записи справочника: не + // записалось (в старой таблице GUID NOT NULL) — справочник всё равно в DEPO, а событие ждёт скриптов. + if _, err := db.ExecContext(ctx, fsql.QEv10); err != nil { + log.Printf("depo-events: справочник записан в FTV_M2M_HANDBOOK (%d строк), но событие HANDBOOK — нет: %v — примените скрипты DEPO (плашка «Обновление bj требует применить скрипты»)", n, err) + return nil + } log.Printf("depo-events: справочник участников записан в FTV_M2M_HANDBOOK: %d строк + событие HANDBOOK", n) return nil } diff --git a/internal/lkgateway/depotables.go b/internal/lkgateway/depotables.go index 892e945..b64e6eb 100644 --- a/internal/lkgateway/depotables.go +++ b/internal/lkgateway/depotables.go @@ -102,7 +102,7 @@ var depoTableSpecs = []depoTableSpec{ depoColComment, }, Indexes: [][]string{{"GUID"}}}, {Name: "FTV_M2M_EVENTS", Cols: []depoCol{ - depoColGUID, + depoNull("GUID", "uniqueidentifier", "uuid"), // NULL — служебные события без перевода (HANDBOOK), как в DEPO Фонтвьель с 12.10.2026 depoNull("REFERENCE", "varchar(36)", "varchar(36)"), depoColState, depoColTimeNew, depoColTimeBeg, depoColTimeEnd, depoColComment, depoNotNull("EVENT_TYPE", "varchar(64)", "varchar(64)"), diff --git a/internal/lkgateway/web/templates/layout.html b/internal/lkgateway/web/templates/layout.html index f3073a6..e160998 100644 --- a/internal/lkgateway/web/templates/layout.html +++ b/internal/lkgateway/web/templates/layout.html @@ -1,6 +1,6 @@ {{define "depoProcsBanner"}}{{if and (can "settings") depoProcsPending}}

Обновление bj требует применить скрипты в базе DEPO

-

В этой версии bj обновлены процедуры обработки M2M в DEPO ({{depoProcOrder}}). Для их установки нужны повышенные права на базу данных: введите логин и пароль администратора SQL (sysadmin, обычно sa). Они используются один раз и не сохраняются.

+

В этой версии bj обновлены процедуры обработки M2M в DEPO ({{depoProcOrder}}) и структура трансферных таблиц (FTV_M2M_EVENTS.GUID — NULL для событий справочника). Для их установки нужны повышенные права на базу данных: введите логин и пароль администратора SQL (sysadmin, обычно sa). Они используются один раз и не сохраняются.