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;
}
}