const fetch = require('node-fetch');
const fs = require('fs');
const API_KEY = process.env.TAXO_API_KEY;
const BASE_URL = 'https://api.taxo.co';
async function main() {
try {
console.log('🚀 Iniciando extracción de facturas...');
// 1. Crear extracción
const extraction = await createExtraction();
console.log(`✅ Extracción creada: ${extraction.publicId}`);
// 2. Esperar a que complete
const result = await waitForCompletion(extraction.publicId);
// 3. Descargar primeros 5 documentos
await downloadDocuments(result, 5);
console.log('🎉 ¡Proceso completado exitosamente!');
} catch (error) {
console.error('❌ Error:', error.message);
process.exit(1);
}
}
async function createExtraction() {
const response = await fetch(`${BASE_URL}/v1/extractions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
subject: {
identifier: 'ABC010101ABC', // Reemplaza con el RFC real
name: 'Mi Empresa S.A. de C.V.'
},
credentials: {
type: 'CIEC',
password: Buffer.from('my_sat_password').toString('base64') // Reemplaza
},
options: {
informationType: 'INVOICE',
period: {
from: '2024-01-01',
to: '2024-03-31' // Solo Q1 para el ejemplo
},
direction: 'RECEIVED'
}
})
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Error creando extracción: ${error.error?.message}`);
}
return await response.json();
}
async function waitForCompletion(extractionId) {
console.log('⏳ Esperando que se complete la extracción...');
const delays = [5, 10, 20, 30, 60]; // Backoff exponencial
let delayIndex = 0;
while (true) {
const response = await fetch(`${BASE_URL}/v1/extractions/${extractionId}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
const status = await response.json();
const progress = status.progress || {};
console.log(` Estado: ${status.status} - Progreso: ${progress.percentage || 0}%`);
if (status.status === 'COMPLETED') {
console.log(`✅ ¡Completado! ${progress.completedCount} documentos extraídos`);
return status;
}
if (status.status === 'FAILED') {
throw new Error(`Extracción falló: ${status.error?.message}`);
}
// Esperar con backoff exponencial
const delay = delays[Math.min(delayIndex++, delays.length - 1)] * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
async function downloadDocuments(extractionStatus, maxDocuments = 5) {
const documents = extractionStatus.documents.slice(0, maxDocuments);
console.log(`📥 Descargando ${documents.length} documentos...`);
for (let i = 0; i < documents.length; i++) {
const doc = documents[i];
const format = doc.availableFormats[0];
console.log(` Descargando ${i + 1}/${documents.length}: ${doc.uuid}`);
const response = await fetch(
`${BASE_URL}/v1/extractions/${extractionStatus.publicId}/documents/${doc.id}/download?type=${format}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
if (!response.ok) {
console.warn(` ⚠️ Error descargando ${doc.uuid}: ${response.status}`);
continue;
}
const buffer = Buffer.from(await response.arrayBuffer());
const filename = `documento_${i + 1}_${doc.uuid}.${format.toLowerCase()}`;
fs.writeFileSync(filename, buffer);
console.log(` ✅ Guardado: ${filename}`);
}
}
// Ejecutar si es llamado directamente
if (require.main === module) {
main();
}