138 lines
5.5 KiB
Python
138 lines
5.5 KiB
Python
import arrow
|
||
|
||
from decimal import Decimal
|
||
from typing import Literal
|
||
from datetime import date
|
||
from dataclasses import dataclass
|
||
|
||
|
||
@dataclass
|
||
class GecikmeFaizSonucu:
|
||
faiz_turu: str
|
||
gecikme_gunu: int
|
||
gunluk_oran: float
|
||
faiz: float
|
||
bsmv: float
|
||
kkdf: float
|
||
toplam: float
|
||
|
||
|
||
# Faiz türüne göre aylık faiz oranı (%)
|
||
GLOBAL_FAIZ_ORANLARI = {"akdi": 5.0, "gecikme": 5.3}
|
||
|
||
# Vergi oranları (%)
|
||
GLOBAL_BSMV_ORANI = 15.0
|
||
GLOBAL_KKDF_ORANI = 15.0
|
||
|
||
|
||
def hesapla_komisyon(vade_tarihi: date, islem_tarihi: date, tutar: float, oran: float) -> float:
|
||
gecikme = (islem_tarihi - vade_tarihi).days
|
||
if gecikme <= 0:
|
||
return 0.0
|
||
komisyon = tutar * oran * gecikme
|
||
return round(komisyon, 2)
|
||
|
||
|
||
def hesapla_gunluk_oran(
|
||
faiz_orani: float, tip: Literal["MIR", "YIR"], gun: int = 0
|
||
) -> float:
|
||
"""
|
||
orijinal_oran: Yıllık ya da aylık faiz oranı (örneğin %12 için 0.12)
|
||
tip: 'MIR' (Monthly Interest Rate) ya da 'YIR' (Yearly Interest Rate)
|
||
"""
|
||
faiz_orani = faiz_orani / 100
|
||
if tip.upper() == "MIR":
|
||
if gun < 1:
|
||
gun = 30
|
||
return faiz_orani / gun # varsayılan aylık 30 gün
|
||
elif tip.upper() == "YIR":
|
||
if gun < 1:
|
||
gun = 360
|
||
return faiz_orani / gun # varsayılan yıl 365 gün
|
||
else:
|
||
raise ValueError("Faiz tipi yalnızca 'MIR' ya da 'YIR' olabilir.")
|
||
|
||
|
||
def hesapla_gecikme_faizi(
|
||
borc: float, vade_tarihi: date, islem_tarihi: date | None = None, faiz_orani: float = None, faiz_turu: str = "akdi", bsmv_orani: float = None, kkdf_orani: float = None,
|
||
) -> GecikmeFaizSonucu:
|
||
|
||
if islem_tarihi is None:
|
||
islem_tarihi = date.today()
|
||
gecikme_gun = (arrow.get(islem_tarihi) - arrow.get(vade_tarihi)).days
|
||
if gecikme_gun <= 0:
|
||
return GecikmeFaizSonucu(faiz_turu, 0, 0, 0, 0, 0, 0)
|
||
|
||
# Varsayılan oranları içerden bağla
|
||
if faiz_orani is None:
|
||
faiz_orani = GLOBAL_FAIZ_ORANLARI.get(faiz_turu, 5.0)
|
||
if bsmv_orani is None:
|
||
bsmv_orani = GLOBAL_BSMV_ORANI
|
||
if kkdf_orani is None:
|
||
kkdf_orani = GLOBAL_KKDF_ORANI
|
||
|
||
faiz_tipi = "MIR" if faiz_turu == "akdi" else "YIR"
|
||
gunluk_oran = hesapla_gunluk_oran(faiz_orani, faiz_tipi)
|
||
|
||
faiz_tutari = Decimal(borc) * Decimal(gunluk_oran) * Decimal(gecikme_gun)
|
||
bsmv = Decimal(faiz_tutari) * Decimal(bsmv_orani / 100)
|
||
kkdf = Decimal(faiz_tutari) * Decimal(kkdf_orani / 100)
|
||
toplam_faiz = Decimal(faiz_tutari) + Decimal(bsmv) + Decimal(kkdf)
|
||
|
||
return GecikmeFaizSonucu(
|
||
faiz_turu=faiz_turu, gecikme_gunu=gecikme_gun, gunluk_oran=round(gunluk_oran, 6), faiz=round(faiz_tutari, 2), bsmv=round(bsmv, 2), kkdf=round(kkdf, 2), toplam=round(toplam_faiz, 4),
|
||
)
|
||
|
||
"""
|
||
2025 Güncel Oranlar (TCMB verilerine göre)
|
||
tip: 'MIR' (Monthly Interest Rate) ya da 'YIR' (Yearly Interest Rate)
|
||
Faiz Türü Aylık Oran Günlük Yaklaşık Açıklama
|
||
Akdi Faiz %5,00 %0,1667 Asgari üzerindeki borca uygulanır
|
||
Gecikme Faizi %5,30 %0,1767 Asgari tutarın ödenmeyen kısmına uygulanır
|
||
|
||
CREATE TABLE public.account_delay_interest (
|
||
|
||
account_records_id int4 NOT NULL,
|
||
build_decision_book_payment_id int4 NOT NULL,
|
||
build_decision_book_payment_refid varchar(100) NOT NULL,
|
||
interest_turn varchar(10) NOT NULL,
|
||
interest_rate numeric(10, 2) NOT NULL,
|
||
delay_day int2 NOT NULL,
|
||
daily_rate numeric(20, 6) NOT NULL,
|
||
interest numeric(20, 6) NOT NULL,
|
||
bsmv numeric(20, 6) NOT NULL,
|
||
kkdf numeric(20, 6) NOT NULL,
|
||
total numeric(20, 6) NOT NULL,
|
||
new_build_decision_book_payment_id int4 NULL,
|
||
approved_record bool false NOT NULL,
|
||
approving_person int4 NOT NULL,
|
||
approving_at timestamptz NULL,
|
||
|
||
id serial4 NOT NULL,
|
||
uu_id uuid DEFAULT gen_random_uuid() NOT NULL,
|
||
expiry_starts timestamptz DEFAULT now() NOT NULL,
|
||
expiry_ends timestamptz DEFAULT now() NOT NULL,
|
||
created_at timestamptz DEFAULT now() NOT NULL,
|
||
updated_at timestamptz DEFAULT now() NOT NULL,
|
||
CONSTRAINT account_delay_interest_pkey PRIMARY KEY (id))
|
||
|
||
CREATE UNIQUE INDEX _account_delay_interest_ndx_01 ON public.account_delay_interest USING btree (account_records_id, build_decision_book_payment_id);
|
||
CREATE INDEX _account_delay_interest_ndx_02 ON public.account_delay_interest USING btree (build_decision_book_payment_id);
|
||
CREATE UNIQUE INDEX _account_delay_interest_ndx_03 ON public.account_delay_interest USING btree (build_decision_book_payment_refid);
|
||
CREATE UNIQUE INDEX _account_delay_interest_ndx_04 ON public.account_delay_interest USING btree (uu_id);
|
||
|
||
-- Column comments
|
||
COMMENT ON COLUMN public.account_delay_interest.build_decision_book_payment_refid IS 'ref id';
|
||
COMMENT ON COLUMN public.account_delay_interest.interest_turn IS 'faiz turu';
|
||
COMMENT ON COLUMN public.account_delay_interest.interest_rate IS 'uygulanan faiz';
|
||
COMMENT ON COLUMN public.account_delay_interest.delay_day IS 'gecikme_gunu';
|
||
COMMENT ON COLUMN public.account_delay_interest.daily_rate IS 'gunluk_oran';
|
||
COMMENT ON COLUMN public.account_delay_interest.interest IS 'faiz';
|
||
COMMENT ON COLUMN public.account_delay_interest.bsmv IS 'bsmv';
|
||
COMMENT ON COLUMN public.account_delay_interest.kkdf IS 'kkdf';
|
||
COMMENT ON COLUMN public.account_delay_interest.total IS 'toplam';
|
||
COMMENT ON COLUMN public.account_delay_interest.approved_record IS 'onaylandı';
|
||
COMMENT ON COLUMN public.account_delay_interest.approving_person IS 'onaylayan';
|
||
COMMENT ON COLUMN public.account_delay_interest.approving_at IS 'onay zamani';
|
||
"""
|