apzl_leasing/calc/com/tenwa/reckon/executor/SegmentedFinancingExecutor.java

239 lines
13 KiB
Java

package com.tenwa.reckon.executor;
import com.amarsoft.are.jbo.BizObject;
import com.amarsoft.are.jbo.BizObjectManager;
import com.amarsoft.are.jbo.JBOFactory;
import com.amarsoft.are.jbo.JBOTransaction;
import com.tenwa.comm.exception.BusinessException;
import com.tenwa.reckon.bean.ConditionBean;
import com.tenwa.reckon.bean.FundRentPlanBean;
import com.tenwa.reckon.bean.TabCalBean;
import com.tenwa.reckon.help.PlanDateServiceImpl;
import com.tenwa.reckon.util.IrrTools;
import com.tenwa.reckon.util.RentTools;
import org.apache.commons.lang3.StringUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class SegmentedFinancingExecutor extends FundRentPlanExecutor {
public SegmentedFinancingExecutor(JBOTransaction tx) {
super( tx );
}
@Override
public FundRentPlanBean create( TabCalBean tcb, Integer startList ) throws Exception {
this.deleteRentPlan( tcb.getRentPlan_tb(), tcb, startList );
// 年还款次数
String flowunid = tcb.getDocId();
BigDecimal incomeNumberYear = new BigDecimal( tcb.getCb().getIncomeNumberYear() );
BizObjectManager bom = JBOFactory.getBizObjectManager( "jbo.app.tenwa.calc.LC_CALC_SUBSECTION_INFO_TEMP", tx );
BizObjectManager bomLSRPT = JBOFactory.getBizObjectManager( "jbo.app.tenwa.calc.LC_SUBSECTION_RENT_PLAN_TEMP", tx );
bomLSRPT.createQuery( "delete from O where flowunid = :flowunid" ).setParameter( "flowunid", flowunid ).executeUpdate();
// 遍历分段融表
List<BizObject> bos = bom.createQuery( "flowunid = :flowunid order by subsection_number" ).setParameter( "flowunid", flowunid )
.getResultList( true );
List<String> dates = new ArrayList<>();
List<String> interests = new ArrayList<>();
List<String> corpuss = new ArrayList<>();
List<String> rents = new ArrayList<>();
List<String> overCorpuss = new ArrayList<>();
PlanDateServiceImpl pdsi = new PlanDateServiceImpl( tx );
ConditionBean cb = tcb.getCb();
for ( BizObject bo : bos ) {
// 分段号
String subsectionNumber = bo.getAttribute( "SUBSECTION_NUMBER" ).getString();
// 融资金额
BigDecimal cleanLeaseMoney = new BigDecimal( bo.getAttribute( "CLEAN_LEASE_MONEY" ).getString() );
// 标准利率
BigDecimal rate = new BigDecimal( bo.getAttribute( "RATE" ).getString() ).divide( new BigDecimal( 100 ), 20, 4 );
// 期利率
BigDecimal preRate = rate.divide( incomeNumberYear, 20, 4 );
// 期次
BigDecimal incomeNumber = new BigDecimal( bo.getAttribute( "INCOME_NUMBER" ).getString() );
cb.setIncomeNumber( incomeNumber.intValue() );
List<String> planDateList = pdsi.getPlanDateList( cb, null );
if ( planDateList.size() > dates.size() ) {
dates = planDateList;
}
// 贴息计算方式
String discountCalcMethod = bo.getAttribute( "DISCOUNT_CALC_METHOD" ).getString();
// 融资利率
BigDecimal financingRate;
//获取融资利率是否只读,如果只读每次计算需要更新融资利率
String iulma =bo.getAttribute( "IS_UPDATE_LEASE_MONEY_RATIO" ).getString();
if ( "1".equals( discountCalcMethod ) ) { // 根据利率计算贴息金额
// 贴息后利率
BigDecimal discountRate = new BigDecimal( bo.getAttribute( "DISCOUNT_RATE" ).getString() ).divide( new BigDecimal( 100 ), 20, 4 );
// 期利率
BigDecimal preDiscountRate = discountRate.divide( incomeNumberYear, 20, 4 );
// 标准利率计算租金
String rent = RentTools.getPMT( preRate.toString(), incomeNumber.toString(), cleanLeaseMoney.negate().toString(), "0", "0" );
// 贴息后利率计算租金
String afterDiscountRent = RentTools.getPMT( preDiscountRate.toString(), incomeNumber.toString(), cleanLeaseMoney.negate().toString(), "0", "0" );
// 计算贴息
BigDecimal discount = new BigDecimal( rent ).setScale( 2, 4 ).multiply( incomeNumber ).subtract( new BigDecimal( afterDiscountRent ).setScale( 2, 4 ).multiply( incomeNumber ) );
//客户要求,如果算出的贴息比配置的大,贴息金额为配置的最大金额,算出的贴息金额小于配置的最小值,贴息金额为配置的最小值,产品利率和融资利率不做调整
if ( discount.compareTo( new BigDecimal( bo.getAttribute( "MAXIMUM_DISCOUNT" ).getString() ) ) > 0 ) {
bo.setAttributeValue( "DISCOUNT_INTEREST", bo.getAttribute( "MAXIMUM_DISCOUNT" ).getString() );
}else if ( discount.compareTo( new BigDecimal( bo.getAttribute( "MINIMUM_DISCOUNT" ).getString() ) ) < 0 ){
bo.setAttributeValue( "DISCOUNT_INTEREST", bo.getAttribute( "MINIMUM_DISCOUNT" ).getString() );
}else {
bo.setAttributeValue( "DISCOUNT_INTEREST", discount );
}
String fr = bo.getAttribute( "FINANCING_RATE" ).getString();
if ( StringUtils.isEmpty( fr ) || ( iulma!=null && "Y".equals(iulma) ) ) {
financingRate = discountRate;
bo.setAttributeValue( "FINANCING_RATE", discountRate.multiply( new BigDecimal( 100 ) ).toString() );
} else {
financingRate = new BigDecimal( fr ).divide( new BigDecimal( 100 ), 20, 4 );
}
bo.setAttributeValue( tcb.getPlanCName(), tcb.getPlanCValue() );
bom.saveObject( bo );
} else if("2".equals( discountCalcMethod )) { //根据金额算利率
// 贴息金额
BigDecimal discount = new BigDecimal( bo.getAttribute( "DISCOUNT_INTEREST" ).getString() );
// 标准利率计算租金
String rent = RentTools.getPMT( preRate.toString(), incomeNumber.toString(), cleanLeaseMoney.negate().toString(), "0", "0" );
// 贴息后租金
BigDecimal afterDiscountRent = new BigDecimal( rent ).setScale( 2, 4 ).multiply( incomeNumber ).subtract( discount ).divide( incomeNumber, 2, 4 );
List<BigDecimal> cashFlow = new ArrayList<>();
cashFlow.add( cleanLeaseMoney.negate() );
for ( int i = 0; i < incomeNumber.intValue(); i ++ ) {
cashFlow.add( afterDiscountRent );
}
BigDecimal discountRate = getIRR( cashFlow, incomeNumberYear ).setScale( 2, 4 );//客户要求,只汽车只保留后小数点后两位
bo.setAttributeValue( "DISCOUNT_RATE", discountRate.toString() );
String fr = bo.getAttribute( "FINANCING_RATE" ).getString();
if ( StringUtils.isEmpty( fr ) || ( iulma!=null && "Y".equals(iulma) ) ) {
financingRate = discountRate.divide( new BigDecimal( 100 ), 20, 4 );
bo.setAttributeValue( "FINANCING_RATE", discountRate.toString() );
} else {
financingRate = new BigDecimal( fr ).divide( new BigDecimal( 100 ), 20, 4 );
}
bo.setAttributeValue( tcb.getPlanCName(), tcb.getPlanCValue() );
bom.saveObject( bo );
}else if("3".equals( discountCalcMethod )) { // 固定值
financingRate = new BigDecimal( bo.getAttribute( "FINANCING_RATE" ).getString() ).divide( new BigDecimal( 100 ), 20, 4 );
} else {
throw new BusinessException( "分段信息没有配置计算规则,无法测算!" );
}
//校验贴息是否在配置的区间内
BigDecimal discountCheck = new BigDecimal( bo.getAttribute( "DISCOUNT_INTEREST" ).getString() );
if(discountCheck.compareTo( new BigDecimal( bo.getAttribute( "MAXIMUM_DISCOUNT" ).getString() ) ) < 0) {
}
/* if ( !( discountCheck.compareTo( new BigDecimal( bo.getAttribute( "MAXIMUM_DISCOUNT" ).getString() ) ) <= 0 && discountCheck.compareTo( new BigDecimal( bo.getAttribute( "MINIMUM_DISCOUNT" ).getString() ) ) >= 0 ) ) {
throw new BusinessException( "分段融的第"+subsectionNumber+"段的贴息金额不在产品配置的区间内!" );
}*/
// 融资期利率
BigDecimal preFinancingRate = financingRate.divide( incomeNumberYear, 20, 4 );
// 实际租金
String rent = RentTools.getPMT( preFinancingRate.toString(), incomeNumber.toString(), cleanLeaseMoney.negate().toString(), "0", "0" );
BigDecimal r = new BigDecimal( rent ).setScale( 2, 4 );
for ( int i = 0; i < incomeNumber.intValue(); i ++ ) {
BigDecimal interest;
BigDecimal corpus;
if ( i == incomeNumber.intValue() - 1 ) {
corpus = cleanLeaseMoney;
if ( corpus.compareTo( r ) >= 0 ) {
r = corpus;
interest = BigDecimal.ZERO;
} else {
interest = r.subtract( corpus );
}
cleanLeaseMoney = BigDecimal.ZERO;
} else {
interest = cleanLeaseMoney.multiply( preFinancingRate ).setScale( 2, 4 );
corpus = r.subtract( interest );
cleanLeaseMoney = cleanLeaseMoney.subtract( corpus );
}
BizObject boLSRPT = bomLSRPT.newObject();
boLSRPT.setAttributeValue( "FLOWUNID", flowunid );
boLSRPT.setAttributeValue( tcb.getPlanCName(), tcb.getPlanCValue() );
boLSRPT.setAttributeValue( "PLAN_LIST", i + 1 );
boLSRPT.setAttributeValue( "PLAN_DATE", planDateList.get( i ) );
boLSRPT.setAttributeValue( "INTEREST_DATE", planDateList.get( i ) );
boLSRPT.setAttributeValue( "PLAN_STATUS", "未回笼" );
boLSRPT.setAttributeValue( "RENT", r.toString() );
boLSRPT.setAttributeValue( "CORPUS", corpus.toString() );
boLSRPT.setAttributeValue( "INTEREST", interest.toString() );
boLSRPT.setAttributeValue( "ALL_REMAIN_CORPUS", cleanLeaseMoney.toString() );
boLSRPT.setAttributeValue( "CORPUS_BUSINESS", corpus.toString() );
boLSRPT.setAttributeValue( "INTEREST_BUSINESS", interest.toString() );
boLSRPT.setAttributeValue( "SUBSECTION_NUMBER", subsectionNumber );
bomLSRPT.saveObject( boLSRPT );
if ( interests.size() > i ) {
interests.set( i, new BigDecimal( interests.get( i ) ).add( interest ).toString() );
corpuss.set( i, new BigDecimal( corpuss.get( i ) ).add( corpus ).toString() );
overCorpuss.set( i, new BigDecimal( overCorpuss.get( i ) ).add( cleanLeaseMoney ).toString() );
rents.set( i, new BigDecimal( rents.get( i ) ).add( r ).toString() );
} else {
interests.add( interest.toString() );
corpuss.add( corpus.toString() );
overCorpuss.add( cleanLeaseMoney.toString() );
rents.add( r.toString() );
}
}
}
FundRentPlanBean fundRentPlanBean = new FundRentPlanBean();
fundRentPlanBean.setCorpusOverageBusinessList( overCorpuss );
fundRentPlanBean.setCorpusBusinessList( corpuss );
fundRentPlanBean.setInterestBusinessList( interests );
fundRentPlanBean.setPlanDateList( dates );
fundRentPlanBean.setRentList( rents );
this.addRentPlan( fundRentPlanBean, tcb, startList );
return fundRentPlanBean;
}
public static BigDecimal getIRR( List cashFlows, BigDecimal incomeNumberYear ) {
List<BigDecimal> cashFlow = new ArrayList<>();
for ( int o = 0; o < cashFlows.size(); o ++ ) {
Object obj = cashFlows.get( o );
if ( obj instanceof BigDecimal ) {
cashFlow.add( ( BigDecimal ) obj );
} else {
cashFlow.add( new BigDecimal( obj.toString() ) );
}
}
BigDecimal up = BigDecimal.ONE;
BigDecimal down = BigDecimal.ZERO;
BigDecimal two = new BigDecimal( "2" );
BigDecimal irr = new BigDecimal( "0.01" );
BigDecimal accuracy = new BigDecimal( "0.0000001" );
BigDecimal out;
int i = 0;
while ( irr.abs().compareTo( accuracy ) > 0 && i < 200 ) {
out = cashFlow.get( 0 );
for ( int j = 1; j < cashFlow.size(); j ++ ) {
out = out.add( cashFlow.get( j ).divide( new BigDecimal( Math.pow( BigDecimal.ONE.add( irr ).doubleValue(), j ) ), 20, 4 ) );
}
if ( out.compareTo( BigDecimal.ZERO ) > 0 ) {
down = irr;
irr = irr.add( up ).divide( two, 20, 4 );
} else if ( out.compareTo( BigDecimal.ZERO ) < 0 ) {
up = irr;
irr = irr.add( down ).divide( two, 20, 4 );
}
i ++;
}
irr = irr.multiply( incomeNumberYear ).multiply( new BigDecimal( 100 ) );
return irr;
}
public static void main(String[] args) {
System.out.println(new BigDecimal("12709.80").compareTo(new BigDecimal("10000.00")));
}
}