BeisenTransferPhaseFacadeControllerBean.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. package com.kingdee.eas.custom.recuritment.task;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.google.common.collect.Maps;
  5. import com.kingdee.bos.metadata.entity.*;
  6. import com.kingdee.bos.metadata.query.util.CompareType;
  7. import com.kingdee.eas.basedata.person.PersonInfo;
  8. import com.kingdee.eas.custom.beisen.utils.BeisenApiClient;
  9. import com.kingdee.eas.custom.beisen.utils.BeisenParam;
  10. import com.kingdee.eas.custom.beisen.utils.BeisenParamByProperties;
  11. import com.kingdee.eas.custom.beisen.entity.PhaseStatusInfo;
  12. import com.kingdee.eas.hr.ats.AtsUtil;
  13. import com.kingdee.eas.hr.base.EmployeeTypeInfo;
  14. import com.kingdee.eas.hr.base.HRBillStateEnum;
  15. import com.kingdee.eas.util.app.DbUtil;
  16. import com.kingdee.shr.recuritment.*;
  17. import com.kingdee.shr.recuritment.app.OfferConfirmStateEnum;
  18. import com.kingdee.util.DateTimeUtils;
  19. import org.apache.commons.lang3.StringUtils;
  20. import org.apache.log4j.Logger;
  21. import com.kingdee.bos.*;
  22. import com.kingdee.eas.common.EASBizException;
  23. import java.io.IOException;
  24. import java.lang.String;
  25. import java.util.*;
  26. public class BeisenTransferPhaseFacadeControllerBean extends AbstractBeisenTransferPhaseFacadeControllerBean {
  27. private static Logger logger = Logger.getLogger(BeisenTransferPhaseFacadeControllerBean.class);
  28. private Map<String, PhaseStatusInfo> phaseStatus = Maps.newHashMap();
  29. //待录用报批单据状态
  30. private static Set hireApprovalBillStatusSet = new HashSet<>();
  31. //待录用报批招聘状态
  32. private static Set hireApprovalResumeStateSet = new HashSet<>();
  33. //录用终止报批招聘状态
  34. private static Set hireTerminationResumeStateSet = new HashSet<>();
  35. //待录用报批招聘状态
  36. private static Set hireOfferStateSet = new HashSet<>();
  37. private static Map<String, String> beisenTransferPhaseErrorMap = new HashMap<>();
  38. private final String RECAPPROVAL1 = "recApproval1";
  39. private final String RECAPPROVAL2 = "recApproval2";
  40. private final String OFFER1 = "offer1";
  41. private final String OFFER2 = "offer2";
  42. private final String OFFER3 = "offer3";
  43. private final String OFFER4 = "offer4";
  44. private final String OFFER5 = "offer5";
  45. private final String ENROLL1 = "enroll1";
  46. private final String ENROLL2 = "enroll2";
  47. private final String ENROLL3 = "enroll3";
  48. static {
  49. hireApprovalBillStatusSet.add(HRBillStateEnum.SAVED);//未提交
  50. hireApprovalBillStatusSet.add(HRBillStateEnum.SUBMITED);//已提交
  51. hireApprovalBillStatusSet.add(HRBillStateEnum.AUDITING);//审批中
  52. hireApprovalResumeStateSet.add("0009");//待报批
  53. hireApprovalResumeStateSet.add("0010");//报批中
  54. hireTerminationResumeStateSet.add("0012");//终止报批
  55. hireTerminationResumeStateSet.add("0011");//报批不通过
  56. hireOfferStateSet.add("0013");//待入职
  57. hireOfferStateSet.add("0015");//已预入职
  58. beisenTransferPhaseErrorMap.put("applyDeleteApplyIds", "因在当前职位下被删除而转移失败");
  59. beisenTransferPhaseErrorMap.put("applicantDeleteApplyIds", "因应聘者被删除而转移失败");
  60. beisenTransferPhaseErrorMap.put("applicantBlackApplyIds", "因应聘者被拉黑而转移失败");
  61. beisenTransferPhaseErrorMap.put("applicantLockedApplyIds", "因应聘者被锁定而转移失败");
  62. beisenTransferPhaseErrorMap.put("applyStatusChangedApplyIds", "因应聘者阶段状态已发生变化而转移失败");
  63. beisenTransferPhaseErrorMap.put("applyOtherReasonRejectedApplyIds", "因定制功能校验失败而转移失败");
  64. beisenTransferPhaseErrorMap.put("applyByHunterOrRPOUnAcceptedIds", "因应聘者存在猎头/RPO简历且未被接受而转移失败");
  65. beisenTransferPhaseErrorMap.put("applyTransferRuleFailedApplyIds", "因应聘者存在不符合准入规则而转移失败");
  66. }
  67. public BeisenTransferPhaseFacadeControllerBean() throws IOException, BOSException {
  68. BeisenParamByProperties properties = null;
  69. try {
  70. properties = new BeisenParamByProperties();
  71. } catch (IOException e) {
  72. logger.error("北森状态转移Facade获取配置文件报错: " + e.getMessage(), e);
  73. throw e;
  74. }
  75. Map<String, String> config = properties.getConfig();
  76. String phase1 = config.get("phase1");
  77. String status1A = config.get("status1A");
  78. String status1B = config.get("status1B");
  79. String phase2 = config.get("phase2");
  80. String status2A = config.get("status2A");
  81. String status2B = config.get("status2B");
  82. String status2C = config.get("status2C");
  83. String status2D = config.get("status2D");
  84. String status2E = config.get("status2E");
  85. String phase3 = config.get("phase3");
  86. String status3A = config.get("status3A");
  87. String status3B = config.get("status3B");
  88. String status3C = config.get("status3C");
  89. if (StringUtils.isAnyBlank(
  90. phase1, phase2, phase3, status1A,
  91. status1B, status2A, status2B, status2C,
  92. status2D, status2E, phase3, status3A,
  93. status3B, status3C)) {
  94. throw new BOSException("北森阶段状态为空!");
  95. }
  96. phaseStatus.put(RECAPPROVAL1, new PhaseStatusInfo(phase1, status1A));
  97. phaseStatus.put(RECAPPROVAL2, new PhaseStatusInfo(phase1, status1B));
  98. phaseStatus.put(OFFER1, new PhaseStatusInfo(phase2, status2A));
  99. phaseStatus.put(OFFER2, new PhaseStatusInfo(phase2, status2B));
  100. phaseStatus.put(OFFER3, new PhaseStatusInfo(phase2, status2C));
  101. phaseStatus.put(OFFER4, new PhaseStatusInfo(phase2, status2D));
  102. phaseStatus.put(OFFER5, new PhaseStatusInfo(phase2, status2E));
  103. phaseStatus.put(ENROLL1, new PhaseStatusInfo(phase3, status3A));
  104. phaseStatus.put(ENROLL2, new PhaseStatusInfo(phase3, status3B));
  105. phaseStatus.put(ENROLL3, new PhaseStatusInfo(phase3, status3C));
  106. }
  107. /**
  108. * 同步录用报批状态到北森
  109. *
  110. * @param ctx
  111. * @param billId
  112. * @param preponeHours
  113. * @throws BOSException
  114. * @throws EASBizException
  115. */
  116. @Override
  117. protected void _syncRecApprovalToBeisen(Context ctx, String billId, int preponeHours)
  118. throws BOSException, EASBizException {
  119. try {
  120. super._syncRecApprovalToBeisen(ctx, billId, preponeHours);
  121. IRecApproval iRecApproval = RecApprovalFactory.getLocalInstance(ctx);
  122. RecApprovalCollection recApprovalCollection = null;
  123. SelectorItemCollection sic = new SelectorItemCollection();
  124. sic.add("*");
  125. sic.add("resumeBaseRec.*");
  126. sic.add("resumeBaseRec.resumeState.*");
  127. if (StringUtils.isNotBlank(billId)) {
  128. FilterInfo filterInfo = new FilterInfo();
  129. FilterItemCollection filterItems = filterInfo.getFilterItems();
  130. filterItems.add(new FilterItemInfo("id", billId));
  131. EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
  132. recApprovalCollection = iRecApproval.getRecApprovalCollection(viewInfo);
  133. if (recApprovalCollection.isEmpty()) {
  134. logger.error("未匹配到录用报批单据,单据id: " + billId);
  135. throw new BOSException("未匹配到录用报批单据");
  136. }
  137. } else {
  138. if (preponeHours <= 0) {
  139. preponeHours = 2;
  140. }
  141. Date now = new Date();
  142. Date before = DateTimeUtils.addHour(now, -preponeHours);
  143. //查询最近12小时内更新的录用报批
  144. FilterInfo filterInfo = new FilterInfo();
  145. FilterItemCollection filterItems = filterInfo.getFilterItems();
  146. //最后更新时间大于等于
  147. filterItems.add(new FilterItemInfo("lastUpdateTime", before, CompareType.GREATER_EQUALS));
  148. //最后更新时间小于等于当前
  149. filterItems.add(new FilterItemInfo("lastUpdateTime", now, CompareType.LESS_EQUALS));
  150. EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
  151. recApprovalCollection = iRecApproval.getRecApprovalCollection(viewInfo);
  152. }
  153. if (recApprovalCollection == null || recApprovalCollection.isEmpty()) {
  154. logger.error("录用报批为空!");
  155. return;
  156. }
  157. //维护录用报批与北森申请id映射关系
  158. Map applyIdRecApprovalMap = new HashMap();
  159. Map<String, JSONArray> recApprovalMap = new HashMap();
  160. IOffer iOffer = OfferFactory.getLocalInstance(ctx);
  161. for (int i = 0; i < recApprovalCollection.size(); i++) {
  162. RecApprovalInfo recApprovalInfo = recApprovalCollection.get(i);
  163. String fid = recApprovalInfo.getId().toString();
  164. //简历基本信息
  165. ResumeBaseRecInfo resumeBaseRec = recApprovalInfo.getResumeBaseRec();
  166. String applyId = resumeBaseRec.getString("applyId");
  167. if (StringUtils.isEmpty(applyId)) {
  168. String errorMsg = "北森申请id为空!";
  169. logger.error(errorMsg);
  170. Set set = new HashSet();
  171. set.add(fid);
  172. updateTable(ctx, "T_REC_RecApproval", errorMsg, "2", set);
  173. continue;
  174. }
  175. applyIdRecApprovalMap.put(applyId, fid);
  176. ResumeStateInfo resumeState = resumeBaseRec.getResumeState();
  177. String resumeStateNumber = resumeState.getNumber();//招聘状态
  178. String beisenStatus = null;
  179. //单据状态
  180. HRBillStateEnum billState = recApprovalInfo.getBillState();
  181. if (hireApprovalBillStatusSet.contains(billState) && hireApprovalResumeStateSet.contains(resumeStateNumber)) {
  182. //单据状态为未提交/未审批/审批中,招聘需求状态为待报批/报批中 北森录用报批状态为待录用报批
  183. beisenStatus = RECAPPROVAL1;
  184. } else if (HRBillStateEnum.AUDITEND.equals(billState) && hireTerminationResumeStateSet.contains(resumeStateNumber)) {
  185. //单据状态为审批不通过,招聘需求状态为终止报批/报批不通过 北森录用报批状态为录用终止
  186. beisenStatus = RECAPPROVAL2;
  187. } else if (HRBillStateEnum.AUDITED.equals(billState) && "0013".equals(resumeStateNumber)) {
  188. //单据状态为审批通过,招聘需求状态为待入职,Offer发送状态为空,北森状态为待发Offer
  189. try {
  190. OfferCollection offerCollection = iOffer.getOfferCollection("where resumeBaseRec ='" + resumeBaseRec.getId() + "'");
  191. //offer发送状态
  192. String sendState = null;
  193. if (!offerCollection.isEmpty()) {
  194. OfferInfo offerInfo = offerCollection.get(0);
  195. sendState = offerInfo.getSendState();
  196. }
  197. if (!StringUtils.isEmpty(sendState)) {
  198. //Offer发送状态不为空,忽略
  199. return;
  200. }
  201. } catch (BOSException e) {
  202. throw new BOSException("获取offer状态报错: " + e.getMessage());
  203. }
  204. beisenStatus = OFFER1;
  205. }
  206. if (StringUtils.isNotBlank(beisenStatus)) {
  207. if (recApprovalMap.containsKey(beisenStatus)) {
  208. recApprovalMap.get(beisenStatus).add(applyId);
  209. } else {
  210. JSONArray applyIds = new JSONArray();
  211. applyIds.add(applyId);
  212. recApprovalMap.put(beisenStatus, applyIds);
  213. }
  214. }
  215. }
  216. //处理北森状态转移请求
  217. handleBeisenTransferPhaseQuery(ctx, recApprovalMap, applyIdRecApprovalMap, "T_REC_RecApproval");
  218. } catch (Exception e) {
  219. logger.error("录用报批同步北森状态转移报错: " + e.getMessage(), e);
  220. }
  221. }
  222. /**
  223. * 同步offer状态到北森
  224. *
  225. * @param ctx
  226. * @param billId
  227. * @throws BOSException
  228. * @throws EASBizException
  229. */
  230. @Override
  231. protected void _syncOfferToBeisen(Context ctx, String billId, int preponeHours) throws BOSException, EASBizException {
  232. try {
  233. super._syncOfferToBeisen(ctx, billId, preponeHours);
  234. IOffer iOffer = OfferFactory.getLocalInstance(ctx);
  235. OfferCollection offerCollection = null;
  236. SelectorItemCollection sic = new SelectorItemCollection();
  237. sic.add("*");
  238. sic.add("resumeBaseRec.*");
  239. sic.add("resumeBaseRec.resumeState.*");
  240. sic.add("person.employeeType.isInCount");
  241. if (StringUtils.isNotBlank(billId)) {
  242. FilterInfo filterInfo = new FilterInfo();
  243. FilterItemCollection filterItems = filterInfo.getFilterItems();
  244. filterItems.add(new FilterItemInfo("id", billId));
  245. EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
  246. offerCollection = iOffer.getOfferCollection(viewInfo);
  247. if (offerCollection.isEmpty()) {
  248. logger.error("未匹配到offer单据,单据id: " + billId);
  249. throw new BOSException("未匹配到offer单据");
  250. }
  251. } else {
  252. if (preponeHours <= 0) {
  253. preponeHours = 2;
  254. }
  255. Date now = new Date();
  256. Date before = DateTimeUtils.addHour(now, -preponeHours);
  257. //查询最近12小时内更新的录用报批
  258. FilterInfo filterInfo = new FilterInfo();
  259. FilterItemCollection filterItems = filterInfo.getFilterItems();
  260. //最后更新时间大于等于
  261. filterItems.add(new FilterItemInfo("lastUpdateTime", before, CompareType.GREATER_EQUALS));
  262. //最后更新时间小于等于当前
  263. filterItems.add(new FilterItemInfo("lastUpdateTime", now, CompareType.LESS_EQUALS));
  264. EntityViewInfo viewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
  265. offerCollection = iOffer.getOfferCollection(viewInfo);
  266. }
  267. if (offerCollection == null || offerCollection.isEmpty()) {
  268. logger.error("offer为空!");
  269. return;
  270. }
  271. //维护OfferId与北森申请id映射关系
  272. Map applyIdOfferMap = new HashMap();
  273. Map<String, JSONArray> offerMap = new HashMap();
  274. Map<String, JSONArray> recApprovalMap = new HashMap();
  275. for (int i = 0; i < offerCollection.size(); i++) {
  276. OfferInfo offerInfo = offerCollection.get(i);
  277. String fid = offerInfo.getId().toString();
  278. //简历基本信息
  279. ResumeBaseRecInfo resumeBaseRec = offerInfo.getResumeBaseRec();
  280. String applyId = resumeBaseRec.getString("applyId");
  281. if (StringUtils.isEmpty(applyId)) {
  282. String errorMsg = "北森申请id为空!";
  283. logger.error(errorMsg);
  284. Set set = new HashSet();
  285. set.add(fid);
  286. updateTable(ctx, "T_REC_Offer", errorMsg, "2", set);
  287. continue;
  288. }
  289. applyIdOfferMap.put(applyId, fid);
  290. ResumeStateInfo resumeState = resumeBaseRec.getResumeState();
  291. String resumeStateNumber = resumeState.getNumber();//招聘状态
  292. //发送状态
  293. String sendState = offerInfo.getSendState();
  294. //确认状态
  295. OfferConfirmStateEnum confirmState = offerInfo.getConfirmState();
  296. String beisenStatus = null;
  297. if ("0013".equals(resumeStateNumber) && StringUtils.isBlank(sendState) || "待发送".equals(sendState)) {
  298. //发送状态为空或待确认,招聘需求状态为待入职 北森录用报批状态为待发Offer
  299. beisenStatus = OFFER1;
  300. } else if ("0013".equals(resumeStateNumber) && "已发送".equals(sendState) && OfferConfirmStateEnum.TOBECONFIRM.equals(confirmState)) {
  301. //确认结果待确认,发送状态为已发送,招聘需求状态为待入职 北森录用报批状态为已发Offer
  302. beisenStatus = OFFER2;
  303. } else if ("0013".equals(resumeStateNumber) && "已发送".equals(sendState) && OfferConfirmStateEnum.ACCEPTED.equals(confirmState)) {
  304. //确认结果已接受,发送状态为已发送,招聘需求状态为待入职 北森录用报批状态为接受Offer
  305. beisenStatus = OFFER4;
  306. } else if ("0013".equals(resumeStateNumber) && "已发送".equals(sendState) && OfferConfirmStateEnum.REJECTED.equals(confirmState)) {
  307. //确认结果已拒绝,发送状态为已发送,招聘需求状态为待入职 北森录用报批状态为拒绝Offer
  308. beisenStatus = OFFER3;
  309. } else if ("0015".equals(resumeStateNumber)) {
  310. //招聘需求状态为已预入职 北森录用报批状态为等待入职
  311. beisenStatus = OFFER5;
  312. } else if ("0017".equals(resumeStateNumber)) {
  313. //招聘需求状态为已入职 北森录用报批状态为已入职
  314. PersonInfo person = offerInfo.getPerson();
  315. if (person != null) {
  316. EmployeeTypeInfo employeeType = person.getEmployeeType();
  317. if (employeeType != null && !employeeType.isIsInCount()) {
  318. //如果有审批通过的离职单,则忽略
  319. return;
  320. }
  321. }
  322. beisenStatus = ENROLL1;
  323. } else if ("0016".equals(resumeStateNumber) || "0014".equals(resumeStateNumber)) {
  324. //招聘需求状态为放弃入职或终止入职 北森录用报批状态为取消入职
  325. beisenStatus = ENROLL2;
  326. }
  327. if (StringUtils.isNotBlank(beisenStatus)) {
  328. if (recApprovalMap.containsKey(beisenStatus)) {
  329. offerMap.get(beisenStatus).add(applyId);
  330. } else {
  331. JSONArray applyIds = new JSONArray();
  332. applyIds.add(applyId);
  333. offerMap.put(beisenStatus, applyIds);
  334. }
  335. }
  336. }
  337. handleBeisenTransferPhaseQuery(ctx, applyIdOfferMap, offerMap, "T_REC_Offer");
  338. } catch (Exception e) {
  339. logger.error("offer同步北森状态转移报错: " + e.getMessage(), e);
  340. }
  341. }
  342. /**
  343. * 处理北森状态转移请求
  344. *
  345. * @param ctx
  346. * @param recApprovalMap
  347. * @param applyIdStatusMap 北森状态与申请id
  348. * @param tableName 数据库表名
  349. * @throws BOSException
  350. */
  351. private void handleBeisenTransferPhaseQuery(
  352. Context ctx,
  353. Map<String, JSONArray> recApprovalMap,
  354. Map applyIdStatusMap,
  355. String tableName
  356. ) throws BOSException, IOException {
  357. BeisenApiClient beisenApiClient = BeisenApiClient.getInstance();
  358. for (String statusName : recApprovalMap.keySet()) {
  359. try {
  360. //申请id
  361. JSONArray applyIds = recApprovalMap.get(statusName);
  362. PhaseStatusInfo phaseStatusInfo = phaseStatus.get(statusName);
  363. JSONObject params = new JSONObject();
  364. params.put("applyIds", applyIds);
  365. params.put("phaseId", phaseStatusInfo.getPhaseId());
  366. params.put("statusId", phaseStatusInfo.getStatusId());
  367. JSONObject response = beisenApiClient.callApi(BeisenParam.POST_TRANSFERPHASE_URL, params);
  368. int code = response.getIntValue("code");
  369. String message = response.getString("message");
  370. if (200 == code) {
  371. JSONObject data = response.getJSONObject("data");
  372. //转移失败数
  373. Integer noTransferCount = data.getInteger("noTransferCount");
  374. if (noTransferCount > 0) {
  375. for (String key : beisenTransferPhaseErrorMap.keySet()) {
  376. JSONArray failApplyIds = data.getJSONArray(key);
  377. if (!failApplyIds.isEmpty()) {
  378. String errorMsg = beisenTransferPhaseErrorMap.get(key);
  379. Set fids = new HashSet<>();
  380. failApplyIds.forEach((applyid) -> {
  381. fids.add(applyIdStatusMap.get(applyid));
  382. });
  383. updateTable(ctx, tableName, errorMsg, "2", fids);
  384. }
  385. }
  386. } else {
  387. Set fids = new HashSet<>();
  388. applyIdStatusMap.values().forEach((id) -> {
  389. fids.add(id);
  390. });
  391. updateTable(ctx, tableName, "成功", "1", fids);
  392. }
  393. } else {
  394. Set fids = new HashSet<>();
  395. applyIdStatusMap.values().forEach((id) -> {
  396. fids.add(id);
  397. });
  398. updateTable(ctx, tableName, message, "2", fids);
  399. }
  400. } catch (Exception e) {
  401. logger.error("同步北森状态转移报错: " + e.getMessage(), e);
  402. throw e;
  403. }
  404. }
  405. }
  406. /**
  407. * 更新offer/录用报批表执行结果和状态
  408. *
  409. * @param ctx
  410. * @param tableName
  411. * @param message
  412. * @param status
  413. * @param fids
  414. * @throws BOSException
  415. */
  416. private void updateTable(
  417. Context ctx,
  418. String tableName,
  419. String message,
  420. String status,
  421. Set fids
  422. ) throws BOSException {
  423. StringBuilder updateSql = new StringBuilder();
  424. updateSql.append("update ").append(tableName).append(" set CFsyncBeisenResult ='");
  425. updateSql.append(message).append("' ,CFsyncStatus = '").append(status).append("'");
  426. updateSql.append(" where fid in (").append(AtsUtil.convertSetToString(fids)).append(")");
  427. DbUtil.execute(ctx, updateSql.toString());
  428. }
  429. }