udesk工单系统接钉钉机器人,支持markdown消息类型

一、背景

由于公司客服系统使用的udesk,办公通讯工具是钉钉。客服人员与技术人员需要同时登录两个系统来工作,加上周六日工单接收不及时,用户问题得不到及时解决,客服经理便想怎么高效的让技术人员及时看到并处理工单,同时客服人员也能及时看到工单的处理进度。

刚开始我们在udesk工单管理后台配置触发器,使用udesk本身的功能来触发消息通知,通知邮件。邮件使用钉邮,钉邮接收到邮件,钉钉会有提示。

但是邮件经常有延迟的情况,便打算用钉钉群机器人了。

二、思路

一开始,我们在udesk中添加提醒目标,URL为钉钉机器人地址(如何创建钉钉机器人就不赘述了)

image

然后通过触发器,添加提醒动作。但是很多信息拿不到,比如工单号、工单标题等,都不能推送到钉钉。

image

询问udesk方后,建议使用API来实现。官方文档 http://www.udesk.cn/doc/apiv2/tickets/ 可以看到大部分都是get请求,使用python处理起来还是很方便的。

要求达到的目的是:

1.不管是新的工单还是工单有更新第一时间推送消息到钉钉群。

2.消息包括:工单号、工单标题、工单内容、创建时间等。如工单有回复,显示完整信息,包括图片。

3.消息还需包括对应的工单链接。

三、方法

整个代码分三部分:

1.登录udesk,拿到token,使用token进行签名

2.udesk创建过滤器,获取某过滤器下的最新工单id。(由于公司业务线路较多,如果直接拿工单列表,很难筛选出对应的工单,而且还有可能漏掉。)拿到工单id后,查看工单详情,编辑相关信息,交给钉钉机器人

3.钉钉机器人推送的json使用markdown类型,以便展示图片等。

代码如下(粘贴过来的代码格式有问题,请注意制表符):


第一部分:

import json
import requests
import time
import random
from dingtalkchatbot.chatbotimport DingtalkChatbot

# 获取 鉴权 Token
def login(host,email,password):
  headers = {
    "content-type":"application/json",
     }
  body = {
    "email":email,
    "password":password
  }
  login_url = host +"open_api_v1/log_in"
    response = requests.post(url=login_url, headers=headers, data=json.dumps(body))
  # print(response.status_code)
  # print(json.dumps(response.json(), indent=2))
  token = response.json()["open_api_auth_token"]
  # print(token)
  return token

# 签名方法,字符串sha256加密
def createSign(email,token,timestamp,nonce,sign_version):
  sign_params = email +"&" + token +"&" + timestamp +"&" + nonce +"&" + sign_version
  signature = hashlib.sha256()
  signature.update(sign_params.encode(encoding='UTF8'))
  # print(signature.hexdigest())
    return signature.hexdigest()

第二部分:

#通用API获取response,first_word和last_word均不填即获取工单列表
def get_response(host,first_word,email,token,last_word):
  timestamp =str(int(time.time()))
  hex_str ="".join([choice("0123456789abcdef")for i in range(32)])
  hex_list =list(hex_str)
  hex_list.insert(20, "-")
  hex_list.insert(16, "-")
  hex_list.insert(12, "-")
  hex_list.insert(8, "-")
  nonce ="".join(hex_list)
  sign_version ="v2"
  sign = createSign(email, token, timestamp, nonce, sign_version)
  get_url = host +"open_api_v1/tickets/" +first_word+"?email=" + email +"&timestamp=" + timestamp +"&sign=" + sign +"&nonce=" + nonce +"&sign_version=" + sign_version+last_word
  # print(info_url)
   response = requests.get(url=get_url)
# print(response.status_code)
# print(json.dumps(response.json(), indent=2))
    return response.json()

# 获取某个工单过滤器下的最后一个工单
def tickets_in_filter(host,email,token,filter_id):
  udesk_response = get_response(host, "tickets_in_filter", email, token, "&filter_id="+filter_id)
  ticket_id = udesk_response["contents"][0]["ticket"]["id"]if udesk_response["contents"][0]["ticket"]["id"]else None
    # print(ticket_id)
    return ticket_id

# 获取工单详情
def list_info(host,email,token,ticket_id):
  udesk_response = get_response(host,"detail",email,token,"&id="+str(ticket_id))
  ticket_id = udesk_response["ticket"]["id"]if udesk_response["ticket"]["subject"]else ""
  ticket_subject = udesk_response["ticket"]["subject"]if udesk_response["ticket"]["subject"]else ""
  ticket_content = udesk_response["ticket"]["content"]if udesk_response["ticket"]["content"]else ""
    # 工单内容展示图片
    img_place =str(ticket_content).find("img")
  if img_place >0:
    ticket_content =str(ticket_content).replace('<img src="', '![](').replace('" />', ')')
    ticket_attachments = udesk_response["ticket"]["attachments"]
  if len(ticket_attachments) >0:
    ticket_content = ticket_content +" 注意有附件!"
  ticket_status = udesk_response["ticket"]["status"]if udesk_response["ticket"]["status"]else ""
  ticket_priority = udesk_response["ticket"]["priority"]if udesk_response["ticket"]["priority"]else ""
  if ticket_priority =="紧急":
      ticket_priority =" >优先级:<font color=#ff0000 size=16>" + ticket_priority +"!!!"
  if ticket_priority =="高":
      ticket_priority =" >优先级:<font color=#ff9900 size=16>" + ticket_priority +"!!!"
  if ticket_priority =="标准":
      ticket_priority =" >优先级:__" + ticket_priority +"__"
    ticket_assignee_name = udesk_response["ticket"]["assignee_name"]if udesk_response["ticket"]["assignee_name"]else ""
    ticket_create_time = udesk_response["ticket"]["created_at"]if udesk_response["ticket"]["created_at"]else ""
    # 处理时间格式
    ticket_create_time = ticket_create_time.replace('T', '  ').replace('Z', '').split('.')[0]
