venerdì 25 novembre 2011

Java calcolo piano ammortamento alla francese

Questa classe provvede a calcolare il piano ammortamento alla francese (rata costante, quota capitale crescente e quota interesse decrescente), tornando una lista di oggetti Rata con le seguenti proprietà:
  • Numero Rata
  • Data Scadenza
  • Importo Rata
  • Quota Interessi
  • Quota Capitale
  • Debito Residuo
Di seguito posto il codice della classe, con un main di esempio invocazione:


package it.test;

import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
enum PERIODICITA
{
    MENSILE(12),
    TRIMESTRALE(4),
    QUADRIMESTRALE(3),
    SEMESTRALE(2),
    ANNUALE(1);
    PERIODICITA(int n)
    {
        this.n=n;
    }
    private int n;
    public int getN() {
        return n;
    }
    public void setN(int n) {
        this.n = n;
    }
   
   
}
class Rata
{
    private Date dataScadenza;
    private int numeroRata;
    private double importoRata;
    private double quotaCapitale;
    private double quotaInteressi;
    private double debitoResiduo;
   
   
    public Date getDataScadenza() {
        return dataScadenza;
    }
    public void setDataScadenza(Date dataScadenza) {
        this.dataScadenza = dataScadenza;
    }
    public String toString(){
        StringBuilder sb=new StringBuilder();
        sb.append("[");
        sb.append(" Numero rata: ");
        sb.append(formatNumber(this.numeroRata));
        sb.append(" Data Scadenza: ");
        sb.append(formatDate(this.dataScadenza));
        sb.append(" Importo: ");
        sb.append(formatNumber(this.importoRata));
        sb.append(" Quota Capitale: ");
        sb.append(formatNumber(this.quotaCapitale));
        sb.append(" Quota Interesse: ");
        sb.append(formatNumber(this.quotaInteressi));
        sb.append(" Debito Residuo: ");
        sb.append(formatNumber(this.debitoResiduo));
        sb.append(" ]");
        sb.append("\n");
       
       
        return sb.toString();
    }
    public int getNumeroRata() {
        return numeroRata;
    }
    public void setNumeroRata(int numeroRata) {
        this.numeroRata = numeroRata;
    }
    public double getImportoRata() {
        return importoRata;
    }
    public void setImportoRata(double importoRata) {
        this.importoRata = importoRata;
    }
    public double getQuotaCapitale() {
        return quotaCapitale;
    }
    public void setQuotaCapitale(double quotaCapitale) {
        this.quotaCapitale = quotaCapitale;
    }
    public double getQuotaInteressi() {
        return quotaInteressi;
    }
    public void setQuotaInteressi(double quotaInteressi) {
        this.quotaInteressi = quotaInteressi;
    }
    public double getDebitoResiduo() {
        return debitoResiduo;
    }
    public void setDebitoResiduo(double debitoResiduo) {
        this.debitoResiduo = debitoResiduo;
    }
    private String formatNumber(double number){
        NumberFormat nf=NumberFormat.getInstance(Locale.ITALY);
        nf.setGroupingUsed(true);
        nf.setMaximumFractionDigits(2);
        nf.setMinimumFractionDigits(2);
        return nf.format(number);
        }
    private String formatDate(Date d){
        SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");
        return sdf.format(d);
    }
   
}
/**
 * Piano di ammortamento a rata costante <br>
 * La rata è divisa in quota interessi e quota capitale, la quota di capitale sarà <br>
 * crescente mentre la quota di interessi decrescente.<br>
 * La somma del totale delle quote capitale deve restituire il capitale prestato.<br>
 *
 *
 *
 * @author
 *
 */
public class PianoAmmortamentoFrancese {
    private double rata;
    private double capitalePrestato;
    private double interesse;
    private PERIODICITA periodicita;
    private int durataMesiMutuo;
    private Date dataPrimaScadenza;
   
