SynCbsDetailNewPlugin.java 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294
  1. package kd.cosmic.jkjt.tmc.cbs8;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import kd.bos.bill.AbstractBillPlugIn;
  6. import kd.bos.coderule.api.CodeRuleInfo;
  7. import kd.bos.dataentity.OperateOption;
  8. import kd.bos.dataentity.entity.DynamicObject;
  9. import kd.bos.dataentity.entity.DynamicObjectCollection;
  10. import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
  11. import kd.bos.entity.EntityMetadataCache;
  12. import kd.bos.entity.datamodel.IDataModel;
  13. import kd.bos.entity.datamodel.events.PropertyChangedArgs;
  14. import kd.bos.entity.operate.result.OperationResult;
  15. import kd.bos.exception.KDBizException;
  16. import kd.bos.form.MessageBoxOptions;
  17. import kd.bos.form.events.AfterDoOperationEventArgs;
  18. import kd.bos.form.field.BasedataEdit;
  19. import kd.bos.form.field.DateRangeEdit;
  20. import kd.bos.form.field.events.BeforeF7SelectEvent;
  21. import kd.bos.form.field.events.BeforeF7SelectListener;
  22. import kd.bos.list.ListFilterParameter;
  23. import kd.bos.list.ListShowParameter;
  24. import kd.bos.logging.Log;
  25. import kd.bos.logging.LogFactory;
  26. import kd.bos.openapi.common.result.CustomApiResult;
  27. import kd.bos.orm.query.QCP;
  28. import kd.bos.orm.query.QFilter;
  29. import kd.bos.sdk.util.KHttpClientUtils;
  30. import kd.bos.servicehelper.BusinessDataServiceHelper;
  31. import kd.bos.servicehelper.QueryServiceHelper;
  32. import kd.bos.servicehelper.coderule.CodeRuleServiceHelper;
  33. import kd.bos.servicehelper.operation.OperationServiceHelper;
  34. import kd.bos.servicehelper.operation.SaveServiceHelper;
  35. import kd.bos.util.StringUtils;
  36. import kd.cosmic.jkjt.tmc.util.ParamsUtil;
  37. import kd.tmc.bei.common.helper.SyncAutoBalanceHelper;
  38. import kd.tmc.fbp.common.enums.FinOrgTypeEnum;
  39. import kd.tmc.fbp.common.helper.TmcDataServiceHelper;
  40. import kd.tmc.fbp.common.helper.TmcViewInputHelper;
  41. import kd.tmc.fbp.common.util.EmptyUtil;
  42. import org.apache.commons.lang.time.DateFormatUtils;
  43. import org.apache.commons.lang3.ObjectUtils;
  44. import java.io.IOException;
  45. import java.math.BigDecimal;
  46. import java.math.BigInteger;
  47. import java.sql.Timestamp;
  48. import java.text.ParseException;
  49. import java.text.SimpleDateFormat;
  50. import java.util.*;
  51. import java.util.stream.Collectors;
  52. /**
  53. * Module :资金云-银企互联-离线明细引入
  54. * Description :将CBS的交易明细通过json格式进行数据同步
  55. *
  56. * @author : zhujintao
  57. * @date : 2024/10/14
  58. */
  59. public class SynCbsDetailNewPlugin extends AbstractBillPlugIn implements BeforeF7SelectListener {
  60. private static Log logger = LogFactory.getLog(SynCbsDetailNewPlugin.class);
  61. private static final String KEY_OP_SAVE = "save";
  62. //离线明细引入实体编码
  63. private static final String KEY_ENTITY_BETRANSDETAIL = "bei_betransdetail_imp";
  64. //出纳初始化
  65. private static final String KEY_ENTITY_CASHINIT = "cas_cashmgtinit";
  66. public SynCbsDetailNewPlugin() {
  67. }
  68. /**
  69. * 监听银行账户变化
  70. *
  71. * @param e
  72. */
  73. @Override
  74. public void registerListener(EventObject e) {
  75. super.registerListener(e);
  76. BasedataEdit accountBank = (BasedataEdit) this.getControl("nckd_accountbank");
  77. accountBank.addBeforeF7SelectListener(this);
  78. }
  79. /**
  80. * 初始化,讲资金组织自动填充,交易日期自动填写
  81. *
  82. * @param e
  83. */
  84. @Override
  85. public void afterCreateNewData(EventObject e) {
  86. super.afterCreateNewData(e);
  87. Map<String, Object> customParams = this.getView().getFormShowParameter().getCustomParams();
  88. List<Object> companyIdList = (List) customParams.get("companyIdList");
  89. if (EmptyUtil.isNoEmpty(companyIdList)) {
  90. String first = String.valueOf(companyIdList.get(0));
  91. if (!"".equals(first)) {
  92. DynamicObject[] load = TmcDataServiceHelper.load(companyIdList.stream().map((s) -> {
  93. return Long.parseLong(s.toString());
  94. }).toArray(), EntityMetadataCache.getDataEntityType("bos_org"));
  95. DynamicObjectCollection orgColls = TmcDataServiceHelper.generateMultiPropValue(this.getModel().getDataEntity(), "nckd_org", load);
  96. TmcViewInputHelper.setValWithoutDataChanged(this.getModel(), "nckd_org", orgColls);
  97. }
  98. }
  99. Date currentDate = ParamsUtil.getCurrentDate();
  100. TmcViewInputHelper.setValWithoutDataChanged(this.getModel(), "startdate", currentDate);
  101. TmcViewInputHelper.setValWithoutDataChanged(this.getModel(), "enddate", currentDate);
  102. }
  103. @Override
  104. public void propertyChanged(PropertyChangedArgs e) {
  105. super.propertyChanged(e);
  106. switch (e.getProperty().getName()) {
  107. case "nckd_detailtype":
  108. TmcViewInputHelper.setValWithoutDataChanged(this.getModel(), "nckd_accountbank", (Object) null);
  109. break;
  110. case "nckd_org":
  111. TmcViewInputHelper.setValWithoutDataChanged(this.getModel(), "nckd_accountbank", (Object) null);
  112. break;
  113. }
  114. }
  115. @Override
  116. public void beforeF7Select(BeforeF7SelectEvent evt) {
  117. String property = evt.getProperty().getName();
  118. boolean mustInput;
  119. if ("nckd_accountbank".equals(property)) {
  120. mustInput = TmcViewInputHelper.checkMustInput(this.getView(), this.getModel(), false, "nckd_org");
  121. if (!mustInput) {
  122. evt.setCancel(true);
  123. } else {
  124. ListShowParameter showParameter = (ListShowParameter) evt.getFormShowParameter();
  125. ListFilterParameter filterParam = showParameter.getListFilterParameter();
  126. List<QFilter> qFilters = filterParam.getQFilters();
  127. DynamicObjectCollection orgs = (DynamicObjectCollection) this.getModel().getValue("nckd_org");
  128. List<Long> orgIds = (List) orgs.stream().map((s) -> {
  129. return s.getDynamicObject("fbasedataid").getLong("id");
  130. }).collect(Collectors.toList());
  131. QFilter qFilter = SyncAutoBalanceHelper.getAccountBankQfilter(orgIds);
  132. if (this.getModel().getValue("nckd_detailtype") == null) {
  133. this.getView().showConfirm("请先选择明细类型!", MessageBoxOptions.OK);
  134. evt.setCancel(true);
  135. return;
  136. }
  137. String detailType = this.getModel().getValue("nckd_detailtype").toString();
  138. //余额明细就是是否 开通CBS银企接口 为依据
  139. if ("balance".equals(detailType)) {
  140. qFilter.and(new QFilter("nckd_issetcbs", QCP.equals, false));
  141. } else if ("current".equals(detailType) || "history".equals(detailType)) {
  142. qFilter.and(new QFilter("nckd_issetcbs", QCP.equals, true));
  143. }
  144. qFilters.add(qFilter);
  145. }
  146. }
  147. }
  148. @Override
  149. public void afterDoOperation(AfterDoOperationEventArgs args) {
  150. super.afterDoOperation(args);
  151. String operateKey = args.getOperateKey();
  152. if (args.getOperationResult() != null && args.getOperationResult().isSuccess() && "syn".equals(operateKey)) {
  153. //同步CBS交易明细 --------------------------
  154. //message 返回的提示信息
  155. String message = synDetail();
  156. if (StringUtils.isNotEmpty(message)) {
  157. this.getView().showConfirm(message, MessageBoxOptions.OK);
  158. return;
  159. }
  160. Map<String, String> returnData = new HashMap(4);
  161. returnData.put("message", "success");
  162. this.getView().returnDataToParent(returnData);
  163. this.getView().close();
  164. }
  165. }
  166. /**
  167. * 同步交易明细
  168. *
  169. * @return
  170. */
  171. public String synDetail() {
  172. if (this.getModel().getValue("nckd_detailtype") == null) {
  173. return "请先选择明细类型!";
  174. }
  175. String detailType = this.getModel().getValue("nckd_detailtype").toString();
  176. //同步当日交易明细
  177. if ("current".equals(detailType)) {
  178. //如果传入账号则按照传入账号查询,否则按照组织下的全部符合条件的账号查询
  179. DynamicObject[] accounts = getSelectAccounts("");
  180. if (accounts.length == 0) {
  181. return "请选择银行账号!";
  182. }
  183. return synCurDetail(accounts);
  184. }
  185. //同步余额交易明细
  186. else if ("balance".equals(detailType)) {
  187. DynamicObjectCollection accountCols = (DynamicObjectCollection) this.getModel().getValue("nckd_accountbank");
  188. List<Long> accountIds = (List) accountCols.stream().map((s) -> {
  189. return s.getDynamicObject("fbasedataid").getLong("id");
  190. }).collect(Collectors.toList());
  191. //先更新cbs开通状态
  192. String updatenckd_issetcbs = synAccountOpenStatus(accountIds);
  193. if (StringUtils.isNotEmpty(updatenckd_issetcbs)) {
  194. return updatenckd_issetcbs;
  195. }
  196. //如果传入账号则按照传入账号查询,否则按照组织下的全部符合条件的账号查询
  197. DynamicObject[] accounts = getSelectAccounts("balance");
  198. if (accounts.length == 0) {
  199. return "请选择银行账号!";
  200. }
  201. return synBalanceDetail(accounts);
  202. }
  203. //同步历史交易明细
  204. else if ("history".equals(detailType)) {
  205. DateRangeEdit headFieldEdit = this.getView().getControl("nckd_daterange");
  206. String startField = headFieldEdit.getStartDateFieldKey();
  207. String endField = headFieldEdit.getEndDateFieldKey();
  208. if (this.getModel().getValue(endField) == null
  209. || this.getModel().getValue(endField) == null) {
  210. return "开始日期或结束日期不能为空。";
  211. }
  212. Date startDate = (Date) this.getModel().getValue(startField);
  213. Date endDate = (Date) this.getModel().getValue(endField);
  214. int diffDays = ParamsUtil.getDiffDays(startDate, endDate);
  215. if (diffDays > 3) {
  216. return "开始日期与结束日期范围不允许超过3天。";
  217. }
  218. DynamicObject[] accounts = getSelectAccounts("");
  219. if (accounts.length == 0) {
  220. return "请选择银行账号!";
  221. }
  222. return synHisDetail(accounts, startDate, endDate);
  223. } else {
  224. return null;
  225. }
  226. }
  227. /**
  228. * 同步余额交易明细
  229. *
  230. * @param accounts
  231. */
  232. public String synBalanceDetail(DynamicObject[] accounts) {
  233. //获取cbsurl //实时余额查询
  234. String cbsUrl = getCbsUrl("balancedetail");
  235. if ("请前往《CBS支付参数设置》进行支付参数设置".equals(cbsUrl)) {
  236. return cbsUrl;
  237. }
  238. List<DynamicObject> listObj = new ArrayList<>();
  239. int count = 0;
  240. StringBuilder err = new StringBuilder();
  241. for (DynamicObject acct : accounts) {
  242. JSONObject lastBal = queryLastBal(acct);
  243. Map<String, String> header = new HashMap<>();
  244. header.put("Content-Type", "application/json; charset=UTF-8");
  245. Map<String, Object> params = new HashMap<>();
  246. Map<String, Object> body = new HashMap<>();
  247. body.put("accountNo", acct.getString("bankaccountnumber"));
  248. //直联未开通
  249. //body.put("directConnectFlag", "0");
  250. //分页查询参数
  251. body.put("currentPage", 1);
  252. body.put("pageSize", 100);
  253. params.put("params", body);
  254. //保存CBS调用日志
  255. String uuid = ParamsUtil.saveCBSLogData(cbsUrl, "detail", JSON.toJSONString(params));
  256. String sTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  257. logger.info("调用CBS接口实时余额查询开始时间:" + sTime);
  258. String sr;
  259. try {
  260. sr = KHttpClientUtils.postjson(cbsUrl, header, JSON.toJSONString(params));
  261. } catch (IOException e) {
  262. throw new KDBizException("调用CBS实时余额查询接口错误" + e);
  263. }
  264. String eTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  265. logger.info("调用CBS接口实时余额查询结束时间:" + eTime);
  266. //更新CBS调用日志
  267. ParamsUtil.updateCBSLogData(uuid, sr);
  268. DynamicObject result = getBalanceDetailInfo(sr, acct, lastBal.getBigDecimal("bal"));
  269. if (result != null) {
  270. listObj.add(result);
  271. }
  272. count++;
  273. //批量保存
  274. if (listObj.size() > 0 && count == 1000) {
  275. count = 0;
  276. OperationResult resultSave = OperationServiceHelper.executeOperate(KEY_OP_SAVE, KEY_ENTITY_BETRANSDETAIL, listObj.toArray(new DynamicObject[]{}), OperateOption.create());
  277. if (resultSave.getAllErrorOrValidateInfo().size() > 0) {
  278. for (int index = 0; index < resultSave.getAllErrorOrValidateInfo().size(); index++) {
  279. String message = resultSave.getAllErrorOrValidateInfo().get(index).getMessage();
  280. err.append("/r/n").append(message);
  281. }
  282. }
  283. listObj.clear();
  284. }
  285. }
  286. //批量保存
  287. if (listObj.size() > 0) {
  288. OperationResult resultSave = OperationServiceHelper.executeOperate(KEY_OP_SAVE, KEY_ENTITY_BETRANSDETAIL, listObj.toArray(new DynamicObject[]{}), OperateOption.create());
  289. if (resultSave.getAllErrorOrValidateInfo().size() > 0) {
  290. for (int index = 0; index < resultSave.getAllErrorOrValidateInfo().size(); index++) {
  291. String message = resultSave.getAllErrorOrValidateInfo().get(index).getMessage();
  292. err.append("/r/n").append(message);
  293. }
  294. }
  295. }
  296. if (err.length() > 0) {
  297. return err.toString();
  298. }
  299. return "同步成功";
  300. }
  301. /**
  302. * 保存余额交易明细
  303. *
  304. * @param cbssr
  305. * @param kingdeeAccount
  306. * @param lastBal
  307. * @return
  308. */
  309. private DynamicObject getBalanceDetailInfo(String cbssr, DynamicObject kingdeeAccount, BigDecimal lastBal) {
  310. JSONObject cbsObj = JSON.parseObject(cbssr);
  311. JSONObject data = (JSONObject) cbsObj.get("data");
  312. JSONObject dataList = (JSONObject) data.get("data");
  313. JSONArray array = (JSONArray) dataList.get("list");
  314. if (array.size() > 0) {
  315. JSONObject cbsAccount = array.getJSONObject(0);
  316. DynamicObject detailInfo = null;
  317. try {
  318. detailInfo = parseBalanceBetransDetail(cbsAccount, kingdeeAccount, lastBal);
  319. } catch (ParseException e) {
  320. throw new KDBizException("CBS返回数据转换未交易明细单据对象错误" + e);
  321. }
  322. return detailInfo;
  323. }
  324. return null;
  325. }
  326. /**
  327. * 组装余额交易明细info
  328. *
  329. * @param cbsAccount
  330. * @param kingdeeAcct
  331. * @param lastBal
  332. * @return
  333. * @throws ParseException
  334. */
  335. private DynamicObject parseBalanceBetransDetail(JSONObject cbsAccount, DynamicObject kingdeeAcct, BigDecimal lastBal) throws ParseException {
  336. //账户余额
  337. BigDecimal actBal = cbsAccount.getBigDecimal("accountBalance");
  338. if (actBal == null) {
  339. actBal = BigDecimal.ZERO;
  340. }
  341. //处理日期类字段
  342. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  343. SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
  344. //交易时间
  345. Date time = new Date();
  346. //交易日期
  347. Date date = sdf1.parse(sdf1.format(time));
  348. //如果当天存在cbs交易明细,则不增加交易明细
  349. Boolean isExistDetail = ParamsUtil.isExistsDetail(kingdeeAcct, date, new String[]{"curday", "history"});
  350. if (isExistDetail) {
  351. return null;
  352. }
  353. DynamicObject objectInfo = ParamsUtil.getDetailInfo(kingdeeAcct, date, "balancecompare");
  354. if (objectInfo == null) {
  355. objectInfo = BusinessDataServiceHelper.newDynamicObject(KEY_ENTITY_BETRANSDETAIL);
  356. }
  357. objectInfo.set("nckd_generatemethod", "balancecompare");
  358. //借贷方向:1:借方,2:贷方
  359. String direct = "";
  360. BigDecimal dayActAmt = actBal.subtract(lastBal).abs();
  361. if (lastBal.compareTo(actBal) > 0) {
  362. direct = "1";
  363. } else if (lastBal.compareTo(actBal) < 0) {
  364. direct = "2";
  365. } else {
  366. return null;
  367. }
  368. String detailid = UUID.randomUUID().toString().replace("-", "");
  369. detailid = (detailid == null) ? ("uuid" + String.valueOf(System.currentTimeMillis())) : detailid;
  370. objectInfo.set("oppunit", null);//对方用户名
  371. objectInfo.set("oppbanknumber", null);//对方账号
  372. objectInfo.set("oppbank", null);//对方开户行
  373. objectInfo.set("detailid", detailid);//明细流水号
  374. objectInfo.set("bizrefno", detailid);//业务参考号
  375. objectInfo.set("uniqueseq", detailid + "01");//银行主键
  376. objectInfo.set("description", null);//摘要
  377. //判断此明细流水号是否已存在,已存在的记录不接收
  378. QFilter filterBizRefNo = new QFilter("detailid", QCP.equals, objectInfo.getString("detailid"));
  379. QFilter filterDataSource = new QFilter("datasource", QCP.equals, "import");
  380. QFilter[] filters = new QFilter[]{filterBizRefNo, filterDataSource};
  381. DynamicObject betransDetailInfo = BusinessDataServiceHelper.loadSingle(KEY_ENTITY_BETRANSDETAIL, "id, billno", filters);
  382. if (betransDetailInfo != null) {
  383. return null;
  384. }
  385. //交易时间
  386. objectInfo.set("bizTime", new Timestamp(time.getTime()));
  387. //交易日期
  388. objectInfo.set("bizdate", new Timestamp(date.getTime()));
  389. //入账状态
  390. objectInfo.set("receredtype", "0");
  391. //发生额
  392. objectInfo.set("debitamount", BigDecimal.ZERO);
  393. objectInfo.set("creditamount", BigDecimal.ZERO);
  394. String amountField = ParamsUtil.getAmountFieldName(direct);
  395. objectInfo.set(amountField, dayActAmt);
  396. //手续费
  397. // objectInfo.set("transfercharge", BigDecimal.ZERO);
  398. //余额
  399. objectInfo.set("transbalance", actBal);
  400. //单据状态
  401. objectInfo.set("billstatus", "A");
  402. //数据来源
  403. objectInfo.set("datasource", "import");
  404. //业务类型
  405. objectInfo.set("biztype", "1");
  406. //币别
  407. DynamicObjectCollection collection = kingdeeAcct.getDynamicObjectCollection("currency");
  408. Long currencyId = 0L;
  409. for (DynamicObject item : collection) {
  410. //引用该基础资料的单据id
  411. long pkid = item.getLong("pkid");
  412. // 获取该基础资料的动态对象
  413. DynamicObject fbasedataid = item.getDynamicObject("fbasedataid");
  414. //获取该基础资料的id
  415. currencyId = item.getLong("fbasedataid_id");
  416. }
  417. DynamicObject currency = BusinessDataServiceHelper.loadSingleFromCache(currencyId, "bd_currency");
  418. objectInfo.set("currency", currency);
  419. //银行账号
  420. objectInfo.set("accountbank", kingdeeAcct);
  421. objectInfo.set("bank", kingdeeAcct.get("bank"));
  422. objectInfo.set("company", kingdeeAcct.get("company"));
  423. CodeRuleInfo codeRule = CodeRuleServiceHelper.getCodeRule(objectInfo.getDataEntityType().getName(), objectInfo, null);
  424. String billno = CodeRuleServiceHelper.getNumber(codeRule, objectInfo);
  425. objectInfo.set("billno", billno);
  426. return objectInfo;
  427. }
  428. /**
  429. * 银行账户上一日余额
  430. *
  431. * @param acct
  432. * @return
  433. */
  434. private JSONObject queryLastBal(DynamicObject acct) {
  435. String code = "200";
  436. BigDecimal bal = BigDecimal.ZERO;
  437. SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
  438. //交易时间
  439. Date time = new Date();
  440. //交易日期
  441. Date date = null;
  442. try {
  443. date = sdf1.parse(sdf1.format(time));
  444. } catch (ParseException e) {
  445. throw new RuntimeException(e);
  446. }
  447. QFilter qFilter = new QFilter("accountbank.id", QCP.equals, acct.getLong("id"));
  448. qFilter.and(new QFilter("bizdate", QCP.less_than, date));
  449. String selectProperties = "transbalance";
  450. String orderBy = "biztime desc";
  451. DynamicObject[] detailList = BusinessDataServiceHelper.load(KEY_ENTITY_BETRANSDETAIL, selectProperties, qFilter.toArray(), orderBy);
  452. //如果没有交易明细,则查找是否有做出纳初始化初始余额
  453. if (detailList.length == 0) {
  454. qFilter = new QFilter("entrybank.bank_accountbank", QCP.equals, acct.getLong("id"));
  455. selectProperties = "entrybank.bank_journalbalance";
  456. orderBy = "startperiod.number desc";
  457. DynamicObjectCollection objCols = QueryServiceHelper.query(KEY_ENTITY_CASHINIT, selectProperties, qFilter.toArray(), orderBy);
  458. if (objCols.size() > 0) {
  459. code = "200";
  460. bal = objCols.get(0).getBigDecimal("entrybank.bank_journalbalance");
  461. }
  462. } else {
  463. code = "200";
  464. bal = detailList[0].getBigDecimal("transbalance");
  465. }
  466. JSONObject reslutData = new JSONObject();
  467. reslutData.put("code", code);
  468. reslutData.put("bal", bal);
  469. return reslutData;
  470. }
  471. /**
  472. * 同步当日交易明细
  473. *
  474. * @param accounts
  475. */
  476. private String synCurDetail(DynamicObject[] accounts) {
  477. //获取cbsurl //交易明细查询
  478. String cbsUrl = getCbsUrl("trandetail");
  479. if ("请前往《CBS支付参数设置》进行支付参数设置".equals(cbsUrl)) {
  480. return cbsUrl;
  481. }
  482. //构造post请求参数
  483. Map<String, String> header = new HashMap<>();
  484. header.put("Content-Type", "application/json; charset=UTF-8");
  485. Map<String, Object> params = new HashMap<>();
  486. Map<String, Object> body = new HashMap<>();
  487. Date startDate = (Date) this.getModel().getValue("startDate");
  488. Date endDate = (Date) this.getModel().getValue("endDate");
  489. body.put("startDate", DateFormatUtils.format(startDate, "yyyy-MM-dd"));
  490. body.put("endDate", DateFormatUtils.format(endDate, "yyyy-MM-dd"));
  491. body.put("dateType", "0");
  492. List<String> bankaccountnumberList = Arrays.stream(accounts).map(e -> e.getString("bankaccountnumber")).collect(Collectors.toList());
  493. body.put("accountNoList", bankaccountnumberList);
  494. //body.put("currentFlag", "1");
  495. //分页查询参数
  496. body.put("currentPage", 1);
  497. body.put("pageSize", 100);
  498. params.put("params", body);
  499. //保存CBS调用日志
  500. String uuid = ParamsUtil.saveCBSLogData(cbsUrl, "detail", JSON.toJSONString(params));
  501. String sTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  502. logger.info("调用CBS接口交易明细查询开始时间:" + sTime);
  503. String resultStr;
  504. try {
  505. resultStr = KHttpClientUtils.postjson(cbsUrl, header, JSON.toJSONString(params));
  506. } catch (IOException e) {
  507. throw new KDBizException("调用CBS交易明细接口错误" + e);
  508. }
  509. String eTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  510. logger.info("调用CBS接口交易明细查询结束时间:" + eTime);
  511. //更新CBS调用日志
  512. ParamsUtil.updateCBSLogData(uuid, resultStr);
  513. //转换cbs的返回数据
  514. if (StringUtils.isNotEmpty(resultStr)) {
  515. StringBuilder errMsg = new StringBuilder();
  516. return saveCurDetailData(resultStr, cbsUrl, header, params, errMsg);
  517. } else {
  518. return "分页查询第" + 1 + "次查询CBS接口交易明细查询未获取到记录";
  519. }
  520. }
  521. /**
  522. * 保存交易明细
  523. *
  524. * @param resultstr
  525. * @param cbsUrl
  526. * @param header
  527. * @param params
  528. * @param errMsg
  529. * @return
  530. */
  531. private String saveCurDetailData(String resultstr, String cbsUrl, Map<String, String> header, Map<String, Object> params, StringBuilder errMsg) {
  532. JSONObject cbsObj = JSON.parseObject(resultstr);
  533. if (200 != cbsObj.getInteger("code")) {
  534. return cbsObj.get("msg").toString();
  535. }
  536. JSONObject data = (JSONObject) cbsObj.get("data");
  537. JSONObject dataList = (JSONObject) data.get("data");
  538. JSONArray array = (JSONArray) dataList.get("list");
  539. if (array.size() > 0) {
  540. List<DynamicObject> listObj = new ArrayList<>();
  541. int count = 0;
  542. for (int i = 0; i < array.size(); i++) {
  543. DynamicObject detailInfo = null;
  544. try {
  545. detailInfo = parseCurBetransDetail(array.getJSONObject(i));
  546. } catch (ParseException e) {
  547. throw new KDBizException("CBS返回数据转换未交易明细单据对象错误" + e);
  548. }
  549. if (detailInfo != null) {
  550. listObj.add(detailInfo);
  551. }
  552. count++;
  553. //满足100条就先批量保存一批
  554. if (listObj.size() > 0 && count == 100) {
  555. count = 0;
  556. OperationResult resultSave = OperationServiceHelper.executeOperate(KEY_OP_SAVE, KEY_ENTITY_BETRANSDETAIL, listObj.toArray(new DynamicObject[]{}), OperateOption.create());
  557. if (resultSave.getAllErrorOrValidateInfo().size() > 0) {
  558. for (int index = 0; index < resultSave.getAllErrorOrValidateInfo().size(); index++) {
  559. String message = resultSave.getAllErrorOrValidateInfo().get(index).getMessage();
  560. errMsg.append("/r/n").append(message);
  561. }
  562. }
  563. listObj.clear();
  564. }
  565. }
  566. //批量保存
  567. if (listObj.size() > 0) {
  568. OperationResult resultSave = OperationServiceHelper.executeOperate(KEY_OP_SAVE, KEY_ENTITY_BETRANSDETAIL, listObj.toArray(new DynamicObject[]{}), OperateOption.create());
  569. if (resultSave.getAllErrorOrValidateInfo().size() > 0) {
  570. for (int index = 0; index < resultSave.getAllErrorOrValidateInfo().size(); index++) {
  571. String message = resultSave.getAllErrorOrValidateInfo().get(index).getMessage();
  572. errMsg.append("/r/n").append(message);
  573. }
  574. }
  575. }
  576. }
  577. //判断是不是最后一页,否继续查询
  578. if (dataList.get("isLastPage") != null && !dataList.getBoolean("isLastPage")) {
  579. Map<String, Object> body = (Map) params.get("params");
  580. int currentPage = (int) body.get("currentPage") + 1;
  581. body.put("currentPage", currentPage);
  582. //保存CBS调用日志
  583. String uuid = ParamsUtil.saveCBSLogData(cbsUrl, "detail", JSON.toJSONString(params));
  584. String sTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  585. logger.info("调用CBS接口交易明细查询开始时间:" + sTime);
  586. String sr = "";
  587. try {
  588. Map<String, Object> params1 = new HashMap<>();
  589. params1.put("params", body);
  590. sr = KHttpClientUtils.postjson(cbsUrl, header, JSON.toJSONString(params1));
  591. } catch (IOException e) {
  592. throw new KDBizException("调用CBS交易明细接口错误" + e);
  593. }
  594. String eTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  595. logger.info("调用CBS接口交易明细查询结束时间:" + eTime);
  596. //更新CBS调用日志
  597. ParamsUtil.updateCBSLogData(uuid, sr);
  598. if (StringUtils.isNotEmpty(sr)) {
  599. saveCurDetailData(sr, cbsUrl, header, params, errMsg);
  600. } else {
  601. errMsg.append("/r/n").append("分页查询第" + currentPage + "次查询CBS接口交易明细查询未获取到记录").toString();
  602. }
  603. }
  604. if (errMsg.length() > 0) {
  605. return errMsg.toString();
  606. }
  607. return "同步成功";
  608. }
  609. /**
  610. * 组装当日交易明细info
  611. *
  612. * @param cbsObj
  613. * @return
  614. * @throws ParseException
  615. */
  616. private DynamicObject parseCurBetransDetail(JSONObject cbsObj) throws ParseException {
  617. //不接收情况:交易额为空、余额为空、当日明细流水号为空
  618. if (StringUtils.isEmpty(cbsObj.getString("incurredAmount"))
  619. || StringUtils.isEmpty(cbsObj.getString("accountBalance"))
  620. || StringUtils.isEmpty(cbsObj.getString("transactionSerialNumber"))) {
  621. return null;
  622. }
  623. String accountNumber = cbsObj.getString("accountNo");
  624. QFilter filterNumber = new QFilter("bankaccountnumber", QCP.equals, accountNumber);
  625. QFilter[] filters = new QFilter[]{filterNumber};
  626. DynamicObject account = BusinessDataServiceHelper.loadSingleFromCache("bd_accountbanks", filters);
  627. if (account == null) {
  628. return null;
  629. }
  630. //处理日期类字段
  631. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  632. SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
  633. SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss");
  634. //交易时间
  635. Date bankTransactionDate = new Date(cbsObj.getLong("bankTransactionDate"));
  636. String formatDate = sdf.format(bankTransactionDate);
  637. Date time = sdf.parse(formatDate);
  638. //交易日期
  639. Date date = sdf1.parse(formatDate);
  640. //更新时间
  641. //Date updateTime = sdf2.parse(cbsObj.getString("UPDTIM")); //----------------------------
  642. //如果交易日期与当前日期不一致则不接收
  643. Date curDate = new Date();
  644. if (!sdf1.format(time).equals(sdf1.format(curDate))) {
  645. return null;
  646. }
  647. //如果当天存在根据余额生成的交易明细,则不增加交易明细
  648. Boolean isExistDetail = ParamsUtil.isExistsDetail(account, date, new String[]{"balancecompare"});
  649. if (isExistDetail) {
  650. return null;
  651. }
  652. DynamicObject objectInfo = BusinessDataServiceHelper.newDynamicObject(KEY_ENTITY_BETRANSDETAIL);
  653. objectInfo.set("accountbank", account);//银行账户
  654. objectInfo.set("bank", account.get("bank"));//开户行
  655. objectInfo.set("company", account.get("company"));//资金组织
  656. objectInfo.set("nckd_generatemethod", "curday");
  657. //处理文本类字段
  658. //ParamsUtil.BetransDetailFieldStringMap.forEach((key, value) -> {
  659. // objectInfo.set(value, cbsObj.getString(key));
  660. //});
  661. objectInfo.set("oppunit", cbsObj.getString("oppositeName"));//对方用户名
  662. objectInfo.set("oppbanknumber", cbsObj.getString("oppositeAccount"));//对方账号
  663. objectInfo.set("oppbank", cbsObj.getString("oppositeOpeningBank"));//对方开户行
  664. //objectInfo.set(, "detailid",cbsObj.getString("BNKFLW"));//明细流水号
  665. objectInfo.set("bizrefno", cbsObj.getString("erpSerialNumber"));//业务参考号
  666. //objectInfo.set("description", cbsObj.getString("digest"));//摘要
  667. objectInfo.set("nckd_dtlseq", cbsObj.getString("transactionSerialNumber"));//交易流水号
  668. objectInfo.set("nckd_cbsbnkflw", cbsObj.getString("bankSerialNumber"));//银行流水号
  669. //objectInfo.set("nckd_cbsoriseq", cbsObj.getString("ORISEQ"));//原始流水号----------------------
  670. //objectInfo.set("nckd_cbspaynbr", cbsObj.getString("PAYNBR"));//结算业务流水号--------------------
  671. //objectInfo.set("nckd_cbserpnbr", cbsObj.getString("ERPNBR"));//结算业务参考号----------------------
  672. //objectInfo.set("nckd_cbsrefcod", cbsObj.getString("REFCOD"));//业务参考号----------------------
  673. //当日交易明细使用DTLSEQ做为唯一值
  674. String detailId = cbsObj.getString("transactionSerialNumber");
  675. String uniqueseq = detailId + "-01";
  676. //判断此银行主键是否已存在,已存在的记录不接收
  677. QFilter filter = new QFilter("uniqueseq", QCP.equals, uniqueseq);
  678. filter.or(new QFilter("detailid", QCP.equals, detailId));
  679. DynamicObject betransDetailInfo = BusinessDataServiceHelper.loadSingle(KEY_ENTITY_BETRANSDETAIL, "id, billno", filter.toArray());
  680. if (betransDetailInfo != null) {
  681. return null;
  682. }
  683. //明细流水号
  684. objectInfo.set("detailid", detailId);
  685. //银行主键
  686. objectInfo.set("uniqueseq", uniqueseq);
  687. Long dtlseq = Long.valueOf(cbsObj.getString("transactionSerialNumber"));
  688. objectInfo.set("sortno", dtlseq);
  689. String usage = cbsObj.getString("digest") == null ? "" : cbsObj.getString("digest");
  690. String description = objectInfo.getString("description") == null ? "" : objectInfo.getString("description");
  691. description = description.concat(usage);
  692. objectInfo.set("description", description);
  693. //cbs更新时间
  694. //objectInfo.set("nckd_cbsbiztime", new Timestamp(updateTime.getTime()));---------------------------------
  695. //交易时间
  696. objectInfo.set("bizTime", new Timestamp(time.getTime()));
  697. //交易日期
  698. objectInfo.set("bizdate", new Timestamp(date.getTime()));
  699. //处理数字类字段
  700. //借贷方向:1:借方,2:贷方
  701. String direct = cbsObj.getString("loanType");
  702. //入账状态
  703. objectInfo.set("receredtype", "0");
  704. //发生额
  705. String amountField = ParamsUtil.getAmountFieldName(direct);
  706. objectInfo.set(amountField, getBigDecimal(cbsObj.get("incurredAmount")));
  707. //手续费
  708. //objectInfo.set("transfercharge", getBigDecimal(cbsObj.get("SERFEE")));---------------------------------------
  709. //余额
  710. objectInfo.set("transbalance", getBigDecimal(cbsObj.get("accountBalance")));
  711. //单据状态
  712. objectInfo.set("billstatus", "A");
  713. //数据来源
  714. objectInfo.set("datasource", "import");
  715. //业务类型
  716. //String bizType = ParamsUtil.getBizType(cbsObj.getString("PTCTYP")); ----------------------------------------
  717. /*objectInfo.set("biztype", bizType);
  718. //上划
  719. if ("2".equals(bizType)) {
  720. objectInfo.set("istransup", "1");
  721. }
  722. //下拨
  723. if ("3".equals(bizType)) {
  724. objectInfo.set("istransdown", "1");
  725. }*/
  726. //币别
  727. filterNumber = new QFilter("number", QCP.equals, ParamsUtil.CurrencyMap.get(cbsObj.getString("currency")));
  728. filters = new QFilter[]{filterNumber};
  729. DynamicObject currency = BusinessDataServiceHelper.loadSingleFromCache("bd_currency", filters);
  730. objectInfo.set("currency", currency);
  731. CodeRuleInfo codeRule = CodeRuleServiceHelper.getCodeRule(objectInfo.getDataEntityType().getName(), objectInfo, null);
  732. String billno = CodeRuleServiceHelper.getNumber(codeRule, objectInfo);
  733. objectInfo.set("billno", billno);
  734. return objectInfo;
  735. }
  736. /**
  737. * 同步历史交易明细
  738. *
  739. * @param accounts
  740. * @param startDate
  741. * @param endDate
  742. */
  743. private String synHisDetail(DynamicObject[] accounts, Date startDate, Date endDate) {
  744. //获取cbsurl //交易明细查询
  745. String cbsUrl = getCbsUrl("trandetail");
  746. if ("请前往《CBS支付参数设置》进行支付参数设置".equals(cbsUrl)) {
  747. return cbsUrl;
  748. }
  749. Map<String, String> header = new HashMap<>();
  750. header.put("Content-Type", "application/json; charset=UTF-8");
  751. Map<String, Object> params = new HashMap<>();
  752. Map<String, Object> body = new HashMap<>();
  753. body.put("startDate", DateFormatUtils.format(startDate, "yyyy-MM-dd"));
  754. body.put("endDate", DateFormatUtils.format(endDate, "yyyy-MM-dd"));
  755. body.put("dateType", "0");
  756. List<String> bankaccountnumberList = Arrays.stream(accounts).map(e -> e.getString("bankaccountnumber")).collect(Collectors.toList());
  757. body.put("accountNoList", bankaccountnumberList);
  758. //body.put("currentFlag", "2");
  759. //分页查询参数
  760. body.put("currentPage", 1);
  761. body.put("pageSize", 100);
  762. params.put("params", body);
  763. //保存CBS调用日志
  764. String uuid = ParamsUtil.saveCBSLogData(cbsUrl, "detail", JSON.toJSONString(params));
  765. String sTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  766. logger.info("调用CBS接口交易明细查询开始时间:" + sTime);
  767. String resultstr;
  768. try {
  769. resultstr = KHttpClientUtils.postjson(cbsUrl, header, JSON.toJSONString(params));
  770. } catch (IOException e) {
  771. throw new KDBizException("调用CBS交易明细接口错误" + e);
  772. }
  773. String eTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  774. logger.info("调用CBS接口交易明细查询结束时间:" + eTime);
  775. //更新CBS调用日志
  776. ParamsUtil.updateCBSLogData(uuid, resultstr);
  777. if (StringUtils.isNotEmpty(resultstr)) {
  778. StringBuilder errMsg = new StringBuilder();
  779. return saveHisDetailData(resultstr, cbsUrl, header, params, errMsg);
  780. } else {
  781. return "分页查询第" + 1 + "次查询CBS接口交易明细查询未获取到记录";
  782. }
  783. }
  784. /**
  785. * 保存历史交易明细
  786. *
  787. * @param resultstr
  788. * @param cbsUrl
  789. * @param header
  790. * @param params
  791. * @param errMsg
  792. * @return
  793. */
  794. private String saveHisDetailData(String resultstr, String cbsUrl, Map<String, String> header, Map<String, Object> params, StringBuilder errMsg) {
  795. JSONObject cbsObj = JSON.parseObject(resultstr);
  796. if (200 != cbsObj.getInteger("code")) {
  797. return cbsObj.get("msg").toString();
  798. }
  799. JSONObject data = (JSONObject) cbsObj.get("data");
  800. JSONObject dataList = (JSONObject) data.get("data");
  801. JSONArray array = (JSONArray) dataList.get("list");
  802. if (array.size() > 0) {
  803. List<DynamicObject> listObj = new ArrayList<>();
  804. int count = 0;
  805. for (int i = 0; i < array.size(); i++) {
  806. DynamicObject detailInfo = null;
  807. try {
  808. detailInfo = parseHistoryBetransDetail(array.getJSONObject(i));
  809. } catch (ParseException e) {
  810. throw new KDBizException("CBS返回数据转换未交易明细单据对象错误" + e);
  811. }
  812. if (detailInfo != null) {
  813. listObj.add(detailInfo);
  814. }
  815. count++;
  816. //批量保存
  817. if (listObj.size() > 0 && count == 100) {
  818. count = 0;
  819. OperationResult resultSave = OperationServiceHelper.executeOperate(KEY_OP_SAVE, KEY_ENTITY_BETRANSDETAIL, listObj.toArray(new DynamicObject[]{}), OperateOption.create());
  820. if (resultSave.getAllErrorOrValidateInfo().size() > 0) {
  821. for (int index = 0; index < resultSave.getAllErrorOrValidateInfo().size(); index++) {
  822. String message = resultSave.getAllErrorOrValidateInfo().get(index).getMessage();
  823. errMsg.append("/r/n").append(message);
  824. }
  825. }
  826. listObj.clear();
  827. }
  828. }
  829. //批量保存
  830. if (listObj.size() > 0) {
  831. OperationResult resultSave = OperationServiceHelper.executeOperate(KEY_OP_SAVE, KEY_ENTITY_BETRANSDETAIL, listObj.toArray(new DynamicObject[]{}), OperateOption.create());
  832. if (resultSave.getAllErrorOrValidateInfo().size() > 0) {
  833. for (int index = 0; index < resultSave.getAllErrorOrValidateInfo().size(); index++) {
  834. String message = resultSave.getAllErrorOrValidateInfo().get(index).getMessage();
  835. errMsg.append("/r/n").append(message);
  836. }
  837. }
  838. }
  839. }
  840. //判断是不是最后一页,否继续查询
  841. if (dataList.get("isLastPage") != null && !dataList.getBoolean("isLastPage")) {
  842. Map<String, Object> body = (Map) params.get("params");
  843. int currentPage = (int) body.get("currentPage") + 1;
  844. body.put("currentPage", currentPage);
  845. //保存CBS调用日志
  846. String uuid = ParamsUtil.saveCBSLogData(cbsUrl, "detail", JSON.toJSONString(params));
  847. String sTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  848. logger.info("调用CBS接口交易明细查询开始时间:" + sTime);
  849. String sr;
  850. try {
  851. Map<String, Object> params1 = new HashMap<>();
  852. params1.put("params", body);
  853. sr = KHttpClientUtils.postjson(cbsUrl, header, JSON.toJSONString(params1));
  854. } catch (IOException e) {
  855. throw new KDBizException("调用CBS交易明细接口错误" + e);
  856. }
  857. String eTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  858. logger.info("调用CBS接口交易明细查询结束时间:" + eTime);
  859. //更新CBS调用日志
  860. ParamsUtil.updateCBSLogData(uuid, sr);
  861. if (StringUtils.isNotEmpty(sr)) {
  862. saveHisDetailData(sr, cbsUrl, header, params, errMsg);
  863. } else {
  864. errMsg.append("/r/n").append("分页查询第" + currentPage + "次查询CBS接口交易明细查询未获取到记录").toString();
  865. }
  866. }
  867. if (errMsg.length() > 0) {
  868. return errMsg.toString();
  869. }
  870. return "同步成功";
  871. }
  872. /**
  873. * 组装历史交易明细info
  874. *
  875. * @param cbsObj
  876. * @return
  877. * @throws ParseException
  878. */
  879. private DynamicObject parseHistoryBetransDetail(JSONObject cbsObj) throws ParseException {
  880. //不接收情况:交易额为空、余额为空、当日明细流水号为空
  881. if (StringUtils.isEmpty(cbsObj.getString("incurredAmount"))
  882. || StringUtils.isEmpty(cbsObj.getString("accountBalance"))
  883. || StringUtils.isEmpty(cbsObj.getString("transactionSerialNumber"))) {
  884. return null;
  885. }
  886. String accountNumber = cbsObj.getString("accountNo");
  887. QFilter filterNumber = new QFilter("bankaccountnumber", QCP.equals, accountNumber);
  888. QFilter[] filters = new QFilter[]{filterNumber};
  889. DynamicObject account = BusinessDataServiceHelper.loadSingleFromCache("bd_accountbanks", filters);
  890. if (account == null) {
  891. return null;
  892. }
  893. //处理日期类字段
  894. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  895. SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
  896. SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss");
  897. //交易时间
  898. Date bankTransactionDate = new Date(cbsObj.getLong("bankTransactionDate"));
  899. String formatDate = sdf.format(bankTransactionDate);
  900. Date time = sdf.parse(formatDate);
  901. //交易日期
  902. Date date = sdf1.parse(formatDate);
  903. //更新时间
  904. //Date updateTime = sdf2.parse(cbsObj.getString("UPDTIM")); //----------------------------
  905. //如果当天存在根据余额生成的交易明细,则不增加交易明细
  906. Boolean isExistDetail = ParamsUtil.isExistsDetail(account, date, new String[]{"balancecompare"});
  907. if (isExistDetail) {
  908. return null;
  909. }
  910. DynamicObject objectInfo = BusinessDataServiceHelper.newDynamicObject(KEY_ENTITY_BETRANSDETAIL);
  911. objectInfo.set("accountbank", account);//银行账户
  912. objectInfo.set("bank", account.get("bank"));//开户行
  913. objectInfo.set("company", account.get("company"));//资金组织
  914. objectInfo.set("nckd_generatemethod", "history");
  915. //处理文本类字段
  916. //ParamsUtil.BetransDetailFieldStringMap.forEach((key, value) -> {
  917. // objectInfo.set(value, cbsObj.getString(key));
  918. //});
  919. objectInfo.set("oppunit", cbsObj.getString("oppositeName"));//对方用户名
  920. objectInfo.set("oppbanknumber", cbsObj.getString("oppositeAccount"));//对方账号
  921. objectInfo.set("oppbank", cbsObj.getString("oppositeOpeningBank"));//对方开户行
  922. //objectInfo.set(, "detailid",cbsObj.getString("BNKFLW"));//明细流水号
  923. objectInfo.set("bizrefno", cbsObj.getString("erpSerialNumber"));//业务参考号
  924. //objectInfo.set("description", cbsObj.getString("digest"));//摘要
  925. objectInfo.set("nckd_dtlseq", cbsObj.getString("transactionSerialNumber"));//交易流水号
  926. objectInfo.set("nckd_cbsbnkflw", cbsObj.getString("bankSerialNumber"));//银行流水号
  927. //objectInfo.set("nckd_cbsoriseq", cbsObj.getString("ORISEQ"));//原始流水号----------------------
  928. //objectInfo.set("nckd_cbspaynbr", cbsObj.getString("PAYNBR"));//结算业务流水号--------------------
  929. //objectInfo.set("nckd_cbserpnbr", cbsObj.getString("ERPNBR"));//结算业务参考号----------------------
  930. //objectInfo.set("nckd_cbsrefcod", cbsObj.getString("REFCOD"));//业务参考号----------------------
  931. //历史交易明细使用CURSEQ做为唯一值,对应当日交易明细的DTLSEQ
  932. String detailId = cbsObj.getString("transactionSerialNumber");
  933. String uniqueseq = detailId + "-01";
  934. //判断此银行主键是否已存在,已存在的记录不接收
  935. QFilter filter = new QFilter("uniqueseq", QCP.equals, uniqueseq);
  936. filter.or(new QFilter("detailid", QCP.equals, detailId));
  937. DynamicObject betransDetailInfo = BusinessDataServiceHelper.loadSingle(KEY_ENTITY_BETRANSDETAIL, "id, billno", filter.toArray());
  938. if (betransDetailInfo != null) {
  939. return null;
  940. }
  941. //明细流水号
  942. objectInfo.set("detailid", detailId);
  943. //银行主键
  944. objectInfo.set("uniqueseq", uniqueseq);
  945. Long dtlseq = Long.valueOf(cbsObj.getString("transactionSerialNumber"));
  946. objectInfo.set("sortno", dtlseq);
  947. String usage = cbsObj.getString("digest") == null ? "" : cbsObj.getString("digest");
  948. String description = objectInfo.getString("description") == null ? "" : objectInfo.getString("description");
  949. description = description.concat(usage);
  950. objectInfo.set("description", description);
  951. //cbs更新时间
  952. //objectInfo.set("nckd_cbsbiztime", new Timestamp(updateTime.getTime()));---------------------------------
  953. //交易时间
  954. objectInfo.set("bizTime", new Timestamp(time.getTime()));
  955. //交易日期
  956. objectInfo.set("bizdate", new Timestamp(date.getTime()));
  957. //处理数字类字段
  958. //借贷方向:1:借方,2:贷方
  959. String direct = cbsObj.getString("loanType");
  960. //入账状态
  961. objectInfo.set("receredtype", "0");
  962. //发生额
  963. String amountField = ParamsUtil.getAmountFieldName(direct);
  964. objectInfo.set(amountField, getBigDecimal(cbsObj.get("incurredAmount")));
  965. //手续费
  966. //objectInfo.set("transfercharge", getBigDecimal(cbsObj.get("SERFEE")));---------------------------------------
  967. //余额
  968. objectInfo.set("transbalance", getBigDecimal(cbsObj.get("accountBalance")));
  969. //单据状态
  970. objectInfo.set("billstatus", "A");
  971. //数据来源
  972. objectInfo.set("datasource", "import");
  973. //业务类型
  974. //String bizType = ParamsUtil.getBizType(cbsObj.getString("PTCTYP")); ----------------------------------------
  975. /*objectInfo.set("biztype", bizType);
  976. //上划
  977. if ("2".equals(bizType)) {
  978. objectInfo.set("istransup", "1");
  979. }
  980. //下拨
  981. if ("3".equals(bizType)) {
  982. objectInfo.set("istransdown", "1");
  983. }*/
  984. //币别
  985. filterNumber = new QFilter("number", QCP.equals, ParamsUtil.CurrencyMap.get(cbsObj.getString("currency")));
  986. filters = new QFilter[]{filterNumber};
  987. DynamicObject currency = BusinessDataServiceHelper.loadSingleFromCache("bd_currency", filters);
  988. objectInfo.set("currency", currency);
  989. CodeRuleInfo codeRule = CodeRuleServiceHelper.getCodeRule(objectInfo.getDataEntityType().getName(), objectInfo, null);
  990. String billno = CodeRuleServiceHelper.getNumber(codeRule, objectInfo);
  991. objectInfo.set("billno", billno);
  992. return objectInfo;
  993. }
  994. public CustomApiResult<JSONObject> returnResult(String code, String message) {
  995. JSONObject reslutData = new JSONObject();
  996. reslutData.put("code", code);
  997. reslutData.put("message", message);
  998. CustomApiResult<JSONObject> result = CustomApiResult.success(reslutData);
  999. return result;
  1000. }
  1001. /**
  1002. * 获取组织下的所有银行账号
  1003. *
  1004. * @return
  1005. */
  1006. public DynamicObject[] getSelectAccounts(String method) {
  1007. logger.info("获取组织下的所有银行账号开始" + method);
  1008. IDataModel model = this.getModel();
  1009. DynamicObjectCollection orgs = model.getDataEntity().getDynamicObjectCollection("nckd_org");
  1010. List<Long> orgIds = (List) orgs.stream().map((s) -> {
  1011. return s.getDynamicObject("fbasedataid").getLong("id");
  1012. }).collect(Collectors.toList());
  1013. DynamicObjectCollection accountBanks = model.getDataEntity().getDynamicObjectCollection("nckd_accountbank");
  1014. List accountBankIds;
  1015. QFilter qFilter;
  1016. if (EmptyUtil.isEmpty(accountBanks)) {
  1017. qFilter = SyncAutoBalanceHelper.getAccountBankQfilter(orgIds);
  1018. if ("balance".equals(method)) {
  1019. qFilter.and(new QFilter("nckd_issetcbs", QCP.equals, false));
  1020. }
  1021. accountBanks = QueryServiceHelper.query("bd_accountbanks", "id", qFilter.toArray());
  1022. accountBankIds = (List) accountBanks.stream().map((s) -> {
  1023. return s.getLong("id");
  1024. }).collect(Collectors.toList());
  1025. } else {
  1026. accountBankIds = (List) accountBanks.stream().map((s) -> {
  1027. return s.getDynamicObject("fbasedataid").getLong("id");
  1028. }).collect(Collectors.toList());
  1029. }
  1030. logger.info("获取组织下的所有银行账号accountBankIds" + accountBankIds.toString());
  1031. DynamicObjectType type = EntityMetadataCache.getDataEntityType("am_accountbank");
  1032. DynamicObject[] accountBankList = BusinessDataServiceHelper.load(accountBankIds.toArray(new Object[accountBankIds.size()]), type);
  1033. // logger.info("获取组织下的所有银行账号accountBankList" + JSON.toJSONString(accountBankList));
  1034. return accountBankList;
  1035. }
  1036. /**
  1037. * 获取cbs接口在中台的配置的接口地址
  1038. *
  1039. * @return
  1040. */
  1041. private String getCbsUrl(String key) {
  1042. //获取CBS支付参数设置 的 接口地址 域名 appkey
  1043. QFilter qFilter = new QFilter("number", QCP.equals, "cbs-20241015001");
  1044. DynamicObject cbspaysetting = BusinessDataServiceHelper.loadSingle("nckd_cbspaysetting", "id,name,nckd_yuming,nckd_appkey,nckd_entryentity.nckd_interfacenbr,nckd_entryentity.nckd_interfacename,nckd_entryentity.nckd_interfaceurl", qFilter.toArray());
  1045. if (ObjectUtils.isEmpty(cbspaysetting)) {
  1046. return "请前往《CBS支付参数设置》进行支付参数设置";
  1047. }
  1048. //域名
  1049. String yuming = cbspaysetting.getString("nckd_yuming");
  1050. //appkey
  1051. String appkey = cbspaysetting.getString("nckd_appkey");
  1052. DynamicObjectCollection entryentity = cbspaysetting.getDynamicObjectCollection("nckd_entryentity");
  1053. //获取的接口地址转换为map
  1054. //转成 key nckd_interfacenbr value nckd_interfaceurl
  1055. Map<String, String> mapentity = entryentity.stream().collect(Collectors.toMap(k -> k.getString("nckd_interfacenbr"), v -> v.getString("nckd_interfaceurl")));
  1056. //交易明细接口地址
  1057. String interfaceurl = mapentity.get(key);
  1058. String cbsUrl = yuming + interfaceurl + "?appKey=" + appkey;
  1059. return cbsUrl;
  1060. }
  1061. /**
  1062. * @param objValue
  1063. * @return
  1064. */
  1065. private BigDecimal getBigDecimal(Object objValue) {
  1066. BigDecimal ret = null;
  1067. if (objValue == null || objValue.equals("")) {
  1068. return BigDecimal.ZERO;
  1069. }
  1070. if (objValue instanceof BigDecimal) {
  1071. ret = (BigDecimal) objValue;
  1072. } else if (objValue instanceof String) {
  1073. ret = new BigDecimal((String) objValue);
  1074. } else if (objValue instanceof BigInteger) {
  1075. ret = new BigDecimal((BigInteger) objValue);
  1076. } else if (objValue instanceof Number) {
  1077. ret = new BigDecimal(((Number) objValue).doubleValue());
  1078. } else {
  1079. throw new ClassCastException("Not possible to coerce [" + objValue + "] from class " + objValue.getClass() + " into a BigDecimal.");
  1080. }
  1081. return ret;
  1082. }
  1083. /**
  1084. * 同步CBS是否开通银企直连平台状态到银行账户
  1085. *
  1086. * @return
  1087. */
  1088. private String synAccountOpenStatus(List<Long> accountIds) {
  1089. String selectFields = "id, number, nckd_issetcbs, openorg";
  1090. QFilter qFilter = new QFilter("issetbankinterface", "=", "0");
  1091. qFilter.and("isvirtual", "=", "0");
  1092. qFilter.and("finorgtype", "!=", FinOrgTypeEnum.CLEARINGHOUSE.getValue());
  1093. qFilter.and("nckd_issetcbs", "=", "0");
  1094. if (accountIds != null && accountIds.size() > 0) {
  1095. qFilter.and("id", "in", accountIds);
  1096. }
  1097. DynamicObject[] accounts = BusinessDataServiceHelper.load("am_accountbank", selectFields, new QFilter[]{qFilter});
  1098. if (accounts.length > 0) {
  1099. List<DynamicObject> listObj = new ArrayList<>();
  1100. //获取cbsurl 账户列表查询
  1101. String cbsUrl = getCbsUrl("accountlist");
  1102. if ("请前往《CBS支付参数设置》进行支付参数设置".equals(cbsUrl)) {
  1103. return cbsUrl;
  1104. }
  1105. Map<String, String> header = new HashMap<>();
  1106. header.put("Content-Type", "application/json; charset=UTF-8");
  1107. Map<String, Object> params = new HashMap<>();
  1108. Map<String, Object> body = new HashMap<>();
  1109. //分页查询参数
  1110. body.put("currentPage", 1);
  1111. body.put("pageSize", 100);
  1112. params.put("params", body);
  1113. for (DynamicObject account : accounts) {
  1114. body.put("accountNo", account.getString("bankaccountnumber"));
  1115. //保存CBS调用日志
  1116. String uuid = ParamsUtil.saveCBSLogData(cbsUrl, "synstatus", JSON.toJSONString(params));
  1117. String sTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  1118. logger.info("调用CBS接口账户列表查询开始时间:" + sTime);
  1119. String resultstr;
  1120. try {
  1121. resultstr = KHttpClientUtils.postjson(cbsUrl, header, JSON.toJSONString(params));
  1122. } catch (IOException e) {
  1123. throw new KDBizException("调用CBS账户列表查询接口错误" + e);
  1124. }
  1125. String eTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
  1126. logger.info("调用CBS接口账户列表查询结束时间:" + eTime);
  1127. //更新CBS调用日志
  1128. ParamsUtil.updateCBSLogData(uuid, resultstr);
  1129. //校验CBS系统中账户是否开通银企直连平台
  1130. Boolean isOpenCBS = checkAccountOpenStatus(resultstr);
  1131. if (isOpenCBS) {
  1132. account.set("nckd_issetcbs", true);
  1133. listObj.add(account);
  1134. }
  1135. }
  1136. if (listObj.size() > 0) {
  1137. Object[] saveResult = SaveServiceHelper.save(listObj.toArray(new DynamicObject[]{}));
  1138. if (saveResult == null || saveResult.length <= 0) {
  1139. logger.info("更新银行账户中的开通CBS银企接口字段失败");
  1140. return "更新银行账户中的开通CBS银企接口字段失败";
  1141. }
  1142. }
  1143. }
  1144. return null;
  1145. }
  1146. /**
  1147. * 校验CBS系统中账户是否开通银企直连平台
  1148. *
  1149. * @param cbssr
  1150. * @return
  1151. */
  1152. private Boolean checkAccountOpenStatus(String cbssr) {
  1153. JSONObject cbsObj = JSON.parseObject(cbssr);
  1154. if (200 != cbsObj.getInteger("code")) {
  1155. return false;
  1156. }
  1157. JSONObject data = (JSONObject) cbsObj.get("data");
  1158. JSONObject dataList = (JSONObject) data.get("data");
  1159. JSONArray array = (JSONArray) dataList.get("list");
  1160. if (array.size() > 0) {
  1161. JSONObject cbsAcct = array.getJSONObject(0);
  1162. if ("9".equals(cbsAcct.getString("directConnectFlag"))) {
  1163. return true;
  1164. }
  1165. }
  1166. return false;
  1167. }
  1168. }