Hallo mede Php-ers,

Sinds enkele dagen ben ik bezig met een ingewikkelde (althans ik vind het ingewikkeld) renteberekeningsclass. De berekeningen zijn redelijk nauwkeurig en komen voor wat betreft de enkelvoudige rente en meervoudige contractuele rente exact overeen met de online tool die meestal voor dergelijke renteberekeningen wordt gebruikt: http://www.wettelijkerente.net/renteberekening.aspx

De wettelijke handelsrente komt nog niet helemaal overeen met voornoemde online bereken tool en dat betekent dat OF mijn formule onjuist is OF de online rekentool. Uiteraard zou ik graag willen weten of jullie zien waar dit aan ligt en of er verbeterpunten zijn (ongetwijfeld).

Hieronder de 2 classes:
<?php
public function checkJaarGrens($vervalDatum,$beginDatum,$eindDatum,$numOfYears){
// Controleer of de periode jaargrens bevat
for($i = 1; $i < $numOfYears + 1; $i++)
{
if(
($beginDatum < ($vervalDatum + ($i*60*60*24*365))) &&
($eindDatum > ($vervalDatum + ($i*60*60*24*365))) )
{
return $vervalDatum + ($i*60*60*24*365);
}
}
}

// Bereken rente
public function calcRente($renteSoort,$samengesteld){

// Gegevens factuur ophalen
$db = new PDO('mysql:host=localhost;port=3307;dbname=****','****','****');
$sql = "SELECT
UNIX_TIMESTAMP(factuurDatum) AS factuurDatum,
factuurBedrag,betaalTermijn,renteSamengesteld, rentePercentage
FROM Invoice WHERE id = '".$this->_id."'";
$result = $db->query($sql);
foreach($result as $row)
{
// Gegevens verzamelen
$heden = time();
$factuurBedrag = $row['factuurBedrag'];
$rentePercentage = $row['rentePercentage'];
$samengesteld = $row['renteSamengesteld'];
$factuurDatum = $row['factuurDatum']; // Datum in seconden
$vervalDatum = $factuurDatum + ($row['betaalTermijn']*24*60*60) + (60*60*24);
$rentePeriode = $heden - $vervalDatum;
$subtotaal = $factuurBedrag;
$subtotaalRente = 0;


echo '<br /><br />';
echo 'De begindatum van de factuur is '.$row['factuurDatum'].'<br />';
echo 'De betaaltermijn is '.$row['betaalTermijn'].' dagen.<br />';
echo 'Dit zijn '.$row['betaalTermijn']*24*60*60 .' seconden.<br />';
echo 'Dit betekent een vervalDatum per '.$vervalDatum.'<br />';
echo 'Dit betekent een vervalDatum per '.date('Y-m-d',$vervalDatum).' tot aan
'.date('Y-m-d',$heden).'<br />';
echo 'De rentePeriode is dus '.$rentePeriode.' seconden of '.ceil($rentePeriode/24/60/60) .' dagen';
echo '<br /><br />';

}

if($renteSoort == 1) // == Wettelijke handelsrente
{

if($samengesteld == 1)
{
// Bereken wettelijke rente (samengesteld)
echo 'De wettelijke rente (samengesteld) wordt berekend.<br />';

$db = new PDO('mysql:host=localhost;port=3307;dbname=****','****','****');
$sql = "SELECT
UNIX_TIMESTAMP(eindDatum) AS eindDatum,
UNIX_TIMESTAMP(beginDatum) AS beginDatum,
rentePercentage
FROM wettelijkerente
WHERE renteSoort = 1
ORDER BY beginDatum ASC;
";
$result = $db->query($sql);
$aantalJaar = floor(($heden - $vervalDatum)/60/60/24/365);
echo 'Er zijn '.$aantalJaar.' jaren<br />';
foreach($result as $row){

$beginDatum = $row['beginDatum'];
$eindDatum = $row['eindDatum'];
$rentePercentage = $row['rentePercentage'];

// Periodes afbakenen
if(
($beginDatum < $vervalDatum) && ($eindDatum > $vervalDatum) && ($eindDatum <= $heden) ||
($beginDatum < $vervalDatum) && ($eindDatum > $vervalDatum) && ($eindDatum >= $heden) ||
($beginDatum > $vervalDatum) && ($eindDatum > $vervalDatum) && ($eindDatum <= $heden) ||
($beginDatum > $vervalDatum) && ($eindDatum > $vervalDatum) && ($eindDatum >= $heden)
)
{
echo 'De begindatum: '.date('d-m-Y',$beginDatum).'<br />';
echo 'De einddatum: '.date('d-m-Y',$eindDatum).'<br />';
echo 'Het rentepercentage: '.$rentePercentage.'<br />';

// ==> Eerste periode
if( ($beginDatum < $vervalDatum) && ($eindDatum > $vervalDatum) && ($eindDatum < $heden) )
{
echo 'Deze periode is gebroken aan het begin.<br />';

// Controleer of de periode jaargrens bevat
if($this->checkJaarGrens($vervalDatum,$beginDatum,$eindDatum,$aantalJaar) > 0)
{

// Ja, er is een jaargrens binnen deze periode
echo 'Deze periode bevat een jaargrens<br />';

$jaarGrens = $this->checkJaarGrens($vervalDatum,$vervalDatum,$eindDatum,$aantalJaar);

echo 'Deze periode heeft '. ceil(($eindDatum-$vervalDatum)/60/60/24) .' dagen<br />';

// ==> Eerste gedeelte rente

// Aantal dagen voor de jaargrens
$aantalDagen = ceil(($jaarGrens - $vervalDatum)/60/60/24);
echo 'Aantal dagen in de periode voor de jaargrens: '.$aantalDagen.'<br />';

// Rente voor de jaargrens berekenen
$renteBedrag = ($subtotaal * ($rentePercentage/100))/365*$aantalDagen;

echo 'Oud subtotaal = '.$subtotaal.'<br />';
echo 'Rente deze periode: '.$renteBedrag.'<br />';
echo 'Rente vorige periodes: '.$subtotaalRente.'<br />';
echo 'Subtotaal rente: '.$renteBedrag + $subtotaalRente.'<br />';

// Oude rente (vorige periodes) en nieuwe rente bij elkaar optellen
$subtotaalRente = $subtotaalRente + $renteBedrag;
echo 'Subtotaal rente: '.$subtotaalRente.'<br />';

// ==> Nieuw subtotaal berekenen
// Nieuwe rente tot nu toe optellen bij subtotaal
$subtotaal = $subtotaal + $subtotaalRente;

echo 'Nieuw subtotaal = '.$subtotaal.'<br />';

// subtotaalRente resetten (want reeds bij subtotaal opgeteld)
$subtotaalRente = 0;

// ==> Twee gedeelte rente
// Aantal dagen voor de jaargrens
$aantalDagen = ceil(($eindDatum - $jaarGrens)/60/60/24);
echo 'Aantal dagen in de periode na de jaargrens: '.$aantalDagen.'<br />';

// Rente na de jaargrens berekenen
$renteBedrag = ($subtotaal * ($rentePercentage/100))/365*$aantalDagen;
$subtotaalRente = $subtotaalRente + $renteBedrag;

echo 'Nieuwe rente deze periode: '.$renteBedrag.'<br />';
echo 'Rente subtotaal: '.$subtotaalRente.'<br />';

}else{

// Nee, er is geen jaargrens binnen deze periode
echo 'Deze periode bevat geen jaargrens.<br />';

// Aantal dagen berekenen
$aantalDagen = ceil(($eindDatum - $vervalDatum)/60/60/24);
echo 'Aantal dagen in deze periode: '.$aantalDagen.'<br />';

echo 'Subtotaal: '.$subtotaal.'<br />';

// Rente berekenen en toevoegen aan renteSubtotaal
$renteBedrag = ($subtotaal * ($rentePercentage/100))/365*$aantalDagen;
echo 'Rentebedrag deze periode: '.$renteBedrag.'<br />';

$subtotaalRente = $subtotaalRente + $renteBedrag;
echo 'Rente subtotaal: '.$subtotaalRente.'<br />';

}
}
// ==> Laatste periode
elseif( (($beginDatum < $vervalDatum) && ($eindDatum > $heden)) ||
(($beginDatum > $vervalDatum) && ($eindDatum > $heden)) )
{
echo 'Deze periode is gebroken aan het einde<br />';

// Controleer of de periode jaargrens bevat
if($this->checkJaarGrens($vervalDatum,$beginDatum,$heden,$aantalJaar) > 0)
{

// Ja, er is een jaargrens binnen deze periode
echo 'Deze periode bevat een jaargrens<br />';

$jaarGrens = $this->checkJaarGrens($vervalDatum,$beginDatum,$heden,$aantalJaar);

echo 'Deze periode heeft '. ceil(($eindDatum-$vervalDatum)/60/60/24) .' dagen<br />';

// ==> Eerste gedeelte rente

// Aantal dagen voor de jaargrens
$aantalDagen = ceil(($jaarGrens - $vervalDatum)/60/60/24);
echo 'Aantal dagen in de periode voor de jaargrens: '.$aantalDagen.'<br />';

// Rente voor de jaargrens berekenen
$renteBedrag = ($subtotaal * ($rentePercentage/100))/365*$aantalDagen;

echo 'Oud subtotaal = '.$subtotaal.'<br />';
echo 'Rente deze periode: '.$renteBedrag.'<br />';
echo 'Rente vorige periodes: '.$subtotaalRente.'<br />';
echo 'Subtotaal rente: '.$renteBedrag + $subtotaalRente.'<br />';

// Oude rente (vorige periodes) en nieuwe rente bij elkaar optellen
$subtotaalRente = $subtotaalRente + $renteBedrag;
echo 'Subtotaal rente: '.$subtotaalRente.'<br />';

// ==> Nieuw subtotaal berekenen
// Nieuwe rente tot nu toe optellen bij subtotaal
$subtotaal = $subtotaal + $subtotaalRente;

echo 'Nieuw subtotaal = '.$subtotaal.'<br />';

// subtotaalRente resetten (want reeds bij subtotaal opgeteld)
$subtotaalRente = 0;

// ==> Twee gedeelte rente
// Aantal dagen voor de jaargrens
$aantalDagen = ceil(($heden - $jaarGrens)/60/60/24);
echo 'Aantal dagen in de periode na de jaargrens: '.$aantalDagen.'<br />';

// Rente na de jaargrens berekenen
$renteBedrag = ($subtotaal * ($rentePercentage/100))/365*$aantalDagen;
$subtotaalRente = $subtotaalRente + $renteBedrag;

echo 'Nieuwe rente deze periode: '.$renteBedrag.'<br />';
echo 'Rente subtotaal: '.$subtotaalRente.'<br />';

}else{

// Nee, er is geen jaargrens binnen deze periode
echo 'Deze periode bevat geen jaargrens.<br />';

if($vervalDatum > $heden)
{
// Aantal dagen berekenen
$aantalDagen = ceil(($heden - $vervalDatum)/60/60/24);
}
else
{
// Aantal dagen berekenen
$aantalDagen = ceil(($heden - $beginDatum)/60/60/24);
}

echo 'Aantal dagen in deze laatste periode: '.$aantalDagen.'<br />';

echo 'Subtotaal voor rente: '.$subtotaal.'<br />';

echo 'Rente subtotaal vorige periodes: '.$subtotaalRente.'<br />';

// Rente berekenen en toevoegen aan renteSubtotaal
$renteBedrag = ($subtotaal * ($rentePercentage/100))/365*$aantalDagen;
$subtotaalRente = $subtotaalRente + $renteBedrag;
echo 'Nieuwe rente deze periode: '.$renteBedrag.'<br />';
echo 'Rente subtotaal: '.$subtotaalRente.'<br />';

// Totaalbedrag berekenen
$subtotaal = $subtotaal + $subtotaalRente;
echo 'Totaalbedrag: '.$subtotaal.'<br />';

}
}
// ==> Tussenperiode
else
{
echo 'Deze periode is niet gebroken maar heel<br />';

// Controleer of de periode jaargrens bevat
if($this->checkJaarGrens($vervalDatum,$beginDatum,$eindDatum,$aantalJaar) > 0)
{

// Ja, er is een jaargrens binnen deze periode
echo 'Deze periode bevat een jaargrens<br />';

$jaarGrens = $this->checkJaarGrens($vervalDatum,$beginDatum,$eindDatum,$aantalJaar);

echo 'Deze periode heeft '. ceil(($eindDatum-$beginDatum)/60/60/24) .' dagen<br />';

// ==> Eerste gedeelte rente

// Aantal dagen voor de jaargrens
$aantalDagen = ceil(($jaarGrens - $beginDatum)/60/60/24);
echo 'Aantal dagen in de periode voor de jaargrens: '.$aantalDagen.'<br />';

// Rente voor de jaargrens berekenen
$renteBedrag = ($subtotaal * ($rentePercentage/100))/365*$aantalDagen;

echo 'Oud subtotaal = '.$subtotaal.'<br />';
echo 'Rente deze periode: '.$renteBedrag.'<br />';
echo 'Rente vorige periodes: '.$subtotaalRente.'<br />';
echo 'Subtotaal rente: '.$renteBedrag + $subtotaalRente.'<br />';

// Oude rente (vorige periodes) en nieuwe rente bij elkaar optellen
$subtotaalRente = $subtotaalRente + $renteBedrag;
echo 'Subtotaal rente: '.$subtotaalRente.'<br />';

// ==> Nieuw subtotaal berekenen
// Nieuwe rente tot nu toe optellen bij subtotaal
$subtotaal = $subtotaal + $subtotaalRente;

echo 'Nieuw subtotaal = '.$subtotaal.'<br />';

// subtotaalRente resetten (want reeds bij subtotaal opgeteld)
$subtotaalRente = 0;

// ==> Twee gedeelte rente
// Aantal dagen voor de jaargrens
$aantalDagen = ceil(($eindDatum - $jaarGrens)/60/60/24);
echo 'Aantal dagen in de periode na de jaargrens: '.$aantalDagen.'<br />';

// Rente na de jaargrens berekenen
$renteBedrag = ($subtotaal * ($rentePercentage/100))/365*$aantalDagen;
$subtotaalRente = $subtotaalRente + $renteBedrag;

echo 'Nieuwe rente deze periode: '.$renteBedrag.'<br />';
echo 'Rente subtotaal: '.$subtotaalRente.'<br />';

}else{

// Nee, er is geen jaargrens binnen deze periode
echo 'Deze periode bevat geen jaargrens.<br />';

// Aantal dagen berekenen
$aantalDagen = ceil(($eindDatum - $beginDatum)/60/60/24);
echo 'Aantal dagen in deze periode: '.$aantalDagen.'<br />';

echo 'Subtotaal: '.$subtotaal.'<br />';

// Rente berekenen en toevoegen aan renteSubtotaal
$renteBedrag = ($factuurBedrag * ($rentePercentage/100))/365*$aantalDagen;
echo 'Rentebedrag deze periode: '.$renteBedrag.'<br />';

// Subtotaal rente
$subtotaalRente = $subtotaalRente + $renteBedrag;
echo 'Rentesubtotaal: '.$subtotaalRente.'<br />';

}
}


echo '<br />';
}

}

// Bereken de som van alle rentePeriodes

}
else
{
// Bereken wettelijke rente (enkelvoud)
return 'De wettelijke rente (enkelvoud) wordt berekend';
}

}elseif($renteSoort == 2) // == Wettelijke rente
{

if($samengesteld == 1)
{
// Bereken wettelijke handelsrente (samengesteld)
return 'De wettelijke handelsrente (samengesteld) wordt berekend';
}
else
{
// Bereken wettelijke handelsrente (enkelvoud)
return 'De wettelijke handelsrente (enkelvoud) wordt berekend';
}

}elseif($renteSoort == 3)
{

if($samengesteld == 1) // == Contractuele rente
{

// Bereken contractuele rente (samengesteld)
$bedrag = $factuurBedrag;
$rente = $rentePercentage;
$produkt = 100+$rente;
$rentePeriode = $heden - $vervalDatum;
$jaar = ceil($rentePeriode/24/60/60)/365;
for ($i = 1;$i<$jaar;$i++){
$bedrag = ($bedrag/100)*$produkt;
// echo '<p>Jaar ' . ($i) . ' - ' . $bedrag . '</p>';
$value[] = $bedrag;
}

// Nu dient nog het 'staartje' te worden toegevoegd.
$restPeriode = floor(($jaar-floor($jaar))*365-2);
$subtotaal = $value[floor($jaar)-1];
$restRente = $subtotaal*($rente/100)/365*$restPeriode;
$totaal = round($subtotaal+$restRente,2);
echo 'De contractuele rente (samengesteld) wordt berekend.<br />';
echo 'Resultaat = '.$totaal;
}
elseif($samengesteld == 2)
{
// Bereken contractuele handelsrente (enkelvoud)
$rentePeriode = $heden - $vervalDatum;
echo 'De contractuele rente (enkelvoud) wordt berekend.<br />';
echo 'Resultaat = ';
echo number_format($factuurBedrag * ($rentePercentage/100) / 365 * ceil($rentePeriode/24/60/60),2);
echo '<br />';
}
}
}

}
?>

