钉钉API-处理业务审批流程 回调爬坑记录

tech2022-12-24  72

API钉钉接入—审批流程


最近由于业务需求需要在项目中介入钉钉审批流程,虽然不是第一次接触钉钉api,但是之前使用是借助同事的配置(爬坑经验借鉴同事的 :简书 少年丶要淡定 ),一直没有比较系统的去了解使用,正好借助这次需求的机会,去深入了解一下,记录一下爬坑经验,难免以后会再次使用到。


文章目录

API钉钉接入—审批流程首先是 需要使用的外部资源:钉钉开放平台钉钉官方demo 项目使用源码钉钉配置项目介入使用钉钉url调用获取钉钉企业中的用户手机号:发起钉钉所用到的token发送请求 发起钉钉审批回调路径注入回调内外网穿透工具启动内网穿透 遇到的坑


首先是 需要使用的外部资源:

钉钉开放平台

使用钉钉开发官方工作流 钉钉开发文档

事件回调 回调是开发者在钉钉开放平台注册一个HTTP接口,并订阅相关的事件,当事件发生时,钉钉会主动调用开发者注册的HTTP接口,推送对应的事件信息。

内外网穿透工具:内外网穿透工具; 提供了一个公网代理服务,目的是方便开发测试。

钉钉官方demo

参考demo

项目使用源码

钉钉配置

要在钉钉企业用户信息中查看 钉钉管理后台,必须企业用户管理员才可以登录 登录开发者后台,点击左侧菜单的【移动接入应用-登录】,然后点击右上角的【创建扫码登录应用授权】,创建用于免登过程中验证身份的appId及appSecret,创建后即可看到appId和appSecret。

/** * 企业corpid, 需要修改成开发者所在企业 */ public static final String CORP_ID = "xxx"; /** * 应用的AppKey,登录开发者后台,点击应用管理,进入应用详情可见 */ public static final String APPKEY = "xxx"; /** * 应用的AppSecret,登录开发者后台,点击应用管理,进入应用详情可见 */ public static final String APPSECRET = "xxx"; /** * 数据加密密钥。用于回调数据的加密,长度固定为43个字符,从a-z, A-Z, 0-9共62个字符中选取,您可以随机生成 */ public static final String ENCODING_AES_KEY = "xxx"; /** * 加解密需要用到的token,企业可以随机填写。如 "12345" */ public static final String TOKEN = "xxx"; /** * 应用的agentdId,正式环境 */ public static final Long AGENTID = xxx;

以上每个参数的查看方式,请前往钉钉开发文档中查看

项目介入使用
钉钉url调用
public static String startProcessInstance(OapiProcessinstanceCreateRequest oapiProcessinstanceCreateRequest,String appKey,String appSecret) throws ApiException { DefaultDingTalkClient client = new DefaultDingTalkClient(URLConstant.URL_PROCESSINSTANCE_START); OapiProcessinstanceCreateResponse response = client.execute(oapiProcessinstanceCreateRequest, AccessTokenUtil.getToken(appKey,appSecret)); logger.debug("发起钉钉审批返回信息"+ new Gson().toJson(response)); return response.getProcessInstanceId(); }

URLConstant.URL_PROCESSINSTANCE_START : 是钉钉的url配置 所用到的配置如下:具体使用的url和参数,请查看

/** * 钉钉网关gettoken地址 */ public static final String URL_GET_TOKKEN = "https://oapi.dingtalk.com/gettoken"; /** *获取用户在企业内userId的接口URL */ public static final String URL_GET_USER_INFO = "https://oapi.dingtalk.com/user/getuserinfo"; /** *获取用户姓名的接口url */ public static final String URL_USER_GET = "https://oapi.dingtalk.com/user/get"; /** * 发起审批实例的接口url */ public static final String URL_PROCESSINSTANCE_START = "https://oapi.dingtalk.com/topapi/processinstance/create"; /** * 获取审批实例的接口url */ public static final String URL_PROCESSINSTANCE_GET = "https://oapi.dingtalk.com/topapi/processinstance/get"; /** * 发送企业通知消息的接口url */ public static final String MESSAGE_ASYNCSEND = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"; /** * 删除企业回调接口url */ public static final String DELETE_CALLBACK = "https://oapi.dingtalk.com/call_back/delete_call_back"; /** * 注册企业回调接口url */ public static final String REGISTER_CALLBACK = "https://oapi.dingtalk.com/call_back/register_call_back"; /** * 获取用户列表 */ public static final String GET_USER_LIST = "https://oapi.dingtalk.com/user/listbypage";

