feat: add observability logs to stock waiting room for easier debugging in Portainer
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m8s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m8s
This commit is contained in:
@@ -199,6 +199,10 @@ app.post('/api/data', authenticateAPIKey, async (req, res) => {
|
|||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// In-memory Waiting Room for WhatsApp Marketing
|
||||||
|
const waitingRoom = {};
|
||||||
|
const N8N_WHATSAPP_TRIGGER_URL = process.env.N8N_WHATSAPP_TRIGGER_URL || 'http://localhost:5678/webhook/whatsapp';
|
||||||
|
|
||||||
// POST stock (for n8n)
|
// POST stock (for n8n)
|
||||||
app.post('/api/stock', authenticateAPIKey, async (req, res) => {
|
app.post('/api/stock', authenticateAPIKey, async (req, res) => {
|
||||||
res.status(201).json({ message: 'Stock data received, processing in background' });
|
res.status(201).json({ message: 'Stock data received, processing in background' });
|
||||||
@@ -225,13 +229,91 @@ app.post('/api/stock', authenticateAPIKey, async (req, res) => {
|
|||||||
const idProduto = item.idProduto || item.ID_Produto || '';
|
const idProduto = item.idProduto || item.ID_Produto || '';
|
||||||
if (!idProduto) continue;
|
if (!idProduto) continue;
|
||||||
|
|
||||||
|
const delta = parseInt(item.delta_estoque) || 0;
|
||||||
|
const nomeStr = item.nome || item.Descricao_Produto || 'Unknown';
|
||||||
|
|
||||||
const values = [
|
const values = [
|
||||||
String(idProduto),
|
String(idProduto),
|
||||||
item.nome || item.Descricao_Produto || 'Unknown',
|
nomeStr,
|
||||||
parseInt(item.saldo) || 0,
|
parseInt(item.saldo) || 0,
|
||||||
parseInt(item.delta_estoque) || 0
|
delta
|
||||||
];
|
];
|
||||||
await client.query(insertQuery, values);
|
await client.query(insertQuery, values);
|
||||||
|
|
||||||
|
// Waiting Room / Debounce Logic
|
||||||
|
if (delta >= 100) {
|
||||||
|
const baseProductName = nomeStr.split(' TAMANHO')[0].trim();
|
||||||
|
|
||||||
|
if (!waitingRoom[baseProductName]) {
|
||||||
|
console.log(`[Waiting Room] Nova entrada: ${baseProductName}. Iniciando timer de 30m...`);
|
||||||
|
waitingRoom[baseProductName] = {
|
||||||
|
total_delta: 0,
|
||||||
|
items: [],
|
||||||
|
timeout: null
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
console.log(`[Waiting Room] Atualização: ${baseProductName}. Timer reiniciado (30m).`);
|
||||||
|
}
|
||||||
|
|
||||||
|
waitingRoom[baseProductName].total_delta += delta;
|
||||||
|
waitingRoom[baseProductName].items.push({
|
||||||
|
id: String(idProduto),
|
||||||
|
nome: nomeStr,
|
||||||
|
delta: delta,
|
||||||
|
saldo: parseInt(item.saldo) || 0
|
||||||
|
});
|
||||||
|
|
||||||
|
if (waitingRoom[baseProductName].timeout) {
|
||||||
|
clearTimeout(waitingRoom[baseProductName].timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
waitingRoom[baseProductName].timeout = setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
const aggData = waitingRoom[baseProductName];
|
||||||
|
delete waitingRoom[baseProductName]; // Clear from waiting room
|
||||||
|
|
||||||
|
console.log(`[Waiting Room] Timer finalizado para ${baseProductName}. Buscando top buyers...`);
|
||||||
|
|
||||||
|
// Find Top 100 buyers for this Base Product
|
||||||
|
const topBuyersQuery = `
|
||||||
|
SELECT
|
||||||
|
MAX(cliente_nome) as nome,
|
||||||
|
cliente_fone as fone,
|
||||||
|
SUM(quantidade) as total_comprado
|
||||||
|
FROM orders
|
||||||
|
WHERE produto_descricao LIKE $1
|
||||||
|
AND cliente_fone IS NOT NULL
|
||||||
|
AND cliente_fone != ''
|
||||||
|
GROUP BY cliente_fone
|
||||||
|
ORDER BY total_comprado DESC
|
||||||
|
LIMIT 100;
|
||||||
|
`;
|
||||||
|
const topBuyersResult = await pool.query(topBuyersQuery, [`${baseProductName}%`]);
|
||||||
|
|
||||||
|
// Only trigger if we actually have buyers
|
||||||
|
if (topBuyersResult.rows.length > 0) {
|
||||||
|
console.log(`[Waiting Room] Disparando webhook do WhatsApp para ${topBuyersResult.rows.length} clientes (${baseProductName})...`);
|
||||||
|
fetch(N8N_WHATSAPP_TRIGGER_URL, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
baseProduct: baseProductName,
|
||||||
|
total_delta: aggData.total_delta,
|
||||||
|
sizes: aggData.items,
|
||||||
|
customers: topBuyersResult.rows
|
||||||
|
})
|
||||||
|
}).then(res => {
|
||||||
|
if(res.ok) console.log(`[Waiting Room] Sucesso! Webhook disparado.`);
|
||||||
|
else console.log(`[Waiting Room] Aviso: Webhook retornou status ${res.status}`);
|
||||||
|
}).catch(err => console.error("Failed to trigger WhatsApp webhook:", err));
|
||||||
|
} else {
|
||||||
|
console.log(`[Waiting Room] Nenhum cliente encontrado com telefone válido para ${baseProductName}. Webhook cancelado.`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error in Waiting Room timeout:", err);
|
||||||
|
}
|
||||||
|
}, 1800000); // 30 minutes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.query('COMMIT');
|
await client.query('COMMIT');
|
||||||
|
|||||||
Reference in New Issue
Block a user