UNPKG

@openade/fe

Version:

Fatturazione Elettronica - Electronic Invoicing for Sistema di Interscambio (SDI)

213 lines 7.77 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BatchProcessor = void 0; exports.createBatchProcessor = createBatchProcessor; exports.processInvoiceBatch = processInvoiceBatch; const invoice_xml_1 = require("./invoice.xml"); const sdicoop_client_1 = require("./sdicoop.client"); class BatchProcessor { constructor(sdiConfig, batchConfig = {}) { this.sdiClient = new sdicoop_client_1.SDICOOPClient(sdiConfig); this.config = { maxBatchSize: 100, batchDelay: 1000, maxConcurrentBatches: 3, retry: { maxRetries: 3, retryDelay: 5000, backoffMultiplier: 2, }, ...batchConfig, }; } async processBatch(items) { const startTime = Date.now(); const results = []; const errors = []; let completed = 0; let failed = 0; const batches = this.splitIntoBatches(items); const totalBatches = batches.length; if (this.config.onProgress) { this.config.onProgress({ total: items.length, completed: 0, failed: 0, pending: items.length, currentBatch: 0, totalBatches, percentage: 0, }); } const batchPromises = []; const semaphore = new Semaphore(this.config.maxConcurrentBatches); for (let i = 0; i < batches.length; i++) { const batch = batches[i]; const batchNumber = i + 1; const batchPromise = semaphore.acquire().then(async (release) => { try { const batchResults = await this.processSingleBatch(batch, batchNumber, totalBatches); results.push(...batchResults); for (const result of batchResults) { if (result.success) { completed++; } else { failed++; errors.push({ itemId: result.id, message: result.error || 'Unknown error', retryCount: result.retryCount, timestamp: new Date().toISOString(), }); } } if (this.config.onProgress) { this.config.onProgress({ total: items.length, completed, failed, pending: items.length - completed - failed, currentBatch: batchNumber, totalBatches, percentage: Math.round(((completed + failed) / items.length) * 100), estimatedTimeRemaining: this.calculateEstimatedTimeRemaining(startTime, completed + failed, items.length), }); } if (batchNumber < totalBatches && this.config.batchDelay > 0) { await this.delay(this.config.batchDelay); } } finally { release(); } }); batchPromises.push(batchPromise); } await Promise.all(batchPromises); const processingTime = Date.now() - startTime; const successful = results.filter((r) => r.success).length; return { total: items.length, successful, failed, processingTime, results, summary: { successRate: items.length > 0 ? (successful / items.length) * 100 : 0, averageProcessingTime: results.length > 0 ? processingTime / results.length : 0, errors, }, }; } async processSingleBatch(items, _batchNumber, _totalBatches) { const results = []; for (const item of items) { let retryCount = 0; let success = false; let result; let error; while (retryCount <= this.config.retry.maxRetries && !success) { try { const xml = (0, invoice_xml_1.buildInvoiceXML)(item.invoice); result = await this.sdiClient.sendInvoice(item.filename, xml); success = result.success; if (!success) { error = result.error; } } catch (err) { error = err instanceof Error ? err.message : 'Unknown error'; } if (!success && retryCount < this.config.retry.maxRetries) { retryCount++; const delay = this.config.retry.retryDelay * Math.pow(this.config.retry.backoffMultiplier, retryCount - 1); await this.delay(delay); } else { break; } } results.push({ id: item.id, success, result, error, retryCount, }); if (!success && this.config.onError) { this.config.onError({ itemId: item.id, message: error || 'Unknown error', retryCount, timestamp: new Date().toISOString(), }); } } return results; } splitIntoBatches(items) { const batches = []; const batchSize = this.config.maxBatchSize; for (let i = 0; i < items.length; i += batchSize) { batches.push(items.slice(i, i + batchSize)); } return batches; } calculateEstimatedTimeRemaining(startTime, completed, total) { if (completed === 0) return 0; const elapsed = Date.now() - startTime; const rate = completed / elapsed; const remaining = total - completed; return Math.round(remaining / rate); } delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } } exports.BatchProcessor = BatchProcessor; class Semaphore { constructor(permits) { this.waiting = []; this.permits = permits; } async acquire() { return new Promise((resolve) => { if (this.permits > 0) { this.permits--; resolve(() => this.release()); } else { this.waiting.push(() => { this.permits--; resolve(() => this.release()); }); } }); } release() { this.permits++; if (this.waiting.length > 0) { const next = this.waiting.shift(); if (next) next(); } } } function createBatchProcessor(sdiConfig, batchConfig = {}) { return new BatchProcessor(sdiConfig, batchConfig); } async function processInvoiceBatch(invoices, sdiConfig, batchConfig = {}) { const processor = createBatchProcessor(sdiConfig, batchConfig); const items = invoices.map((inv, index) => ({ id: `invoice_${index}_${Date.now()}`, invoice: inv.invoice, filename: inv.filename, channel: inv.channel, metadata: inv.metadata, })); return await processor.processBatch(items); } //# sourceMappingURL=batch.processor.js.map