理财收益计提报表

This commit is contained in:
李贵强 2025-04-11 12:12:43 +08:00
parent 4c4e67cdd3
commit 986d9ac682
5 changed files with 581 additions and 2 deletions

View File

@ -80,8 +80,8 @@ public class RecBillChangeListExtendPlugin extends AbstractListPlugin implements
}
// 收款类型校验
if (!Arrays.asList("103", "109", "100").contains(typeNumber)) {
this.getView().showTipNotification("所选单据不满足变更条件,只有收款类型=“预付款退回/员工还款/销售回款”的收款单允许变更。");
if (Arrays.asList("103", "109", "100").contains(typeNumber)) {
this.getView().showTipNotification("所选单据不满足变更条件,收款类型=“预付款退回/员工还款/销售回款”的收款单允许变更。");
evt.setCancel(true);
return;
}

View File

@ -0,0 +1,314 @@
package shjh.jhzj7.fi.fi.plugin.report;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.entity.report.FilterItemInfo;
import kd.bos.entity.report.ReportColumn;
import kd.bos.entity.report.ReportQueryParam;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.report.ReportList;
import kd.bos.report.plugin.AbstractReportFormPlugin;
import kd.sdk.plugin.Plugin;
import shjh.jhzj7.fi.fi.plugin.report.util.ReportUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
/**
* 报表界面插件
* 理财收益计提报表界面插件
*/
public class FinancialFormReport extends AbstractReportFormPlugin implements Plugin {
private final static Log logger = LogFactory.getLog(FinancialFormReport.class);
private static final String FILTER_DATE = "shjh_filterdate";
private static final String[] REPORT_FIELDS = {
"shjh_bankname", "shjh_productname", "shjh_producttype", "shjh_productterm",
"shjh_amount", "shjh_buycopies", "shjh_iopv", "shjh_buydate", "shjh_valuedate",
"shjh_expiredate", "shjh_planrevenue", "shjh_monthiopv", "shjh_monthiopvdate"
};
private static final String[] DYNAMICS_FIELDS = {
"shjh_projectrevenueamt","shjh_date","shjh_days","shjh_revenueamt",
"shjh_monthrevenueamt","shjh_monthrate","shjh_yearrevenueamt"
};
@Override
public void beforeQuery(ReportQueryParam queryParam) {
super.beforeQuery(queryParam);
ReportList reportList = getControl("reportlistap");
reportList.getColumns().add(ReportUtils.createReportColumn(new String [] { DYNAMICS_FIELDS[0], "预计收益(千元)", ReportColumn.TYPE_DECIMAL , String.valueOf(2)}));
reportList.getColumns().add(ReportUtils.createReportColumn(new String [] { DYNAMICS_FIELDS[1], "计提日", ReportColumn.TYPE_DATE }));
reportList.getColumns().add(ReportUtils.createReportColumn(new String [] { DYNAMICS_FIELDS[2], "天数", ReportColumn.TYPE_BIGINT }));
reportList.getColumns().add(ReportUtils.createReportColumn(new String [] { DYNAMICS_FIELDS[3], "收益计提(千元)", ReportColumn.TYPE_DECIMAL , String.valueOf(2)}));
reportList.getColumns().add(ReportUtils.createReportColumn(new String [] { DYNAMICS_FIELDS[4], "本月收益(千元)", ReportColumn.TYPE_DECIMAL , String.valueOf(2)}));
reportList.getColumns().add(ReportUtils.createReportColumn(new String [] { DYNAMICS_FIELDS[5], "当月收益率(%", ReportColumn.TYPE_DECIMAL , String.valueOf(2)}));
reportList.getColumns().add(ReportUtils.createReportColumn(new String [] { DYNAMICS_FIELDS[6], "本年累计收益(千元)", ReportColumn.TYPE_DECIMAL , String.valueOf(2)}));
}
@Override
public void processRowData(String gridPK, DynamicObjectCollection rowData, ReportQueryParam queryParam) {
super.processRowData(gridPK, rowData, queryParam);
// 获取筛选条件中的计提日
Date accrualDate = queryParam.getFilter().getDate(FILTER_DATE);
Calendar calendar = Calendar.getInstance();
calendar.setTime(accrualDate);
// 遍历每一行数据
Iterator<DynamicObject> iterator = rowData.iterator();
while (iterator.hasNext()) {
DynamicObject row = iterator.next();
//跳过小计行
if (row.getString(REPORT_FIELDS[0]).contains("-小计")){
continue;
}
// 基础字段获取添加null检查
BigDecimal amount = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[4]); // 原始金额
row.set(REPORT_FIELDS[4],amount.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP));
BigDecimal buyCopies = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[5]); // 持有份额
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]); // 预计业绩比较基准%
BigDecimal monthNetWorth = ReportUtils.getBigDecimalValue(row, REPORT_FIELDS[11]); // 月末单位净值
// 1. 设置计提日
row.set(DYNAMICS_FIELDS[1], accrualDate);
// 2. 计算天数 = 计提日 - 计息日
countDays(valueDate,accrualDate,row);
// 3. 计算产品期限总天数=到期日-购买日若到期日为空则用计提日-购买日
String day = countProductTerm(buyDate, expireDate, accrualDate, row);
// 4. 预计收益 = 产品期限 * 金额(千元) * 预计业绩比较基准 / 365
BigDecimal proRevenue = countProRevenue(expectedRate, day, amount, row);
// 5. 收益计提 = 持有份额 * (月末单位净值 - 购买时单位净值) / 1000
BigDecimal revenueAmt = countRevenueAmt(buyCopies, monthNetWorth, netWorth, row);
// 6. 本月收益计算严格按生效期间计算
BigDecimal monthRevenue = countMonthRevenue(monthNetWorth, netWorth, buyCopies, valueDate, accrualDate, expireDate, row);
// 7. 当月收益率 = 本月收益 / 金额(千元) * 100 * 12
countMonthRate(amount,monthRevenue,row);
// 8. 本年累计收益 = 当年各月收益之和按实际持有天数比例计算
BigDecimal yearRevenue = countYearRevenue(monthNetWorth, netWorth, buyCopies, valueDate, accrualDate, expireDate, row);
}
}
/**
* 计算天数 = 计提日 - 计息日
* @param valueDate 计息日
* @param accrualDate 计提日
* @param row 表格
*/
private void countDays(Date valueDate,Date accrualDate,DynamicObject row){
if (valueDate != null) {
long days = (accrualDate.getTime() - valueDate.getTime()) / (1000 * 60 * 60 * 24);
row.set(DYNAMICS_FIELDS[2], new BigDecimal(days));
} else {
row.set(DYNAMICS_FIELDS[2], BigDecimal.ZERO);
}
}
/**
* 计算产品期限总天数=到期日-购买日若到期日为空则用计提日-购买日
* @param buyDate 购买日
* @param expireDate 到期日
* @param accrualDate 计提日
* @param row 表格
* @return 总天数
*/
private String countProductTerm(Date buyDate,Date expireDate,Date accrualDate,DynamicObject row){
String day = "0"; // 默认值设为0
if (buyDate != null) {
Date endDate = (expireDate != null) ? expireDate : accrualDate;
// 检查计提日/到期日是否早于购买日
if (endDate.getTime() >= buyDate.getTime()) {
long termDays = (endDate.getTime() - buyDate.getTime()) / (1000 * 60 * 60 * 24);
day = String.valueOf(termDays);
}
// 如果endDate早于buyDate保持day=0
}
row.set(REPORT_FIELDS[3], day);
return day;
}
/**
* 预计收益 = 产品期限 * 金额(千元) * 预计业绩比较基准 / 365
* @param expectedRate 预计业绩比较基准%
* @param day 总天数
* @param amount 投资金额
* @param row 表格
*/
private BigDecimal countProRevenue(BigDecimal expectedRate,String day,BigDecimal amount,DynamicObject row) {
BigDecimal projectRevenue = BigDecimal.ZERO;
if (expectedRate != null) {
projectRevenue = new BigDecimal(day).multiply(amount.divide(new BigDecimal(1000), 10, RoundingMode.HALF_UP))
.multiply(expectedRate.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP))
.divide(new BigDecimal(365), 2, RoundingMode.HALF_UP);
row.set(DYNAMICS_FIELDS[0], projectRevenue);
}
return projectRevenue;
}
/**
* 收益计提 = 持有份额 * (月末单位净值 - 购买时单位净值) / 1000
* @param buyCopies 持有份额
* @param monthNetWorth 月末单位净值
* @param netWorth 购买时单位净值
* @param row 表格
*/
private BigDecimal countRevenueAmt(BigDecimal buyCopies,BigDecimal monthNetWorth,BigDecimal netWorth,DynamicObject row){
BigDecimal revenue=BigDecimal.ZERO;
if (buyCopies != null && monthNetWorth != null && netWorth != null) {
revenue = buyCopies.multiply(monthNetWorth.subtract(netWorth))
.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP);
row.set(DYNAMICS_FIELDS[3], revenue);
}
return revenue;
}
/**
* 本月收益计算严格按生效期间计算
* @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;
}
}

View File

@ -0,0 +1,175 @@
package shjh.jhzj7.fi.fi.plugin.report;
import kd.bos.algo.DataSet;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.entity.report.AbstractReportColumn;
import kd.bos.entity.report.AbstractReportListDataPlugin;
import kd.bos.entity.report.FilterItemInfo;
import kd.bos.entity.report.ReportQueryParam;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.ORM;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.QueryServiceHelper;
import kd.sdk.plugin.Plugin;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 报表取数插件
* 理财收益计提报表取数
*/
public class FinancialListReport extends AbstractReportListDataPlugin implements Plugin {
private static final Log logger = LogFactory.getLog(FinancialListReport.class);
// 理财申购单字段
private static final String[] FINANCIAL_FIELDS = {
"finorginfo.name", "productname", "revenuetype", "term", "amount",
"buycopies", "iopv", "purchasedate", "valuedate", "expiredate", "planrevenue"
};
// 报表输出字段
private static final String[] REPORT_FIELDS = {
"shjh_bankname", "shjh_productname", "shjh_producttype", "shjh_productterm",
"shjh_amount", "shjh_buycopies", "shjh_iopv", "shjh_buydate", "shjh_valuedate",
"shjh_expiredate", "shjh_planrevenue", "shjh_monthiopv", "shjh_monthiopvdate"
};
// 筛选条件字段名
private static final String FILTER_BANK_NAME = "shjh_filtername";
private static final String FILTER_PRODUCT_NAME = "shjh_filterproduct";
private static final String FILTER_BUY_DATE = "shjh_filterbuydate";
private static final String FILTER_START_DATE = "shjh_startdate";
private static final String FILTER_END_DATE = "shjh_enddate";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
@Override
public DataSet query(ReportQueryParam param, Object context) throws Throwable {
// 1. 构建查询条件
List<QFilter> filters = buildFilters(param.getFilter().getFilterItems());
filters.add(new QFilter("billstatus", QCP.equals, "C")); // 只查询已审核单据
// 2. 查询理财申购单数据
StringBuilder selectFields = new StringBuilder();
assembleSQL(selectFields);
selectFields.append(",").append("billno");
DataSet mainDataSet = QueryServiceHelper.queryDataSet(
this.getClass().getName(),
"cim_finsubscribe",
String.valueOf(selectFields),
filters.toArray(new QFilter[0]),
null
);
// 3. 查询理财收益预提数据
DataSet addDataSet = QueryServiceHelper.queryDataSet(
this.getClass().getName() + "1",
"cim_intbill_batch",
"entry.finbillno, entry.shjh_nowamount AS shjh_monthiopv, preintdate AS shjh_monthiopvdate",
null,
null
);
// 4. 合并数据并返回结果
return processAndMergeDatasets(mainDataSet, addDataSet);
}
/**
* 根据界面筛选条件构建QFilter列表
*/
private List<QFilter> buildFilters(List<FilterItemInfo> filterItems) {
List<QFilter> filters = new ArrayList<>();
for (FilterItemInfo filterItem : filterItems) {
Object value = filterItem.getValue();
Date date = filterItem.getDate();
switch (filterItem.getPropName()) {
case FILTER_BANK_NAME: // 银行筛选
if (value != null) {
Long bankId = (Long) ((DynamicObject) value).getPkValue();
filters.add(new QFilter("finorginfo", QCP.equals, bankId));
}
break;
case FILTER_PRODUCT_NAME: // 产品筛选
if (value != null) {
Long productId = (Long) ((DynamicObject) value).getPkValue();
filters.add(new QFilter("product", QCP.equals, productId));
}
break;
case FILTER_BUY_DATE: // 购买日筛选
if (date != null) {
filters.add(new QFilter("purchasedate", QCP.equals, DATE_FORMAT.format(date)));
}
break;
case FILTER_START_DATE: // 计息日筛选
if (date != null) {
filters.add(new QFilter("valuedate", QCP.equals, DATE_FORMAT.format(date)));
}
break;
case FILTER_END_DATE: // 到期日筛选
if (date != null) {
filters.add(new QFilter("expiredate", QCP.equals, DATE_FORMAT.format(date)));
}
break;
}
}
return filters;
}
/**
* 处理并合并数据集
*/
private DataSet processAndMergeDatasets(DataSet mainDataSet, DataSet addDataSet) {
// 关联两个数据集
DataSet joinedDataSet = mainDataSet.join(addDataSet)
.on("billno", "entry.finbillno")
.select(REPORT_FIELDS)
.finish();
// 生成按银行分组的小计行
DataSet summaryDataSet = joinedDataSet.groupBy(new String[]{REPORT_FIELDS[0]})
.sum(REPORT_FIELDS[4]) // 对金额字段求和
.finish()
.addField("'-'", REPORT_FIELDS[1]) // 产品名称
.addField("'-'", REPORT_FIELDS[2]) // 产品类型
.addField("'-'", REPORT_FIELDS[3]) // 产品期限
.addField("0L", REPORT_FIELDS[5]) // 持有份数
.addField("0L", REPORT_FIELDS[6]) // 单位净值
.addField("NULL", REPORT_FIELDS[7]) // 购买日
.addField("NULL", REPORT_FIELDS[8]) // 计息日
.addField("NULL", REPORT_FIELDS[9]) // 到期日
.addField("0L", REPORT_FIELDS[10]) // 预计收益
.addField("0L", REPORT_FIELDS[11]) // 月末净值
.addField("NULL", REPORT_FIELDS[12]) // 净值报告日
.select("concat(shjh_bankname+'-小计') as " + String.join(",", REPORT_FIELDS))
.select(String.join(",", REPORT_FIELDS));
// 合并明细数据和小计数据并按银行名称排序
return joinedDataSet.union(summaryDataSet)
.orderBy(new String[]{REPORT_FIELDS[0]});
}
/**
* 组装SQL
*
* @param selectFields
*/
private void assembleSQL(StringBuilder selectFields) {
for (int i = 0; i < FINANCIAL_FIELDS.length; i++) {
if (i == FINANCIAL_FIELDS.length-1) {
selectFields.append(FINANCIAL_FIELDS[i]).append(" as ").append(REPORT_FIELDS[i]);
}else {
selectFields.append(FINANCIAL_FIELDS[i]).append(" as ").append(REPORT_FIELDS[i]).append(",");
}
}
}
}

