apzl_leasing/calc/com/tenwa/reckon/executor/SegmentedFinancingExecutor.java
2021-07-27 15:15:21 +08:00

210 lines
11 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.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 {
// 贴息金额
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 );
}
// 融资期利率
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() - 1 > 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;
}
}