-- SP_Webhook_CaptureEvent — SAP HANA / SQLScript -- -- Equivalente HANA de sp-webhook-capture-event-mssql.sql: toda la lógica -- de captura vive acá, no en el cuerpo de SBO_SP_PostTransactionNotice -- (hook compartido de SAP, ver recreate_sbo_sp_posttransactionnotice_hana.sql). -- -- Requiere que la UserTable "@OEVN" ya exista (creada por -- `npm run provision`, ver src/provisioning/). -- -- ✅ Verificado contra un HANA real (SAP Business One), instalado y -- funcionando — incluida la sintaxis del EXIT HANDLER y el filtro de eco -- (INSERT...SELECT...WHERE, más abajo): se confirmó que un DELETE vía -- Service Layer sobre una fila de @OEVN ya no genera ningún eco nuevo. -- ⚠️ El filtro por suscripción activa (EXISTS contra @EVC1/@OEVC, más -- abajo) es nuevo y todavía NO se probó contra ese ambiente. -- -- U_UserID: no se completa. CURRENT_USER da el usuario de la conexión a -- HANA (una cuenta técnica), no el usuario real de SAP que hizo la -- transacción — confirmado contra este mismo ambiente. Ninguno de los 5 -- parámetros que recibe el hook trae ese dato, así que por ahora el campo -- queda sin poblar en las dos variantes (ver también mssql.sql). -- -- Name: en una UserTable de SAP, "Name" también debe ser único (no solo -- "Code") — confirmado contra Service Layer real (ODBC -2035 al repetir -- un Name, con Code distinto). Por eso Name usa el mismo UUID que Code: -- cualquier otro valor (como el propio ObjectType) se repite entre -- eventos del mismo tipo y hace fallar el INSERT en el segundo evento -- (en silencio, por el EXIT HANDLER). -- -- Eco de nuestras propias escrituras: cualquier POST/PATCH/DELETE que -- hace el dispatcher sobre @OEVC/@EVC1/@OEVN/@EVN1 vía Service Layer -- dispara este mismo hook de nuevo, con un ObjectType especial de SAP -- para "operación genérica sobre una UserTable simple": un código -- negativo + tab + nombre físico de la tabla (confirmado real: -- "-3\t@OEVN" para un DELETE). Si insertáramos esa fila iba a generar -- otro eco al borrarla, indefinidamente — por eso el INSERT usa -- SELECT...FROM DUMMY WHERE en vez de VALUES, para poder filtrar el -- ObjectType sin agregar una rama procedural nueva (ver docs/DISENO.md, -- hallazgo 5). -- -- Filtro por suscripción activa: además de lo anterior, solo se inserta -- si existe al menos una fila en @EVC1 (con su @OEVC en State='A') para -- este ObjectType+TransType exacto. No es "lógica de negocio propia" del -- SP — consulta la misma tabla de configuración que ya es la fuente de -- verdad para el dispatcher, no una copia/lista fija a mantener -- sincronizada. Evita ensuciar @OEVN con todo lo que SAP genera y a -- nadie le interesa (en el ambiente de prueba, cientos de eventos por -- minuto sin ninguna suscripción real). DROP PROCEDURE "SP_Webhook_CaptureEvent"; CREATE PROCEDURE "SP_Webhook_CaptureEvent" ( IN object_type NVARCHAR(20), IN transaction_type NVARCHAR(1), IN num_of_cols_in_key INTEGER, IN list_of_key_cols_tab_del NVARCHAR(255), IN list_of_cols_val_tab_del NVARCHAR(255), OUT error INTEGER, OUT error_message NVARCHAR(200) ) LANGUAGE SQLSCRIPT AS BEGIN DECLARE v_code NVARCHAR(36); DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN error := ::SQL_ERROR_CODE; error_message := SUBSTR(::SQL_ERROR_MESSAGE, 1, 200); END; error := 0; error_message := N'Ok'; -- Sin condiciones de negocio: inserta siempre, salvo que sea un eco -- de una escritura nuestra sobre estas mismas 4 tablas (arriba). SELECT SYSUUID INTO v_code FROM DUMMY; INSERT INTO "@OEVN" ( "Code", "Name", "U_SourceDB", "U_Status", "U_ObjectType", "U_TransType", "U_FieldsInKe", "U_FieldNames", "U_FieldValue", "U_ReplayStat" ) SELECT :v_code, :v_code, CURRENT_SCHEMA, 'N', :object_type, :transaction_type, :num_of_cols_in_key, :list_of_key_cols_tab_del, :list_of_cols_val_tab_del, 'N' FROM DUMMY WHERE NOT ( :object_type LIKE '-%' || CHAR(9) || '@OEVC' OR :object_type LIKE '-%' || CHAR(9) || '@EVC1' OR :object_type LIKE '-%' || CHAR(9) || '@OEVN' OR :object_type LIKE '-%' || CHAR(9) || '@EVN1' ) AND EXISTS ( SELECT 1 FROM "@EVC1" f INNER JOIN "@OEVC" s ON s."Code" = f."U_WebhookID" WHERE f."U_ObjectType" = :object_type AND f."U_TransType" = :transaction_type AND s."U_State" = 'A' ); END;