package com.yaochen.boss.commons; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import com.yaochen.boss.model.CProdUpdate; import com.yaochen.boss.model.CProdCycleDto; /** * 使用公用后的产品到期日计算算法 */ public class InvalidMath { private static ComparatorCProd comparator=new ComparatorCProd(); /** * 按周期产品计算到期日 * 按周期产品的出账日期判断非周期产品能否看到这个日期 * 计算公式存在问题,未排除不需要继续计算的产品 * @param cu * @throws Exception */ public static void doMathCycle(CProdUpdate cu) throws Exception{ double maxinvalidnum=doMath(cu); if(cu.getCycle_sign()==null||!cu.getCycle_sign()) return; List<CProdCycleDto> updateList=cu.getCprods();//按Invaliddatetonum从小到大的顺序 List<CProdCycleDto> cycleList = new ArrayList<CProdCycleDto>();//周期性产品列表 List<CProdCycleDto> normalList = new ArrayList<CProdCycleDto>();//普通包月产品列表 //按非包月规则设置反推的最小周期到期日 double backinvalidnum=0.0; for(CProdCycleDto cprod:updateList){ if(cprod.getTariff_billing_cycle()!=1){ double tempinvalidnum= cprod.getBackup_invlaid_num()+ (int)((maxinvalidnum-cprod.getBackup_invlaid_num())/cprod.getInvalid_cycle_num())*cprod.getInvalid_cycle_num(); if(tempinvalidnum<backinvalidnum||backinvalidnum==0.0) backinvalidnum=tempinvalidnum; cprod.setInvalid_date_num(tempinvalidnum); cycleList.add(cprod); }else normalList.add(cprod); } //设置包月的产品的到期日为backinvalidnum double minbalance=0.0;//周期产品下个周期需要最小金额 for(CProdCycleDto cprod:updateList){ if(cprod.getTariff_billing_cycle()==1) cprod.setInvalid_date_num(backinvalidnum); else if(cprod.getInvalid_date_num()==backinvalidnum){ if(cprod.getTariff_cycle_rent_365()<minbalance||minbalance==0.0) minbalance=cprod.getTariff_cycle_rent_365(); } } //反推剩余公用金额 double publicbalance=getBalanceByInvalidNum(updateList, maxinvalidnum); //剩余的公用金额>最小的周期产品需要的金额 while(publicbalance>=minbalance){ //周期产品一次性扣费 for(CProdCycleDto cprod:cycleList){ if(cprod.getInvalid_date_num()==backinvalidnum &&publicbalance>=cprod.getTariff_cycle_rent_365()){ cprod.setInvalid_date_num(cprod.getInvalid_date_num()+cprod.getInvalid_cycle_num()); publicbalance=publicbalance-cprod.getTariff_cycle_rent_365(); } } //并取下一个周期日 double tempbackinvalidnum=backinvalidnum; for(CProdCycleDto cprod:cycleList){ if(cprod.getInvalid_date_num()<backinvalidnum||tempbackinvalidnum==backinvalidnum) backinvalidnum=cprod.getInvalid_date_num(); } //非周期产品计费到 下个周期日 if(backinvalidnum!=tempbackinvalidnum){ double ba=getBalanceByInvalidNum(normalList, backinvalidnum); if(publicbalance>=ba){ publicbalance=publicbalance-ba; for( CProdCycleDto cprod:normalList) cprod.setInvalid_date_num(backinvalidnum); }else break; } //取下个周期的最小金额 minbalance=0.0; for(CProdCycleDto cprod:cycleList){ if(cprod.getInvalid_date_num()==backinvalidnum){ if(cprod.getTariff_cycle_rent_365()<minbalance||minbalance==0.0) minbalance=cprod.getTariff_cycle_rent_365(); } } } backinvalidnum=getMaxInvalidNum(normalList, publicbalance); for(CProdCycleDto cprod:normalList) cprod.setInvalid_date_num(backinvalidnum); } /** * 按普通产品计算到期日 * @param cu * @return * @throws Exception */ public static double doMath(CProdUpdate cu) throws Exception{ List<CProdCycleDto> updateList= cu.getCprods();//产品集合 按Invaliddatetonum从小到大的顺序 Collections.sort(updateList,comparator); List<CProdCycleDto> tempnoupdateList = new ArrayList<CProdCycleDto>();//临时产品集合 到期日大于理论均化最大到期日的产品集合或过了失效日期的产品 try{ int expcnt=0;//在updateList中的有失效日期的产品数 //过滤失效日期产品 按原始到期日 for(int i=updateList.size()-1;i>=0;i--){ CProdCycleDto cprod=updateList.get(i); if(cprod.getExp_date_num()!=null){ if(cprod.getInvalid_date_num()>=cprod.getExp_date_num()){ updateList.remove(i); tempnoupdateList.add(cprod); }else{ expcnt=expcnt+1; } } } double publicbalance=cu.getBlanace(); //获得理论均化的最大到期日 double maxinvalidnum=getMaxInvalidNum(updateList, publicbalance); //过滤失效日期产品按理论均化的最大到期日 boolean exp_check_sign=true;//判断是否继续判断失效日期 while(expcnt>0&&exp_check_sign){ exp_check_sign=false; for(int i=updateList.size()-1;i>=0;i--){ CProdCycleDto cprod=updateList.get(i); if(cprod.getExp_date_num()!=null&&maxinvalidnum>cprod.getExp_date_num()){ expcnt=expcnt-1; updateList.remove(i); tempnoupdateList.add(cprod); //扣除改产品到失效日期需要的金额 publicbalance=publicbalance-cprod.getTariff_rent_365()*(cprod.getExp_date_num()-cprod.getInvalid_date_num()); cprod.setInvalid_date_num(cprod.getExp_date_num()); exp_check_sign=true;//有失效日期的产品过滤掉了,继续判断其他有失效日期产品 //有失效日期的产品过滤掉了,重新计算理论均化到期日 maxinvalidnum=getMaxInvalidNum(updateList, publicbalance); } } } //如果存在大于理论均化最大到期日的产品,则重新计算理论均化最大到期日 while(updateList.size()>0&&updateList.get(updateList.size()-1).getInvalid_date_num()>maxinvalidnum){ //循环判断到期日超过理论到期日的产品,和过了失效时间的产品 for(int i=updateList.size()-1;i>=0;i--){ if(updateList.get(i).getInvalid_date_num()>maxinvalidnum){ tempnoupdateList.add(updateList.get(i)); updateList.remove(i); }else break; } //去掉大于理论均化最大到期日产品后,重新计算理论均化到期日 maxinvalidnum=getMaxInvalidNum(updateList, publicbalance); } for(CProdCycleDto cprod:updateList) cprod.setInvalid_date_num(maxinvalidnum); if(tempnoupdateList!=null) for(CProdCycleDto cprod:tempnoupdateList) updateList.add(cprod); return maxinvalidnum; }catch(Exception e){ String prod_sn=updateList.size()>0?updateList.get(0).getProd_sn(): (tempnoupdateList.size()>0?tempnoupdateList.get(0).getProd_sn():"无"); throw new Exception("PROD_SN="+prod_sn+"的客户到期日计算错误",e); } } /** * 计算统一到期日 * @return */ private static double getMaxInvalidNum(List<CProdCycleDto> updateList,double publicbalance){ if(updateList.size()>0){ double numerator=publicbalance; double denominator=0.0; for(CProdCycleDto cprod:updateList){ numerator=numerator+cprod.getInvalid_date_num()*cprod.getTariff_rent_365(); denominator=denominator+cprod.getTariff_rent_365(); } return numerator/denominator; } return 0; } /** * 指定一个统一到期日计算需要的公用账目是多少金额 * @param updateList * @param InvalidNum * @return */ private static double getBalanceByInvalidNum(List<CProdCycleDto> updateList,double invalidnum){ if(updateList.size()==0) return 0; double balance=0; for(CProdCycleDto cprod:updateList) balance=balance+cprod.getTariff_rent_365()*(invalidnum-cprod.getInvalid_date_num()); return balance; } public static void main(String[] args){ CProdCycleDto a=new CProdCycleDto(); a.setProd_sn("1"); a.setTariff_rent_365(30.0); a.setInvalid_date_num(0.0); a.setBackup_invlaid_num(0.0); a.setExp_date_num(25.0); CProdCycleDto b=new CProdCycleDto(); b.setProd_sn("2"); b.setTariff_rent_365(20.0); b.setInvalid_date_num(30.0); b.setBackup_invlaid_num(30.0); CProdCycleDto c=new CProdCycleDto(); c.setProd_sn("3"); c.setTariff_rent_365(30.0); c.setInvalid_date_num(60.0); c.setBackup_invlaid_num(60.0); c.setExp_date_num(64.0); CProdCycleDto d=new CProdCycleDto(); d.setProd_sn("4"); d.setTariff_rent_365(70.0); d.setInvalid_date_num(65.0); d.setBackup_invlaid_num(65.0); CProdCycleDto e=new CProdCycleDto(); e.setProd_sn("5"); e.setTariff_rent_365(60.0); e.setInvalid_date_num(98.0); e.setBackup_invlaid_num(98.0); List<CProdCycleDto> cprods=new ArrayList<CProdCycleDto>(); cprods.add(a); cprods.add(b); cprods.add(c); cprods.add(d); cprods.add(e); CProdUpdate cu=new CProdUpdate(); cu.setCprods(cprods); cu.setBlanace(2300); System.out.println(InvalidMath.getMaxInvalidNum(cu.getCprods(), cu.getBlanace())); try { InvalidMath.doMath(cu); } catch (Exception e1) { e1.printStackTrace(); } for(CProdCycleDto cp:cprods) System.out.println(cp.getProd_sn()+" "+cp.getExp_date_num()+" "+cp.getBackup_invlaid_num()+" "+cp.getInvalid_date_num()); System.out.println(cu.getBlanace()); double a1=0.0; for(CProdCycleDto cp:cprods) a1=a1+cp.getTariff_rent_365()*(cp.getInvalid_date_num()-cp.getBackup_invlaid_num()); System.out.println(a1); } } class ComparatorCProd implements Comparator<CProdCycleDto>{ public int compare(CProdCycleDto o1, CProdCycleDto o2) { if(o1.getInvalid_date_num()>o2.getInvalid_date_num()) return 1; if(o1.getInvalid_date_num()<o2.getInvalid_date_num()) return -1; return 0; } }