|
@@ -1,46 +1,251 @@
|
|
|
#!/usr/bin/env python3
|
|
|
# encoding:utf-8
|
|
|
|
|
|
-import traceback
|
|
|
-from typing import List
|
|
|
+import threading
|
|
|
from collections import defaultdict
|
|
|
-from src.core.callcenter.constant import START_AGENT_NUM
|
|
|
-from src.core.callcenter.enumeration import AgentState, AgentCheck, AgentHeartState, AgentServiceState, AgentLogState, \
|
|
|
- AgentScene, BizErrorCode, WorkStatus, DownEvent, HumanState
|
|
|
+from concurrent.futures import ThreadPoolExecutor
|
|
|
+from typing import List
|
|
|
+
|
|
|
from sqlalchemy import or_
|
|
|
+
|
|
|
+import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
|
|
|
+from src.core import with_app_context
|
|
|
+from src.core.callcenter.api import AgentActionRequest, AgentQueryRequest, AgentRequest, AgentEventData, \
|
|
|
+ AgentStateData, HumanServiceQueryRequest, AgentMonitorData, CallInfo, DeviceInfo, AgentDelayStateData
|
|
|
+from src.core.callcenter.cache import Cache
|
|
|
from src.core.callcenter.dao import *
|
|
|
+from src.core.callcenter.data_handler import DataHandleServer
|
|
|
+from src.core.callcenter.enumeration import AgentState, AgentCheck, AgentHeartState, AgentServiceState, AgentLogState, \
|
|
|
+ AgentScene, BizErrorCode, WorkStatus, DownEvent, HumanState, DeviceType, ServiceDirect
|
|
|
+from src.core.callcenter.esl.constant.event_names import *
|
|
|
from src.core.callcenter.exception import BizException
|
|
|
-from src.core.callcenter.api import AgentActionRequest, AgentInfo, AgentQueryRequest, AgentRequest, AgentEventData, \
|
|
|
- AgentStateData, HumanServiceQueryRequest, AgentMonitorData
|
|
|
from src.core.callcenter.push import PushHandler
|
|
|
from src.core.datasource import RedisHandler
|
|
|
|
|
|
-from concurrent.futures import ThreadPoolExecutor
|
|
|
-import threading
|
|
|
+
|
|
|
+class AgentEventService:
|
|
|
+ def __init__(self, app):
|
|
|
+ self.app = app
|
|
|
+ self.logger = app.logger
|
|
|
+ self.cache = Cache(app)
|
|
|
+ self.push_handler = PushHandler(app.logger)
|
|
|
+ self.data_handle_server = DataHandleServer(app)
|
|
|
+ self.agent_monitor_service = AgentMonitorService(app)
|
|
|
+ self.agent_state_service = AgentStateService(app)
|
|
|
+ self.agent_actionlog_service = AgentActionLogService(app)
|
|
|
+
|
|
|
+ def delay_state(self, state_data: AgentDelayStateData):
|
|
|
+ agent = self.data_handle_server.get_agent(state_data.saas_id, state_data.agent_num)
|
|
|
+ if not agent:
|
|
|
+ return
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(state_data.saas_id, state_data.agent_num)
|
|
|
+ if not agent_monitor:
|
|
|
+ return
|
|
|
+
|
|
|
+ #TODO 非最新通话的延迟事件,忽略.
|
|
|
+
|
|
|
+ agent_scene = AgentScene.get_by_code(state_data.scene)
|
|
|
+ self.logger.info("agent event delay state %s %s %s %s", state_data.saas_id, state_data.agent_num, state_data.service_state, agent_monitor.service_state)
|
|
|
+ if AgentServiceState.REPROCESSING.code == state_data.service_state and AgentServiceState.REPROCESSING.code == agent_monitor.service_state:
|
|
|
+ self.reprocessing_idle(state_data)
|
|
|
+
|
|
|
+ if AgentServiceState.DIALING.code == state_data.service_state and AgentServiceState.DIALING.code == agent_monitor.service_state:
|
|
|
+ if self.cache.get_call_is_answer(state_data.saas_id, state_data.agent_num):
|
|
|
+ return
|
|
|
+ self.agent_monitor_service.update_idle(agent_monitor)
|
|
|
+
|
|
|
+ self.push_handler.push_on_call_end(state_data.saas_id, state_data.flow_id, state_data.agent_num, agent_scene, ServiceDirect.MANUAL_CALL.service_direct, '0')
|
|
|
+ self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, '', agent_scene, WorkStatus.AGENT_HANG_REPROCESSING)
|
|
|
+ self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, '', agent_scene, WorkStatus.AGENT_HANG_IDLE)
|
|
|
+
|
|
|
+ self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.IDLE, AgentLogState.BIZ_DIALING_IDLE)
|
|
|
+
|
|
|
+ if AgentServiceState.HANGING.code == state_data.service_state \
|
|
|
+ and (AgentServiceState.DIALING.code == agent_monitor.service_state
|
|
|
+ or AgentServiceState.CALLING.code == agent_monitor.service_state):
|
|
|
+ self.agent_monitor_service.update_idle(agent_monitor)
|
|
|
+
|
|
|
+ if AgentServiceState.DIALING.code == agent_monitor.service_state:
|
|
|
+ self.push_handler.push_on_call_end(state_data.saas_id, state_data.flow_id, state_data.agent_num, agent_scene, ServiceDirect.MANUAL_CALL.service_direct, '0')
|
|
|
+ self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, '', agent_scene, WorkStatus.AGENT_HANG_REPROCESSING)
|
|
|
+
|
|
|
+ self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, '', agent_scene, WorkStatus.AGENT_HANG_IDLE)
|
|
|
+ self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.IDLE, AgentLogState.MANUAL_HANG_UP)
|
|
|
+
|
|
|
+
|
|
|
+ def agent_event_channel(self, event, call_info: CallInfo, device_info: DeviceInfo):
|
|
|
+ event_name = EslEventUtil.getEventName(event)
|
|
|
+ saas_id = call_info.saas_id if call_info else None
|
|
|
+ flow_id = call_info.cti_flow_id if call_info else None
|
|
|
+ call_id = call_info.call_id if call_info else None
|
|
|
+ device_id = device_info.device_id if device_info else None
|
|
|
+ agent_num = device_info.agent_key if device_info else None
|
|
|
+ caller = device_info.caller if device_info else None
|
|
|
+ called = device_info.called if device_info else None
|
|
|
+ is_agent = (device_info and DeviceType.AGENT.code == device_info.device_type) if device_info else False
|
|
|
+
|
|
|
+ self.logger.info('agent_event_channel, event_name=%s, call_id=%s, device_id=%s, is_agent=%s', event_name, call_id, device_id, is_agent)
|
|
|
+ agent = self.data_handle_server.get_agent(saas_id, agent_num)
|
|
|
+ if not agent:
|
|
|
+ # self.logger.warn("event service channel agent is null %s %s %s %s %s", saas_id, event_name, caller, called, json.loads(event.serialize('json')))
|
|
|
+ return
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_num)
|
|
|
+ if not agent_monitor:
|
|
|
+ # self.logger.warn("event service channel agentMonitor is null %s %s %s %s %s", saas_id, event_name, caller, called, json.loads(event.serialize('json')))
|
|
|
+ return
|
|
|
+
|
|
|
+ # 信道发起事件,触发完成发起(或桥)&& 坐席侧
|
|
|
+ if CHANNEL_ORIGINATE == event_name and is_agent:
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_RINGING)
|
|
|
+
|
|
|
+ # 进度事件,外呼时对方提醒。或者入呼时提醒 && 坐席侧
|
|
|
+ if CHANNEL_PROGRESS == event_name and is_agent:
|
|
|
+ self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.MANUAL, AgentServiceState.DIALING)
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_CALLING)
|
|
|
+
|
|
|
+ # 媒体进度事件,外呼时对方提醒。或者入呼时提醒 && 用户侧
|
|
|
+ if CHANNEL_PROGRESS_MEDIA == event_name and not is_agent:
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_CALLING_RINGING)
|
|
|
+
|
|
|
+ #应答
|
|
|
+ if CHANNEL_ANSWER == event_name:
|
|
|
+ if call_id:
|
|
|
+ if self.cache.get_call_is_end(call_id):
|
|
|
+ # self.logger.warn("event service channel call is end {} {} {} {} {} {}", saas_id, event_name, caller, called, call_id, json.dumps(event.serialize('json')))
|
|
|
+ return
|
|
|
+
|
|
|
+ self.agent_state_service.busy(saas_id, agent.agent_num, agent.phone_num)
|
|
|
+ if is_agent:
|
|
|
+ # 坐席接起
|
|
|
+ self.cache.set_call_is_answer(saas_id, flow_id)
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.ANSWER_COMPENSATE)
|
|
|
+ self.push_handler.push_answer_call(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, ServiceDirect.MANUAL_CALL.service_direct, WorkStatus.AGENT_HANG_REPROCESSING)
|
|
|
+
|
|
|
+ self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.CALLING, AgentLogState.CHANNEL_TURN_ON)
|
|
|
+ else:
|
|
|
+ # 用户侧接起
|
|
|
+ self.agent_monitor_service.update_calling(agent_monitor)
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_ANSWER_OUTGOING)
|
|
|
+ self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.MANUAL, AgentServiceState.CALLING)
|
|
|
+
|
|
|
+ #挂断
|
|
|
+ if CHANNEL_HANGUP == event_name:
|
|
|
+ # 坐席侧挂断
|
|
|
+ if is_agent:
|
|
|
+ if call_id:
|
|
|
+ self.cache.set_call_is_end(call_id)
|
|
|
+
|
|
|
+ self.agent_monitor_service.update_processing(agent_monitor)
|
|
|
+ self.reprocessing_idle(AgentDelayStateData(saas_id, flow_id, agent_num, AgentServiceState.REPROCESSING, AgentScene.MANUAL))
|
|
|
+ self.push_handler.push_on_call_end(saas_id, flow_id, agent_num, AgentScene.MANUAL, ServiceDirect.MANUAL_CALL.service_direct, '0')
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_HANG_REPROCESSING)
|
|
|
+ self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.MANUAL, AgentServiceState.REPROCESSING)
|
|
|
+
|
|
|
+ self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.REPROCESSING, AgentLogState.CHANNEL_HANG_UP)
|
|
|
+
|
|
|
+ # 同步处理后处理置闲
|
|
|
+ # reprocessingIdle(statusDto);
|
|
|
+ # agentProducer.pushDelayedStatus(statusDto, reprocessingTimeout);
|
|
|
+
|
|
|
+ if (CHANNEL_BRIDGE == event_name or PLAYBACK_START == event_name) and is_agent:
|
|
|
+ self.push_handler.push_on_ring_start(saas_id, flow_id, agent_num, AgentScene.MANUAL, call_id)
|
|
|
+ # self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_ANSWER_OUTGOING)
|
|
|
+ # self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.MANUAL, AgentServiceState.CALLING)
|
|
|
+
|
|
|
+ if DETECTED_TONE == event_name and not is_agent:
|
|
|
+ self.push_handler.push_on_detected_tone(saas_id, flow_id, call_id, AgentScene.MANUAL, call_id)
|
|
|
+
|
|
|
+ if (CHANNEL_UNBRIDGE == event_name or PLAYBACK_STOP == event_name) and is_agent:
|
|
|
+ self.push_handler.push_on_ring_end(saas_id, flow_id, call_id, AgentScene.MANUAL, call_id)
|
|
|
+
|
|
|
+
|
|
|
+ def bot_event_channel(self, event, call_info, device_info):
|
|
|
+ event_name = EslEventUtil.getEventName(event)
|
|
|
+ saas_id = call_info.saas_id if call_info else None
|
|
|
+ flow_id = call_info.cti_flow_id if call_info else None
|
|
|
+ call_id = call_info.call_id if call_info else None
|
|
|
+ agent_num = device_info.agent_key if device_info else None
|
|
|
+ is_agent = (device_info and DeviceType.AGENT.code == device_info.device_type) if device_info else False
|
|
|
+ caller = (device_info.called if is_agent else device_info.caller) if device_info else None
|
|
|
+ called = (device_info.caller if is_agent else device_info.called) if device_info else None
|
|
|
+ human_service_id = '00000000000000000'
|
|
|
+
|
|
|
+ agent = self.data_handle_server.get_agent(saas_id, agent_num)
|
|
|
+ if not agent:
|
|
|
+ # self.logger.warn("bot event service channel agent is null %s %s %s %s %s", saas_id, event_name, caller, called,
|
|
|
+ # json.dumps(event.serialize('json')))
|
|
|
+ return
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_num)
|
|
|
+ if not agent_monitor:
|
|
|
+ # self.logger.warn("bot event service channel agentMonitor is null %s %s %s %s %s", saas_id, event_name, caller,
|
|
|
+ # called, json.dumps(event.serialize('json')))
|
|
|
+ return
|
|
|
+
|
|
|
+ # 信道发起事件,触发完成发起(或桥)&& 坐席侧
|
|
|
+ if CHANNEL_ORIGINATE == event_name and is_agent:
|
|
|
+ self.push_handler.push_on_call_ring(saas_id, flow_id, agent_num, AgentScene.ROBOT, call_id, ServiceDirect.ROBOT_CALL.service_direct, called, caller, human_service_id)
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, WorkStatus.AGENT_RINGING)
|
|
|
+
|
|
|
+
|
|
|
+ if CHANNEL_ANSWER == event_name:
|
|
|
+ self.agent_state_service.busy(saas_id, agent.agent_num, agent.phone_num)
|
|
|
+ if is_agent:
|
|
|
+ self.agent_monitor_service.update_calling(agent_monitor)
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, WorkStatus.AGENT_ANSWER_INCOMING, "座席接通呼入电话! internal")
|
|
|
+ self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.ROBOT, AgentServiceState.CALLING)
|
|
|
+ self.push_handler.push_answer_call(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, ServiceDirect.ROBOT_CALL.service_direct, WorkStatus.AGENT_HANG_REPROCESSING)
|
|
|
+
|
|
|
+ self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.CALLING, AgentLogState.CHANNEL_TURN_ON, service_id=human_service_id)
|
|
|
+ else:
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, WorkStatus.AGENT_ANSWER_INCOMING, "座席接通呼入电话! external")
|
|
|
+
|
|
|
+ if CHANNEL_HANGUP == event_name and is_agent:
|
|
|
+ self.agent_monitor_service.update_processing(agent_monitor)
|
|
|
+ self.push_handler.push_on_call_end(saas_id, flow_id, agent_num, AgentScene.ROBOT, ServiceDirect.ROBOT_CALL.service_direct, "0")
|
|
|
+ self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, WorkStatus.AGENT_HANG_REPROCESSING)
|
|
|
+ self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.ROBOT, AgentServiceState.REPROCESSING)
|
|
|
+
|
|
|
+ self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.REPROCESSING,
|
|
|
+ AgentLogState.CHANNEL_HANG_UP, service_id=human_service_id)
|
|
|
+
|
|
|
+
|
|
|
+ def reprocessing_idle(self, state_data: AgentDelayStateData):
|
|
|
+ agent = self.data_handle_server.get_agent(state_data.saas_id, state_data.agent_num)
|
|
|
+ if not agent:
|
|
|
+ return
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(state_data.saas_id, state_data.agent_num)
|
|
|
+ if not agent_monitor:
|
|
|
+ return
|
|
|
+ self.agent_monitor_service.update_idle(agent_monitor)
|
|
|
+ self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, "", state_data.scene, WorkStatus.AGENT_HANG_IDLE)
|
|
|
+ self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.IDLE, AgentLogState.REPROCESSING_IDLE)
|
|
|
|
|
|
|
|
|
class AgentOperService:
|
|
|
|
|
|
- def __init__(self, client, logger):
|
|
|
- self.inbound_client = client
|
|
|
- self.logger = logger
|
|
|
- self.push_handler = PushHandler(logger)
|
|
|
- self.agent_monitor_service = AgentMonitorService(client, logger)
|
|
|
- self.agent_actionlog_service = AgentActionLogService(client, logger)
|
|
|
- self.agent_state_service = AgentStateService(client, logger)
|
|
|
+ def __init__(self, app):
|
|
|
+ self.app = app
|
|
|
+ self.logger = app.logger
|
|
|
+ self.push_handler = PushHandler(app.logger)
|
|
|
+ self.data_handle_server = DataHandleServer(app)
|
|
|
+ self.agent_monitor_service = AgentMonitorService(app)
|
|
|
+ self.agent_actionlog_service = AgentActionLogService(app)
|
|
|
+ self.agent_state_service = AgentStateService(app)
|
|
|
|
|
|
+ @with_app_context
|
|
|
def enable(self, req: AgentActionRequest):
|
|
|
- agent = _get_agent(req.saas_id, req.agent_number, req.out_id)
|
|
|
+ agent = self.data_handle_server.get_agent(req.saas_id, req.agent_number, req.out_id)
|
|
|
if agent.agent_state == AgentState.ENABLE.code:
|
|
|
return
|
|
|
agent.agent_state = AgentState.ENABLE.code
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def disable(self, req: AgentActionRequest):
|
|
|
- agent = _get_agent(req.saas_id, req.agent_id)
|
|
|
+ agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
|
|
|
if agent.agent_state == AgentState.DISABLE.code:
|
|
|
return
|
|
|
- agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_number)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_number)
|
|
|
if agent_monitor.check_state == AgentCheck.IN.code and \
|
|
|
agent_monitor.service_state == AgentServiceState.CALLING.code:
|
|
|
raise BizException(BizErrorCode.AGENT_CALLING_NOT_ALLOW_OPERATE)
|
|
@@ -49,36 +254,34 @@ class AgentOperService:
|
|
|
agent.agent_state = AgentState.DISABLE.code
|
|
|
db.session.commit()
|
|
|
|
|
|
- phone = _get_phone(req.saas_id, agent.phone_num)
|
|
|
+ phone = self.data_handle_server.get_phone(req.saas_id, agent.phone_num)
|
|
|
phone.is_delete = 1
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def checkin(self, req: AgentActionRequest):
|
|
|
- try:
|
|
|
- agent = _get_agent(req.saas_id, req.agent_id)
|
|
|
- if not agent or agent.agent_state == AgentState.DISABLE.code:
|
|
|
- raise BizException(BizErrorCode.ERROR_NOT_FOLLOW_CHECK_IN)
|
|
|
- phone = _get_phone(req.saas_id, agent.phone_num)
|
|
|
- agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_num)
|
|
|
- agent_monitor.check_scene = req.scene
|
|
|
- self.agent_monitor_service.update_checkin(agent_monitor)
|
|
|
- self.agent_actionlog_service.insert_check_state(agent_monitor, AgentCheck.IN, AgentLogState.CHECKIN)
|
|
|
- self.agent_state_service.checkin(agent.saas_id, agent.out_id, agent.phone_num)
|
|
|
-
|
|
|
- if req.scene == AgentScene.MANUAL.code:
|
|
|
- # 如果是手动外呼增加置闲
|
|
|
- self._handle_idle(req.scene, agent)
|
|
|
- return self._push_event_for_checkin(agent, agent_monitor, phone, req.scene)
|
|
|
- except Exception as e:
|
|
|
- self.logger.error(traceback.format_exc())
|
|
|
- raise e
|
|
|
-
|
|
|
+ agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
|
|
|
+ if not agent or agent.agent_state == AgentState.DISABLE.code:
|
|
|
+ raise BizException(BizErrorCode.ERROR_NOT_FOLLOW_CHECK_IN)
|
|
|
+ phone = self.data_handle_server.get_phone(req.saas_id, agent.phone_num)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_num)
|
|
|
+ agent_monitor.check_scene = req.scene
|
|
|
+ self.agent_monitor_service.update_checkin(agent_monitor)
|
|
|
+ self.agent_actionlog_service.insert_check_state(agent_monitor, AgentCheck.IN, AgentLogState.CHECKIN)
|
|
|
+ self.agent_state_service.checkin(agent.saas_id, agent.out_id, agent.phone_num)
|
|
|
+
|
|
|
+ # if req.scene == AgentScene.MANUAL.code:
|
|
|
+ # # 如果是手动外呼增加置忙
|
|
|
+ # self._handle_idle(req.scene, agent)
|
|
|
+ return self._push_event_for_checkin(agent, agent_monitor, phone, req.scene)
|
|
|
+
|
|
|
+ @with_app_context
|
|
|
def checkout(self, req: AgentActionRequest):
|
|
|
- agent = _get_agent(req.saas_id, req.agent_id)
|
|
|
+ agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
|
|
|
if not agent or agent.agent_state == AgentState.DISABLE.code:
|
|
|
raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
|
|
|
|
|
|
- agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_num)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_num)
|
|
|
if not agent_monitor or agent_monitor.service_state == AgentServiceState.CALLING.code:
|
|
|
raise BizException(BizErrorCode.AGENT_CALLING_NOT_ALLOW_OPERATE)
|
|
|
|
|
@@ -91,12 +294,13 @@ class AgentOperService:
|
|
|
|
|
|
return self._push_event_for_checkout(agent, req.scene)
|
|
|
|
|
|
+ @with_app_context
|
|
|
def busy(self, req: AgentActionRequest):
|
|
|
- agent = _get_agent(req.saas_id, req.agent_id)
|
|
|
+ agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
|
|
|
if not agent or agent.agent_state == AgentState.DISABLE.code:
|
|
|
raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
|
|
|
|
|
|
- agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_num)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_num)
|
|
|
if not agent_monitor or agent_monitor.check_state == AgentCheck.OUT.code:
|
|
|
raise BizException(BizErrorCode.AGENT_CHECK_OUT_NOT_ALLOW_OPERATE)
|
|
|
|
|
@@ -112,25 +316,30 @@ class AgentOperService:
|
|
|
self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.BUSY, AgentLogState.BUSY)
|
|
|
self._push_event_for_busy(agent, req.scene)
|
|
|
|
|
|
+ @with_app_context
|
|
|
def idle(self, req: AgentActionRequest):
|
|
|
- agent = _get_agent(req.saas_id, req.agent_id)
|
|
|
+ agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
|
|
|
if not agent or agent.agent_state == AgentState.DISABLE.code:
|
|
|
raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
|
|
|
self._handle_idle(req.scene, agent)
|
|
|
|
|
|
+ @with_app_context
|
|
|
def assign(self, req: AgentActionRequest):
|
|
|
return self.agent_state_service.assign_agent(req.saas_id, req.service_id)
|
|
|
|
|
|
def idle_agent_exist(self, request: AgentActionRequest):
|
|
|
pass
|
|
|
+
|
|
|
+ @with_app_context
|
|
|
def agent_state(self,req: AgentActionRequest):
|
|
|
# agent = _get_agent(req.saas_id, req.agent_id)
|
|
|
- agent_monitor = _get_agent_monitor(req.saas_id, req.agent_id)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, req.agent_id)
|
|
|
return agent_monitor.service_state
|
|
|
|
|
|
+ @with_app_context
|
|
|
def turn_on(self, req: AgentActionRequest):
|
|
|
- agent = _get_agent(req.saas_id, req.agent_id)
|
|
|
- agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_num)
|
|
|
+ agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_num)
|
|
|
agent_scene = AgentScene.get_by_code(req.scene)
|
|
|
if not agent_monitor:
|
|
|
raise BizException(BizErrorCode.RECORD_NOT_EXIST_ERROR)
|
|
@@ -143,8 +352,9 @@ class AgentOperService:
|
|
|
self.agent_state_service.busy(agent.saas_id, agent.out_id, agent.phone_num)
|
|
|
self.push_handler.push_on_agent_report(agent.saas_id, agent.out_id, agent_scene, AgentServiceState.BUSY)
|
|
|
|
|
|
+ @with_app_context
|
|
|
def _handle_idle(self, scene, agent):
|
|
|
- agent_monitor = _get_agent_monitor(agent.saas_id, agent.agent_num)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(agent.saas_id, agent.agent_num)
|
|
|
if agent_monitor.check_state == AgentCheck.OUT.code:
|
|
|
raise BizException(BizErrorCode.AGENT_CHECK_OUT_NOT_ALLOW_OPERATE)
|
|
|
if agent_monitor.service_state == AgentServiceState.CALLING.code or agent_monitor.service_state == AgentServiceState.DIALING.code:
|
|
@@ -206,18 +416,21 @@ class AgentOperService:
|
|
|
|
|
|
class AgentService:
|
|
|
|
|
|
- def __init__(self, client, logger):
|
|
|
- self.inbound_client = client
|
|
|
- self.logger = logger
|
|
|
- self.agent_monitor_service = AgentMonitorService(client, logger)
|
|
|
+ def __init__(self, app):
|
|
|
+ self.app = app
|
|
|
+ self.logger = app.logger
|
|
|
+ self.data_handle_server = DataHandleServer(app)
|
|
|
+ self.agent_monitor_service = AgentMonitorService(app)
|
|
|
|
|
|
+ @with_app_context
|
|
|
def get_and_check(self, req: AgentActionRequest):
|
|
|
- agent = _get_agent(req.saas_id, req.agent_id)
|
|
|
+ agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
|
|
|
if not agent:
|
|
|
return {}
|
|
|
- phone = _get_phone(req.saas_id, agent.phone_num)
|
|
|
+ phone = self.data_handle_server.get_phone(req.saas_id, agent.phone_num)
|
|
|
return phone.to_dict()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def watch_agent_state(self, req: HumanServiceQueryRequest):
|
|
|
pos = HumanServiceMap.query.filter(HumanServiceMap.is_delete == 0, HumanServiceMap.saas_id == req.saas_id,
|
|
|
HumanServiceMap.service_id == req.serviceId).all()
|
|
@@ -225,8 +438,9 @@ class AgentService:
|
|
|
monitors = self.agent_monitor_service.detail_monitor_out_ids(req.saas_id, agent_ids)
|
|
|
return monitors
|
|
|
|
|
|
+ @with_app_context
|
|
|
def add(self, req: AgentRequest):
|
|
|
- new_agent_num = _get_newest_agent_number(req.saas_id)
|
|
|
+ new_agent_num = self.data_handle_server.get_newest_agent_number(req.saas_id)
|
|
|
agent = Agent(saas_id=req.saas_id, agent_num=new_agent_num, agent_name=req.agent_name, out_id=req.out_id,
|
|
|
agent_pwd=req.agent_password, agent_type=req.agent_type, phone_num=req.phone_number,
|
|
|
distribute=req.distribute, agent_state=req.agent_state)
|
|
@@ -238,8 +452,9 @@ class AgentService:
|
|
|
db.session.commit()
|
|
|
return new_agent_num
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update(self, req: AgentRequest):
|
|
|
- agent = _get_agent(req.saas_id, req.agent_number, req.out_id)
|
|
|
+ agent = self.data_handle_server.get_agent(req.saas_id, req.agent_number, req.out_id)
|
|
|
if not agent:
|
|
|
return
|
|
|
phone_num = agent.phone_num
|
|
@@ -259,10 +474,12 @@ class AgentService:
|
|
|
if phone:
|
|
|
db.session.delete(phone)
|
|
|
|
|
|
+ @with_app_context
|
|
|
def detail(self, saas_id, agent_number):
|
|
|
- agent = _get_agent(saas_id, agent_number=agent_number, out_id='')
|
|
|
+ agent = self.data_handle_server.get_agent(saas_id, agent_number=agent_number, out_id='')
|
|
|
return agent
|
|
|
|
|
|
+ @with_app_context
|
|
|
def count(self, req: AgentQueryRequest):
|
|
|
cnt = Agent.query.filter(Agent.saas_id == req.saas_id,
|
|
|
or_(Agent.agent_num == req.agent_number,
|
|
@@ -273,6 +490,7 @@ class AgentService:
|
|
|
).count()
|
|
|
return cnt
|
|
|
|
|
|
+ @with_app_context
|
|
|
def query_page(self, req: AgentQueryRequest):
|
|
|
pagination = Agent.query.filter(Agent.saas_id == req.saas_id,
|
|
|
or_(Agent.agent_num == req.agent_number,
|
|
@@ -298,27 +516,30 @@ class AgentService:
|
|
|
# }
|
|
|
return pagination
|
|
|
|
|
|
+ @with_app_context
|
|
|
def delete(self, saas_id, agent_number):
|
|
|
- agent = _get_agent(saas_id, agent_number=agent_number, out_id='')
|
|
|
+ agent = self.data_handle_server.get_agent(saas_id, agent_number=agent_number, out_id='')
|
|
|
if not agent:
|
|
|
return
|
|
|
agent.is_delete = 1
|
|
|
|
|
|
- agent_monitor = _get_agent_monitor(saas_id, agent_number)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_number)
|
|
|
agent_monitor.is_delete = 1
|
|
|
db.session.commit()
|
|
|
|
|
|
- phone = _get_phone(saas_id, agent.phone_num)
|
|
|
+ phone = self.data_handle_server.get_phone(saas_id, agent.phone_num)
|
|
|
phone.is_delete = 1
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
|
class AgentMonitorService:
|
|
|
|
|
|
- def __init__(self, client, logger):
|
|
|
- self.inbound_client = client
|
|
|
- self.logger = logger
|
|
|
+ def __init__(self, app):
|
|
|
+ self.app = app
|
|
|
+ self.logger = app.logger
|
|
|
+ self.data_handle_server = DataHandleServer(app)
|
|
|
|
|
|
+ @with_app_context
|
|
|
def detail_monitor_out_ids(self, saas_id, out_ids, check_scene=None):
|
|
|
if not out_ids:
|
|
|
return []
|
|
@@ -360,6 +581,7 @@ class AgentMonitorService:
|
|
|
res.append(data.__dict__)
|
|
|
return res
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update_checkin(self, agent_monitor):
|
|
|
agent_monitor.check_state = AgentCheck.IN.code
|
|
|
agent_monitor.check_in_time = datetime.utcnow()
|
|
@@ -367,6 +589,7 @@ class AgentMonitorService:
|
|
|
agent_monitor.heart_time = datetime.utcnow()
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update_checkout(self, agent_monitor):
|
|
|
agent_monitor.check_state = AgentCheck.OUT.code
|
|
|
agent_monitor.check_out_time = datetime.utcnow()
|
|
@@ -376,34 +599,41 @@ class AgentMonitorService:
|
|
|
self.logger.info("update_checkout %s", agent_monitor.check_out_time)
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update_idle(self, agent_monitor):
|
|
|
agent_monitor.service_state = AgentServiceState.IDLE.code
|
|
|
agent_monitor.idle_time = datetime.utcnow()
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update_busy(self, agent_monitor):
|
|
|
agent_monitor.service_state = AgentServiceState.BUSY.code
|
|
|
agent_monitor.busy_time = datetime.utcnow()
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update_dialing(self, agent_monitor):
|
|
|
agent_monitor.service_state = AgentServiceState.DIALING.code
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update_calling(self, agent_monitor):
|
|
|
agent_monitor.service_state = AgentServiceState.CALLING.code
|
|
|
agent_monitor.call_time = datetime.utcnow()
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update_processing(self, agent_monitor):
|
|
|
agent_monitor.service_state = AgentServiceState.REPROCESSING.code
|
|
|
agent_monitor.hang_time = datetime.utcnow()
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update_session_id(self, agent_monitor, session_id):
|
|
|
agent_monitor.session_id = session_id
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def update_heart_error(self, agent_monitor):
|
|
|
agent_monitor.heart_state = AgentHeartState.ABNORMAL.code
|
|
|
agent_monitor.heart_time = datetime.utcnow()
|
|
@@ -416,10 +646,12 @@ class AgentMonitorService:
|
|
|
|
|
|
class AgentActionLogService:
|
|
|
|
|
|
- def __init__(self, client, logger):
|
|
|
- self.inbound_client = client
|
|
|
- self.logger = logger
|
|
|
+ def __init__(self, app):
|
|
|
+ self.app = app
|
|
|
+ self.logger = app.logger
|
|
|
+ self.data_handle_server = DataHandleServer(app)
|
|
|
|
|
|
+ @with_app_context
|
|
|
def insert_check_state(self, agent_monitor, agent_check_enum: AgentCheck, agent_log_enum: AgentLogState):
|
|
|
action_log = AgentActionLog()
|
|
|
action_log.saas_id = agent_monitor.saas_id
|
|
@@ -445,6 +677,7 @@ class AgentActionLogService:
|
|
|
db.session.add(action_log)
|
|
|
db.session.commit()
|
|
|
|
|
|
+ @with_app_context
|
|
|
def insert_service_state(self, agent_monitor, agent_service_state: AgentServiceState, agent_log_enum: AgentLogState,
|
|
|
task_id=None, service_id=None):
|
|
|
if agent_monitor.service_state == agent_service_state.code:
|
|
@@ -485,35 +718,36 @@ class AgentActionLogService:
|
|
|
|
|
|
class AgentStateService:
|
|
|
|
|
|
- def __init__(self, client, logger):
|
|
|
- self.inbound_client = client
|
|
|
- self.logger = logger
|
|
|
+ def __init__(self, app):
|
|
|
+ self.app = app
|
|
|
+ self.logger = app.logger
|
|
|
self.redis_handler = RedisHandler()
|
|
|
self.assigned_recycle_millisecond = 60000
|
|
|
self.state_service_id_data_map = defaultdict(dict)
|
|
|
self.executor = ThreadPoolExecutor(max_workers=10)
|
|
|
- self.agent_monitor_service = AgentMonitorService(client, logger)
|
|
|
- self.agent_actionlog_service = AgentActionLogService(client, logger)
|
|
|
+ self.data_handle_server = DataHandleServer(app)
|
|
|
+ self.agent_monitor_service = AgentMonitorService(app)
|
|
|
+ self.agent_actionlog_service = AgentActionLogService(app)
|
|
|
|
|
|
def idle(self, saas_id, agent_id, phone_num):
|
|
|
- human_service = _get_human_service_service(saas_id, agent_id)
|
|
|
+ human_service = self.data_handle_server.get_human_service_service(saas_id, agent_id)
|
|
|
if human_service is None:
|
|
|
self.logger.info(f"agent engine idle not have human service {saas_id} {agent_id}") # 使用print替代log
|
|
|
return
|
|
|
self.idle_hash(saas_id, agent_id, phone_num, human_service.service_id)
|
|
|
|
|
|
def busy(self, saas_id, agent_id, phone_num):
|
|
|
- human_service = _get_human_service_service(saas_id, agent_id)
|
|
|
+ human_service = self.data_handle_server.get_human_service_service(saas_id, agent_id)
|
|
|
if human_service is None:
|
|
|
self.logger.info(f"agent engine busy not hava human service {saas_id} {agent_id}") # 使用print替代log
|
|
|
return
|
|
|
self.busy_hash(saas_id, agent_id, phone_num, human_service.service_id)
|
|
|
|
|
|
def idle_by_human(self, saas_id, agent_id, service_id):
|
|
|
- agent = _get_agent(saas_id, out_id=agent_id)
|
|
|
+ agent = self.data_handle_server.get_agent(saas_id, out_id=agent_id)
|
|
|
if not agent:
|
|
|
return
|
|
|
- agent_monitor = _get_agent_monitor(saas_id, agent_number=agent.agent_num)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_number=agent.agent_num)
|
|
|
if not agent_monitor:
|
|
|
return
|
|
|
if agent_monitor.check_state == AgentCheck.IN.code:
|
|
@@ -522,10 +756,10 @@ class AgentStateService:
|
|
|
self.idle_hash(saas_id, agent_id, agent.phone_num, service_id)
|
|
|
|
|
|
def busy_by_human(self, saas_id, service_id, agent_id=None):
|
|
|
- agent = _get_agent(saas_id, out_id=agent_id)
|
|
|
+ agent = self.data_handle_server.get_agent(saas_id, out_id=agent_id)
|
|
|
if not agent:
|
|
|
return
|
|
|
- agent_monitor = _get_agent_monitor(saas_id, agent_number=agent.agent_num)
|
|
|
+ agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_number=agent.agent_num)
|
|
|
if not agent_monitor:
|
|
|
return
|
|
|
if agent_monitor.check_state == AgentCheck.IN.code:
|
|
@@ -697,34 +931,3 @@ class AgentStateService:
|
|
|
idle_agents = sorted(idle_agents, key=lambda agent: agent.assign_time, reverse=False)
|
|
|
return idle_agents[0].phone_num
|
|
|
|
|
|
-
|
|
|
-def _get_agent(saas_id, agent_id=None, agent_number=None, out_id=None):
|
|
|
- agent = Agent.query.filter(
|
|
|
- Agent.saas_id == saas_id,
|
|
|
- or_(Agent.out_id == agent_id, Agent.out_id == out_id, Agent.agent_num == agent_number)
|
|
|
- ).first()
|
|
|
- return agent
|
|
|
-
|
|
|
-
|
|
|
-def _get_newest_agent_number(saas_id):
|
|
|
- agent = Agent.query.filter(Agent.saas_id == saas_id).order_by(Agent.agent_num.desc()).first()
|
|
|
- agentNum = START_AGENT_NUM
|
|
|
- if agent and agent.agent_num:
|
|
|
- agentNum = str(int(agent.agent_num) + 1)
|
|
|
- return agentNum
|
|
|
-
|
|
|
-
|
|
|
-def _get_agent_monitor(saas_id, agent_number):
|
|
|
- monitor = AgentMonitor.query.filter(AgentMonitor.saas_id == saas_id,
|
|
|
- AgentMonitor.agent_num == agent_number).first()
|
|
|
- return monitor
|
|
|
-
|
|
|
-
|
|
|
-def _get_phone(saas_id, phone_num):
|
|
|
- phone = Phone.query.filter(Phone.saas_id == saas_id, Phone.phone_num == phone_num).first()
|
|
|
- return phone
|
|
|
-
|
|
|
-
|
|
|
-def _get_human_service_service(saas_id, agent_id):
|
|
|
- human_service_map = HumanServiceMap.query.filter(HumanServiceMap.saas_id == saas_id, HumanServiceMap.agent_id ==agent_id).first()
|
|
|
- return human_service_map
|