/** * @Project: hehenian-biz-service * @Package com.hehenian.biz.common.settle * @Title: SettleCalculatorUtils.java * @Description: TODO * @author: liuzgmf * @date 2015年1月6日 上午11:01:49 * @Copyright: HEHENIAN Co.,Ltd. All rights reserved. * @version V1.0 */ package com.hehenian.biz.common.settle; import java.util.Date; import java.util.List; import com.hehenian.biz.common.loan.dataobject.LoanRepaymentFeeDo; import com.hehenian.biz.common.system.dataobject.FeeRuleDo; import com.hehenian.biz.common.system.dataobject.FeeRuleDo.GatherWay; import com.hehenian.biz.common.system.dataobject.FeeRuleDo.RuleType; import com.hehenian.biz.common.system.dataobject.SettDetailDo; import com.hehenian.biz.common.system.dataobject.SettSchemeDo; import com.hehenian.biz.common.system.dataobject.SettSchemeDo.SettleWay; import com.hehenian.biz.common.util.CalculateUtils; /** * * @author: liuzgmf * @date 2015年1月6日 上午11:01:49 */ public class SettleCalculatorUtils { private static final SettleCalculator fpicSettleCalculator = new FPICSettleCalculator(); private static final SettleCalculator lpSettleCalculator = new LPSettleCalculator(); private static final SettleCalculator iifpSettleCalculator = new IIFPSettleCalculator(); private static final SettleCalculator mifpSettleCalculator = new MIFPSettleCalculator(); private static final SettleCalculator piSettleCalculator = new PISettleCalculator(); private static final SettleCalculator hhn24SettleCalculator = new HHN24SettleCalculator(); // 合和贷24期 private static final SettleCalculator hhn36SettleCalculator = new HHN36SettleCalculator(); // 合和贷36期 private static final SettleCalculator elSettleCalculator = new ELSettleCalculator(); // 精英贷 /** * 根据还款方式获取还款结算计算器 * * @param schemeCode * @return */ public static SettleCalculator createSettleCalculator(SettleWay repayWay) { if (repayWay.equals(SettleWay.FPIC)) { return fpicSettleCalculator; } else if (repayWay.equals(SettleWay.LP)) { return lpSettleCalculator; } else if (repayWay.equals(SettleWay.IIFP)) { return iifpSettleCalculator; } else if (repayWay.equals(SettleWay.MIFP)) { return mifpSettleCalculator; } else if (repayWay.equals(SettleWay.PI)) { return piSettleCalculator; } else if (repayWay.equals(SettleWay.HHD24)) { return hhn24SettleCalculator; } else if (repayWay.equals(SettleWay.HHD36)) { return hhn36SettleCalculator; } else if (repayWay.equals(SettleWay.EL)) { return elSettleCalculator; } else { throw new RuntimeException("未知还款类型!"); } } /** * 计算借贷的结算明细信息 * * @param loanAmount * 借款金额 * @param loanPeriod * 借款期限 * @param loanAnnualRate * 借款年利率 * @param investAnnualRate * 投资年利率 * @param settSchemeDo * 结算方案对象 * @return * @author: liuzgmf * @date: 2015年1月6日上午10:50:35 */ public static List<SettDetailDo> calSettDetail(Double loanAmount, Integer loanPeriod, Double loanAnnualRate, Double investAnnualRate, SettSchemeDo settSchemeDo) { SettleCalculator repaySettleCalculator = createSettleCalculator(settSchemeDo.getRepayWay()); SettleCalculator receiptSettleCalculator = createSettleCalculator(settSchemeDo.getReceiptWay()); List<SettDetailDo> detailDoList = repaySettleCalculator.calSettDetail(loanAmount, loanPeriod, getLoanAnnualRate(loanAnnualRate, investAnnualRate, settSchemeDo)); List<SettDetailDo> retDetailDoList = receiptSettleCalculator.calSettDetail(loanAmount, loanPeriod, investAnnualRate); if (detailDoList.size() != retDetailDoList.size()) { throw new RuntimeException("结算方案[" + settSchemeDo.getSchemeId() + "]还款方式和回款方式不匹配!"); } // 计算咨询费,咨询费=还款利息-回款利息 //咨询费 = 还款总额-回款总额 2015-3-30修改 for (SettDetailDo detailDo : retDetailDoList) { for (SettDetailDo repaySettDetailDo : detailDoList) { if (detailDo.getPeriod().intValue() == repaySettDetailDo.getPeriod().intValue()) { detailDo.setConsultFee(CalculateUtils.sub( CalculateUtils.add(repaySettDetailDo.getInterest(), repaySettDetailDo.getPrincipal()), CalculateUtils.add(detailDo.getInterest(), detailDo.getPrincipal()))); RuleType[] ruleTypes = new RuleType[] { RuleType.CREDIT_FEE }; double creditFee = calSettleFee(detailDo, settSchemeDo, loanAmount, loanPeriod, ruleTypes); detailDo.setConsultFee(CalculateUtils.add(detailDo.getConsultFee(), creditFee));// 咨询费=咨询费+征信费 break; } } } // 计算服务费 for (SettDetailDo detailDo : retDetailDoList) { // 计入服务费的类型包括借款手续费,其他费用 RuleType[] ruleTypes = new RuleType[] { RuleType.SERV_FEE, RuleType.OTHER }; double servFee = calSettleFee(detailDo, settSchemeDo, loanAmount, loanPeriod, ruleTypes); detailDo.setServFee(servFee); } return retDetailDoList; } /** * 还款计划表展示 * @param loanAmount 借款金额 * @param loanPeriod 借款期限 * @param loanAnnualRate 借款年利率 * @param settSchemeDo 结算方案对象 * @return */ public static List<SettDetailDo> calSettDetailForRepayPlanShow(Double loanAmount, Integer loanPeriod, Double loanAnnualRate,SettSchemeDo settSchemeDo,Date startDate){ SettleCalculator repaySettleCalculator = createSettleCalculator(settSchemeDo.getRepayWay()); List<SettDetailDo> detailDoList = repaySettleCalculator.calSettDetail(loanAmount, loanPeriod,loanAnnualRate,startDate); for(SettDetailDo detailDo : detailDoList){ double servFee = calSettleFeeForRepayPlanShow(detailDo, settSchemeDo, loanAmount, loanPeriod); detailDo.setInterest(CalculateUtils.add(detailDo.getInterest(),servFee)); } return detailDoList; } /** * 放款后生成还款计划表 * @param loanAmount * @param loanPeriod * @param loanAnnualRate * @param investAnnualRate * @param settSchemeDo * @return */ public static List<SettDetailDo> calSettDetailForRepayPlanRecord(Double loanAmount, Integer loanPeriod, Double loanAnnualRate,Double investAnnualRate,SettSchemeDo settSchemeDo){ SettleCalculator repaySettleCalculator = createSettleCalculator(settSchemeDo.getRepayWay()); SettleCalculator receiptSettleCalculator = createSettleCalculator(settSchemeDo.getReceiptWay()); List<SettDetailDo> detailDoList = repaySettleCalculator.calSettDetail(loanAmount, loanPeriod,loanAnnualRate); List<SettDetailDo> retDetailDoList = receiptSettleCalculator.calSettDetail(loanAmount, loanPeriod,investAnnualRate); for(SettDetailDo detailDo : detailDoList) { for(SettDetailDo repaySettDetailDo : retDetailDoList) { if(detailDo.getPeriod().intValue() == repaySettDetailDo.getPeriod().intValue()){ detailDo.setConsultFee(CalculateUtils.sub(CalculateUtils.add(detailDo.getInterest(),detailDo.getPrincipal()), CalculateUtils.add(repaySettDetailDo.getInterest(),repaySettDetailDo.getPrincipal()))); double servFee = calSettleFeeForRepayPlanRecord(detailDo, settSchemeDo, loanAmount, loanPeriod); detailDo.setInterest(CalculateUtils.add(detailDo.getInterest(),servFee)); } } } for(SettDetailDo detailDo : detailDoList){ double servFee = calSettleFeeForRepayPlanRecord(detailDo, settSchemeDo, loanAmount, loanPeriod); detailDo.setInterest(CalculateUtils.add(detailDo.getInterest(),servFee)); } return detailDoList; } /** * 获取借款年利率 * * @param loanAnnualRate * @param investAnnualRate * @param settSchemeDo * @return * @author: liuzgmf * @date: 2015年1月8日上午10:40:33 */ private static Double getLoanAnnualRate(Double loanAnnualRate, Double investAnnualRate, SettSchemeDo settSchemeDo) { if (loanAnnualRate == null || CalculateUtils.lt(loanAnnualRate, investAnnualRate)) { return settSchemeDo.getDefaultAnnualRate(); } return loanAnnualRate; } /** * 计算结算费用 * * @param settSchemeDo * @return * @author: liuzgmf * @date: 2015年1月6日下午1:58:44 */ private static double calSettleFee(SettDetailDo detailDo, SettSchemeDo settSchemeDo, Double loanAmount, Integer loanPeriod, RuleType[] ruleTypes) { double servFee = 0.00; if (settSchemeDo.getFeeRuleDoList() == null || settSchemeDo.getFeeRuleDoList().size() == 0) { return servFee; } for (FeeRuleDo feeRuleDo : settSchemeDo.getFeeRuleDoList()) { for (RuleType ruleType : ruleTypes) { if (!ruleType.equals(feeRuleDo.getRuleType())) { continue; } //确定乘数, 是用剩余本金,还是借款金额 double baseAmount = loanAmount; if("2".equals(feeRuleDo.getBaseAmountType())){ baseAmount = detailDo.getRemainingPrincipal(); } // 一次性按比例收取 if (feeRuleDo.getGatherWay().equals(GatherWay.ONCE_RATIO) && detailDo.getPeriod().intValue() == 1) { double gatherRate = CalculateUtils.div(feeRuleDo.getGatherRate(), 100); servFee = CalculateUtils.add(servFee, CalculateUtils.mul(baseAmount, gatherRate)); continue; } // 一次性固定收取 if (feeRuleDo.getGatherWay().equals(GatherWay.ONCE_FIXED) && detailDo.getPeriod().intValue() == 1) { servFee = CalculateUtils.add(servFee, feeRuleDo.getFeeAmount()); continue; } // 每期按比例收取 if (feeRuleDo.getGatherWay().equals(GatherWay.EACH_RATIO)) { double gatherRate = CalculateUtils.div(feeRuleDo.getGatherRate(), 100); servFee = CalculateUtils.add(servFee, CalculateUtils.mul(baseAmount, gatherRate)); continue; } // 每期固定收取 if (feeRuleDo.getGatherWay().equals(GatherWay.EACH_FIXED)) { servFee = CalculateUtils.add(servFee, feeRuleDo.getFeeAmount()); continue; } // 一次性比例收取(月度比例) if (feeRuleDo.getGatherWay().equals(GatherWay.ONCE_MONRATIO) && detailDo.getPeriod().intValue() == 1) { double monthGatherRate = CalculateUtils.div(feeRuleDo.getGatherRate(), 100); servFee = CalculateUtils.add(servFee,CalculateUtils.mul(CalculateUtils.mul(baseAmount, monthGatherRate), loanPeriod)); continue; } } if(feeRuleDo.getIsInclude().equalsIgnoreCase("T")){ double consultFee = detailDo.getConsultFee(); //咨询-手续费, 原来咨询费= 利率差, //新的咨询费 = 利率差-0.2%手续费 double newConsultFee = CalculateUtils.sub(consultFee, servFee); detailDo.setConsultFee(newConsultFee); } } return CalculateUtils.round(servFee, 2); } /** * 还款计划表展示 费用计算 * @param detailDo * @param settSchemeDo * @param loanAmount * @param loanPeriod * @return */ private static double calSettleFeeForRepayPlanShow(SettDetailDo detailDo, SettSchemeDo settSchemeDo, Double loanAmount, Integer loanPeriod) { double servFee = 0.00; if (settSchemeDo.getFeeRuleDoList() == null || settSchemeDo.getFeeRuleDoList().size() == 0) { return servFee; } for (FeeRuleDo feeRuleDo : settSchemeDo.getFeeRuleDoList()){ if(feeRuleDo.getIsInitRepayPlanUse().equalsIgnoreCase("F")){ //不是初始还款计划表使用 continue; } if(feeRuleDo.getIsInclude().equalsIgnoreCase("T")){ //包含在年利率内 continue; } //确定乘数, 是用剩余本金,还是借款金额 double baseAmount = loanAmount; if("2".equals(feeRuleDo.getBaseAmountType())){ baseAmount = detailDo.getRemainingPrincipal(); } double fee = calFee(detailDo,feeRuleDo,baseAmount,loanPeriod); servFee = CalculateUtils.add(servFee, fee); } return CalculateUtils.round(servFee, 2); } /** * 放款后 还款计划表 费用计算 * @param detailDo * @param settSchemeDo * @param loanAmount * @param loanPeriod * @return */ private static double calSettleFeeForRepayPlanRecord(SettDetailDo detailDo, SettSchemeDo settSchemeDo, Double loanAmount, Integer loanPeriod) { double servFee = 0.00; if (settSchemeDo.getFeeRuleDoList() == null || settSchemeDo.getFeeRuleDoList().size() == 0) { return servFee; } for (FeeRuleDo feeRuleDo : settSchemeDo.getFeeRuleDoList()){ if(feeRuleDo.getIsInitRepayPlanUse().equalsIgnoreCase("F")){ //不是初始还款计划表使用 continue; } //确定乘数, 是用剩余本金,还是借款金额 double baseAmount = loanAmount; if("2".equals(feeRuleDo.getBaseAmountType())){ baseAmount = detailDo.getRemainingPrincipal(); } double fee = calFee(detailDo,feeRuleDo,baseAmount,loanPeriod); if(feeRuleDo.getIsInclude().equalsIgnoreCase("T")){ //包含在年利率内 detailDo.setConsultFee(CalculateUtils.sub(detailDo.getConsultFee(), servFee)); }else{ servFee = CalculateUtils.add(servFee, fee); } LoanRepaymentFeeDo loanRepaymentFeeDo = new LoanRepaymentFeeDo(); loanRepaymentFeeDo.setFeeAmount(fee); loanRepaymentFeeDo.setFeeType(feeRuleDo.getRuleType().toString()); loanRepaymentFeeDo.setFeeName(feeRuleDo.getRuleName()); detailDo.getRfList().add(loanRepaymentFeeDo); } LoanRepaymentFeeDo loanRepaymentFeeDo = new LoanRepaymentFeeDo(); loanRepaymentFeeDo.setFeeAmount(detailDo.getConsultFee()); loanRepaymentFeeDo.setFeeType(FeeRuleDo.RuleType.CONSULT_FEE.toString()); loanRepaymentFeeDo.setFeeName("咨询费"); detailDo.getRfList().add(loanRepaymentFeeDo); return CalculateUtils.round(servFee, 2); } private static double calFee(SettDetailDo detailDo,FeeRuleDo feeRuleDo, double baseAmount,Integer loanPeriod){ double fee = 0d; // 一次性按比例收取 if(feeRuleDo.getGatherWay().equals(GatherWay.ONCE_RATIO) && detailDo.getPeriod().intValue() == 1) { double gatherRate = CalculateUtils.div(feeRuleDo.getGatherRate(), 100); fee = CalculateUtils.mul(baseAmount, gatherRate); return fee; } // 一次性固定收取 if(feeRuleDo.getGatherWay().equals(GatherWay.ONCE_FIXED) && detailDo.getPeriod().intValue() == 1) { fee = feeRuleDo.getFeeAmount(); return fee; } // 每期按比例收取 if(feeRuleDo.getGatherWay().equals(GatherWay.EACH_RATIO)) { double gatherRate = CalculateUtils.div(feeRuleDo.getGatherRate(), 100); fee = CalculateUtils.mul(baseAmount, gatherRate); return fee; } // 每期固定收取 if(feeRuleDo.getGatherWay().equals(GatherWay.EACH_FIXED)) { fee = feeRuleDo.getFeeAmount(); return fee; } // 一次性比例收取(月度比例) if(feeRuleDo.getGatherWay().equals(GatherWay.ONCE_MONRATIO) && detailDo.getPeriod().intValue() == 1) { double monthGatherRate = CalculateUtils.div(feeRuleDo.getGatherRate(), 100); fee = CalculateUtils.mul(CalculateUtils.mul(baseAmount, monthGatherRate), loanPeriod); return fee; } return fee; } /** * 计算计算费用 * * @param transAmt * 交易金额 * @param loanPeriod * 借款期限 * @param feeRuleDo * 费用对象 * @return * @author: liuzgmf * @date: 2015年1月12日下午5:59:28 */ public static double calSettleFee(Double transAmt, Integer loanPeriod, FeeRuleDo feeRuleDo) { // 一次性按比例收取 if (feeRuleDo.getGatherWay().equals(GatherWay.ONCE_RATIO)) { double gatherRate = CalculateUtils.div(feeRuleDo.getGatherRate(), 100); return CalculateUtils.mul(transAmt, gatherRate); } // 一次性固定收取 if (feeRuleDo.getGatherWay().equals(GatherWay.ONCE_FIXED)) { return feeRuleDo.getFeeAmount(); } // 每期按比例收取 if (feeRuleDo.getGatherWay().equals(GatherWay.EACH_RATIO)) { double gatherRate = CalculateUtils.div(feeRuleDo.getGatherRate(), 100); return CalculateUtils.mul(transAmt, gatherRate); } // 每期固定收取 if (feeRuleDo.getGatherWay().equals(GatherWay.EACH_FIXED)) { return feeRuleDo.getFeeAmount(); } // 一次性比例收取(月度比例) if (feeRuleDo.getGatherWay().equals(GatherWay.ONCE_MONRATIO)) { double monthGatherRate = CalculateUtils.div(feeRuleDo.getGatherRate(), 100); return CalculateUtils.mul(CalculateUtils.mul(transAmt, monthGatherRate), loanPeriod); } return 0d; } public static List<SettDetailDo> displayRepayDetail(Double loanAmount, Integer loanPeriod, Double loanAnnualRate, Double investAnnualRate, SettSchemeDo settSchemeDo) { SettleCalculator repaySettleCalculator = createSettleCalculator(settSchemeDo.getRepayWay()); return repaySettleCalculator.calSettDetail(loanAmount, loanPeriod, getLoanAnnualRate(loanAnnualRate, investAnnualRate, settSchemeDo)); } public static void main(String[] args) { SettSchemeDo settSchemeDo = new SettSchemeDo(); settSchemeDo.setRepayWay(SettSchemeDo.SettleWay.FPIC); List<SettDetailDo> l = SettleCalculatorUtils.calSettDetailForRepayPlanShow(1000d, 12, 0.1, settSchemeDo,new Date()); for(SettDetailDo sd : l) System.out.println(sd); } }