Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save iDavidMorales/46b9436eb8f3d00507ca14fdb3680dcb to your computer and use it in GitHub Desktop.

Select an option

Save iDavidMorales/46b9436eb8f3d00507ca14fdb3680dcb to your computer and use it in GitHub Desktop.
const Firebird = require('node-firebird');
const axios = require('axios');
// Configuración de conexión (ruta absoluta en macOS)
const options = {
host: '127.0.0.1',
port: 3050,
database: '/Library/Frameworks/Firebird.framework/Resources/data/PDVDATA.fdb',
user: 'SYSDBA',
password: 'masterkey'
};
// URL de tu API en Routicket
const API_ENDPOINT = 'https://routicket.com/api/eleventa/recibir-tickets.php';
const API_KEY = 'rt_live_8f7d6e5c4b3a2';
const COMERCIO_ID = 'com_00192';
async function sincronizar() {
console.log(`[${new Date().toLocaleString()}] Buscando tickets nuevos...`);
Firebird.attach(options, (err, db) => {
if (err) {
console.error("Error al conectar a Firebird:", err.message);
return;
}
// 1. Buscamos ventas que aún no se han subido
db.query('SELECT * FROM VENTAS WHERE SINCRONIZADO = 0', async (err, ventasResult) => {
if (err) {
console.error("Error en la consulta de ventas:", err.message);
db.detach();
return;
}
if (ventasResult.length === 0) {
db.detach();
return; // Silencioso si no hay ventas para no llenar los logs de PM2
}
console.log(`Procesando ${ventasResult.length} ticket(s)...`);
let ventasProcesadas = [];
// 2. Extraemos las partidas de cada venta usando un bucle asíncrono
for (let v of ventasResult) {
const queryPartidas = `SELECT * FROM PARTIDAS WHERE ID_VENTA = ${v.ID_VENTA}`;
// Esperamos a que Firebird nos devuelva los productos de este ticket
const partidas = await new Promise((resolve) => {
db.query(queryPartidas, (err, items) => {
if (err || !items) {
resolve([]);
} else {
resolve(items.map(p => ({
codigo_barras: p.CODIGO || '',
descripcion: p.DESCRIPCION || 'Sin descripción',
cantidad: parseFloat(p.CANTIDAD) || 1,
precio_unitario: parseFloat(p.PRECIO) || 0,
importe: (parseFloat(p.CANTIDAD) || 1) * (parseFloat(p.PRECIO) || 0)
})));
}
});
});
// 3. Armamos el objeto final del ticket
ventasProcesadas.push({
id_venta_local: v.ID_VENTA,
folio_ticket: v.FOLIO,
fecha_venta: new Date(v.FECHA).toISOString(),
cajero: "Caja 1", // Ajustar si agregas la columna cajero en Firebird
total_vendido: parseFloat(v.TOTAL) || 0,
partidas: partidas // Ahora lleva todo el detalle de productos
});
}
// 4. Preparamos el paquete JSON para el servidor
const payload = {
auth: { api_key: API_KEY, comercio_id: COMERCIO_ID },
ventas: ventasProcesadas
};
// 5. Enviamos a Routicket
axios.post(API_ENDPOINT, payload)
.then(response => {
console.log("Respuesta del servidor:", response.data);
// Si el servidor confirma éxito, marcamos en la BD local
if (response.data.status === 'success' || response.data.status === 200) {
db.query('UPDATE VENTAS SET SINCRONIZADO = 1 WHERE SINCRONIZADO = 0', (err) => {
if (!err) console.log("BD Local: Tickets marcados como sincronizados.");
db.detach();
});
} else {
db.detach();
}
})
.catch(error => {
console.error("Error HTTP al enviar a Routicket:", error.message);
db.detach();
});
});
});
}
// Ejecutar cada minuto (60000 ms)
setInterval(sincronizar, 60000);
sincronizar();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment