Browse Source

资金预警需求-非银企直连通知:
1.非银企直连预警消息通知

lisheng 1 week ago
parent
commit
35f5f788f1

+ 1 - 1
main/java/kd/cosmic/jkjt/tmc/bei/common/CommonUtils.java

@@ -33,7 +33,7 @@ public class CommonUtils {
         }
 
         // 转换为万元:除以 10000
-        BigDecimal tenThousand = amount.divide(new BigDecimal("10000"), 1, RoundingMode.HALF_UP);
+        BigDecimal tenThousand = amount.divide(new BigDecimal("10000"), 4, RoundingMode.HALF_UP);
         return tenThousand.stripTrailingZeros().toPlainString() + "万元";
     }
 

+ 6 - 0
main/java/kd/cosmic/jkjt/tmc/bei/common/DateUtils.java

@@ -10,6 +10,9 @@ public class DateUtils {
     private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
     private static final SimpleDateFormat DATE_FORMAT_DAY = new SimpleDateFormat("yyyy-MM-dd");
 
+    private static final SimpleDateFormat DATE_FORMAT_MONTH= new SimpleDateFormat("yyyy-MM");
+
+
     /**
      * 获取 n 天前/后的指定小时的时间点
      * @param days 偏移天数,如 -1 表示昨天,+1 表示明天
@@ -42,4 +45,7 @@ public class DateUtils {
     public static String formatDateDay(Date date) {
         return DATE_FORMAT_DAY.format(date);
     }
+    public static String formatDateMonth(Date date) {
+        return DATE_FORMAT_MONTH.format(date);
+    }
 }

+ 74 - 2
main/java/kd/cosmic/jkjt/tmc/bei/common/constant/MsgWarnTemplateConstant.java

@@ -1,13 +1,18 @@
 package kd.cosmic.jkjt.tmc.bei.common.constant;
 
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import kd.cosmic.jkjt.tmc.bei.common.CommonUtils;
+
+import java.math.BigDecimal;
 
 public class MsgWarnTemplateConstant {
 
 
     /** 飞书消息模板 */
     public static final String TEMPLATESTR = "{\"schema\":\"2.0\",\"config\":{\"update_multi\":true,\"style\":{\"text_size\":{\"normal_v2\":{\"default\":\"normal\",\"pc\":\"normal\",\"mobile\":\"heading\"}}}},\"body\":{\"direction\":\"vertical\",\"padding\":\"12px 12px 12px 12px\",\"elements\":[{\"tag\":\"div\",\"text\":{\"tag\":\"plain_text\",\"content\":\"付款信息\",\"text_size\":\"normal_v2\",\"text_align\":\"left\",\"text_color\":\"default\"},\"margin\":\"0px 0px 0px 0px\"}]},\"header\":{\"title\":{\"tag\":\"plain_text\",\"content\":\"\"},\"subtitle\":{\"tag\":\"plain_text\",\"content\":\"消息发送\"},\"template\":\"blue\",\"padding\":\"12px 12px 12px 12px\"}}";
+    public static final String TEMPLATESTR_OTHERACCOUNT = "{\"schema\":\"2.0\",\"config\":{\"update_multi\":true,\"style\":{\"text_size\":{\"normal_v2\":{\"default\":\"normal\",\"pc\":\"normal\",\"mobile\":\"heading\"}}}},\"body\":{\"direction\":\"vertical\",\"padding\":\"12px 12px 12px 12px\",\"elements\":[{\"tag\":\"div\",\"text\":{\"tag\":\"plain_text\",\"content\":\"按公司规定,此账户严禁对私转账\",\"text_size\":\"normal_v2\",\"text_align\":\"left\",\"text_color\":\"red\"},\"margin\":\"0px 0px 0px 0px\"},{\"tag\":\"div\",\"text\":{\"tag\":\"plain_text\",\"content\":\"付款信息\",\"text_size\":\"normal_v2\",\"text_align\":\"left\",\"text_color\":\"default\"},\"margin\":\"0px 0px 0px 0px\"}]},\"header\":{\"title\":{\"tag\":\"plain_text\",\"content\":\"\"},\"subtitle\":{\"tag\":\"plain_text\",\"content\":\"消息发送\"},\"template\":\"blue\",\"padding\":\"12px 12px 12px 12px\"}}";
 
     // 收款通知模板
 
@@ -57,6 +62,21 @@ public class MsgWarnTemplateConstant {
                 paymentCount);
     }
 
