#include "StdAfx.h" #include "IvrFlowHolder.h" #include "IvrFlow.h" #include "CtiCore.h" #include "TaskMgr.h" #include "Inc/CallDetailInc.h" #include "StatisticsMgr.h" #include "NetworkCti.h" #include "LogicLine.h" #include "LineHolder.h" SINGLETON_IMPLEMENT(CIvrFlowHolder) CIvrFlowHolder::CIvrFlowHolder(void) { } CIvrFlowHolder::~CIvrFlowHolder(void) { } /***************************************************************** **【函数名称】 __procCallInReturn **【函数功能】 处理CallIn命令返回 **【参数】 PduEntity:消息实体 **【返回值】 ****************************************************************/ void CIvrFlowHolder::__procCallInReturn( CPduEntity &PduEntity ) { // 显示日志 ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL,_T("IVR->CTI, CMD = return[CallIn], \ IVR = %d, Line = %d, CallerNum = %s, CalleeNum = %s, IsSuccess = %d"), PduEntity.GetDataInt(1), PduEntity.GetDataUInt(5), PduEntity.GetDataString(3), PduEntity.GetDataString(4), PduEntity.GetDataBool(0)); // 转发给IvrFlow __transmitToIvrFlow(PduEntity); } /***************************************************************** **【函数名称】 __procTurnIvrReturn **【函数功能】 处理转Ivr命令返回 **【参数】 PduEntity: 消息实体 **【返回值】 ****************************************************************/ void CIvrFlowHolder::__procTurnIvrReturn( CPduEntity &PduEntity ) { // 显示日志 ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_NORMAL,_T("IVR->CTI, Cmd = return[TurnIVR], \ IVR = %d, Line = %d, CallerNum = %s, CalleeNum = %s, IsSuccess = %d"), PduEntity.GetDataInt(1), PduEntity.GetDataUInt(5), PduEntity.GetDataString(3), PduEntity.GetDataString(4), PduEntity.GetDataBool(0)); // 如果IVR不存在,通知Task转IVR失败 if(PduEntity.GetDataInt(1) == -1) CTaskMgr::GetInstance().onTaskPduMsg(PduEntity.GetDataUInt(5), PduEntity); else __transmitToIvrFlow(PduEntity); } /***************************************************************** **【函数名称】 __transmitToIvrFlow **【函数功能】 命令转发给IvrFlow **【参数】 PduEntity: 消息实体 **【返回值】 ****************************************************************/ void CIvrFlowHolder::__transmitToIvrFlow( CPduEntity &PduEntity ) { // 根据IvrId获取Ivr对象 CIvrFlow *pIvrFlow = getFlowByIvrId(PduEntity.GetDataInt(1)); if(pIvrFlow == NULL) { ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_ERROR, _T("{IvrFlowHolder}: 向IVR转发命令时定位不到IvrFlow,IVR = %d"), PduEntity.GetDataInt(1)); if (PDU_CMD_CTI_IVR_CALLIN == PduEntity.GetCmdType()) // 通知IVR外线来电消息返回,注:只有该类型添加的第二个字段数据其值为CallID { // 统计找不到IVR流程资源造成的呼入失败记录 T_EvtError repInfo; memset(&repInfo, 0, sizeof(repInfo)); repInfo.nErrorType = REP_ERROR_IVRFLOW; CStatisticsMgr::GetInstance().onCallDetail(PduEntity.GetDataULong(2), REP_EVENT_ERROR, PduEntity.GetDataUInt(5), &repInfo); } // 命令返回失败 if(PduEntity.GetIsExecReturn()) return; PduEntity.SetToExecReturn(); PduEntity.SetDataBool(0, false); CNetworkCti::GetInstance().send2IVR(PduEntity); } else { PDU_CMD_TYPE CmdType = PduEntity.GetCmdType(); if (PDU_CMD_IVR_WANT_AGENT == CmdType) { // 在处理ACD相关消息时,添加判断是否与ACD正常连接,若没有正常连接则与ACD相关的操作数据记录为呼损数据。 if (!CNetworkCti::GetInstance().isACDConnected()) { // 显示日志 ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING,_T("{IvrFlowHolder}: 执行来电排队操作失败,ACD未连接到系统,或ACD未启动!")); // 统计ACD未启动造成呼入失败记录 T_EvtError repInfo; memset(&repInfo, 0, sizeof(repInfo)); repInfo.nErrorType = REP_ERROR_ACD; CStatisticsMgr::GetInstance().onCallDetail(PduEntity.GetDataULong(2), REP_EVENT_ERROR, PduEntity.GetDataInt(5), &repInfo); } } pIvrFlow->onPduMessage(PduEntity); } } /***************************************************************** **【函数名称】 __procDevOpCallIn **【函数功能】 处理底层设备外线呼入 **【参数】 DevOpInfo: 底层操作数据 **【返回值】 ****************************************************************/ void CIvrFlowHolder::__procDevOpCallIn( EventDevOperation &DevOpInfo ) { T_EvtError repInfo; memset(&repInfo, 0, sizeof(repInfo)); // 获取线路类指针 CLogicLine *pLogicLine = CLineHolder::GetInstance().getLogicLine(DevOpInfo.nLineId); if(pLogicLine == NULL) return; if(pLogicLine->type() != DEV_RES_TYPE_TRUNK && pLogicLine->type() != DEV_RES_TYPE_VOIP) { repInfo.nErrorType = REP_ERROR_SYSTEM; CStatisticsMgr::GetInstance().onCallDetail(pLogicLine->callId(), REP_EVENT_ERROR, DevOpInfo.nLineId, &repInfo); ILogger::getInstance().log(LOG_CLASS_BUSI, LOG_LEVEL_WARNING,_T("{IvrFlowHolder}: 外线呼入通知IVR时检测到线路类型非外线, Line Id = %u, type = %u"), pLogicLine->lineId(), pLogicLine->type()); } // 判断IVR是否断开连接,如果断开连接则作为外线呼入失败记录 if (!CNetworkCti::GetInstance().isIVRConnected()) { // 显示日志 ILogger::getInstance().log(LOG_CLASS_SOCKET, LOG_LEVEL_WARNING,_T("{IvrFlowHolder}: 外线呼入通知IVR失败,IVR未连接到系统,或IVR未启动")); // 统计IVR未启动造成呼入失败记录 repInfo.nErrorType = REP_ERROR_IVR; CStatisticsMgr::GetInstance().onCallDetail(pLogicLine->callId(), REP_EVENT_ERROR, DevOpInfo.nLineId, &repInfo); } else { // 通知IVR程序外线来电 CPduEntity CmdCallIn(PDU_CMD_CTI_IVR_CALLIN); CmdCallIn.SetDataULong(2, pLogicLine->callId()); CmdCallIn.SetDataString(3, DevOpInfo.szCallerNum); CmdCallIn.SetDataString(4, DevOpInfo.szCalleeNum); CmdCallIn.SetDataUInt(5, DevOpInfo.nLineId); CNetworkCti::GetInstance().send2IVR(CmdCallIn); } } /***************************************************************** **【函数名称】 createIvrFlow **【函数功能】 创建IvrFlow **【参数】 **【返回值】 ****************************************************************/ void CIvrFlowHolder::createIvrFlow( int IvrFlowNum ) { for(int i = 0; i < IvrFlowNum; i++) { CIvrFlow *pIvrFlow = new CIvrFlow(i); m_IvrFlowMap.SetAt(i, pIvrFlow); } } /***************************************************************** **【函数名称】 destroyIvrFlow **【函数功能】 销毁IvrFlow **【参数】 **【返回值】 ****************************************************************/ void CIvrFlowHolder::destroyIvrFlow( void ) { UINT Key = 0; CIvrFlow *pIvrFlow = NULL; POSITION pos = m_IvrFlowMap.GetStartPosition(); while(pos != NULL) { m_IvrFlowMap.GetNextAssoc(pos, Key, pIvrFlow); if(pIvrFlow != NULL) delete pIvrFlow; } // end while m_IvrFlowMap.RemoveAll(); } /***************************************************************** **【函数名称】 onPduMessage **【函数功能】 Pdu命令处理接口 **【参数】 PduEntity:消息实体 **【返回值】 ***************************************************************/ void CIvrFlowHolder::onPduMessage( CPduEntity &PduEntity ) { switch(PduEntity.GetCmdType()) { case PDU_CMD_CTI_IVR_CALLIN: // CallIn命令返回 __procCallInReturn(PduEntity); break; case PDU_CMD_CTI_IVR_TURNIVR: // 转Ivr命令 __procTurnIvrReturn(PduEntity); break; default: // 命令转发给IvrFlow __transmitToIvrFlow(PduEntity); break; } } /***************************************************************** **【函数名称】 onDevMessage **【函数功能】 底层设备事件 **【参数】 EvtType 消息事件类型 lpContent 消息内容 **【返回值】 ****************************************************************/ void CIvrFlowHolder::onDevMessage( EventDevOperation &DevOpInfo ) { switch(DevOpInfo.nOpType) { case DEV_OP_CALL_IN: __procDevOpCallIn(DevOpInfo); break; default: break; } } /***************************************************************** **【函数名称】 onIvrDisconnect **【函数功能】 处理Ivr连接断开 **【参数】 **【返回值】 ****************************************************************/ void CIvrFlowHolder::onIvrDisconnect(void) { UINT nIndex; CIvrFlow *pIvrFlow = NULL; POSITION pos = m_IvrFlowMap.GetStartPosition(); // 循环遍历结束所有Ivrflow while(pos != NULL) { m_IvrFlowMap.GetNextAssoc(pos, nIndex, pIvrFlow); if(pIvrFlow == NULL) continue; // 向关联线路发送挂机命令 if(pIvrFlow->assoLineId() != -1) CCtiCore::GetInstance().getDevLink().exec(-1, LINE_OP_HANG_UP, pIvrFlow->assoLineId(), NULL); // Ivrflow重置 pIvrFlow->resetFlow(); } } /***************************************************************** **【函数名称】 getFlowByIvrId **【函数功能】 通过IvrId获取关联的IVR流程 **【参数】 IvrId: IVR ID **【返回值】 CIvrFlow对象 ****************************************************************/ CIvrFlow* CIvrFlowHolder::getFlowByIvrId( int IvrId ) { CIvrFlow *pIvrFlow = NULL; m_IvrFlowMap.Lookup(IvrId, pIvrFlow); return pIvrFlow; } /***************************************************************** **【函数名称】 getFlowByLineId **【函数功能】 通过线路号获取关联的IVR流程 **【参数】 LineId: 线路号 **【返回值】 CIvrFlow对象 ****************************************************************/ CIvrFlow* CIvrFlowHolder::getFlowByLineId( int LineId ) { UINT nIndex; CIvrFlow *pIvrFlow = NULL; POSITION pos = m_IvrFlowMap.GetStartPosition(); while(pos != NULL) { m_IvrFlowMap.GetNextAssoc(pos, nIndex, pIvrFlow); if(pIvrFlow != NULL && pIvrFlow->assoLineId() == LineId) return pIvrFlow; } return NULL; }