Create_by_fileOSFService.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. package com.kingdee.eas.custom.esign.osf;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.google.common.collect.Lists;
  6. import com.google.common.collect.Maps;
  7. import com.google.common.collect.Sets;
  8. import com.kingdee.bos.BOSException;
  9. import com.kingdee.bos.Context;
  10. import com.kingdee.bos.bsf.service.app.IHRMsfService;
  11. import com.kingdee.eas.common.EASBizException;
  12. import com.kingdee.eas.custom.esign.bizEnum.EsignStatusEnum;
  13. import com.kingdee.eas.custom.esign.tsign.hz.comm.EsignHttpResponse;
  14. import com.kingdee.eas.custom.esign.tsign.hz.exception.EsignException;
  15. import com.kingdee.eas.custom.esign.util.EsignConfig;
  16. import com.kingdee.eas.custom.esign.util.EsignHttpUtil;
  17. import org.apache.commons.lang3.StringUtils;
  18. import java.net.URISyntaxException;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.Set;
  22. import java.util.concurrent.TimeUnit;
  23. /**
  24. * description: Create_by_fileOSFService <br>
  25. * date: 28/11/2025 上午 9:46 <br>
  26. * author: lhbj <br>
  27. * version: 1.0 <br>
  28. */
  29. public class Create_by_fileOSFService implements IHRMsfService {
  30. private static final String SUCCESS_CODE = "0";
  31. private static final String PREVIEW_OPERATION = "预览";
  32. private static final int MAX_RETRY_COUNT = 20;
  33. private static final int RETRY_INTERVAL_SECONDS = 3;
  34. @Override
  35. public Object process(Context context, Map map) throws EASBizException, BOSException {
  36. String mack = (String) map.get("mack");
  37. String data = (String) map.get("data");
  38. Map<String, Object> resul = Maps.newHashMap();
  39. try {
  40. JSONObject jsonObject = JSON.parseObject(data);
  41. if ("preview".equals(mack)) {
  42. EsignHttpResponse response = this.previewFile(context, jsonObject, "预览");
  43. if (response.getStatus() >= 200 && response.getStatus() < 300) {
  44. resul.putAll(this.processFileResponse(response,context));
  45. } else {
  46. resul.put("code", response.getStatus());
  47. resul.put("message", "网络异常");
  48. resul.put("data", null);
  49. }
  50. } else {
  51. Map<String, Object> signMap = Maps.newHashMap();
  52. String sourceId = jsonObject.getString("sourceId");
  53. String signFlowTitle = jsonObject.getString("signFlowTitle");
  54. String personId = jsonObject.getString("personId");
  55. String operatorId = jsonObject.getString("operatorId");
  56. //文件
  57. JSONObject templateInfo = jsonObject.getJSONObject("templateInfo");
  58. //设置待签署文件信息
  59. List<Map<String, Object>> docs = this.addDocs(context, jsonObject, templateInfo);
  60. signMap.put("docs", docs);
  61. //签署流程配置项
  62. Map<String, Object> signFlowConfig = this.addSignFlowConfig(context, signFlowTitle, jsonObject);
  63. signMap.put("signFlowConfig", signFlowConfig);
  64. //签署方信息
  65. JSONObject signInfo = jsonObject.getJSONObject("signInfo");
  66. JSONArray signs = signInfo.getJSONArray("signers");
  67. List<Map<String, Object>> signers = this.addSigners(context, signs, docs, sourceId);
  68. signMap.put("signers", signers);
  69. //抄送方信息
  70. JSONArray copis = signInfo.getJSONArray("copiers");
  71. List<Map<String, Object>> copiers = this.addCopiers(context, copis);
  72. if (copiers.size() > 0) {
  73. signMap.put("copiers", copiers);
  74. }
  75. //必须要存在签署文件才能签署
  76. if(docs.size()>0) {
  77. EsignHttpResponse response = EsignHttpUtil.create_by_file(context, personId, operatorId, signFlowTitle, sourceId, JSON.toJSONString(signMap));
  78. if (response.getStatus() >= 200 && response.getStatus() < 300) {
  79. JSONObject body = JSON.parseObject(response.getBody());
  80. resul.putAll(body);
  81. } else {
  82. resul.put("code", response.getStatus());
  83. resul.put("message", "网络异常");
  84. resul.put("data", null);
  85. }
  86. }
  87. }
  88. } catch (EsignException | URISyntaxException e) {
  89. e.printStackTrace();
  90. }
  91. return resul;
  92. }
  93. /**
  94. * 根据”填写模板生成文件“返回的文件id查询文件处理状态
  95. * 需要阻塞等待这个状态变为2或者5才能调用发起签署接口
  96. * @param response
  97. * @param context
  98. * @return
  99. */
  100. public Map<String, Object> processFileResponse(EsignHttpResponse response, Context context) {
  101. Map<String, Object> result = Maps.newHashMap();
  102. JSONObject body = JSON.parseObject(response.getBody());
  103. if (!SUCCESS_CODE.equals(String.valueOf(body.get("code")))) {
  104. result.putAll(body);
  105. return result;
  106. }
  107. JSONObject jsonData = body.getJSONObject("data");
  108. String fileId = jsonData.getString("fileId");
  109. JSONObject pollData = pollFileDownloadUrl(context, fileId);
  110. if (null!=pollData && StringUtils.isNotBlank(pollData.getString("fileDownloadUrl"))) {
  111. jsonData.putAll(pollData);
  112. }
  113. result.putAll(body);
  114. return result;
  115. }
  116. /**
  117. * 阻塞循环调用获取文件信息接口
  118. * @param context
  119. * @param fileId
  120. * @return
  121. */
  122. private JSONObject pollFileDownloadUrl(Context context, String fileId) {
  123. for (int i = MAX_RETRY_COUNT; i > 0; i--) {
  124. try {
  125. JSONObject data = tryGetFileDownloadUrl(context, fileId);
  126. if (null!=data && StringUtils.isNotBlank(data.getString("fileDownloadUrl"))) {
  127. return data;
  128. }
  129. TimeUnit.SECONDS.sleep(RETRY_INTERVAL_SECONDS);
  130. } catch (InterruptedException e) {
  131. Thread.currentThread().interrupt();
  132. break;
  133. } catch (Exception e) {
  134. // 记录日志,继续重试
  135. e.printStackTrace();
  136. }
  137. }
  138. return null;
  139. }
  140. /**
  141. * 等待这个状态变为2或者5才返回
  142. *
  143. * @param context
  144. * @param fileId
  145. * @return
  146. */
  147. private JSONObject tryGetFileDownloadUrl(Context context, String fileId) {
  148. try {
  149. EsignHttpResponse response = EsignHttpUtil.getFileStatus(context, fileId, PREVIEW_OPERATION);
  150. if (response.getStatus() < 200 || response.getStatus() >= 300) {
  151. return null;
  152. }
  153. JSONObject responseBody = JSON.parseObject(response.getBody());
  154. if (!SUCCESS_CODE.equals(String.valueOf(responseBody.get("code")))) {
  155. return null;
  156. }
  157. JSONObject data = responseBody.getJSONObject("data");
  158. String fileStatus = data.getString("fileStatus");
  159. Set<String> COMPLETED_STATUS = Sets.newHashSet();
  160. COMPLETED_STATUS.add("2");
  161. COMPLETED_STATUS.add("5");
  162. if (COMPLETED_STATUS.contains(fileStatus)) {
  163. return data;
  164. }
  165. }catch (EsignException e){
  166. e.printStackTrace();
  167. }
  168. return null;
  169. }
  170. /**
  171. * 设置待签署文件信息
  172. *
  173. * @param context
  174. * @param jsonObject
  175. * @param templateInfo
  176. * @return
  177. * @throws EsignException
  178. */
  179. public List<Map<String, Object>> addDocs(Context context, JSONObject jsonObject, JSONObject templateInfo) throws EsignException {
  180. //设置待签署文件信息
  181. Map<String, Object> resul = Maps.newHashMap();
  182. List<Map<String, Object>> docs = Lists.newArrayList();
  183. for (Map.Entry<String, Object> fileEntry : templateInfo.entrySet()) {
  184. JSONObject fieldObject = (JSONObject) fileEntry.getValue();
  185. String docTemplateId = jsonObject.getString("id");
  186. String fileName = jsonObject.getString("name");
  187. Object order = jsonObject.get("order");
  188. String sourceId = jsonObject.getString("sourceId");
  189. EsignHttpResponse response = this.previewFile(context, fieldObject, sourceId);
  190. if (response.getStatus() >= 200 && response.getStatus() < 300) {
  191. Map<String,Object> body = this.processFileResponse(response,context);
  192. if ("0".equals(String.valueOf(body.get("code")))) {
  193. JSONObject file = (JSONObject) body.get("data");
  194. Map<String, Object> doc = Maps.newHashMap();
  195. doc.put("fileId", file.get("fileId"));
  196. doc.put("fileName", fileName);
  197. if (null != order) {
  198. doc.put("order", Integer.parseInt(String.valueOf(order)));
  199. }
  200. docs.add(doc);
  201. } else {
  202. //文件模板生成失败
  203. resul.putAll(body);
  204. throw new EsignException(JSON.toJSONString(resul));
  205. }
  206. } else {
  207. throw new EsignException("网络异常:" + JSON.toJSONString(response));
  208. }
  209. }
  210. return docs;
  211. }
  212. /**
  213. * 抄送方信息
  214. *
  215. * @param copis
  216. * @return
  217. */
  218. public List<Map<String, Object>> addCopiers(Context context, JSONArray copis) {
  219. List<Map<String, Object>> copiers = Lists.newArrayList();
  220. for (int i = 0; i < copis.size(); i++) {
  221. JSONObject cop = copis.getJSONObject(i);
  222. Map<String, Object> copierPsn = Maps.newHashMap();
  223. Map<String, Object> copierPsnInfo = Maps.newHashMap();
  224. copierPsnInfo.put("psnAccount", cop.getString("psnAccount"));
  225. copierPsn.put("copierPsnInfo", copierPsnInfo);
  226. copiers.add(copierPsn);
  227. }
  228. return copiers;
  229. }
  230. /**
  231. * 添加签署组织
  232. * @param context
  233. * @param orgSignerInfo
  234. * @param docs
  235. * @param sourceId
  236. * @return
  237. * @throws EsignException
  238. * @throws URISyntaxException
  239. */
  240. public Map<String, Object> addOrgSignerInfo(Context context, JSONObject orgSignerInfo, List<Map<String, Object>> docs, String sourceId) throws EsignException, URISyntaxException {
  241. Map<String, Object> resul = Maps.newHashMap();
  242. Map<String, Object> signMapInfo = Maps.newHashMap();
  243. Map<String, Object> orgPsnSignMap = Maps.newHashMap();
  244. String orgName = orgSignerInfo.getString("orgName");
  245. EsignHttpResponse response = EsignHttpUtil.getOrgIdentity_infoByOrgName(context, orgName);
  246. if (response.getStatus() >= 200 && response.getStatus() < 300) {
  247. JSONObject body = JSON.parseObject(response.getBody());
  248. if ("0".equals(String.valueOf(body.get("code")))) {
  249. JSONObject orgPsn = body.getJSONObject("data");
  250. String orgId = orgPsn.getString("orgId");
  251. orgName = orgPsn.getString("orgName");
  252. orgPsnSignMap.put("orgId", orgId);
  253. orgPsnSignMap.put("orgName", orgName);
  254. orgPsnSignMap.put("orgInfo", orgPsn.getJSONObject("orgInfo"));
  255. } else {
  256. //失败
  257. resul.putAll(body);
  258. throw new EsignException(JSON.toJSONString(resul));
  259. }
  260. } else {
  261. throw new EsignException("网络异常:" + JSON.toJSONString(response));
  262. }
  263. Integer signOrder = orgSignerInfo.getInteger("signOrder");
  264. //设置签署方的签署顺序
  265. if (null != signOrder) {
  266. Map<String, Object> signConfig = Maps.newHashMap();
  267. signConfig.put("signOrder", signOrder);
  268. signMapInfo.put("signConfig", signConfig);
  269. }
  270. signMapInfo.put("orgSignerInfo", orgPsnSignMap);
  271. //设置签署方的通知方式
  272. String noticeTypes = orgSignerInfo.getString("noticeTypes");
  273. Map<String, String> noticeConfig = Maps.newHashMap();
  274. if (StringUtils.isNotBlank(noticeTypes)) {
  275. noticeConfig.put("noticeTypes", noticeTypes);
  276. } else {
  277. noticeConfig.put("noticeTypes", "1,2");
  278. }
  279. signMapInfo.put("noticeConfig", noticeConfig);
  280. //签署区信息
  281. List<Map<String, Object>> signFields = Lists.newArrayList();
  282. for (Map<String, Object> doc : docs) {
  283. Map<String, Object> field = Maps.newHashMap();
  284. field.put("fileId", doc.get("fileId"));
  285. field.put("customBizNum", sourceId);
  286. field.put("signFieldType", 0);
  287. //签章区配置项(指定signFieldType为 0 - 签章区时,该参数为必传项)
  288. Map<String, Object> normalSignFieldConfig = Maps.newHashMap();
  289. normalSignFieldConfig.put("freeMode", true);
  290. field.put("normalSignFieldConfig", normalSignFieldConfig);
  291. signFields.add(field);
  292. }
  293. signMapInfo.put("signFields", signFields);
  294. return signMapInfo;
  295. }
  296. /**
  297. * 添加签署人
  298. * @param context
  299. * @param psnSignerInfo
  300. * @param docs
  301. * @param sourceId
  302. * @return
  303. * @throws EsignException
  304. * @throws URISyntaxException
  305. */
  306. public Map<String, Object> addPsnSignerInfo(Context context, JSONObject psnSignerInfo, List<Map<String, Object>> docs, String sourceId) throws EsignException, URISyntaxException {
  307. Map<String, Object> resul = Maps.newHashMap();
  308. Map<String, Object> signMapInfo = Maps.newHashMap();
  309. Map<String, Object> orgPsnSignMap = Maps.newHashMap();
  310. //个人签署方信息
  311. String psnAccount = psnSignerInfo.getString("psnAccount");
  312. String psnName = psnSignerInfo.getString("psnName");
  313. Integer signOrder = psnSignerInfo.getInteger("signOrder");
  314. //设置签署方的签署顺序
  315. if (null != signOrder) {
  316. Map<String, Object> signConfig = Maps.newHashMap();
  317. signConfig.put("signOrder", signOrder);
  318. signMapInfo.put("signConfig", signConfig);
  319. }
  320. orgPsnSignMap.put("psnAccount", psnAccount);
  321. Map<String, String> psnInfo = Maps.newHashMap();
  322. psnInfo.put("psnName", psnName);
  323. orgPsnSignMap.put("psnInfo", psnInfo);
  324. //个人签署方信息
  325. signMapInfo.put("psnSignerInfo", orgPsnSignMap);
  326. //设置签署方的通知方式
  327. String noticeTypes = psnSignerInfo.getString("noticeTypes");
  328. Map<String, String> noticeConfig = Maps.newHashMap();
  329. if (StringUtils.isNotBlank(noticeTypes)) {
  330. noticeConfig.put("noticeTypes", noticeTypes);
  331. } else {
  332. noticeConfig.put("noticeTypes", "1,2");
  333. }
  334. signMapInfo.put("noticeConfig", noticeConfig);
  335. //签署区信息
  336. List<Map<String, Object>> signFields = Lists.newArrayList();
  337. for (Map<String, Object> doc : docs) {
  338. Map<String, Object> field = Maps.newHashMap();
  339. field.put("fileId", doc.get("fileId"));
  340. field.put("customBizNum", sourceId);
  341. field.put("signFieldType", 0);
  342. //签章区配置项(指定signFieldType为 0 - 签章区时,该参数为必传项)
  343. Map<String, Object> normalSignFieldConfig = Maps.newHashMap();
  344. normalSignFieldConfig.put("freeMode", true);
  345. field.put("normalSignFieldConfig", normalSignFieldConfig);
  346. signFields.add(field);
  347. }
  348. signMapInfo.put("signFields", signFields);
  349. return signMapInfo;
  350. }
  351. /**
  352. * 处理签署方信息
  353. *
  354. * @param context
  355. * @param signs
  356. * @param docs
  357. * @param sourceId
  358. * @return
  359. * @throws EsignException
  360. * @throws URISyntaxException
  361. */
  362. public List<Map<String, Object>> addSigners(Context context, JSONArray signs, List<Map<String, Object>> docs, String sourceId) throws EsignException, URISyntaxException {
  363. List<Map<String, Object>> signers = Lists.newArrayList();
  364. for (int i = 0; i < signs.size(); i++) {
  365. Map<String, Object> signMapInfo = Maps.newHashMap();
  366. JSONObject sign = signs.getJSONObject(i);
  367. Map<String, Object> orgPsnSignMap = Maps.newHashMap();
  368. JSONObject orgSignerInfo = sign.getJSONObject("orgSignerInfo");
  369. JSONObject psnSignerInfo = sign.getJSONObject("psnSignerInfo");
  370. //企业/机构签署方信息
  371. if (null != orgSignerInfo) {
  372. signMapInfo = addOrgSignerInfo(context, orgSignerInfo, docs, sourceId);
  373. } else {
  374. //个人签署方信息
  375. signMapInfo = addPsnSignerInfo(context, psnSignerInfo, docs, sourceId);
  376. }
  377. signers.add(signMapInfo);
  378. }
  379. return signers;
  380. }
  381. /**
  382. * 签署流程配置项
  383. *
  384. * @param context
  385. * @param signFlowTitle
  386. * @param jsonObject
  387. * @return
  388. */
  389. public Map<String, Object> addSignFlowConfig(Context context, String signFlowTitle, JSONObject jsonObject) {
  390. Map<String, Object> signFlowConfig = Maps.newHashMap();
  391. signFlowConfig.put("signFlowTitle", signFlowTitle);
  392. Boolean autoStart = jsonObject.getBoolean("autoStart");
  393. if (null != autoStart) {
  394. signFlowConfig.put("autoStart", autoStart);
  395. } else {
  396. signFlowConfig.put("autoStart", true);
  397. }
  398. Boolean autoFinish = jsonObject.getBoolean("autoFinish");
  399. if (null != autoFinish) {
  400. signFlowConfig.put("autoFinish", autoFinish);
  401. } else {
  402. signFlowConfig.put("autoFinish", true);
  403. }
  404. String notifyUrl = jsonObject.getString("notifyUrl");
  405. if (null != notifyUrl) {
  406. signFlowConfig.put("notifyUrl", notifyUrl);
  407. } else {
  408. notifyUrl = EsignConfig.getInstance().get("notifyUrl");
  409. signFlowConfig.put("notifyUrl", notifyUrl);
  410. }
  411. return signFlowConfig;
  412. }
  413. /**
  414. * 根据传入数据调用 ”填写模板生成文件“ 接口
  415. * @param jsonObject
  416. * @return
  417. */
  418. public EsignHttpResponse previewFile(Context context, JSONObject jsonObject, String sourceId) throws EsignException {
  419. String docTemplateId = jsonObject.getString("id");
  420. String fileName = jsonObject.getString("name");
  421. if (StringUtils.isBlank(docTemplateId)) {
  422. docTemplateId = jsonObject.getString("tableId");
  423. }
  424. if (StringUtils.isBlank(fileName)) {
  425. fileName = jsonObject.getString("tableName");
  426. }
  427. Map<String, Object> map = Maps.newHashMap();
  428. map.put("docTemplateId", docTemplateId);
  429. map.put("fileName", fileName);
  430. List<Map<String, Object>> components = Lists.newArrayList();
  431. JSONObject fields = jsonObject.getJSONObject("fields");
  432. for (Map.Entry<String, Object> field : fields.entrySet()) {
  433. Map<String, Object> component = Maps.newHashMap();
  434. component.put("componentId", field.getKey());
  435. JSONObject fieldInfo = (JSONObject) field.getValue();
  436. component.put("componentValue", fieldInfo.get("value"));
  437. components.add(component);
  438. }
  439. map.put("components", components);
  440. EsignHttpResponse response = EsignHttpUtil.createByDocTemplate(context, JSON.toJSONString(map), sourceId);
  441. return response;
  442. }
  443. }