package com.malk.shantai.service.impl; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.malk.server.common.McR; import com.malk.server.dingtalk.DDR_New; import com.malk.shantai.config.StEkbConfig; import com.malk.shantai.entity.Shantai; import com.malk.shantai.mapper.ShantaiMapper; import com.malk.shantai.service.StDingProcService; import com.malk.service.dingtalk.DDClient; import com.malk.service.dingtalk.DDClient_Workflow; import com.malk.utils.UtilHttp; import com.malk.utils.UtilMap; import com.malk.utils.UtilToken; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.*; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.*; @Service @Slf4j public class StDingProcServiceImpl extends ServiceImpl implements StDingProcService { @Autowired private DDClient_Workflow ddClient_workflow; @Autowired private DDClient ddClient; @Autowired private StEkbConfig stEkbConfig; @Autowired private ShantaiMapper shantaiMapper; @Value("${download.path}") private String filePath; @Value("${dingtalk.operatorUserId}") private String operatorUserId; @Value("${dingtalk.operatorUnionId}") private String operatorUnionId; @Value("${ekb.operatorStaffId}") private String operatorStaffId; //法人实体 private static Map CORPORATION = new HashMap<>(); //任务状态 private static Map STATUS = new HashMap<>(); static{ CORPORATION.put("杉泰健康管理(上海)有限公司","ID01tX0xhMwgbR"); CORPORATION.put("上海广慈太保互联网医院有限公司","LY4cw6EvcNZQ00"); CORPORATION.put("苏州杉泰大药房有限公司","ID_3IzESoE1lxM"); CORPORATION.put("成都杉泰互联网医院有限公司","zsIcw6E-tcIM00"); CORPORATION.put("海南杉泰健康科技有限公司","kcwcw6F3esco00"); CORPORATION.put("上海杉泰健康科技有限公司","SdEcw6EvcN9U00"); STATUS.put("APPROVING","待审批"); STATUS.put("PAYING","待支付"); STATUS.put("PROCESSING","处理中(支付中)"); STATUS.put("PROCESSED","已处理(审批完成、已支付)"); STATUS.put("CANCELED","待办被取消"); STATUS.put("SENDING","待寄送"); STATUS.put("RECEIVING","待收单"); STATUS.put("RECEIVING_EXCEP","收单异常"); STATUS.put("REQUISITION_PAID","临时状态(申请单支付时消息发送)"); STATUS.put("DRAFT","草稿"); STATUS.put("PENDING","提交中"); STATUS.put("REJECTED","已驳回"); STATUS.put("PAID","已支付/审批完成"); STATUS.put("ARCHIVED","归档"); } @Override public void fkdSync(String procInstId) { Map map=ddClient_workflow.getProcessInstanceId(ddClient.getAccessToken(),procInstId); log.info("map:{}",map); List tasks = (List) map.get("tasks"); boolean hasRunning = false; for (Map task : tasks) { if ("RUNNING".equals(task.get("status").toString())){ hasRunning = true; //判断是否为审批流程第一个出纳节点是否完成(第二个出纳节点进行中) if (!"55d3_4702".equals(task.get("activityId").toString())){ log.info("当前节点为:activityId:{},activityName:{},不进行同步",task.get("activityId"),task.get("activityName")); return; }else { log.info("当前节点为:activityId:{},activityName:{},进行同步",task.get("activityId"),task.get("activityName")); break; } } } //若没有正在运行的审批流程,则不进行同步 if (!hasRunning){ log.info("没有正在运行的审批流程,不进行同步"); return; } Map rule=new HashMap(); rule.put("DDSelectField_8UJMKRMLWYK0","是否推送到易快报");// 是否推送到易快报 // rule.put("TextField-K11U6U5Q","付款事由");// 标题/付款事由 rule.put("TextField_18XU5XCGC4RK0","付款摘要");// 标题/付款摘要 rule.put("RecipientAccountField-K11U6U5P","收款信息");// 收款信息 rule.put("MoneyField_FMP7OAX3TZ40","付款金额");// 付款金额 rule.put("TextareaField_15PEUHBWFDDS0","备注");// 备注 rule.put("DDMultiSelectField_17IA7RJQYGWW0","付款公司");// 付款公司 Map data=getData(map,rule); if( Objects.isNull(data.get("是否推送到易快报")) || data.get("是否推送到易快报").toString().equals("否")){ return; } data.put("户名", UtilMap.getMap(data,"收款信息").get("name"));// 户名 data.put("银行",UtilMap.getMap(data,"收款信息").get("instName"));// 银行 data.put("支行信息",UtilMap.getMap(data,"收款信息").get("instBranchName"));// 支行信息 data.put("账号",UtilMap.getMap(data,"收款信息").get("cardNo"));// 账号 data.put("省份",UtilMap.getMap(data,"收款信息").get("instProvince"));// 省份 data.put("城市",UtilMap.getMap(data,"收款信息").get("instCity"));// 城市 log.info("data:{}",JSONObject.toJSONString(data)); //获取发起人userId String userId = map.get("originatorUserId").toString(); String staffId = operatorStaffId;// 曹艳杰 //查询易快报中发起人是否存在 /*Map param3 = new HashMap<>(); param3.put("accessToken",getToken()); Map body3 = new HashMap<>(); body3.put("type","USERID"); body3.put("conditionIds",Arrays.asList(userId)); Map user = (Map) JSONObject.parseObject(UtilHttp.doPost(stEkbConfig.getPreUrl() + "/api/openapi/v1/staffs/getStaffIds", null, param3, body3)).getJSONArray("items").get(0); if (Objects.isNull(user)){ log.error("易快报中发起人不存在"); staffId = "pQccdcNGsM3U00:16278700718435315";// 李溯 }else { staffId = "pQccdcNGsM3U00:16278700718435315";// 李溯 staffId = user.get("id").toString(); }*/ //查询易快报中收款账户是否存在 Map result = (Map) JSONObject.parseObject(UtilHttp.doGet(stEkbConfig.getPreUrl() + "/api/openapi/v2/payeeInfos", null, UtilMap.map("accessToken, start, count, names, cardNos, ids, active, orderBy, orderByType", getToken(), 0, 100, data.get("户名"), data.get("账号"), null, true, "updateTime", "desc"))) ; System.out.println(result); String payeeId = ""; List items = (List) result.get("items"); //若不存在则新增收款账户 if (Objects.isNull(items) || items.isEmpty()){ Map body = new HashMap<>(); Map visibility = new HashMap(); visibility.put("fullVisible",true); body.put("sort","BANK"); body.put("type","PUBLIC"); body.put("owner","CORPORATION"); body.put("name",data.get("户名")); body.put("cardNo",data.get("账号")); body.put("bank",data.get("银行")); body.put("branch",data.get("支行信息")); body.put("province",data.get("省份")); body.put("city",data.get("城市")); body.put("visibility",visibility); Map param = new HashMap<>(); param.put("accessToken",getToken()); payeeId = JSONObject.parseObject(UtilHttp.doPost(stEkbConfig.getPreUrl() + "/api/openapi/v2.1/payeeInfos", null, param, body)).getString("id"); //再次获取新增后的收款账户 /* account = JSONObject.parseObject(UtilHttp.doGet(stEkbConfig.getPreUrl() + "/api/openapi/v2/payeeInfos", null, UtilMap.map("accessToken, start, count, names, cardNos, ids, active", getToken(), 0, 100, null, null, id, true))) ;*/ }else { payeeId = items.get(0).get("id").toString(); } //根据模板ID获取模板信息 String id="ID01yVMv53gDSL";// "对外付款单"模板id Map template = (Map) JSONObject.parseObject(HttpUtil.get(stEkbConfig.getPreUrl().concat("/api/openapi/v2/specifications/byIds/[").concat(id).concat("]"), UtilMap.map("accessToken, type, start, count", getToken(), "payment", 0, 10))).getJSONArray("items").get(0); String specificationId = template.get("id").toString(); //新增单据 Map param = new HashMap<>(); param.put("accessToken",getToken()); param.put("isCommit",true); param.put("isUpdate",true); Map body = new HashMap<>(); Map form = new HashMap<>(); //金额 Map payMoney = new HashMap<>(); payMoney.put("standard",data.get("付款金额")); payMoney.put("standardStrCode","CNY"); payMoney.put("standardNumCode","156"); payMoney.put("standardSymbol","¥"); payMoney.put("standardUnit","元"); payMoney.put("standardScale",2); form.put("title",data.get("付款摘要")); //单据标题 form.put("submitterId",staffId); //提交人ID form.put("description",data.get("备注")); //描述 form.put("specificationId",specificationId); //单据模板id form.put("payMoney",payMoney); //付款金额 form.put("payeeId",payeeId); form.put("u_订单信息",procInstId); if (CORPORATION.keySet().contains(data.get("付款公司"))){ form.put("法人实体",CORPORATION.get(data.get("付款公司"))); //法人实体 } body.put("form",form); Map document = JSONObject.parseObject(UtilHttp.doPost(stEkbConfig.getPreUrl() + ("/api/openapi/v2.2/flow/data"), null, param, body)); Map flow = (Map) document.get("flow"); String flowId = flow.get("id").toString(); Shantai shantai = new Shantai(); shantai.setProcInstId(procInstId); shantai.setState("3"); shantai.setUserId(userId); shantai.setFlowId(flowId); shantaiMapper.insert(shantai); log.info("新增单据成功:{}",document); } @Override public McR commentSync(Map map,String flowId){ try{ String procInstId = map.get("procInstId").toString(); //查询表中是否存在同步评论记录 LambdaQueryWrapper shantaiLambdaQueryWrapper = new LambdaQueryWrapper<>(); shantaiLambdaQueryWrapper.eq(Shantai::getProcInstId,procInstId) .eq(Shantai::getValidFlag,"1"); Shantai shantai = shantaiMapper.selectOne(shantaiLambdaQueryWrapper); //获取提交人 String userId = ""; if (Objects.nonNull(shantai)){ if (shantai.getState().equals("1")){ log.info("该单据Id:{}已同步过水单,本次不进行同步",flowId); return McR.success(); } userId = shantai.getUserId(); } if (Objects.isNull(userId)){ userId = map.get("userId").toString(); } //上传钉盘目前设置为管理员 String unionId = operatorUnionId; /*DDR_New ddrNew = (DDR_New) UtilHttp.doPost("https://oapi.dingtalk.com/topapi/v2/user/get", null, ddClient.initTokenParams(), UtilMap.map("userid", userId), DDR_New.class); Map result = (Map) ddrNew.getResult(); if (Objects.nonNull(result)){ unionId = result.get("unionid").toString(); }else { unionId = operatorUnionId;//曹艳杰 userId = operatorUserId;//曹艳杰 }*/ //获取附件上传到钉盘 List paths = (List) map.get("paths"); List dentries = new ArrayList<>(); if (Objects.nonNull(paths) && !paths.isEmpty()){ for (String path : paths) { File file = new File(path); try{ //上传文件至钉盘 Map dentry = upload(file,unionId); dentries.add(dentry); }catch (IOException e){ e.printStackTrace(); log.info("上传文件至钉盘失败:{}",e.getMessage()); return McR.errorUnknown("上传文件至钉盘失败"); } } } String state = map.get("state").toString(); if (Objects.nonNull(shantai) && shantai.getState().equals("2") && dentries.isEmpty()){ log.info("该单据Id:{}本次无水单上传,不进行同步",flowId); return McR.success(); } //新增评论 // comment(dentries,state,userId,procInstId); //20241018 评论人统一改为曹艳杰 comment(dentries,state,operatorUserId,procInstId); if (Objects.isNull(shantai)){ //更新表中同步状态 shantai = new Shantai(); if (dentries.isEmpty()){ shantai.setState("2"); }else { shantai.setState("1"); } shantai.setFlowId(flowId); shantai.setProcInstId(procInstId); shantai.setUserId(userId); shantaiMapper.insert(shantai); }else { //更新表中同步状态 if (dentries.isEmpty()){ shantai.setState("2"); shantai.setFlowId(flowId); }else { shantai.setState("1"); shantai.setFlowId(flowId); } //更新评论状态 shantaiMapper.updateById(shantai); } }catch (Exception e){ log.info("单据Id:{}同步失败,原因:{}",flowId,e.getMessage()); return McR.errorUnknown("同步评论失败"); } return McR.success(); } @Override public Map getFlowInfo(String flowId) { //根据单据id获取单据信息 Map param = new HashMap<>(); param.put("accessToken",getToken()); param.put("flowId",flowId); Map flow = JSONObject.parseObject(UtilHttp.doGet("https://dd2.hosecloud.com/api/openapi/v1.1/flowDetails", null, param)).getJSONObject("value"); Map form = (Map) flow.get("form"); String procInstId = form.get("u_订单信息").toString(); String submitterId = form.get("submitterId").toString(); String userId = submitterId.substring(submitterId.indexOf(':') + 1); String state = flow.get("state").toString(); log.info("流程状态:{}",state.toUpperCase()); if (STATUS.keySet().contains(state.toUpperCase())){ state = STATUS.get(state.toUpperCase()); } //根据单据id获取单据附件信息 Map param2 = new HashMap<>(); param2.put("accessToken",getToken()); Map body2 = new HashMap<>(); String[] flowIds = {flowId}; body2.put("flowIds",flowIds); JSONArray items = JSONObject.parseObject(UtilHttp.doPost("https://dd2.hosecloud.com/api/openapi/v1/flowDetails/attachment", null, param2, body2)).getJSONArray("items"); Map item = (Map) items.get(0); List attachmentList = (List) item.get("attachmentList"); List paths = new ArrayList<>(); if (!attachmentList.isEmpty()){ for (Map attachment : attachmentList) { if (attachment.get("type").toString().equals("flow.receipt")){ List receiptUrls = (List) attachment.get("receiptUrls"); for (Map receiptUrl : receiptUrls) { //附件下载到本地 String url = receiptUrl.get("url").toString(); String fileName = receiptUrl.get("key").toString(); String path = filePath + fileName; downloadNet(url, path); //添加到路径列表 paths.add(path); } } } } Map result = new HashMap(); result.put("state",state); result.put("procInstId",procInstId); result.put("paths",paths); result.put("userId",userId); return result; } // 下载网络文件 public void downloadNet(String netUrl, String path){ int bytesum = 0; int byteread = 0; try{ URL url = new URL(netUrl); URLConnection conn = url.openConnection(); InputStream inStream = conn.getInputStream(); FileOutputStream fs = new FileOutputStream(path); byte[] buffer = new byte[1204]; while ((byteread = inStream.read(buffer)) != -1) { bytesum += byteread; fs.write(buffer, 0, byteread); } } catch (MalformedURLException e){ e.printStackTrace(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } @Override public void commentSyncAll() { //获取所有评论未同步水单的单据列表 LambdaQueryWrapper shantaiLambdaQueryWrapper = new LambdaQueryWrapper<>(); shantaiLambdaQueryWrapper.ne(Shantai::getState,"1") .eq(Shantai::getValidFlag,"1"); List shantaiList = shantaiMapper.selectList(shantaiLambdaQueryWrapper); for (Shantai shantai : shantaiList) { String flowId = shantai.getFlowId(); log.info("开始定时同步评论水单:{}",flowId); Map flowInfo = getFlowInfo(flowId); commentSync(flowInfo,flowId); } } private void comment(List dentries, String state, String userId, String procInstId) { Map body = new HashMap<>(); Map fileMap = new HashMap<>(); List attachments= new ArrayList<>(); for (Map dentry : dentries) { Map attachment = new HashMap<>(); attachment.put("spaceId",dentry.get("spaceId").toString()); attachment.put("fileSize",dentry.get("size").toString()); attachment.put("fileId",dentry.get("id").toString()); attachment.put("fileName",dentry.get("name").toString()); attachment.put("fileType",dentry.get("type").toString()); attachments.add(attachment); } fileMap.put("photos",null); fileMap.put("attachments",attachments); body.put("processInstanceId",procInstId); body.put("text","付款状态:" + state); body.put("commentUserId",userId); body.put("file",fileMap); UtilHttp.doPost("https://api.dingtalk.com/v1.0/workflow/processInstances/comments",ddClient.initTokenHeader(),null,body); } private Map upload(File file,String unionId) throws IOException { //获取文件上传信息 // String parentDentryUuid = "ZQYprEoWonmdnzdOFpklzk1a81waOeDk";// poc目录 api测试上传/附件 String parentDentryUuid = "YQBnd5ExVEowejBQtZ1v6wO28yeZqMmz";// 杉泰目录 /技术文档/易快报银企直连 Map param1 = new HashMap<>(); param1.put("unionId",unionId); Map body1 = new HashMap<>(); body1.put("protocol","HEADER_SIGNATURE"); DDR_New ddrNew = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v2.0/storage/spaces/files/" + parentDentryUuid + "/uploadInfos/query", ddClient.initTokenHeader(), param1, body1, DDR_New.class); String uploadKey = ddrNew.getUploadKey(); Map headerSignatureInfo = ddrNew.getHeaderSignatureInfo(); Map headers = (Map) headerSignatureInfo.get("headers"); String resourceUrl = ((List) headerSignatureInfo.get("resourceUrls")).get(0); //使用OSS的header加签方式上传文件 URL url = new URL(resourceUrl); HttpURLConnection connection = (HttpURLConnection)url.openConnection(); if (headers != null) { for (Map.Entry entry : headers.entrySet()) { connection.setRequestProperty(entry.getKey(), entry.getValue()); } } connection.setDoOutput(true); connection.setRequestMethod("PUT"); connection.setUseCaches(false); connection.setReadTimeout(10000); connection.setConnectTimeout(10000); connection.connect(); OutputStream out = connection.getOutputStream(); InputStream is = new FileInputStream(file); byte[] b =new byte[1024]; int temp; while ((temp=is.read(b))!=-1){ out.write(b,0,temp); } out.flush(); out.close(); int responseCode = connection.getResponseCode(); connection.disconnect(); if (responseCode == 200) { System.out.println("上传成功"); } else { System.out.println("上传失败"); } //提交文件 Map param2 = new HashMap<>(); param2.put("unionId",unionId); Map body2 = new HashMap<>(); body2.put("uploadKey",uploadKey); body2.put("name",file.getName()); Map option = new HashMap<>(); option.put("conflictStrategy","OVERWRITE");//文件名称冲突策略:覆盖 body2.put("option",option); DDR_New ddrNew2 = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v2.0/storage/spaces/files/" + parentDentryUuid + "/commit", ddClient.initTokenHeader(), param2, body2, DDR_New.class); return ddrNew2.getDentry(); } public Map getData(Map instance,Map rule){ Map resultMap=new HashMap(); List list=(List) instance.get("formComponentValues"); for (Map map:list) { if(rule.containsKey(String.valueOf(map.get("id")))){ String componentType=String.valueOf(map.get("componentType")); if(componentType.equals("RecipientAccountField")){ resultMap.put(rule.get(String.valueOf(map.get("id"))),JSONObject.parseObject(String.valueOf(map.get("extValue")))); }else if (componentType.equals("DDMultiSelectField")){ resultMap.put(rule.get(String.valueOf(map.get("id"))),JSONObject.parseArray(String.valueOf(map.get("value"))).get(0).toString()); }else{ resultMap.put(rule.get(String.valueOf(map.get("id"))),map.get("value")); } } } return resultMap; } private String getToken(){ String accessToken = UtilToken.get("invalid-token-ykb"); if (StringUtils.isNotBlank(accessToken)) return accessToken; Map result = JSONObject.parseObject(HttpUtil.post(stEkbConfig.getPreUrl().concat("/api/openapi/v1/auth/getAccessToken"),JSONObject.toJSONString(UtilMap.map("appKey, appSecurity",stEkbConfig.getAppKey(),stEkbConfig.getAppSecurity())))); String token = ((Map) result.get("value")).get("accessToken").toString(); long expireTime = (long) ((Map) result.get("value")).get("expireTime"); log.info("响应token, {}", token); // token失效自动重置: 重新调用会重置过期时间 UtilToken.put("invalid-token-ykb", token, 2 * 3600 * 1000L); return token; } }