Initial commit: sap-legacy-webhook-emulator
Reconstruye el Webhook Messenger nativo de SAP B1 (FP2605) para clientes que aun no estan en esa version: captura eventos via SBO_SP_PostTransactionNotice, provisiona UserTables OEVC/EVC1/OEVN/EVN1 y despacha CloudEvents al mismo endpoint que el messenger real. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
commit
e1c8ee9015
42 files changed
+4042
No files matched your search
@@ -0,0 +1,103 @@
|
||||
-- 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;
|
||||
Reference in new issue
Block a user