agentId:是微应用的ID

​processCode:钉钉审批模板的ID(你需要钉钉的企业管理员的权限,去创建一个模板,创建好以后去地址栏中找)

​ formComponentValues:这个就是审批的表单(这里后台中控件的Name属性要和你创建表单时的控件名称要一致)

​ originatorUserId:发起流程的用户(这里看看你们项目中的用户和钉钉的用户是怎么关联的,一般应该是电话吧)

deptId:发起人所在部门的ID

获取钉钉企业中的用户手机号:
public static OapiUserGetResponse getRequestUser(String phone,String appKey,String appSecret) throws RuntimeException, ApiException { StringBuffer buffer = new StringBuffer(); buffer.append("https://oapi.dingtalk.com/user/get_by_mobile"); buffer.append("?access_token="); buffer.append(AccessTokenUtil.getToken(appKey,appSecret)); buffer.append("&mobile="); buffer.append(phone); String line = sendGet(buffer.toString()); DingDingUserId dingDingUserId = new Gson().fromJson(line, DingDingUserId.class); DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/get"); OapiUserGetRequest request = new OapiUserGetRequest(); request.setUserid(dingDingUserId.getUserid()); request.setHttpMethod("GET"); OapiUserGetResponse response = client.execute(request, AccessTokenUtil.getToken(appKey,appSecret)); return response; }
发起钉钉所用到的token
public static String getToken(String appKey,String appSecret) throws RuntimeException { try { DefaultDingTalkClient client = new DefaultDingTalkClient(URL_GET_TOKKEN); OapiGettokenRequest request = new OapiGettokenRequest(); request.setAppkey(appKey); request.setAppsecret(appSecret); request.setHttpMethod("GET"); OapiGettokenResponse response = client.execute(request); String accessToken = response.getAccessToken(); logger.debug("发起钉钉所需要的accessToken:" + accessToken); return accessToken; } catch (ApiException e) { logger.error("getAccessToken failed", e); throw new RuntimeException(); } }
发送请求
public static String sendGet(String u) { String result = ""; try { URL url = new URL(u); //得到connection对象。 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //设置请求方式 connection.setRequestMethod("GET"); //连接 connection.connect(); //得到响应码 int responseCode = connection.getResponseCode(); if(responseCode == HttpURLConnection.HTTP_OK){ //得到响应流 InputStream inputStream = connection.getInputStream(); //获取响应 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = reader.readLine()) != null){ result = line; } reader.close(); //该干的都干完了,记得把连接断了 connection.disconnect(); } } catch (Exception e) { e.printStackTrace(); } return result; }
发起钉钉审批

钉钉审批官方流程 方式一 指定审批人 (1)调用接口时,传入approvers或者approvers_v2参数,指定审批人。其中,approvers_v2支持或签和会签。 (2)指定审批人方式,不支持审批模板的高级设置,比如手写签名、表单操作权限等均无法使用等。 方式二 复用审批后台设置的审批流程 (1)调用接口时,不传入approvers或者approvers_v2参数,会自动复用在审批管理后台预设的审批人。流程设置页面见下图。

(2)可在流程设计里设置审批人的或签会签等操作。

(3)复用审批后台设置的审批流程时,若接口填写cc_list、cc_position,参数不生效,会复用审批后台设置的抄送人员。

回调路径
public String getCallBackUrl(HttpServletRequest request){ StringBuffer buffer = new StringBuffer(); buffer.append("xxxx"); return buffer.toString(); }
注入回调
public static void RegisterCallBack(String callBackUrl,String appKey,String appSecret) throws RuntimeException { try { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/call_back/get_call_back"); OapiCallBackGetCallBackRequest request = new OapiCallBackGetCallBackRequest(); request.setHttpMethod("GET"); OapiCallBackGetCallBackResponse response = client.execute(request,AccessTokenUtil.getToken(appKey,appSecret)); if(!callBackUrl.equals(response.getUrl())){ client = new DefaultDingTalkClient(URLConstant.REGISTER_CALLBACK); OapiCallBackRegisterCallBackRequest registerRequest = new OapiCallBackRegisterCallBackRequest(); registerRequest.setUrl(callBackUrl); registerRequest.setAesKey(Constant.ENCODING_AES_KEY); registerRequest.setToken(Constant.TOKEN); registerRequest.setCallBackTag(Arrays.asList("bpms_instance_change","bpms_task_change")); OapiCallBackRegisterCallBackResponse registerResponse = client.execute(registerRequest,AccessTokenUtil.getToken(appKey,appSecret)); if (registerResponse.isSuccess()) { logger.debug("注册回调成功了!"); } } } catch (ApiException e) { e.printStackTrace(); } }

注意: 在正式环境中,不能保留删除回调那一部分代码,如果保留的话,会造成回调部分失效。发起A流程之后,回调地址是A的回调地址,之后再发起B流程,回调地址是B流程的,如果在发起B流程的时候删除所有回调,那么A流程回调就会失效,大家要注意。大家也可以在接口注册回调之后进行记录,再一次发起该流程时进行判断是否已经注册,避免重复注册(或者保留所有的注册接口,即删除删除回调部分的代码)。

内外网穿透工具
启动内网穿透

下载工具

启动工具,执行命令“./ding -config=./ding.cfg -subdomain=域名前缀 端口”,以mac为例: 2.启动完客户端后,你访问http://abcde.vaiwan.com/xxxxx都会映射到 http://127.0.0.1:8080/xxxxx。

注意:

1.你需要访问的域名是http://abcde.vaiwan.com/xxxxx 而不是http://abcde.vaiwan.com:8080/xxxxx

2.你启动命令的subdomain参数有可能被别人占用,尽量不要用常用字符,可以用自己公司名的拼音,例如:alibaba、dingding等。

3.可以在本地起个http-server服务,放置一个index.html文件,然后访问http://abcde.vaiwan.com/index.html测试一下。

启动成功后 不要关闭

遇到的坑

审批流程代码 可忽略

private static final String CHECK_URL = "check_url"; private static final String BPMS_TASK_CHANGE = "bpms_task_change"; private static final String BPMS_INSTANCE_CHANGE = "bpms_instance_change"; private static final String CALLBACK_RESPONSE_SUCCESS = "success"; @RequestMapping(value = "/ddCallBack", method = RequestMethod.POST) @ResponseBody public Map<String, String> dingCallBack(@RequestParam(value = "signature", required = false) String signature, @RequestParam(value = "timestamp", required = false) String timestamp, @RequestParam(value = "nonce", required = false) String nonce, @RequestBody(required = false) JSONObject json) { try { String corpId = systemConfigServiceImpl.dynamicGetSystemConfigValueByCode("corpid"); String appKey = systemConfigServiceImpl.dynamicGetSystemConfigValueByCode("appKey"); String appSecret = systemConfigServiceImpl.dynamicGetSystemConfigValueByCode("appSecret"); if(corpId == null || corpId.equals("") || appKey ==null || appKey.equals("") || appSecret == null || appSecret.equals("")){ logger.debug("回调接口[editContractCallBack]---corpId:"+corpId+",appKey:"+appKey+",appSecret:"+appSecret); return null; } DingTalkEncryptor dingTalkEncryptor = new DingTalkEncryptor(Constant.TOKEN, Constant.ENCODING_AES_KEY,corpId); String encryptMsg = json.getString("encrypt"); String plainText = dingTalkEncryptor.getDecryptMsg(signature, timestamp, nonce, encryptMsg); JSONObject obj = JSON.parseObject(plainText); String eventType = obj.getString("EventType"); String processInstanceId = obj.getString("processInstanceId"); InstanceDetail instanceDetail = instanceIsFinish(processInstanceId,appKey,appSecret); if(instanceDetail != null){ /** * 这是框架协议的回调 */ FrameTreaty queryFrametreaty = new FrameTreaty(); queryFrametreaty.setDdInstanceId(processInstanceId); List<FrameTreaty> frametreatyList = frameTreatyServiceImpl.query(queryFrametreaty); if(!frametreatyList.isEmpty()) { FrameTreaty frametreaty = frametreatyList.get(0); if((frametreatyList.get(0).getStatus() == FrameTreatyStatusEnum.BE_REVIEWED.getCode() || frametreatyList.get(0).getStatus() == FrameTreatyStatusEnum.UNDER_REVISION.getCode())){ return createFrameTreatyCallBack(instanceDetail,processInstanceId,eventType,obj,dingTalkEncryptor,frametreaty); } } Contract contract = new Contract(); contract.setDdInstanceId(processInstanceId); List<Contract> contractList = contractServiceImpl.query(contract); /** * 这是合同回调 */ if(!contractList.isEmpty()) { Contract record = contractList.get(0); if(record.getStatus() == ContractEnum.EDIT_AUDITING.getCode()){ return edit(instanceDetail,processInstanceId,eventType,obj,dingTalkEncryptor,record); } else if(record.getStatus() == ContractEnum.LEGAL_AUDITING.getCode()){ return createLegalContract(instanceDetail,processInstanceId,eventType,obj,dingTalkEncryptor,record); } else if(record.getStatus() == ContractEnum.LEGAL_PROCESS_INVALIDING.getCode()){ return cancelLegalContractCallBack(instanceDetail,processInstanceId,eventType,obj,dingTalkEncryptor,record); } else if(record.getStatus() == ContractEnum.ORDER_DISASSOCIATE.getCode()){ return cancelAssociatedOrderCallBack(instanceDetail,processInstanceId,eventType,obj,dingTalkEncryptor,record); } } InvoiceRecord invoiceRecord = new InvoiceRecord(); invoiceRecord.setDdInstanceId(processInstanceId); List<InvoiceRecord> recordList = invoiceRecordServiceImpl.query(invoiceRecord); //当框架协议和合同都为空的时候就走发票回调 if(!recordList.isEmpty()){ /** * 这是发票回调 */ return createInvoiceCallBack(instanceDetail,processInstanceId,eventType,obj,dingTalkEncryptor); } } return dingTalkEncryptor.getEncryptedMap(CALLBACK_RESPONSE_SUCCESS, System.currentTimeMillis(), Utils.getRandomStr(8)); } catch (Exception e) { logger.debug("回调接口异常:", e); return null; } } /** * 框架协议回调函数:通过就正常、不通过就是审核拒绝 * @param instanceDetail 流程详情 * @param processInstanceId 流程实例ID * @param eventType 事件类型 * @param obj 整个对象 * @param dingTalkEncryptor 返回给钉钉数据 * @param frametreaty 自己的对象 * @return * @throws DingTalkEncryptException */ private Map<String, String> createFrameTreatyCallBack(InstanceDetail instanceDetail, String processInstanceId, String eventType, JSONObject obj, DingTalkEncryptor dingTalkEncryptor, FrameTreaty frametreaty) throws DingTalkEncryptException { logger.debug("进入框架协议回调函数,操作事件:",eventType ); FrameTreaty instance = new FrameTreaty(); //拒绝(result)、同意(agree)、-- 这俩种情况对应BPMS_TASK_CHANGE 事件 结束保证节点(finish) if (BPMS_TASK_CHANGE.equals(eventType)) { //COMPLETED : 代表结束 if("COMPLETED".equals(instanceDetail.getProcess_instance().getStatus())) { //流程同意 if (obj.containsKey("result") && obj.getString("result").equals("agree") && obj.containsKey("type") && obj.getString("type").equals("finish")) { instance.setStatus(FrameTreatyStatusEnum.NORMAL.getCode());//同意状态改为正常 instance.setFrameTreatyId(frametreaty.getFrameTreatyId()); instance.setDdInstanceId(""); instance.setComment(""); //进行更新 boolean b = frameTreatyServiceImpl.updateFrameTreatyInfoUntilCallBack(instance); logger.debug("进入框架协议回调函数,同意操作,更新是否成功",String.valueOf(b)); } //将数据更新 } //如果流程拒绝就将数据状态改为审核拒绝 if(obj.containsKey("result") && obj.getString("result").equals("refuse") && obj.containsKey("type") && obj.getString("type").equals("finish")){ instance.setFrameTreatyId(frametreaty.getFrameTreatyId()); instance.setStatus(FrameTreatyStatusEnum.AUDIT_REJECTION.getCode());//拒绝状态改为审核拒绝 instance.setDdInstanceId(""); instance.setComment(""); //进行更新 boolean b = frameTreatyServiceImpl.updateFrameTreatyInfoUntilCallBack(instance); logger.debug("进入框架协议回调函数,拒绝操作,更新是否成功",String.valueOf(b)); } } //撤销(terminate)-- 这俩种情况对应 BPMS_TASK_CHANGE 事件 结束保证节点(finish) if(BPMS_INSTANCE_CHANGE.equals(eventType)){ if(obj.containsKey("type") && obj.getString("type").equals("terminate")){ instance.setFrameTreatyId(frametreaty.getFrameTreatyId()); //如果流程撤销就将数据还原到以前状态 instance = new Gson().fromJson(frametreaty.getComment(),FrameTreaty.class); //进行更新 boolean b = frameTreatyServiceImpl.updateFrameTreatyInfoUntilCallBack(instance); logger.debug("进入框架协议回调函数撤回绝操作,更新是否成功",String.valueOf(b)); } } return dingTalkEncryptor.getEncryptedMap(CALLBACK_RESPONSE_SUCCESS, System.currentTimeMillis(), Utils.getRandomStr(8)); } public Map<String, String> edit(InstanceDetail instanceDetail,String processInstanceId,String eventType,JSONObject obj,DingTalkEncryptor dingTalkEncryptor,Contract record) throws DingTalkEncryptException { ApprovalProcessLog log = new ApprovalProcessLog(); log.setDdInstanceId(processInstanceId); log.setType(ApprovalProcessLogTypeEnum.EDIT_AUDIT.getCode()); List<ApprovalProcessLog> logList = approvalProcessLogServiceImpl.query(log); Contract instance = new Contract(); ApprovalProcessLog approvalProcessLog = new ApprovalProcessLog(); if (BPMS_TASK_CHANGE.equals(eventType)) { if("COMPLETED".equals(instanceDetail.getProcess_instance().getStatus())) { if (obj.containsKey("result") && obj.getString("result").equals("agree") && obj.containsKey("type") && obj.getString("type").equals("finish")) { instance.setDdInstanceId(""); instance.setId(record.getId()); instance.setBackInfo(""); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.EDIT_AUDIT.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_PASS.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if (!logList.isEmpty()) { approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); } else { approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.EDIT_CONTRACT.getCode(), approvalProcessLog,null); } } if(obj.containsKey("result") && obj.getString("result").equals("refuse") && obj.containsKey("type") && obj.getString("type").equals("finish")){ instance = new Gson().fromJson(record.getBackInfo(),Contract.class); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.EDIT_AUDIT.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_CANCEL.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.EDIT_CONTRACT.getCode(),approvalProcessLog,null); } } if(BPMS_INSTANCE_CHANGE.equals(eventType)){ if(obj.containsKey("type") && obj.getString("type").equals("terminate")){ instance = new Gson().fromJson(record.getBackInfo(),Contract.class); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.EDIT_AUDIT.getCode()); approvalProcessLog.setResult(AuditResultEnum.BACKOUT.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.EDIT_CONTRACT.getCode(),approvalProcessLog,null); } } return dingTalkEncryptor.getEncryptedMap(CALLBACK_RESPONSE_SUCCESS, System.currentTimeMillis(), Utils.getRandomStr(8)); } public Map<String, String> createLegalContract(InstanceDetail instanceDetail,String processInstanceId,String eventType,JSONObject obj,DingTalkEncryptor dingTalkEncryptor,Contract record) throws DingTalkEncryptException { ApprovalProcessLog log = new ApprovalProcessLog(); log.setDdInstanceId(processInstanceId); log.setType(ApprovalProcessLogTypeEnum.LEGAL_AUDIT.getCode()); List<ApprovalProcessLog> logList = approvalProcessLogServiceImpl.query(log); Contract instance = new Contract(); ApprovalProcessLog approvalProcessLog = new ApprovalProcessLog(); if (BPMS_TASK_CHANGE.equals(eventType)) { if("COMPLETED".equals(instanceDetail.getProcess_instance().getStatus())) { if (obj.containsKey("result") && obj.getString("result").equals("agree") && obj.containsKey("type") && obj.getString("type").equals("finish")) { instance.setDdInstanceId(""); instance.setBackInfo(""); instance.setId(record.getId()); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.LEGAL_AUDIT.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_PASS.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if (!logList.isEmpty()) { approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); } else { approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.CREATE_LEGAL_CONTRACT.getCode(), approvalProcessLog,null); } } if(obj.containsKey("result") && obj.getString("result").equals("refuse") && obj.containsKey("type") && obj.getString("type").equals("finish")){ instance = new Gson().fromJson(record.getBackInfo(),Contract.class); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.LEGAL_AUDIT.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_CANCEL.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.CREATE_LEGAL_CONTRACT.getCode(),approvalProcessLog,null); } } if(BPMS_INSTANCE_CHANGE.equals(eventType)) { if (obj.containsKey("type") && obj.getString("type").equals("terminate")) { instance = new Gson().fromJson(record.getBackInfo(),Contract.class); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.LEGAL_AUDIT.getCode()); approvalProcessLog.setResult(AuditResultEnum.BACKOUT.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.CREATE_LEGAL_CONTRACT.getCode(),approvalProcessLog,null); } } return dingTalkEncryptor.getEncryptedMap(CALLBACK_RESPONSE_SUCCESS, System.currentTimeMillis(), Utils.getRandomStr(8)); } public Map<String, String> cancelLegalContractCallBack(InstanceDetail instanceDetail,String processInstanceId,String eventType,JSONObject obj,DingTalkEncryptor dingTalkEncryptor,Contract record) throws DingTalkEncryptException { ApprovalProcessLog log = new ApprovalProcessLog(); log.setDdInstanceId(processInstanceId); log.setType(ApprovalProcessLogTypeEnum.LEGAL_INSTANCE_INVOICING.getCode()); List<ApprovalProcessLog> logList = approvalProcessLogServiceImpl.query(log); Contract instance = new Contract(); ApprovalProcessLog approvalProcessLog = new ApprovalProcessLog(); if (BPMS_TASK_CHANGE.equals(eventType)) { if("COMPLETED".equals(instanceDetail.getProcess_instance().getStatus())) { if (obj.containsKey("result") && obj.getString("result").equals("agree") && obj.containsKey("type") && obj.getString("type").equals("finish")) { LegalContract legalContract = new LegalContract(); legalContract.setBackInfo(""); legalContract.setId(record.getLegalContractId()); instance.setDdInstanceId(""); instance.setBackInfo(""); instance.setId(record.getId()); instance.setLegalContractId(0); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.LEGAL_INSTANCE_INVOICING.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_PASS.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if (!logList.isEmpty()) { approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); } else { approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.CANCEL_LEGAL_CONTRACT.getCode(), approvalProcessLog,legalContract); } } if(obj.containsKey("result") && obj.getString("result").equals("refuse") && obj.containsKey("type") && obj.getString("type").equals("finish")){ LegalContract legalContract = legalContractServiceImpl.queryLegalContractById(record.getLegalContractId()); legalContract = new Gson().fromJson(legalContract.getBackInfo(),LegalContract.class); legalContract.setBackInfo(""); instance = new Gson().fromJson(record.getBackInfo(),Contract.class); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.LEGAL_INSTANCE_INVOICING.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_CANCEL.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.CANCEL_LEGAL_CONTRACT.getCode(),approvalProcessLog,legalContract); } } if(BPMS_INSTANCE_CHANGE.equals(eventType)) { if (obj.containsKey("type") && obj.getString("type").equals("terminate")) { LegalContract legalContract = legalContractServiceImpl.queryLegalContractById(record.getLegalContractId()); legalContract = new Gson().fromJson(legalContract.getBackInfo(),LegalContract.class); legalContract.setBackInfo(""); instance = new Gson().fromJson(record.getBackInfo(),Contract.class); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.LEGAL_INSTANCE_INVOICING.getCode()); approvalProcessLog.setResult(AuditResultEnum.BACKOUT.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.CANCEL_LEGAL_CONTRACT.getCode(),approvalProcessLog,legalContract); } } return dingTalkEncryptor.getEncryptedMap(CALLBACK_RESPONSE_SUCCESS, System.currentTimeMillis(), Utils.getRandomStr(8)); } public Map<String, String> cancelAssociatedOrderCallBack(InstanceDetail instanceDetail,String processInstanceId,String eventType,JSONObject obj,DingTalkEncryptor dingTalkEncryptor,Contract record) throws DingTalkEncryptException { ApprovalProcessLog log = new ApprovalProcessLog(); log.setDdInstanceId(processInstanceId); log.setType(ApprovalProcessLogTypeEnum.ORDER_DISASSOCIATE.getCode()); List<ApprovalProcessLog> logList = approvalProcessLogServiceImpl.query(log); Contract instance = new Contract(); ApprovalProcessLog approvalProcessLog = new ApprovalProcessLog(); if (BPMS_TASK_CHANGE.equals(eventType)) { if("COMPLETED".equals(instanceDetail.getProcess_instance().getStatus())) { if (obj.containsKey("result") && obj.getString("result").equals("agree") && obj.containsKey("type") && obj.getString("type").equals("finish")) { instance.setDdInstanceId(""); instance.setBackInfo(""); instance.setCancelAssociatedOrderArray(""); instance.setStatus(ContractEnum.NORMAL.getCode()); instance.setId(record.getId()); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.ORDER_DISASSOCIATE.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_PASS.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if (!logList.isEmpty()) { approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); } else { approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.CANCEL_ASSOCIATE_ORDER.getCode(), approvalProcessLog,null); } } if(obj.containsKey("result") && obj.getString("result").equals("refuse") && obj.containsKey("type") && obj.getString("type").equals("finish")){ instance = new Gson().fromJson(record.getBackInfo(),Contract.class); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.ORDER_DISASSOCIATE.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_CANCEL.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.CANCEL_ASSOCIATE_ORDER.getCode(),approvalProcessLog,null); } } if(BPMS_INSTANCE_CHANGE.equals(eventType)) { if (obj.containsKey("type") && obj.getString("type").equals("terminate")) { instance = new Gson().fromJson(record.getBackInfo(),Contract.class); approvalProcessLog.setType(ApprovalProcessLogTypeEnum.ORDER_DISASSOCIATE.getCode()); approvalProcessLog.setResult(AuditResultEnum.BACKOUT.getCode()); approvalProcessLog.setContractId(record.getId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); boolean b = contractServiceImpl.updateContractInfoUntilCallBack(instance, ServiceTypeEnum.CANCEL_ASSOCIATE_ORDER.getCode(),approvalProcessLog,null); } } return dingTalkEncryptor.getEncryptedMap(CALLBACK_RESPONSE_SUCCESS, System.currentTimeMillis(), Utils.getRandomStr(8)); } public Map<String, String> createInvoiceCallBack(InstanceDetail instanceDetail,String processInstanceId,String eventType,JSONObject obj,DingTalkEncryptor dingTalkEncryptor) throws DingTalkEncryptException { InvoiceRecord invoiceRecord = new InvoiceRecord(); invoiceRecord.setDdInstanceId(processInstanceId); List<InvoiceRecord> recordList = invoiceRecordServiceImpl.query(invoiceRecord); ApprovalProcessLog log = new ApprovalProcessLog(); log.setDdInstanceId(processInstanceId); log.setType(ApprovalProcessLogTypeEnum.CREATE_INVOICE_RECORD.getCode()); List<ApprovalProcessLog> logList = approvalProcessLogServiceImpl.query(log); ApprovalProcessLog approvalProcessLog = new ApprovalProcessLog(); InvoiceRecord record = new InvoiceRecord(); if (BPMS_TASK_CHANGE.equals(eventType)) { if("COMPLETED".equals(instanceDetail.getProcess_instance().getStatus())) { if (obj.containsKey("result") && obj.getString("result").equals("agree") && obj.containsKey("type") && obj.getString("type").equals("finish")) { approvalProcessLog.setType(ApprovalProcessLogTypeEnum.CREATE_INVOICE_RECORD.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_PASS.getCode()); approvalProcessLog.setContractId(recordList.get(0).getContractId()); approvalProcessLog.setCreateTime(new Date()); if (!logList.isEmpty()) { approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); } else { approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); record.setDdInstanceId(""); record.setStatus(InvoiceStatusEnum.AUDIT_PASS.getCode()); record.setId(recordList.get(0).getId()); record.setSuccessTime(new Date()); boolean b = invoiceRecordServiceImpl.updateInvoiceStatusUntilCallBack(record, approvalProcessLog); } } if(obj.containsKey("result") && obj.getString("result").equals("refuse") && obj.containsKey("type") && obj.getString("type").equals("finish")){ approvalProcessLog.setType(ApprovalProcessLogTypeEnum.CREATE_INVOICE_RECORD.getCode()); approvalProcessLog.setResult(AuditResultEnum.AUDIT_CANCEL.getCode()); approvalProcessLog.setContractId(recordList.get(0).getContractId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); record.setDdInstanceId(""); record.setStatus(InvoiceStatusEnum.AUDIT_REFUSE.getCode()); record.setId(recordList.get(0).getId()); boolean b = invoiceRecordServiceImpl.updateInvoiceStatusUntilCallBack(record, approvalProcessLog); } } if(BPMS_INSTANCE_CHANGE.equals(eventType)) { if (obj.containsKey("type") && obj.getString("type").equals("terminate")) { approvalProcessLog.setType(ApprovalProcessLogTypeEnum.CREATE_INVOICE_RECORD.getCode()); approvalProcessLog.setResult(AuditResultEnum.BACKOUT.getCode()); approvalProcessLog.setContractId(recordList.get(0).getContractId()); approvalProcessLog.setCreateTime(new Date()); if(!logList.isEmpty()){ approvalProcessLog.setCreateUser(logList.get(0).getCreateUser()); }else{ approvalProcessLog.setCreateUser("发起钉钉记录为空!"); } approvalProcessLog.setDdInstanceId(processInstanceId); record.setDdInstanceId(""); record.setStatus(InvoiceStatusEnum.AUDIT_BACK.getCode()); record.setId(recordList.get(0).getId()); boolean b = invoiceRecordServiceImpl.updateInvoiceStatusUntilCallBack(record, approvalProcessLog); } } return dingTalkEncryptor.getEncryptedMap(CALLBACK_RESPONSE_SUCCESS, System.currentTimeMillis(), Utils.getRandomStr(8)); } public static InstanceDetail instanceIsFinish(String ddInstanceId,String appKey,String appSecret) throws ApiException { DingTalkClient client = new DefaultDingTalkClient(URLConstant.URL_PROCESSINSTANCE_GET); OapiProcessinstanceGetRequest request = new OapiProcessinstanceGetRequest(); request.setProcessInstanceId(ddInstanceId); OapiProcessinstanceGetResponse response = client.execute(request, AccessTokenUtil.getToken(appKey,appSecret)); System.out.println(response.getBody()); InstanceDetail instanceDetail = new Gson().fromJson(response.getBody(),InstanceDetail.class); return instanceDetail; } }

bpms_task_change:如果你发起的审批通过和拒绝,返回的事件类型是这个。

​bpms_instance_change:如果你发起的审批撤销了,返回的事件类型是这个。

​ 我们如果有多个审批人,只要通过一个,他都会进回调,我们这里只关心结果,所以前边不管通过了几个,都不能去操作数据库,更改审批的状态。可是它这个接口我找了半天,返回值中没法去判断是不是最终的审批用户,怎么办呢?先去通过钉钉实例的id获取这个实例的详情,详情里边有状态,通过详情中的状态才能判断这个流程有没有结束,再去操作数据库。

最新回复(0)