package zoho import ( "crm-api/internal/app/mysql" "crm-api/pkg/httpclient" "crm-api/pkg/lfshook" "encoding/json" "fmt" "io/ioutil" "net/http" "slices" "strconv" "strings" "time" "gopkg.in/ini.v1" ) var TimestampList = make(map[string]string) //临时记录通话成功时的初始时间戳,用于计算通话时长,通话结束后删除 var StartTimeList = make(map[string]time.Time) //临时记录通话的初始时间,通话结束时删除 // var LinkedidList = make(map[string]string) // 临时记录 incoming 和 outgoing // var DialStatusList = make(map[string]string) // 临时记录 DialStatus:ANSWER NOANSWER var CallTypeList = make(map[string]string) //通过Linkedid临时记录拨打类型呼入还是呼出,通话结束后删除 var TimetimesList = make(map[string]int) //通过Linkedid临时记录呼入队列或部门的数量,通话结束后删除 var AttendedTransferList = make(map[string]string) //临时记录协商转接的初始时间戳 var AttendedSecondTransferList = make(map[string]string) //临时记录协商转接后的初始时间戳 var ZohoExtenList = make([]string, 0) //记录zoho用户分机列表,只有zoho用户分机的呼入和呼出才会进行推送 var n int //临时记录判断通话未接听的数量,若与呼入数量相同进行推送,若接听让n归0 var ZOHO_URL string //设置推送地址 // macro-trunkdial-failover为呼出判定;macro-stdexten为呼入开启语音留言的判定;macro-stdexten-withoutvm为呼入关闭语音留言的判定 func CallClicktodialerror(event map[string]string) { //CallClicktodialerrorh函数用于过滤zoho crm拨打时出现的错误 if event["Event"] == "SoftHangupRequest" { Channel := strings.Split(event["Channel"], "/") if (event["Context"] == "macro-stdexten" || event["Context"] == "macro-stdexten-withoutvm") && len(event["Exten"]) > 3 && Channel[0] == "Local" { ExtenStatus := strings.Split(event["Exten"], "-") if ExtenStatus[1] == "NOANSWER" && slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) { //坐席未接听,通过ExtenStatus判断挂断原因,slices.Contains(ZohoExtenList, event["ConnectedLineNum"])判断主叫是否时zoho用户分机(坐席) getURL := fmt.Sprintf("%s/phonebridge/v3/clicktodialerror?code=noanswer&from=%s&to=%s", ZOHO_URL, event["ConnectedLineNum"], event["CallerIDNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) return } else if ExtenStatus[1] == "BUSY" { //坐席不可用 ChannelStatus1 := strings.Split(event["Channel"], "@") ChannelStatus2 := strings.Split(ChannelStatus1[0], "/") if slices.Contains(ZohoExtenList, ChannelStatus2[1]) { getURL := fmt.Sprintf("%s/phonebridge/v3/clicktodialerror?code=notavailble&from=%s&to=%s&message=agentunavailable", ZOHO_URL, ChannelStatus2[1], event["CallerIDNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) return } } else if ExtenStatus[1] == "CHANUNAVAIL" && slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) { //坐席拒接 getURL := fmt.Sprintf("%s/phonebridge/v3/clicktodialerror?code=rejected&from=%s&to=%s", ZOHO_URL, event["ConnectedLineNum"], event["CallerIDNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) return } } } else if event["Event"] == "DialEnd" { //坐席未接听 Channel := strings.Split(event["Channel"], "/") if (event["Context"] == "macro-stdexten" || event["Context"] == "macro-stdexten-withoutvm") && event["DialStatus"] == "CANCEL" && slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) && Channel[0] == "Local" { getURL := fmt.Sprintf("%s/phonebridge/v3/clicktodialerror?code=noanswer&from=%s&to=%s", ZOHO_URL, event["ConnectedLineNum"], event["CallerIDNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) return } } CallNotify(event) } func CallNotify(event map[string]string) { // 坐席接听后调用此函数 if event["Event"] == "DialBegin" { //响铃标志事件 lfshook.NewLogger().Error(event) Channel := strings.Split(event["Channel"], "/") // Outgoing Call - Ringing if event["Context"] == "macro-trunkdial-failover" && slices.Contains(ZohoExtenList, event["CallerIDNum"]) { StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour) // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=ringing&id=10031&from=123456789&to=12300000001 getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=ringing&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) // Incoming Call - Ringing } else if (event["Context"] == "macro-stdexten" && Channel[0] != "Local" && slices.Contains(ZohoExtenList, event["DestCallerIDNum"])) || (event["Context"] == "macro-stdexten-withoutvm" && Channel[0] != "Local" && slices.Contains(ZohoExtenList, event["DestCallerIDNum"])) { // 开启语音留言:macro-stdexten 关闭语音留言:macro-stdexten-withoutvm StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour) // https://www.zohoapis.com/phonebridge/v3/callnotify?type=received&state=ringing&id=10033&from=12300000001&to=123456789 // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ringing&id=%s&from=%s&to=%s", ZOHO_URL, callId, event["Exten"], callDest) // 取得from to 可能不准 getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ringing&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } else if (strings.HasPrefix(event["Context"], "department") || strings.HasSuffix(event["Context"], "queue")) && slices.Contains(ZohoExtenList, event["DestCallerIDNum"]) { //队列和部门判断 TimetimesList[event["Linkedid"]] = TimetimesList[event["Linkedid"]] + 1 StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour) getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ringing&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } } else if event["Event"] == "DialEnd" { // 呼叫结束事件,未接听集合 Channel := strings.Split(event["Channel"], "/") // 记录呼叫状态 // Outgoing Call - Unattended if event["Context"] == "macro-trunkdial-failover" && event["DialStatus"] == "CANCEL" && slices.Contains(ZohoExtenList, event["CallerIDNum"]) { //坐席取消呼叫客户电话,event["DialStatus"]判断未接听挂断原因 // startTime := StartTimeList[event["Linkedid"]].Format("2006-01-02 15:04:09") startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=busy&id=10025&from=123456789&to=12300000001&start_time=2024-12-04 15:09:10 getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=busy&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) delete(StartTimeList, event["Linkedid"]) // Incoming Call - Missed } else if event["Context"] == "macro-trunkdial-failover" && event["DialStatus"] == "NOANSWER" && slices.Contains(ZohoExtenList, event["CallerIDNum"]) { //坐席呼出,客户未接听,event["DialStatus"]判断未接听挂断原因 startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=busy&id=10025&from=123456789&to=12300000001&start_time=2024-12-04 15:09:10 getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=noanswer&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) delete(StartTimeList, event["Linkedid"]) // Incoming Call - Missed } else if event["Context"] == "macro-trunkdial-failover" && event["DialStatus"] == "BUSY" && slices.Contains(ZohoExtenList, event["CallerIDNum"]) { //坐席呼出,客户拒接 startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=busy&id=10025&from=123456789&to=12300000001&start_time=2024-12-04 15:09:10 getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=rejected&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) delete(StartTimeList, event["Linkedid"]) // Incoming Call - Missed } else if (event["Context"] == "macro-stdexten" && event["DialStatus"] != "ANSWER" && Channel[0] != "Local" && slices.Contains(ZohoExtenList, event["DestCallerIDNum"])) || (event["Context"] == "macro-stdexten-withoutvm" && event["DialStatus"] != "ANSWER" && Channel[0] != "Local" && slices.Contains(ZohoExtenList, event["DestCallerIDNum"])) { // 呼入坐席未接听 startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) // https://www.zohoapis.com/phonebridge/v3/callnotify?type=received&state=missed&id=10005&from=12300000001&to=123456789&start_time=2024-12-04 15:09:10 getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=missed&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) delete(StartTimeList, event["Linkedid"]) } else if (strings.HasPrefix(event["Context"], "department") || strings.HasSuffix(event["Context"], "queue")) && event["DialStatus"] != "ANSWER" && TimetimesList[event["Linkedid"]] < 2 && TimetimesList[event["Linkedid"]] > 0 && slices.Contains(ZohoExtenList, event["DestCallerIDNum"]) { //呼入队列或部门成员未接听(一个) startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=missed&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) delete(TimetimesList, event["Linkedid"]) delete(StartTimeList, event["Linkedid"]) } else if (strings.HasPrefix(event["Context"], "department") || strings.HasSuffix(event["Context"], "queue")) && event["DialStatus"] != "ANSWER" && TimetimesList[event["Linkedid"]] >= 2 && slices.Contains(ZohoExtenList, event["DestCallerIDNum"]) { //呼入队列或部门(两个以上) n = n + 1 if TimetimesList[event["Linkedid"]] == n { startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=missed&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["DestCallerIDNum"], startTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) delete(TimetimesList, event["Linkedid"]) delete(StartTimeList, event["Linkedid"]) n = 0 } } else if event["DialStatus"] == "ANSWER" { delete(TimetimesList, event["Linkedid"]) } // 呼叫已连接事件 } else if event["Event"] == "BridgeEnter" { //接听标志事件 Channel := strings.Split(event["Channel"], "/") // Outgoing Call - Answered if event["Context"] == "macro-trunkdial-failover" && event["Priority"] == "1" && slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) { // 注意这里选择 Priority:1 的,便于确认 CallerIDNum,ConnectedLineNum // 记录开始时间 TimestampList[event["Linkedid"]] = event["Timestamp"] StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour) // LinkedidList["Linkedid"] = event["Linkedid"] CallTypeList[event["Linkedid"]] = "outgoing" // https: //www.zohoapis.com/phonebridge/v3/callnotify?type=dialed&state=answered&id=10003&from=123456789&to=12300000001 // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, callId, event["CallerIDNum"], event["ConnectedLineNum"]) getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dialed&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["ConnectedLineNum"], event["CallerIDNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) // Incoming Call - Answered } else if (event["Context"] == "macro-stdexten" || event["Context"] == "macro-stdexten-withoutvm") && Channel[0] != "Local" && slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) && event["SwapUniqueid"] == "" { // event["SwapUniqueid"]判断是否转移 // 记录开始时间 TimestampList[event["Linkedid"]] = event["Timestamp"] // 呼入时设置 Uniqueid 不是 Linkedid StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour) // 呼入时设置 Uniqueid 不是 Linkedid CallTypeList[event["Linkedid"]] = "incoming" // https://www.zohoapis.com/phonebridge/v3/callnotify?type=received&state=answered&id=10023&from=12300000001&to=123456789 getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["ConnectedLineNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } else if (strings.HasPrefix(event["Context"], "department") && event["Priority"] == "1" && event["SwapUniqueid"] == "") || (strings.HasSuffix(event["Context"], "queue") && event["SwapUniqueid"] == "") { //部门或队列成员接听 TimestampList[event["Linkedid"]] = event["Timestamp"] // 呼入时设置 Uniqueid 不是 Linkedid StartTimeList[event["Linkedid"]] = time.Now().Add(-8 * time.Hour) // 呼入时设置 Uniqueid 不是 Linkedid // LinkedidList["Linkedid"] = event["Linkedid"] CallTypeList[event["Linkedid"]] = "incoming" if event["Priority"] == "1" && slices.Contains(ZohoExtenList, event["CallerIDNum"]) { getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["ConnectedLineNum"], event["CallerIDNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } else if slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) { getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=answered&id=%s&from=%s&to=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["ConnectedLineNum"]) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } delete(TimetimesList, event["Linkedid"]) n = 0 } // else if event["SwapUniqueid"] != "" { // CallTypeList[event["Linkedid"]] = "incoming" // } // 呼叫挂断事件 } else if event["Event"] == "Hangup" { //接听挂断标志事件 // * ===================================================================================== */ // 判断呼叫状态,为 ANSWER 时才推送,否则见以上推送 Outgoing Call - Unattended 或 Incoming Call - Missed Channel := strings.Split(event["Channel"], "/") // lfshook.NewLogger().Errorf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa %+v", event["Context"]) // fmt.Println("ChannelHangupRequest1 = ", DialStatusList[event["Linkedid"]]) // Outgoing Call - Ended if event["Context"] == "macro-trunkdial-failover" && CallTypeList[event["Linkedid"]] == "outgoing" { //坐席呼出挂断 startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) durationTime := getDuration(event["Linkedid"], event["Timestamp"]) if durationTime != -1 { //判断通话时长是否正常 if event["Priority"] == "1" && slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) { // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dailed&state=ended&id=10030&from=123456789&to=12300000001&start_time=2024-12-04 11:32:15&duration=325 // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dailed&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime) getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dailed&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["ConnectedLineNum"], event["CallerIDNum"], startTime, durationTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } else if slices.Contains(ZohoExtenList, event["CallerIDNum"]) { // https://www.zohoapis.com/phonebridge/v3/callnotify?type=dailed&state=ended&id=10030&from=123456789&to=12300000001&start_time=2024-12-04 11:32:15&duration=325 // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dailed&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime) getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=dailed&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } } // 删除记录时间 delete(StartTimeList, event["Linkedid"]) delete(CallTypeList, event["Linkedid"]) } else if Channel[0] != "Local" && CallTypeList[event["Linkedid"]] == "incoming" && AttendedTransferList[event["Linkedid"]] == "" { //坐席呼入挂断 startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) durationTime := getDuration(event["Linkedid"], event["Timestamp"]) if durationTime != -1 { if event["Priority"] == "1" && slices.Contains(ZohoExtenList, event["CallerIDNum"]) { getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["ConnectedLineNum"], event["CallerIDNum"], startTime, durationTime) // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } else if slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) { getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime) // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } } delete(StartTimeList, event["Linkedid"]) delete(CallTypeList, event["Linkedid"]) } else if AttendedTransferList[event["Linkedid"]] != "" && CallTypeList[event["Linkedid"]] == "incoming" { //转接挂断 startTimeutc := StartTimeList[event["Linkedid"]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) durationTime := getDuration(event["Linkedid"], event["Timestamp"]) if event["Priority"] == "1" && slices.Contains(ZohoExtenList, event["CallerIDNum"]) { getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["ConnectedLineNum"], event["CallerIDNum"], startTime, durationTime) // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } else if slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) { getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime) // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } AttendedSecondTransferList[event["Linkedid"]] = AttendedTransferList[event["Linkedid"]] //创建转移后通话的初始时间戳 delete(StartTimeList, event["Linkedid"]) delete(CallTypeList, event["Linkedid"]) delete(AttendedTransferList, event["Linkedid"]) } else if AttendedSecondTransferList[event["Linkedid"]] != "" { //转接挂断 startTimeutc := StartTimeList[AttendedSecondTransferList[event["Linkedid"]]].In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) durationTime := getDuration(AttendedSecondTransferList[event["Linkedid"]], event["Timestamp"]) if event["Priority"] == "1" && slices.Contains(ZohoExtenList, event["CallerIDNum"]) { getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, AttendedSecondTransferList[event["Linkedid"]], event["ConnectedLineNum"], event["CallerIDNum"], startTime, durationTime) // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } else if slices.Contains(ZohoExtenList, event["ConnectedLineNum"]) { getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, AttendedSecondTransferList[event["Linkedid"]], event["CallerIDNum"], event["ConnectedLineNum"], startTime, durationTime) // getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=ended&id=%s&from=%s&to=%s&start_time=%s&duration=%d", ZOHO_URL, callId, event["ConnectedLineNum"], event["CallerIDName"], startTime, durationTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } delete(StartTimeList, AttendedSecondTransferList[event["Linkedid"]]) delete(AttendedSecondTransferList, event["Linkedid"]) } } else if event["Event"] == "AttendedTransfer" && slices.Contains(ZohoExtenList, event["TransfereeConnectedLineNum"]) { //热转接 if event["Result"] == "Success" { AttendedTransferList[event["OrigTransfererLinkedid"]] = event["SecondTransfererLinkedid"] delete(CallTypeList, event["SecondTransfererLinkedid"]) } } else if event["Event"] == "SoftHangupRequest" { //呼入离线坐席 Channel := strings.Split(event["Channel"], "/") if (event["Context"] == "macro-stdexten" || event["Context"] == "macro-stdexten-withoutvm") && Channel[0] != "Local" && len(event["Exten"]) > 3 { startTimebj := time.Now().Add(-8 * time.Hour) startTimeutc := startTimebj.In(time.UTC) // 存储从string 改为 time.Time startTime := startTimeutc.Format(time.RFC3339) if event["ConnectedLineNum"] == "" { ConnectedLineNum := strings.Split(strings.Split(event["ConnectedLineNum"], "<")[1], ">")[0] getURL := fmt.Sprintf("%s/phonebridge/v3/callnotify?type=received&state=missed&id=%s&from=%s&to=%s&start_time=%s", ZOHO_URL, event["Linkedid"], event["CallerIDNum"], ConnectedLineNum, startTime) // fmt.Println("getURL = ", getURL) go httpclient.ZohoGet(getURL) } } } // 测试验证下上面有没有删除,以防TimestampList越来越大 // for k, v := range TimestampList { // fmt.Printf("===Linkedid:%s Timestamp:%s===\n", k, v) // } } // 使用事件中event["Timestamp"]的值计算时间间隔 // func getDuration(uniqueid string, timeStamp string) int { func getDuration(linkedid string, timeStamp string) int { // 都改为 Linkedid fmt.Println("startTimeStamp Str: ", TimestampList[linkedid]) if TimestampList[linkedid] == "" || timeStamp == "" { fmt.Printf("linkedid 或 timeStamp 为空\n") return -1 } startTimeStamp, err := strconv.ParseFloat(TimestampList[linkedid], 64) if err != nil { fmt.Printf("startTimeStamp转换出错: %v\n", err) return -1 } fmt.Printf("startTimeStamp=%f\n", startTimeStamp) endTimeStamp, err := strconv.ParseFloat(timeStamp, 64) if err != nil { fmt.Printf("endTimeStamp转换出错: %v\n", err) return -1 } fmt.Printf("endTimeStamp=%f\n", endTimeStamp) durationTime := time.Duration(endTimeStamp-startTimeStamp) * time.Second fmt.Printf("durationTime=%d\n", int(durationTime.Seconds())) // durationTime=35 // 删除记录时间 delete(TimestampList, linkedid) // return durationTime return int(durationTime.Seconds()) } // @tags PBX-zoho // @Summary 刷新token // @Description 刷新token // @Security ZohoToken // @Accept json // @Produce json // @Router /api/zoho/refresh-token [post] func RefreshToken() { // 获取配置文件信息 // confPath := "/etc/asterisk/vtiger_api.conf" confPath := "/etc/asterisk/crm_api.conf" cfg, err := ini.Load(confPath) if err != nil { lfshook.NewLogger().Error(err) return } ZohoAuthUrl := cfg.Section("general").Key("zohoAuthUrl").String() ZohoRefreshToken := cfg.Section("general").Key("zohoRefreshToken").String() ZohoClientId := cfg.Section("general").Key("zohoClientId").String() ZohoClientSecret := cfg.Section("general").Key("zohoClientSecret").String() if ZohoAuthUrl == "" || ZohoRefreshToken == "" || ZohoClientId == "" || ZohoClientSecret == "" { lfshook.NewLogger().Error("/etc/asterisk/crm_api.conf not set zohoAuthUrl or zohoRefreshToken or zohoClientId or zohoClientSecret") return } // 创建请求 // https://accounts.zoho.com/oauth/v2/token?refresh_token=1004.86c8c0e3db7bfe9133598825bef28eb9.17a82a3bf3e675c504f478c1b0b5c456 // &client_id=1004.LWJCJZD5O9DB6SZLL5YJEWHT7LH0BV&client_secret=fc3aef43dc58af8a49d3ed597710924200b03f74d0&grant_type=refresh_token getURL := fmt.Sprintf("%s/oauth/v2/token?refresh_token=%s&client_id=%s&client_secret=%s&grant_type=refresh_token", ZohoAuthUrl, ZohoRefreshToken, ZohoClientId, ZohoClientSecret) fmt.Printf("getURL = %s\n", getURL) // data := httpRequest(ctx, "POST", getURL) // /* ===================================================================================== req, err := http.NewRequest("POST", getURL, nil) if err != nil { fmt.Println("创建请求时发生错误:", err) return } // 创建HTTP客户端 client := &http.Client{} // req.Header.Set("Authorization", "Bearer "+accessToken) // 刷新token时不需要 // 发送请求 resp, err := client.Do(req) if err != nil { fmt.Println("发送请求时发生错误:", err) return } defer resp.Body.Close() // 读取请求后的响应 data, err := ioutil.ReadAll(resp.Body) if err != nil { // 读取数据错误 lfshook.NewLogger().Warn("ioutil ReadAll failed :", err.Error()) // api.Error(ctx, http.StatusInternalServerError, err.Error()) return } lfshook.NewLogger().Infof("data %+v", string(data)) // * ===================================================================================== */ refreshTokenData := RefreshTokenResp{} err = json.Unmarshal([]byte(data), &refreshTokenData) if err != nil { // 转换数据错误 lfshook.NewLogger().Warn("json unmarshal failed :", err.Error()) // api.Error(ctx, http.StatusInternalServerError, err.Error()) return } // 将获取的 access_token 写入文件 crm_api.conf cfg.Section("general").Key("zohoAccessToken").SetValue(refreshTokenData.AccessToken) ZOHO_URL = refreshTokenData.ApiDomain err = cfg.SaveTo(confPath) if err != nil { lfshook.NewLogger().Error(err) // api.Error(ctx, http.StatusInternalServerError, err.Error()) return } // 打印请求后的响应 fmt.Printf("data = %+v\n", string(data)) } // 每隔55分钟刷新token func RefreshTokenTicker() { ticker := time.NewTicker(55 * time.Minute) defer ticker.Stop() done := make(chan bool) // go func() { // 注释掉OK for { select { case <-done: return case t := <-ticker.C: fmt.Println("Tick at", t) RefreshToken() } } // }() } // 每隔3秒更新zoho用户分机集合 func ZohoUserExtenList() { // 构建参数 // lfshook.NewLogger().Error("来了") list := make([]string, 0) session := mysql.DBOrmInstance.Prepare() // 查询数据 var data []TabZohouser _, err := session.FindAndCount(&data) if err != nil { lfshook.NewLogger().Error(err) return } for _, v := range data { list = append(list, v.Exten) } ZohoExtenList = list // lfshook.NewLogger().Error(ZohoExtenList) } func RefreshZohoUserExtenListTicker() { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() done := make(chan bool) // go func() { // 注释掉OK for { select { case <-done: return case <-ticker.C: // fmt.Println("Tick at", t) ZohoUserExtenList() } } }