mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage-server
synced 2026-04-11 18:08:16 +00:00
233 lines
8.4 KiB
TypeScript
233 lines
8.4 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import { ConfigService } from '@nestjs/config';
|
|
import axios from 'axios';
|
|
|
|
@Injectable()
|
|
export class OzonetelAgentService {
|
|
private readonly logger = new Logger(OzonetelAgentService.name);
|
|
private readonly apiDomain: string;
|
|
private readonly apiKey: string;
|
|
private readonly accountId: string;
|
|
private cachedToken: string | null = null;
|
|
private tokenExpiry: number = 0;
|
|
|
|
constructor(private config: ConfigService) {
|
|
this.apiDomain = config.get<string>('exotel.subdomain') ?? 'in1-ccaas-api.ozonetel.com';
|
|
this.apiKey = config.get<string>('exotel.apiKey') ?? '';
|
|
this.accountId = config.get<string>('exotel.accountSid') ?? '';
|
|
}
|
|
|
|
private async getToken(): Promise<string> {
|
|
if (this.cachedToken && Date.now() < this.tokenExpiry) {
|
|
return this.cachedToken;
|
|
}
|
|
|
|
const url = `https://${this.apiDomain}/ca_apis/CAToken/generateToken`;
|
|
this.logger.log('Generating CloudAgent API token');
|
|
|
|
const response = await axios.post(url, { userName: this.accountId }, {
|
|
headers: { apiKey: this.apiKey, 'Content-Type': 'application/json' },
|
|
});
|
|
|
|
const data = response.data;
|
|
if (data.token) {
|
|
this.cachedToken = data.token;
|
|
this.tokenExpiry = Date.now() + 55 * 60 * 1000;
|
|
this.logger.log('CloudAgent token generated successfully');
|
|
return data.token;
|
|
}
|
|
|
|
throw new Error(data.message ?? 'Token generation failed');
|
|
}
|
|
|
|
async loginAgent(params: {
|
|
agentId: string;
|
|
password: string;
|
|
phoneNumber: string;
|
|
mode?: string;
|
|
}): Promise<{ status: string; message: string }> {
|
|
const url = `https://${this.apiDomain}/CAServices/AgentAuthenticationV2/index.php`;
|
|
|
|
this.logger.log(`Logging in agent ${params.agentId} with phone ${params.phoneNumber}`);
|
|
|
|
try {
|
|
const response = await axios.post(
|
|
url,
|
|
new URLSearchParams({
|
|
userName: this.accountId,
|
|
apiKey: this.apiKey,
|
|
phoneNumber: params.phoneNumber,
|
|
action: 'login',
|
|
mode: params.mode ?? 'blended',
|
|
state: 'Ready',
|
|
}).toString(),
|
|
{
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
auth: {
|
|
username: params.agentId,
|
|
password: params.password,
|
|
},
|
|
},
|
|
);
|
|
|
|
const data = response.data;
|
|
|
|
// "already logged in" is not a real error — treat as success
|
|
if (data.status === 'error' && data.message?.includes('already logged in')) {
|
|
this.logger.log(`Agent ${params.agentId} already logged in — treating as success`);
|
|
return { status: 'success', message: data.message };
|
|
}
|
|
|
|
this.logger.log(`Agent login response: ${JSON.stringify(data)}`);
|
|
return data;
|
|
} catch (error: any) {
|
|
this.logger.error(`Agent login failed: ${error.message}`);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async manualDial(params: {
|
|
agentId: string;
|
|
campaignName: string;
|
|
customerNumber: string;
|
|
}): Promise<{ status: string; ucid?: string; message?: string }> {
|
|
const url = `https://${this.apiDomain}/ca_apis/AgentManualDial`;
|
|
|
|
this.logger.log(`Manual dial: agent=${params.agentId} campaign=${params.campaignName} number=${params.customerNumber}`);
|
|
|
|
try {
|
|
const token = await this.getToken();
|
|
const response = await axios.post(url, {
|
|
userName: this.accountId,
|
|
agentID: params.agentId,
|
|
campaignName: params.campaignName,
|
|
customerNumber: params.customerNumber,
|
|
UCID: 'true',
|
|
}, {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
this.logger.log(`Manual dial response: ${JSON.stringify(response.data)}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
const responseData = error?.response?.data ? JSON.stringify(error.response.data) : '';
|
|
this.logger.error(`Manual dial failed: ${error.message} ${responseData}`);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async changeAgentState(params: {
|
|
agentId: string;
|
|
state: 'Ready' | 'Pause';
|
|
pauseReason?: string;
|
|
}): Promise<{ status: string; message: string }> {
|
|
const url = `https://${this.apiDomain}/ca_apis/changeAgentState`;
|
|
|
|
this.logger.log(`Changing agent ${params.agentId} state to ${params.state}`);
|
|
|
|
try {
|
|
const body: Record<string, string> = {
|
|
userName: this.accountId,
|
|
agentId: params.agentId,
|
|
state: params.state,
|
|
};
|
|
if (params.pauseReason) {
|
|
body.pauseReason = params.pauseReason;
|
|
}
|
|
|
|
const token = await this.getToken();
|
|
const response = await axios.post(url, body, {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
this.logger.log(`Change agent state response: ${JSON.stringify(response.data)}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
const responseData = error?.response?.data ? JSON.stringify(error.response.data) : '';
|
|
this.logger.error(`Change agent state failed: ${error.message} ${responseData}`);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async setDisposition(params: {
|
|
agentId: string;
|
|
ucid: string;
|
|
disposition: string;
|
|
}): Promise<{ status: string; message?: string; details?: string }> {
|
|
const url = `https://${this.apiDomain}/ca_apis/DispositionAPIV2`;
|
|
const did = process.env.OZONETEL_DID ?? '918041763265';
|
|
|
|
this.logger.log(`Set disposition: agent=${params.agentId} ucid=${params.ucid} disposition=${params.disposition}`);
|
|
|
|
try {
|
|
const token = await this.getToken();
|
|
const response = await axios.post(url, {
|
|
userName: this.accountId,
|
|
agentID: params.agentId,
|
|
did,
|
|
ucid: params.ucid,
|
|
action: 'Set',
|
|
disposition: params.disposition,
|
|
autoRelease: 'true',
|
|
}, {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
this.logger.log(`Set disposition response: ${JSON.stringify(response.data)}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
const responseData = error?.response?.data ? JSON.stringify(error.response.data) : '';
|
|
this.logger.error(`Set disposition failed: ${error.message} ${responseData}`);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async logoutAgent(params: {
|
|
agentId: string;
|
|
password: string;
|
|
}): Promise<{ status: string; message: string }> {
|
|
const url = `https://${this.apiDomain}/CAServices/AgentAuthenticationV2/index.php`;
|
|
|
|
this.logger.log(`Logging out agent ${params.agentId}`);
|
|
|
|
try {
|
|
const response = await axios.post(
|
|
url,
|
|
new URLSearchParams({
|
|
userName: this.accountId,
|
|
apiKey: this.apiKey,
|
|
action: 'logout',
|
|
mode: 'blended',
|
|
state: 'Ready',
|
|
}).toString(),
|
|
{
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
auth: {
|
|
username: params.agentId,
|
|
password: params.password,
|
|
},
|
|
},
|
|
);
|
|
|
|
this.logger.log(`Agent logout response: ${JSON.stringify(response.data)}`);
|
|
return response.data;
|
|
} catch (error: any) {
|
|
this.logger.error(`Agent logout failed: ${error.message}`);
|
|
throw error;
|
|
}
|
|
}
|
|
}
|