View File

@ -102,6 +102,7 @@ public class RegularListReport extends AbstractReportListDataPlugin implements P
logger.error(e.getMessage());
}
// 按组织名称排序这样底部的合计数据就会与上面的组织名称排在一起
assert unionDataSet != null;
return unionDataSet.orderBy(new String[]{FIELDS[0]});
}

View File

@ -0,0 +1,89 @@
package shjh.jhzj7.fi.fi.plugin.report.util;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.LocaleString;
import kd.bos.entity.report.ReportColumn;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Date;
public class ReportUtils {
/**
* 动态创建报表列表字段列
* @param columnInfo
* @return
*/
public static ReportColumn createReportColumn(String [] columnInfo) {
ReportColumn reportColumn = new ReportColumn();
// 设置报表列字段的标识
reportColumn.setFieldKey(columnInfo[0]);
// 设置报表列字段的标识
reportColumn.setCaption(new LocaleString(columnInfo[1]));
// 设置报表列字段的类型
reportColumn.setFieldType(columnInfo[2]);
// 设置报表列字段的精度
if (columnInfo.length>3){
reportColumn.setScale(Integer.parseInt(columnInfo[3]));
}
return reportColumn;
}
// 辅助方法获取某个月的第一天
public static Date getFirstDayOfMonth(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.DAY_OF_MONTH, 1);
return cal.getTime();
}
// 安全获取BigDecimal值
public static BigDecimal getBigDecimalValue(DynamicObject row, String fieldName) {
Object value = row.get(fieldName);
if (value instanceof BigDecimal) {
return (BigDecimal) value;
} else if (value instanceof Number) {
return BigDecimal.valueOf(((Number) value).doubleValue());
}
return BigDecimal.ZERO;
}
// 辅助方法按比例计算收益
public static BigDecimal calculateProportionalRevenue(BigDecimal totalRevenue, long totalDays, long effectiveDays) {
if (totalDays <= 0 || effectiveDays <= 0) {
return BigDecimal.ZERO;
}
return totalRevenue
.divide(new BigDecimal(totalDays), 10, RoundingMode.HALF_UP)
.multiply(new BigDecimal(effectiveDays))
.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP); // 转换为千元单位
}
// 辅助方法计算两个日期之间的天数
public static long getDaysBetween(Date start, Date end) {
if (start == null || end == null) return 0;
return (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24) + 1;
}
// 辅助方法判断是否同月
public static boolean isSameMonth(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
&& cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
}
// 辅助方法判断是否同年
public static boolean isSameYear(Date date1, Date date2) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
return cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
}
}