DEPO: установка процедур bj2depo из bj (проверка возможностей + применение)
Процедуры FTV_M2M_PROCESS_* и FTV_M2M_JOB встроены в bj (depoprocs/*.sql). В разделе «Учёт DEPO» карточка «Процедуры обработки bj2depo»: - «Проверить возможности» — подключение, это ли база DEPO, какие процедуры установлены, есть ли право CREATE PROCEDURE и логин bj в базе (ничего не меняет); - «Установить» — логином администратора SQL (разово, не сохраняется) выполняет CREATE OR ALTER в порядке WIRING→OPERATION→EVENTS→CREATE→JOB и GRANT EXECUTE на FTV_M2M_JOB логину bj; без прав — отказ без изменений; - скачивание единого скрипта для ручной установки в SSMS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
This commit is contained in:
@@ -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)...))
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/* тестовый блок удалён при переносе в репозиторий */
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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)
|
||||
|
||||
@@ -113,6 +113,25 @@
|
||||
{{if and (eq .Settings.Fancy.DepoJobMode "bj") .Settings.Fancy.DepoJobLast}}<p class="muted" style="font-size:12px;margin-top:6px">Последний вызов процедуры — {{.Settings.Fancy.DepoJobLast}}</p>{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="card" id="sec-fancy-depo-procs">
|
||||
<h2><span class="dot {{if .Settings.Fancy.DepoProcCheckOK}}ok{{else}}warn{{end}}"></span>Процедуры обработки bj2depo</h2>
|
||||
<p class="muted">Процедуры <code>FTV_M2M_PROCESS_*</code> и <code>FTV_M2M_JOB</code> встроены в bj. Сначала «Проверить возможности» (ничего не меняет), затем «Установить» — bj выполнит их в базе DEPO в порядке WIRING→OPERATION→EVENTS→CREATE→JOB и выдаст логину bj право запуска.</p>
|
||||
<form method="post" style="display:grid;gap:10px;max-width:720px">
|
||||
<input type="hidden" name="section" value="sec-fancy-depo-procs">
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:10px">
|
||||
<label>Логин администратора SQL <input type="text" name="admin_user" autocomplete="off" placeholder="sa" style="width:100%"></label>
|
||||
<label>Пароль <input type="password" name="admin_password" autocomplete="new-password" style="width:100%"></label>
|
||||
</div>
|
||||
<p class="muted" style="font-size:12px;margin:0">Логин sysadmin (например sa) вводится один раз и не сохраняется. Пусто — bj попробует своим логином (прав на создание процедур у него обычно нет).</p>
|
||||
<div style="display:flex;gap:10px;flex-wrap:wrap">
|
||||
<button type="submit" class="btn" formaction="/admin/setup/fancy/depo-procs/check">Проверить возможности</button>
|
||||
<button type="submit" class="btn btn-ok" formaction="/admin/setup/fancy/depo-procs/install" onclick="return confirm('Установить процедуры обработки в базу DEPO {{.Settings.Fancy.DepoDB}}?')">⚙ Установить процедуры</button>
|
||||
</div>
|
||||
</form>
|
||||
<p style="margin-top:8px"><a href="/admin/setup/fancy/depo-procs/script.sql">Скачать скрипт bj-depo-procs-mssql.sql</a> <span class="muted" style="font-size:12px">— для ручной установки администратором в SSMS</span></p>
|
||||
{{if .Settings.Fancy.DepoProcCheck}}<p style="margin-top:6px;font-size:13px;{{if .Settings.Fancy.DepoProcCheckOK}}color:var(--ok){{else}}color:var(--warn){{end}}">{{if .Settings.Fancy.DepoProcCheckOK}}✓{{else}}⚠{{end}} {{.Settings.Fancy.DepoProcCheck}}</p>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{define "verline"}}{{if .Title}}<p class="muted" style="font-size:12.5px;margin:-6px 0 12px">{{.Title}}: {{if .Version}}<strong>{{.Version}}</strong>{{else}}не определена{{end}}{{with .Detail}} · {{.}}{{end}}{{with .Err}} · <span style="color:var(--err)">{{.}}</span>{{end}}</p>{{end}}{{end}}
|
||||
|
||||
Reference in New Issue
Block a user