audit and sync

This commit is contained in:
Lucas Tettamanti
2026-01-18 19:00:49 -03:00
parent 3b39e706af
commit 23c3d44490
9 changed files with 404 additions and 19 deletions

View File

@@ -1,5 +1,6 @@
import { refreshProductByWooId } from "../../shared/wooSnapshot.js";
import { getTenantByKey } from "../db/repo.js";
import { insertAuditLog } from "../../0-ui/db/repo.js";
function unauthorized(res) {
res.setHeader("WWW-Authenticate", 'Basic realm="woo-webhook"');
@@ -18,11 +19,25 @@ function checkBasicAuth(req) {
return { ok: false, reason: "invalid_creds" };
}
function parseWooId(payload) {
function parseWooPayload(payload) {
const id = payload?.id || payload?.data?.id || null;
const parentId = payload?.parent_id || payload?.data?.parent_id || null;
const resource = payload?.resource || payload?.topic || null;
return { id: id ? Number(id) : null, parentId: parentId ? Number(parentId) : null, resource };
const action = payload?.action || null; // 'created' | 'updated' | 'deleted'
// Extraer campos relevantes para audit
const name = payload?.name || null;
const price = payload?.price || null;
const stockStatus = payload?.stock_status || null;
const stockQty = payload?.stock_quantity ?? null;
return {
id: id ? Number(id) : null,
parentId: parentId ? Number(parentId) : null,
resource,
action,
changes: { name, price, stockStatus, stockQty }
};
}
export function makeWooProductWebhook() {
@@ -30,7 +45,7 @@ export function makeWooProductWebhook() {
const auth = checkBasicAuth(req);
if (!auth.ok) return unauthorized(res);
const { id, parentId, resource } = parseWooId(req.body || {});
const { id, parentId, resource, action, changes } = parseWooPayload(req.body || {});
if (!id) return res.status(400).json({ ok: false, error: "missing_id" });
// Determinar tenant por query ?tenant_key=...
@@ -42,17 +57,55 @@ export function makeWooProductWebhook() {
const parentForVariation =
resource && String(resource).includes("variation") ? parentId || null : null;
const updated = await refreshProductByWooId({
tenantId: tenant.id,
wooId: id,
parentId: parentForVariation,
});
// Determinar acción para audit
let auditAction = 'update';
if (action === 'created' || resource?.includes('created')) {
auditAction = 'create';
} else if (action === 'deleted' || resource?.includes('deleted')) {
auditAction = 'delete';
}
let updated = null;
// Si es delete, no podemos refresh (el producto ya no existe en Woo)
if (auditAction !== 'delete') {
try {
updated = await refreshProductByWooId({
tenantId: tenant.id,
wooId: id,
parentId: parentForVariation,
});
} catch (err) {
console.error("[wooWebhook] Error refreshing product:", err.message);
// Si falla el refresh (ej: producto eliminado), registramos igual en audit
}
}
// Registrar en audit_log
try {
await insertAuditLog({
tenantId: tenant.id,
entityType: 'product',
entityId: String(id),
action: auditAction,
changes: {
...changes,
resource,
woo_action: action,
refreshed: updated != null
},
actor: 'webhook'
});
} catch (err) {
console.error("[wooWebhook] Error inserting audit log:", err.message);
}
return res.status(200).json({
ok: true,
woo_id: updated?.woo_id || id,
type: updated?.type || null,
parent_id: updated?.parent_id || null,
action: auditAction,
});
};
}