Enables outbound PSTN probes via TwiML webhooks with Webex result cards, status polling, and optional store CDR enrichment.
81 lines
2.5 KiB
JavaScript
81 lines
2.5 KiB
JavaScript
// services/callTest/storeResolver.js
|
||
// Lightweight store main number lookup (same chain as phoneService, no Meraki fan-out).
|
||
|
||
import webex from '../../integrations/webex/WebexClient.js';
|
||
import { logger } from '../../utils/logger.js';
|
||
|
||
async function getPersonIdByEmail(email) {
|
||
if (!email) return null;
|
||
try {
|
||
const response = await webex.request('GET', 'people', null, { email });
|
||
const people = response.items || [];
|
||
return people.length ? people[0].id : null;
|
||
} catch (err) {
|
||
logger('calltest:resolver', `Person lookup failed: ${err.message}`, 'warn');
|
||
return null;
|
||
}
|
||
}
|
||
|
||
async function getDectNetworksForPerson(personId) {
|
||
if (!personId) return [];
|
||
try {
|
||
const response = await webex.request('GET', `telephony/config/people/${personId}/dectNetworks`);
|
||
const networks = response.dectNetworks || [];
|
||
return networks.map((net) => ({
|
||
id: net.id,
|
||
locationName: net.location?.name || '—',
|
||
locationId: net.location?.id || '—',
|
||
}));
|
||
} catch (err) {
|
||
logger('calltest:resolver', `DECT network lookup failed: ${err.message}`, 'warn');
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Resolve the store's public main number (auto-attendant DID).
|
||
*
|
||
* @param {string} storeNum 2–4 digit store number
|
||
*/
|
||
export async function resolveStoreMainNumber(storeNum) {
|
||
const store = String(storeNum).trim();
|
||
const padded = store.padStart(5, '0');
|
||
const email = `ae${padded}@ae.com`;
|
||
|
||
logger('calltest:resolver', `Resolving main number for store ${store} (${email})`, 'debug');
|
||
|
||
const personId = await getPersonIdByEmail(email);
|
||
if (!personId) {
|
||
throw new Error(`No Webex person found for store ${store} (${email})`);
|
||
}
|
||
|
||
const dectNets = await getDectNetworksForPerson(personId);
|
||
if (!dectNets.length) {
|
||
throw new Error(`No DECT network / location found for store ${store}`);
|
||
}
|
||
|
||
const net = dectNets[0];
|
||
const locationId = net.locationId && net.locationId !== '—' ? net.locationId : null;
|
||
const locationName = net.locationName && net.locationName !== '—' ? net.locationName : null;
|
||
|
||
if (!locationId) {
|
||
throw new Error(`No locationId on DECT network for store ${store}`);
|
||
}
|
||
|
||
const locationDetails = await webex.request('GET', `telephony/config/locations/${locationId}`).catch(() => null);
|
||
const dialNumber = locationDetails?.callingLineId?.phoneNumber
|
||
|| locationDetails?.phoneNumber
|
||
|| null;
|
||
|
||
if (!dialNumber) {
|
||
throw new Error(`No main number (callingLineId) on location for store ${store}`);
|
||
}
|
||
|
||
return {
|
||
storeNum: store,
|
||
dialNumber,
|
||
personId,
|
||
locationId,
|
||
locationName,
|
||
};
|
||
}
|