ソースを参照

agent state fix

刘威 4 ヶ月 前
コミット
40afaea85a
1 ファイル変更55 行追加11 行削除
  1. 55 11
      src/core/callcenter/agent.py

+ 55 - 11
src/core/callcenter/agent.py

@@ -2,6 +2,7 @@
 # encoding:utf-8
 
 import traceback
+from typing import List
 from collections import defaultdict
 from src.core.callcenter.constant import START_AGENT_NUM
 from src.core.callcenter.enumeration import AgentState, AgentCheck, AgentHeartState, AgentServiceState, AgentLogState, \
@@ -17,6 +18,7 @@ from src.core.datasource import RedisHandler
 from concurrent.futures import ThreadPoolExecutor
 import threading
 
+
 class AgentOperService:
 
     def __init__(self, client, logger):
@@ -113,6 +115,7 @@ class AgentOperService:
         if not agent or agent.agent_state == AgentState.DISABLE.code:
             raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
         self._handle_idle(req.scene, agent)
+
     def assign(self, request: AgentActionRequest):
         pass
 
@@ -133,6 +136,7 @@ class AgentOperService:
         self.agent_monitor_service.update_calling(agent_monitor)
         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)
+
     def _handle_idle(self, scene, agent):
         agent_monitor = _get_agent_monitor(agent.saas_id, agent.agent_num)
         if agent_monitor.check_state == AgentCheck.OUT.code:
@@ -168,6 +172,7 @@ class AgentOperService:
                                    }
                            }
         return event_data.__dict__
+
     def _push_event_for_checkout(self,agent,scene):
         """签出事件推送"""
         agent_scene = AgentScene.get_by_code(scene)
@@ -192,6 +197,7 @@ class AgentOperService:
         agent_scene = AgentScene.get_by_code(scene)
         self.push_handler.push_on_agent_work_report(agent.saas_id, "", agent.out_id, "", agent_scene, WorkStatus.AGENT_READY)
 
+
 class AgentService:
 
     def __init__(self, client, logger):
@@ -479,7 +485,9 @@ class AgentStateService:
         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)
+
     def idle(self, saas_id, agent_id, phone_num):
         human_service = _get_human_service_service(saas_id, agent_id)
         if human_service is None:
@@ -495,10 +503,29 @@ class AgentStateService:
         self.busy_hash(saas_id, agent_id, phone_num, human_service.service_id)
 
     def idle_by_human(self, saas_id, agent_id, service_id):
-        pass
+        agent = _get_agent(saas_id, out_id=agent_id)
+        if not agent:
+            return
+        agent_monitor = _get_agent_monitor(saas_id, agent_number=agent.agent_num)
+        if not agent_monitor:
+            return
+        if agent_monitor.check_state == AgentCheck.IN.code:
+            self.agent_monitor_service.update_idle(agent_monitor)
+            self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.IDLE, AgentLogState.ACTIVE_HUMAN_SERVICE)
+            self.idle_hash(saas_id, agent_id, agent.phone_num, service_id)
 
     def busy_by_human(self, saas_id, service_id, agent_id=None):
-        pass
+        agent = _get_agent(saas_id, out_id=agent_id)
+        if not agent:
+            return
+        agent_monitor = _get_agent_monitor(saas_id, agent_number=agent.agent_num)
+        if not agent_monitor:
+            return
+        if agent_monitor.check_state == AgentCheck.IN.code:
+            self.agent_monitor_service.update_busy(agent_monitor)
+            self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.BUSY,
+                                                              AgentLogState.DEL_HUMAN_SERVICE)
+            self.busy_hash(saas_id, agent_id, agent.phone_num, service_id)
 
     def checkin(self, saas_id, agent_id, phone_num):
         key = self._check_in_key(saas_id)
@@ -512,14 +539,25 @@ class AgentStateService:
         key = self._check_in_key(saas_id)
         self.redis_handler.redis.hdel(key, phone_num)
 
