From fefd6e772ee7342603681c8c574ad6cbc7dee514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E8=B4=B5=E5=BC=BA?= Date: Fri, 17 Oct 2025 17:37:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=98=E6=AC=BE=E6=8E=92=E7=A8=8B=E8=B0=83?= =?UTF-8?q?=E5=BA=A6=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fi/plugin/operate/PaybillOperation.java | 19 +- .../fi/fi/plugin/task/PayApplyFukuanTask.java | 342 ++++++++++++------ .../fi/fi/plugin/task/RecPushSapTask.java | 8 +- 3 files changed, 256 insertions(+), 113 deletions(-) diff --git a/main/java/shjh/jhzj7/fi/fi/plugin/operate/PaybillOperation.java b/main/java/shjh/jhzj7/fi/fi/plugin/operate/PaybillOperation.java index 37cec34..451bc76 100644 --- a/main/java/shjh/jhzj7/fi/fi/plugin/operate/PaybillOperation.java +++ b/main/java/shjh/jhzj7/fi/fi/plugin/operate/PaybillOperation.java @@ -171,15 +171,16 @@ public class PaybillOperation extends AbstractOperationServicePlugIn implements header.put("FM_ExpenseTypeCode", FM_ExpenseTypeCode);// 业务大类编码(EQ49,EQ44,EQ1101) header.put("FM_CurrencyCode", "RMB");// 币种编码,默认:RMB header.put("FM_RequestName", bill.getString("description"));// 单据主题_拼接 - List> attachments = AttachmentServiceHelper.getAttachments(bill.getDataEntityType().getName(), bill.getLong("id"), "attachmentpanel"); - if (attachments.size()!=0){ - JSONArray attachUrls = new JSONArray(); - for (Map attachment : attachments) { - String url = (String)attachment.get("url"); - attachUrls.add(url); - } - header.put("FM_AttachUrl", attachUrls);//附件URL地址:array - } +// List> attachments = AttachmentServiceHelper.getAttachments(bill.getDataEntityType().getName(), bill.getLong("id"), "attachmentpanel"); +// if (attachments.size()!=0){ +// JSONArray attachUrls = new JSONArray(); +// for (Map attachment : attachments) { +// String url = (String)attachment.get("url"); +// attachUrls.add(url); +// } +// header.put("FM_AttachUrl", attachUrls);//附件URL地址:array +// } + header.put("FM_AttachUrl", null);//附件URL地址:array header.put("FM_BudType", 0);//预算类别0-组织预算,1-全年预算,当前只处理0 int header.put("Remark", bill.getString("description"));// 事项描述_摘要 diff --git a/main/java/shjh/jhzj7/fi/fi/plugin/task/PayApplyFukuanTask.java b/main/java/shjh/jhzj7/fi/fi/plugin/task/PayApplyFukuanTask.java index 8e7a56c..2fcaf72 100644 --- a/main/java/shjh/jhzj7/fi/fi/plugin/task/PayApplyFukuanTask.java +++ b/main/java/shjh/jhzj7/fi/fi/plugin/task/PayApplyFukuanTask.java @@ -17,153 +17,291 @@ import kd.bos.servicehelper.QueryServiceHelper; import kd.bos.servicehelper.operation.OperationServiceHelper; import kd.sdk.plugin.Plugin; +import java.math.BigDecimal; import java.util.*; /** * 定时任务 付款申请定时生成付款单 + * * @author LiGuiQiang */ public class PayApplyFukuanTask extends AbstractTask implements Plugin { - private static final String AP_PAYAPPLY ="ap_payapply";// 付款申请单 - private static final String CAS_PAYBILL ="cas_paybill";// 付款单 + private static final String AP_PAYAPPLY = "ap_payapply";// 付款申请单 + //private static final String CAS_PAYBILL = "cas_paybill";// 付款单 private static final Log logger = LogFactory.getLog(PayApplyFukuanTask.class); @Override public void execute(RequestContext requestContext, Map map) throws KDException { - // 【单据状态】=已审核 + // 初始查询条件 QFilter qFilter = new QFilter("billstatus", QCP.equals, "C"); - //qFilter.and(new QFilter("billno",QCP.equals,"FKSQ2507112268"));//测试用 - DynamicObject[] collection = BusinessDataServiceHelper.load(AP_PAYAPPLY, "id,billstatus", qFilter.toArray()); - if (collection.length!=0){ - ArrayList ids = new ArrayList<>(); - for (DynamicObject dynamicObject : collection) { - ids.add(dynamicObject.getLong("id")); - } - Map recBillMap = BusinessDataServiceHelper.loadFromCache(ids.toArray(), AP_PAYAPPLY); - OperateOption operateOption = OperateOption.create(); - // 不执行警告级别校验器 - operateOption.setVariableValue(OperateOptionConst.IGNOREWARN, String.valueOf(true)); - // 不显示交互提示,自动执行到底 - operateOption.setVariableValue(OperateOptionConst.IGNOREINTERACTION, String.valueOf(true)); - // 全部校验通过才保存 - //operateOption.setVariableValue(OperateOptionConst.STRICTVALIDATION, String.valueOf(true)); - //同一个用户在多个界面操作同一张,也不允许操作 - operateOption.setVariableValue(OperateOptionConst.MUTEX_ISSTRICT, String.valueOf(true)); + qFilter.and(new QFilter("paystatus", QCP.not_equals, "Alreadypay")); +// qFilter.and(new QFilter("billno", QCP.equals, "FKSQ2510170003")); - List qualifiedBills = new ArrayList<>();//需要下推的付款申请单的集合 - DynamicObjectCollection entry; - boolean scheduleflag; - for (DynamicObject dynamicObject : recBillMap.values()) { - // 注意:executeOperate 需要一个数组形式的 DynamicObject[] - entry = dynamicObject.getDynamicObjectCollection("entry"); - if (entry!=null && entry.size()!=0){ - //判断是否集团内-境内外供应商(外部系统单据类型=I,返回false) - boolean supplierFilter = supplierFilter(dynamicObject,entry.get(0)); - //判断是否存在数据在下推期间范围(到期日是当前月月底前) - boolean expirationDateFilter = expirationDateFilter(entry); - //如果付款申请单有下游排程单且排程单是已退单,则说明这个付款申请单不用再下推了 - scheduleflag = scheduleFilter(dynamicObject.getLong("id")); - if (!supplierFilter && expirationDateFilter && scheduleflag){ - qualifiedBills.add(dynamicObject); - } - } + + DynamicObject[] collection = BusinessDataServiceHelper.load(AP_PAYAPPLY, "id,billstatus,applyamount,shjh_externalsystemdocume,entry.id,entry.e_asstacttype,entry.e_asstact,entry.e_duedate,entry.lockedamt", qFilter.toArray()); + if (collection.length == 0) { + logger.info("没有符合条件的付款申请单"); + return; + } + + // 批量处理逻辑 + processPayApplyBatch(collection); + } + + private void processPayApplyBatch(DynamicObject[] collection) throws KDException { + // 收集所有ID + List payApplyIds = new ArrayList<>(); + for (DynamicObject dynamicObject : collection) { + payApplyIds.add(dynamicObject.getLong("id")); + } + + // 批量预计算过滤条件 + Map supplierFilterMap = batchSupplierFilter(collection); + Set hasChargeBackIds = batchScheduleFilter(payApplyIds); + Date endOfCurrentMonth = getEndOfCurrentMonth(); + + OperateOption operateOption = createOperateOption(); + List qualifiedBills = new ArrayList<>(); + + // 内存中快速过滤 + for (DynamicObject dynamicObject : collection) { + Long payApplyId = dynamicObject.getLong("id"); + + // 快速跳过检查 + if (hasChargeBackIds.contains(payApplyId)) { + continue; } - if (!qualifiedBills.isEmpty()){ - DynamicObject[] billArray = qualifiedBills.toArray(new DynamicObject[0]); - OperationResult operationResult = OperationServiceHelper.executeOperate("pushandsave", AP_PAYAPPLY, billArray, operateOption); - // 可以根据需要处理 operationResult,例如检查是否成功、获取返回值等 - if (operationResult.isSuccess()) { - logger.info("执行 pay 成功,共处理单据数量:" + qualifiedBills.size()); - // Log individual successful bills if needed - for (DynamicObject bill : qualifiedBills) { - logger.info("成功单据编号:" + bill.getPkValue()); + + DynamicObjectCollection entry = dynamicObject.getDynamicObjectCollection("entry"); + if (entry == null || entry.isEmpty()) { + continue; + } + + // 金额过滤 - 检查所有分录 + BigDecimal applyamount = dynamicObject.getBigDecimal("applyamount"); + if (amountEqualFilter(applyamount, entry)) { + continue; + } + + // 供应商过滤 - 仅检查第一行分录 + Boolean isFilterSupplier = supplierFilterMap.get(payApplyId); + if (isFilterSupplier != null && isFilterSupplier) { + continue; + } + + // 日期过滤 - 检查所有分录 + if (!expirationDateFilter(entry, endOfCurrentMonth)) { + continue; + } + + qualifiedBills.add(dynamicObject); + } + + executePushOperation(qualifiedBills, operateOption); + } + + /** + * 批量处理供应商过滤 - 仅检查第一行分录 + */ + private Map batchSupplierFilter(DynamicObject[] collection) { + Map supplierFilterMap = new HashMap<>(); + Set supplierIds = new HashSet<>(); + Map payApplySupplierMap = new HashMap<>(); + + for (DynamicObject dynamicObject : collection) { + Long payApplyId = dynamicObject.getLong("id"); + + // 先检查外部系统单据类型 + String billType = dynamicObject.getString("shjh_externalsystemdocume"); + if ("I".equals(billType)) { + supplierFilterMap.put(payApplyId, false); + continue; + } + + DynamicObjectCollection entry = dynamicObject.getDynamicObjectCollection("entry"); + if (entry != null && !entry.isEmpty()) { + // 仅检查第一行分录 + DynamicObject firstEntry = entry.get(0); + String asstacttype = firstEntry.getString("e_asstacttype"); + if ("bd_supplier".equals(asstacttype)) { + DynamicObject asstact = firstEntry.getDynamicObject("e_asstact"); + if (asstact != null) { + Long supplierId = asstact.getLong("id"); + supplierIds.add(supplierId); + payApplySupplierMap.put(payApplyId, supplierId); + } else { + // 第一行分录有供应商类型但没有供应商对象,不过滤 + supplierFilterMap.put(payApplyId, false); } } else { - logger.error("批量下推失败:" + operationResult.getMessage()); + // 第一行分录不是供应商类型,不过滤 + supplierFilterMap.put(payApplyId, false); } - }else { - logger.info("没有符合条件的单据需要下推"); + } else { + // 没有分录,不过滤 + supplierFilterMap.put(payApplyId, false); } } - } - private boolean scheduleFilter(Long payrequestid){ - //如果付款申请单有下游排程单且排程单是已退单,则说明这个付款申请单不用再下推了,返回false - //否则返回true继续下推 - //付款申请单的id存于排程单的sourcebillid中 如果id无效果,则用sourcebillnumber 对应付款申请单的billno - QFilter sqfilter = new QFilter("sourcebillid", QCP.equals, payrequestid); - sqfilter.and("schedulstatus", QCP.equals, "yetchargeback");//排程状态已退单 - sqfilter.and("modifytime",QCP.large_equals,getDate("start")); - sqfilter.and("modifytime",QCP.less_equals,getDate("end")); - if (QueryServiceHelper.exists("psd_schedulebill", sqfilter.toArray())) { - return false; - } - return true; - } + // 批量查询供应商分类 + if (!supplierIds.isEmpty()) { + QFilter supplierFilter = new QFilter("supplier.id", QCP.in, supplierIds.toArray()); + DynamicObject[] supplierDetails = BusinessDataServiceHelper.load( + "bd_suppliergroupdetail", + "supplier.id,group.number", + supplierFilter.toArray() + ); - //entry为付款申请单的第一行 - private boolean supplierFilter(DynamicObject dynamicObject,DynamicObject entry){ - boolean isFilterSupplier = false; - //如果外部系统单据类型=I,直接返回false - String billType = dynamicObject.getString("shjh_externalsystemdocume"); - if ("I".equals(billType)){ - return false; - } - String asstacttype = entry.getString("e_asstacttype"); - if ("bd_supplier".equals(asstacttype)){ - DynamicObject asstact = entry.getDynamicObject("e_asstact"); - if (asstact!=null){ - //获取供应商分类映射 - QFilter qFilter1 = new QFilter("supplier.id", QCP.equals, asstact.getPkValue()); - DynamicObject dynamicObject1 = BusinessDataServiceHelper.loadSingle("bd_suppliergroupdetail", qFilter1.toArray()); - if (dynamicObject1!=null){ - String number = dynamicObject1.getString("group.number"); - if ("D200".equals(number) || "D201".equals(number)){ - isFilterSupplier=true; - } - } + // 构建供应商分类映射 + Map supplierGroupMap = new HashMap<>(); + for (DynamicObject detail : supplierDetails) { + Long supplierId = detail.getLong("supplier.id"); + String groupNumber = detail.getString("group.number"); + supplierGroupMap.put(supplierId, groupNumber); + } + + // 为每个单据设置过滤标志 + for (Map.Entry entry : payApplySupplierMap.entrySet()) { + Long payApplyId = entry.getKey(); + Long supplierId = entry.getValue(); + + String groupNumber = supplierGroupMap.get(supplierId); + boolean isFilter = "D200".equals(groupNumber) || "D201".equals(groupNumber); + supplierFilterMap.put(payApplyId, isFilter); } } - return isFilterSupplier; + + // 确保所有单据都有过滤结果 + for (DynamicObject dynamicObject : collection) { + Long payApplyId = dynamicObject.getLong("id"); + if (!supplierFilterMap.containsKey(payApplyId)) { + supplierFilterMap.put(payApplyId, false); + } + } + + return supplierFilterMap; } - private boolean expirationDateFilter(DynamicObjectCollection entry){ - boolean hasValidDueDate = false; // 默认false,表示没有符合条件的数据 + /** + * 金额过滤方法 - 检查所有分录 + */ + private boolean amountEqualFilter(BigDecimal applyamount, DynamicObjectCollection entry) { + BigDecimal entryAmount = BigDecimal.ZERO; + for (DynamicObject dynamicObject : entry) { + BigDecimal lockedamt = dynamicObject.getBigDecimal("lockedamt"); + if (lockedamt != null) { + entryAmount = entryAmount.add(lockedamt); + } + } + return applyamount.compareTo(entryAmount) == 0; + } - // 获取当前月的最后一天(月底) - Calendar calendar = Calendar.getInstance(); - calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); - Date endOfCurrentMonth = calendar.getTime(); - - //遍历entry集合,检查是否有到期日小于等于当前月月底的数据 + /** + * 日期过滤方法 - 检查所有分录 + * 只要有一个分录的到期日在当前月月底前,就返回true + */ + private boolean expirationDateFilter(DynamicObjectCollection entry, Date endOfCurrentMonth) { for (DynamicObject object : entry) { Date dueDate = object.getDate("e_duedate"); if (dueDate != null && dueDate.compareTo(endOfCurrentMonth) <= 0) { - hasValidDueDate = true; // 找到符合条件的数据 - break; // 只要有一条符合就退出循环 + return true; } } - return hasValidDueDate; + return false; } - private Date getDate(String key){ - Calendar calendar = Calendar.getInstance(); + /** + * 批量处理排程单过滤 + */ + private Set batchScheduleFilter(List payApplyIds) { + Set hasChargeBackIds = new HashSet<>(); - if ("start".equals(key)){ - // 获取月初(1号 00:00:00.000) + if (payApplyIds.isEmpty()) { + return hasChargeBackIds; + } + + // 批量查询有退单的付款申请单 + QFilter scheduleFilter = new QFilter("sourcebillid", QCP.in, payApplyIds.toArray()); + scheduleFilter.and("schedulstatus", QCP.equals, "yetchargeback"); + scheduleFilter.and("modifytime", QCP.large_equals, getDate("start")); + scheduleFilter.and("modifytime", QCP.less_equals, getDate("end")); + + DynamicObject[] scheduleBills = BusinessDataServiceHelper.load( + "psd_schedulebill", + "sourcebillid", + scheduleFilter.toArray() + ); + + for (DynamicObject scheduleBill : scheduleBills) { + hasChargeBackIds.add(scheduleBill.getLong("sourcebillid")); + } + + return hasChargeBackIds; + } + + // 其他辅助方法保持不变 + private Date getEndOfCurrentMonth() { + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); + calendar.set(Calendar.HOUR_OF_DAY, 23); + calendar.set(Calendar.MINUTE, 59); + calendar.set(Calendar.SECOND, 59); + calendar.set(Calendar.MILLISECOND, 999); + return calendar.getTime(); + } + + private OperateOption createOperateOption() { + OperateOption operateOption = OperateOption.create(); + operateOption.setVariableValue(OperateOptionConst.IGNOREWARN, "true"); + operateOption.setVariableValue(OperateOptionConst.IGNOREINTERACTION, "true"); + operateOption.setVariableValue(OperateOptionConst.MUTEX_ISSTRICT, "true"); + return operateOption; + } + + private void executePushOperation(List qualifiedBills, OperateOption operateOption) { + if (!qualifiedBills.isEmpty()) { + DynamicObject[] billArray = qualifiedBills.toArray(new DynamicObject[0]); + OperationResult operationResult = OperationServiceHelper.executeOperate( + "pushandsave", AP_PAYAPPLY, billArray, operateOption + ); + + if (operationResult.isSuccess()) { + logger.info("执行pay成功,共处理单据数量:" + qualifiedBills.size()); + // 可以记录成功单据的ID + for (DynamicObject bill : qualifiedBills) { + logger.info("成功下推单据ID:" + bill.getLong("id")); + } + } else { + logger.error("批量下推失败:" + operationResult.getMessage()); + // 记录失败详情 + if (operationResult.getMessage() != null) { + logger.error("错误信息:" + operationResult.getMessage()); + } + } + } else { + logger.info("没有符合条件的单据需要下推"); + } + } + + private Date getDate(String key) { + Calendar calendar = Calendar.getInstance(); + if ("start".equals(key)) { calendar.set(Calendar.DAY_OF_MONTH, 1); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); return calendar.getTime(); - }else if ("end".equals(key)){ - // 获取下个月1号,然后减1天得到月底(时间部分仍为 00:00:00.000) + } else if ("end".equals(key)) { calendar.add(Calendar.MONTH, 1); calendar.set(Calendar.DAY_OF_MONTH, 1); calendar.add(Calendar.DATE, -1); + calendar.set(Calendar.HOUR_OF_DAY, 23); + calendar.set(Calendar.MINUTE, 59); + calendar.set(Calendar.SECOND, 59); + calendar.set(Calendar.MILLISECOND, 999); return calendar.getTime(); } return null; diff --git a/main/java/shjh/jhzj7/fi/fi/plugin/task/RecPushSapTask.java b/main/java/shjh/jhzj7/fi/fi/plugin/task/RecPushSapTask.java index 093c45d..3fa5999 100644 --- a/main/java/shjh/jhzj7/fi/fi/plugin/task/RecPushSapTask.java +++ b/main/java/shjh/jhzj7/fi/fi/plugin/task/RecPushSapTask.java @@ -45,12 +45,16 @@ public class RecPushSapTask extends AbstractTask implements Plugin { logger.info("未找到符合条件的收款单"); return; } - + ArrayList ids = new ArrayList<>(); + for (DynamicObject recBill : recBillList) { + ids.add(recBill.getLong("id")); + } //按金额正负分组 List normalBills = new ArrayList<>(); //正数单据 List redBills = new ArrayList<>(); //负数单据(红冲) + Map recBillMap = BusinessDataServiceHelper.loadFromCache(ids.toArray(), KEY_REC_BILL); - for (DynamicObject bill : recBillList) { + for (DynamicObject bill : recBillMap.values()) { if (bill.getBigDecimal("actrecamt").compareTo(BigDecimal.ZERO) > 0) { normalBills.add(bill); } else {