1、等额本金:每期本金相同
2、等额本息:每期还款额相同
/**
* @author wzh
* @date 2019-11-20 18:45
* @description 试算还款计划-入参
*/
@Data
@Builder
public class CalculateRepayPlanReq implements Serializable {
/**
* 借款金额(元),非空
*/
private BigDecimal principle;
/**
* 期限天,非空
*/
private Integer termDay;
/**
* 年利率,比如一年期贷款4.35,传入4.35,非空
*/
private BigDecimal yearRate;
/**
* 起息日,非空
*/
private Date beginProfitDate;
/**
* 费率集合,可空
*/
private List feeRulePojoList;
/**
* 特殊日期范围,例如:28-31
*/
private String specialDateRange;
/**
* 特殊日期调整日,27
*/
private String specialDateAdjustDay;
}
/**
* @Author: wzh
* @Date: 2019-03-28T15:33:47.526
* @Description: 还款计划
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RepayPlanRes implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 总期次
*/
@NotNull
private Integer repayNum;
/**
* 当前期次
*/
@NotNull
private Integer currentNum;
/**
* 开始时间
*/
@NotNull
private Date startDate;
/**
* 到期时间
*/
@NotNull
private Date endDate;
/**
* 收益天数
*/
@NotNull
private Integer profitDays;
/**
* 应还时间
*/
@NotNull
private Date preRepayDate;
/**
* 应还总额
*/
@NotNull
private BigDecimal preRepayAmt;
/**
* 应还本金
*/
@NotNull
private BigDecimal preRepayPrincipal;
/**
* 应还利息
*/
@NotNull
private BigDecimal preRepayInterest;
/**
* 应还手续费
*/
@NotNull
private BigDecimal preRepayFee;
/**
* 应还账户管理费
*/
@NotNull
private BigDecimal preRepayManagementFee;
/**
* 剩余本金
*/
@NotNull
private BigDecimal leftPrincipal;
}
/**
* 包装公共方法
*
* @author wzh
* @date 2019年09月23日11:27:04
*/
public abstract class AbstractCalculateServiceImpl implements CalculateService {
/**
* 期限天转期限月
* 备注:主要适用于按月计息的
* @param termDay
* @return
*/
protected Integer transTermMonth(Integer termDay) {
//按月计算,除以30取整
BigDecimal termDayBg=new BigDecimal(termDay);
return termDayBg.divide(new BigDecimal(30),0,BigDecimal.ROUND_HALF_UP).intValue();
}
/**
* 月利率
* 备注:主要适用于按月计息的
* @param yearRate
* @return
*/
protected BigDecimal transMonthRate(BigDecimal yearRate) {
//月利率
return yearRate.divide(new BigDecimal(12),6,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(0.01));
}
/**
* 返回日利率
*
* @param yearRate
* @return
*/
protected BigDecimal transDayRate(BigDecimal yearRate) {
return yearRate.divide(new BigDecimal(360),6,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(0.01));
}
/**
* 计算手续费
* @param principle 本金
* @param feeRulePojoList 费率规则
* @return
*/
protected BigDecimal calculateFee(BigDecimal principle,List feeRulePojoList) {
if(CollectionUtils.isEmpty(feeRulePojoList)){
return BigDecimal.ZERO;
}
BigDecimal feeTotal = BigDecimal.ZERO;
for(FeeRuleReq feeRulePojo:feeRulePojoList) {
BigDecimal fee = BigDecimal.ZERO;
EnumFeeType enumFeeType = feeRulePojo.getFeeType();
if (ONCE_SERVICE_FEE.equals(enumFeeType)) {
fee = principle.multiply(feeRulePojo.getFeeRate()).multiply(new BigDecimal(0.01));
} else if (FEE.equals(enumFeeType)) {
fee = principle.multiply(feeRulePojo.getFeeRate()).multiply(new BigDecimal(0.01));
}
feeTotal=feeTotal.add(fee);
}
return feeTotal;
}
/**
* 计算账户管理费
* @param principle 本金
* @param leftPrinciple 剩余本金
* @param feeRulePojoList 费率规则
* @return
*/
protected BigDecimal calculateManagementFee(BigDecimal principle, BigDecimal leftPrinciple, List feeRulePojoList) {
if(CollectionUtils.isEmpty(feeRulePojoList)){
return BigDecimal.ZERO;
}
BigDecimal feeTotal = BigDecimal.ZERO;
for(FeeRuleReq feeRulePojo:feeRulePojoList) {
BigDecimal fee = BigDecimal.ZERO;
EnumFeeType enumFeeType = feeRulePojo.getFeeType();
if (MANAGEMENT_FEE.equals(enumFeeType)) {
if (feeRulePojo.getFeeCalculateType() == EnumFeeCalculateType.LOANAMT_FEERATE) {
fee = principle.multiply(feeRulePojo.getFeeRate()).multiply(new BigDecimal(0.01));
} else if (feeRulePojo.getFeeCalculateType() == EnumFeeCalculateType.LEFTPRINCIPLE_FEERATE) {
fee = leftPrinciple.multiply(feeRulePojo.getFeeRate()).multiply(new BigDecimal(0.01));
}
}
feeTotal=feeTotal.add(fee);
}
return feeTotal;
}
}
/**
* 等额本息
*
* @author wzh
* @date 2019年09月19日16:17:12
*/
@Slf4j
@Component
public class EqualAmtInterestCalculate extends AbstractCalculateServiceImpl {
@Override
public List calculateRepayPlan(CalculateRepayPlanReq calculateRepayPlanDto) {
BigDecimal principle=calculateRepayPlanDto.getPrinciple();
Date date=calculateRepayPlanDto.getBeginProfitDate();
List repayPlanList=new ArrayList();
//转期限月
Integer termMonth=transTermMonth(calculateRepayPlanDto.getTermDay());
//月利率
BigDecimal monthRate=transMonthRate(calculateRepayPlanDto.getYearRate());
/**
* 计算每期应还息费总额=(贷款本金×期利率×(1+期利率)^还款期数)÷((1+期利率)^还款期数-1) (四舍五入)
*/
BigDecimal periodAmt = principle.multiply(monthRate).multiply((BigDecimal.ONE.add(monthRate)).pow(termMonth))
.divide(((BigDecimal.ONE.add(monthRate)).pow(termMonth)).subtract(BigDecimal.ONE), 2,BigDecimal.ROUND_HALF_UP);
//应还总利息
//BigDecimal preRepayInterestTotal=principle.multiply(BigDecimal.valueOf(repayNum+1)).multiply(monthRate).divide(new BigDecimal(2));
//剩余本金
BigDecimal leftPrincipal=principle;
for(int i=1;i<=termMonth;i++) {
RepayPlanRes repayPlanPojo = new RepayPlanRes();
//总期次
repayPlanPojo.setRepayNum(termMonth);
//当期期次
repayPlanPojo.setCurrentNum(i);
if(i==1){
//起息日
repayPlanPojo.setStartDate(date);
}else{
Date startDate=DateUtil.dateAddMonth(date,i-1);
if(!CollectionUtils.isEmpty(dayList)&&dayList.contains(DateUtil.formateDate(startDate,DateUtil.FMT_DD))){
//处于范围期,下移一个月,再取月初X号
Date nextMonthDate=DateUtil.dateAddMonth(startDate,1);
repayPlanPojo.setStartDate(DateUtil.getMonthBegin(nextMonthDate, Integer.parseInt(calculateRepayPlanDto.getSpecialDateAdjustDay())));
}else{
//起息日
repayPlanPojo.setStartDate(startDate);
}
}
Date endDate=DateUtil.dateAddMonth(date,i);
if(!CollectionUtils.isEmpty(dayList)&&dayList.contains(DateUtil.formateDate(endDate,DateUtil.FMT_DD))){
//处于范围期,下移一个月,再取月初X号
Date nextMonthDate=DateUtil.dateAddMonth(endDate,1);
repayPlanPojo.setEndDate(DateUtil.getMonthBegin(nextMonthDate, Integer.parseInt(calculateRepayPlanDto.getSpecialDateAdjustDay())));
//应还日
repayPlanPojo.setPreRepayDate(DateUtil.getMonthBegin(nextMonthDate, Integer.parseInt(calculateRepayPlanDto.getSpecialDateAdjustDay())));
}else{
//起息日
repayPlanPojo.setEndDate(endDate);
//应还日
repayPlanPojo.setPreRepayDate(endDate);
}
//收益天数
int profitDays=DateUtil.getBetweenDays(repayPlanPojo.getStartDate(),repayPlanPojo.getEndDate());
//应还利息
BigDecimal preRepayInterest=leftPrincipal.multiply(monthRate);
//应还利息赋值
repayPlanPojo.setPreRepayInterest(preRepayInterest.setScale(2,BigDecimal.ROUND_HALF_UP));
//应还本金
BigDecimal preRepayPrinciple=periodAmt.subtract(preRepayInterest).setScale(2,BigDecimal.ROUND_HALF_UP);
//应还本金,判断是否最后一期
if(i==termMonth){
//最后一期应还本金
repayPlanPojo.setPreRepayPrincipal(leftPrincipal.setScale(2,BigDecimal.ROUND_HALF_UP));
//应还利息赋值
repayPlanPojo.setPreRepayInterest(periodAmt.subtract(leftPrincipal).setScale(2,BigDecimal.ROUND_HALF_UP));
}else{
//应还本金赋值
repayPlanPojo.setPreRepayPrincipal(preRepayPrinciple.setScale(2,BigDecimal.ROUND_HALF_UP));
//应还利息赋值
repayPlanPojo.setPreRepayInterest(preRepayInterest.setScale(2,BigDecimal.ROUND_HALF_UP));
}
//应还手续费
BigDecimal preRepayFee=calculateFee(principle,calculateRepayPlanDto.getFeeRulePojoList());
repayPlanPojo.setPreRepayFee(preRepayFee);
//应还账户管理费
BigDecimal preRepayManagementFee=calculateManagementFee(principle,leftPrincipal,calculateRepayPlanDto.getFeeRulePojoList());
repayPlanPojo.setPreRepayManagementFee(preRepayManagementFee);
//应还总额=应还本金+应还利息+应还手续费+应还账户管理费
repayPlanPojo.setPreRepayAmt(periodAmt.add(preRepayFee.add(preRepayManagementFee)).setScale(2,BigDecimal.ROUND_HALF_UP));
//剩余应还本金
repayPlanPojo.setLeftPrincipal(leftPrincipal.setScale(2,BigDecimal.ROUND_HALF_UP));
//以下内容暂且注释
//repayPlanPojo.setLeftRepayPrincipal(leftPrincipal.setScale(2,BigDecimal.ROUND_HALF_UP));
//剩余应还利息
//BigDecimal leftRepayInterest=preRepayInterestTotal.subtract(preRepayInterest);
//repayPlanPojo.setLeftRepayInterest(leftRepayInterest.setScale(4,BigDecimal.ROUND_HALF_UP));
//剩余应还总金额
//repayPlanPojo.setLeftRepayAmt(leftPrincipal.add(leftRepayInterest).setScale(4,BigDecimal.ROUND_HALF_UP));
//当期——剩余应还本金
leftPrincipal=leftPrincipal.subtract(preRepayPrinciple);
repayPlanList.add(repayPlanPojo);
}
return repayPlanList;
}
}
/**
* 等额本金
*
* @author wzh
* @date 2019年09月19日16:16:54
*/
@Component
public class EqualAmtPrincipleCalculate extends AbstractCalculateServiceImpl {
@Override
public List calculateRepayPlan(CalculateRepayPlanReq calculateRepayPlanDto) {
BigDecimal principle=calculateRepayPlanDto.getPrinciple();
Date date=calculateRepayPlanDto.getBeginProfitDate();
List repayPlanList=new ArrayList();
//转期限月
Integer termMonth=transTermMonth(calculateRepayPlanDto.getTermDay());
//月利率
BigDecimal monthRate=transMonthRate(calculateRepayPlanDto.getYearRate());
//日利率
//BigDecimal dayRate=yearRate.divide(new BigDecimal(360),6,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(0.01));
//应还总利息
//BigDecimal preRepayInterestTotal=principle.multiply(BigDecimal.valueOf(repayNum+1)).multiply(monthRate).divide(new BigDecimal(2));
//必须进行循环处理,最后一期用总数减去累加值,防止小数点误差
BigDecimal preRepayPrincipleTotal=BigDecimal.ZERO;
BigDecimal preRepayPrinciple=principle.divide(BigDecimal.valueOf(termMonth),2,BigDecimal.ROUND_HALF_UP).setScale(2,BigDecimal.ROUND_HALF_UP);
for(int i=1;i<=termMonth;i++) {
RepayPlanRes repayPlanPojo = new RepayPlanRes();
//总期次
repayPlanPojo.setRepayNum(termMonth);
//当期期次
repayPlanPojo.setCurrentNum(i);
//起息日
repayPlanPojo.setStartDate(DateUtil.dateAddMonth(date,i-1));
//结息日
repayPlanPojo.setEndDate(DateUtil.dateAddMonth(date,i));
//应还日
repayPlanPojo.setPreRepayDate(DateUtil.dateAddMonth(date,i));
//收益天数
repayPlanPojo.setProfitDays(DateUtil.getBetweenDays(DateUtil.dateAddMonth(date,i-1),DateUtil.dateAddMonth(date,i)));
//应还本金,判断是否最后一期
if(i==termMonth){
//最后一期应还本金
repayPlanPojo.setPreRepayPrincipal(principle.subtract(preRepayPrincipleTotal));
}else{
//应还本金
repayPlanPojo.setPreRepayPrincipal(preRepayPrinciple);
}
//剩余本金
BigDecimal leftPrincipal=principle.subtract(preRepayPrincipleTotal);
//应还利息
BigDecimal preRepayInterest=leftPrincipal.multiply(monthRate);
//应还利息
repayPlanPojo.setPreRepayInterest(preRepayInterest.setScale(2,BigDecimal.ROUND_HALF_UP));
//应还费用
BigDecimal preRepayFee=calculateFee(principle,calculateRepayPlanDto.getFeeRulePojoList());
repayPlanPojo.setPreRepayFee(preRepayFee);
//应还账户管理费
BigDecimal preRepayManagementFee=calculateManagementFee(principle,leftPrincipal,calculateRepayPlanDto.getFeeRulePojoList());
repayPlanPojo.setPreRepayManagementFee(preRepayManagementFee);
//应还总额=应还本金+应还利息+应还手续费+应还账户管理费
repayPlanPojo.setPreRepayAmt(preRepayPrinciple.add(preRepayInterest).add(preRepayFee.add(preRepayManagementFee)).setScale(2,BigDecimal.ROUND_HALF_UP));
//剩余应还本金
repayPlanPojo.setLeftPrincipal(leftPrincipal.setScale(2,BigDecimal.ROUND_HALF_UP));
//以下内容暂且注释
//repayPlanPojo.setLeftRepayPrincipal(leftPrincipal.setScale(2,BigDecimal.ROUND_HALF_UP));
//剩余应还利息
//BigDecimal leftRepayInterest=preRepayInterestTotal.subtract(preRepayInterest);
//repayPlanPojo.setLeftRepayInterest(leftRepayInterest.setScale(4,BigDecimal.ROUND_HALF_UP));
//剩余应还总金额
//repayPlanPojo.setLeftRepayAmt(leftPrincipal.add(leftRepayInterest).setScale(4,BigDecimal.ROUND_HALF_UP));
//当期——累计应还总本金
preRepayPrincipleTotal=preRepayPrincipleTotal.add(preRepayPrinciple);
repayPlanList.add(repayPlanPojo);
}
return repayPlanList;
}
}