diff --git a/deploy/depo/fancy-m2m/FTV_M2M_JOB.sql b/deploy/depo/fancy-m2m/FTV_M2M_JOB.sql index 62ad39b..fddcde9 100644 --- a/deploy/depo/fancy-m2m/FTV_M2M_JOB.sql +++ b/deploy/depo/fancy-m2m/FTV_M2M_JOB.sql @@ -1,71 +1,120 @@ 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; - - /* тестовый блок удалён при переносе в репозиторий */ + +--grant execute on FTV_M2M_JOB to public; +--exec FTV_M2M_JOB; + +as +set nocount on; + +declare + @ID int, + @STATE varchar(64), + @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; + + --Процесс создания М2М-поручения + begin try + set @COMMENT = null; + 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 + set @COMMENT = null; + 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 + + --Тут также можно уведомить об ошибочном статусе (вне транзакции) + if @COMMENT is not null + update FTV_M2M_EVENTS set STATE = @STATE, TimeEnd = GETDATE(),COMMENT = @COMMENT where ID = @ID; + else + update FTV_M2M_EVENTS set STATE = @STATE, TimeEnd = GETDATE() where ID = @ID; + +end; +close cur; +deallocate cur; + +/* +НИЖЕ - ПРИМЕР ДЛЯ ТЕСТИРОВАНИЯ + +declare @GUID uniqueidentifier; +set @GUID = NEWID(); + +INSERT INTO [dbo].[FTV_M2M] ([GUID], [CONTRAGENT_M2M_CODE], [DEPONENT_NAME], [DEPONENT_DOC], [DIRECTION]) +VALUES (@GUID, 'MC0034900000', 'Абабков Александр Владимирович', '4508 147055', 'OUT'); + +--Замечание - списание возможно только по одной строке подвала!! +INSERT INTO [dbo].[FTV_M2M_LINES] ([GUID], [REFERENCE], [ISIN], [SEC_CODE], [AMOUNT], [PLACE_NUMBER], [LINK_NUMBER], [DEPO_NUMBER]) +VALUES (@GUID, 'M2MREF_11', 'RU000A0JVHH1', 'RU000A0JVHH1', 11, '36MC0413600000F00', 'HL171004001C', 'ВТНКЦ00000060'); + +--INSERT INTO [dbo].[FTV_M2M_LINES] ([GUID], [REFERENCE], [ISIN], [SEC_CODE], [AMOUNT], [PLACE_NUMBER], [LINK_NUMBER], [DEPO_NUMBER]) +--VALUES (@GUID, 'M2MREF_22', 'RU0009029540', 'SBER/03', 12, '36MC0413600000F00', 'HL171004001C', 'ВТНКЦ00000060'); + +exec FTV_M2M_JOB; + +--select COMMENT, * from [dbo].[FTV_M2M] +--select COMMENT, * from [dbo].[FTV_M2M_LINES] +--select COMMENT, * from [dbo].[FTV_M2M_EVENTS] +-------------------------- + +--set @GUID = '' +INSERT INTO [dbo].[FTV_M2M_EVENTS] (GUID, REFERENCE, EVENT_TYPE, EVENT_DATE, M2M_REJECT_CODE) + VALUES (@GUID, 'M2MREF_11', 'BJ_ORDER_ACCEPTED', getdate()); + +exec FTV_M2M_JOB; +select COMMENT, * from [dbo].[FTV_M2M] +select COMMENT, * from [dbo].[FTV_M2M_LINES] +select COMMENT, * from [dbo].[FTV_M2M_EVENTS] + + + +Ошибка преобразования значения varchar "IN" в тип данных int. // FTV_M2M_PROCESS_CREATE // 22 +Не удалось вставить значение NULL в столбец "D_CAT", таблицы "UPD_DE_DATA.dbo.OD_DOCS"; в столбце запрещены значения NULL. Ошибка в INSERT. // propagate // 4 +Дублирование номера внутреннего или исходящего документа (M2M поручение на зачисление от 05.09.2026: No TEST M2M) // propagate // 4 +Обнаружена ошибка: деление на ноль. // FTV_M2M_PROCESS_CREATE // 118 +Ошибка при преобразовании типа данных nvarchar к datetime. // FU_NEXT_DOC_NUM // 0 + + +*/ diff --git a/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_CREATE.sql b/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_CREATE.sql index 611c8e3..0d93703 100644 --- a/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_CREATE.sql +++ b/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_CREATE.sql @@ -1,188 +1,209 @@ CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_CREATE] (@ID int) + +--grant execute on FTV_M2M_PROCESS_CREATE to public; - /* - TODO: - Дата поручения - сейчас getdate, но можно передавать, для этого ввести пновое поле в FTV_M2M, или потом брать з события и изменять - Для входящий переводов из СПБ возможно следует дать raiserror - */ +/* +TODO: +Дата поручения - сейчас getdate, но можно передавать, для этого ввести пновое поле в FTV_M2M, или потом брать из события и изменять +Для входящих переводов из СПБ возможно следует дать raiserror (но это должен делать bj) +*/ - as - set nocount on; +as +set nocount on; - if user = 'dbo' execute as user = 'SYSDBA'; +if user = 'dbo' execute as user = 'SYSDBA'; - print 'FTV_M2M_PROCESS_CREATE'; - print @ID; +print 'FTV_M2M_PROCESS_CREATE'; +print @ID; - --Создаем M2M-поручение вместе с подвалом документа +--Создаем 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; +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; +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. Критические ошибки +--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.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.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.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(); +--1.5. Шапка документа +exec GEN_ID 'OD_DOC_ID_GEN', 1, @CLISER_ID out; +set @D_DATE = getdate(); - exec FU_NEXT_DOC_NUM @D_CAT, @D_DATE, null, @CLISER_ID, @NUM out, null; +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 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; +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); +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.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.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; +--1.8. Входящая запись только для списания (исходящего перевода OUT) +if @DIRECTION = 'OUT' begin + exec GEN_ID 'OD_DOC_ID_GEN', 1, @FILER_ID out; - 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; + set @FILER_DATE = getdate(); - --Бумага - 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; + exec FU_NEXT_DOC_NUM 'D_FILER', @FILER_DATE, 1, @FILER_ID, @FILER_NUM out, null; - --Счет МХ - 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; + insert into OD_DOCS + (ID, NUM, D_CAT, D_DATE, STATE, DIRECTION, WHOS) + values + (@FILER_ID, @FILER_NUM, 255, @FILER_DATE, 2, 1, @WHOS); - --Счет клиента - select @DEPO = C.ID - from OD_CLIENTS C - where C.NUMBER = @DEPO_NUMBER; + insert into D_FILER + (DOC, PASS_KIND, RUBRICA, COMMENT, DOC_NUM, DOC_DATE, CORR_FACE, FUND, ACCOUNT, PLACE, ORI_DATE, CHILD_CAT, MESS) + values + (@FILER_ID, 7, 8, 'M2M поручение на списание через MOEX-МОСТ', @NUM, cast(@D_DATE as date), @DEPONENT, @DEPONENT, @DEPO, @PLACE, @FILER_DATE, @D_CAT, cast(@GUID as varchar(36))); - 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; + --Связываем с М2М-поручением + update OD_DOCS set ID = 0, KVIT = @FILER_ID where ID = @CLISER_ID; +end; diff --git a/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_EVENTS.sql b/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_EVENTS.sql index 51b0b29..c7ae2e7 100644 --- a/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_EVENTS.sql +++ b/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_EVENTS.sql @@ -1,277 +1,205 @@ CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_EVENTS] (@ID int) + +--grant execute on FTV_M2M_PROCESS_EVENTS to public; +--TODO что делать если мы проставили статус не по всем строкам документа?? + +as +set nocount on; - as - set nocount on; - /* - Вынести создание операции в отдельную процедуру FTV_M2M_PROCESS_OPERATION (параметры - @GUID и @REFERENCE, но проверку параметров оставить тут). Будем возвращать @OPER_ID - */ +--if user = 'dbo' execute as user = 'SYSDBA'; - if user = 'dbo' execute as user = 'SYSDBA'; +print 'FTV_M2M_PROCESS_EVENTS'; +print @ID; + + +declare + @WHOS int = 383118, + @GUID uniqueidentifier, + @REFERENCE varchar(255), + @EVENT_TYPE varchar(64), + @EVENT_DATE datetime, + @M2M_REJECT_CODE varchar, + @PARAMETERS nvarchar(4000), + @DIRECTION varchar(64), + @COMMENT varchar(MAX), + -- + @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), + @STATE int, + @RAISERROR varchar(64) = null; - 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); +select + @GUID = ME.GUID, + @REFERENCE = ME.REFERENCE, + @EVENT_TYPE = ME.EVENT_TYPE, + @EVENT_DATE = ME.EVENT_DATE, + @M2M_REJECT_CODE = ME.M2M_REJECT_CODE, + @PARAMETERS = ME.PARAMETERS, + @DIRECTION = M.DIRECTION, + @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; + + +--1. Обновление справоника участников сервмса +if @EVENT_TYPE = 'HANDBOOK' begin + exec FTV_M2M_UPDATE_HANDBOOK @COMMENT out; + update FTV_M2M_EVENTS set COMMENT = @COMMENT where ID = @ID; + return; +end; + + +--2. Критические ошибки (TODO другте обязательные поля) +if @GUID is null raiserror ('Не указан GUID', 16, 1); +if @REFERENCE is null raiserror ('Не указан REFERENCE', 16, 1); +if @DOL_ID is null raiserror ('Не найдена строка M2M-поручение по GUID + REFERENCE', 16, 1); - -- 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; +--3. Пишем в признаки документа +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') + ); - 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; +print @EVENT_TYPE; + + +--4. ОБРАБОТКА КАЖДОГО ТИПА СОБЫТИЯ +-- https://lic.zetit.ru/docs/fancy-events + + +if @EVENT_TYPE = 'BJ_RECEIVED' begin + update OD_DOCS set ID = 0, STATE = 1 where ID = @CLISER_ID; --START = Начало обработки (зарегистрирован) +end + +if @EVENT_TYPE = 'BJ_SENT' begin + select @STATE = ID from OD_DOC_STATES where SYS_NAME = 'WAIT_RESP_DECIS'; + update OD_DOCS set ID = 0, STATE = @STATE where ID = @CLISER_ID; --WAIT_RESP_DECIS = Ожидание ответа Response/Decision +end + +else +if @EVENT_TYPE in ('BJ_DECISION_CONFIRM', 'BJ_CP_CONFIRM') begin + --TODO эти события для СТРОКИ!!! + update OD_DOCS set ID = 0, STATE = 8 where ID = @CLISER_ID; --RECIEVED = Принят: ожидает обработки +end + +else +if @EVENT_TYPE in ('BJ_DECISION_REJECT', 'BJ_CP_REJECT') begin + --TODO эти события для СТРОКИ!!! + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT = Отмена обработки +end + +else +if @EVENT_TYPE = 'BJ_SERVICE_ERROR' begin + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT = Отмена обработки +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 +if @EVENT_TYPE = 'BJ_ORDER_SENT' begin + select @STATE = ID from OD_DOC_STATES where SYS_NAME = 'WAIT_OPER'; + update OD_DOCS set ID = 0, STATE = @STATE where ID = @CLISER_ID; --WAIT_OPER = Ожидание исполнения операции +end + +else +if @EVENT_TYPE = 'BJ_ORDER_ACCEPTED' begin + --Создаем операцию и проводим ее + exec FTV_M2M_PROCESS_OPERATION @GUID, @REFERENCE, @EVENT_DATE, @PARAMETERS, @OPER_ID out; + update OD_DOCS set ID = 0, STATE = 2 where ID = @CLISER_ID; -- FINAL - Конец обработки (в архиве) +end + +--BJ_ORDER_REJECTED +--TODO задал вопрос 16.10.2026 + +--BJ_EXECUTED +--Оно уже в событии BJ_ORDER_ACCEPTED в финале и с проводками, что делать-то? +else +if @EVENT_TYPE = 'BJ_EXECUTED' begin + print 'BJ_EXECUTED --Оно уже в событии BJ_ORDER_ACCEPTED в финале и с проводками, что делать-то?'; +end + +else +if @EVENT_TYPE = 'BJ_CANCELLED' begin + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT = Отмена обработки +end + +else +if @EVENT_TYPE = 'BJ_GATEWAY_REJECT' begin + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT = Отмена обработки + --ОНО по строке, и не понятно что делать +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 in + ( + 'BJ_ORDER_LATE', + 'BJ_PING', + 'BJ_QUIK_BLOCKED', + 'BJ_QUIK_RELEASED', + 'BJ_QUIK_SIGNED', + 'BJ_QUIK_DEPOSITED' + ) begin + print 'ничего не делать'; +end + +else begin + set @RAISERROR = 'От сервиса BJ получено неизвестное событие ' + @EVENT_TYPE; + raiserror (@RAISERROR, 16, 1); +end; diff --git a/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_OPERATION.sql b/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_OPERATION.sql index 4e8892c..3f26ffe 100644 --- a/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_OPERATION.sql +++ b/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_OPERATION.sql @@ -1,165 +1,204 @@ -CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_OPERATION] @GUID uniqueidentifier, @REFERENCE varchar(255), @OPER_DATE datetime, @OPER_ID int output +CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_OPERATION] @GUID uniqueidentifier, @REFERENCE varchar(255), @OPER_DATE datetime, @PARAMETERS nvarchar(4000), @OPER_ID int output + +--grant execute on FTV_M2M_PROCESS_OPERATION to public; + +/* +Создает операцию, возвращает OPER_ID созданной операции +Параметры нацелены прежде всего на строки уже созданного М2М-поручения D_CLISER_M2M_DOL, а не на буферные таблицы (к ним больше не обращаемся) +Все проверки идут до вызова, но элементарные проверки можно сделать и тут. Или дать raiserror +Мы существенно разгружаем FTV_M2M_PROCESS_EVENTS - /* - Создает операцию, возвращает 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', @PARAMETERS = '1234567890 от 10.10.2026', @OPER_ID = @OPER_ID out; +select @OPER_ID; - 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; - as - set nocount on; +if user = 'dbo' execute as user = 'SYSDBA'; - if user = 'dbo' execute as user = 'SYSDBA'; +print 'FTV_M2M_PROCESS_OPERATION' + ' GUID = ' + cast(@GUID as varchar(36)) + ', REFERENCE = ' + @REFERENCE; - 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), + @FILER_ID int, + @FILER_NUM varchar(64), + @FILER_DATE datetime, + @STEP_ID int; - 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; - 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); - --Элеметарные проверки - 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; - --Направление - 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; +set @NUM = @NUM + '_' + @REFERENCE; - --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); - --Создаем документ - 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, + 313, /*98010 - 0 - Ценные бумаги и цифровые активы на хранении в ведущем депозитарии (НОСТРО депо базовый) */ + @CLIENT, + 836, /*98070 - 4 - Ценные бумаги и цифровые активы на торгах*/ + 8106, /*ММВБ - ПАО Московская Биржа*/ + null, null, null, + 31, /*Отчет депозитария*/ + @CLISER_DATE, @CLISER_NUM, + @OPER_DATE, @OPER_DATE, @OPER_DATE, + 0, + @FACE, + null, + 'Отчет НКО АО НРД ' + @PARAMETERS + '. Перевод M2M (без поручения), GUID ' + cast(@GUID as varchar(36)) + ', референс ' + @REFERENCE + ); +end - 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, + 313, /*98010 - 0 - Ценные бумаги и цифровые активы на хранении в ведущем депозитарии (НОСТРО депо базовый) */ + @CLIENT, + 836, /*98070 - 4 - Ценные бумаги и цифровые активы на торгах*/ + 8106, /*ММВБ - ПАО Московская Биржа*/ + null, null, null, + 31, /*Отчет депозитария*/ + @CLISER_DATE, @CLISER_NUM, + @OPER_DATE, @OPER_DATE, @OPER_DATE, + 0, + @FACE, + null, + 'Отчет НКО АО НРД ' + @PARAMETERS + '. Перевод M2M, GUID ' + cast(@GUID as varchar(36)) + ', референс ' + @REFERENCE + ); +end; + +--Входящая запись (для отчета НРД) + exec GEN_ID 'OD_DOC_ID_GEN', 1, @FILER_ID out; + + set @FILER_DATE = getdate(); - 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 FU_NEXT_DOC_NUM 'D_FILER', @FILER_DATE, 1, @FILER_ID, @FILER_NUM out, null; - --И сразу проводим - exec FTV_M2M_PROCESS_WIRING @OPER_ID; + 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, MESS) + values + (@FILER_ID, 8, 5 /*уточнить в депозитарии*/, + 'Отчет (перевод через MOEX-МОСТ)', + LEFT(@PARAMETERS, CHARINDEX(' ', @PARAMETERS + ' ') - 1), + CONVERT(date, RIGHT(TRIM(@PARAMETERS), CHARINDEX(' ', REVERSE(TRIM(@PARAMETERS))) - 1), 104), + 18174, + @FACE, @CLIENT, @PLACE, @FILER_DATE, null, 'MS010 / ' + cast(@GUID as varchar(36)) + ' / ' + @REFERENCE); + + --ORI_DATE поточнее? может из события? TODO + + --Связываем с операцией + exec GEN_ID 'OD_STEPS_ID_GEN', 1, @STEP_ID out; + insert into OD_STEPS + (ID, DOC, A_DOC, ERR_CODE, S_TYPE, OUT_STATE, S_DATE, OPER) + values + (@STEP_ID, @FILER_ID, @OPER_ID, 2004, 0, 0, getdate(), null); + +--И сразу проводим +exec FTV_M2M_PROCESS_WIRING @OPER_ID; diff --git a/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_WIRING.sql b/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_WIRING.sql index d53493b..adfba6e 100644 --- a/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_WIRING.sql +++ b/deploy/depo/fancy-m2m/FTV_M2M_PROCESS_WIRING.sql @@ -1,5 +1,7 @@ CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_WIRING] (@OPER_ID int) - + +--grant execute on FTV_M2M_PROCESS_WIRING to public; + as set nocount on; diff --git a/deploy/depo/fancy-m2m/FTV_M2M_UPDATE_HANDBOOK.sql b/deploy/depo/fancy-m2m/FTV_M2M_UPDATE_HANDBOOK.sql new file mode 100644 index 0000000..86d5312 --- /dev/null +++ b/deploy/depo/fancy-m2m/FTV_M2M_UPDATE_HANDBOOK.sql @@ -0,0 +1,173 @@ +CREATE OR ALTER procedure [dbo].[FTV_M2M_UPDATE_HANDBOOK] @COMMENT nvarchar(MAX) out + +--grant execute on FTV_M2M_UPDATE_HANDBOOK to public; + +/* +Обновление справочника участников сервиса +select * from FTV_M2M_HANDBOOK where ACTIVE = 1 and PARTICIPANT_CODE is not null + +insert into FTV_M2M_EVENTS (EVENT_TYPE, EVENT_DATE) select 'HANDBOOK', getdate(); +declare @ID int, @COMMENT nvarchar(MAX); +select @ID = max(ID) from FTV_M2M_EVENTS where EVENT_TYPE = 'HANDBOOK'; +exec FTV_M2M_UPDATE_HANDBOOK @COMMENT out; +update FTV_M2M_EVENTS set COMMENT = @COMMENT where ID = @ID; +PRINT @COMMENT; +SELECT @COMMENT; + +--УДАЛЯЛКА ДЛЯ ТИКЕРОВ +declare @M2M_Coder int; +select @M2M_Coder = F.SELF_ID from OD_FACES F where F.LAST_FLAG = 1 and F.MNEM = 'M2M'; +delete from OD_FACE_CODERS where CODER = @M2M_Coder + +--УДАЛЯЛКА ДЛЯ ЮРЛИЦ +delete from OD_FACES where S_TYPE = 1 and B_DATE >= dateadd(DAY, -1, cast(getdate() as date)) + + +*/ +as +set nocount on; + +declare + @M2M_Coder int, + --@COMMENT nvarchar(MAX), + @Cnt int, + @FACE_ID int, + @ID int, + @ROW int = 0, + @DoubleINN int, + @INN varchar(12), + @CODE varchar(64), + @CODE2 varchar(64), + @NAME_SHORT nvarchar(128), + @NAME_FULL nvarchar(255); + +declare @CRLF nvarchar(2) = NCHAR(13) + NCHAR(10); + +select @M2M_Coder = F.SELF_ID from OD_FACES F where F.LAST_FLAG = 1 and F.MNEM = 'M2M'; +--select @M2M_Coder; + +--1. Статистика по участникам +declare @Codes_OUR table (SELF_ID int, INN varchar(12), CODE varchar(64), NAME_SHORT varchar(255), NAME_FULL varchar(255)); + +insert into @Codes_OUR (SELF_ID, INN, CODE, NAME_SHORT, NAME_FULL) +select + F.SELF_ID, F.INN, C.CODE, F.NAME, UF.FULL_NAME +from OD_FACE_CODERS C + left join OD_FACES F on F.SELF_ID = C.FACE and F.LAST_FLAG = 1 and F.E_DATE = '1.1.9999' + left join OD_U_FACES UF on UF.FACE = F.SELF_ID +where C.CODER = @M2M_Coder; +--select * from @Codes_OUR; + +select @Cnt = count(*) from @Codes_OUR; + +set @COMMENT = N'УЧАСТНИКИ СЕРВИСА: в справочнике юрлиц Фэнси - ' + trim(str(@Cnt)); + +select @Cnt = count(*) from FTV_M2M_HANDBOOK where ACTIVE = 1 and PARTICIPANT_CODE is not null; + +set @COMMENT = @COMMENT + N', по данным НРД - ' + trim(str(@Cnt)); +--PRINT @COMMENT; + + +--2. Принудительно добавляем отсутствующих юрлиц в Фэнси +declare cur cursor local fast_forward read_only for + select HB.ID, HB.PARTICIPANT_CODE, HB.INN, HB.NAME_SHORT, HB.NAME_FULL + from FTV_M2M_HANDBOOK HB + where HB.ACTIVE = 1 and HB.INN not in (select INN from OD_FACES F where F.LAST_FLAG = 1 and F.E_DATE = '1.1.9999' and F.INN is not null) + order by HB.NAME_SHORT; + +open cur; +while 0 = 0 begin fetch next from cur into @ID, @CODE, @INN, @NAME_SHORT, @NAME_FULL; +if @@FETCH_STATUS <> 0 break; + set @ROW = @ROW + 1; + exec GEN_ID 'OD_FACES_ID_GEN', 1, @FACE_ID out; + + insert into OD_FACES (ID, S_TYPE, INN, NAME) + values (@FACE_ID, 1, @INN, @NAME_SHORT); + + insert into OD_U_FACES (FACE, FULL_NAME) + values (@FACE_ID, @NAME_FULL); + + insert into OD_FACE_CODERS (CODE, CODER, FACE) + values (@CODE, @M2M_Coder, @FACE_ID); + + set @COMMENT = @COMMENT + @CRLF + trim(str(@ROW)) + N'. Добавлено юрлицо: ' + @CODE + N', ' + @INN + N', ' + @NAME_SHORT; +end; +close cur; +deallocate cur; + + +----3. Добавляем отсутствующие коды участников в справочник тикеров Фэнси, сразу предупреждая о двойниках по ИНН +delete from @Codes_OUR; +insert into @Codes_OUR (SELF_ID, INN, CODE, NAME_SHORT, NAME_FULL) +select + F.SELF_ID, F.INN, C.CODE, F.NAME, UF.FULL_NAME +from OD_FACE_CODERS C + left join OD_FACES F on F.SELF_ID = C.FACE and F.LAST_FLAG = 1 and F.E_DATE = '1.1.9999' + left join OD_U_FACES UF on UF.FACE = F.SELF_ID +where C.CODER = @M2M_Coder; + +declare cur cursor local fast_forward read_only for + select HB.ID, HB.PARTICIPANT_CODE, HB.INN, HB.NAME_SHORT, min(F.SELF_ID), count(*) + from FTV_M2M_HANDBOOK HB + left join OD_FACES F on F.INN = HB.INN + left join OD_FACE_CODERS C on C.CODER = @M2M_Coder and F.SELF_ID = C.FACE + where + HB.ACTIVE = 1 + and HB.PARTICIPANT_CODE is not null + and F.S_TYPE = 1 + and F.LAST_FLAG = 1 + and F.E_DATE = '1.1.9999' + and C.CODE is null + and F.INN not in (select INN from @Codes_OUR) + group by HB.ID, HB.PARTICIPANT_CODE, HB.INN, HB.NAME_SHORT + order by HB.NAME_SHORT; + +open cur; +while 0 = 0 begin fetch next from cur into @ID, @CODE, @INN, @NAME_SHORT, @FACE_ID, @Cnt; +if @@FETCH_STATUS <> 0 break; + set @ROW = @ROW + 1; + + insert into OD_FACE_CODERS (CODE, CODER, FACE) + values (@CODE, @M2M_Coder, @FACE_ID); + + set @COMMENT = @COMMENT + @CRLF + trim(str(@ROW)) + N'. Добавлен код участника ' + @CODE + N' к юрлицу: ' + @INN + N', ' + @NAME_SHORT; + if @Cnt > 1 begin + set @COMMENT = @COMMENT + N' (ПРЕДУПРЕЖДЕНИЕ: в Фэнси найдено несколько юрлиц с ИНН ' + @INN + N')'; + end; +end; +close cur; +deallocate cur; + +if @ROW = 0 begin + set @COMMENT = @COMMENT + N' (при обработке нового справочника НРД никаких изменений не обнаружено)' +end; + + +--4. Проверка на отличающиеся коды в Фэнси и НРД для одного юрлица по идентификации ИНН, или лишние коды в Фэнси +delete from @Codes_OUR; +insert into @Codes_OUR (SELF_ID, INN, CODE, NAME_SHORT, NAME_FULL) +select + F.SELF_ID, F.INN, C.CODE, F.NAME, UF.FULL_NAME +from OD_FACE_CODERS C + left join OD_FACES F on F.SELF_ID = C.FACE and F.LAST_FLAG = 1 and F.E_DATE = '1.1.9999' + left join OD_U_FACES UF on UF.FACE = F.SELF_ID +where C.CODER = @M2M_Coder; + +declare cur cursor local fast_forward read_only for + select C.INN, C.NAME_SHORT, C.CODE, HB.PARTICIPANT_CODE + from @Codes_OUR C + left join FTV_M2M_HANDBOOK HB on HB.INN = C.INN and ACTIVE = 1 and HB.PARTICIPANT_CODE is not null + where + C.CODE <> HB.PARTICIPANT_CODE or HB.PARTICIPANT_CODE is null; + +open cur; +while 0 = 0 begin fetch next from cur into @INN, @NAME_SHORT, @CODE, @CODE2 +if @@FETCH_STATUS <> 0 break; + set @ROW = @ROW + 1; + if @CODE2 is null + set @COMMENT = @COMMENT + @CRLF + N'КРИТИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ: для юрлица ' + @INN + ' (' + @NAME_SHORT + N') в Фэнси указан код ' + @CODE + N', отсутствующий в НРД'; + else + set @COMMENT = @COMMENT + @CRLF + N'КРИТИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ: для юрлица ' + @INN + ' (' + @NAME_SHORT + N') в Фэнси указан код ' + @CODE + N', отличающийся от кода в НРД ' + @CODE2; +end; +close cur; +deallocate cur; diff --git a/deploy/depo/fancy-m2m/README.md b/deploy/depo/fancy-m2m/README.md index 28bdae0..490fa0e 100644 --- a/deploy/depo/fancy-m2m/README.md +++ b/deploy/depo/fancy-m2m/README.md @@ -1,7 +1,7 @@ # Расширение Fancy DEPO для M2M (bj2depo) — процедуры Фонтвьель Код написан программистом Фонтвьель (В. Кокин) как собственное дополнение к Fancy DEPO — код Fancy не меняется, -это штатная для Fancy практика. Сняты из базы SQL002/BJ_DEPO_DATA 23.09.2026 (`sys.sql_modules`), тестовые вставки удалены. +это штатная для Fancy практика. Сняты из базы SQL002/BJ_DEPO_DATA (тестовая DEPO, 10.10.10.21) 22.10.2026 (`sys.sql_modules`) — с правками программиста 09–21.10; код без изменений, только `CREATE` → `CREATE OR ALTER` (примеры для теста — в комментариях `/* */` автора). ## Что делает - `FTV_M2M_JOB` — точка входа джобы SQL Agent (bj ставит её как `bj2depo`, раз в N секунд; режим «bj» — bj вызывает сам): @@ -12,6 +12,8 @@ - `FTV_M2M_PROCESS_EVENTS @ID` — событие по строке (GUID+REFERENCE): решения, поручения, исполнение → операции зачисления/списания (`U_OP_INV_ZACH`, `U_OP_INV_SPIS`) через `FTV_M2M_PROCESS_OPERATION` и проводки через `FTV_M2M_PROCESS_WIRING` (`OD_PR_INS_WIRS`, `OD_STEPS`). - `FTV_M2M_PROCESS_OPERATION`, `FTV_M2M_PROCESS_WIRING` — служебные. +- `FTV_M2M_UPDATE_HANDBOOK @COMMENT out` — справочник участников M2M (`FTV_M2M_HANDBOOK`, его пишет bj) → юрлица и кодеры Fancy (`OD_FACES`, `OD_FACE_CODERS`, кодер `MNEM='M2M'`); вызывается из EVENTS по событию HANDBOOK. +- 22.10.2026: в OPERATION счёт ностро `313` (98010 — ведущий депозитарий, «НОСТРО депо базовый») вместо прежнего `314`. ## От чего зависит на стороне Fancy (должно быть в DEPO клиента) Таблицы поставки Fancy с поддержкой M2M (у Фонтвьель появились 25.08.2026): `D_CLISER_M2M`, `D_CLISER_M2M_DOL`, `OD_M2M_ACCS`, @@ -31,7 +33,7 @@ ## Порядок установки у клиента 1. bj → «Обмен Fancy → Подключение» (логин bj_user: datareader+datawriter на FTV_M2M*). 2. bj → «Трансферные таблицы DEPO»: создать (логином с правами) или скрипт DBA. -3. Этот каталог: выполнить 5 файлов в порядке WIRING → OPERATION → CREATE → EVENTS → JOB (CREATE OR ALTER, повторно безопасно). +3. Этот каталог: выполнить 6 файлов в порядке WIRING → OPERATION → UPDATE_HANDBOOK → EVENTS → CREATE → JOB (CREATE OR ALTER, повторно безопасно). `FTV_M2M_PROCESS_EVENTS` вызывает `FTV_M2M_UPDATE_HANDBOOK` (событие HANDBOOK — справочник участников в юрлица Fancy). Права: `GRANT EXECUTE ON dbo.FTV_M2M_JOB TO bj_user` (для режима «bj»). 4. bj → «Обработка DEPO»: режим `sql-auto` (bj создаёт джобу `bj2depo`: `EXEC dbo.FTV_M2M_JOB`, интервал по настройке) или `sql-manual`. 5. bj → «Проверить готовность»: событие `BJ_PING` должно получить STATE от джобы. diff --git a/internal/lkgateway/depo_procs.go b/internal/lkgateway/depo_procs.go index 17fe16d..77d8662 100644 --- a/internal/lkgateway/depo_procs.go +++ b/internal/lkgateway/depo_procs.go @@ -4,7 +4,9 @@ package lkgateway // в базу DEPO прямо из bj: «Проверить возможности» (предпросмотр без изменений) и // «Установить» (выполняется логином администратора SQL — разово, не сохраняется). // Процедуры встроены в bj (internal/lkgateway/depoprocs/*.sql), порядок установки — -// WIRING → OPERATION → EVENTS → CREATE → JOB; затем GRANT EXECUTE на FTV_M2M_JOB логину bj. +// WIRING → OPERATION → UPDATE_HANDBOOK → EVENTS → CREATE → JOB; затем GRANT EXECUTE логину bj. +// Тексты — с тестовой DEPO Фонтвьель на 22.10.2026 (правки программиста 09–21.10; EVENTS вызывает +// UPDATE_HANDBOOK — без неё обработка событий падает). import ( "context" @@ -25,6 +27,7 @@ var depoProcFS embed.FS 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_UPDATE_HANDBOOK", "depoprocs/FTV_M2M_UPDATE_HANDBOOK.sql"}, // вызывается из EVENTS (HANDBOOK) {"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"}, @@ -73,6 +76,15 @@ func depoProcEffective(f FancyMSSQLSettings, name string) string { return embeddedProcBody(name) } +// depoProcOrderText — порядок установки коротко: WIRING→OPERATION→UPDATE_HANDBOOK→… +func depoProcOrderText(sep string) string { + var parts []string + for _, p := range depoProcInstallOrder { + parts = append(parts, strings.TrimPrefix(strings.TrimPrefix(p.Name, "FTV_M2M_PROCESS_"), "FTV_M2M_")) + } + return strings.Join(parts, sep) +} + // depoProcList — порядок процедур для шаблона (редактор текстов). func depoProcList() []struct{ Name, File string } { return depoProcInstallOrder } @@ -86,7 +98,7 @@ func depoProcsCombined(f FancyMSSQLSettings) string { func depoProcsScriptFor(f FancyMSSQLSettings, db, login string) string { var b strings.Builder b.WriteString("/* Bridge&Join: процедуры обработки bj2depo для базы DEPO.\n") - b.WriteString(" Порядок WIRING -> OPERATION -> EVENTS -> CREATE -> JOB. Запуск под sysadmin в SSMS.\n") + b.WriteString(" Порядок " + depoProcOrderText(" -> ") + ". Запуск под sysadmin в SSMS.\n") b.WriteString(" CREATE OR ALTER — повторный запуск безопасен (данные не меняются). */\n") fmt.Fprintf(&b, "USE %s;\nGO\n\n", quoteIdent(db)) for _, p := range depoProcInstallOrder { @@ -176,9 +188,9 @@ func depoProcsPreflight(ctx context.Context, f FancyMSSQLSettings, adminUser, ad 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") + fmt.Fprintf(&b, "Процедуры: все %d уже установлены (будут обновлены CREATE OR ALTER).\n", len(depoProcInstallOrder)) } else { - fmt.Fprintf(&b, "Процедуры: нет %d из 5 (%s).\n", len(missing), strings.Join(missing, ", ")) + fmt.Fprintf(&b, "Процедуры: нет %d из %d (%s).\n", len(missing), len(depoProcInstallOrder), strings.Join(missing, ", ")) } if canApply { b.WriteString("Право создавать процедуры: есть.\n") @@ -195,7 +207,7 @@ func depoProcsPreflight(ctx context.Context, f FancyMSSQLSettings, adminUser, ad } else { fmt.Fprintf(&b, "Пользователь %s (для EXECUTE AS в процедурах): НЕТ — процедуры FTV_M2M_PROCESS_* используют EXECUTE AS USER='%s' и не создадутся без него. Создайте этого пользователя в базе (как в рабочей базе Fancy) или замените имя в «Тексты процедур».\n", execAs, execAs) } - b.WriteString("Будет выполнено: CREATE OR ALTER 5 процедур (WIRING→OPERATION→EVENTS→CREATE→JOB) + GRANT EXECUTE на FTV_M2M_JOB.") + fmt.Fprintf(&b, "Будет выполнено: CREATE OR ALTER %d процедур (%s) + GRANT EXECUTE логину bj.", len(depoProcInstallOrder), depoProcOrderText("→")) return b.String(), canApply, nil } diff --git a/internal/lkgateway/depoprocs/FTV_M2M_JOB.sql b/internal/lkgateway/depoprocs/FTV_M2M_JOB.sql index 62ad39b..fddcde9 100644 --- a/internal/lkgateway/depoprocs/FTV_M2M_JOB.sql +++ b/internal/lkgateway/depoprocs/FTV_M2M_JOB.sql @@ -1,71 +1,120 @@ 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; - - /* тестовый блок удалён при переносе в репозиторий */ + +--grant execute on FTV_M2M_JOB to public; +--exec FTV_M2M_JOB; + +as +set nocount on; + +declare + @ID int, + @STATE varchar(64), + @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; + + --Процесс создания М2М-поручения + begin try + set @COMMENT = null; + 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 + set @COMMENT = null; + 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 + + --Тут также можно уведомить об ошибочном статусе (вне транзакции) + if @COMMENT is not null + update FTV_M2M_EVENTS set STATE = @STATE, TimeEnd = GETDATE(),COMMENT = @COMMENT where ID = @ID; + else + update FTV_M2M_EVENTS set STATE = @STATE, TimeEnd = GETDATE() where ID = @ID; + +end; +close cur; +deallocate cur; + +/* +НИЖЕ - ПРИМЕР ДЛЯ ТЕСТИРОВАНИЯ + +declare @GUID uniqueidentifier; +set @GUID = NEWID(); + +INSERT INTO [dbo].[FTV_M2M] ([GUID], [CONTRAGENT_M2M_CODE], [DEPONENT_NAME], [DEPONENT_DOC], [DIRECTION]) +VALUES (@GUID, 'MC0034900000', 'Абабков Александр Владимирович', '4508 147055', 'OUT'); + +--Замечание - списание возможно только по одной строке подвала!! +INSERT INTO [dbo].[FTV_M2M_LINES] ([GUID], [REFERENCE], [ISIN], [SEC_CODE], [AMOUNT], [PLACE_NUMBER], [LINK_NUMBER], [DEPO_NUMBER]) +VALUES (@GUID, 'M2MREF_11', 'RU000A0JVHH1', 'RU000A0JVHH1', 11, '36MC0413600000F00', 'HL171004001C', 'ВТНКЦ00000060'); + +--INSERT INTO [dbo].[FTV_M2M_LINES] ([GUID], [REFERENCE], [ISIN], [SEC_CODE], [AMOUNT], [PLACE_NUMBER], [LINK_NUMBER], [DEPO_NUMBER]) +--VALUES (@GUID, 'M2MREF_22', 'RU0009029540', 'SBER/03', 12, '36MC0413600000F00', 'HL171004001C', 'ВТНКЦ00000060'); + +exec FTV_M2M_JOB; + +--select COMMENT, * from [dbo].[FTV_M2M] +--select COMMENT, * from [dbo].[FTV_M2M_LINES] +--select COMMENT, * from [dbo].[FTV_M2M_EVENTS] +-------------------------- + +--set @GUID = '' +INSERT INTO [dbo].[FTV_M2M_EVENTS] (GUID, REFERENCE, EVENT_TYPE, EVENT_DATE, M2M_REJECT_CODE) + VALUES (@GUID, 'M2MREF_11', 'BJ_ORDER_ACCEPTED', getdate()); + +exec FTV_M2M_JOB; +select COMMENT, * from [dbo].[FTV_M2M] +select COMMENT, * from [dbo].[FTV_M2M_LINES] +select COMMENT, * from [dbo].[FTV_M2M_EVENTS] + + + +Ошибка преобразования значения varchar "IN" в тип данных int. // FTV_M2M_PROCESS_CREATE // 22 +Не удалось вставить значение NULL в столбец "D_CAT", таблицы "UPD_DE_DATA.dbo.OD_DOCS"; в столбце запрещены значения NULL. Ошибка в INSERT. // propagate // 4 +Дублирование номера внутреннего или исходящего документа (M2M поручение на зачисление от 05.09.2026: No TEST M2M) // propagate // 4 +Обнаружена ошибка: деление на ноль. // FTV_M2M_PROCESS_CREATE // 118 +Ошибка при преобразовании типа данных nvarchar к datetime. // FU_NEXT_DOC_NUM // 0 + + +*/ diff --git a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_CREATE.sql b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_CREATE.sql index 611c8e3..0d93703 100644 --- a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_CREATE.sql +++ b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_CREATE.sql @@ -1,188 +1,209 @@ CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_CREATE] (@ID int) + +--grant execute on FTV_M2M_PROCESS_CREATE to public; - /* - TODO: - Дата поручения - сейчас getdate, но можно передавать, для этого ввести пновое поле в FTV_M2M, или потом брать з события и изменять - Для входящий переводов из СПБ возможно следует дать raiserror - */ +/* +TODO: +Дата поручения - сейчас getdate, но можно передавать, для этого ввести пновое поле в FTV_M2M, или потом брать из события и изменять +Для входящих переводов из СПБ возможно следует дать raiserror (но это должен делать bj) +*/ - as - set nocount on; +as +set nocount on; - if user = 'dbo' execute as user = 'SYSDBA'; +if user = 'dbo' execute as user = 'SYSDBA'; - print 'FTV_M2M_PROCESS_CREATE'; - print @ID; +print 'FTV_M2M_PROCESS_CREATE'; +print @ID; - --Создаем M2M-поручение вместе с подвалом документа +--Создаем 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; +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; +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. Критические ошибки +--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.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.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.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(); +--1.5. Шапка документа +exec GEN_ID 'OD_DOC_ID_GEN', 1, @CLISER_ID out; +set @D_DATE = getdate(); - exec FU_NEXT_DOC_NUM @D_CAT, @D_DATE, null, @CLISER_ID, @NUM out, null; +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 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; +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); +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.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.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; +--1.8. Входящая запись только для списания (исходящего перевода OUT) +if @DIRECTION = 'OUT' begin + exec GEN_ID 'OD_DOC_ID_GEN', 1, @FILER_ID out; - 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; + set @FILER_DATE = getdate(); - --Бумага - 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; + exec FU_NEXT_DOC_NUM 'D_FILER', @FILER_DATE, 1, @FILER_ID, @FILER_NUM out, null; - --Счет МХ - 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; + insert into OD_DOCS + (ID, NUM, D_CAT, D_DATE, STATE, DIRECTION, WHOS) + values + (@FILER_ID, @FILER_NUM, 255, @FILER_DATE, 2, 1, @WHOS); - --Счет клиента - select @DEPO = C.ID - from OD_CLIENTS C - where C.NUMBER = @DEPO_NUMBER; + insert into D_FILER + (DOC, PASS_KIND, RUBRICA, COMMENT, DOC_NUM, DOC_DATE, CORR_FACE, FUND, ACCOUNT, PLACE, ORI_DATE, CHILD_CAT, MESS) + values + (@FILER_ID, 7, 8, 'M2M поручение на списание через MOEX-МОСТ', @NUM, cast(@D_DATE as date), @DEPONENT, @DEPONENT, @DEPO, @PLACE, @FILER_DATE, @D_CAT, cast(@GUID as varchar(36))); - 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; + --Связываем с М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 index 51b0b29..c7ae2e7 100644 --- a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_EVENTS.sql +++ b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_EVENTS.sql @@ -1,277 +1,205 @@ CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_EVENTS] (@ID int) + +--grant execute on FTV_M2M_PROCESS_EVENTS to public; +--TODO что делать если мы проставили статус не по всем строкам документа?? + +as +set nocount on; - as - set nocount on; - /* - Вынести создание операции в отдельную процедуру FTV_M2M_PROCESS_OPERATION (параметры - @GUID и @REFERENCE, но проверку параметров оставить тут). Будем возвращать @OPER_ID - */ +--if user = 'dbo' execute as user = 'SYSDBA'; - if user = 'dbo' execute as user = 'SYSDBA'; +print 'FTV_M2M_PROCESS_EVENTS'; +print @ID; + + +declare + @WHOS int = 383118, + @GUID uniqueidentifier, + @REFERENCE varchar(255), + @EVENT_TYPE varchar(64), + @EVENT_DATE datetime, + @M2M_REJECT_CODE varchar, + @PARAMETERS nvarchar(4000), + @DIRECTION varchar(64), + @COMMENT varchar(MAX), + -- + @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), + @STATE int, + @RAISERROR varchar(64) = null; - 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); +select + @GUID = ME.GUID, + @REFERENCE = ME.REFERENCE, + @EVENT_TYPE = ME.EVENT_TYPE, + @EVENT_DATE = ME.EVENT_DATE, + @M2M_REJECT_CODE = ME.M2M_REJECT_CODE, + @PARAMETERS = ME.PARAMETERS, + @DIRECTION = M.DIRECTION, + @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; + + +--1. Обновление справоника участников сервмса +if @EVENT_TYPE = 'HANDBOOK' begin + exec FTV_M2M_UPDATE_HANDBOOK @COMMENT out; + update FTV_M2M_EVENTS set COMMENT = @COMMENT where ID = @ID; + return; +end; + + +--2. Критические ошибки (TODO другте обязательные поля) +if @GUID is null raiserror ('Не указан GUID', 16, 1); +if @REFERENCE is null raiserror ('Не указан REFERENCE', 16, 1); +if @DOL_ID is null raiserror ('Не найдена строка M2M-поручение по GUID + REFERENCE', 16, 1); - -- 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; +--3. Пишем в признаки документа +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') + ); - 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; +print @EVENT_TYPE; + + +--4. ОБРАБОТКА КАЖДОГО ТИПА СОБЫТИЯ +-- https://lic.zetit.ru/docs/fancy-events + + +if @EVENT_TYPE = 'BJ_RECEIVED' begin + update OD_DOCS set ID = 0, STATE = 1 where ID = @CLISER_ID; --START = Начало обработки (зарегистрирован) +end + +if @EVENT_TYPE = 'BJ_SENT' begin + select @STATE = ID from OD_DOC_STATES where SYS_NAME = 'WAIT_RESP_DECIS'; + update OD_DOCS set ID = 0, STATE = @STATE where ID = @CLISER_ID; --WAIT_RESP_DECIS = Ожидание ответа Response/Decision +end + +else +if @EVENT_TYPE in ('BJ_DECISION_CONFIRM', 'BJ_CP_CONFIRM') begin + --TODO эти события для СТРОКИ!!! + update OD_DOCS set ID = 0, STATE = 8 where ID = @CLISER_ID; --RECIEVED = Принят: ожидает обработки +end + +else +if @EVENT_TYPE in ('BJ_DECISION_REJECT', 'BJ_CP_REJECT') begin + --TODO эти события для СТРОКИ!!! + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT = Отмена обработки +end + +else +if @EVENT_TYPE = 'BJ_SERVICE_ERROR' begin + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT = Отмена обработки +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 +if @EVENT_TYPE = 'BJ_ORDER_SENT' begin + select @STATE = ID from OD_DOC_STATES where SYS_NAME = 'WAIT_OPER'; + update OD_DOCS set ID = 0, STATE = @STATE where ID = @CLISER_ID; --WAIT_OPER = Ожидание исполнения операции +end + +else +if @EVENT_TYPE = 'BJ_ORDER_ACCEPTED' begin + --Создаем операцию и проводим ее + exec FTV_M2M_PROCESS_OPERATION @GUID, @REFERENCE, @EVENT_DATE, @PARAMETERS, @OPER_ID out; + update OD_DOCS set ID = 0, STATE = 2 where ID = @CLISER_ID; -- FINAL - Конец обработки (в архиве) +end + +--BJ_ORDER_REJECTED +--TODO задал вопрос 16.10.2026 + +--BJ_EXECUTED +--Оно уже в событии BJ_ORDER_ACCEPTED в финале и с проводками, что делать-то? +else +if @EVENT_TYPE = 'BJ_EXECUTED' begin + print 'BJ_EXECUTED --Оно уже в событии BJ_ORDER_ACCEPTED в финале и с проводками, что делать-то?'; +end + +else +if @EVENT_TYPE = 'BJ_CANCELLED' begin + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT = Отмена обработки +end + +else +if @EVENT_TYPE = 'BJ_GATEWAY_REJECT' begin + update OD_DOCS set ID = 0, STATE = 3 where ID = @CLISER_ID; --REJECT = Отмена обработки + --ОНО по строке, и не понятно что делать +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 in + ( + 'BJ_ORDER_LATE', + 'BJ_PING', + 'BJ_QUIK_BLOCKED', + 'BJ_QUIK_RELEASED', + 'BJ_QUIK_SIGNED', + 'BJ_QUIK_DEPOSITED' + ) begin + print 'ничего не делать'; +end + +else begin + set @RAISERROR = 'От сервиса BJ получено неизвестное событие ' + @EVENT_TYPE; + raiserror (@RAISERROR, 16, 1); +end; diff --git a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_OPERATION.sql b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_OPERATION.sql index 4e8892c..3f26ffe 100644 --- a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_OPERATION.sql +++ b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_OPERATION.sql @@ -1,165 +1,204 @@ -CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_OPERATION] @GUID uniqueidentifier, @REFERENCE varchar(255), @OPER_DATE datetime, @OPER_ID int output +CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_OPERATION] @GUID uniqueidentifier, @REFERENCE varchar(255), @OPER_DATE datetime, @PARAMETERS nvarchar(4000), @OPER_ID int output + +--grant execute on FTV_M2M_PROCESS_OPERATION to public; + +/* +Создает операцию, возвращает OPER_ID созданной операции +Параметры нацелены прежде всего на строки уже созданного М2М-поручения D_CLISER_M2M_DOL, а не на буферные таблицы (к ним больше не обращаемся) +Все проверки идут до вызова, но элементарные проверки можно сделать и тут. Или дать raiserror +Мы существенно разгружаем FTV_M2M_PROCESS_EVENTS - /* - Создает операцию, возвращает 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', @PARAMETERS = '1234567890 от 10.10.2026', @OPER_ID = @OPER_ID out; +select @OPER_ID; - 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; - as - set nocount on; +if user = 'dbo' execute as user = 'SYSDBA'; - if user = 'dbo' execute as user = 'SYSDBA'; +print 'FTV_M2M_PROCESS_OPERATION' + ' GUID = ' + cast(@GUID as varchar(36)) + ', REFERENCE = ' + @REFERENCE; - 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), + @FILER_ID int, + @FILER_NUM varchar(64), + @FILER_DATE datetime, + @STEP_ID int; - 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; - 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); - --Элеметарные проверки - 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; - --Направление - 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; +set @NUM = @NUM + '_' + @REFERENCE; - --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); - --Создаем документ - 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, + 313, /*98010 - 0 - Ценные бумаги и цифровые активы на хранении в ведущем депозитарии (НОСТРО депо базовый) */ + @CLIENT, + 836, /*98070 - 4 - Ценные бумаги и цифровые активы на торгах*/ + 8106, /*ММВБ - ПАО Московская Биржа*/ + null, null, null, + 31, /*Отчет депозитария*/ + @CLISER_DATE, @CLISER_NUM, + @OPER_DATE, @OPER_DATE, @OPER_DATE, + 0, + @FACE, + null, + 'Отчет НКО АО НРД ' + @PARAMETERS + '. Перевод M2M (без поручения), GUID ' + cast(@GUID as varchar(36)) + ', референс ' + @REFERENCE + ); +end - 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, + 313, /*98010 - 0 - Ценные бумаги и цифровые активы на хранении в ведущем депозитарии (НОСТРО депо базовый) */ + @CLIENT, + 836, /*98070 - 4 - Ценные бумаги и цифровые активы на торгах*/ + 8106, /*ММВБ - ПАО Московская Биржа*/ + null, null, null, + 31, /*Отчет депозитария*/ + @CLISER_DATE, @CLISER_NUM, + @OPER_DATE, @OPER_DATE, @OPER_DATE, + 0, + @FACE, + null, + 'Отчет НКО АО НРД ' + @PARAMETERS + '. Перевод M2M, GUID ' + cast(@GUID as varchar(36)) + ', референс ' + @REFERENCE + ); +end; + +--Входящая запись (для отчета НРД) + exec GEN_ID 'OD_DOC_ID_GEN', 1, @FILER_ID out; + + set @FILER_DATE = getdate(); - 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 FU_NEXT_DOC_NUM 'D_FILER', @FILER_DATE, 1, @FILER_ID, @FILER_NUM out, null; - --И сразу проводим - exec FTV_M2M_PROCESS_WIRING @OPER_ID; + 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, MESS) + values + (@FILER_ID, 8, 5 /*уточнить в депозитарии*/, + 'Отчет (перевод через MOEX-МОСТ)', + LEFT(@PARAMETERS, CHARINDEX(' ', @PARAMETERS + ' ') - 1), + CONVERT(date, RIGHT(TRIM(@PARAMETERS), CHARINDEX(' ', REVERSE(TRIM(@PARAMETERS))) - 1), 104), + 18174, + @FACE, @CLIENT, @PLACE, @FILER_DATE, null, 'MS010 / ' + cast(@GUID as varchar(36)) + ' / ' + @REFERENCE); + + --ORI_DATE поточнее? может из события? TODO + + --Связываем с операцией + exec GEN_ID 'OD_STEPS_ID_GEN', 1, @STEP_ID out; + insert into OD_STEPS + (ID, DOC, A_DOC, ERR_CODE, S_TYPE, OUT_STATE, S_DATE, OPER) + values + (@STEP_ID, @FILER_ID, @OPER_ID, 2004, 0, 0, getdate(), null); + +--И сразу проводим +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 index d53493b..adfba6e 100644 --- a/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_WIRING.sql +++ b/internal/lkgateway/depoprocs/FTV_M2M_PROCESS_WIRING.sql @@ -1,5 +1,7 @@ CREATE OR ALTER procedure [dbo].[FTV_M2M_PROCESS_WIRING] (@OPER_ID int) - + +--grant execute on FTV_M2M_PROCESS_WIRING to public; + as set nocount on; diff --git a/internal/lkgateway/depoprocs/FTV_M2M_UPDATE_HANDBOOK.sql b/internal/lkgateway/depoprocs/FTV_M2M_UPDATE_HANDBOOK.sql new file mode 100644 index 0000000..86d5312 --- /dev/null +++ b/internal/lkgateway/depoprocs/FTV_M2M_UPDATE_HANDBOOK.sql @@ -0,0 +1,173 @@ +CREATE OR ALTER procedure [dbo].[FTV_M2M_UPDATE_HANDBOOK] @COMMENT nvarchar(MAX) out + +--grant execute on FTV_M2M_UPDATE_HANDBOOK to public; + +/* +Обновление справочника участников сервиса +select * from FTV_M2M_HANDBOOK where ACTIVE = 1 and PARTICIPANT_CODE is not null + +insert into FTV_M2M_EVENTS (EVENT_TYPE, EVENT_DATE) select 'HANDBOOK', getdate(); +declare @ID int, @COMMENT nvarchar(MAX); +select @ID = max(ID) from FTV_M2M_EVENTS where EVENT_TYPE = 'HANDBOOK'; +exec FTV_M2M_UPDATE_HANDBOOK @COMMENT out; +update FTV_M2M_EVENTS set COMMENT = @COMMENT where ID = @ID; +PRINT @COMMENT; +SELECT @COMMENT; + +--УДАЛЯЛКА ДЛЯ ТИКЕРОВ +declare @M2M_Coder int; +select @M2M_Coder = F.SELF_ID from OD_FACES F where F.LAST_FLAG = 1 and F.MNEM = 'M2M'; +delete from OD_FACE_CODERS where CODER = @M2M_Coder + +--УДАЛЯЛКА ДЛЯ ЮРЛИЦ +delete from OD_FACES where S_TYPE = 1 and B_DATE >= dateadd(DAY, -1, cast(getdate() as date)) + + +*/ +as +set nocount on; + +declare + @M2M_Coder int, + --@COMMENT nvarchar(MAX), + @Cnt int, + @FACE_ID int, + @ID int, + @ROW int = 0, + @DoubleINN int, + @INN varchar(12), + @CODE varchar(64), + @CODE2 varchar(64), + @NAME_SHORT nvarchar(128), + @NAME_FULL nvarchar(255); + +declare @CRLF nvarchar(2) = NCHAR(13) + NCHAR(10); + +select @M2M_Coder = F.SELF_ID from OD_FACES F where F.LAST_FLAG = 1 and F.MNEM = 'M2M'; +--select @M2M_Coder; + +--1. Статистика по участникам +declare @Codes_OUR table (SELF_ID int, INN varchar(12), CODE varchar(64), NAME_SHORT varchar(255), NAME_FULL varchar(255)); + +insert into @Codes_OUR (SELF_ID, INN, CODE, NAME_SHORT, NAME_FULL) +select + F.SELF_ID, F.INN, C.CODE, F.NAME, UF.FULL_NAME +from OD_FACE_CODERS C + left join OD_FACES F on F.SELF_ID = C.FACE and F.LAST_FLAG = 1 and F.E_DATE = '1.1.9999' + left join OD_U_FACES UF on UF.FACE = F.SELF_ID +where C.CODER = @M2M_Coder; +--select * from @Codes_OUR; + +select @Cnt = count(*) from @Codes_OUR; + +set @COMMENT = N'УЧАСТНИКИ СЕРВИСА: в справочнике юрлиц Фэнси - ' + trim(str(@Cnt)); + +select @Cnt = count(*) from FTV_M2M_HANDBOOK where ACTIVE = 1 and PARTICIPANT_CODE is not null; + +set @COMMENT = @COMMENT + N', по данным НРД - ' + trim(str(@Cnt)); +--PRINT @COMMENT; + + +--2. Принудительно добавляем отсутствующих юрлиц в Фэнси +declare cur cursor local fast_forward read_only for + select HB.ID, HB.PARTICIPANT_CODE, HB.INN, HB.NAME_SHORT, HB.NAME_FULL + from FTV_M2M_HANDBOOK HB + where HB.ACTIVE = 1 and HB.INN not in (select INN from OD_FACES F where F.LAST_FLAG = 1 and F.E_DATE = '1.1.9999' and F.INN is not null) + order by HB.NAME_SHORT; + +open cur; +while 0 = 0 begin fetch next from cur into @ID, @CODE, @INN, @NAME_SHORT, @NAME_FULL; +if @@FETCH_STATUS <> 0 break; + set @ROW = @ROW + 1; + exec GEN_ID 'OD_FACES_ID_GEN', 1, @FACE_ID out; + + insert into OD_FACES (ID, S_TYPE, INN, NAME) + values (@FACE_ID, 1, @INN, @NAME_SHORT); + + insert into OD_U_FACES (FACE, FULL_NAME) + values (@FACE_ID, @NAME_FULL); + + insert into OD_FACE_CODERS (CODE, CODER, FACE) + values (@CODE, @M2M_Coder, @FACE_ID); + + set @COMMENT = @COMMENT + @CRLF + trim(str(@ROW)) + N'. Добавлено юрлицо: ' + @CODE + N', ' + @INN + N', ' + @NAME_SHORT; +end; +close cur; +deallocate cur; + + +----3. Добавляем отсутствующие коды участников в справочник тикеров Фэнси, сразу предупреждая о двойниках по ИНН +delete from @Codes_OUR; +insert into @Codes_OUR (SELF_ID, INN, CODE, NAME_SHORT, NAME_FULL) +select + F.SELF_ID, F.INN, C.CODE, F.NAME, UF.FULL_NAME +from OD_FACE_CODERS C + left join OD_FACES F on F.SELF_ID = C.FACE and F.LAST_FLAG = 1 and F.E_DATE = '1.1.9999' + left join OD_U_FACES UF on UF.FACE = F.SELF_ID +where C.CODER = @M2M_Coder; + +declare cur cursor local fast_forward read_only for + select HB.ID, HB.PARTICIPANT_CODE, HB.INN, HB.NAME_SHORT, min(F.SELF_ID), count(*) + from FTV_M2M_HANDBOOK HB + left join OD_FACES F on F.INN = HB.INN + left join OD_FACE_CODERS C on C.CODER = @M2M_Coder and F.SELF_ID = C.FACE + where + HB.ACTIVE = 1 + and HB.PARTICIPANT_CODE is not null + and F.S_TYPE = 1 + and F.LAST_FLAG = 1 + and F.E_DATE = '1.1.9999' + and C.CODE is null + and F.INN not in (select INN from @Codes_OUR) + group by HB.ID, HB.PARTICIPANT_CODE, HB.INN, HB.NAME_SHORT + order by HB.NAME_SHORT; + +open cur; +while 0 = 0 begin fetch next from cur into @ID, @CODE, @INN, @NAME_SHORT, @FACE_ID, @Cnt; +if @@FETCH_STATUS <> 0 break; + set @ROW = @ROW + 1; + + insert into OD_FACE_CODERS (CODE, CODER, FACE) + values (@CODE, @M2M_Coder, @FACE_ID); + + set @COMMENT = @COMMENT + @CRLF + trim(str(@ROW)) + N'. Добавлен код участника ' + @CODE + N' к юрлицу: ' + @INN + N', ' + @NAME_SHORT; + if @Cnt > 1 begin + set @COMMENT = @COMMENT + N' (ПРЕДУПРЕЖДЕНИЕ: в Фэнси найдено несколько юрлиц с ИНН ' + @INN + N')'; + end; +end; +close cur; +deallocate cur; + +if @ROW = 0 begin + set @COMMENT = @COMMENT + N' (при обработке нового справочника НРД никаких изменений не обнаружено)' +end; + + +--4. Проверка на отличающиеся коды в Фэнси и НРД для одного юрлица по идентификации ИНН, или лишние коды в Фэнси +delete from @Codes_OUR; +insert into @Codes_OUR (SELF_ID, INN, CODE, NAME_SHORT, NAME_FULL) +select + F.SELF_ID, F.INN, C.CODE, F.NAME, UF.FULL_NAME +from OD_FACE_CODERS C + left join OD_FACES F on F.SELF_ID = C.FACE and F.LAST_FLAG = 1 and F.E_DATE = '1.1.9999' + left join OD_U_FACES UF on UF.FACE = F.SELF_ID +where C.CODER = @M2M_Coder; + +declare cur cursor local fast_forward read_only for + select C.INN, C.NAME_SHORT, C.CODE, HB.PARTICIPANT_CODE + from @Codes_OUR C + left join FTV_M2M_HANDBOOK HB on HB.INN = C.INN and ACTIVE = 1 and HB.PARTICIPANT_CODE is not null + where + C.CODE <> HB.PARTICIPANT_CODE or HB.PARTICIPANT_CODE is null; + +open cur; +while 0 = 0 begin fetch next from cur into @INN, @NAME_SHORT, @CODE, @CODE2 +if @@FETCH_STATUS <> 0 break; + set @ROW = @ROW + 1; + if @CODE2 is null + set @COMMENT = @COMMENT + @CRLF + N'КРИТИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ: для юрлица ' + @INN + ' (' + @NAME_SHORT + N') в Фэнси указан код ' + @CODE + N', отсутствующий в НРД'; + else + set @COMMENT = @COMMENT + @CRLF + N'КРИТИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ: для юрлица ' + @INN + ' (' + @NAME_SHORT + N') в Фэнси указан код ' + @CODE + N', отличающийся от кода в НРД ' + @CODE2; +end; +close cur; +deallocate cur;