7073ce2a33
Полная перезапись FTV_M2M_HANDBOOK + событие HANDBOOK, как bj пишет в MSSQL (169 участников, 2 места расчётов): первый прогон — 168 юрлиц с кодами M2M, повторный — без изменений. Относительно MSSQL-версии: - место расчётов без кода участника — юрлицо без кода M2M (OD_FACE_CODERS.CODE NOT NULL, иначе падал весь справочник); - один ИНН дважды (СПБ Банк — место расчётов и депозитарий) — одно юрлицо, код добавляет шаг 3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
648 lines
36 KiB
SQL
648 lines
36 KiB
SQL
/* Bridge&Join — процедуры обработки M2M для Fancy DEPO на Firebird 2.5.
|
||
Перенос процедур MSSQL-версии (Фонтвьель, тексты от 22.10.2026, OPERATION — от 24.10.2026) на PSQL. Логика та же; отличия:
|
||
- raiserror — FTV_M2M_FAIL: текст причины кладётся в контекст транзакции и поднимается исключение FTV_M2M_ERROR;
|
||
FTV_M2M_JOB пишет этот текст в COMMENT (в Firebird 2.5 текст исключения в WHEN не доступен; контекст
|
||
возвращает строку без кодировки — приводится к WIN1251, кодировке базы Fancy);
|
||
- ошибка записи откатывает только её изменения (WHEN ANY = точка сохранения), в MSSQL-версии изменения
|
||
до ошибки оставались;
|
||
- числа-привязки Фонтвьель (WHOS, счета, биржа, тип основания, НРД, оператор) — из FTV_M2M_SETTINGS;
|
||
- «execute as user = 'SYSDBA'» нет: процедуры работают правами, выданными им самим (GRANT … TO PROCEDURE,
|
||
20_FTV_M2M_GRANTS.sql); логину bj нужно только EXECUTE на FTV_M2M_JOB;
|
||
- SELECT … INTO, который в MSSQL молча брал последнюю из нескольких строк, — SELECT FIRST 1;
|
||
- в цикле по строкам поручения бумага/счета сбрасываются перед поиском (в MSSQL ненайденное значение
|
||
оставалось от предыдущей строки).
|
||
Тексты работают в обоих диалектах: база Fancy — диалект 1 (DATE хранит и время, "…" — строка, а не имя),
|
||
поэтому COMMENT без кавычек, а дата без времени — через FTV_M2M_DAY. Проверено 27.10.2026 на обезличенной
|
||
базе Fancy (Firebird 2.5, диалект 1, кодировка NONE) с UDF ib_Fansy и штатными триггерами.
|
||
Порядок создания: вспомогательные, WIRING, OPERATION, UPDATE_HANDBOOK, EVENTS, CREATE, JOB. */
|
||
|
||
SET TERM ^ ;
|
||
|
||
/* Ошибка обработки с текстом причины. */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_FAIL (MSG VARCHAR(1000)) AS
|
||
DECLARE VARIABLE R INTEGER;
|
||
BEGIN
|
||
R = RDB$SET_CONTEXT('USER_TRANSACTION', 'FTV_M2M_ERR', SUBSTRING(MSG FROM 1 FOR 255));
|
||
EXCEPTION FTV_M2M_ERROR MSG;
|
||
END^
|
||
|
||
/* Привязка из FTV_M2M_SETTINGS; не заполнена — ошибка с именем настройки. */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_GET (NAME VARCHAR(64)) RETURNS (VAL INTEGER) AS
|
||
BEGIN
|
||
VAL = NULL;
|
||
SELECT S.VAL FROM FTV_M2M_SETTINGS S WHERE S.NAME = :NAME INTO :VAL;
|
||
IF (VAL IS NULL) THEN
|
||
EXECUTE PROCEDURE FTV_M2M_FAIL('Не заполнена настройка FTV_M2M_SETTINGS.' || NAME || ' (привязка к справочнику Fancy)');
|
||
END^
|
||
|
||
/* «дд.мм.гггг чч:мм:сс» (FORMAT(…, 'dd.MM.yyyy HH:mm:ss') MSSQL-версии). */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_DT (T TIMESTAMP) RETURNS (S VARCHAR(19)) AS
|
||
BEGIN
|
||
S = NULL;
|
||
IF (T IS NOT NULL) THEN
|
||
S = LPAD(EXTRACT(DAY FROM T), 2, '0') || '.' || LPAD(EXTRACT(MONTH FROM T), 2, '0') || '.' || EXTRACT(YEAR FROM T) || ' ' ||
|
||
LPAD(EXTRACT(HOUR FROM T), 2, '0') || ':' || LPAD(EXTRACT(MINUTE FROM T), 2, '0') || ':' ||
|
||
LPAD(CAST(FLOOR(EXTRACT(SECOND FROM T)) AS INTEGER), 2, '0');
|
||
END^
|
||
|
||
/* Дата без времени (CONVERT(DATE, …) MSSQL-версии). В диалекте 1 CAST(… AS DATE) время не отрезает. */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_DAY (T TIMESTAMP) RETURNS (D TIMESTAMP) AS
|
||
BEGIN
|
||
D = NULL;
|
||
IF (T IS NOT NULL) THEN
|
||
D = CAST(EXTRACT(YEAR FROM T) || '-' || EXTRACT(MONTH FROM T) || '-' || EXTRACT(DAY FROM T) AS TIMESTAMP);
|
||
END^
|
||
|
||
|
||
/* Директива «Обработать» для документа «Зачисление» или «Списание». Значения берутся только из самого
|
||
документа; M2M-поручение и трансферные таблицы не используются. */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_PROCESS_WIRING (OPER_ID INTEGER) AS
|
||
DECLARE VARIABLE USER_ID INTEGER;
|
||
DECLARE VARIABLE DIRECTION VARCHAR(3);
|
||
DECLARE VARIABLE D_CAT INTEGER;
|
||
DECLARE VARIABLE SHARE INTEGER;
|
||
DECLARE VARIABLE PLACE INTEGER;
|
||
DECLARE VARIABLE DEPO INTEGER;
|
||
DECLARE VARIABLE AMOUNT NUMERIC(18,7);
|
||
DECLARE VARIABLE CMT VARCHAR(255);
|
||
DECLARE VARIABLE B_TYPE INTEGER;
|
||
DECLARE VARIABLE B_NUM VARCHAR(255);
|
||
DECLARE VARIABLE B_DATE TIMESTAMP;
|
||
DECLARE VARIABLE WIR_DATE TIMESTAMP;
|
||
DECLARE VARIABLE D_NUM INTEGER;
|
||
DECLARE VARIABLE K_NUM INTEGER;
|
||
DECLARE VARIABLE MARKET INTEGER;
|
||
DECLARE VARIABLE OP_NAME VARCHAR(255);
|
||
DECLARE VARIABLE TEXT_B_TYPE VARCHAR(255);
|
||
DECLARE VARIABLE B_DATE_S VARCHAR(19);
|
||
DECLARE VARIABLE WIR_ID INTEGER;
|
||
DECLARE VARIABLE WIR_LIST VARCHAR(255);
|
||
DECLARE VARIABLE DEB_ID INTEGER;
|
||
DECLARE VARIABLE KRD_ID INTEGER;
|
||
DECLARE VARIABLE D_REG_1 INTEGER; DECLARE VARIABLE K_REG_1 INTEGER;
|
||
DECLARE VARIABLE D_REG_2 INTEGER; DECLARE VARIABLE K_REG_2 INTEGER;
|
||
DECLARE VARIABLE D_REG_3 INTEGER; DECLARE VARIABLE K_REG_3 INTEGER;
|
||
DECLARE VARIABLE D_REG_4 INTEGER; DECLARE VARIABLE K_REG_4 INTEGER;
|
||
DECLARE VARIABLE D_REG_5 INTEGER; DECLARE VARIABLE K_REG_5 INTEGER;
|
||
DECLARE VARIABLE D_REG_6 INTEGER; DECLARE VARIABLE K_REG_6 INTEGER;
|
||
DECLARE VARIABLE DIR_ID INTEGER;
|
||
DECLARE VARIABLE OUT_STATE INTEGER;
|
||
DECLARE VARIABLE STEP_ID INTEGER;
|
||
BEGIN
|
||
EXECUTE PROCEDURE FTV_M2M_GET('OPER_USER') RETURNING_VALUES :USER_ID;
|
||
|
||
/* НАПРАВЛЕНИЕ (MSSQL-версия при ненайденном документе молча выходила — здесь ошибка, видно в COMMENT) */
|
||
IF (EXISTS (SELECT 1 FROM U_OP_INV_ZACH WHERE DOC = :OPER_ID)) THEN DIRECTION = 'IN';
|
||
ELSE IF (EXISTS (SELECT 1 FROM U_OP_INV_SPIS WHERE DOC = :OPER_ID)) THEN DIRECTION = 'OUT';
|
||
ELSE EXECUTE PROCEDURE FTV_M2M_FAIL('Не найден документ операции ID = ' || OPER_ID);
|
||
|
||
/* ЗНАЧЕНИЯ ПЕРЕМЕННЫХ */
|
||
IF (DIRECTION = 'IN') THEN
|
||
BEGIN
|
||
SELECT D.D_CAT, H.D_NUM, H.K_NUM, H.B_TYPE, H.B_NUM, H.B_DATE, H.SHARE, H.AMOUNT, H.PLACE, H.DEPO, H.MARKET, H.WIR_DATE
|
||
FROM OD_DOCS D LEFT JOIN U_OP_INV_ZACH H ON H.DOC = D.ID
|
||
WHERE D.ID = :OPER_ID
|
||
INTO :D_CAT, :D_NUM, :K_NUM, :B_TYPE, :B_NUM, :B_DATE, :SHARE, :AMOUNT, :PLACE, :DEPO, :MARKET, :WIR_DATE;
|
||
OP_NAME = 'Зачисление';
|
||
SELECT C.SELF_ID, C.FACE, 0, 0, 0, :PLACE FROM OD_CLIENTS C WHERE C.ID = :PLACE
|
||
INTO :D_REG_1, :D_REG_2, :D_REG_3, :D_REG_4, :D_REG_5, :D_REG_6;
|
||
SELECT C.SELF_ID, :MARKET, 0, :D_REG_1, :PLACE, :DEPO FROM OD_CLIENTS C WHERE C.ID = :DEPO
|
||
INTO :K_REG_1, :K_REG_2, :K_REG_3, :K_REG_4, :K_REG_5, :K_REG_6;
|
||
END
|
||
ELSE
|
||
BEGIN
|
||
SELECT D.D_CAT, H.K_NUM /* реверс */, H.D_NUM /* реверс */, H.B_TYPE, H.B_NUM, H.B_DATE, H.SHARE, H.AMOUNT, H.PLACE, H.DEPO, H.MARKET, H.WIR_DATE
|
||
FROM OD_DOCS D LEFT JOIN U_OP_INV_SPIS H ON H.DOC = D.ID
|
||
WHERE D.ID = :OPER_ID
|
||
INTO :D_CAT, :D_NUM, :K_NUM, :B_TYPE, :B_NUM, :B_DATE, :SHARE, :AMOUNT, :PLACE, :DEPO, :MARKET, :WIR_DATE;
|
||
OP_NAME = 'Списание';
|
||
SELECT C.SELF_ID, C.FACE, 0, 0, 0, :PLACE FROM OD_CLIENTS C WHERE C.ID = :PLACE
|
||
INTO :K_REG_1, :K_REG_2, :K_REG_3, :K_REG_4, :K_REG_5, :K_REG_6;
|
||
SELECT C.SELF_ID, :MARKET, 0, :K_REG_1, :PLACE, :DEPO FROM OD_CLIENTS C WHERE C.ID = :DEPO
|
||
INTO :D_REG_1, :D_REG_2, :D_REG_3, :D_REG_4, :D_REG_5, :D_REG_6;
|
||
END
|
||
|
||
/* ДОПОЛНИТЕЛЬНЫЕ ПАРАМЕТРЫ: «<тип основания> N<номер> от <дата>»
|
||
(в MSSQL-версии FORMATMESSAGE начинал строку с пустого @COMMENT — «(null); …») */
|
||
SELECT FIRST 1 T.NAME FROM OD_SYS_TABS T WHERE T.CODE = 'DEPO96_DCLA' AND T.NUM = :B_TYPE INTO :TEXT_B_TYPE;
|
||
EXECUTE PROCEDURE FTV_M2M_DT(:B_DATE) RETURNING_VALUES :B_DATE_S;
|
||
CMT = SUBSTRING((COALESCE(TEXT_B_TYPE, '') || ' N' || COALESCE(B_NUM, '') || ' от ' || COALESCE(SUBSTRING(B_DATE_S FROM 1 FOR 10), '')) FROM 1 FOR 255);
|
||
|
||
/* ДИРЕКТИВА */
|
||
SELECT FIRST 1 T.ID, T.OUT_STATE FROM OD_STEP_TYPES T WHERE T.SYS_NAME = 'PROCESS' AND T.D_CAT = :D_CAT INTO :DIR_ID, :OUT_STATE;
|
||
STEP_ID = GEN_ID(OD_STEPS_ID_GEN, 1);
|
||
INSERT INTO OD_STEPS (ID, DOC, S_TYPE, S_DATE, ERR_CODE, OUT_STATE, OPER)
|
||
VALUES (:STEP_ID, :OPER_ID, :DIR_ID, CURRENT_TIMESTAMP, 0, :OUT_STATE, :USER_ID);
|
||
|
||
/* ПРОВОДКА */
|
||
EXECUTE PROCEDURE OD_PR_INS_WIRS (
|
||
NULL, 4, :WIR_DATE, :OP_NAME, :CMT, :AMOUNT, :AMOUNT, NULL, 0, 0, NULL, :STEP_ID, NULL, :USER_ID, 'F',
|
||
:D_NUM, :SHARE, :D_REG_1, :D_REG_2, :D_REG_3, :D_REG_4, :D_REG_5, :D_REG_6, /* дебет */
|
||
:K_NUM, :SHARE, :K_REG_1, :K_REG_2, :K_REG_3, :K_REG_4, :K_REG_5, :K_REG_6) /* кредит */
|
||
RETURNING_VALUES :WIR_ID, :WIR_LIST, :DEB_ID, :KRD_ID;
|
||
|
||
/* СОСТОЯНИЕ ДОКУМЕНТА */
|
||
UPDATE OD_DOCS SET STATE = :OUT_STATE WHERE ID = :OPER_ID;
|
||
END^
|
||
|
||
|
||
/* Создаёт операцию «Зачисление»/«Списание» по строке M2M-поручения, входящую запись (отчёт НРД) и проводит
|
||
операцию. Возвращает OPER_ID. */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_PROCESS_OPERATION (GUID CHAR(36), REFERENCE VARCHAR(255), OPER_DATE TIMESTAMP, PARAMETERS VARCHAR(4000))
|
||
RETURNS (OPER_ID INTEGER) AS
|
||
DECLARE VARIABLE WHOS INTEGER;
|
||
DECLARE VARIABLE ACC_D INTEGER;
|
||
DECLARE VARIABLE ACC_K INTEGER;
|
||
DECLARE VARIABLE MARKET INTEGER;
|
||
DECLARE VARIABLE B_TYPE INTEGER;
|
||
DECLARE VARIABLE CORR_FACE INTEGER;
|
||
DECLARE VARIABLE FILER_CAT INTEGER;
|
||
DECLARE VARIABLE RUBRICA INTEGER;
|
||
DECLARE VARIABLE CLISER_ID INTEGER;
|
||
DECLARE VARIABLE CLISER_NUM VARCHAR(64);
|
||
DECLARE VARIABLE CLISER_DATE TIMESTAMP;
|
||
DECLARE VARIABLE DIRECTION VARCHAR(64);
|
||
DECLARE VARIABLE DD_DATE TIMESTAMP;
|
||
DECLARE VARIABLE DD_NUM VARCHAR(64);
|
||
DECLARE VARIABLE SHARE INTEGER;
|
||
DECLARE VARIABLE AMOUNT NUMERIC(18,7);
|
||
DECLARE VARIABLE CLIENT INTEGER;
|
||
DECLARE VARIABLE FACE INTEGER;
|
||
DECLARE VARIABLE PLACE INTEGER;
|
||
DECLARE VARIABLE D_CAT INTEGER;
|
||
DECLARE VARIABLE NUM VARCHAR(255);
|
||
DECLARE VARIABLE NEW_DATE TIMESTAMP;
|
||
DECLARE VARIABLE FILER_ID INTEGER;
|
||
DECLARE VARIABLE FILER_NUM VARCHAR(255);
|
||
DECLARE VARIABLE FILER_DATE TIMESTAMP;
|
||
DECLARE VARIABLE STEP_ID INTEGER;
|
||
DECLARE VARIABLE P VARCHAR(4000);
|
||
DECLARE VARIABLE REP_NUM VARCHAR(255);
|
||
DECLARE VARIABLE REP_DATE TIMESTAMP;
|
||
DECLARE VARIABLE CMT VARCHAR(4000);
|
||
BEGIN
|
||
EXECUTE PROCEDURE FTV_M2M_GET('WHOS') RETURNING_VALUES :WHOS;
|
||
EXECUTE PROCEDURE FTV_M2M_GET('D_NUM') RETURNING_VALUES :ACC_D;
|
||
EXECUTE PROCEDURE FTV_M2M_GET('K_NUM') RETURNING_VALUES :ACC_K;
|
||
EXECUTE PROCEDURE FTV_M2M_GET('MARKET') RETURNING_VALUES :MARKET;
|
||
EXECUTE PROCEDURE FTV_M2M_GET('B_TYPE') RETURNING_VALUES :B_TYPE;
|
||
EXECUTE PROCEDURE FTV_M2M_GET('CORR_FACE') RETURNING_VALUES :CORR_FACE;
|
||
EXECUTE PROCEDURE FTV_M2M_GET('FILER_CAT') RETURNING_VALUES :FILER_CAT;
|
||
EXECUTE PROCEDURE FTV_M2M_GET('FILER_RUBRICA') RETURNING_VALUES :RUBRICA;
|
||
|
||
SELECT FIRST 1 H.DOC, D.NUM, D.D_DATE,
|
||
CASE WHEN DC.SYS_NAME = 'I_CLISER_M2M_ZACH' THEN 'IN' WHEN DC.SYS_NAME = 'I_CLISER_M2M_SPIS' THEN 'OUT' END,
|
||
D.D_DATE, D.NUM, F.SHARE, F.AMOUNT, F.CLIENT, H.DEPONENT, 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
|
||
INTO :CLISER_ID, :CLISER_NUM, :CLISER_DATE, :DIRECTION, :DD_DATE, :DD_NUM, :SHARE, :AMOUNT, :CLIENT, :FACE, :PLACE;
|
||
|
||
IF (CLISER_ID IS NULL) THEN
|
||
EXECUTE PROCEDURE FTV_M2M_FAIL('Не найдено M2M-поручение по GUID + REFERENCE');
|
||
EXECUTE PROCEDURE FTV_M2M_DAY(:DD_DATE) RETURNING_VALUES :DD_DATE;
|
||
|
||
/* Направление */
|
||
SELECT FIRST 1 DC.ID FROM OD_DOC_CATS DC
|
||
WHERE DC.SYS_NAME = CASE WHEN :DIRECTION = 'IN' THEN 'OP_INV_ZACH' ELSE 'OP_INV_SPIS' END
|
||
INTO :D_CAT;
|
||
|
||
/* ID и номер операции */
|
||
OPER_ID = GEN_ID(OD_DOCS_ID_GEN, 1);
|
||
EXECUTE PROCEDURE FU_NEXT_DOC_NUM (:D_CAT, :OPER_DATE, NULL, :OPER_ID) RETURNING_VALUES :NUM, :NEW_DATE;
|
||
NUM = NUM || '_' || REFERENCE;
|
||
|
||
/* Документ */
|
||
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);
|
||
|
||
/* Отчёт НРД из PARAMETERS — «<номер отчёта> от <дд.мм.гггг>»: номер — до первого пробела, дата — после
|
||
последнего. Основание операции (B_NUM, B_DATE) и входящая запись — по отчёту НРД, а не по M2M-поручению
|
||
(MSSQL-версия, правка программиста 24.10.2026). */
|
||
P = TRIM(PARAMETERS);
|
||
REP_NUM = LEFT(P, POSITION(' ' IN P || ' ') - 1);
|
||
REP_DATE = CAST(RIGHT(P, POSITION(' ' IN REVERSE(P)) - 1) AS TIMESTAMP);
|
||
|
||
IF (DIRECTION = 'IN') THEN
|
||
BEGIN
|
||
CMT = 'Перевод M2M (без поручения), GUID ' || GUID || ', референс ' || REFERENCE;
|
||
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, :ACC_D, :CLIENT, :ACC_K, :MARKET,
|
||
NULL, NULL, NULL, :B_TYPE, :REP_DATE, :REP_NUM, :OPER_DATE, :OPER_DATE, :OPER_DATE, 0, :FACE, NULL, :CMT);
|
||
END
|
||
ELSE IF (DIRECTION = 'OUT') THEN
|
||
BEGIN
|
||
CMT = 'Перевод M2M, GUID ' || GUID || ', референс ' || REFERENCE;
|
||
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, :ACC_D, :CLIENT, :ACC_K, :MARKET,
|
||
NULL, NULL, NULL, :B_TYPE, :REP_DATE, :REP_NUM, :OPER_DATE, :OPER_DATE, :OPER_DATE, 0, :FACE, NULL, :CMT);
|
||
END
|
||
|
||
/* Входящая запись (отчёт НРД) */
|
||
FILER_ID = GEN_ID(OD_DOCS_ID_GEN, 1);
|
||
FILER_DATE = CURRENT_TIMESTAMP;
|
||
EXECUTE PROCEDURE FU_NEXT_DOC_NUM ('D_FILER', :FILER_DATE, 1, :FILER_ID) RETURNING_VALUES :FILER_NUM, :NEW_DATE;
|
||
INSERT INTO OD_DOCS (ID, NUM, D_CAT, D_DATE, STATE, DIRECTION, WHOS)
|
||
VALUES (:FILER_ID, :FILER_NUM, :FILER_CAT, :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, :RUBRICA, 'Отчет (перевод через MOEX-МОСТ)', :REP_NUM, :REP_DATE, :CORR_FACE,
|
||
:FACE, :CLIENT, :PLACE, :FILER_DATE, NULL, 'MS010 / ' || :GUID || ' / ' || :REFERENCE);
|
||
|
||
/* Связь входящей записи с операцией */
|
||
STEP_ID = GEN_ID(OD_STEPS_ID_GEN, 1);
|
||
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, CURRENT_TIMESTAMP, NULL);
|
||
|
||
/* И сразу проводим */
|
||
EXECUTE PROCEDURE FTV_M2M_PROCESS_WIRING (:OPER_ID);
|
||
END^
|
||
|
||
|
||
/* Обновление справочника участников сервиса: недостающие юрлица и коды M2M в Fancy, предупреждения о
|
||
двойниках по ИНН и расхождении кодов. Возвращает текст отчёта (пишется в COMMENT события HANDBOOK). */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_UPDATE_HANDBOOK RETURNS (CMT BLOB SUB_TYPE TEXT) AS
|
||
DECLARE VARIABLE M2M_CODER INTEGER;
|
||
DECLARE VARIABLE CNT INTEGER;
|
||
DECLARE VARIABLE FACE_ID INTEGER;
|
||
DECLARE VARIABLE HB_ID INTEGER;
|
||
DECLARE VARIABLE RW INTEGER = 0;
|
||
DECLARE VARIABLE INN VARCHAR(12);
|
||
DECLARE VARIABLE CODE VARCHAR(64);
|
||
DECLARE VARIABLE CODE2 VARCHAR(64);
|
||
DECLARE VARIABLE NAME_SHORT VARCHAR(255);
|
||
DECLARE VARIABLE NAME_FULL VARCHAR(255);
|
||
DECLARE VARIABLE CRLF CHAR(2);
|
||
BEGIN
|
||
CRLF = ASCII_CHAR(13) || ASCII_CHAR(10);
|
||
SELECT FIRST 1 F.SELF_ID FROM OD_FACES F WHERE F.LAST_FLAG = 1 AND F.MNEM = 'M2M' INTO :M2M_CODER;
|
||
IF (M2M_CODER IS NULL) THEN
|
||
EXECUTE PROCEDURE FTV_M2M_FAIL('В Fancy нет кодировщика M2M (OD_FACES с MNEM = ''M2M'')');
|
||
|
||
/* 1. Статистика по участникам */
|
||
SELECT COUNT(*) FROM OD_FACE_CODERS C WHERE C.CODER = :M2M_CODER INTO :CNT;
|
||
CMT = 'УЧАСТНИКИ СЕРВИСА: в справочнике юрлиц Фэнси - ' || CNT;
|
||
SELECT COUNT(*) FROM FTV_M2M_HANDBOOK WHERE ACTIVE = 1 AND PARTICIPANT_CODE IS NOT NULL INTO :CNT;
|
||
CMT = CMT || ', по данным НРД - ' || CNT;
|
||
|
||
/* 2. Принудительно добавляем отсутствующих юрлиц */
|
||
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 F.INN FROM OD_FACES F WHERE F.LAST_FLAG = 1 AND F.E_DATE = '9999-01-01' AND F.INN IS NOT NULL)
|
||
ORDER BY HB.NAME_SHORT
|
||
INTO :HB_ID, :CODE, :INN, :NAME_SHORT, :NAME_FULL DO
|
||
/* один ИНН бывает в справочнике дважды (СПБ Банк — место расчётов и депозитарий): второе юрлицо не создаём,
|
||
код к созданному добавит шаг 3 (в MSSQL-версии — два одинаковых юрлица) */
|
||
IF (NOT EXISTS (SELECT 1 FROM OD_FACES F WHERE F.INN = :INN AND F.LAST_FLAG = 1 AND F.E_DATE = '9999-01-01')) THEN
|
||
BEGIN
|
||
RW = RW + 1;
|
||
FACE_ID = GEN_ID(OD_FACES_ID_GEN, 1);
|
||
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);
|
||
/* у мест расчётов (KIND = 'PLACE') кода участника нет, а OD_FACE_CODERS.CODE — NOT NULL: в MSSQL-версии
|
||
такой справочник падает целиком, если места расчётов ещё нет в юрлицах Fancy */
|
||
IF (CODE IS NOT NULL) THEN
|
||
INSERT INTO OD_FACE_CODERS (CODE, CODER, FACE) VALUES (:CODE, :M2M_CODER, :FACE_ID);
|
||
CMT = CMT || CRLF || RW || '. Добавлено юрлицо: ' || COALESCE(CODE, '') || ', ' || INN || ', ' || COALESCE(NAME_SHORT, '');
|
||
END
|
||
|
||
/* 3. Недостающие коды участников к существующим юрлицам, с предупреждением о двойниках по ИНН
|
||
(в подзапросе ИНН без NULL: иначе NOT IN не находит ни одной строки) */
|
||
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 = '9999-01-01'
|
||
AND C.CODE IS NULL
|
||
AND F.INN NOT IN (SELECT F2.INN FROM OD_FACE_CODERS C2
|
||
JOIN OD_FACES F2 ON F2.SELF_ID = C2.FACE AND F2.LAST_FLAG = 1 AND F2.E_DATE = '9999-01-01'
|
||
WHERE C2.CODER = :M2M_CODER AND F2.INN IS NOT NULL)
|
||
GROUP BY HB.ID, HB.PARTICIPANT_CODE, HB.INN, HB.NAME_SHORT
|
||
ORDER BY HB.NAME_SHORT
|
||
INTO :HB_ID, :CODE, :INN, :NAME_SHORT, :FACE_ID, :CNT DO
|
||
BEGIN
|
||
RW = RW + 1;
|
||
INSERT INTO OD_FACE_CODERS (CODE, CODER, FACE) VALUES (:CODE, :M2M_CODER, :FACE_ID);
|
||
CMT = CMT || CRLF || RW || '. Добавлен код участника ' || CODE || ' к юрлицу: ' || INN || ', ' || COALESCE(NAME_SHORT, '');
|
||
IF (CNT > 1) THEN
|
||
CMT = CMT || ' (ПРЕДУПРЕЖДЕНИЕ: в Фэнси найдено несколько юрлиц с ИНН ' || INN || ')';
|
||
END
|
||
|
||
IF (RW = 0) THEN
|
||
CMT = CMT || ' (при обработке нового справочника НРД никаких изменений не обнаружено)';
|
||
|
||
/* 4. Отличающиеся коды в Fancy и НРД для одного юрлица (по ИНН) или лишние коды в Fancy */
|
||
FOR SELECT F.INN, F.NAME, C.CODE, HB.PARTICIPANT_CODE
|
||
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 = '9999-01-01'
|
||
LEFT JOIN FTV_M2M_HANDBOOK HB ON HB.INN = F.INN AND HB.ACTIVE = 1 AND HB.PARTICIPANT_CODE IS NOT NULL
|
||
WHERE C.CODER = :M2M_CODER
|
||
AND (C.CODE <> HB.PARTICIPANT_CODE OR HB.PARTICIPANT_CODE IS NULL)
|
||
INTO :INN, :NAME_SHORT, :CODE, :CODE2 DO
|
||
BEGIN
|
||
RW = RW + 1;
|
||
IF (CODE2 IS NULL) THEN
|
||
CMT = CMT || CRLF || 'КРИТИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ: для юрлица ' || COALESCE(INN, '?') || ' (' || COALESCE(NAME_SHORT, '') || ') в Фэнси указан код ' || CODE || ', отсутствующий в НРД';
|
||
ELSE
|
||
CMT = CMT || CRLF || 'КРИТИЧЕСКОЕ ПРЕДУПРЕЖДЕНИЕ: для юрлица ' || COALESCE(INN, '?') || ' (' || COALESCE(NAME_SHORT, '') || ') в Фэнси указан код ' || CODE || ', отличающийся от кода в НРД ' || CODE2;
|
||
END
|
||
END^
|
||
|
||
|
||
/* Обработка одного события FTV_M2M_EVENTS. Ссылки — https://lic.zetit.ru/docs/fancy-events */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_PROCESS_EVENTS (ID INTEGER) AS
|
||
DECLARE VARIABLE GUID CHAR(36);
|
||
DECLARE VARIABLE REFERENCE VARCHAR(255);
|
||
DECLARE VARIABLE EVENT_TYPE VARCHAR(64);
|
||
DECLARE VARIABLE EVENT_DATE TIMESTAMP;
|
||
DECLARE VARIABLE M2M_REJECT_CODE VARCHAR(1000);
|
||
DECLARE VARIABLE PARAMETERS VARCHAR(4000);
|
||
DECLARE VARIABLE DIRECTION VARCHAR(64);
|
||
DECLARE VARIABLE CMT BLOB SUB_TYPE TEXT;
|
||
DECLARE VARIABLE SHARE INTEGER;
|
||
DECLARE VARIABLE AMOUNT NUMERIC(18,7);
|
||
DECLARE VARIABLE PLACE INTEGER;
|
||
DECLARE VARIABLE CLIENT INTEGER;
|
||
DECLARE VARIABLE FACE INTEGER;
|
||
DECLARE VARIABLE CLISER_ID INTEGER;
|
||
DECLARE VARIABLE DOL_ID INTEGER;
|
||
DECLARE VARIABLE DD_DATE TIMESTAMP;
|
||
DECLARE VARIABLE DD_NUM VARCHAR(64);
|
||
DECLARE VARIABLE OPER_ID INTEGER;
|
||
DECLARE VARIABLE ST INTEGER;
|
||
DECLARE VARIABLE EV_S VARCHAR(19);
|
||
DECLARE VARIABLE NOW_S VARCHAR(19);
|
||
BEGIN
|
||
SELECT FIRST 1 ME.GUID, ME.REFERENCE, ME.EVENT_TYPE, ME.EVENT_DATE, ME.M2M_REJECT_CODE, ME.PARAMETERS, M.DIRECTION,
|
||
H.DOC, F.DOL, D.D_DATE, D.NUM, F.SHARE, F.AMOUNT, F.PLACE, F.CLIENT, H.DEPONENT
|
||
FROM FTV_M2M_EVENTS ME
|
||
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
|
||
INTO :GUID, :REFERENCE, :EVENT_TYPE, :EVENT_DATE, :M2M_REJECT_CODE, :PARAMETERS, :DIRECTION,
|
||
:CLISER_ID, :DOL_ID, :DD_DATE, :DD_NUM, :SHARE, :AMOUNT, :PLACE, :CLIENT, :FACE;
|
||
|
||
/* 1. Обновление справочника участников сервиса */
|
||
IF (EVENT_TYPE = 'HANDBOOK') THEN
|
||
BEGIN
|
||
EXECUTE PROCEDURE FTV_M2M_UPDATE_HANDBOOK RETURNING_VALUES :CMT;
|
||
UPDATE FTV_M2M_EVENTS SET COMMENT = :CMT WHERE ID = :ID;
|
||
EXIT;
|
||
END
|
||
|
||
/* 1a. BJ_PING — проверочное событие bj (без GUID и REFERENCE): отметить обработанным, документ не трогать */
|
||
IF (EVENT_TYPE = 'BJ_PING') THEN EXIT;
|
||
|
||
/* 2. Критические ошибки */
|
||
IF (GUID IS NULL) THEN EXECUTE PROCEDURE FTV_M2M_FAIL('Не указан GUID');
|
||
IF (REFERENCE IS NULL) THEN EXECUTE PROCEDURE FTV_M2M_FAIL('Не указан REFERENCE');
|
||
IF (DOL_ID IS NULL) THEN EXECUTE PROCEDURE FTV_M2M_FAIL('Не найдена строка M2M-поручения по GUID + REFERENCE');
|
||
|
||
/* 3. Признак документа */
|
||
EXECUTE PROCEDURE FTV_M2M_DT(:EVENT_DATE) RETURNING_VALUES :EV_S;
|
||
EXECUTE PROCEDURE FTV_M2M_DT(CURRENT_TIMESTAMP) RETURNING_VALUES :NOW_S;
|
||
INSERT INTO OD_INVALIDS (DOC, STATUS, COMMENT, DO_ING)
|
||
VALUES (:CLISER_ID, 0,
|
||
:EV_S || ' - ' || :EVENT_TYPE || COALESCE(' (референс - ' || :REFERENCE || ')', '') || COALESCE(' (параметры - ' || :PARAMETERS || ')', ''),
|
||
'Время начала обработки: ' || :NOW_S);
|
||
|
||
/* 4. Обработка каждого типа события. ID = 0 в UPDATE OD_DOCS — служебное изменение Fancy (триггер оставляет
|
||
прежний ID и не проверяет права оператора). */
|
||
IF (EVENT_TYPE = 'BJ_RECEIVED') THEN
|
||
UPDATE OD_DOCS SET ID = 0, STATE = 1 WHERE ID = :CLISER_ID; /* START — начало обработки */
|
||
ELSE IF (EVENT_TYPE = 'BJ_SENT') THEN
|
||
BEGIN
|
||
ST = NULL;
|
||
SELECT FIRST 1 S.ID FROM OD_DOC_STATES S WHERE S.SYS_NAME = 'WAIT_RESP_DECIS' INTO :ST;
|
||
UPDATE OD_DOCS SET ID = 0, STATE = :ST WHERE ID = :CLISER_ID; /* ожидание ответа Response/Decision */
|
||
END
|
||
ELSE IF (EVENT_TYPE IN ('BJ_DECISION_CONFIRM', 'BJ_CP_CONFIRM')) THEN
|
||
UPDATE OD_DOCS SET ID = 0, STATE = 8 WHERE ID = :CLISER_ID; /* RECIEVED — принят, ожидает обработки */
|
||
ELSE IF (EVENT_TYPE IN ('BJ_DECISION_REJECT', 'BJ_CP_REJECT')) THEN
|
||
UPDATE OD_DOCS SET ID = 0, STATE = 3 WHERE ID = :CLISER_ID; /* REJECT — отмена обработки */
|
||
ELSE IF (EVENT_TYPE = 'BJ_SERVICE_ERROR') THEN
|
||
UPDATE OD_DOCS SET ID = 0, STATE = 3 WHERE ID = :CLISER_ID;
|
||
ELSE IF (EVENT_TYPE = 'BJ_ORDER_SENT') THEN
|
||
BEGIN
|
||
ST = NULL;
|
||
SELECT FIRST 1 S.ID FROM OD_DOC_STATES S WHERE S.SYS_NAME = 'WAIT_OPER' INTO :ST;
|
||
UPDATE OD_DOCS SET ID = 0, STATE = :ST WHERE ID = :CLISER_ID; /* ожидание исполнения операции */
|
||
END
|
||
ELSE IF (EVENT_TYPE = 'BJ_ORDER_ACCEPTED') THEN
|
||
BEGIN
|
||
EXECUTE PROCEDURE FTV_M2M_PROCESS_OPERATION (:GUID, :REFERENCE, :EVENT_DATE, :PARAMETERS) RETURNING_VALUES :OPER_ID;
|
||
UPDATE OD_DOCS SET ID = 0, STATE = 2 WHERE ID = :CLISER_ID; /* FINAL — конец обработки */
|
||
END
|
||
ELSE IF (EVENT_TYPE = 'BJ_EXECUTED') THEN
|
||
EXIT; /* уже исполнено по BJ_ORDER_ACCEPTED */
|
||
ELSE IF (EVENT_TYPE = 'BJ_CANCELLED') THEN
|
||
UPDATE OD_DOCS SET ID = 0, STATE = 3 WHERE ID = :CLISER_ID;
|
||
ELSE IF (EVENT_TYPE = 'BJ_GATEWAY_REJECT') THEN
|
||
UPDATE OD_DOCS SET ID = 0, STATE = 3 WHERE ID = :CLISER_ID;
|
||
ELSE IF (EVENT_TYPE IN ('BJ_ORDER_LATE', 'BJ_QUIK_BLOCKED', 'BJ_QUIK_RELEASED', 'BJ_QUIK_SIGNED', 'BJ_QUIK_DEPOSITED')) THEN
|
||
EXIT; /* ничего не делать */
|
||
ELSE
|
||
EXECUTE PROCEDURE FTV_M2M_FAIL('От сервиса BJ получено неизвестное событие ' || EVENT_TYPE);
|
||
END^
|
||
|
||
|
||
/* Создаёт M2M-поручение вместе с подвалом документа по записи FTV_M2M. */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_PROCESS_CREATE (ID INTEGER) AS
|
||
DECLARE VARIABLE WHOS INTEGER;
|
||
DECLARE VARIABLE FILER_CAT INTEGER;
|
||
DECLARE VARIABLE GUID CHAR(36);
|
||
DECLARE VARIABLE DIRECTION VARCHAR(64);
|
||
DECLARE VARIABLE CONTRAGENT_M2M_CODE VARCHAR(255);
|
||
DECLARE VARIABLE DEPONENT_NAME VARCHAR(255);
|
||
DECLARE VARIABLE DEPONENT_DOC VARCHAR(255);
|
||
DECLARE VARIABLE REFERENCE VARCHAR(36);
|
||
DECLARE VARIABLE ISIN VARCHAR(12);
|
||
DECLARE VARIABLE SEC_CODE VARCHAR(255);
|
||
DECLARE VARIABLE AMOUNT NUMERIC(18,7);
|
||
DECLARE VARIABLE PLACE_NUMBER VARCHAR(255);
|
||
DECLARE VARIABLE LINK_NUMBER VARCHAR(128);
|
||
DECLARE VARIABLE DEPO_NUMBER VARCHAR(128);
|
||
DECLARE VARIABLE D_CAT INTEGER;
|
||
DECLARE VARIABLE NUM VARCHAR(255);
|
||
DECLARE VARIABLE NEW_DATE TIMESTAMP;
|
||
DECLARE VARIABLE D_DATE TIMESTAMP;
|
||
DECLARE VARIABLE CONTRAGENT INTEGER;
|
||
DECLARE VARIABLE DEPONENT INTEGER;
|
||
DECLARE VARIABLE SHARE INTEGER;
|
||
DECLARE VARIABLE PLACE INTEGER;
|
||
DECLARE VARIABLE DEPO INTEGER;
|
||
DECLARE VARIABLE CLISER_ID INTEGER;
|
||
DECLARE VARIABLE FILER_ID INTEGER;
|
||
DECLARE VARIABLE FILER_NUM VARCHAR(255);
|
||
DECLARE VARIABLE FILER_DATE TIMESTAMP;
|
||
DECLARE VARIABLE DOL_ID INTEGER;
|
||
DECLARE VARIABLE D_DAY TIMESTAMP;
|
||
BEGIN
|
||
EXECUTE PROCEDURE FTV_M2M_GET('WHOS') RETURNING_VALUES :WHOS;
|
||
|
||
SELECT M.GUID, M.DIRECTION, M.CONTRAGENT_M2M_CODE, M.DEPONENT_NAME, M.DEPONENT_DOC FROM FTV_M2M M WHERE M.ID = :ID
|
||
INTO :GUID, :DIRECTION, :CONTRAGENT_M2M_CODE, :DEPONENT_NAME, :DEPONENT_DOC;
|
||
|
||
/* 1.1. Неуникальный GUID */
|
||
IF (EXISTS (SELECT 1 FROM D_CLISER_M2M WHERE DOC_GUID = :GUID)) THEN
|
||
EXECUTE PROCEDURE FTV_M2M_FAIL('Неуникальный GUID');
|
||
|
||
/* 1.2. Направление перевода */
|
||
IF (DIRECTION = 'IN') THEN
|
||
SELECT FIRST 1 C.ID FROM OD_DOC_CATS C WHERE C.SYS_NAME = 'I_CLISER_M2M_ZACH' INTO :D_CAT;
|
||
ELSE IF (DIRECTION = 'OUT') THEN
|
||
SELECT FIRST 1 C.ID FROM OD_DOC_CATS C WHERE C.SYS_NAME = 'I_CLISER_M2M_SPIS' INTO :D_CAT;
|
||
ELSE
|
||
EXECUTE PROCEDURE FTV_M2M_FAIL('Ошибочное направление DIRECTION (должно быть IN, OUT)');
|
||
|
||
/* 1.3. Контрагент */
|
||
SELECT FIRST 1 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
|
||
INTO :CONTRAGENT;
|
||
IF (CONTRAGENT IS NULL) THEN
|
||
EXECUTE PROCEDURE FTV_M2M_FAIL('Не найден депозитарий-контрагент');
|
||
|
||
/* 1.4. Депонент (как в MSSQL-версии: не найден — поручение создаётся без депонента) */
|
||
SELECT FIRST 1 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, ' ', '')
|
||
INTO :DEPONENT;
|
||
|
||
/* 1.5. Шапка документа */
|
||
CLISER_ID = GEN_ID(OD_DOCS_ID_GEN, 1);
|
||
D_DATE = CURRENT_TIMESTAMP;
|
||
EXECUTE PROCEDURE FU_NEXT_DOC_NUM (:D_CAT, :D_DATE, NULL, :CLISER_ID) RETURNING_VALUES :NUM, :NEW_DATE;
|
||
|
||
INSERT INTO OD_DOCS (ID, NUM, PARAM, D_CAT, D_DATE, STATE, DIRECTION, WHOS, KVIT)
|
||
VALUES (: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)
|
||
VALUES (:CLISER_ID, :DEPONENT, :GUID, 0, 0, NULL, NULL, NULL);
|
||
IF (DIRECTION = 'IN') THEN
|
||
INSERT INTO OD_IN_DOCS (DOC, FROM_FACE, PASS_KIND) VALUES (:CLISER_ID, :CONTRAGENT, 8);
|
||
ELSE
|
||
INSERT INTO OD_OUT_DOCS (DOC, TO_FACE, PASS_KIND) VALUES (:CLISER_ID, :CONTRAGENT, 8);
|
||
|
||
/* 1.6. Обогащаем FTV_M2M */
|
||
UPDATE FTV_M2M SET DOC = :CLISER_ID, CONTRAGENT = :CONTRAGENT, DEPONENT = :DEPONENT WHERE GUID = :GUID;
|
||
|
||
/* 1.7. Подвал документа */
|
||
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
|
||
INTO :REFERENCE, :ISIN, :SEC_CODE, :AMOUNT, :PLACE_NUMBER, :LINK_NUMBER, :DEPO_NUMBER DO
|
||
BEGIN
|
||
SHARE = NULL; PLACE = NULL; DEPO = NULL;
|
||
|
||
/* Бумага */
|
||
SELECT FIRST 1 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
|
||
INTO :SHARE;
|
||
|
||
/* Счёт места хранения */
|
||
SELECT FIRST 1 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
|
||
INTO :PLACE;
|
||
|
||
/* Счёт клиента */
|
||
SELECT FIRST 1 C.ID FROM OD_CLIENTS C WHERE C.NUMBER = :DEPO_NUMBER INTO :DEPO;
|
||
|
||
DOL_ID = GEN_ID(OD_DOLS_ID_GEN, 1);
|
||
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);
|
||
|
||
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
|
||
|
||
/* 1.8. Входящая запись — только для списания (исходящий перевод OUT) */
|
||
IF (DIRECTION = 'OUT') THEN
|
||
BEGIN
|
||
EXECUTE PROCEDURE FTV_M2M_GET('FILER_CAT') RETURNING_VALUES :FILER_CAT;
|
||
FILER_ID = GEN_ID(OD_DOCS_ID_GEN, 1);
|
||
FILER_DATE = CURRENT_TIMESTAMP;
|
||
EXECUTE PROCEDURE FU_NEXT_DOC_NUM ('D_FILER', :FILER_DATE, 1, :FILER_ID) RETURNING_VALUES :FILER_NUM, :NEW_DATE;
|
||
EXECUTE PROCEDURE FTV_M2M_DAY(:D_DATE) RETURNING_VALUES :D_DAY;
|
||
INSERT INTO OD_DOCS (ID, NUM, D_CAT, D_DATE, STATE, DIRECTION, WHOS)
|
||
VALUES (:FILER_ID, :FILER_NUM, :FILER_CAT, :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, 7, 8, 'M2M поручение на списание через MOEX-МОСТ', :NUM, :D_DAY, :DEPONENT, :DEPONENT,
|
||
:DEPO, :PLACE, :FILER_DATE, :D_CAT, :GUID);
|
||
/* Связываем с M2M-поручением */
|
||
UPDATE OD_DOCS SET ID = 0, KVIT = :FILER_ID WHERE ID = :CLISER_ID;
|
||
END
|
||
END^
|
||
|
||
|
||
/* Запуск обработки: новые поручения (FTV_M2M) и события (FTV_M2M_EVENTS) со STATE = 'TODO'. Вызывает bj
|
||
(в Firebird нет SQL Server Agent). Ошибка одной записи не останавливает остальные. */
|
||
CREATE OR ALTER PROCEDURE FTV_M2M_JOB AS
|
||
DECLARE VARIABLE ID INTEGER;
|
||
DECLARE VARIABLE ST VARCHAR(64);
|
||
DECLARE VARIABLE CMT VARCHAR(1000);
|
||
DECLARE VARIABLE R INTEGER;
|
||
BEGIN
|
||
/* НОВЫЕ ПОРУЧЕНИЯ */
|
||
FOR SELECT M.ID FROM FTV_M2M M WHERE M.STATE = 'TODO' ORDER BY M.TIMENEW, M.ID INTO :ID DO
|
||
BEGIN
|
||
UPDATE FTV_M2M SET TIMEBEG = CURRENT_TIMESTAMP WHERE ID = :ID;
|
||
ST = 'SUCCESS'; CMT = NULL;
|
||
R = RDB$SET_CONTEXT('USER_TRANSACTION', 'FTV_M2M_ERR', NULL);
|
||
BEGIN
|
||
EXECUTE PROCEDURE FTV_M2M_PROCESS_CREATE (:ID);
|
||
WHEN ANY DO
|
||
BEGIN
|
||
ST = 'ERROR';
|
||
CMT = COALESCE(CAST(RDB$GET_CONTEXT('USER_TRANSACTION', 'FTV_M2M_ERR') AS VARCHAR(255) CHARACTER SET WIN1251), 'ошибка Fancy') || ' // FTV_M2M_PROCESS_CREATE // SQLCODE ' || SQLCODE || ', GDSCODE ' || GDSCODE;
|
||
END
|
||
END
|
||
UPDATE FTV_M2M SET STATE = :ST, TIMEEND = CURRENT_TIMESTAMP, COMMENT = :CMT WHERE ID = :ID;
|
||
END
|
||
|
||
/* НОВЫЕ СОБЫТИЯ */
|
||
FOR SELECT E.ID FROM FTV_M2M_EVENTS E WHERE E.STATE = 'TODO' ORDER BY E.TIMENEW, E.ID INTO :ID DO
|
||
BEGIN
|
||
UPDATE FTV_M2M_EVENTS SET TIMEBEG = CURRENT_TIMESTAMP WHERE ID = :ID;
|
||
ST = 'SUCCESS'; CMT = NULL;
|
||
R = RDB$SET_CONTEXT('USER_TRANSACTION', 'FTV_M2M_ERR', NULL);
|
||
BEGIN
|
||
EXECUTE PROCEDURE FTV_M2M_PROCESS_EVENTS (:ID);
|
||
WHEN ANY DO
|
||
BEGIN
|
||
ST = 'ERROR';
|
||
CMT = COALESCE(CAST(RDB$GET_CONTEXT('USER_TRANSACTION', 'FTV_M2M_ERR') AS VARCHAR(255) CHARACTER SET WIN1251), 'ошибка Fancy') || ' // FTV_M2M_PROCESS_EVENTS // SQLCODE ' || SQLCODE || ', GDSCODE ' || GDSCODE;
|
||
END
|
||
END
|
||
/* без ошибки COMMENT не трогаем: в нём отчёт справочника (HANDBOOK) */
|
||
IF (CMT IS NOT NULL) THEN
|
||
UPDATE FTV_M2M_EVENTS SET STATE = :ST, TIMEEND = CURRENT_TIMESTAMP, COMMENT = :CMT WHERE ID = :ID;
|
||
ELSE
|
||
UPDATE FTV_M2M_EVENTS SET STATE = :ST, TIMEEND = CURRENT_TIMESTAMP WHERE ID = :ID;
|
||
END
|
||
END^
|
||
|
||
SET TERM ; ^
|
||
|
||
COMMIT;
|