diff --git a/internal/lkgateway/depo_procs.go b/internal/lkgateway/depo_procs.go new file mode 100644 index 0000000..32b8879 --- /dev/null +++ b/internal/lkgateway/depo_procs.go @@ -0,0 +1,239 @@ +package lkgateway + +// depo_procs.go — установка процедур обработки bj2depo (FTV_M2M_PROCESS_* и FTV_M2M_JOB) +// в базу DEPO прямо из bj: «Проверить возможности» (предпросмотр без изменений) и +// «Установить» (выполняется логином администратора SQL — разово, не сохраняется). +// Процедуры встроены в bj (internal/lkgateway/depoprocs/*.sql), порядок установки — +// WIRING → OPERATION → EVENTS → CREATE → JOB; затем GRANT EXECUTE на FTV_M2M_JOB логину bj. + +import ( + "context" + "database/sql" + "embed" + "fmt" + "log" + "net/http" + "regexp" + "strings" + "time" +) + +//go:embed depoprocs/*.sql +var depoProcFS embed.FS + +// depoProcInstallOrder — имя процедуры и файл; порядок важен для зависимостей. +var depoProcInstallOrder = []struct{ Name, File string }{ + {"FTV_M2M_PROCESS_WIRING", "depoprocs/FTV_M2M_PROCESS_WIRING.sql"}, + {"FTV_M2M_PROCESS_OPERATION", "depoprocs/FTV_M2M_PROCESS_OPERATION.sql"}, + {"FTV_M2M_PROCESS_EVENTS", "depoprocs/FTV_M2M_PROCESS_EVENTS.sql"}, + {"FTV_M2M_PROCESS_CREATE", "depoprocs/FTV_M2M_PROCESS_CREATE.sql"}, + {"FTV_M2M_JOB", "depoprocs/FTV_M2M_JOB.sql"}, +} + +var goBatchRe = regexp.MustCompile(`(?im)^\s*GO\s*$`) + +// splitSQLBatches — разбить скрипт на батчи по строкам «GO» (директива клиента, не T-SQL). +func splitSQLBatches(s string) []string { + var out []string + for _, part := range goBatchRe.Split(s, -1) { + if strings.TrimSpace(part) != "" { + out = append(out, part) + } + } + return out +} + +// depoProcFile — тело встроенной процедуры. +func depoProcFile(file string) (string, error) { + b, err := depoProcFS.ReadFile(file) + if err != nil { + return "", err + } + return string(b), nil +} + +// depoProcsCombined — единый скрипт установки (для скачивания администратору): USE, процедуры, GRANT. +func depoProcsCombined(f FancyMSSQLSettings) string { + var b strings.Builder + login := depoSetupLogin(f) + b.WriteString("/* Bridge&Join: установка процедур обработки bj2depo в базу DEPO.\n") + b.WriteString(" Порядок WIRING -> OPERATION -> EVENTS -> CREATE -> JOB. Запуск под sysadmin в SSMS.\n") + b.WriteString(" CREATE OR ALTER — повторный запуск безопасен (данные не меняются). */\n") + fmt.Fprintf(&b, "USE %s;\nGO\n\n", quoteIdent(f.DepoDB())) + for _, p := range depoProcInstallOrder { + body, err := depoProcFile(p.File) + if err != nil { + continue + } + fmt.Fprintf(&b, "/* ===== %s ===== */\n%s\nGO\n\n", p.Name, strings.TrimRight(body, "\n")) + } + fmt.Fprintf(&b, "/* Право запуска задания логину bj */\nGRANT EXECUTE ON dbo.FTV_M2M_JOB TO %s;\nGO\n", quoteIdent(login)) + return b.String() +} + +// quoteIdent — квадратные скобки для идентификатора T-SQL. +func quoteIdent(s string) string { return "[" + strings.ReplaceAll(s, "]", "]]") + "]" } + +// depoProcsPreflight — проверка возможности установки (без изменений в базе). Возвращает отчёт +// для экрана, признак «можно применять» и ошибку подключения/проверки. +func depoProcsPreflight(ctx context.Context, f FancyMSSQLSettings, adminUser, adminPass string) (report string, canApply bool, err error) { + if f.IsPostgres() { + return "", false, fmt.Errorf("установка процедур bj2depo поддержана только для MSSQL") + } + conn := f + admin := strings.TrimSpace(adminUser) + if admin != "" { + conn.User, conn.Password = admin, adminPass + } + db, err := fancyOpen(conn, f.DepoDB()) + if err != nil { + return "", false, err + } + defer db.Close() + if err := db.PingContext(ctx); err != nil { + return "", false, fmt.Errorf("подключение к базе %s логином %s: %s", f.DepoDB(), conn.User, quikErrorDetail(err)) + } + if err := depoCheckIsDepo(ctx, conn, f.DepoDB()); err != nil { + return "", false, err + } + missing := depoMissing(ctx, db, depoBj2depoProcs, "P") + login := depoSetupLogin(f) + var canCreate, sysadmin, bjUser int + _ = db.QueryRowContext(ctx, + `SELECT CAST(ISNULL(HAS_PERMS_BY_NAME(NULL,'DATABASE','CREATE PROCEDURE'),0) AS int), + CAST(ISNULL(IS_SRVROLEMEMBER('sysadmin'),0) AS int), + CASE WHEN DATABASE_PRINCIPAL_ID(@u) IS NULL THEN 0 ELSE 1 END`, + sql.Named("u", login)).Scan(&canCreate, &sysadmin, &bjUser) + canApply = canCreate == 1 || sysadmin == 1 + + var b strings.Builder + fmt.Fprintf(&b, "Сервер %s, база %s, логин %s.\n", f.Server, f.DepoDB(), conn.User) + if len(missing) == 0 { + b.WriteString("Процедуры: все 5 уже установлены (будут обновлены CREATE OR ALTER).\n") + } else { + fmt.Fprintf(&b, "Процедуры: нет %d из 5 (%s).\n", len(missing), strings.Join(missing, ", ")) + } + if canApply { + b.WriteString("Право создавать процедуры: есть.\n") + } else { + b.WriteString("Право создавать процедуры: НЕТ — введите логин администратора SQL (sysadmin, обычно sa).\n") + } + if bjUser == 1 { + fmt.Fprintf(&b, "Логин %s в базе: есть — выдам ему EXECUTE на FTV_M2M_JOB.\n", login) + } else { + fmt.Fprintf(&b, "Логин %s в базе: нет — сначала подготовьте базу (логин/таблицы), GRANT будет пропущен.\n", login) + } + b.WriteString("Будет выполнено: CREATE OR ALTER 5 процедур (WIRING→OPERATION→EVENTS→CREATE→JOB) + GRANT EXECUTE на FTV_M2M_JOB.") + return b.String(), canApply, nil +} + +// depoProcsInstall — установить процедуры логином администратора. Сначала preflight; при отсутствии +// прав — отказ без изменений. Возвращает итоговое сообщение. +func depoProcsInstall(ctx context.Context, f FancyMSSQLSettings, adminUser, adminPass string) (string, error) { + report, canApply, err := depoProcsPreflight(ctx, f, adminUser, adminPass) + if err != nil { + return "", err + } + if !canApply { + return "", fmt.Errorf("нет прав на установку. %s", report) + } + conn := f + if u := strings.TrimSpace(adminUser); u != "" { + conn.User, conn.Password = u, adminPass + } + db, err := fancyOpen(conn, f.DepoDB()) + if err != nil { + return "", err + } + defer db.Close() + for _, p := range depoProcInstallOrder { + body, err := depoProcFile(p.File) + if err != nil { + return "", fmt.Errorf("встроенный файл %s: %w", p.File, err) + } + for _, batch := range splitSQLBatches(body) { + if _, err := db.ExecContext(ctx, batch); err != nil { + return "", fmt.Errorf("установка %s: %s", p.Name, quikErrorDetail(err)) + } + } + } + msg := "установлено процедур: 5 (WIRING, OPERATION, EVENTS, CREATE, JOB)" + login := depoSetupLogin(f) + if depoLoginRe.MatchString(login) { + if _, err := db.ExecContext(ctx, "GRANT EXECUTE ON dbo.FTV_M2M_JOB TO "+quoteIdent(login)); err != nil { + msg += "; право EXECUTE логину " + login + " не выдано: " + quikErrorDetail(err) + } else { + msg += "; право EXECUTE логину " + login + " выдано" + } + } + log.Printf("depo-procs: %s", msg) + return msg, nil +} + +// ---- хендлеры ---- + +// checkFancyDepoProcs — POST /admin/setup/fancy/depo-procs/check: проверка возможностей (без изменений). +func (h *setupHandlers) checkFancyDepoProcs(w http.ResponseWriter, r *http.Request) { + if !requireDepo(w, r) { + return + } + if r.Method != http.MethodPost { + http.Error(w, "method", http.StatusMethodNotAllowed) + return + } + s := h.rc.Snapshot().Fancy + if s.Server == "" { + setupFlash(w, r, "Процедуры DEPO: сначала сохраните подключение к серверу БД") + return + } + ctx, cancel := context.WithTimeout(depoLoginForce(r.Context()), time.Minute) + defer cancel() + report, canApply, err := depoProcsPreflight(ctx, s, r.FormValue("admin_user"), r.FormValue("admin_password")) + if err != nil { + setupFlash(w, r, "Процедуры DEPO: проверка не удалась — "+err.Error()) + return + } + verdict := "можно устанавливать" + if !canApply { + verdict = "установка невозможна" + } + setupFlash(w, r, "Процедуры DEPO ("+verdict+"): "+report) +} + +// installFancyDepoProcs — POST /admin/setup/fancy/depo-procs/install: установить процедуры. +func (h *setupHandlers) installFancyDepoProcs(w http.ResponseWriter, r *http.Request) { + if !requireDepo(w, r) { + return + } + if r.Method != http.MethodPost { + http.Error(w, "method", http.StatusMethodNotAllowed) + return + } + s := h.rc.Snapshot().Fancy + if s.Server == "" { + setupFlash(w, r, "Процедуры DEPO: сначала сохраните подключение к серверу БД") + return + } + ctx, cancel := context.WithTimeout(depoLoginForce(r.Context()), 2*time.Minute) + defer cancel() + msg, err := depoProcsInstall(ctx, s, r.FormValue("admin_user"), r.FormValue("admin_password")) + if err != nil { + log.Printf("depo-procs: установка не удалась: %v", err) + setupFlash(w, r, "Процедуры DEPO: не установлены — "+err.Error()) + return + } + pmsg, pok := depoProcCheck(ctx, h.rc) + s = h.rc.Snapshot().Fancy + s.DepoProcCheck, s.DepoProcCheckOK, s.DepoProcCheckAt = pmsg, pok, time.Now() + _ = h.rc.UpdateFancy(s) + setupFlash(w, r, "Процедуры DEPO: "+msg+". Проверка обработки: "+pmsg) +} + +// fancyDepoProcsScript — GET /admin/setup/fancy/depo-procs/script.sql: единый скрипт для администратора. +func (h *setupHandlers) fancyDepoProcsScript(w http.ResponseWriter, r *http.Request) { + s := h.rc.Snapshot().Fancy + w.Header().Set("Content-Type", "application/sql; charset=utf-8") + w.Header().Set("Content-Disposition", `attachment; filename="bj-depo-procs-mssql.sql"`) + // UTF-8 BOM (0xEF 0xBB 0xBF): SSMS без него читает кириллицу в комментариях как ANSI. + _, _ = w.Write(append([]byte{0xEF, 0xBB, 0xBF}, depoProcsCombined(s)...)) +} diff --git a/internal/lkgateway/depoprocs/FTV_M2M_JOB.sql b/internal/lkgateway/depoprocs/FTV_M2M_JOB.sql new file mode 100644 index 0000000..62ad39b --- /dev/null +++ b/internal/lkgateway/depoprocs/FTV_M2M_JOB.sql @@ -0,0 +1,71 @@ +CREATE OR ALTER procedure [dbo].[FTV_M2M_JOB] + + as + set nocount on; + + declare + @ID int, + @STATE varchar(64); + + declare + @ERROR_NUMBER int, + @COMMENT varchar(MAX); + + --Новые поручения + declare cur cursor local fast_forward read_only for select ID from FTV_M2M M where M.STATE = 'TODO' order by M.TimeNew; + + open cur; + while 0 = 0 begin fetch next from cur into @ID; + if @@FETCH_STATUS <> 0 break; + + --Тут можно отправить уведомление, создать входящее сообщение и т.д. + update FTV_M2M set TimeBeg = GETDATE() where ID = @ID; + + --Главный процесс + begin try + exec FTV_M2M_PROCESS_CREATE @ID; + set @STATE = 'SUCCESS'; + end try + begin catch + set @ERROR_NUMBER = ERROR_NUMBER(); + set @COMMENT = ERROR_MESSAGE() + ' // ' + ERROR_PROCEDURE() + ' // ' + trim(str(ERROR_LINE())); + set @STATE = 'ERROR' + end catch + + --Тут можно уведомить об ошибочном статусе + update FTV_M2M set STATE = @STATE, TimeEnd = GETDATE(), COMMENT = @COMMENT where ID = @ID; + + end; + close cur; + deallocate cur; + + + --Новые события + declare cur cursor local fast_forward read_only for select ID from FTV_M2M_EVENTS ME where ME.STATE = 'TODO' order by ME.TimeNew; + + open cur; + while 0 = 0 begin fetch next from cur into @ID; + if @@FETCH_STATUS <> 0 break; + + --Тут можно отправить уведомление, создать входящее сообщение и т.д. + update FTV_M2M_EVENTS set TimeBeg = GETDATE() where ID = @ID; + + --Процесс изменения событий + begin try + exec FTV_M2M_PROCESS_EVENTS @ID; + set @STATE = 'SUCCESS'; + end try + begin catch + set @ERROR_NUMBER = ERROR_NUMBER(); + set @COMMENT = ERROR_MESSAGE() + ' // ' + ERROR_PROCEDURE() + ' // ' + trim(str(ERROR_LINE())); + set @STATE = 'ERROR' + end catch + + --Тут можно уведомить об ошибочном статусе + update FTV_M2M_EVENTS set STATE = @STATE, TimeEnd = GETDATE(), COMMENT = @COMMENT where ID = @ID; + + end; + close cur; + deallocate cur; + + /* тестовый блок удалён при переносе в репозиторий */ diff --git a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_CREATE.sql b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_CREATE.sql new file mode 100644 index 0000000..611c8e3 --- /dev/null +++ b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_CREATE.sql @@ -0,0 +1,188 @@ +CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_CREATE] (@ID int) + + /* + TODO: + Дата поручения - сейчас getdate, но можно передавать, для этого ввести пновое поле в FTV_M2M, или потом брать з события и изменять + Для входящий переводов из СПБ возможно следует дать raiserror + */ + + as + set nocount on; + + if user = 'dbo' execute as user = 'SYSDBA'; + + print 'FTV_M2M_PROCESS_CREATE'; + print @ID; + + --Создаем M2M-поручение вместе с подвалом документа + + declare + @WHOS int = 383118, + @GUID uniqueidentifier, + --шапка + @DIRECTION varchar(64), + @CONTRAGENT_M2M_CODE varchar(255), + @DEPONENT_NAME varchar(255), + @DEPONENT_DOC varchar(255), + --подвал + @REFERENCE varchar(36), + @ISIN varchar(12), + @SEC_CODE varchar(255), + @AMOUNT numeric(25, 7), + @PLACE_NUMBER varchar(255), + @LINK_NUMBER varchar(128), + @DEPO_NUMBER varchar(128), + --переменные документа + @D_CAT int, + @NUM varchar(64), + @D_DATE datetime, + @CONTRAGENT int, + @DEPONENT int, + @SHARE int, + @PLACE int, + @DEPO int, + @CLISER_ID int, + @FILER_ID int, + @FILER_NUM varchar(64), + @FILER_DATE datetime, + @DOL_ID int; + + select + @GUID = GUID, + @DIRECTION = DIRECTION, + @CONTRAGENT_M2M_CODE = CONTRAGENT_M2M_CODE, + @DEPONENT_NAME = DEPONENT_NAME, + @DEPONENT_DOC = DEPONENT_DOC + from FTV_M2M where ID = @ID; + + --1. Критические ошибки + --1.1. Неуникальный GUID + if exists (select top 1 1 from D_CLISER_M2M where DOC_GUID = @GUID) + raiserror ('Неуникальный GUID', 16, 1); + + + --1.2. Направление перевода + if @DIRECTION = 'IN' + select @D_CAT = ID from OD_DOC_CATS where SYS_NAME = 'I_CLISER_M2M_ZACH' + else if @DIRECTION = 'OUT' + select @D_CAT = ID from OD_DOC_CATS where SYS_NAME = 'I_CLISER_M2M_SPIS' + else + raiserror ('Ошибочное направление DIRECTION (должно быть IN, OUT)', 16, 1); + + + --1.3. Контрагент + select @CONTRAGENT = C.FACE + from OD_FACE_CODERS C + left join OD_FACES F on F.SELF_ID = C.CODER and F.LAST_FLAG = 1 + where F.MNEM = 'M2M' and C.CODE = @CONTRAGENT_M2M_CODE; + if @CONTRAGENT is null + raiserror ('Не найден депозитарий-контрагент', 16, 1); + + + --1.4. Депонент + select @DEPONENT = F.SELF_ID + from OD_FACES F + where F.LAST_FLAG = 1 + and replace(F.NAME, ' ', '') = replace(@DEPONENT_NAME, ' ', '') + and replace(F.DOC_SER + F.DOC_NUM, ' ', '') = replace(@DEPONENT_DOC, ' ', '') + + + --1.5. Шапка документа + exec GEN_ID 'OD_DOC_ID_GEN', 1, @CLISER_ID out; + --TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + set @D_DATE = getdate(); + + exec FU_NEXT_DOC_NUM @D_CAT, @D_DATE, null, @CLISER_ID, @NUM out, null; + + insert into OD_DOCS + (ID, NUM, PARAM, D_CAT, D_DATE, STATE, DIRECTION, WHOS, KVIT) + select + @CLISER_ID, @NUM, null, @D_CAT, @D_DATE, 0, 0, @WHOS, null; + + insert into D_CLISER_M2M + (DOC, DEPONENT, DOC_GUID, DOC_STATUS, IIS_TYPE, IIS_INN, IIS_NUM, IIS_DATE) + select + @CLISER_ID, @DEPONENT, @GUID, 0, 0, null, null, null; + + if @DIRECTION = 'IN' + insert into OD_IN_DOCS (DOC, FROM_FACE, PASS_KIND) values (@CLISER_ID, @CONTRAGENT, 8); + else if @DIRECTION = 'OUT' + insert into OD_OUT_DOCS (DOC, TO_FACE, PASS_KIND) values (@CLISER_ID, @CONTRAGENT, 8); + + --1.6. Обогащаем FTV_M2M + update FTV_M2M set + DOC = @CLISER_ID, + CONTRAGENT = @CONTRAGENT, + DEPONENT = @DEPONENT + where GUID = @GUID; + + + --1.7. Подвал документа (только в курсоре) + declare cur cursor local fast_forward read_only for + select ML.REFERENCE, ML.ISIN, ML.SEC_CODE, ML.AMOUNT, ML.PLACE_NUMBER, ML.LINK_NUMBER, ML.DEPO_NUMBER + from FTV_M2M_LINES ML + join FTV_M2M M on M.GUID = ML.GUID + where ML.GUID = @GUID and ML.STATE = 'TODO' + order by ML.ID; + + open cur; + while 0 = 0 begin fetch next from cur into @REFERENCE, @ISIN, @SEC_CODE, @AMOUNT, @PLACE_NUMBER, @LINK_NUMBER, @DEPO_NUMBER; + if @@FETCH_STATUS <> 0 break; + + --Бумага + select @SHARE = V.ID + from OD_VALUES V + left join OD_VALUE_CODERS C on C.SHARE = V.ID + left join OD_FACES F on F.SELF_ID = C.CODER and F.LAST_FLAG = 1 + where V.ISIN = @ISIN and F.MNEM = 'НДЦ' and C.CODE = @SEC_CODE; + + --Счет МХ + select @PLACE = C.ID + from OD_CLIENTS C + left join OD_CLIENTS_REC CR on CR.CLIENT = C.SELF_ID and CR.E_DATE = '9999-01-01' + where C.NUMBER like '%' + @PLACE_NUMBER + '%' and CR.LINK_NUMBER = @LINK_NUMBER; + + --Счет клиента + select @DEPO = C.ID + from OD_CLIENTS C + where C.NUMBER = @DEPO_NUMBER; + + exec GEN_ID 'OD_DOL_ID_GEN', 1, @DOL_ID out; + + insert into OD_DOLS (ID, DOC) values (@DOL_ID, @CLISER_ID); + + insert into D_CLISER_M2M_DOL (DOL, SHARE, AMOUNT, DOL_REF, PLACE, CLIENT) values (@DOL_ID, @SHARE, @AMOUNT, @REFERENCE, @PLACE, @DEPO); + + --Обогащаем FTV_M2M_LINES + update FTV_M2M_LINES set + STATE = 'SUCCESS', + DOC = @CLISER_ID, + DOL = @DOL_ID, + SHARE = @SHARE, + PLACE = @PLACE, + DEPO = @DEPO + where GUID = @GUID and REFERENCE = @REFERENCE; + + end; + close cur; + deallocate cur; + + + --1.8. Входящая запись только для списания (исходящего перевода OUT) + if @DIRECTION = 'OUT' begin + exec GEN_ID 'OD_DOC_ID_GEN', 1, @FILER_ID out; + + --TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + set @FILER_DATE = getdate(); + + exec FU_NEXT_DOC_NUM @D_CAT, @FILER_DATE, null, @FILER_ID, @FILER_NUM out, null; + + insert into OD_DOCS (ID, NUM, D_CAT, D_DATE, STATE, DIRECTION, WHOS) + values (@FILER_ID, @FILER_NUM, 255, @FILER_DATE, 2, 1, @WHOS); + + insert into D_FILER (DOC, PASS_KIND, RUBRICA, COMMENT, DOC_NUM, DOC_DATE, CORR_FACE, FUND, ACCOUNT, PLACE, ORI_DATE, CHILD_CAT) + values (@FILER_ID, 7, 173, 'M2M поручение на списание через MOEX-МОСТ', @NUM, cast(@D_DATE as date), @DEPONENT, @DEPONENT, @DEPO, @PLACE, @FILER_DATE, @D_CAT); + + --Связываем с М2М-поручением + update OD_DOCS set ID = 0, KVIT = @FILER_ID where ID = @CLISER_ID; + end; diff --git a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_EVENTS.sql b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_EVENTS.sql new file mode 100644 index 0000000..51b0b29 --- /dev/null +++ b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_EVENTS.sql @@ -0,0 +1,277 @@ +CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_EVENTS] (@ID int) + + as + set nocount on; + /* + Вынести создание операции в отдельную процедуру FTV_M2M_PROCESS_OPERATION (параметры - @GUID и @REFERENCE, но проверку параметров оставить тут). Будем возвращать @OPER_ID + */ + + if user = 'dbo' execute as user = 'SYSDBA'; + + print 'FTV_M2M_PROCESS_EVENTS'; + print @ID; + + --Обрабатываем событие по M2M-поручению + + declare + @WHOS int = 383118, + @GUID uniqueidentifier, + @REFERENCE varchar(255), + @EVENT_TYPE varchar(64), + @EVENT_DATE datetime, + @M2M_REJECT_CODE varchar, + @PARAMETERS varchar(max), + @DIRECTION varchar(64), + -- + @CONTRAGENT_FACE int, + @DEPONENT_FACE int, + @SHARE int, + @AMOUNT numeric(27, 7), + @PLACE int, + @CLIENT int, + @FACE int, + @CLISER_ID int, + @DOL_ID int, + -- + @D_CAT int, + @NUM varchar(64), + @D_DATE datetime, + @OPER_ID int, + @DD_DATE datetime, + @DD_NUM varchar(64); + + + -- FTV_M2M_EVENTS.REFERENCE может быть пустой, в этом случае событие относится ко всему М2М-поручению + select + @GUID = ME.GUID, + @REFERENCE = ME.REFERENCE, + @EVENT_TYPE = ME.EVENT_TYPE, + @EVENT_DATE = ME.EVENT_DATE, + @M2M_REJECT_CODE = ME.M2M_REJECT_CODE, + @DIRECTION = M.DIRECTION + from FTV_M2M_EVENTS ME + left join FTV_M2M M on M.GUID = ME.GUID + where ME.ID = @ID; + + if @REFERENCE is null begin + --Не все события могут быть применены ко всему М2М-поручению + if not (@EVENT_TYPE in ('BJ_RECEIVED', 'BJ_SENT', 'BJ_ORDER_SENT', 'BJ_ORDER_ACCEPTED', 'BJ_EXECUTED') or @EVENT_TYPE like 'BJ_QUIK_%') + raiserror ('Событие этого типа не может быть указано без REFERENCE', 16, 1); + + select + @REFERENCE = ME.REFERENCE, + @CLISER_ID = H.DOC, + @DOL_ID = F.DOL, + @DD_DATE = cast(D.D_DATE as date), + @DD_NUM = D.NUM, + @SHARE = F.SHARE, + @AMOUNT = F.AMOUNT, + @PLACE = F.PLACE, + @CLIENT = F.CLIENT, + @FACE = H.DEPONENT + from FTV_M2M_EVENTS ME + left join FTV_M2M_LINES ML on ML.GUID = ME.GUID and ML.REFERENCE = ME.REFERENCE + left join FTV_M2M M on M.GUID = ME.GUID + left join D_CLISER_M2M_DOL F on F.DOL_REF = ME.REFERENCE + left join D_CLISER_M2M H on H.DOC_GUID = ME.GUID + left join OD_DOCS D on D.ID = H.DOC + where ME.ID = @ID; + end + else begin + select + @REFERENCE = ME.REFERENCE, + @CLISER_ID = H.DOC, + @DOL_ID = F.DOL, + @DD_DATE = cast(D.D_DATE as date), + @DD_NUM = D.NUM, + @SHARE = F.SHARE, + @AMOUNT = F.AMOUNT, + @PLACE = F.PLACE, + @CLIENT = F.CLIENT, + @FACE = H.DEPONENT + from FTV_M2M_EVENTS ME + left join FTV_M2M_LINES ML on ML.GUID = ME.GUID and ML.REFERENCE = ME.REFERENCE + left join FTV_M2M M on M.GUID = ME.GUID + left join D_CLISER_M2M_DOL F on F.DOL_REF = ME.REFERENCE + left join D_CLISER_M2M H on H.DOC_GUID = ME.GUID + left join OD_DOCS D on D.ID = H.DOC + where ME.ID = @ID; + + --Критические ошибки + if @DOL_ID is null + raiserror ('Не найдена строка M2M-поручение по GUID + REFERENCE', 16, 1); + end; + + + --Пишем в признаки документа + insert into OD_INVALIDS (DOC, STATUS, COMMENT, DO_ING) + values ( + @CLISER_ID, + 0, + 'Обработано событие: ' + FORMAT(@EVENT_DATE, 'dd.MM.yyyy HH:mm:ss') + ' - ' + @EVENT_TYPE + coalesce (' (референс - ' + @REFERENCE + ')', '') + coalesce (' (парамерты - ' + @PARAMETERS + ')', ''), + 'Время начала обработки: ' + FORMAT(GETDATE(), 'dd.MM.yyyy HH:mm:ss') + ) + + print @EVENT_TYPE; + + --ОБРАБОТКА КАЖДОГО ТИПА СОБЫТИЯ + + if @EVENT_TYPE = 'BJ_RECEIVED' and @DIRECTION = 'OUT' begin + update OD_DOCS set ID = 0, STATE = 1 where ID = @CLISER_ID; --START - Начало обработки (зарегистрирован) + end + + else + if @EVENT_TYPE = 'BJ_SENT' and @DIRECTION = 'IN' begin + update OD_DOCS set ID = 0, STATE = 1 where ID = @CLISER_ID; --START - Начало обработки (зарегистрирован) + end + + else + if @EVENT_TYPE = 'BJ_DECISION_REJECT' and @DIRECTION = 'IN' begin + --M2M_STATUS = 10 TODO!!!!!!!!!!!!!!!!! + update D_CLISER_M2M_DOL set M2M_STATUS = 10, M2M_TEXT = '???' where DOL = @DOL_ID; + --только если отказ по всем строкам подвала документа + if not exists (select top 1 DOL from D_CLISER_M2M_DOL F left join OD_DOLS L on L.ID = F.DOL where L.DOC = @CLISER_ID and (M2M_STATUS is null or M2M_TEXT is null)) begin + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT - Отмена обработки + end; + end + + else + if @EVENT_TYPE = 'BJ_CP_REJECT' and @DIRECTION = 'OUT' begin + --M2M_STATUS = 10 TODO!!!!!!!!!!!!!!!!! + update D_CLISER_M2M_DOL set M2M_STATUS = 10, M2M_TEXT = '???' where DOL = @DOL_ID; + --только если отказ по всем строкам подвала документа + --TODO зачем проверять все строки подвала, если мы не будем делать многострочные исходящие??? + if not exists (select top 1 DOL from D_CLISER_M2M_DOL F left join OD_DOLS L on L.ID = F.DOL where L.DOC = @CLISER_ID and (M2M_STATUS is null or M2M_TEXT is null)) begin + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT - Отмена обработки + end; + end + + else + --TODO что делать если мы проставили статус не по всем строкам документа?? + if @EVENT_TYPE = 'BJ_DECISION_CONFIRM' and @DIRECTION = 'IN' begin + update OD_DOCS set ID = 0, STATE = 1 where ID = @CLISER_ID; --START - Начало обработки (зарегистрирован) --ОНО И ТАК УЖЕ ДОЛЖНО БЫТЬ В ЭТОМ СОСТОЯНИИ!!! + end + + else + --TODO что делать если контрагент проставил статус не по всем строкам документа?? + if @EVENT_TYPE = 'BJ_CP_CONFIRM' and @DIRECTION = 'OUT' begin + update OD_DOCS set ID = 0, STATE = 1 where ID = @CLISER_ID; --START - Начало обработки (зарегистрирован) --ОНО И ТАК УЖЕ ДОЛЖНО БЫТЬ В ЭТОМ СОСТОЯНИИ!!! + end + + else + if @EVENT_TYPE = 'BJ_SERVICE_ERROR' or @EVENT_TYPE = 'BJ_CANCELLED' begin + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT - Отмена обработки + end + + else + if @EVENT_TYPE = 'BJ_ORDER_ACCEPTED' begin + -----TODO exec FTV_M2M_PROCESS_OPERATION @GUID, @REFERENCE, @EVENT_DATE, @OPER_ID out; + + --Направление + select @D_CAT = DC.ID + from OD_DOC_CATS DC + where DC.SYS_NAME = case when @DIRECTION = 'IN' then 'OP_INV_ZACH' else 'OP_INV_SPIS' end; + + set @D_DATE = @EVENT_DATE; + + exec GEN_ID 'OD_DOC_ID_GEN', 1, @OPER_ID out; + exec FU_NEXT_DOC_NUM @D_CAT, @D_DATE, null, @OPER_ID, @NUM out, @D_DATE out; + + insert into OD_DOCS (ID, NUM, PARAM, D_CAT, D_DATE, STATE, DIRECTION, WHOS, KVIT) + values (@OPER_ID, @NUM, null, @D_CAT, @D_DATE, 0, 0, @WHOS, @CLISER_ID); + + if @DIRECTION = 'IN' begin + --порядок полей - по форме документа (сверху вниз) + insert into U_OP_INV_ZACH + ( + DOC, + DD_TYPE, + DD_DATE, DD_NUM, + SHARE, AMOUNT, BLANKS, + PLACE, + D_NUM, + DEPO, + K_NUM, + MARKET, + CONDITION, IS_REG, TAX_R, + B_TYPE, + B_DATE, B_NUM, + WIR_DATE, NOTIFY_DATE, REG_DATE, + IS_BLOCK, + FROM_FACE, + REJECT_REASON, + COMMENT + ) + values + ( + @OPER_ID, + 1 /*Клиентское*/, + @DD_DATE, @DD_NUM, + @SHARE, @AMOUNT, null, + @PLACE, + 314, /*98015 - 0 - Ценные бумаги и цифровые активы на хранении в других депозитариях (НОСТРО депо расчетный)*/ + @CLIENT, + 836, /*98070 - 4 - Ценные бумаги и цифровые активы на торгах*/ + 8106, /*ММВБ - ПАО Московская Биржа*/ + null, null, null, + 31, /*Отчет депозитария*/ + @EVENT_DATE, 'Вопрос, что тут пишем', + @EVENT_DATE, @EVENT_DATE, @EVENT_DATE, --Берем из BJ + 0, + @FACE, + null, --А есди это отмена?? + 'Перевод M2M (без поручения), GUID ' + cast(@GUID as varchar(36)) + ', референс ' + @REFERENCE + ); + end + + else + if @DIRECTION = 'OUT' begin + insert into U_OP_INV_SPIS + ( + DOC, + DD_TYPE, + DD_DATE, DD_NUM, + SHARE, AMOUNT, BLANKS, + PLACE, + D_NUM, + DEPO, + K_NUM, + MARKET, + OLD_CONDITIONS, IS_REG, TAX_R, + B_TYPE, + B_DATE, B_NUM, + WIR_DATE, NOTIFY_DATE, REG_DATE, + IS_BLOCK, + FROM_FACE, + REJECT_REASON, + COMMENT + ) + values + ( + @OPER_ID, + 1 /*Клиентское*/, + @DD_DATE, @DD_NUM, + @SHARE, @AMOUNT, null, + @PLACE, + 314, /*98015 - 0 - Ценные бумаги и цифровые активы на хранении в других депозитариях (НОСТРО депо расчетный)*/ + @CLIENT, + 836, /*98070 - 4 - Ценные бумаги и цифровые активы на торгах*/ + 8106, /*ММВБ - ПАО Московская Биржа*/ + null, null, null, + 31, /*Отчет депозитария*/ + @EVENT_DATE, 'Вопрос, что тут пишем', + @EVENT_DATE, @EVENT_DATE, @EVENT_DATE, --Берем из BJ + 0, + @FACE, + null, --А есди это отмена?? + 'Отчет НКО АО НРД [номер, дата]. Перевод M2M, GUID ' + cast(@GUID as varchar(36)) + ', референс ' + @REFERENCE + ); + end; + + --И сразу проводим + exec FTV_M2M_PROCESS_WIRING @OPER_ID; + + end + else if @EVENT_TYPE = 'CREATE_WIRING' begin + print 'CREATE_WIRING' + end; diff --git a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_OPERATION.sql b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_OPERATION.sql new file mode 100644 index 0000000..4e8892c --- /dev/null +++ b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_OPERATION.sql @@ -0,0 +1,165 @@ +CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_OPERATION] @GUID uniqueidentifier, @REFERENCE varchar(255), @OPER_DATE datetime, @OPER_ID int output + + /* + Создает операцию, возвращает OPER_ID созданной операции + Параметры нацелены прежде всего на строки уже созданного М2М-поручения D_CLISER_M2M_DOL, а не на буферные таблицы (к ним больше не обращаемся) + Все проверки идут до вызова, но элементарные проверки можно сделать и тут. Или дать raiserror + Мы существенно разгружаем FTV_M2M_PROCESS_EVENTS + + declare @OPER_ID int; + exec FTV_M2M_PROCESS_OPERATION @GUID = 'BAE1FA60-EB0A-4FEE-B12C-018D1EAFCBD2', @REFERENCE = 'M2M0917165643657', @OPER_DATE = '20260922', @OPER_ID = @OPER_ID out; + select @OPER_ID; + + */ + + as + set nocount on; + + if user = 'dbo' execute as user = 'SYSDBA'; + + print 'FTV_M2M_PROCESS_OPERATION' + ' GUID = ' + cast(@GUID as varchar(36)) + ', REFERENCE = ' + @REFERENCE; + + declare + @WHOS int = 383118, + @CLISER_ID int, + @CLISER_NUM varchar(64), + @CLISER_DATE datetime, + @DIRECTION varchar(64), + @DD_DATE datetime, + @DD_NUM varchar(64), + @SHARE int, + @AMOUNT numeric(27, 7), + @CLIENT int, + @FACE int, + @PLACE int, + @D_CAT int, + @NUM varchar(64); + + select + @CLISER_ID = H.DOC, + @CLISER_NUM = D.NUM, + @CLISER_DATE= D.D_DATE, + @DIRECTION = case + when DC.SYS_NAME = 'I_CLISER_M2M_ZACH' then 'IN' + when DC.SYS_NAME = 'I_CLISER_M2M_SPIS' then 'OUT' + end, + @DD_DATE = cast(D.D_DATE as date), + @DD_NUM = D.NUM, + @SHARE = F.SHARE, + @AMOUNT = F.AMOUNT, + @CLIENT = F.CLIENT, + @FACE = H.DEPONENT, + @PLACE = F.PLACE + from D_CLISER_M2M_DOL F + left join OD_DOLS L on L.ID = F.DOL + left join OD_DOCS D on D.ID = L.DOC + left join D_CLISER_M2M H on H.DOC = D.ID + left join OD_DOC_CATS DC on DC.ID = D.D_CAT + where H.DOC_GUID = @GUID and F.DOL_REF = @REFERENCE; + + --Элеметарные проверки + if @CLISER_ID is null + raiserror ('Не найдено M2M-поручение по GUID + REFERENCE', 16, 1); + + --Направление + select @D_CAT = DC.ID + from OD_DOC_CATS DC + where DC.SYS_NAME = case when @DIRECTION = 'IN' then 'OP_INV_ZACH' else 'OP_INV_SPIS' end; + + --ID и номер операции + exec GEN_ID 'OD_DOC_ID_GEN', 1, @OPER_ID out; + exec FU_NEXT_DOC_NUM @D_CAT, @OPER_DATE, null, @OPER_ID, @NUM out, null; + + --Создаем документ + insert into OD_DOCS (ID, NUM, PARAM, D_CAT, D_DATE, STATE, DIRECTION, WHOS, KVIT) + values (@OPER_ID, @NUM, null, @D_CAT, @OPER_DATE, 0, 0, @WHOS, @CLISER_ID); + + if @DIRECTION = 'IN' begin + insert into U_OP_INV_ZACH + ( + DOC, + DD_TYPE, + DD_DATE, DD_NUM, + SHARE, AMOUNT, BLANKS, + PLACE, + D_NUM, + DEPO, + K_NUM, + MARKET, + CONDITION, IS_REG, TAX_R, + B_TYPE, + B_DATE, B_NUM, + WIR_DATE, NOTIFY_DATE, REG_DATE, + IS_BLOCK, + FROM_FACE, + REJECT_REASON, + COMMENT + ) + values + ( + @OPER_ID, + 1 /*Клиентское*/, + @DD_DATE, @DD_NUM, + @SHARE, @AMOUNT, null, + @PLACE, + 314, /*98015 - 0 - Ценные бумаги и цифровые активы на хранении в других депозитариях (НОСТРО депо расчетный)*/ + @CLIENT, + 836, /*98070 - 4 - Ценные бумаги и цифровые активы на торгах*/ + 8106, /*ММВБ - ПАО Московская Биржа*/ + null, null, null, + 31, /*Отчет депозитария*/ + @CLISER_DATE, @CLISER_NUM, + @OPER_DATE, @OPER_DATE, @OPER_DATE, + 0, + @FACE, + null, + 'Перевод M2M (без поручения), GUID ' + cast(@GUID as varchar(36)) + ', референс ' + @REFERENCE + ); + end + + else + if @DIRECTION = 'OUT' begin + insert into U_OP_INV_SPIS + ( + DOC, + DD_TYPE, + DD_DATE, DD_NUM, + SHARE, AMOUNT, BLANKS, + PLACE, + D_NUM, + DEPO, + K_NUM, + MARKET, + OLD_CONDITIONS, IS_REG, TAX_R, + B_TYPE, + B_DATE, B_NUM, + WIR_DATE, NOTIFY_DATE, REG_DATE, + IS_BLOCK, + FROM_FACE, + REJECT_REASON, + COMMENT + ) + values + ( + @OPER_ID, + 1 /*Клиентское*/, + @DD_DATE, @DD_NUM, + @SHARE, @AMOUNT, null, + @PLACE, + 314, /*98015 - 0 - Ценные бумаги и цифровые активы на хранении в других депозитариях (НОСТРО депо расчетный)*/ + @CLIENT, + 836, /*98070 - 4 - Ценные бумаги и цифровые активы на торгах*/ + 8106, /*ММВБ - ПАО Московская Биржа*/ + null, null, null, + 31, /*Отчет депозитария*/ + @CLISER_DATE, @CLISER_NUM, + @OPER_DATE, @OPER_DATE, @OPER_DATE, + 0, + @FACE, + null, + 'Отчет НКО АО НРД [номер, дата]. Перевод M2M, GUID ' + cast(@GUID as varchar(36)) + ', референс ' + @REFERENCE + ); + end; + + --И сразу проводим + exec FTV_M2M_PROCESS_WIRING @OPER_ID; diff --git a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_WIRING.sql b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_WIRING.sql new file mode 100644 index 0000000..d53493b --- /dev/null +++ b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_WIRING.sql @@ -0,0 +1,172 @@ +CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_WIRING] (@OPER_ID int) + + as + set nocount on; + + /* + --Выполняет директиву "Обраотать" для документа "Зачисление" или "Списание" + --Все значения переменных берем только из самого документа, М2М-поручения и трансфертные таблицы тут не используются + + exec FTV_M2M_PROCESS_WIRING 75069916; + */ + + if user = 'dbo' execute as user = 'SYSDBA'; + declare @USER int = 84; + + declare + @DIRECTION varchar(3), + @D_CAT int, + @SHARE int, + @PLACE int, + @DEPO int, + @AMOUNT numeric(22,7), + @COMMENT varchar(255), + @B_TYPE int, + @B_NUM varchar(255), + @B_DATE datetime, + @WIR_DATE datetime, + @D_NUM int, + @K_NUM int, + @MARKET int, + @NAME varchar(255), + @TEXT_B_TYPE varchar(255), + @WIR_ID int; + + declare + @D_REG_1 int, @K_REG_1 int, + @D_REG_2 int, @K_REG_2 int, + @D_REG_3 int, @K_REG_3 int, + @D_REG_4 int, @K_REG_4 int, + @D_REG_5 int, @K_REG_5 int, + @D_REG_6 int, @K_REG_6 int; + + declare + @DIR_ID int, + @OUT_STATE int, + @STEP_ID int; + + + --НАПРАВЛЕНИЕ + if exists (select top 1 DOC from U_OP_INV_ZACH where DOC = @OPER_ID) set @DIRECTION = 'IN'; + else + if exists(select top 1 DOC from U_OP_INV_SPIS where DOC = @OPER_ID) set @DIRECTION = 'OUT'; + else begin + print 'Не найден документ ID = ' + trim(str(@OPER_ID)); + return; --TODO исключительная ситуация + end; + + + --ПРОВЕРКИ, ЧТО ДОКУМЕНТ МОЖНО ПРОВОДИТЬ + --Состояние документа + --Связь с M2M + --TODO + + + --ЗНАЧЕНИЯ ПЕРЕМЕННЫХ + if @DIRECTION = 'IN' begin + --Смотрим шапку операции + select + @D_CAT = D.D_CAT, + @D_NUM = H.D_NUM, + @K_NUM = H.K_NUM, + @B_TYPE = H.B_TYPE, + @B_NUM = H.B_NUM, + @B_DATE = H.B_DATE, + @SHARE = H.SHARE, + @AMOUNT = H.AMOUNT, + @PLACE = H.PLACE, + @DEPO = H.DEPO, + @MARKET = H.MARKET, + @WIR_DATE = H.WIR_DATE, + @NAME = 'Зачисление' + from OD_DOCS D + left join U_OP_INV_ZACH H ON H.DOC = D.ID + where D.ID = @OPER_ID; + + --D_REG + select + @D_REG_1 = C.SELF_ID, + @D_REG_2 = C.FACE, + @D_REG_3 = 0, + @D_REG_4 = 0, + @D_REG_5 = 0, + @D_REG_6 = @PLACE + from OD_CLIENTS C where C.ID = @PLACE; + + --K_REG + select + @K_REG_1 = C.SELF_ID, + @K_REG_2 = @MARKET, + @K_REG_3 = 0, + @K_REG_4 = @D_REG_1, + @K_REG_5 = @PLACE, + @K_REG_6 = @DEPO + from OD_CLIENTS C where C.ID = @DEPO; + end + else if @DIRECTION = 'OUT' begin + --Смотрим шапку операции + select + @D_CAT = D.D_CAT, + @D_NUM = H.K_NUM, --реверс + @K_NUM = H.D_NUM, --реверс + @B_TYPE = H.B_TYPE, + @B_NUM = H.B_NUM, + @B_DATE = H.B_DATE, + @SHARE = H.SHARE, + @AMOUNT = H.AMOUNT, + @PLACE = H.PLACE, + @DEPO = H.DEPO, + @MARKET = H.MARKET, + @WIR_DATE = H.WIR_DATE, + @NAME = 'Списание' + from OD_DOCS D + left join U_OP_INV_SPIS H ON H.DOC = D.ID + where D.ID = @OPER_ID; + + --K_REG + select + @K_REG_1 = C.SELF_ID, + @K_REG_2 = C.FACE, + @K_REG_3 = 0, + @K_REG_4 = 0, + @K_REG_5 = 0, + @K_REG_6 = @PLACE + from OD_CLIENTS C where C.ID = @PLACE; + + --D_REG + select + @D_REG_1 = C.SELF_ID, + @D_REG_2 = @MARKET, + @D_REG_3 = 0, + @D_REG_4 = @K_REG_1, + @D_REG_5 = @PLACE, + @D_REG_6 = @DEPO + from OD_CLIENTS C where C.ID = @DEPO; + end; + + + --ДОПОЛНИТЕЛЬНЫЕ ПАРАМЕТРЫ + select @TEXT_B_TYPE = NAME from OD_SYS_TABS where CODE = 'DEPO96_DCLA' and NUM = @B_TYPE; + set @COMMENT = FORMATMESSAGE('%s; %s N%s от %s', @COMMENT, @TEXT_B_TYPE, @B_NUM, convert(varchar, @B_DATE, 104)); + + + --ДИРЕКТИВА + select @DIR_ID = ID, @OUT_STATE = OUT_STATE from OD_STEP_TYPES where SYS_NAME = 'PROCESS' and D_CAT = @D_CAT; + exec GEN_ID 'OD_STEPS_ID_GEN', 1, @STEP_ID out; + insert into OD_STEPS (ID, DOC, S_TYPE, S_DATE, ERR_CODE, OUT_STATE, OPER) values (@STEP_ID, @OPER_ID, @DIR_ID, GETDATE(), 0, @OUT_STATE, @USER); + --update OD_STEPS set OPER = @USER where ID = @STEP_ID; может и не пригодится + + + --ПРОВОДКА + exec OD_PR_INS_WIRS + null, 4, @WIR_DATE, @NAME, @COMMENT, @AMOUNT, @AMOUNT, null, 0, 0, null, @STEP_ID, null, @USER, 'F', + @D_NUM, @SHARE, @D_REG_1, @D_REG_2, @D_REG_3, @D_REG_4, @D_REG_5, @D_REG_6, --дебет + @K_NUM, @SHARE, @K_REG_1, @K_REG_2, @K_REG_3, @K_REG_4, @K_REG_5, @K_REG_6, --кредит + @WIR_ID out, null, null, null; --return + + + --СОСТОЯНИЕ ДОКУМЕНТА + update OD_DOCS set STATE = @OUT_STATE where ID = @OPER_ID; + + --select @WIR_ID; + --select * from OD_WIRING where ID = @WIR_ID; diff --git a/internal/lkgateway/fancydb_handlers.go b/internal/lkgateway/fancydb_handlers.go index e341b17..cde4f20 100644 --- a/internal/lkgateway/fancydb_handlers.go +++ b/internal/lkgateway/fancydb_handlers.go @@ -26,6 +26,9 @@ func (h *setupHandlers) registerFancy(mux *http.ServeMux) { mux.HandleFunc("/admin/setup/fancy/depo-tables/script.sql", h.fancyDepoTablesScript) mux.HandleFunc("/admin/setup/fancy/depo-login/script.sql", h.fancyDepoLoginScript) mux.HandleFunc("/admin/setup/fancy/depo-job/script.sql", h.fancyDepoJobScript) + mux.HandleFunc("/admin/setup/fancy/depo-procs/check", h.checkFancyDepoProcs) + mux.HandleFunc("/admin/setup/fancy/depo-procs/install", h.installFancyDepoProcs) + mux.HandleFunc("/admin/setup/fancy/depo-procs/script.sql", h.fancyDepoProcsScript) mux.HandleFunc("/admin/fancy-queue", h.fancyQueue) mux.HandleFunc("/admin/fancy-queue/requeue", h.fancyQueueRequeue) mux.HandleFunc("/admin/fancy-queue/dismiss", h.fancyQueueDismiss) diff --git a/internal/lkgateway/web/templates/part_fancy.html b/internal/lkgateway/web/templates/part_fancy.html index ee4c934..6a31b49 100644 --- a/internal/lkgateway/web/templates/part_fancy.html +++ b/internal/lkgateway/web/templates/part_fancy.html @@ -113,6 +113,25 @@ {{if and (eq .Settings.Fancy.DepoJobMode "bj") .Settings.Fancy.DepoJobLast}}
Последний вызов процедуры — {{.Settings.Fancy.DepoJobLast}}
{{end}} {{end}} + +Процедуры FTV_M2M_PROCESS_* и FTV_M2M_JOB встроены в bj. Сначала «Проверить возможности» (ничего не меняет), затем «Установить» — bj выполнит их в базе DEPO в порядке WIRING→OPERATION→EVENTS→CREATE→JOB и выдаст логину bj право запуска.
Скачать скрипт bj-depo-procs-mssql.sql — для ручной установки администратором в SSMS
+ {{if .Settings.Fancy.DepoProcCheck}}{{if .Settings.Fancy.DepoProcCheckOK}}✓{{else}}⚠{{end}} {{.Settings.Fancy.DepoProcCheck}}
{{end}} +{{.Title}}: {{if .Version}}{{.Version}}{{else}}не определена{{end}}{{with .Detail}} · {{.}}{{end}}{{with .Err}} · {{.}}{{end}}
{{end}}{{end}}