Initial commit: sap-webhook-api
API NestJS que recibe el Webhook Messenger de SAP Business One (CloudEvents), valida HMAC opcional y guarda cada notificacion local (data/events/) e inserta en Postgres (webhook_events). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
commit
5e0df73477
28 files changed
+11773
No files matched your search
@@ -0,0 +1,78 @@
|
||||
# Del alta de una Orden al archivo JSON
|
||||
|
||||
Cómo viaja un evento de SAP Business One hasta quedar guardado en disco por
|
||||
`sap-webhook-api`: los dos servidores involucrados, sus componentes,
|
||||
puertos e IPs de ejemplo, y dónde entra en juego el certificado
|
||||
autofirmado.
|
||||
|
||||
## Diagrama
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph SAP["SAP Business One — servidor Windows · 192.168.1.205"]
|
||||
direction TB
|
||||
SL["Service Layer\nsap10:50000\nLogin · EventSubscriptions\ncert propio autofirmado"]
|
||||
SQL["SQL Server (MSSQL)\nDB: SBODemoCL\nTablas: OEVC · OEVN · EVN1\nlogin: sa"]
|
||||
WM["Webhook Messenger\npuerto 40008\nWebhookMessenger.jar\nDEFAULT_LANGUAGE=us_english (workaround)"]
|
||||
SL <-->|"Login / EventSubscriptions"| SQL
|
||||
SQL <-->|"SELECT/UPDATE OEVN, EVN1 (login sa)"| WM
|
||||
end
|
||||
|
||||
subgraph MAC["Mac de desarrollo · 192.168.1.166"]
|
||||
direction TB
|
||||
CFG["Configuración\ncurl / sl.http"]
|
||||
API["sap-webhook-api (NestJS)\n192.168.1.166:3000\nPOST /webhooks/sap\ncert CN/SAN=192.168.1.166"]
|
||||
FS["data/events/*.json\n1 archivo por notificación"]
|
||||
API -->|guarda| FS
|
||||
end
|
||||
|
||||
CFG -- "HTTPS :50000\nLogin, EventSubscriptions" --> SL
|
||||
WM -- "HTTPS :3000\nCloudEvents batch\nPOST /webhooks/sap" --> API
|
||||
|
||||
classDef warn fill:#faf0dd,stroke:#a8690b,color:#7a4c08;
|
||||
class WM warn
|
||||
```
|
||||
|
||||
Dos servidores en la misma LAN. La Mac llama al Service Layer para
|
||||
configurar la suscripción (flecha superior); el Webhook Messenger — que
|
||||
corre dentro del servidor SAP y lee la cola de eventos en SQL Server
|
||||
autenticado como `sa` — es quien llama de vuelta a la Mac para entregar
|
||||
cada evento (flecha inferior). El recuadro en ámbar marca el workaround de
|
||||
`DATEFORMAT` aplicado para que esa segunda flecha funcione.
|
||||
|
||||
## Componentes e IPs de ejemplo
|
||||
|
||||
| Componente | Host : puerto | Protocolo | Notas |
|
||||
|---|---|---|---|
|
||||
| **Service Layer** (SAP Business One) | `sap10 : 50000` | HTTPS | Certificado propio autofirmado; nuestras llamadas lo ignoran con `curl -k`. |
|
||||
| **Webhook Messenger** (servicio Windows) | `192.168.1.205 : 40008` | TCP (health) + JDBC a SQL Server | Se conecta a SQL Server como `sa`; despacha los eventos por HTTPS hacia el `WebhookURL` suscripto. |
|
||||
| **SQL Server** (MSSQL) | — (interno) | TDS | DB `SBODemoCL`. Tablas `OEVC` / `OEVN` / `EVN1`. |
|
||||
| **sap-webhook-api** (NestJS) | `192.168.1.166 : 3000` | HTTPS | Certificado autofirmado propio, `CN/SAN = 192.168.1.166`. |
|
||||
| **data/events/** (filesystem local) | — (disco) | — | Un archivo `.json` por notificación recibida. |
|
||||
|
||||
## 🔐 Certificado autofirmado
|
||||
|
||||
Generado en la Mac para `CN/SAN = 192.168.1.166` — la IP donde corre
|
||||
`sap-webhook-api`, no la del servidor SAP.
|
||||
|
||||
Ese nombre **tiene que coincidir** con el host que se declara como
|
||||
`WebhookURL` al crear la suscripción
|
||||
(`https://192.168.1.166:3000/webhooks/sap`). Como la suscripción usa
|
||||
`VerifyCertificate: tNO`, SAP nunca valida este certificado — si más
|
||||
adelante se activa la verificación, hay que importarlo además en el
|
||||
keystore del propio Webhook Messenger.
|
||||
|
||||
## 🟠 Estado del bug de fechas
|
||||
|
||||
El Webhook Messenger construye el SQL contra `OEVN` con la fecha como
|
||||
texto plano. Con el login `sa` en idioma `Español` (`DATEFORMAT dmy`),
|
||||
cualquier día del mes mayor a 12 rompía la consulta.
|
||||
|
||||
Workaround confirmado en este ambiente de desarrollo: cambiar `sa` a
|
||||
`DEFAULT_LANGUAGE = us_english` y reiniciar el servicio. Sigue pendiente
|
||||
confirmar si `FP2605 HFX1` lo corrige oficialmente.
|
||||
|
||||
---
|
||||
|
||||
Detalle completo del diagnóstico, la evidencia y los pasos de instalación
|
||||
en `CLAUDE.md` y `PASOS-REALIZADOS.md` de este repositorio.
|
||||
Binary file not shown.
@@ -0,0 +1,114 @@
|
||||
# Cómo ejecutar la API (con y sin HMAC)
|
||||
|
||||
Guía rápida para levantar `sap-webhook-api` en los dos modos soportados:
|
||||
sin autenticación (`AuthenticationType: None`, el modo actual de la
|
||||
suscripción real en SAP) y con firma HMAC.
|
||||
|
||||
## 0. Una sola vez: preparar el entorno
|
||||
|
||||
```bash
|
||||
cd sap-webhook-api
|
||||
npm install
|
||||
cp .env.example .env # si todavía no existe .env
|
||||
```
|
||||
|
||||
Revisá que `.env` tenga los datos correctos de tu Service Layer
|
||||
(`SERVICE_LAYER_URL`, `COMPANY_DB`, `SL_USER`, `SL_PASS`, `WEBHOOK_ID`). El
|
||||
certificado HTTPS (`certs/key.pem` / `certs/cert.pem`) ya debería existir —
|
||||
si no, ver `PASOS-REALIZADOS.md`, sección 9.
|
||||
|
||||
**Importante**: el modo con el que arranca la API (`.env` →
|
||||
`HMAC_SECRET_KEY`) tiene que coincidir con el `AuthenticationType`
|
||||
configurado en la suscripción real de SAP. Si no coinciden, SAP manda
|
||||
notificaciones que la API rechaza (o al revés, la API acepta sin validar
|
||||
nada aunque SAP crea que está firmando). Los scripts de la sección 2 se
|
||||
encargan de mantenerlos sincronizados.
|
||||
|
||||
## 1. Modo sin autenticación (`AuthenticationType: None`)
|
||||
|
||||
Es el modo por defecto — no requiere ningún paso extra.
|
||||
|
||||
```bash
|
||||
# confirmá que HMAC_SECRET_KEY esté vacío en .env
|
||||
npm run start
|
||||
```
|
||||
|
||||
La API queda escuchando en `https://<tu-ip>:3000/webhooks/sap`, acepta
|
||||
cualquier notificación sin validar firma. Prueba local:
|
||||
|
||||
```bash
|
||||
curl -sk -i -X POST https://localhost:3000/webhooks/sap \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '[{"id":"test-1","type":"sap.b1.Orders.Created.v1","subject":"1","data":{"DocEntry":"1"}}]'
|
||||
# -> 200 OK
|
||||
```
|
||||
|
||||
## 2. Modo con HMAC (`AuthenticationType: HMAC`)
|
||||
|
||||
### 2.1 Activar
|
||||
|
||||
```bash
|
||||
npm run auth:hmac:on
|
||||
```
|
||||
|
||||
Esto:
|
||||
1. Genera un `HMAC_SECRET_KEY` (si `.env` no tenía uno) y lo guarda en `.env`.
|
||||
2. Hace `Login` en el Service Layer, lee la configuración actual de la
|
||||
suscripción (`WEBHOOK_ID` de `.env`), la **pausa**, la **elimina** y la
|
||||
**vuelve a crear** con `AuthenticationType: "HMAC"` — el Service Layer
|
||||
no permite cambiar `AuthenticationType` con `PATCH` sobre una
|
||||
suscripción existente, así que este es el único camino soportado
|
||||
(se conserva `WebhookURL`, `Handshake` y `EventCollection` originales).
|
||||
`AuthenticationCred` no es el secreto pelado: va como un string con
|
||||
JSON embebido, `{"Key": "<secreto>", "Algorithm": "hmacsha256"}`.
|
||||
|
||||
Después, **reiniciá la API** para que tome el `HMAC_SECRET_KEY` nuevo:
|
||||
|
||||
```bash
|
||||
npm run start
|
||||
```
|
||||
|
||||
A partir de este momento, todo `POST /webhooks/sap` sin la firma correcta
|
||||
en el header `X-B1-Webhook-Signature` (HMAC-SHA256 del body, en base64)
|
||||
devuelve `401 Unauthorized`.
|
||||
|
||||
### 2.2 Probar manualmente (simulando lo que hace SAP)
|
||||
|
||||
```bash
|
||||
SECRET=$(grep '^HMAC_SECRET_KEY=' .env | cut -d= -f2)
|
||||
BODY='[{"id":"test-2","type":"sap.b1.Orders.Created.v1","subject":"2","data":{"DocEntry":"2"}}]'
|
||||
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -binary | openssl base64)
|
||||
|
||||
curl -sk -i -X POST https://localhost:3000/webhooks/sap \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-B1-Webhook-Signature: $SIG" \
|
||||
-d "$BODY"
|
||||
# -> 200 OK
|
||||
|
||||
# sin firma o con una firma incorrecta -> 401
|
||||
curl -sk -i -X POST https://localhost:3000/webhooks/sap \
|
||||
-H "Content-Type: application/json" -d "$BODY"
|
||||
```
|
||||
|
||||
### 2.3 Desactivar (volver a `None`)
|
||||
|
||||
```bash
|
||||
npm run auth:hmac:off
|
||||
npm run start # reiniciar para que la API deje de exigir la firma
|
||||
```
|
||||
|
||||
Esto revierte la suscripción en SAP a `AuthenticationType: "None"` y vacía
|
||||
`HMAC_SECRET_KEY` en `.env`, en un solo paso.
|
||||
|
||||
## Referencia rápida
|
||||
|
||||
| Acción | Comando |
|
||||
|---|---|
|
||||
| Instalar dependencias | `npm install` |
|
||||
| Levantar la API | `npm run start` |
|
||||
| Activar HMAC (API + SAP) | `npm run auth:hmac:on` |
|
||||
| Desactivar HMAC (API + SAP) | `npm run auth:hmac:off` |
|
||||
| Ver estado actual de la suscripción | `curl -sk -b cookies.txt "$SERVICE_LAYER_URL/EventSubscriptions('$WEBHOOK_ID')"` (después de un `Login`) |
|
||||
|
||||
Detalle de la implementación (cómo se valida la firma, por qué se usa el
|
||||
body crudo, etc.) en `CLAUDE.md`.
|
||||
@@ -0,0 +1,291 @@
|
||||
# Pasos realizados — API de Webhooks SAP Business One
|
||||
|
||||
Documento de los pasos ejecutados para levantar la API NestJS que escucha el
|
||||
Event Notification del Webhook de SAP Business One Service Layer, desde el
|
||||
proyecto vacío hasta tener la suscripción activa y lista para recibir
|
||||
notificaciones reales. No incluye las pruebas contra SAP real (creación de
|
||||
órdenes de venta) ni la investigación de errores posteriores — eso queda
|
||||
documentado por separado.
|
||||
|
||||
## Contexto / objetivo
|
||||
|
||||
- API sencilla en NestJS que escucha el Webhook Messenger de SAP Business One
|
||||
(Service Layer) y guarda localmente cada Event Notification recibido.
|
||||
- SAP Business One corre en `sap10` (Service Layer, puerto `50000`) y en
|
||||
`192.168.1.205` (Webhook Messenger, puerto `40008`), en la misma LAN que la
|
||||
máquina de desarrollo (Mac, IP `192.168.1.166`).
|
||||
- Compañía de pruebas: `SBODemoCL`, usuario `manager`.
|
||||
|
||||
## 1. Crear el proyecto NestJS
|
||||
|
||||
```bash
|
||||
npx --yes @nestjs/cli new sap-webhook-api --package-manager npm --skip-git
|
||||
```
|
||||
|
||||
Genera el scaffold estándar de Nest (TypeScript, npm) en `sap-webhook-api/`.
|
||||
|
||||
## 2. Crear el módulo de webhooks
|
||||
|
||||
```bash
|
||||
cd sap-webhook-api
|
||||
npx nest generate module webhooks --no-spec
|
||||
npx nest generate controller webhooks --no-spec
|
||||
```
|
||||
|
||||
Esto registra automáticamente `WebhooksModule` en `AppModule` y crea
|
||||
`src/webhooks/webhooks.controller.ts`.
|
||||
|
||||
## 3. Endpoint mínimo que recibe el webhook
|
||||
|
||||
`src/webhooks/webhooks.controller.ts`:
|
||||
|
||||
```ts
|
||||
import { Body, Controller, HttpCode, Logger, Post } from '@nestjs/common';
|
||||
import { mkdirSync, writeFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
const EVENTS_DIR = join(process.cwd(), 'data', 'events');
|
||||
|
||||
interface SapEventNotification {
|
||||
EventID?: string;
|
||||
SourceDB?: string;
|
||||
BusinessObject?: string;
|
||||
Operation?: string;
|
||||
Status?: string;
|
||||
ReplayState?: string;
|
||||
FieldNames?: string;
|
||||
FieldValues?: string;
|
||||
CreateDate?: string;
|
||||
CreateTime?: string;
|
||||
}
|
||||
|
||||
@Controller('webhooks')
|
||||
export class WebhooksController {
|
||||
private readonly logger = new Logger(WebhooksController.name);
|
||||
|
||||
@Post('sap')
|
||||
@HttpCode(200)
|
||||
receiveSapEvent(@Body() body: SapEventNotification | SapEventNotification[]) {
|
||||
const notifications = Array.isArray(body) ? body : [body];
|
||||
this.logger.log(`Recibidas ${notifications.length} notificación(es) de SAP`);
|
||||
|
||||
mkdirSync(EVENTS_DIR, { recursive: true });
|
||||
notifications.forEach((notification, index) => {
|
||||
const id = notification?.EventID ?? `${Date.now()}-${index}`;
|
||||
const fileName = `${id}.json`;
|
||||
writeFileSync(join(EVENTS_DIR, fileName), JSON.stringify(notification, null, 2));
|
||||
this.logger.log(`Evento guardado: ${fileName}`);
|
||||
});
|
||||
|
||||
return { received: true, count: notifications.length };
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
SAP puede enviar varias notificaciones "bateadas" en un solo `POST` (según
|
||||
`MessageBatchLimit`), como confirma el sample oficial de SAP
|
||||
(`webhook-service-sample-nodejs`). Por eso el body se normaliza siempre a un
|
||||
array, y se guarda **un archivo por notificación**, nombrado por su
|
||||
`EventID` cuando está disponible (o timestamp + índice como respaldo).
|
||||
|
||||
> Nota: esta versión reemplaza a una anterior más simple que guardaba el
|
||||
> `body` completo en un solo archivo por request — ver historial de cambios
|
||||
> del proyecto si se necesita esa versión.
|
||||
|
||||
## 4. Primera prueba local (HTTP)
|
||||
|
||||
```bash
|
||||
npm run start
|
||||
curl -s -i -X POST http://localhost:3000/webhooks/sap \
|
||||
-H "Content-Type: application/json" -d '{"test":"hola"}'
|
||||
```
|
||||
|
||||
Resultado: `200 OK`, `{"received":true}`, y log
|
||||
`Evento recibido de SAP: {"test":"hola"}`.
|
||||
|
||||
## 5. Verificar conectividad de red en la LAN
|
||||
|
||||
- IP de la Mac en la LAN: `192.168.1.166` (`ipconfig getifaddr en0`).
|
||||
- Confirmar que Node escucha en todas las interfaces, no solo localhost:
|
||||
|
||||
```bash
|
||||
lsof -nP -iTCP:3000 -sTCP:LISTEN
|
||||
# node ... TCP *:3000 (LISTEN)
|
||||
```
|
||||
|
||||
- Desde el servidor SAP (Windows), verificar que puede llegar a la Mac en el
|
||||
puerto `3000` (macOS no trae `telnet`, así que se usó `Test-NetConnection`):
|
||||
|
||||
```powershell
|
||||
Test-NetConnection -ComputerName 192.168.1.166 -Port 3000
|
||||
# TcpTestSucceeded : True
|
||||
```
|
||||
|
||||
- Desde la Mac, verificar conectividad hacia el Webhook Messenger de SAP
|
||||
(puerto `40008`) y hacia el Service Layer (puerto `50000`), con `nc`
|
||||
(netcat, viene instalado en macOS):
|
||||
|
||||
```bash
|
||||
nc -zv 192.168.1.205 40008 # Connection succeeded
|
||||
nc -zv sap10 50000 # Connection succeeded
|
||||
```
|
||||
|
||||
Con esto queda confirmada la conectividad en ambos sentidos.
|
||||
|
||||
## 6. Login en el Service Layer y estado del webhook
|
||||
|
||||
```bash
|
||||
curl -sk -i -c cookies.txt -X POST https://sap10:50000/b1s/v2/Login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"CompanyDB":"SBODemoCL","UserName":"manager","Password":"mngr"}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -sk -b cookies.txt https://sap10:50000/b1s/v2/CompanyService_GetAdminInfo
|
||||
```
|
||||
|
||||
El campo `EnableWebhook` ya estaba en `"tYES"` en esta compañía, así que no
|
||||
hizo falta llamar a `CompanyService_UpdateAdminInfo`.
|
||||
|
||||
## 7. Confirmar el evento en el catálogo
|
||||
|
||||
```bash
|
||||
curl -sk -b cookies.txt \
|
||||
"https://sap10:50000/b1s/v2/EventSubscriptionsService_GetEventCatalog"
|
||||
```
|
||||
|
||||
Se confirmó la entrada:
|
||||
|
||||
```json
|
||||
{"BusinessObject": "Orders", "ObjectType": "17", "TransactionTypes": "Created,Updated,Deleted,Closed,Cancelled,Reopened"}
|
||||
```
|
||||
|
||||
## 8. Primer intento de suscripción (falló — HTTP no permitido)
|
||||
|
||||
```bash
|
||||
curl -sk -i -b cookies.txt -X POST https://sap10:50000/b1s/v2/EventSubscriptions \
|
||||
-H "Content-Type: application/json" -d '{
|
||||
"WebhookID": "SapWebhookApiTest",
|
||||
"WebhookURL": "http://192.168.1.166:3000/webhooks/sap",
|
||||
"AuthenticationType": "None",
|
||||
"Handshake": "tNO",
|
||||
"EventCollection": [{"BusinessObject": "Orders", "TransactionType": "Created"}]
|
||||
}'
|
||||
```
|
||||
|
||||
Resultado: `400 Bad Request`, `-21100 Invalid webhook URL` — SAP exige que
|
||||
`WebhookURL` sea HTTPS.
|
||||
|
||||
## 9. Certificado autofirmado y API en HTTPS
|
||||
|
||||
```bash
|
||||
cd sap-webhook-api
|
||||
mkdir -p certs
|
||||
openssl req -x509 -newkey rsa:2048 -keyout certs/key.pem -out certs/cert.pem \
|
||||
-days 825 -nodes -subj "/CN=192.168.1.166" \
|
||||
-addext "subjectAltName=IP:192.168.1.166"
|
||||
```
|
||||
|
||||
`src/main.ts`:
|
||||
|
||||
```ts
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const httpsOptions = {
|
||||
key: readFileSync(join(__dirname, '..', 'certs', 'key.pem')),
|
||||
cert: readFileSync(join(__dirname, '..', 'certs', 'cert.pem')),
|
||||
};
|
||||
const app = await NestFactory.create(AppModule, { httpsOptions });
|
||||
await app.listen(process.env.PORT ?? 3000);
|
||||
}
|
||||
bootstrap();
|
||||
```
|
||||
|
||||
Prueba local tras el cambio:
|
||||
|
||||
```bash
|
||||
curl -sk -i -X POST https://localhost:3000/webhooks/sap \
|
||||
-H "Content-Type: application/json" -d '{"test":"https-ok"}'
|
||||
ls -la data/events/
|
||||
```
|
||||
|
||||
Resultado: `200 OK` y el archivo del evento guardado correctamente en
|
||||
`data/events/`.
|
||||
|
||||
## 10. Crear la suscripción con HTTPS (éxito)
|
||||
|
||||
```bash
|
||||
curl -sk -i -b cookies.txt -X POST https://sap10:50000/b1s/v2/EventSubscriptions \
|
||||
-H "Content-Type: application/json" -d '{
|
||||
"WebhookID": "SapWebhookApiTest",
|
||||
"WebhookURL": "https://192.168.1.166:3000/webhooks/sap",
|
||||
"AuthenticationType": "None",
|
||||
"Handshake": "tNO",
|
||||
"EventCollection": [{"BusinessObject": "Orders", "TransactionType": "Created"}]
|
||||
}'
|
||||
```
|
||||
|
||||
Resultado: `201 Created`, `State: "Active"` — pero con `VerifyCertificate:
|
||||
"tYES"` (SAP intentaría validar nuestro certificado autofirmado y lo
|
||||
rechazaría).
|
||||
|
||||
## 11. Desactivar la verificación de certificado
|
||||
|
||||
```bash
|
||||
curl -sk -i -b cookies.txt -X PATCH \
|
||||
"https://sap10:50000/b1s/v2/EventSubscriptions('SapWebhookApiTest')" \
|
||||
-H "Content-Type: application/json" -d '{"VerifyCertificate": "tNO"}'
|
||||
```
|
||||
|
||||
Resultado: `204 No Content`. Verificado con un `GET` posterior:
|
||||
`VerifyCertificate: "tNO"`, `State: "Active"`.
|
||||
|
||||
## Estado al cierre de esta etapa
|
||||
|
||||
| Ítem | Estado |
|
||||
|---|---|
|
||||
| Proyecto NestJS (`sap-webhook-api`) | ✅ Creado |
|
||||
| Endpoint `POST /webhooks/sap` | ✅ Responde 200 y guarda cada evento en `data/events/` |
|
||||
| Conectividad LAN (Mac ↔ SAP, ambos sentidos) | ✅ Confirmada |
|
||||
| Webhook habilitado en la compañía SAP | ✅ (ya estaba `tYES`) |
|
||||
| Certificado HTTPS autofirmado | ✅ Generado y en uso |
|
||||
| Suscripción `SapWebhookApiTest` (`Orders`/`Created`) | ✅ `Active`, `VerifyCertificate: tNO` |
|
||||
|
||||
A partir de aquí comienzan las pruebas con órdenes de venta reales en SAP, que
|
||||
llevaron a identificar un bug en el Webhook Messenger de SAP (no cubierto en
|
||||
este documento).
|
||||
|
||||
## Anexo: tablas internas de SAP para diagnóstico
|
||||
|
||||
Para diagnosticar problemas de entrega del webhook (suscripción activa pero
|
||||
sin eventos llegando, errores de envío, etc.), conviene revisar directamente
|
||||
estas tablas en la base de la compañía (ej. `SBODemoCL`), vía SSMS, en modo
|
||||
**solo lectura**:
|
||||
|
||||
```sql
|
||||
-- Suscripciones de webhook registradas (una fila por WebhookID: URL, estado,
|
||||
-- fecha/hora de creación, último envío, último error)
|
||||
SELECT * FROM OEVC
|
||||
|
||||
-- Cola de eventos de negocio generados (una fila por transacción que matchea
|
||||
-- algún BusinessObject/TransactionType suscripto: EventID, CreateDate,
|
||||
-- CreateTime, Status, BizObject, TransType). Status = 'N' significa
|
||||
-- pendiente de enviar.
|
||||
SELECT * FROM OEVN
|
||||
|
||||
-- Estado de envío de cada evento hacia cada webhook suscripto (relaciona
|
||||
-- EventID + WebhookID con su resultado: Status, Retry, ReturnCode,
|
||||
-- LastSentDT, LastSentTM)
|
||||
SELECT * FROM EVN1
|
||||
```
|
||||
|
||||
Estas tablas son internas del motor de SAP Business One — **no están
|
||||
pensadas para escritura directa vía SQL** (cualquier cambio debería hacerse
|
||||
a través de Service Layer / DI API). Sirven únicamente para inspeccionar el
|
||||
estado real de la cola de eventos y de las suscripciones cuando el
|
||||
comportamiento reportado por el Service Layer (`GET /EventSubscriptions`) no
|
||||
alcanza para explicar por qué no llegan las notificaciones.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 553 KiB |
Reference in new issue
Block a user