@openade/pem
Version:
Punto di Emissione (Emission Point) - Device library for fiscal receipts
150 lines • 5.97 kB
JavaScript
"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