☎️ Web interface for viewing and processing Asterisk call logs (2020)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

173 lines
5.3 KiB

'use strict';
const Dayjs = require('dayjs');
const Joi = require('joi');
const Rfr = require('rfr');
const Common = Rfr('/shared/common');
const ComSrv = Rfr('/server/comsrv');
const Db = Rfr('/server/db');
const dispToNumber = function(disp) {
disp = disp.toUpperCase();
if (disp === 'ANSWERED') {
return Common.resAnswered;
}
if (disp === 'NO ANSWER') {
return Common.resNoAnswer;
}
if (disp === 'FAILED') {
return Common.resFailed;
}
if (disp === 'BUSY') {
return Common.resBusy;
}
if (disp === 'CANCELLED') {
return Common.resCancelled;
}
return Common.resOther;
}
const moveSingleRecord = async function(r) {
try {
await Db.db().transaction(async trx => {
const n = {
calldate: Dayjs(r.calldate),
source: Common.uglifyPhone(r.src),
destination: (r.actualdst ? Common.uglifyPhone(r.actualdst) : Common.uglifyPhone(r.dst)),
uniqueid: (r.actualuniqueid ? r.actualuniqueid : r.uniqueid),
callduration: (r.actualbillsec ? r.actualbillsec : r.billsec),
totalduration: r.duration,
ivr: (r.ivr || 0)
};
if (r.actualdst2 && r.ivr === 3) {
n.destination = Common.uglifyPhone(r.actualdst2);
}
if (r.startedat && r.end) {
const actualCD = Math.ceil(r.end - parseInt(r.startedat, 10));
if (Number.isSafeInteger(actualCD)) {
n.callduration = actualCD;
console.log('changing CD');
}
}
n.calltype = Common.getCallType(n.source, n.destination);
if (r.actualdisposition) {
n.callresult = dispToNumber(r.actualdisposition);
} else if (r.ivr === 1 || r.ivr === 2) {
n.callresult = Common.resCancelled;
} else if (r.disposition === 'ANSWERED' && !r.startedat) {
n.callresult = Common.resNoAnswer;
} else {
n.callresult = dispToNumber(r.disposition);
}
if (n.callresult === Common.resCancelled || n.callresult === Common.resNoAnswer) {
n.callduration = 0;
}
const maxDaily = await trx.max('dailyid').from('ptable')
.where('calldate', '>=', Dayjs(r.calldate).startOf('day'))
.andWhere('calldate', '<=', Dayjs(r.calldate).endOf('day')).first();
n.dailyid = (!maxDaily || !maxDaily.max) ? 1 : (maxDaily.max + 1);
const maxCT = await trx.max('dailyct').from('ptable')
.where('calldate', '>=', Dayjs(r.calldate).startOf('day'))
.andWhere('calldate', '<=', Dayjs(r.calldate).endOf('day'))
.andWhere('calltype', '=', n.calltype).first();
n.dailyct = (!maxCT || !maxCT.max) ? 1 : (maxCT.max + 1);
await trx.insert(n).into('ptable');
ComSrv.debug('Inserted record with UID: ' + n.uniqueid);
});
} catch (e) {
console.error('Failed to insert record to PTable: ' + e);
}
}
const createPTable = async function() {
const hasTable = await Db.db().schema.hasTable('ptable');
if (!hasTable) {
console.log('PTable is missing - will create');
await Db.db().schema.createTable('ptable', t => {
t.increments('id').primary();
t.timestamp('calldate');
t.integer('calltype');
t.integer('callresult');
t.string('source');
t.string('destination');
t.string('uniqueid');
t.integer('callduration');
t.integer('totalduration');
t.integer('dailyid');
t.integer('dailyct');
t.string('comment');
t.integer('ivr');
});
console.log('PTable created');
}
};
const moveToPTable = async function() {
await createPTable();
const rec = await Db.db().select('*').from(process.env.DB_TABLE)
.where(function() {
this.where(function() {
this.whereNotNull('uniqueid')
.whereNull('actualuniqueid')
.whereNotIn('uniqueid', function() {
this.select('uniqueid').from('ptable');
})
})
.orWhere(function() {
this.whereNotNull('actualuniqueid')
.whereNotIn('actualuniqueid', function() {
this.select('uniqueid').from('ptable');
})
})
})
.where('duration', '>', 0)
.whereNotNull('realcall')
.where('realcall', '>=', 1)
.whereNot(function() {
this.whereNotNull('ivr')
.where('ivr', '=', 3)
.whereNull('startedat')
})
.orderBy('calldate', 'asc');
if (rec && rec.length) {
ComSrv.debug('Importing ' + rec.length + ' new records to PTable');
for (const r of rec) {
await moveSingleRecord(r);
}
}
setTimeout(moveToPTable, process.env.PTABLE_INTERVAL * 1000);
};
const initPTable = async function() {
await moveToPTable();
ComSrv.debug('PTable initialized');
};
module.exports = {
initPTable: initPTable,
config: Joi.object({
PTABLE_INTERVAL: Joi.number().min(1).max(300).default(10).optional()
})
};