ticket_update_time = udesk_response["ticket"]["updated_at"]if udesk_response["ticket"]["updated_at"]else ""
    ticket_text ="## 标题:[" + ticket_subject +"](https://bitz.s2.udesk.cn/entry/ticket/show/" +str(ticket_id) +")\n- - -\n" + ticket_priority +"\n- - -\n >内容:__" + ticket_content +"__ \n- - -\n  >受理人:__" + ticket_assignee_name +"__  \n- - -\n >创建时间:__" + ticket_create_time +"__ \n- - -\n"
    # print(ticket_text)
    return ticket_text

# 获取工单最新回复
def ticket_replies(host,email,token,ticket_id):
udesk_response = get_response(host, str(ticket_id)+"/replies", email, token, "")
reply_text =""
    if len(udesk_response["replies"])>0:
reply_content = udesk_response["replies"][0]["content"]
img_place =str(reply_content).find("img")
if img_place >0:
reply_content =str(reply_content).replace('<img src="', '![](').replace('" />', ')')
# print(reply_content)
        reply_time = udesk_response["replies"][0]["created_at"]
reply_user = udesk_response["replies"][0]["author"]["nick_name"]
reply_text =" >回复人员:__"+reply_user+"__\n- - -\n >回复内容:__"+ reply_content+"__"
        # print(reply_text)
    return reply_text

# 钉钉消息
def dingtalk(webhook,text):
    xiaoding = DingtalkChatbot(webhook)
    markdown_text = {
    "msgtype":"markdown",
        "markdown": {
            "title":"您有新的工单!!!",
            "text":text
    },
    "at": {
        "atMobiles": [
                "18xx6"
          ],
         "isAtAll":True
            }
}
xiaoding.send_markdown(title = markdown_text["markdown"]["title"],text = markdown_text["markdown"]["text"])

主程序

udesk_host ="https://demo.s2.udesk.cn/"
    email ="XXXXXX"
    password ="XXXXXXX"
    test1_webhook = "https://oapi.dingtalk.com/robot/send?access_token=d78dXXXX"
    test2_webhook = "https://oapi.dingtalk.com/robot/send?access_token=d78dXXXX"
    test3_webhook = "https://oapi.dingtalk.com/robot/send?access_token=d78dXXXX"
    token = login(udesk_host,email,password)
ticket_id1,ticket_id2=0,0
    try:
        filter_list = ["12345","12xx","323x4""]
        webhook_list = [test1_webhook,test2_webhook,test3_webhook]
        ticket_id,ticket_text,ticket_replay = [],[],[]
        for i in range(len(filter_list)):
        ticket_id.append(tickets_in_filter(udesk_host, email, token, filter_list[i]))
        ticket_text.append(list_info(udesk_host, email, token, ticket_id[i]))
        ticket_replay.append(ticket_replies(udesk_host, email, token, ticket_id[i]))
    except Exception as e:
        print("First Exception:")
        print(str(e))
    while True:
        time.sleep(10)# 10秒查询一次
        try:
            ticket_id_new, ticket_text_new, ticket_replay_new = [], [], []
            for i in range(len(filter_list)):
                ticket_id_new.append(tickets_in_filter(udesk_host, email, token, filter_list[i]))
                ticket_text_new.append(list_info(udesk_host, email, token, ticket_id_new[i]))
                ticket_replay_new.append(ticket_replies(udesk_host, email, token, ticket_id_new[i]))
                if ticket_id_new[i] != ticket_id[i]or ticket_text_new[i]+ticket_replay_new[i] != ticket_text[i]+ticket_replay[i]:
                        dingtalk(webhook_list[i], ticket_text_new[i] + ticket_replay_new[i])
                        ticket_id[i] = ticket_id_new[i]
                        ticket_text[i] = ticket_text_new[i]
                        ticket_replay[i] = ticket_replay_new[i]
                time.sleep(1)# 防止 429 错误  api接口超过请求限制
except Exception as e:
print("Exception:\n")
print(str(e))```
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 二十一世纪旧体诗词风骚榜[https://www.jianshu.com/c/da968ae2d498] 上榜絮语...
    张成昱阅读 727评论 0 20
  • 1、国际:全球最大转账公司西联汇款暂停美国向古巴汇款(因特朗普政府对古巴实施最新制裁) 2、经济:包商银行65亿二...
    81d3fa880d65阅读 91评论 0 0
  • 小说|畸形新生儿 “麻好了吗?” 贾医生收起手机,走到手术间的一侧,踩下像皮球,洗手液立刻喷溅在他的双手上。摩搓手...
    宫麦阅读 263评论 0 0
  • 黑色的海岛上悬着一轮又大又圆的明月,毫不嫌弃地把温柔的月色照在这寸草不生的小岛上。一个少年白衣白发,悠闲自如地倚坐...
    小水Vivian阅读 3,093评论 1 5
  • 渐变的面目拼图要我怎么拼? 我是疲乏了还是投降了? 不是不允许自己坠落, 我没有滴水不进的保护膜。 就是害怕变得面...
    闷热当乘凉阅读 4,233评论 0 13