Create_by_fileOSFService.java 20 KB

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