+
+    public static String formatOtherAccountMessage(String payerAccount, String payerAccountId, String payerBank, String amount,
+                                                 String receiver, String description, String time) {
+        String MSGTEMPLATE_LARGETRANS = new StringBuffer()
+                .append("收款方:").append("%s").append("\r\n")
+                .append("金额:").append("%s").append("\r\n")
+                .append("付款方账户:").append("%s").append("\r\n")
+                .append("付款方账号:").append("%s").append("\r\n")
+                .append("付款方开户行:").append("%s").append("\r\n")
+                .append("摘要:").append("%s").append("\r\n")
+                .append("时间:").append("%s").append("\r\n")
+                .toString();
+        return String.format(MSGTEMPLATE_LARGETRANS,receiver,amount,payerAccount, payerAccountId, payerBank, description, time);
+    }
+
     /** 付款通知消息格式化
      * @param amount         支出金额
      * @param payerAccount   付方账户
@@ -82,6 +102,47 @@ public class MsgWarnTemplateConstant {
     }
 
 
+    public static String formatNonDirectMessageDebit(String time,String payerAccount, String payerAccountId, String payerBank,
+                                                String paymentCount, String totalAmount) {
+        String wyAmountStr = CommonUtils.convertToTenThousandYuan(new BigDecimal(totalAmount));
+        String MSGTEMPLATE_PAYMENT_NOTIFICATION = new StringBuffer()
+                .append("时间:").append("%s").append("\r\n")
+                .append("付款方账户:").append("%s").append("\r\n")
+                .append("付款方账号:").append("%s").append("\r\n")
+                .append("付款方开户行:").append("%s").append("\r\n")
+                .append("付款笔数:").append("%s").append("\r\n")
+                .append("合计金额:").append("%s元,").append(wyAmountStr).append("\r\n")
+                .toString();
+
+        return String.format(MSGTEMPLATE_PAYMENT_NOTIFICATION,
+                time,
+                payerAccount,
+                payerAccountId,
+                payerBank,
+                paymentCount,
+                totalAmount);
+}
+    public static String formatNonDirectMessageCredit(String time,String payerAccount, String payerAccountId, String payerBank,
+                                                     String paymentCount, String totalAmount) {
+        String wyAmountStr = CommonUtils.convertToTenThousandYuan(new BigDecimal(totalAmount));
+        String MSGTEMPLATE_PAYMENT_NOTIFICATION = new StringBuffer()
+                .append("时间:").append("%s").append("\r\n")
+                .append("付款方账户:").append("%s").append("\r\n")
+                .append("付款方账号:").append("%s").append("\r\n")
+                .append("付款方开户行:").append("%s").append("\r\n")
+                .append("收款笔数:").append("%s").append("\r\n")
+                .append("合计金额:").append("%s元,").append(wyAmountStr).append("\r\n")
+                .toString();
+
+        return String.format(MSGTEMPLATE_PAYMENT_NOTIFICATION,
+                time,
+                payerAccount,
+                payerAccountId,
+                payerBank,
+                paymentCount,
+                totalAmount);
+    }
+
 
     /** 收款通知消息格式化
      * @param amount         到账金额
@@ -108,9 +169,20 @@ public class MsgWarnTemplateConstant {
     }
 
     public static String getFeishuTemplate(String title , String content) {
-        JSONObject templateObj = JSON.parseObject(TEMPLATESTR);
+        return getFeishuTemplate(title,content,TEMPLATESTR);
+    }
+
+    public static String getFeishuTemplate(String title , String content , String template) {
+        JSONObject templateObj = JSON.parseObject(template);
         templateObj.getJSONObject("header").getJSONObject("subtitle").put("content", title);
-        templateObj.getJSONObject("body").getJSONArray("elements").getJSONObject(0).getJSONObject("text").put("content", content);
+        JSONArray elements = templateObj.getJSONObject("body").getJSONArray("elements");
+        for(int i = 0; i < elements.size(); i++){
+            String contentTemplate = elements.getJSONObject(i).getJSONObject("text").getString("content");
+            if("付款信息".equals(contentTemplate)){
+                elements.getJSONObject(i).getJSONObject("text").put("content", content);
+                break;
+            }
+        }
         return templateObj.toJSONString();
     }
 }

+ 192 - 0
main/java/kd/cosmic/jkjt/tmc/bei/task/NonDirectConMsgWarnTask.java

@@ -0,0 +1,192 @@
+package kd.cosmic.jkjt.tmc.bei.task;
+
+import kd.bos.algo.DataSet;
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.exception.KDException;
+import kd.bos.logging.BizLog;
+import kd.bos.orm.ORM;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.schedule.api.StopTask;
+import kd.bos.schedule.executor.AbstractTask;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.workflow.engine.msg.info.MessageInfo;
+import kd.cosmic.jkjt.tmc.bei.common.CommonUtils;
+import kd.cosmic.jkjt.tmc.bei.common.DateUtils;
+import kd.cosmic.jkjt.tmc.bei.common.FeishuSendMessageUtils;
+import kd.cosmic.jkjt.tmc.bei.common.constant.BeiBeTransDetailConstant;
+import kd.cosmic.jkjt.tmc.bei.common.constant.MsgWarnConfigConstant;
+import kd.cosmic.jkjt.tmc.bei.common.constant.MsgWarnTemplateConstant;
+import kd.cosmic.jkjt.tmc.bei.common.entity.MsgWarnMessageInfo;
+import kd.cosmic.jkjt.tmc.bei.common.enums.MsgWarnTypeEnum;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 其他账户每日提醒提醒
+ */
+public class NonDirectConMsgWarnTask extends AbstractTask implements StopTask {
+    private MsgWarnTypeEnum WARTYPE = MsgWarnTypeEnum.NONDIRECTCON;
+    @Override
+    public void execute(RequestContext requestContext, Map<String, Object> map) throws KDException {
+        // 查询生效的账户大额交易通知配置
+        Set<Long> largeTransIdConfig = getMsgWarnConfig();
+
+        largeTransIdConfig.forEach(configId -> transConfigSendMessage(configId));
+    }
+
+    protected Set<Long> getMsgWarnConfig() {
+        DynamicObjectCollection configCol = QueryServiceHelper.query(MsgWarnConfigConstant.ENTITYID, "id,nckd_company.id", new QFilter[]{
+                new QFilter(MsgWarnConfigConstant.KEY_NCKD_TYPE, QFilter.equals, WARTYPE.getValue()),
+                new QFilter(MsgWarnConfigConstant.KEY_STATUS, QFilter.equals, "C"),
+                new QFilter(MsgWarnConfigConstant.KEY_ENABLE, QFilter.equals, "1")
+        });
+        Map<Long, Long> companyIdMap = configCol.stream()
+                .collect(Collectors.toMap(r -> r.getLong("nckd_company.id"), r -> r.getLong("id"), (a, b) -> a));
+        return companyIdMap.values().stream().collect(Collectors.toSet());
+    }
+
+    protected void transConfigSendMessage(Long configId) {
+        DynamicObject msgWarnConfig = BusinessDataServiceHelper.loadSingle(configId, MsgWarnConfigConstant.ENTITYID);
+        DynamicObject company = msgWarnConfig.getDynamicObject(MsgWarnConfigConstant.KEY_NCKD_COMPANY);
+        DynamicObject financeDirectors = msgWarnConfig.getDynamicObject(MsgWarnConfigConstant.KEY_NCKD_FINANCE_DIRECTOR);
+        DynamicObject financeLeader = msgWarnConfig.getDynamicObject(MsgWarnConfigConstant.KEY_NCKD_FINANCE_LEADER);
+        DynamicObject unitLeader = msgWarnConfig.getDynamicObject(MsgWarnConfigConstant.KEY_NCKD_UNIT_LEADER);
+        // 没有设置接收人时跳过
+        if(financeDirectors == null || financeLeader == null || unitLeader == null){
+            BizLog.log("消息接收人为空,不进行消息发送。");
+            return;
+        }
+        List<Long> receiverIdList = new ArrayList<>();
+        receiverIdList.add(financeDirectors.getLong("id"));
+        receiverIdList.add(financeLeader.getLong("id"));
+        LocalDate today = LocalDate.now();
+        // 上个月第一天
+        LocalDate firstDayOfLastMonth = today.minusMonths(1).withDayOfMonth(1);
+        // 本月第一天
+        LocalDate firstDayOfThisMonth = today.withDayOfMonth(1);
+
+        Date beginDate = Date.from(firstDayOfLastMonth.atStartOfDay().atZone(java.time.ZoneId.systemDefault()).toInstant());
+        Date endDate = Date.from(firstDayOfThisMonth.atStartOfDay().atZone(java.time.ZoneId.systemDefault()).toInstant());
+        // 自测------暂时设置成当前时间
+        DynamicObjectCollection transDetailData = getTransDetailData(company, beginDate,endDate);
+        if(transDetailData == null || transDetailData.isEmpty()){
+            BizLog.log("没有符合条件的数据,不进行消息发送。");
+            return;
+        }
+        String messageTime = String.format("%s年%s月",today.getYear(),today.getMonthValue()-1);
+        String timeFlag = DateUtils.formatDateMonth(beginDate);
+
+        for(DynamicObject transDetail : transDetailData){
+            String dc = transDetail.getString("dc");
+            String uniqueKey = String.join("-", WARTYPE.getValue(),timeFlag,dc,transDetail.getString("nckd_payaccbanknumber"));
+            if(ORM.create().exists("nckd_msgwarnlog",new QFilter("nckd_unique_key", QCP.equals,uniqueKey).toArray())){
+                // 消息如果已发送,就不在执行
+                continue;
+            }
+            String messageContent = getMcCenterMessage(messageTime,transDetail);
+
+            MessageInfo messageInfo = new MessageInfo();
+            messageInfo.setTitle(String.join("-",WARTYPE.getName()));
+            messageInfo.setUserIds(receiverIdList);
+            messageInfo.setContent(messageContent);
+            messageInfo.setTag(WARTYPE.getName());
+            messageInfo.setSenderId(RequestContext.get().getCurrUserId());
+            messageInfo.setEntityNumber("nckd_msgwarnconfig");
+            messageInfo.setBizDataId(configId);
+
+            String feishuMessage = MsgWarnTemplateConstant.getFeishuTemplate(WARTYPE.getName(),messageContent);
+            MsgWarnMessageInfo warnMessageInfo = new MsgWarnMessageInfo(WARTYPE.getValue(),
+                    company.getString("name"),
+                    uniqueKey,
+                    feishuMessage,
+                    messageInfo);
+            FeishuSendMessageUtils.sendFeishuMessage(warnMessageInfo);
+        }
+
+    }
+
+    protected String getMcCenterMessage(String time,DynamicObject transDetail) {
+
+        String dc = transDetail.getString("dc");
+        if("1".equals(dc)){
+            return MsgWarnTemplateConstant.formatNonDirectMessageDebit(
+                    time,
+                    transDetail.getString("nckd_payaccount"),
+                    transDetail.getString("nckd_payaccbanknumber"),
+                    transDetail.getString("nckd_payaccbank"),
+                    transDetail.getString("nckd_count"),
+                    transDetail.getBigDecimal("nckd_amount").setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
+        }else{
+            return MsgWarnTemplateConstant.formatNonDirectMessageCredit(
+                    time,
+                    transDetail.getString("nckd_payaccount"),
+                    transDetail.getString("nckd_payaccbanknumber"),
+                    transDetail.getString("nckd_payaccbank"),
+                    transDetail.getString("nckd_count"),
+                    transDetail.getBigDecimal("nckd_amount").setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
+        }
+
+    }
+
+    protected DynamicObjectCollection getTransDetailData(DynamicObject company , Date beginDate , Date endDate){
+        DataSet debitDetailDataSet = getTransDetailDataSet(company, beginDate,endDate,true);
+        DataSet crediDetailDataSet = getTransDetailDataSet(company, beginDate,endDate,false);
+        DataSet transDetailDataSet = debitDetailDataSet.union(crediDetailDataSet);
+        // 看报表与消息的兼容程度,再看怎么处理,暂时转成动态对象集合
+        return ORM.create().toPlainDynamicObjectCollection(transDetailDataSet.copy());
+    }
+
+    /**
+     * 获取账户交易明细
+     * 1.非日常报销账户
+     * 2.
+     * @param company
+     * @param beginDate
+     * @return
+     */
+    protected DataSet getTransDetailDataSet(DynamicObject company , Date beginDate , Date endDate,boolean isDebitamount){
+
+        String amountField = isDebitamount?BeiBeTransDetailConstant.KEY_DEBITAMOUNT:BeiBeTransDetailConstant.KEY_CREDITAMOUNT;
+        List<QFilter> filterList = new ArrayList<>();
+        filterList.add(new QFilter(BeiBeTransDetailConstant.KEY_COMPANY, QFilter.equals, company.getPkValue()));
+        if(beginDate != null){
+            filterList.add(new QFilter(BeiBeTransDetailConstant.KEY_BIZTIME, QFilter.large_equals, beginDate));
+        }
+        if(endDate != null){
+            filterList.add(new QFilter(BeiBeTransDetailConstant.KEY_BIZTIME, QFilter.less_than, endDate));
+        }
+        filterList.add(new QFilter("nckd_generatemethod", QCP.equals,"Manual import"));
+        filterList.add(new QFilter(amountField, QCP.large_than,BigDecimal.ZERO));
+
+
+        DataSet dataSet = QueryServiceHelper.queryDataSet(this.getClass().getName(), BeiBeTransDetailConstant.ENTITYID,
+                "id,company.id,accountbank.id,"+amountField+",biztime",
+                filterList.toArray(new QFilter[0]), "");
+
+        // 通过公司、我方账号,对方账号分组,求和
+        DataSet amountDataSet = dataSet
+                .groupBy(new String[]{"company.id", "accountbank.id"}).sum(amountField).count("totaltimes").finish()
+                .select("company.id,accountbank.id,"+amountField+" totalamount,totaltimes");
+
+        Set companyIdSet = CommonUtils.getFieldValue(amountDataSet, "company.id");
+        DataSet companyDataSet = QueryServiceHelper
+                .queryDataSet(this.getClass().getName(), "bos_org", "id,name", new QFilter("id", QCP.in, companyIdSet).toArray(), "");
+        // 查询银行账户
+        Set accountBankIdSet = CommonUtils.getFieldValue(amountDataSet, "accountbank.id");
+        DataSet accountBankDataSet = QueryServiceHelper
+                .queryDataSet(this.getClass().getName(), "bd_accountbanks", "id,bankaccountnumber,bank.name", new QFilter("id", QCP.in, accountBankIdSet).toArray(), "");
+        return amountDataSet
+                .leftJoin(companyDataSet).on("company.id", "id")
+                .select( new String[] {"company.id nckd_company", "accountbank.id accountbankid","totaltimes nckd_count","totalamount nckd_amount"},  new String[] {"name nckd_payaccount"}).finish()
+                .leftJoin(accountBankDataSet).on("accountbankid", "id")
+                .select(new String[] {"nckd_company", "nckd_payaccount","nckd_count","nckd_amount", String.format("'%s' dc",isDebitamount?"1":"-1")}, new String[]{"bankaccountnumber nckd_payaccbanknumber", "bank.name nckd_payaccbank"})
+                .finish();
+    }
+}