|
@@ -0,0 +1,351 @@
|
|
|
+package com.care.outcall.schedule;
|
|
|
+
|
|
|
+
|
|
|
+import com.care.outcall.entity.Bill;
|
|
|
+import com.care.outcall.entity.KoalaLogDomain;
|
|
|
+import com.care.outcall.entity.KoalaTaskDto;
|
|
|
+import com.care.outcall.mapper.KoalaLoggerDao;
|
|
|
+import com.care.util.CommonConfUtil;
|
|
|
+import com.care.util.DateUtils;
|
|
|
+import org.apache.logging.log4j.LogManager;
|
|
|
+import org.apache.logging.log4j.Logger;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.context.annotation.Configuration;
|
|
|
+import org.springframework.context.annotation.PropertySource;
|
|
|
+import org.springframework.scheduling.annotation.EnableScheduling;
|
|
|
+import org.springframework.scheduling.annotation.Scheduled;
|
|
|
+import org.springframework.util.StringUtils;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+/** 手动外呼话单调度
|
|
|
+ * @author 许明
|
|
|
+ * @version 2.7.0.0 创建于 2018/7/16
|
|
|
+ **/
|
|
|
+@PropertySource("classpath:/CommonConfig.properties") //配置文件中添加
|
|
|
+@Configuration
|
|
|
+@EnableScheduling
|
|
|
+public class CcKoalaPhoneBillSchuding {
|
|
|
+ private static final Logger logger = LogManager.getLogger(CcKoalaPhoneBillSchuding.class);
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private KoalaLoggerDao koalaLoggerDao;
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 10 秒钟调用一次
|
|
|
+ */
|
|
|
+ //@Scheduled(cron = "${koala.out.call.bill.cron}")
|
|
|
+ public void exePhoneBill() {
|
|
|
+ try {
|
|
|
+ //构建话单
|
|
|
+ buildBill();
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("话单计算出错:{}", e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Scheduled(cron = "0 0 0 * * ?")
|
|
|
+ public void updateComputeTrafficToFinish() {
|
|
|
+ try {
|
|
|
+ //大于两天的话单日志默认已计算
|
|
|
+ koalaLoggerDao.updateComputeTrafficToFinish();
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.getMessage();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建话单
|
|
|
+ *
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ private void buildBill() throws Exception {
|
|
|
+ Map<String, List<KoalaLogDomain>> map = new HashMap();
|
|
|
+ List<Map<String, String>> idList = new ArrayList<>();
|
|
|
+ List<String> makeCallIds = new ArrayList<>();
|
|
|
+ //获取所有未计算的话单
|
|
|
+ List<KoalaLogDomain> logList = koalaLoggerDao.getAllBillInfo();
|
|
|
+ //重新构建话单日志结构
|
|
|
+ reBuildBill(map, logList);
|
|
|
+
|
|
|
+ //遍历每一条sessionId
|
|
|
+ for (String sid : map.keySet()) {
|
|
|
+ List<KoalaLogDomain> logDomains = map.get(sid);
|
|
|
+ //1:只拼接会话结束的日志,通话成功的
|
|
|
+ //描述事件的生存周期:1.坐席振铃,2.坐席接通,3.客户振铃,4.客户接通,5.坐席挂断,6.客户挂断,7.未接通
|
|
|
+ if (logDomains.size() > 2) {
|
|
|
+ //构建大有话单 关于成功话单部分
|
|
|
+ Bill bill = buildDataUBill(sid, logDomains, makeCallIds);
|
|
|
+ if (bill == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(bill.getOutCallRadioStatus())) {
|
|
|
+ bill.setOutCallRadioStatus("1");
|
|
|
+ }
|
|
|
+ bill.setCallResultStatus("1");
|
|
|
+ bill.setListenType("2");//默认设置为sip接听,后期会变
|
|
|
+ //判断话单表是否已存在该数据,不存在则新增,存在则更新状态
|
|
|
+ int count = koalaLoggerDao.checkSession(bill.getSessionId());
|
|
|
+ if (count == 0) {
|
|
|
+ //不存在则新增
|
|
|
+ try {
|
|
|
+ koalaLoggerDao.addBill(bill);
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("生成考拉话单异常,信息为:" + e.getMessage());
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ koalaLoggerDao.updatePhoneBillBySessionIdNew(bill);
|
|
|
+ }
|
|
|
+ Map<String, String> idMap = new HashMap<>();
|
|
|
+ idMap.put("id", sid);
|
|
|
+ idList.add(idMap);
|
|
|
+ } else if (logDomains.size() >= 1 && logDomains.size() <= 2) {
|
|
|
+ //构建大有话单 关于未接通的话单部分
|
|
|
+ Bill bill = buildDataUBill(sid, logDomains, makeCallIds);
|
|
|
+ if (bill == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ bill.setOrigOutCallStatus("2");
|
|
|
+ bill.setOutCallRadioStatus("2");
|
|
|
+ bill.setOutCallStatus("2");
|
|
|
+ bill.setListenType("2");//默认设置为sip接听,后期会变
|
|
|
+
|
|
|
+ int count = koalaLoggerDao.checkSession(bill.getSessionId());
|
|
|
+ if (count == 0) {
|
|
|
+ koalaLoggerDao.addBill(bill);
|
|
|
+ } else {
|
|
|
+ koalaLoggerDao.updatePhoneBillBySessionIdNew(bill);
|
|
|
+ }
|
|
|
+ Map<String, String> idMap = new HashMap<>();
|
|
|
+ idMap.put("id", sid);
|
|
|
+ idList.add(idMap);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!idList.isEmpty()) {
|
|
|
+ koalaLoggerDao.updateComputeTraffic(idList);
|
|
|
+ }
|
|
|
+ if (!makeCallIds.isEmpty()) {
|
|
|
+ koalaLoggerDao.updateMakeCallStatus(makeCallIds);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //构建大有话单
|
|
|
+ private synchronized Bill buildDataUBill(String sessionId, List<KoalaLogDomain> logDomains, List<String> idList) {
|
|
|
+ try {
|
|
|
+ Bill bill = new Bill();
|
|
|
+ //离外呼最近的事件时间
|
|
|
+ String receiveTime = "";
|
|
|
+ //通话计费开始时间
|
|
|
+ String callStartTime = "";
|
|
|
+ //双方通话结束时间
|
|
|
+ String callEndTime = "";
|
|
|
+ //客户振铃时间
|
|
|
+ String clientAlterTime = "";
|
|
|
+ //判断是客户挂断还是坐席挂断
|
|
|
+ String hangupType = "";
|
|
|
+ //通话结果状态
|
|
|
+ String callResultStatus = "1";
|
|
|
+ //如果为1说明客户接听已接通,2未接通客户只是振铃,
|
|
|
+ String outCallCheck = "0";
|
|
|
+ //租户id,考拉开通的租户id
|
|
|
+ String tenantId = "";
|
|
|
+ //被叫号码
|
|
|
+ String calledNumber = "";
|
|
|
+ //任务id
|
|
|
+ String taskId = "";
|
|
|
+ //开始外呼时间,用于记录无人接听的时候的开始时间
|
|
|
+ String unReceivedCallStartTime = "";
|
|
|
+ boolean callFlag = false;
|
|
|
+ boolean unCalledFlag = false;
|
|
|
+ boolean isCalledFlag = false;
|
|
|
+ //开始振铃时间
|
|
|
+ String dialingTime = "";
|
|
|
+ //话单变量,标记该话单为正确话单
|
|
|
+ boolean isBill = false;
|
|
|
+ for (KoalaLogDomain logDomain : logDomains) {
|
|
|
+ tenantId = logDomain.getTenantId();
|
|
|
+ calledNumber = logDomain.getCalledNumber();
|
|
|
+ taskId = logDomain.getTaskId();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ for (KoalaLogDomain logDomain : logDomains) {
|
|
|
+ //通话计费开始时间
|
|
|
+ if ("1".equals(logDomain.getEventStatus())) {
|
|
|
+ clientAlterTime = logDomain.getReceiveTime();
|
|
|
+ unReceivedCallStartTime = logDomain.getReceiveTime();
|
|
|
+ dialingTime = logDomain.getReceiveTime();
|
|
|
+ isCalledFlag = true;
|
|
|
+ }
|
|
|
+ //双方通话结束时间
|
|
|
+ if ("5,6".contains(logDomain.getEventStatus())) {
|
|
|
+ callEndTime = logDomain.getReceiveTime();
|
|
|
+ hangupType = "5".equals(logDomain.getEventStatus()) ? "1" : "0";
|
|
|
+ callResultStatus = "5";
|
|
|
+ isBill = true;
|
|
|
+ callFlag = true;
|
|
|
+ }
|
|
|
+ //客户振铃时间
|
|
|
+ if ("3".equals(logDomain.getEventStatus())) {
|
|
|
+ clientAlterTime = logDomain.getReceiveTime();
|
|
|
+ }
|
|
|
+ //日志中有4 说明客户接通
|
|
|
+ if ("4".equals(logDomain.getEventStatus())) {
|
|
|
+ callStartTime = logDomain.getReceiveTime();
|
|
|
+ outCallCheck = "1";
|
|
|
+ unCalledFlag = true;
|
|
|
+ }
|
|
|
+ //日志中有7 说明无人接听,坐席主动挂断(6表示客户拒接)
|
|
|
+ if ("7".equals(logDomain.getEventStatus())) {
|
|
|
+ callEndTime = logDomain.getReceiveTime();
|
|
|
+ callResultStatus = "5";
|
|
|
+ hangupType = "1";
|
|
|
+ isBill = true;
|
|
|
+ callFlag = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //如果不是完整话单则暂时不生成当前话单
|
|
|
+ if (!isBill) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!unCalledFlag) {
|
|
|
+ callStartTime = unReceivedCallStartTime;
|
|
|
+ }
|
|
|
+ if (isCalledFlag) {
|
|
|
+ //更新流水号表已拨打状态
|
|
|
+ koalaLoggerDao.updateIsCallStatusByTaskId(taskId, calledNumber);
|
|
|
+ }
|
|
|
+
|
|
|
+ //表示是正常的话单数据,有录音文件(考拉接通即产生录音)
|
|
|
+ String creationTime = dialingTime.replaceAll("-", "").replaceAll(":", "").replaceAll(" ", "");
|
|
|
+ String audioCreateTime = creationTime.substring(0, 8);
|
|
|
+ //挂断表示通话结束,构造mp3录音文件地址
|
|
|
+ String audioUri = CommonConfUtil.getConf("koala.mp3.url.host");
|
|
|
+ //构建考拉外呼录音文件路径
|
|
|
+ String audioUrl = audioUri + "/" + tenantId + "/" + audioCreateTime + "/" + sessionId + "_" + calledNumber + ".mp3";
|
|
|
+ //根据 sessionId 获取 sessionId 对应的流水号,和电信任务的具体信息
|
|
|
+ List<KoalaTaskDto> koalaTaskDtoList = koalaLoggerDao.getTaskInfoBySessionId(sessionId);
|
|
|
+ if (koalaTaskDtoList == null || koalaTaskDtoList.isEmpty()) {
|
|
|
+ logger.info("没有找到 sessionId={} 对应信息的流水号信息", sessionId);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ KoalaTaskDto koalaTaskDto = getNewOne(koalaTaskDtoList);
|
|
|
+
|
|
|
+ bill.setTelecomTaskId(koalaTaskDto.getDyTaskId());
|
|
|
+ //新增,内容----
|
|
|
+ //屏蔽内容 ----
|
|
|
+ KoalaLogDomain logDomain = logDomains.get(0);
|
|
|
+ //该会话的坐席号
|
|
|
+ String agentId = logDomain.getAgentId();
|
|
|
+ //该会话的企业id
|
|
|
+ bill.setClientFlowNo(koalaTaskDto.getDyFlowNo());
|
|
|
+ bill.setCallStartTime(callStartTime);
|
|
|
+ bill.setOutCallStatus("1");
|
|
|
+ bill.setOrigOutCallStatus("1");
|
|
|
+ bill.setCallResultStatus(callResultStatus);
|
|
|
+ bill.setCallEndTime(callEndTime);
|
|
|
+ bill.setAudioUrl(audioUrl);
|
|
|
+ bill.setOutCallRadioStatus("2");//录件获取状态。1未获取,2已获取
|
|
|
+ bill.setBatchId(koalaTaskDto.getDyTaskNo());
|
|
|
+ bill.setTeleTaskName(koalaTaskDto.getDyTaskName());
|
|
|
+ bill.setSessionId(sessionId);
|
|
|
+ bill.setTeleAgentId(agentId);
|
|
|
+ //大有
|
|
|
+ bill.setClientAlertStartTime(clientAlterTime);
|
|
|
+ if (callFlag && !unCalledFlag) {
|
|
|
+ bill.setCallDuration("0");
|
|
|
+ } else {
|
|
|
+ try {
|
|
|
+ long callDuration = DateUtils.compute_yyyy_MM_ddHHmmssTime(callStartTime, callEndTime);
|
|
|
+ bill.setCallDuration(String.valueOf(callDuration));
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("时间处理异常,异常信息为==>" + e.getMessage());
|
|
|
+ bill.setCallDuration("0");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ bill.setCallResultType("1");//呼出
|
|
|
+ bill.setHangupType(hangupType);
|
|
|
+ bill.setChannelFlag(6);
|
|
|
+ bill.setEnterpriseNo(koalaTaskDto.getEnterpriseNo());
|
|
|
+ return bill;
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("计算话单失败,失败原因={}", e.getMessage());
|
|
|
+ //e.printStackTrace();
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //重新构建日志格式,去重
|
|
|
+ private void reBuildBill(Map<String, List<KoalaLogDomain>> map, List<KoalaLogDomain> logList) {
|
|
|
+ Set<String> set = new HashSet<>();
|
|
|
+ Map<String, Set<String>> noRepeatSetMap = new HashMap<>();
|
|
|
+
|
|
|
+ //所有sessionId放入内存
|
|
|
+ for (KoalaLogDomain logDomain : logList) {
|
|
|
+ set.add(logDomain.getSessionId());
|
|
|
+ noRepeatSetMap.put(logDomain.getSessionId(), null);
|
|
|
+ }
|
|
|
+ //遍历sessionId
|
|
|
+ for (String sid : set) {
|
|
|
+ List<KoalaLogDomain> resulList = new ArrayList<>();
|
|
|
+ for (KoalaLogDomain logDomain : logList) {
|
|
|
+ if (sid.equals(logDomain.getSessionId())) {
|
|
|
+ //去重
|
|
|
+ String apiMethod = logDomain.getApiMethod();
|
|
|
+ if (noRepeatSetMap.get(sid) == null) {
|
|
|
+ Set<String> noRepeatSet = new HashSet<>();
|
|
|
+ noRepeatSet.add(apiMethod);
|
|
|
+ noRepeatSetMap.put(sid, noRepeatSet);
|
|
|
+ } else if (noRepeatSetMap.get(sid) != null && noRepeatSetMap.get(sid).contains(apiMethod)) {
|
|
|
+ continue;
|
|
|
+ } else if (noRepeatSetMap.get(sid) != null && !noRepeatSetMap.get(sid).contains(apiMethod)) {
|
|
|
+ //同一个sessionId不同的操作,如:振铃、接听、挂断等
|
|
|
+ noRepeatSetMap.get(sid).add(apiMethod);
|
|
|
+ }
|
|
|
+ resulList.add(logDomain);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ boolean isBill1 = false;
|
|
|
+ boolean isBill2 = false;
|
|
|
+ //判断是不是可计算的话单
|
|
|
+ //同一个sessionId话单数据中,如果既有振铃又有挂断,则表示是可计算的话单
|
|
|
+ for (KoalaLogDomain logDomain : resulList) {
|
|
|
+ if ("4,5,6,7".contains(logDomain.getEventStatus())) {
|
|
|
+ isBill1 = true;
|
|
|
+ }
|
|
|
+ //坐席拨号即振铃
|
|
|
+ if ("1".equals(logDomain.getEventStatus())) {
|
|
|
+ isBill2 = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (isBill1 && isBill2) {
|
|
|
+ //得出话单
|
|
|
+ map.put(sid, resulList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ logList.clear();
|
|
|
+ noRepeatSetMap.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ private KoalaTaskDto getNewOne(List<KoalaTaskDto> koalaTaskDtoList) {
|
|
|
+ koalaTaskDtoList.sort(new Comparator<KoalaTaskDto>() {
|
|
|
+ @Override
|
|
|
+ public int compare(KoalaTaskDto o1, KoalaTaskDto o2) {
|
|
|
+ return Integer.valueOf(String.valueOf(Long.parseLong(o2.getCreateTime()) - Long.parseLong(o1.getCreateTime())));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return koalaTaskDtoList.get(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+ double a = 1000000000.22;
|
|
|
+ float b = 10.22f;
|
|
|
+ String s = "1";
|
|
|
+ s = s + 1;
|
|
|
+ s += 1;
|
|
|
+ }
|
|
|
+}
|