144 lines
3.9 KiB
JavaScript
144 lines
3.9 KiB
JavaScript
const config = require('./config');
|
|
const apiClient = require('./api-client');
|
|
|
|
class AbandonedCallPoller {
|
|
constructor(database, printer) {
|
|
this.db = database;
|
|
this.printer = printer;
|
|
this.intervalId = null;
|
|
this.isPolling = false;
|
|
}
|
|
|
|
async start() {
|
|
console.log('Starting abandoned call poller...');
|
|
this.poll();
|
|
this.scheduleNextPoll();
|
|
}
|
|
|
|
scheduleNextPoll() {
|
|
const appConfig = config.getAll();
|
|
const interval = parseInt(appConfig.abandonedCallPollingInterval, 10) || 30000;
|
|
|
|
if (this.intervalId) {
|
|
clearTimeout(this.intervalId);
|
|
}
|
|
|
|
this.intervalId = setTimeout(() => {
|
|
this.poll();
|
|
this.scheduleNextPoll();
|
|
}, interval);
|
|
}
|
|
|
|
async poll() {
|
|
if (this.isPolling) return;
|
|
this.isPolling = true;
|
|
|
|
try {
|
|
const appConfig = config.getAll();
|
|
|
|
if (!appConfig.authToken || !appConfig.selectedBotId) {
|
|
this.isPolling = false;
|
|
return;
|
|
}
|
|
|
|
if (apiClient.isTokenNearExpiry(appConfig.tokenExpiry, 7)) {
|
|
const refreshed = await apiClient.ensureValidToken();
|
|
if (!refreshed) {
|
|
this.isPolling = false;
|
|
return;
|
|
}
|
|
Object.assign(appConfig, config.getAll());
|
|
}
|
|
|
|
const result = await apiClient.getAbandonedCalls(
|
|
appConfig.authToken,
|
|
appConfig.selectedBotId,
|
|
{ limit: 50 }
|
|
);
|
|
|
|
if (result.error) {
|
|
console.error('Abandoned calls poll error:', result.message);
|
|
this.isPolling = false;
|
|
return;
|
|
}
|
|
|
|
const calls = result.calls || [];
|
|
|
|
for (const call of calls) {
|
|
this.db.cacheAbandonedCall(call.id, call);
|
|
}
|
|
|
|
// Also fetch callback queue for the management page cache
|
|
const queueResult = await apiClient.getAbandonedCallbackQueue(
|
|
appConfig.authToken,
|
|
appConfig.selectedBotId,
|
|
50
|
|
);
|
|
|
|
if (!queueResult.error && queueResult.queue) {
|
|
for (const call of queueResult.queue) {
|
|
this.db.cacheAbandonedCall(call.id, call);
|
|
}
|
|
}
|
|
|
|
// Print new abandoned calls that haven't been printed yet
|
|
await this.printNewAbandonedCalls(calls, appConfig);
|
|
|
|
// Clean old cache periodically
|
|
this.db.cleanOldAbandonedCallCache(7);
|
|
|
|
} catch (error) {
|
|
console.error('Abandoned call poll error:', error.message);
|
|
}
|
|
|
|
this.isPolling = false;
|
|
}
|
|
|
|
async printNewAbandonedCalls(calls, appConfig) {
|
|
const printerConfigs = this.db.getAbandonedCallPrinters();
|
|
if (!printerConfigs || printerConfigs.length === 0) return;
|
|
|
|
const cooldownSeconds = parseInt(appConfig.abandonedCallPrintCooldown, 10) || 300;
|
|
const lastPrintTime = this.db.getLastAbandonedCallPrintTime();
|
|
const now = Math.floor(Date.now() / 1000);
|
|
|
|
const printablePriorities = new Set(['critical', 'high', 'medium']);
|
|
|
|
for (const call of calls) {
|
|
if (this.db.hasAbandonedCallPrint(call.id)) continue;
|
|
|
|
const priority = call.callback_priority || 'none';
|
|
if (!printablePriorities.has(priority)) continue;
|
|
|
|
if (lastPrintTime && (now - lastPrintTime) < cooldownSeconds) {
|
|
console.log(`Abandoned call #${call.id}: skipping print (cooldown active)`);
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
const result = await this.printer.printAbandonedCallReceipt(call, printerConfigs);
|
|
const printedCount = result ? (result.successCount || printerConfigs.length) : 0;
|
|
this.db.addAbandonedCallPrint(call.id, printedCount);
|
|
console.log(`Abandoned call #${call.id}: printed on ${printedCount} printer(s)`);
|
|
} catch (err) {
|
|
console.error(`Abandoned call #${call.id}: print failed:`, err.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
stop() {
|
|
if (this.intervalId) {
|
|
clearTimeout(this.intervalId);
|
|
this.intervalId = null;
|
|
}
|
|
console.log('Abandoned call poller stopped');
|
|
}
|
|
|
|
restart() {
|
|
this.stop();
|
|
this.start();
|
|
}
|
|
}
|
|
|
|
module.exports = AbandonedCallPoller;
|