Hola chino150, te dejo aquí el código que uso en un procedimiento almacenado para el calculo de cuotas de de amortización de Leasing, pero puede valerte para la amortización de cualquier tipo de prestamo. Espero que puedas sacar algo en limpio, si no entiendes pregunta, ahora no tengo tiempo y te lo pongo tal cual lo tengo yo en un procedimiento almacenado.
Código SQL
[-]CREATE PROCEDURE CALCULOLEASING (
in_codben integer,
in_anoben integer,
in_importe numeric(15,2),
in_vresidual numeric(15,2),
in_interes float,
in_periodicidade integer,
in_cuotas integer,
in_fecini date,
in_mult integer,
in_iso numeric(15,2))
returns (
ou_cuota numeric(15,2),
ou_cfin numeric(15,2),
ou_pendente numeric(15,2))
as
declare variable v_int float;
declare variable v_acumulado numeric(15,2);
declare variable v_ncuota integer;
declare variable v_dia integer;
declare variable v_mes integer;
declare variable v_ano integer;
declare variable v_pam numeric(15,4);
declare variable v_afi numeric(15,2);
declare variable v_data date;
declare variable v_cuofisini numeric(15,2);
declare variable v_imp numeric(15,2);
begin
v_data = in_fecini;
--Calculamos o tipo de interes en tanto por 1 que lle corresponde á
--periodicidade escollida
v_int = (in_interes * in_periodicidade)/ 1200;
if (in_vresidual is null) then --Valor residual igual a unha cuota
begin
--Calculamos a cuota mensual
Ou_cuota = Redondeo(in_importe * Exp((1 + v_int),in_cuotas), 2);
Ou_cuota = Redondeo(Ou_cuota / ((((1 + v_int) *
(1 -(1 / Exp((1 + v_int), in_cuotas))) *
Exp((1 + v_int), in_cuotas)
)
/ v_int) +
1
), 2);
in_vresidual = Ou_cuota;
end
else --Valor residual introducido polo usuario
begin
Ou_cuota = Redondeo(in_importe - (in_vresidual / Exp((1 + v_int),in_cuotas)), 2);
Ou_cuota = Redondeo((Ou_cuota * v_int) / ((1+ v_int) * (1 - (1/Exp((1 + v_int), in_cuotas)))), 2);
end
v_ncuota = 0;
v_acumulado = 0;
ou_pendente = in_importe;
v_dia = cast(extract(day from in_fecini) as integer);
while (v_ncuota < in_cuotas - 1) do
begin
v_ncuota = v_ncuota +1;
Ou_cfin = Redondeo((ou_pendente - Ou_cuota) * v_int, 2);
v_acumulado = Redondeo(v_acumulado + Ou_cfin, 2);
ou_pendente = Redondeo(ou_pendente - Ou_cuota + Ou_cfin, 2);
--Se o código do ben é nulo tratase dunha simulación, polo tanto so
--devolvemos o resultado do calculo das cuotas de leasing
if (in_codben is null) then
suspend;
else --Se non se trata dunha simulación introducimos os datos na táboa de leasing
begin
insert into Leasing values (:in_codben, :in_anoben, :v_data, :ou_cuota,
:ou_cfin, :ou_pendente, 0, 0, 0);
--Calculamos a fecha de pago da próxima cuota
v_mes = cast(extract(month from v_data) as integer);
v_ano = cast(extract(year from v_data) as integer);
if (v_mes = 12) then
begin
v_mes = in_periodicidade;
v_ano = v_ano + 1;
end
else
v_mes = v_mes + in_periodicidade;
if (v_mes > 12) then
begin
v_mes = v_mes - 12;
v_ano = v_ano + 1;
end
if ((v_mes <> 2) or (v_dia <= 28)) then
v_data = cast(v_mes || '/' || v_dia || '/' || v_ano as date);
else
begin
if (bisiesto(v_ano) = 1) then
v_data = cast(v_mes || '/' || 29 || '/' || v_ano as date);
else
v_data = cast(v_mes || '/' || 28 || '/' || v_ano as date);
end
end
end
v_ncuota = v_ncuota + 1;
Ou_cfin = Redondeo(Ou_cuota * (v_ncuota) + in_vresidual - in_importe - v_acumulado, 2);
Ou_pendente = Redondeo(ou_pendente - ou_cuota + Ou_cfin, 2);
--Se o código do ben é nulo tratase dunha simulación, polo tanto so devolvemos
--o resultado do calculo das cuotas de leasing
if (in_codben is null) then
suspend;
else --Se non se trata dunha simulación introducimos os datos na táboa de leasing e actualizamos o valor residual
begin
insert into Leasing values (:in_codben, :in_anoben, :v_data, :ou_cuota,
:ou_cfin, :ou_pendente, 0, 0, 0);
update bens
set vre_be = :in_vresidual
where cod_Be = :in_codben and ano_be = :in_anoben;
-- Introducimos a cuota pertencente ao valor residual no caso de que este
-- sexa distinto de 0
if (in_vresidual > 0) then
begin
--Calculamos a fecha de pago da próxima cuota
v_mes = cast(extract(month from v_data) as integer);
v_ano = cast(extract(year from v_data) as integer);
if (v_mes = 12) then
begin
v_mes = in_periodicidade;
v_ano = v_ano + 1;
end
else
v_mes = v_mes + in_periodicidade;
if (v_mes > 12) then
begin
v_mes = v_mes - 12;
v_ano = v_ano + 1;
end
if ((v_mes <> 2) or (v_dia <= 28)) then
v_data = cast(v_mes || '/' || v_dia || '/' || v_ano as date);
else
begin
if (bisiesto(v_ano) = 1) then
v_data = cast(v_mes || '/' || 29 || '/' || v_ano as date);
else
v_data = cast(v_mes || '/' || 28 || '/' || v_ano as date);
end
-- Insertamos a cuota Leasing
insert into Leasing values (:in_codben, :in_anoben, :v_data, :in_vresidual,
0, 0, 0, 0, 0);
in_cuotas = in_cuotas + 1;
end
-- Calculamos a porcentaxe de amortización anual
select Redondeo(Pam_be/100, 4)
from bens
where cod_be = :in_codben and ano_be = :in_anoben
into :V_PAM;
v_pam = v_pam * in_mult;
-- Calculamos a cuota fiscal
v_afi = Redondeo(in_importe * v_pam, 2);
v_afi = Redondeo(v_afi / truncar(12/in_periodicidade), 2);
-- Calculamos a primeira cuota parcial, no caso que non se inicie
-- a amortización ao principio do periodo
v_cuofisini = mod((cast(extract(month from in_fecini) as integer) - 1), in_periodicidade);
v_cuofisini = Redondeo(v_afi * (in_periodicidade - v_cuofisini) / in_periodicidade, 2);
v_ncuota = 0;
v_data = in_fecini;
while ((in_importe > 0) or (v_ncuota < in_cuotas)) do
begin
v_ncuota = v_ncuota + 1;
if (v_ncuota = 1) then
v_imp = v_cuofisini;
else if (in_importe = 0) then
v_imp = 0;
else if (v_imp >= in_importe) then
v_imp = in_importe;
else
v_imp = v_afi;
if (v_ncuota <= in_cuotas) then
update leasing
set afi_le = :V_IMP, iso_le = Redondeo((cuo_le - cfi_le - :v_imp) * :in_iso, 2)
where cbe_le = :in_codben and abe_le = :in_anoben and
fec_le = :V_DATA;
else
insert into leasing values(:in_codben, :in_anoben, :v_data, 0,
0, 0, 0, :V_IMP, Redondeo(-:v_imp * :in_iso, 2));
if (in_importe > 0) then
in_importe = in_importe - v_imp;
--Calculamos a data de pago da próxima cuota
v_mes = cast(extract(month from v_data) as integer);
v_ano = cast(extract(year from v_data) as integer);
if (v_mes = 12) then
begin
v_mes = in_periodicidade;
v_ano = v_ano + 1;
end
else
v_mes = v_mes + in_periodicidade;
if (v_mes > 12) then
begin
v_mes = v_mes - 12;
v_ano = v_ano + 1;
end
if ((v_mes <> 2) or (v_dia <= 28)) then
v_data = cast(v_mes || '/' || v_dia || '/' || v_ano as date);
else
begin
if (bisiesto(v_ano) = 1) then
v_data = cast(v_mes || '/' || 29 || '/' || v_ano as date);
else
v_data = cast(v_mes || '/' || 28 || '/' || v_ano as date);
end
end
end
end
Los comentarios están en gallego, espero que no sea inconveniente.
Un saúdo, y lo dicho, si no entiendes pregunta, pero ahora mismo tengo que marchar.