From 48a8d64455a7ee9ebaa35e06f847ea886736763f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E8=B4=B5=E5=BC=BA?= Date: Wed, 9 Jul 2025 15:03:42 +0800 Subject: [PATCH] =?UTF-8?q?=E7=90=86=E8=B4=A2=E6=94=B6=E7=9B=8A=E8=AE=A1?= =?UTF-8?q?=E6=8F=905.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fi/plugin/report/FinancialFormReport.java | 301 ++++++++---------- .../fi/plugin/report/FinancialListReport.java | 4 +- 2 files changed, 143 insertions(+), 162 deletions(-) diff --git a/main/java/shjh/jhzj7/fi/fi/plugin/report/FinancialFormReport.java b/main/java/shjh/jhzj7/fi/fi/plugin/report/FinancialFormReport.java index 2a57072..2d090eb 100644 --- a/main/java/shjh/jhzj7/fi/fi/plugin/report/FinancialFormReport.java +++ b/main/java/shjh/jhzj7/fi/fi/plugin/report/FinancialFormReport.java @@ -84,16 +84,17 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu BigDecimal buyAmount = amount.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP);//购买金额(千元) row.set(REPORT_FIELDS[4],buyAmount); + BigDecimal netWorth = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[6]); // 购买时单位净值 Date buyDate = row.getDate(REPORT_FIELDS[7]); // 购买日 Date valueDate = row.getDate(REPORT_FIELDS[8]); // 计息日 Date expireDate = row.getDate(REPORT_FIELDS[9]); // 到期日-初始值 BigDecimal expectedRate = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[10]); // 预计业绩比较基准(%) String basis = row.getString(REPORT_FIELDS[15]);//计息基准 + BigDecimal startBuyCopies = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[16]); // 购买份额 // 2. 设置计提日 row.set(DYNAMICS_FIELDS[1], accrualDate); - // 3. 计算产品期限(总天数)=到期日-计息日 String term = countProductTerm(valueDate, expireDate, accrualDate, row); @@ -111,7 +112,6 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu BigDecimal proRevenue = countProRevenue(expectedRate, term, amount, row,basisDays); sumProjectedEarnings=sumProjectedEarnings.add(proRevenue); - // 理财申购单估值分录相关数据处理 // 7. 持有份额 = 计提日期向上最近持有份额 // 8. 月末单位净值 = 计提日期向上最近一次的净值 @@ -119,18 +119,16 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu // 10. 本月收益(千元)、当月年化收益率% // 11. 本年累计收益(千元)、本年累计年化收益率 Long id = row.getLong(REPORT_FIELDS[13]); - BigDecimal redAmount = valuationEntry(accrualDate, buyDate, expireDate2, valueDate, buyAmount, days, basisDays, id, row); + BigDecimal allRedProductAmount = valuationEntry(accrualDate, buyDate, expireDate2, valueDate, buyAmount, days, basisDays, id, row,netWorth,startBuyCopies); BigDecimal buyCopies = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[5]); // 持有份额 - BigDecimal netWorth = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[6]); // 购买时单位净值 BigDecimal monthNetWorth = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[11]); // 月末单位净值 - BigDecimal startBuyCopies = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[16]); // 购买份额 - - // 12. 收益计提 = (持有份额 *月末单位净值 - 购买份额*购买时单位净值) / 1000 - BigDecimal revenueAmt = countRevenueAmt(valueDate,expireDate2, accrualDate,buyCopies, monthNetWorth, netWorth, row,startBuyCopies,redAmount); + // 12. 收益计提 = (持有份额 *月末单位净值 - 购买份额*购买时单位净值*[(1-赎回比)*N])/ 1000 + BigDecimal revenueAmt = countRevenueAmt(valueDate,expireDate2, accrualDate,buyCopies, monthNetWorth, netWorth, row,startBuyCopies,allRedProductAmount); sumProvisionEarnings=sumProvisionEarnings.add(revenueAmt); + // 本月收益计算累计 BigDecimal monthRevenue = ReportUtils.getBigDecimalValue(row, DYNAMICS_FIELDS[4]); sumMonthEarnings=sumMonthEarnings.add(monthRevenue); @@ -191,7 +189,7 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu * @param id 表单id * @return allRedAmount 计提日期之前赎回金额之和 */ - private BigDecimal valuationEntry(Date accrualDate, Date buyDate,Date expireDate,Date valueDate, BigDecimal buyAmount,BigDecimal days,BigDecimal basisDays, Long id, DynamicObject row) { + private BigDecimal valuationEntry(Date accrualDate, Date buyDate,Date expireDate,Date valueDate, BigDecimal buyAmount,BigDecimal days,BigDecimal basisDays, Long id, DynamicObject row,BigDecimal netWorth,BigDecimal startBuyCopies) { // 初始化所有变量 BigDecimal buyCopies = BigDecimal.ZERO; BigDecimal monthIop = BigDecimal.ZERO; @@ -200,8 +198,11 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu BigDecimal monthAnnualizedRate = BigDecimal.ZERO; BigDecimal yearAmount = BigDecimal.ZERO; BigDecimal yearAnnualizedRate = BigDecimal.ZERO; - //计提日期之前赎回金额之和(用于收益计提计算) + //计提日期之前赎回金额之和(用于实际收益计算) BigDecimal allRedAmount = BigDecimal.ZERO; + //计提日期之前赎回金额之和(用于收益计提计算) + BigDecimal allRedProductAmount = BigDecimal.ZERO; + DynamicObject dynamicObject = BusinessDataServiceHelper.loadSingle(id, "cim_finsubscribe"); @@ -254,7 +255,6 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu closestRecord = object; } } - allRedAmount=this.getRedAmount(dynamicObjectCollection,closestRecord.getDate("e_valuationdate")); // 2. 寻找本月最后一次估值记录(相同日期取赎回日期最大的) if (!valuationDate.after(accrualDate)) { @@ -310,9 +310,16 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu } } + // 设置持有份额 if (closestRecord != null) { buyCopies = closestRecord.getBigDecimal("e_surpcopies"); + + //计提日最近估值记录获取——(赎回金额+实际收益)* 所有赎回单 + allRedAmount=this.getRedAmount(dynamicObjectCollection,closestRecord.getDate("e_valuationdate")); + + //计提日最近估值记录获取——(1-赎回份额/赎回日剩余份额)* 所有赎回单 + allRedProductAmount=this.getRedProductAmount(dynamicObjectCollection,closestRecord.getDate("e_valuationdate")); } // 设置月末单位净值 @@ -425,6 +432,8 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu } } + //计算实际收益 + countActRevenueAmt(buyCopies, monthIop, netWorth, row,startBuyCopies,allRedAmount); // 设置结果 row.set(REPORT_FIELDS[5], buyCopies); row.set(REPORT_FIELDS[11], monthIop); @@ -434,9 +443,11 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu row.set(DYNAMICS_FIELDS[6], yearAmount); row.set(DYNAMICS_FIELDS[7], yearAnnualizedRate); - return allRedAmount; + return allRedProductAmount; } + + /** * 获取填入日期之前的赎回单中的赎回金额之和 * @param entry 估值分录 @@ -491,6 +502,81 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu return sum; } + + /** + * 计提日最近估值记录获取——(1-赎回份额/赎回日剩余份额)* 所有赎回单 + * @param entry 输入数据集合 + * @param date 目标日期 + * @return 所有符合条件的赎回单的(1-赎回份额/剩余份额)的乘积 + */ + private BigDecimal getRedProductAmount(DynamicObjectCollection entry, Date date) { + // 1. 按估值日期和赎回日期排序 + DynamicObjectCollection sortedEntries = new DynamicObjectCollection(); + sortedEntries.addAll(entry); + + sortedEntries.sort((o1, o2) -> { + // 优先按估值日期排序(从小到大) + Date valDate1 = o1.getDate("e_valuationdate"); + Date valDate2 = o2.getDate("e_valuationdate"); + int compareValDate = valDate1.compareTo(valDate2); + if (compareValDate != 0) { + return compareValDate; + } + + // 估值日期相同时,按赎回日期排序 + Date redDate1 = o1.getDate("shjh_shrq"); + Date redDate2 = o2.getDate("shjh_shrq"); + if (redDate1 == null && redDate2 == null) return 0; + if (redDate1 == null) return -1; // null视为较小值 + if (redDate2 == null) return 1; + return redDate1.compareTo(redDate2); + }); + + // 2. 累乘符合条件的差额,初始值设为1 + BigDecimal product = BigDecimal.ONE; + + for (DynamicObject item : sortedEntries) { + try { + // 检查是否为赎回单(跳过非赎回条目) + DynamicObject shdh = item.getDynamicObject("shjh_shdh"); + if (shdh == null) { + continue; + } + + // 检查估值日期是否 ≤ 目标日期 + Date valDate = item.getDate("e_valuationdate"); + if (valDate == null || valDate.compareTo(date) > 0) { + continue; + } + + Object pkValue = shdh.getPkValue(); + DynamicObject dynamicObject = BusinessDataServiceHelper.loadSingle(pkValue, "cim_redeem"); + + // 安全获取数值字段 + BigDecimal copies = dynamicObject.getBigDecimal("copies"); // 赎回份额 + BigDecimal remainderCopies = dynamicObject.getBigDecimal("shjh_shrsyfe"); // 赎回日剩余份额 + + if (copies == null || remainderCopies == null || remainderCopies.compareTo(BigDecimal.ZERO) == 0) { + continue; // 跳过无效数据 + } + + // 计算 (1 - 赎回份额/剩余日份额) + BigDecimal ratio = copies.divide(remainderCopies, 10, RoundingMode.HALF_UP); + BigDecimal difference = BigDecimal.ONE.subtract(ratio); + + // 累乘 + product = product.multiply(difference).setScale(10, RoundingMode.HALF_UP); + + } catch (Exception e) { + // 记录错误并跳过当前条目 + logger.error("处理赎回单数据出错: " + e.getMessage(), e); + continue; + } + } + + return product; + } + /** * 计算天数规则: * 1. 计提日 <= 到期日:天数 = 计提日 - 计息日 @@ -543,18 +629,18 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu String day = "0"; // 默认值设为0 Date endDate = (expireDate != null) ? expireDate : accrualDate; - BigDecimal actualEarnings = BigDecimal.ZERO; +// BigDecimal actualEarnings = BigDecimal.ZERO; Long id = row.getLong(REPORT_FIELDS[13]); // id DynamicObject[] load = BusinessDataServiceHelper.load("cim_redeem", "id,redeemdate,lastmodifytime,realrevenue", (new QFilter("sourcebillid", QCP.equals, id)).toArray()); // 计算实际收益 - if (load != null && load.length != 0) { - for (DynamicObject dynamicObject : load) { - BigDecimal realrevenue = dynamicObject.getBigDecimal("realrevenue"); - actualEarnings = actualEarnings.add(realrevenue); - } - } +// if (load != null && load.length != 0) { +// for (DynamicObject dynamicObject : load) { +// BigDecimal realrevenue = dynamicObject.getBigDecimal("realrevenue"); +// actualEarnings = actualEarnings.add(realrevenue); +// } +// } if (valueDate != null) { String status = row.getString(REPORT_FIELDS[14]); // 状态 @@ -592,7 +678,7 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu row.set(DYNAMICS_FIELDS[10], isExpired); // 是否到期 row.set(REPORT_FIELDS[3], day); // 产品期限天数 - row.set(DYNAMICS_FIELDS[8], actualEarnings); // 实际收益 + //row.set(DYNAMICS_FIELDS[8], actualEarnings); // 实际收益 return day; } @@ -639,7 +725,7 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu BigDecimal netWorth, DynamicObject row, BigDecimal startBuyCopies, - BigDecimal redAmount + BigDecimal allRedProductAmount ) { if (expireDate==null){ expireDate=accrualDate; @@ -649,10 +735,9 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu // 检查所有参数是否非空 if (buyCopies != null && monthNetWorth != null && netWorth != null && startBuyCopies != null) { - // 计算:(持有份额 * 月末单位净值 - 购买份额 * 购买时单位净值) / 1000 + // 计算:(持有份额 * 月末单位净值+(所有赎回单金额+实际收益) - 购买份额 * 购买时单位净值) / 1000 revenue = buyCopies.multiply(monthNetWorth) - .add(redAmount) - .subtract(startBuyCopies.multiply(netWorth)) + .subtract(startBuyCopies.multiply(netWorth).multiply(allRedProductAmount)) .divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP); // 设置到表格行 @@ -669,6 +754,38 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu return revenue; } + /** + * 实际收益 = (持有份额 * 月末单位净值+(赎回单赎回金额、实际收益之和) - 购买份额 * 购买时单位净值) / 1000 + * @param buyCopies 持有份额(当前份额) + * @param monthNetWorth 月末单位净值(当前净值) + * @param netWorth 购买时单位净值(初始净值) + * @param row 表格行数据 + * @param startBuyCopies 购买份额(初始份额) + * @return 计算后的收益金额(保留2位小数) + */ + private void countActRevenueAmt( + BigDecimal buyCopies, + BigDecimal monthNetWorth, + BigDecimal netWorth, + DynamicObject row, + BigDecimal startBuyCopies, + BigDecimal redAmount + ) { + + BigDecimal revenue = BigDecimal.ZERO; + + // 检查所有参数是否非空 + if (buyCopies != null && monthNetWorth != null && netWorth != null && startBuyCopies != null) { + // 计算:(持有份额 * 月末单位净值+(所有赎回单金额+实际收益) - 购买份额 * 购买时单位净值) / 1000 + revenue = buyCopies.multiply(monthNetWorth) + .add(redAmount) + .subtract(startBuyCopies.multiply(netWorth)) + .divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP); + row.set(DYNAMICS_FIELDS[8], revenue); // 实际收益 + } + } + + // 辅助方法:比较赎回日期 private boolean isRedeemDateLater(Date newRedeemDate, Date existingRedeemDate) { if (newRedeemDate == null) return false; @@ -676,140 +793,4 @@ public class FinancialFormReport extends AbstractReportFormPlugin implements Plu return newRedeemDate.after(existingRedeemDate); } - /** - * 本月收益计算(严格按生效期间计算) - * @param monthNetWorth 月末单位净值 - * @param netWorth 单位净值 - * @param buyCopies 持有份额 - * @param valueDate 计息日 - * @param accrualDate 计提日 - * @param expireDate 到期日 - * @param row 表格 - * @return 本月收益金额 - */ - private BigDecimal countMonthRevenue(BigDecimal monthNetWorth,BigDecimal netWorth,BigDecimal buyCopies,Date valueDate,Date accrualDate,Date expireDate,DynamicObject row){ - BigDecimal monthRevenue = BigDecimal.ZERO; - if (monthNetWorth != null && netWorth != null && buyCopies != null && valueDate != null) { - - // 关键判断:计提日必须在计息日之后(产品已生效) - if (!accrualDate.before(valueDate)) { - - // 获取当月第一天(月初) - Date monthFirstDay = ReportUtils.getFirstDayOfMonth(accrualDate); - - // 情况1:产品已过期 - if (expireDate != null && expireDate.before(accrualDate)) { - // 仅在过期当月计算 - if (ReportUtils.isSameMonth(expireDate, accrualDate)) { - Date periodStart = valueDate.after(monthFirstDay) ? valueDate : monthFirstDay; - long effectiveDays = ReportUtils.getDaysBetween(periodStart, expireDate); - BigDecimal totalRevenue = buyCopies.multiply(monthNetWorth.subtract(netWorth)); - monthRevenue = ReportUtils.calculateProportionalRevenue( - totalRevenue, - ReportUtils.getDaysBetween(valueDate, expireDate), - effectiveDays - ); - } - } - // 情况2:产品未过期 - else { - Date periodStart = valueDate.after(monthFirstDay) ? valueDate : monthFirstDay; - long effectiveDays = ReportUtils.getDaysBetween(periodStart, accrualDate); - BigDecimal totalRevenue = buyCopies.multiply(monthNetWorth.subtract(netWorth)); - monthRevenue = ReportUtils.calculateProportionalRevenue( - totalRevenue, - ReportUtils.getDaysBetween(valueDate, expireDate != null ? expireDate : accrualDate), - effectiveDays - ); - } - } - // 计提日在计息日之前(产品未生效)则monthRevenue保持为0 - } - row.set(DYNAMICS_FIELDS[4], monthRevenue.setScale(2, RoundingMode.HALF_UP)); - return monthRevenue; - } - - /** - * 当月收益率 = 本月收益 / 金额(千元) * 100 * 12 - * @param amount 投资金额 - * @param monthRevenue 本月收益 - * @param row 表格 - */ - private void countMonthRate(BigDecimal amount,BigDecimal monthRevenue,DynamicObject row){ - if (amount.compareTo(BigDecimal.ZERO) != 0) { - BigDecimal monthRate = monthRevenue - .divide(amount, 10, RoundingMode.HALF_UP) // 先计算 (月收入/金额) - .multiply(new BigDecimal(1200)) // 再 ×1200(假设业务需要) - .setScale(2, RoundingMode.HALF_UP); // 最终保留2位小数 - - row.set(DYNAMICS_FIELDS[5], monthRate); - } else { - row.set(DYNAMICS_FIELDS[5], BigDecimal.ZERO); - } - } - - /** - * 本年累计收益 = 当年各月收益之和(按实际持有天数比例计算) - * @param monthNetWorth 月末单位净值 - * @param netWorth 单位净值 - * @param buyCopies 持有份额 - * @param valueDate 计息日 - * @param accrualDate 计提日 - * @param expireDate 到期日 - * @param row 表格 - */ - private BigDecimal countYearRevenue(BigDecimal monthNetWorth,BigDecimal netWorth,BigDecimal buyCopies,Date valueDate,Date accrualDate,Date expireDate,DynamicObject row){ - BigDecimal yearRevenue = BigDecimal.ZERO; - if (monthNetWorth != null && netWorth != null && buyCopies != null && valueDate != null) { - - // 获取计提日所在年份的起止时间 - Calendar cal = Calendar.getInstance(); - cal.setTime(accrualDate); - cal.set(Calendar.MONTH, Calendar.JANUARY); - cal.set(Calendar.DAY_OF_MONTH, 1); - cal.set(Calendar.HOUR_OF_DAY, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MILLISECOND, 0); - Date yearStart = cal.getTime(); - - cal.set(Calendar.MONTH, Calendar.DECEMBER); - cal.set(Calendar.DAY_OF_MONTH, 31); - Date yearEnd = cal.getTime(); - - // 核心判断:产品在当年有存续期(满足任意一条即可) - // 1. 计息日 <= 年末 且 到期日 >= 年初(跨年产品) - // 2. 到期日为null且计息日 <= 年末(未到期产品) - boolean isEffectiveThisYear = - (valueDate.before(yearEnd) || ReportUtils.isSameYear(valueDate, yearStart)) && - (expireDate == null || expireDate.after(yearStart)) || - (expireDate == null && (valueDate.before(yearEnd) || ReportUtils.isSameYear(valueDate, yearStart))); - - if (isEffectiveThisYear) { - // 计算实际生效时间段 - Date effectiveStart = valueDate.after(yearStart) ? valueDate : yearStart; - Date effectiveEnd = (expireDate == null || expireDate.after(yearEnd)) ? yearEnd : expireDate; - - // 计算本年有效天数 - long effectiveDays = ReportUtils.getDaysBetween(effectiveStart, effectiveEnd); - - // 计算总存续天数 - long totalDays = ReportUtils.getDaysBetween(valueDate, - expireDate != null ? expireDate : accrualDate); - - // 计算总收益 - BigDecimal totalRevenue = buyCopies.multiply(monthNetWorth.subtract(netWorth)); - - // 按比例计算本年收益 - yearRevenue = ReportUtils.calculateProportionalRevenue( - totalRevenue, - totalDays, - effectiveDays - ); - } - } - row.set(DYNAMICS_FIELDS[6], yearRevenue.setScale(2, RoundingMode.HALF_UP)); - return yearRevenue; - } - } \ No newline at end of file diff --git a/main/java/shjh/jhzj7/fi/fi/plugin/report/FinancialListReport.java b/main/java/shjh/jhzj7/fi/fi/plugin/report/FinancialListReport.java index 34f4507..8e4caa8 100644 --- a/main/java/shjh/jhzj7/fi/fi/plugin/report/FinancialListReport.java +++ b/main/java/shjh/jhzj7/fi/fi/plugin/report/FinancialListReport.java @@ -59,7 +59,7 @@ public class FinancialListReport extends AbstractReportListDataPlugin implements // 2. 查询理财申购单数据 StringBuilder selectFields = new StringBuilder(); assembleSQL(selectFields); - selectFields.append(",").append("billno"); + selectFields.append(",").append("billno,finorginfo"); DataSet mainDataSet = QueryServiceHelper.queryDataSet( this.getClass().getName(), "cim_finsubscribe", @@ -136,7 +136,7 @@ public class FinancialListReport extends AbstractReportListDataPlugin implements filters.add(new QFilter("finorginfo", QCP.in,bankNameIds)); } - if (bankNameIds.size()!=0){ + if (productTypeIds.size()!=0){ filters.add(new QFilter("investvarieties", QCP.in,productTypeIds)); } }