企业微信开发实战(三、OA审批之回调通知、获取审批单号、审批详情)
文章目录
- 4.审批申请状态变化回调通知
- 4.1设置接收事件服务器
- 4.1.1 设置入口
- 4.2 配置说明
- 5.批量获取审批单号
- 5.1概述
- 5.2代码实战
- 5.3试错
- 6.获取审批申请详情
- 6.1概述
- 6.2代码实战
- 6.3试错
- 源码
- 赞赏
4.审批申请状态变化回调通知
订阅后,当企业内指定类型的企业微信“审批应用”单据流程发生变化时,会将审批单最新的流程状态回调给开发者。
4.1设置接收事件服务器
查看事件回调详细说明
4.1.1 设置入口
目前,支持将审批状态变化通知回调给审批应用、指定的自建应用。
1、审批应用回调地址设置
- 企业可以在【管理后台->应用和小程序->审批->API->接收事件服务器】中,设置回调地址,并勾选需要进行状态变化回调通知的审批模板类型。
- 设置后,回调地址可接收审批应用所有允许进行回调的审批申请相关状态变化通知。
2、自建应用回调地址设置
- 企业可在【管理后台->应用管理->审批->API->可调用应用】中,设置可调用审批相关接口的自建应用。
- 设置后,回调地址可接收自建应用可见范围内成员提交的、审批应用允许进行回调的审批申请相关状态变化通知。
3、注意:只有在【审批->API->可调用应用】中勾选了的自建应用才可以接收到在【审批->API->接收事件服务器】勾选模板相关的审批申请回调通知。
4.2 配置说明
1、参数设置
进入配置页面,要求填写URL、Token、EncodingAESKey三个参数。
- URL是企业后台接收企业微信推送请求的访问协议和地址,支持http或https协议(建议使用https)。
- Token可由企业任意填写,用于生成签名。
- EncodingAESKey用于消息体的加密,是AES密钥的Base64编码。
2、其他配置
- 在审批应用“接收事件服务器”,可设置允许进行回调通知的模板类型,此配置将同样作用于自建应用与第三方应用的回调通知。
- 在自建应用中,可通过在【应用详情-接收消息-设置API接收】中开关“审批状态通知事件”,来控制是否接收相关回调。
(1)按下图所示步骤打开"配置回调地址"界面:
(2)打开utools工具(安装utools工具),搜索"内网穿透",如下图所示将本机的5000端口通过"你的自定义四级域名.cn.utools.club"暴露到外网,此时其他人就可以通过你配置的域名访问到你本机跑的netcore项目。
(3)接收消息服务器配置如下,其中url指的是你代码中Callback地址,记得要将localhost改为内网穿透后的地址;token和EncodingAESKey都可自定义,也可通过"随机获取"按钮随机生成,后面代码中需要用到。
(4)具体代码如下:
- 官方提供的加解密类
- 官方回调解析
- 官方在线回调调试
Callback
接口是事件回调接收接口。Verify
方法是校验信息的有消息,在页面上配置接口,点击"保存"时,企业微信会调用该接口,校验接口是否能正常解析sEchoStr
并返回。DecryptMsg
方法是对用户回复的消息解密,会在控制台中输出企业微信推送过来的xml信息。
#region 4、审批申请状态变化回调通知[Route("Callback")]public Task<string> Callback(CallbackModel model){//1、校验回调是否成功return Verify(model);//2、解析回调的数据//return DecryptMsg(model);}/// <summary>/// 1、校验信息有效性/// </summary>/// <param name="model"></param>/// <returns></returns>private string Verify(CallbackModel model){//调用官方解析方法Tencent.WXBizMsgCrypt wxcpt = new Tencent.WXBizMsgCrypt("你的回调token", "你的EncodingAESKey", "你的企业id");// string sVerifyMsgSig = HttpUtils.ParseUrl("msg_signature");//获取url中的msg_signature参数值string sVerifyMsgSig = model.msg_signature;// string sVerifyTimeStamp = HttpUtils.ParseUrl("timestamp");//获取url中的timestamp参数值string sVerifyTimeStamp = model.timestamp;// string sVerifyNonce = HttpUtils.ParseUrl("nonce");//获取url中的nonce参数值string sVerifyNonce = model.nonce;// string sVerifyEchoStr = HttpUtils.ParseUrl("echostr");//获取url中的echostr参数值string sVerifyEchoStr = model.echostr;int ret = 0;string sEchoStr = "";//校验数据的有消息,如果有效则返回0ret = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, sVerifyEchoStr, ref sEchoStr);if (ret != 0){System.Console.WriteLine("ERR: VerifyURL fail, ret: " + ret);}return sEchoStr;}/// <summary>/// 2、对用户回复的消息解密(解析并输出xml)/// </summary>/// <param name="model"></param>/// <returns></returns>private async Task<string> DecryptMsg(CallbackModel model){//获取请求体var context = HttpContext.Request.Body;int ret = 0;Tencent.WXBizMsgCrypt wxcpt = new Tencent.WXBizMsgCrypt("你的回调token", "你的EncodingAESKey", "你的企业id");// string sReqMsgSig = HttpUtils.ParseUrl("msg_signature");//获取url中的msg_signature参数值string sReqMsgSig = model.msg_signature;// string sReqTimeStamp = HttpUtils.ParseUrl("timestamp");//获取url中的timestamp参数值string sReqTimeStamp = model.timestamp;// string sReqNonce = HttpUtils.ParseUrl("nonce");//获取url中的nonce参数值string sReqNonce = model.nonce;// Post请求的密文数据// string sReqData = HttpUtils.PostData();string sReqData = "";//将请求体中的内容通过流的方式输出到字符串sReqData中using (var reader = new StreamReader(Request.Body)){sReqData = await reader.ReadToEndAsync();}//string sReqData = "<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>";string sMsg = ""; // 解析之后的明文ret = wxcpt.DecryptMsg(sReqMsgSig, sReqTimeStamp, sReqNonce, sReqData, ref sMsg);if (ret != 0){System.Console.WriteLine("ERR: Decrypt Fail, ret: " + ret);return "";}// ret==0表示解密成功,sMsg表示解密之后的明文xml串// TODO: 对明文的处理// For example:XmlDocument doc = new XmlDocument();doc.LoadXml(sMsg);//XmlNode root = doc.FirstChild;//string content = root["Content"].InnerText;//System.Console.WriteLine(content);//XmlNode root = doc.FirstChild;//string content = root.InnerText;//控制台打印请求体中获取到的内容System.Console.WriteLine(sMsg);return sMsg;}#endregion
(5)在项目未运行时或者设置不存在的回调接口时点击"保存",会看到提示"openapi回调地址请求不通过"的错误信息。
(6)注释掉"return DecryptMsg(model)",取消"return Verify(model)"的注释,运行该netcore项目,并开启内网穿透工具。
(7)Verify
方法返回的sEchoStr
参数是官方调用我们的回调接口时存放在加密数据中的信息,只有解析成功,并将该sEchoStr
参数返回,界面上才能看到"保存成功"的提示(在线回调调试),如下图:
(8)注释掉"return DecryptMsg(model)",取消"return Verify(model)"的注释,运行该netcore项目,并开启内网穿透工具,并在客户端中发起一条申请,如下图所示:
(9)此时命令行中会输出上一步中发起的"请假"申请,如下所示(xml文档属性解析):
<?xml version="1.0" encoding="utf-8"?>
<xml><ToUserName><![CDATA[ww94e74526d29a98c4]]></ToUserName><FromUserName><![CDATA[sys]]></FromUserName><CreateTime>1619146833</CreateTime><MsgType><![CDATA[event]]></MsgType><Event><![CDATA[sys_approval_change]]></Event><AgentID>3010040</AgentID><ApprovalInfo><SpNo>202104230001</SpNo><SpName><![CDATA[请假]]></SpName><SpStatus>1</SpStatus><TemplateId><![CDATA[3TmmUh7YqD7QMLPZWKJFP8bvanYgmndV6eqbq84n]]></TemplateId><ApplyTime>1619146832</ApplyTime><Applyer><UserId><![CDATA[XieGuoYong]]></UserId><Party><![CDATA[1]]></Party></Applyer><SpRecord><SpStatus>1</SpStatus><ApproverAttr>1</ApproverAttr><Details><Approver><UserId><![CDATA[a7a885f027068925d1609a726fb945a6]]></UserId></Approver><Speech><![CDATA[]]></Speech><SpStatus>1</SpStatus><SpTime>0</SpTime></Details></SpRecord><StatuChangeEvent>1</StatuChangeEvent></ApprovalInfo>
</xml>
(10)到这一步就完成了"审批申请状态变化回调通知"的配置与代码实现了,后续需要入库操作,请自行解析xml,并进行持久化操作(注:后面有空的话也可能会分享我入库的版本出来,如果看的人多且我有空的话!)。
5.批量获取审批单号
5.1概述
1、调试工具地址:调试工具
2、审批应用及有权限的自建应用,可通过Secret调用本接口,以获取企业一段时间内企业微信“审批应用”单据的审批编号,支持按模板类型、申请人、部门、申请单审批状态等条件筛选。
自建应用调用此接口,需在“管理后台-应用管理-审批-API-审批数据权限”中,授权应用允许提交审批单据。
3、一次拉取调用最多拉取100个审批记录,可以通过多次拉取的方式来满足需求,但调用频率不可超过600次/分。
推荐使用此接口获取审批数据,旧接口后续将不再维护。
**请求方式:**POST(HTTPS)
**请求地址:**https://qyapi.weixin.qq.com/cgi-bin/oa/getapprovalinfo?access_token=ACCESS_TOKEN
请求示例:
{"starttime" : "1569546000","endtime" : "1569718800","cursor" : 0 ,"size" : 100 ,"filters" : [{"key": "template_id","value": "ZLqk8pcsAoaXZ1eY56vpAgfX28MPdYU3ayMaSPHaaa"},{"key" : "creator","value" : "WuJunJie"},{"key" : "department","value" : "1"}, {"key" : "sp_status","value" : "1"} ]
}
参数说明:
参数 | 必须 | 说明 |
---|---|---|
access_token | 是 | 调用接口凭证。必须使用审批应用或企业内自建应用的secret获取,获取方式参考:文档-获取access_token |
starttime | 是 | 审批单提交的时间范围,开始时间,UNix时间戳 |
endtime | 是 | 审批单提交的时间范围,结束时间,Unix时间戳 |
cursor | 是 | 分页查询游标,默认为0,后续使用返回的next_cursor进行分页拉取 |
size | 是 | 一次请求拉取审批单数量,默认值为100,上限值为100 |
filters | 否 | 筛选条件,可对批量拉取的审批申请设置约束条件,支持设置多个条件 |
└ key | 否 | 筛选类型,包括: template_id - 模板类型/模板id; creator - 申请人; department - 审批单提单者所在部门; sp_status - 审批状态。 注意: 仅“部门”支持同时配置多个筛选条件。 不同类型的筛选条件之间为“与”的关系,同类型筛选条件之间为“或”的关系 |
└ value | 否 | 筛选值,对应为:template_id-模板id;creator-申请人userid ;department-所在部门id;sp_status-审批单状态(1-审批中;2-已通过;3-已驳回;4-已撤销;6-通过后撤销;7-已删除;10-已支付) |
1 接口频率限制 600次/分钟
2 请求的参数endtime需要大于startime, 起始时间跨度不能超过31天;
返回结果 :
{"errcode": 0,"errmsg": "ok","sp_no_list": ["201909270001","201909270002","201909270003"]
}
参数说明:
参数 | 说明 |
---|---|
sp_no_list | 审批单号列表,包含满足条件的审批申请 |
next_cursor | 后续请求查询的游标,当返回结果没有该字段时表示审批单已经拉取完 |
错误说明:
错误码 | 说明 |
---|---|
301055 | 无审批应用数据拉取权限 |
301025 | 请求参数错误 |
301026 | 批量拉取审批单内部接口失败 |
5.2代码实战
1、代码如下:
#region 5、批量获取审批单号/// <summary>/// 批量获取审批单号/// </summary>/// <returns></returns>[Route("ApprovalInfo")]public async Task<IActionResult> ApprovalInfo(){//request accessTokenvar model = GetAccessToken();string accessToken = "";if (model != null)accessToken = model.access_token;//build request urlstring url = "https://qyapi.weixin.qq.com/cgi-bin/oa/getapprovalinfo?access_token=" + accessToken;//build filter model//很多在线的unix时间戳转换工具,将开始与结束时间戳设置为你发起过申请的时间段内即可//实际开发应该是在页面上可以选择,然后后端才动态去请求,这里只做演示,故写死ApprovalInfoFilterModel filter = new ApprovalInfoFilterModel(){starttime = "1618880400",//开始时间戳endtime = "1618968648"//结束时间戳};//request using (HttpClient client = new HttpClient()){var response = await client.PostAsync(url, new JsonContent(filter));//get result/*{"errcode": 0,"errmsg": "ok","sp_no_list": ["201909270001","201909270002","201909270003"]}*///sp_no_list 审批单号列表,包含满足条件的审批申请//next_cursor 后续请求查询的游标,当返回结果没有该字段时表示审批单已经拉取完var res = response.Content.ReadAsStringAsync().Result;return Content(res);}}/** 错误码 说明301055 无审批应用数据拉取权限301025 请求参数错误301026 批量拉取审批单内部接口失败*/#endregion
2、访问ApprovalInfo
接口,可看到返回的"审批单号"列表(注:这个单号是你当前的审批应用发起过的申请的单号,如果你没发起过,返回的列表就是空的)
5.3试错
此时将请求的开始时间改为两个月前的时间,并重新运行项目,会出现如下参数错误的json,原因时企业微信那边规定了起始时间与结束时间的跨度不能超过31天。
{"errcode": 301025,"errmsg": "get approval param error, hint: [1619148837_171_c18ae242ea46634c3d1c0e81d30579a4], from ip: 61.144.144.239, more info at https://open.work.weixin.qq.com/devtool/query?e=301025","sp_no_list": []
}
6.获取审批申请详情
6.1概述
1、调试工具地址:调试工具
2、企业可通过审批应用或自建应用Secret调用本接口,根据审批单号查询企业微信“审批应用”的审批申请详情。
**请求方式:**POST(HTTPS)
请求地址: https://qyapi.weixin.qq.com/cgi-bin/oa/getapprovaldetail?access_token=ACCESS_TOKEN
请求示例:
{ "sp_no" : "201909270001"}
参数说明:
参数 | 必须 | 说明 |
---|---|---|
access_token | 是 | 调用接口凭证。必须使用审批应用或企业内自建应用的secret获取,获取方式参考:文档-获取access_token |
sp_no | 是 | 审批单编号。 |
接口频率限制 600次/分钟
返回结果参数说明 :官网文档链接
6.2代码实战
1、代码如下:
#region 6、获取审批申请详情/// <summary>/// 获取审批申请详情/// </summary>/// <param name="sp_no">审批单号</param>/// <returns></returns>[Route("ApprovalDetail")]public async Task<IActionResult> ApprovalDetail(string sp_no){//request accessTokenvar model = GetAccessToken();string accessToken = "";if (model != null)accessToken = model.access_token;//build request urlstring url = "https://qyapi.weixin.qq.com/cgi-bin/oa/getapprovaldetail?access_token=" + accessToken;//request using (HttpClient client = new HttpClient()){var response = await client.PostAsync(url, new JsonContent(new { sp_no = sp_no }));//get resultvar res = response.Content.ReadAsStringAsync().Result;return Content(res);}}#endregion
2、访问ApprovalDetail
接口,并在url后面加上?sp_no=你的审批单号
,可看到返回了指定的审批详情数据(字段解析传送门)。
6.3试错
1、填写一个错误的审批单号,会出现"获取审批数据错误",如下是返回的json:
{"errcode": 301026,
"errmsg": "get approval data error, hint: [1619150281_164_57932dd54c6c8511da178b6acb01d061], from ip: 61.144.145.51, more info at https://open.work.weixin.qq.com/devtool/query?e=301026"
}
2、将代码中的sp_no = sp_no
更改为sp_no1 = sp_no
,会出现如下错误,提示参数错误,原因是接口需要的是"sp_no"而不是"sp_no1"。
{"errcode": 301025,
"errmsg": "get approval param error, hint: [1619150454_164_e80e6d553772daf415132280984e5858], from ip: 61.144.144.239, more info at https://open.work.weixin.qq.com/devtool/query?e=301025"
}
错误说明
错误码 | 说明 |
---|---|
301055 | 无审批应用数据拉取权限 |
301025 | 请求参数错误 |
301026 | 拉取审批申请详情内部接口失败 |
源码
地址:https://gitee.com/wusuoweixgy/QiYeWeiXinCode
克隆:git clone https://gitee.com/wusuoweixgy/QiYeWeiXinCode.git
赞赏
如果您觉得文章还不错,那就请作者喝杯咖啡吧!
企业微信开发实战(三、OA审批之回调通知、获取审批单号、审批详情)相关推荐
- 手把手教你springboot企业微信开发(三)之 weui、zepto、thymeleaf
手把手教你springboot企业微信开发(三)之 weui.zepto.thymeleaf weui zepto thymeleaf 这一篇主要事基础部分,概述一下weui.zepto.thymel ...
- 企业微信开发实战(四、OA审批之企业假期管理配置、获取成员假期余额、修改成员假期余额)
文章目录 7.获取企业假期管理配置 7.1概述 7.2代码实战 8.获取成员假期余额 8.1概述 8.2代码实战 8.3试错 9.修改成员假期余额 9.1概述 9.2代码实战 9.3试错 源码 赞赏 ...
- 企业微信开发实战(五、自建应用-审批流程引擎之配置可信任域名、创建审批模版、发起审批)
文章目录 四.自建应用-审批流程引擎 1.概述 2.创建自建应用审批模板 2.1创建自建审批应用 2.2配置可信任域名 2.3创建审批模版 3.自建应用发起审批 3.1概述 3.2代码实战 3.2.1 ...
- 企业微信开发(三)访问频率限制
参考: 访问频率限制 - 接口文档 - 企业微信开发者中心 基础频率 每企业调用单个cgi/api不可超过1万次/分,15万次/小时 每ip调用单个cgi/api不可超过2万次/分,60万次/小时 第 ...
- 企业微信开发实战(一、相关说明及注册企业微信)
文章目录 一.写着前面 1.说明 2.环境 二.注册企业微信 源码 赞赏 一.写着前面 1.说明 1.官方文档地址:https://open.work.weixin.qq.com/api/doc/90 ...
- 企业微信开发:获取 access_token(二)
前言 简单的用白话了解一下企业微信的作用,企业微信是腾讯微信团队为企业打造的专业办公管理工具.大致和钉钉差不多,适用于政府.企业等各类组织的一个产品,可以有效的帮您管理员工.个人感觉企业微信开发要 ...
- 企业微信接口测试实战
企业微信接口测试实战1 企业微信接口测试实战1 http://home.testing-studio.com/t/topic/5478企业微信接口测试实战1 课程内容介绍:接口请求组合,针对测试用例封 ...
- 服务器端缓存企业微信,企业微信开发
企业微信开发又以下三类,可以根据需要查看相应的文档 企业内部应用开发:开发内部使用应用,开发个性化办公应用 第三方应用开发:开发出来的应用可供其他企业使用 第三方应用开发.png 智慧硬件开发 企业内 ...
- 《精通Spring4.X企业应用开发实战》读后感第二章
一.配置Maven\tomcat https://www.cnblogs.com/Miracle-Maker/articles/6476687.html https://www.cnblogs.com ...
- 第八篇 :微信公众平台开发实战Java版之如何网页授权获取用户基本信息
第一部分:微信授权获取基本信息的介绍 我们首先来看看官方的文档怎么说: 如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑. 关于网页授权回调域 ...
最新文章
- mybatis做批量删除时写SQL语句时遇到的问题
- Mysql主从复制(docker例子)
- QT实现Media Player(媒体播放器)
- 服务器任务管理器详细信息,任务管理器服务器主机
- idea的setting界面怎么进_电脑怎么备份系统
- C正数负数的原码补码反码以及内存地址分析
- 利用CSS按比例缩小图片
- android的surfaceflinger原理讲解
- 4.看板方法---在五个季度内,从最差变为最好
- 【android自定义控件】ProgressBar自定义
- break 和continue 区别以及用法。
- 语音识别之前端处理及相关算法
- jQuery事件绑定和解绑
- java敏感词屏蔽器,“敏感词过滤”功能设置
- 云和恩墨大讲堂新春第一讲-Oracle安全特性之加密登陆
- 腾讯云服务器基础使用方法
- android状态栏高度px,安卓720*1280界面尺寸规范参考
- Linux系统DNS详解(BIND)
- 那些让你痛苦的,终将让你成长
- 中国社交:打不倒的微信,输不了的抖音