Weergeven doe ik op de volgende wijze:
<?php

$_GET['dossier'] = '1';

// Instants van classes creeren
$invoice = new Invoice($_GET['dossier']);
$user = new User($invoice->getUser());
$debtor = new Debtor($invoice->getDebtor());
$dossier = new Dossier($invoice->getId());
$misc = new Misc();

// Factuurgegevens ophalen
$db = new PDO('mysql:host=localhost;port=3307;dbname=****','****','****');
$sql = "SELECT id,rentePercentage,renteSoort FROM invoice WHERE dossierId = ".$dossier->getId();
$result = $db->query($sql);
$i = 0;
foreach($result as $row) {
$obj = new Invoice($row['id']);
// Bereken rente
echo $obj->calcRente($row['renteSoort'],$row['rentePercentage']);
$i++;
}
unset($obj);
?>
Dat betekend dus dat de rente per half jaar berekend moet worden? Zoals ik dat lees is dat niet echt standaard...
Nee, de rente is in het verleden ook weleens na enkele dagen of na bij voorbeeld 3 maanden gewijzigd. De laatste tijd wijzigt de rente (gelukkig) maar eens per half jaar.

Oja, weet iemand waarom dit niet werkt:
<?php
$jaarSecs = 3.15 * pow(10,7);
echo $jaarSecs;
?>
Dan krijg ik namelijk als uitkomst: 3.15E+7 (niet echt handig).
Dat werkt wel. Wetenschappelijke notatie. Zie [php]sprintf[/php].
Voor jou voorbeeld wijzigt de rente maar eens per half jaar.
Maar ik heb echt geen idee hoe je dit zou uit moeten rekenen. Volgens mij klopt het gewoon niet.