    public double getRata() {
        return rata;
    }
    public void setRata(double rata) {
        this.rata = rata;
    }
    public PianoAmmortamentoFrancese(double capitalePrestato,double interesse,PERIODICITA per,int durataMesiMutuo,Date dataPrimaScadenza){
        this.capitalePrestato=capitalePrestato;
        this.interesse=interesse;
        this.periodicita=per;
        this.durataMesiMutuo=durataMesiMutuo;
        this.dataPrimaScadenza=dataPrimaScadenza;
        calcolaImportoRata();
    }
    public List<Rata> getPianoAmmortamento(){
        List<Rata> myList=new LinkedList<Rata>();
        Rata rIn=new Rata();
        rIn.setDebitoResiduo(this.capitalePrestato);
        rIn.setDataScadenza(dataPrimaScadenza);
       
        Date dataScadenza=dataPrimaScadenza;
        int[] dati=getGiorniMesiAnnoFromDate(dataScadenza);
        int giorno=dati[0];
       
        double debitoResiduo=this.capitalePrestato;
        double quotaCapitale=0;
        double interesse=0;
        int numeroRata=0;
        myList.add(rIn);
        do
        {
            numeroRata++;
           
           
            dataScadenza=getDataSuccessiva(dataScadenza);
            int nuovoGiorno=getGiorniMesiAnnoFromDate(dataScadenza)[0];
            if(nuovoGiorno!=giorno){
                if(isGiornoAmmissibilePerData(dataScadenza, giorno)){
                    Calendar c=Calendar.getInstance();
                    c.setTime(dataScadenza);
                    c.set(Calendar.DAY_OF_MONTH, giorno);
                    dataScadenza=c.getTime();
                }
            }
            double[] quote=getQuoteDebito(debitoResiduo);
            Rata r=new Rata();
            quotaCapitale=quote[1];
            interesse=quote[0];
            debitoResiduo=debitoResiduo-quotaCapitale;
            r.setImportoRata(rata);
            r.setDataScadenza(dataScadenza);
            r.setDebitoResiduo(debitoResiduo);
            r.setQuotaCapitale(quotaCapitale);
            r.setQuotaInteressi(interesse);
            r.setNumeroRata(numeroRata);
            myList.add(r);
           
           
        }
        while((int)debitoResiduo!=0);
       
        return myList;
    }
    private void calcolaImportoRata(){

        rata= this.capitalePrestato*getFattoreA()*getFattoreB();
    }
    private double getFattoreB(){
        double numeratore=calcolaA()-(double)1;
        double denominatore=getFattoreA()-1;
        return numeratore/denominatore;
    }
    /**
     * Stiamo calcolando 1+ TA/PA dove TA è l'interesse e PA i periodi annui
     * @return
     */
    private double calcolaA(){
       
        return (double)1+this.interesse/(double)periodicita.getN();
       
    }
    private double esponenteA(){
        return (double)periodicita.getN()*anniRimborso();
       
    }
    private double getFattoreA(){
        return Math.pow(calcolaA(), esponenteA());
    }
   
    private double anniRimborso()
    {
        return (double)this.durataMesiMutuo/(double)12;
    }
    public static void main(String[] args) throws Exception
    {
        Date dataPrimaScadenza= creaData(26, 12, 2011);
       PianoAmmortamentoFrancese p=new PianoAmmortamentoFrancese((double)100000, 0.05,PERIODICITA.MENSILE, 24,dataPrimaScadenza);
      System.out.println(p.getPianoAmmortamento());
      
    }
    private double[] getQuoteDebito(double capitaleResiduo){
        double[] retVal=new double[2];
        double quotaInteressi=(this.interesse/(double)periodicita.getN())*capitaleResiduo;
        double quotaCapitale=rata-quotaInteressi;
        retVal[0]=quotaInteressi;
        retVal[1]=quotaCapitale;
        return retVal;
    }
    private int[] getGiorniMesiAnnoFromDate(Date d){
        Calendar c=Calendar.getInstance();
        c.setTime(d);
        int anno=c.get(Calendar.YEAR);
        int mese=c.get(Calendar.MONTH);
        int giorno=c.get(Calendar.DAY_OF_MONTH);
        int[] lista=new int[3];
        lista[0]=giorno;
        lista[1]=mese;
        lista[2]=anno;
        return lista;
    }
    private Date getDataSuccessiva(Date d){
        int p=12/this.periodicita.getN();
        Calendar c=Calendar.getInstance();
        c.setTime(d);
        c.add(Calendar.MONTH, p);
        return c.getTime();
    }
   private static Date creaData(int giorno,int mese,int anno){
        Calendar c=Calendar.getInstance();
        c.set(Calendar.YEAR, anno);
        c.set(Calendar.MONTH, mese-1);
        c.set(Calendar.DAY_OF_MONTH, giorno);
        return c.getTime();
    }
   private boolean isGiornoAmmissibilePerData(Date d,int giorno){
       boolean retVal=false;
       if(giorno<=28){
           retVal=true;
       }
       else
       {
           int mese=getGiorniMesiAnnoFromDate(d)[1];
           if(mese==Calendar.FEBRUARY){
               if(isLeapYear(getGiorniMesiAnnoFromDate(d)[2]) && giorno==29){
                   retVal=true;
               }
               else
               {
                   retVal=false;
               }
           }
           else if(giorno==31 ){
               if(mese!=Calendar.APRIL && mese !=Calendar.JUNE && mese !=Calendar.SEPTEMBER && mese !=Calendar.NOVEMBER)
               {
                   retVal=true;
               }
               else
               {
                   retVal=false;
               }
           }
       }
       return retVal;
   }
  
   /**
     * Un anno è bisestile se:<br>
     * 1) divisibile per 4<br>
     * 2) non secolare (a parte i secolari divisibili per 400)<br>
     * @param anno
     * @return
     */
    private boolean isLeapYear(int anno){
        boolean retVal=false;
        int div4=anno%4;
        if(div4==0){
            //divisibile per quattro
            int div100=anno%100;
            if(div100==0){
                // è un anno "secolare"
                int div400=anno%400;
                if(div400==0){
                    // però è divisibile anche per 400
                    retVal=true;
                }
                else
                {
                    // anno secolare non divisibile per 400
                    // non è bisestile
                    retVal=false;
                }
            }
            else
            {
                // divisibile per 4 e non secolare è bisestile
                retVal=true;
            }
        }
        return retVal;
    }
}

2 commenti:

  1. Ciao,
    complimenti per questo codice utilissimo.
    Conosci anche come calcolare il TAEG?

    Grazie

    RispondiElimina
  2. Ciao, grazie a te dei complimenti.
    No purtroppo con il TAEG non mi ci sono mai scontrato :-))

    RispondiElimina