221 lines
12 KiB
Java
221 lines
12 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;
|
|
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 ) );
|
|
bo.setAttributeValue( "DISCOUNT", discount );
|
|
|
|
String fr = bo.getAttribute( "FINANCING_RATE" ).getString();
|
|
if ( StringUtils.isEmpty( fr ) ) {
|
|
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("2".equals( discountCalcMethod )) { //根据金额算利率
|
|
// 贴息金额
|
|
BigDecimal discount = new BigDecimal( bo.getAttribute( "DISCOUNT" ).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( 6, 4 );
|
|
bo.setAttributeValue( "DISCOUNT_RATE", discountRate.toString() );
|
|
String fr = bo.getAttribute( "FINANCING_RATE" ).getString();
|
|
if ( StringUtils.isEmpty( fr ) ) {
|
|
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" ).getString() );
|
|
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;
|
|
}
|
|
}
|