Edit:
Kan je ook gewoon de berekening laten zien?
Al is het alleen maar op papier ofzo....
Om de enkelvoudige rente te berekenen heb ik inmiddels de volgende formule:
<?php
// ==> Bereken contractuele handelsrente (enkelvoudig)
$aantalDagen = ceil($rentePeriode/60/60/24);
$rentePerDag = ($rentePercentage / 365 / 100) + 1;
$subtotaal = $factuurBedrag * pow($rentePerDag, $aantalDagen);
$subtotaalRente = $subtotaal - $factuurBedrag;

?>

Dit zou juist moeten zijn, maar desondanks krijg ik een andere uitkomst wanneer ik de resultaten vergelijk met http://www.wettelijkerente.net/renteberekening.aspx

Als ik uitga van een factuurbedrag van 100,00 en een rentepercentage van 10%. De startdatum = 01-01-2006 en de einddatum = 03-08-2010. De renteperiode is uiteraard de einddatum - startdatum in secs. Bij mij komt er dan 50.65 uit en op de online berekeningstool 46.08

Wie o wie weet hoe dit komt?
Wederom, volgens mij werkt die site niet correct. De rente is 10% dus dat is een groeifactor van 1.1.
Het begin getal is 100.
Het aantal dagen, jaren, seconde, of whatever weten we niet, das dus X.

Dus:
100*1.1^X = 145.89
1.1^X = 1.4589
X = 1.1 log 1.4589 = log 1.4589 / log 1.1 = 3.962669338
En wat voor eenheid die heeft, weet ik niet. Geen dagen, geen maanden, geen minuten, geen seconden, dus denk ik jaren.
Dat klinkt op zich ook wel goed, maar je hebt nu tussen die twee data als 4 jaar gehad.
Het gedeelte achter de komma is maar 11.55 maanden (in het totaal overigs 47.55 maanden) dus dan zou je op een verschil van 3 jaar 11 maanden 18 dagen en nog wat onzin uitkomen terwijl je dus 4 jaar 7 maanden 2 dagen nodig zou moeten hebben.

Reageren