-    def assign_agent(self, saas_id, service_id, ivr_id, task_id, called, cbp):
-        pass
+    def assign_agent(self, saas_id, service_id, called, ivr_id=None, task_id=None, cbp=None):
+        choose_phone_num = ''
+        self.logger.info("assignAgent %s %s %s", saas_id, service_id, called)
+        idle_agents = self.idle_agents(saas_id, service_id)
+        if len(idle_agents) <= 0:
+            return choose_phone_num
+        choose_phone_num = self._choose_max_idle_time(idle_agents)
+        return choose_phone_num
 
     def idle_agents(self, saas_id, service_id):
-        pass
+        cache_agent_list = self.get_cache_agent_list(saas_id, service_id)
+        if not cache_agent_list:
+            return []
+        agent_str = '\n'.join(["%s-%s-%s-%s".format(x.phone_num, x.status, x.time, x.assign_time) for x in cache_agent_list])
+        self.logger.info("assignAgent %s %s idleAgents:%s ", saas_id, service_id, agent_str)
+        return self.get_idle_agents(cache_agent_list)
 
     def idle_hash(self, saas_id, agent_id, phone_num, service_id):
-        key =  self._key(saas_id, service_id)
+        key = self._key(saas_id, service_id)
         state_data = AgentStateData()
 
         cache_agent_map = self.get_cache_agent_map(saas_id, service_id)
@@ -530,7 +568,7 @@ class AgentStateService:
         state_data.time = datetime.utcnow().timestamp()
         self.redis_handler.redis.hset(key, phone_num, state_data.to_json_string())
         self.redis_handler.redis.expire(key, self._get_expire_time())
-        self.update_report_state(saas_id, service_id)
+        # self.update_report_state(saas_id, service_id)
 
     def busy_hash(self, saas_id, agent_id, phone_num, service_id):
         cache_agent_map = self.get_cache_agent_map(saas_id, service_id)
@@ -541,7 +579,7 @@ class AgentStateService:
         state_data.status = HumanState.BUSY.code
         self.redis_handler.redis.hset(key, phone_num, state_data.to_json_string())
         self.redis_handler.redis.expire(key, self._get_expire_time())
-        self.update_report_state(saas_id, service_id)
+        # self.update_report_state(saas_id, service_id)
 
     def get_cache_agent_map(self, saas_id, service_id):
         cache_agent_list = self.get_cache_agent_list(saas_id, service_id)
@@ -552,7 +590,6 @@ class AgentStateService:
         # 使用字典推导式将 cache_agent_list 转换为字典
         return {agent.phone_num: agent for agent in cache_agent_list}
 
-
     def get_cache_agent_list(self, saas_id, service_id):
         redis_key = self._key(saas_id, service_id)
         map_cache_by_key = self.redis_handler.redis.hgetall(redis_key)
@@ -624,8 +661,10 @@ class AgentStateService:
         elif human_state == HumanState.BUSY:
             self.meter_registry.gauge(name, tag_list, self, lambda ctx: ctx.get_agent_service_idle_size(saas_id, service_id))
         return 0
+
     def _check_in_key(self, saas_id):
         return "CTI:%s:HUMAN:AGENT".format(saas_id.upper())
+
     def _key(self, saas_id, service_id):
         return "CTI:%s:HUMAN:%s".format(saas_id.upper(), service_id)
 
@@ -635,6 +674,10 @@ class AgentStateService:
         expire_time = (end_of_day - now).total_seconds() * 1000  # Convert to milliseconds
         return int(expire_time)
 
+    def _choose_max_idle_time(self, idle_agents: List[AgentStateData]) -> str:
+        idle_agents.sort(key=lambda agent: agent.get_assign_time())
+        return idle_agents[0].get_phone_num()
+
 
 def _get_agent(saas_id, agent_number, out_id):
     agent = Agent.query.filter(
@@ -663,6 +706,7 @@ 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
+    return human_service_map