UNPKG

@openade/pem

Version:

Punto di Emissione (Emission Point) - Device library for fiscal receipts

150 lines 5.97 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PEMManager = void 0; const document_builder_1 = require("./document.builder"); const journal_manager_1 = require("./journal.manager"); const pel_client_1 = require("./pel.client"); class PEMManager { constructor(config, storage) { this.documentCounter = 0; this.isSessionOpen = false; this.unsyncedDocuments = []; this.config = config; this.documentBuilder = new document_builder_1.DocumentBuilder({ vatNumber: config.vatNumber, businessName: config.businessName, pemId: config.serialNumber, }); this.journal = new journal_manager_1.JournalManager(); this.storage = storage; if (config.pelUrl) { this.pelClient = new pel_client_1.PELClient({ pelBaseUrl: config.pelUrl }); } } async openSession() { if (this.isSessionOpen) throw new Error('Session already open'); if (this.pelClient) { try { const { seed } = await this.pelClient.getSessionSeed(); console.log(`Received session seed from PEL: ${seed.substring(0, 8)}...`); } catch (error) { console.warn('Failed to get seed from PEL, continuing offline:', error); } } this.journal.openCash(); this.isSessionOpen = true; this.documentCounter = 0; this.unsyncedDocuments = []; console.log(`✅ PEM Session Opened (${this.config.serialNumber})`); } async emitReceipt(lines) { if (!this.isSessionOpen) throw new Error('Session not open'); this.documentCounter++; const documentNumber = this.documentCounter.toString().padStart(6, '0'); const document = this.documentBuilder.build(lines, documentNumber); const hash = this.journal.addDocument(document); await this.storage.saveDocument(documentNumber, document); let synced = false; if (this.pelClient) { try { const result = await this.pelClient.sendDocument(document); if (result.success) { synced = true; console.log(`📄 Receipt emitted: ${documentNumber} (${document.importoTotale}€) ✓ Synced`); } else { console.warn(`📄 Receipt emitted: ${documentNumber} - Sync failed: ${result.error}`); this.unsyncedDocuments.push(document); } } catch (error) { console.warn('Failed to send document to PEL:', error); this.unsyncedDocuments.push(document); } } else { console.log(`📄 Receipt emitted: ${documentNumber} (${document.importoTotale}€) [Offline]`); } return { document, hash, synced }; } async closeSession() { if (!this.isSessionOpen) throw new Error('Session not open'); const result = this.journal.closeCash(); const date = new Date().toISOString().split('T')[0]; const journalData = this.journal.exportJournal(); await this.storage.saveJournal(date, journalData); let journalSynced = false; if (this.pelClient) { try { if (this.unsyncedDocuments.length > 0) { console.log(`⚠️ Retrying ${this.unsyncedDocuments.length} unsynced documents...`); for (const doc of this.unsyncedDocuments) { try { await this.pelClient.sendDocument(doc); console.log(` ✓ Synced ${doc.datiGenerali.numero}`); } catch { console.error(` ✗ Failed to sync ${doc.datiGenerali.numero}`); } } } const journal = JSON.parse(journalData); const result = await this.pelClient.sendJournal(journal); if (result.success) { journalSynced = true; console.log('✓ Journal synced to PEL'); } else { console.warn('⚠️ Journal sync failed:', result.error); } } catch (error) { console.warn('Failed to send journal to PEL:', error); } } this.isSessionOpen = false; console.log(`✅ Session Closed - ${result.totalDocuments} documents, ${result.totalAmount}€`); if (!journalSynced && this.pelClient) { console.warn(`⚠️ Journal NOT synced to PEL - stored locally`); } if (this.unsyncedDocuments.length > 0) { console.warn(`⚠️ ${this.unsyncedDocuments.length} documents failed to sync`); } return { totalDocuments: result.totalDocuments, totalAmount: result.totalAmount, journalSynced, unsyncedDocuments: this.unsyncedDocuments.length, }; } getJournalEntries() { return this.journal.getEntries(); } verifyJournal() { return this.journal.verify(); } async getDocuments() { return this.storage.listDocuments(); } getStatus() { return { isOpen: this.isSessionOpen, deviceType: this.config.deviceType, serialNumber: this.config.serialNumber, documentsCount: this.documentCounter, journalVerified: this.journal.verify(), }; } async exportForSync() { return this.journal.exportJournal(); } exportJournal() { return JSON.parse(this.journal.exportJournal()); } } exports.PEMManager = PEMManager; //# sourceMappingURL=pem.manager.js.map