Files
Bridge-and-Join-s/deploy/depo/fancy-m2m-firebird/10_FTV_M2M_PROCS.sql
T
fontvielle 56efa9266c DEPO: основание операции M2M — номер и дата отчёта НРД (правка программиста 24.10 с боя)
FTV_M2M_PROCESS_OPERATION: B_NUM/B_DATE операции зачисления/списания берутся из PARAMETERS
события BJ_ORDER_ACCEPTED («<номер> от <дд.мм.гггг>», отчёт НРД), а не из M2M-поручения;
комментарий операции без «Отчет НКО АО НРД …». Текст снят с тестовой DEPO (там та же правка
24.10 00:04, на боевой — 24.10 00:02; логину bj текст на боевой не виден). Без переноса
повторная установка процедур из bj вернула бы старый текст.

Firebird-версия — та же правка; прогон на заглушках: изменилось только основание и комментарий.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn
2026-10-26 15:34:16 +03:00

628 lines
34 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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 ненайденное значение
оставалось от предыдущей строки).
Порядок создания: вспомогательные → 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^
/* Директива «Обработать» для документа «Зачисление» или «Списание». Значения берутся только из самого
документа; 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 DATE;
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 DATE;
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,
CAST(D.D_DATE AS 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');
/* Направление */
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_DOC_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 DATE);
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_DOC_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
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);
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 DATE;
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, CAST(D.D_DATE AS 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;
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_DOC_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_DOL_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_DOC_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, 7, 8, 'M2M поручение на списание через MOEX-МОСТ', :NUM, CAST(:D_DATE AS DATE), :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;