Files
sap-legacy-webhook-emulator/sql/transaction-notification/sp-webhook-capture-event-mssql.sql
T

98 lines
4.3 KiB
Transact-SQL
Raw Normal View History

2026-09-16 08:30:45 -05:00
-- SP_Webhook_CaptureEvent — SQL Server / T-SQL
--
-- Toda la lógica de captura del emulador vive acá, en un procedimiento
-- propio y con nombre descriptivo — no directamente en el cuerpo de
-- SBO_SP_PostTransactionNotice (ver mssql.sql), que es un hook compartido
-- de SAP donde puede convivir código de otros add-ons. Así el nuestro
-- queda identificable y fácil de mantener o remover por separado.
--
-- Requiere que la UserTable "@OEVN" ya exista (creada por
-- `npm run provision`, ver src/provisioning/).
--
-- U_UserID: no se completa. SUSER_SNAME() da el login de la conexión a SQL
-- Server (una cuenta técnica), no el usuario real de SAP que hizo la
-- transacción — confirmado equivalente en HANA (CURRENT_USER, ver
-- sp-webhook-capture-event-hana.sql). 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.
--
-- 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 TRY/CATCH).
--
-- 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 NO se inserta nada
-- cuando el ObjectType matchea ese patrón para una de nuestras 4 tablas
-- (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).
CREATE OR ALTER PROCEDURE [dbo].[SP_Webhook_CaptureEvent]
@object_type NVARCHAR(20),
@transaction_type NCHAR(1),
@num_of_cols_in_key INT,
@list_of_key_cols_tab_del NVARCHAR(255),
@list_of_cols_val_tab_del NVARCHAR(255),
@error INT OUTPUT,
@error_message NVARCHAR(200) OUTPUT
AS
BEGIN
SET @error = 0
SET @error_message = N'Ok'
DECLARE @code NVARCHAR(36) = CONVERT(NVARCHAR(36), NEWID())
DECLARE @isOwnTableEcho BIT = CASE
WHEN @object_type LIKE '-%' + CHAR(9) + '@OEVC' THEN 1
WHEN @object_type LIKE '-%' + CHAR(9) + '@EVC1' THEN 1
WHEN @object_type LIKE '-%' + CHAR(9) + '@OEVN' THEN 1
WHEN @object_type LIKE '-%' + CHAR(9) + '@EVN1' THEN 1
ELSE 0
END
DECLARE @hasActiveSubscription BIT = CASE WHEN EXISTS (
SELECT 1
FROM [dbo].[@EVC1] f
INNER JOIN [dbo].[@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'
) THEN 1 ELSE 0 END
-- Solo inserta si no es un eco de nuestras propias tablas (arriba) y
-- si hay una suscripción activa interesada en este ObjectType+TransType.
IF @isOwnTableEcho = 0 AND @hasActiveSubscription = 1
BEGIN
BEGIN TRY
INSERT INTO [dbo].[@OEVN] (
Code, Name,
U_SourceDB, U_Status, U_ObjectType, U_TransType,
U_FieldsInKe, U_FieldNames, U_FieldValue, U_ReplayStat
) VALUES (
@code, @code,
DB_NAME(), 'N', @object_type, @transaction_type,
@num_of_cols_in_key, @list_of_key_cols_tab_del, @list_of_cols_val_tab_del, 'N'
)
END TRY
BEGIN CATCH
SET @error = ERROR_NUMBER()
SET @error_message = LEFT(ERROR_MESSAGE(), 200)
END CATCH
END
END
GO