Add store/email/phone filtering, richer call-line formatting, CDR feed pagination and queueing, and split Jira poller enrichment into testable modules. Co-authored-by: Cursor <cursoragent@cursor.com>
107 lines
3.6 KiB
JavaScript
107 lines
3.6 KiB
JavaScript
// commands/callReport.js
|
||
|
||
import { DateTime } from 'luxon';
|
||
import { logger } from '../utils/logger.js';
|
||
import { collectCallReport } from '../services/callReport/callReportService.js';
|
||
import { renderCallReportMarkdown } from '../services/renderers/callReportRenderer.js';
|
||
import { parseCallReportTarget } from '../services/callReport/parseTarget.js';
|
||
|
||
function pickDateArg(args) {
|
||
const targetParsed = parseCallReportTarget(args[0]);
|
||
for (let i = 1; i < args.length; i++) {
|
||
const a = String(args[i] || '').trim();
|
||
if (!a || a.startsWith('--')) continue;
|
||
if (i === 1 && targetParsed?.kind === 'store' && /^\d{2,4}$/.test(a)) continue;
|
||
return a;
|
||
}
|
||
const flag = args.find((a) => String(a).startsWith('--date='));
|
||
if (flag) return flag.split('=').slice(1).join('=');
|
||
const idx = args.indexOf('--date');
|
||
if (idx >= 0 && args[idx + 1]) return args[idx + 1];
|
||
return null;
|
||
}
|
||
|
||
function hasDetailFlag(args, query) {
|
||
return args.some((a) => ['detail', 'detailed', '--detail', '--detailed'].includes(String(a).toLowerCase()))
|
||
|| query.detail === 'true'
|
||
|| query.detailed === 'true';
|
||
}
|
||
|
||
function formatQueuedRunAt(runAt) {
|
||
return DateTime.fromJSDate(runAt).toFormat('h:mm:ss a');
|
||
}
|
||
|
||
function pickTargetArg(args, query) {
|
||
return args[0]?.trim()
|
||
|| query.target
|
||
|| query.storeNum
|
||
|| query.store
|
||
|| query.email
|
||
|| query.number
|
||
|| query.s
|
||
|| null;
|
||
}
|
||
|
||
function usageMarkdown() {
|
||
return (
|
||
'**Call report usage**\n\n' +
|
||
'`/callreport <store>` — yesterday 9am–9pm local (default)\n' +
|
||
'`/callreport <email>` — calls for that user at their location\n' +
|
||
'`/callreport <phone>` — calls for that assigned number\n' +
|
||
'`/callreport <target> today` — today 9am → 5 min ago\n' +
|
||
'`/callreport <target> 2026-07-22` — specific day\n' +
|
||
'`/callreport <target> --detail` — include per-call table\n\n' +
|
||
'HTTP: `?target=782&date=yesterday&detail=true` (also `storeNum`, `email`, `number`)'
|
||
);
|
||
}
|
||
|
||
function ackLabel(target) {
|
||
if (!target) return 'target';
|
||
if (target.kind === 'store') return `store **${target.storeNum}**`;
|
||
if (target.locationName) return `**${target.label}** (${target.locationName})`;
|
||
return `**${target.label}**`;
|
||
}
|
||
|
||
export async function handleCallReport(bot, trigger) {
|
||
logger('callreport', 'Handler entered', 'debug');
|
||
|
||
const query = trigger.query || {};
|
||
const args = trigger.args || [];
|
||
|
||
const targetToken = pickTargetArg(args, query);
|
||
const dateArg = pickDateArg(args) || query.date || null;
|
||
const detail = hasDetailFlag(args, query);
|
||
|
||
if (!targetToken || !parseCallReportTarget(targetToken)) {
|
||
await bot.say('markdown', usageMarkdown());
|
||
return;
|
||
}
|
||
|
||
await bot.say(
|
||
'markdown',
|
||
`**Call report** — generating for ${ackLabel({ label: targetToken })} (${dateArg || 'yesterday'})…`,
|
||
);
|
||
|
||
let cdrQueuedNoticeSent = false;
|
||
|
||
try {
|
||
const report = await collectCallReport(targetToken, {
|
||
dateArg,
|
||
onCdrQueued: async ({ runAt, waitMs }) => {
|
||
if (cdrQueuedNoticeSent) return;
|
||
cdrQueuedNoticeSent = true;
|
||
const secs = Math.max(1, Math.ceil(waitMs / 1000));
|
||
await bot.say(
|
||
'markdown',
|
||
`⏳ **Call report** — CDR query queued. Webex allows one \`cdr_feed\` request per ~90 seconds. ` +
|
||
`Your request will run at **${formatQueuedRunAt(runAt)}** (~${secs}s).`,
|
||
);
|
||
},
|
||
});
|
||
const md = renderCallReportMarkdown(report, { detail });
|
||
await bot.say('markdown', md);
|
||
} catch (err) {
|
||
logger('callreport', `Failed for target ${targetToken}: ${err.message}`, 'error');
|
||
await bot.say('markdown', `❌ Call report failed for **${targetToken}**: ${err.message}`);
|
||
}
|
||
}
|