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 bos = bom.createQuery( "flowunid = :flowunid order by subsection_number" ).setParameter( "flowunid", flowunid ) .getResultList( true ); List dates = new ArrayList<>(); List interests = new ArrayList<>(); List corpuss = new ArrayList<>(); List rents = new ArrayList<>(); List overCorpuss = new ArrayList<>(); PlanDateServiceImpl pdsi = new PlanDateServiceImpl( tx ); ConditionBean cb = tcb.getCb(); BigDecimal maxIncomeNumber = BigDecimal.ZERO; 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() ); if(incomeNumber.compareTo(maxIncomeNumber) > 0 ) { maxIncomeNumber = incomeNumber; } cb.setIncomeNumber( incomeNumber.intValue() ); List 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 ); } } 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 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 ); } }else if("3".equals( discountCalcMethod )) { // 固定值 financingRate = new BigDecimal( bo.getAttribute( "FINANCING_RATE" ).getString() ).divide( new BigDecimal( 100 ), 20, 4 ); } else { throw new BusinessException( "分段信息没有配置计算规则,无法测算!" ); } bo.setAttributeValue( tcb.getPlanCName(), tcb.getPlanCValue() ); bom.saveObject( bo ); //校验贴息是否在配置的区间内 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() ); } } } //将分段融的最大值赋值给测算期次 cb.setIncomeNumber( maxIncomeNumber.intValue() ); //分段融目前没有配置还款间隔,默认为月付。租赁期限和租赁次数一致 cb.setLeaseTerm( maxIncomeNumber.intValue() ); 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 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"))); } }