package kd.cosmic.jkjt.tmc.api; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import kd.bos.coderule.api.CodeRuleInfo; import kd.bos.dataentity.OperateOption; import kd.bos.dataentity.entity.DynamicObject; import kd.bos.dataentity.entity.DynamicObjectCollection; import kd.bos.entity.operate.result.OperationResult; import kd.bos.logging.Log; import kd.bos.logging.LogFactory; import kd.bos.openapi.common.custom.annotation.ApiController; import kd.bos.openapi.common.custom.annotation.ApiPostMapping; import kd.bos.openapi.common.result.CustomApiResult; import kd.bos.orm.query.QCP; import kd.bos.orm.query.QFilter; import kd.bos.servicehelper.BusinessDataServiceHelper; import kd.bos.servicehelper.QueryServiceHelper; import kd.bos.servicehelper.coderule.CodeRuleServiceHelper; import kd.bos.servicehelper.operation.OperationServiceHelper; import kd.bos.util.StringUtils; import kd.cosmic.jkjt.tmc.util.CBSToolUtil; import kd.cosmic.jkjt.tmc.util.ParamsUtil; import kd.cosmic.jkjt.tmc.util.XmlUtils; import org.apache.commons.lang.time.DateFormatUtils; import java.io.Serializable; import java.math.BigDecimal; import java.sql.Timestamp; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; /** * @author wanghaiwu_kd * @date 2023/05/08 * @description API插件,未开通银企直连的账户,根据CBS系统的账户余额,与星瀚中的余额比较,如果有差额,则自动生成交易明细。 */ @ApiController( desc = "未开通银企直连的账户根据CBS账户余额生产交易明细", value = "jkjt_cbsapi" ) public class SynBentransByBalance2Plugin implements Serializable { private static final long serialVersionUID = -5560815141256121757L; private static Log logger = LogFactory.getLog(SynBentransByBalance2Plugin.class); //出纳初始化 private static final String KEY_ENTITY_CASHINIT = "cas_cashmgtinit"; //银行账户 private static final String KEY_ENTITY_ACCOUNT = "am_accountbank"; //离线明细引入实体编码 private static final String KEY_ENTITY_BETRANSDETAIL = "bei_betransdetail_imp"; @ApiPostMapping("SynBetransByBalance") public CustomApiResult doCustomerService(){ //先更新cbs开通状态 List orgIds = new ArrayList<>(); CBSToolUtil.synAccountOpenStatus(orgIds); String selectProperties = "bankaccountnumber, openorg, currency, bank, company"; QFilter qFilter = new QFilter("nckd_issetcbs", QCP.equals, false); qFilter.and(new QFilter("acctstatus", QCP.equals, "normal")); // qFilter.and(new QFilter("bankaccountnumber", QCP.equals, "791909297510506")); DynamicObject[] acctList = BusinessDataServiceHelper.load(KEY_ENTITY_ACCOUNT, selectProperties, new QFilter[]{qFilter}); List listObj = new ArrayList<>(); int count = 0; for(DynamicObject acct : acctList){ JSONObject lastBal = queryLastBal(acct); // if("500".equals(lastBal.getString("code"))){ // continue; // } String accountNumber = acct.getString("bankaccountnumber"); DynamicObject openOrg = acct.getDynamicObject("openorg"); if(openOrg == null){ continue; } Long orgId = openOrg.getLong("id"); String cbsUrl = ParamsUtil.getCBSURLByMaster(orgId); if(StringUtils.isEmpty(cbsUrl)){ logger.info("同步交易明细失败:组织【" + openOrg.getString("name") + "】(" + orgId.toString() + ")未配置相应的CBS地址"); continue; } //账户实时余额查询ERCURBAL报文内容 String body = getDetailBodyString(accountNumber); String paramBody = CBSToolUtil.getBodyString(body); //保存CBS调用日志 String uuid = ParamsUtil.saveCBSLogData(cbsUrl, "detail", paramBody); String sTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"); logger.info("调用CBS接口ERCURBAL开始时间:" + sTime); String sr = CBSToolUtil.sendPost(cbsUrl, paramBody); String eTime = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"); logger.info("调用CBS接口ERCURBAL结束时间:" + eTime); //更新CBS调用日志 ParamsUtil.updateCBSLogData(uuid, sr); String cbssr = CBSToolUtil.parseXMLcbs(sr); DynamicObject result = getBalanceDetailInfo(cbssr, acct, lastBal.getBigDecimal("bal")); if(result != null){ listObj.add(result); } count++; //批量保存 if(listObj.size() > 0 && count == 1000) { count = 0; OperationResult resultSave = OperationServiceHelper.executeOperate("save", KEY_ENTITY_BETRANSDETAIL, listObj.toArray(new DynamicObject[]{}), OperateOption.create()); StringBuilder err = new StringBuilder(); if (resultSave.getSuccessPkIds().size() <= 0) { for (int index = 0; index < resultSave.getAllErrorOrValidateInfo().size(); index++) { String message = resultSave.getAllErrorOrValidateInfo().get(index).getMessage(); err.append("/").append(message); } } listObj.clear(); } } //批量保存 if(listObj.size() > 0) { OperationResult resultSave = OperationServiceHelper.executeOperate("save", KEY_ENTITY_BETRANSDETAIL, listObj.toArray(new DynamicObject[]{}), OperateOption.create()); StringBuilder err = new StringBuilder(); if (resultSave.getSuccessPkIds().size() <= 0) { for (int index = 0; index < resultSave.getAllErrorOrValidateInfo().size(); index++) { String message = resultSave.getAllErrorOrValidateInfo().get(index).getMessage(); err.append("/").append(message); } } } //自动生成余额 // try { // ParamsUtil.createBalance(); // } catch (ParseException e) { // throw new RuntimeException(e); // } return returnResult("200", "同步成功!"); } /** * 查询账号在星瀚的当前余额 * @param acct * @return */ private JSONObject queryLastBal(DynamicObject acct){ String code = "200"; BigDecimal bal = BigDecimal.ZERO; //查询是否存在交易明细 SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd"); //交易时间 Date time = new Date(); //交易日期 Date date = null; try { date = sdf1.parse(sdf1.format(time)); } catch (ParseException e) { throw new RuntimeException(e); } QFilter qFilter = new QFilter("accountbank.id", QCP.equals, acct.getLong("id")); qFilter.and(new QFilter("bizdate", QCP.less_than, date)); String selectProperties = "transbalance"; String orderBy = "biztime desc"; DynamicObject[] detailList = BusinessDataServiceHelper.load(KEY_ENTITY_BETRANSDETAIL, selectProperties, qFilter.toArray(), orderBy); //如果没有交易明细,则查找是否有做出纳初始化初始余额 if(detailList.length == 0){ qFilter = new QFilter("entrybank.bank_accountbank", QCP.equals, acct.getLong("id")); selectProperties = "entrybank.bank_journalbalance"; orderBy = "startperiod.number desc"; DynamicObjectCollection objCols = QueryServiceHelper.query(KEY_ENTITY_CASHINIT, selectProperties, qFilter.toArray(), orderBy); if(objCols.size() > 0){ code = "200"; bal = objCols.get(0).getBigDecimal("entrybank.bank_journalbalance"); } } else { code = "200"; bal = detailList[0].getBigDecimal("transbalance"); } JSONObject reslutData = new JSONObject(); reslutData.put("code", code); reslutData.put("bal", bal); return reslutData; } /** * 交易明细参数body * @return */ private String getDetailBodyString(String accountNumber){ StringBuffer body = new StringBuffer(); body.append("\r\n"); body.append("\r\n"); body.append("\r\n"); body.append("ERCURBAL\r\n"); body.append("\r\n"); body.append("\r\n"); body.append("").append(accountNumber).append("\r\n"); body.append("\r\n"); body.append("\r\n"); return body.toString(); } /** * 处理cbs返回结果 * @param cbssr * @return */ private DynamicObject getBalanceDetailInfo(String cbssr, DynamicObject acct, BigDecimal lastBal){ JSONObject cbsObj = XmlUtils.documentToJSONObject(cbssr); if(cbsObj != null && cbsObj.get("ACACTINFY") != null){ JSONArray array = (JSONArray)cbsObj.get("ACACTINFY"); JSONObject account = array.getJSONObject(0); List listObj = new ArrayList<>(); DynamicObject detailInfo = null; try { detailInfo = parseBetransDetail(account, acct, lastBal); } catch (ParseException e) { throw new RuntimeException(e); } return detailInfo; } return null; } /** * 创建离线明细引入对象 * @param cbsObj * @return */ private DynamicObject parseBetransDetail(JSONObject cbsObj, DynamicObject acct, BigDecimal lastBal) throws ParseException { //账户余额 BigDecimal actBal = cbsObj.getBigDecimal("ACTBAL"); if(actBal == null){ actBal = BigDecimal.ZERO; } //处理日期类字段 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd"); //交易时间 Date time = new Date(); //交易日期 Date date = sdf1.parse(sdf1.format(time)); //如果当天存在cbs交易明细,则不增加交易明细 Boolean isExistDetail = ParamsUtil.isExistsDetail(acct, date, new String[]{"curday", "history"}); if(isExistDetail){ return null; } DynamicObject objectInfo = ParamsUtil.getDetailInfo(acct, date, "balancecompare"); if(objectInfo == null){ objectInfo = BusinessDataServiceHelper.newDynamicObject(KEY_ENTITY_BETRANSDETAIL); } objectInfo.set("nckd_generatemethod", "balancecompare"); //借贷方向:1:借方,2:贷方 String direct = ""; BigDecimal dayActAmt = actBal.subtract(lastBal).abs(); if(lastBal.compareTo(actBal) > 0){ direct = "1"; } else if(lastBal.compareTo(actBal) < 0){ direct = "2"; } else { return null; } String detailid = UUID.randomUUID().toString().replace("-", ""); detailid = (detailid == null) ? ("uuid" + String.valueOf(System.currentTimeMillis())) : detailid; objectInfo.set("oppunit", null);//对方用户名 objectInfo.set("oppbanknumber", null);//对方账号 objectInfo.set("oppbank", null);//对方开户行 objectInfo.set("detailid", detailid);//明细流水号 objectInfo.set("bizrefno", detailid);//业务参考号 objectInfo.set("uniqueseq", detailid + "01");//银行主键 objectInfo.set("description", null);//摘要 //判断此明细流水号是否已存在,已存在的记录不接收 QFilter filterBizRefNo = new QFilter("detailid", QCP.equals, objectInfo.getString("detailid")); QFilter filterDataSource = new QFilter("datasource", QCP.equals, "import"); QFilter[] filters = new QFilter[]{filterBizRefNo, filterDataSource}; DynamicObject betransDetailInfo = BusinessDataServiceHelper.loadSingle(KEY_ENTITY_BETRANSDETAIL, "id, billno", filters); if(betransDetailInfo != null){ return null; } //交易时间 objectInfo.set("bizTime", new Timestamp(time.getTime())); //交易日期 objectInfo.set("bizdate", new Timestamp(date.getTime())); //入账状态 if("2".equals(direct)){ objectInfo.set("receredtype", "0"); } //发生额 objectInfo.set("debitamount", BigDecimal.ZERO); objectInfo.set("creditamount", BigDecimal.ZERO); String amountField = ParamsUtil.getAmountFieldName(direct); objectInfo.set(amountField, dayActAmt); //手续费 // objectInfo.set("transfercharge", BigDecimal.ZERO); //余额 objectInfo.set("transbalance", actBal); //单据状态 objectInfo.set("billstatus", "A"); //数据来源 objectInfo.set("datasource", "import"); //业务类型 objectInfo.set("biztype", "1"); //币别 DynamicObjectCollection collection = acct.getDynamicObjectCollection("currency"); Long currencyId = 0L; for (DynamicObject item : collection) { //引用该基础资料的单据id long pkid = item.getLong("pkid"); // 获取该基础资料的动态对象 DynamicObject fbasedataid = item.getDynamicObject("fbasedataid"); //获取该基础资料的id currencyId = item.getLong("fbasedataid_id"); } DynamicObject currency = BusinessDataServiceHelper.loadSingleFromCache(currencyId, "bd_currency"); objectInfo.set("currency", currency); //银行账号 objectInfo.set("accountbank", acct); objectInfo.set("bank", acct.get("bank")); objectInfo.set("company", acct.get("company")); CodeRuleInfo codeRule = CodeRuleServiceHelper.getCodeRule(objectInfo.getDataEntityType().getName(), objectInfo, null); String billno = CodeRuleServiceHelper.getNumber(codeRule, objectInfo); objectInfo.set("billno", billno); return objectInfo; } /** * 自定义返回data对象 * @param code * @param message * @return */ public CustomApiResult returnResult(String code, String message){ JSONObject reslutData = new JSONObject(); reslutData.put("code", code); reslutData.put("message", message); CustomApiResult result = CustomApiResult.success(reslutData); return result; } }