[add]: Lona repayment schedule

This commit is contained in:
Vivian Dee
2025-04-25 14:29:13 +01:00
parent 0995f08aea
commit c216c55928
5 changed files with 106 additions and 14 deletions
+2 -1
View File
@@ -7,6 +7,7 @@ from .loan_charge import LoanCharge
from .offer import Offer
from .charge import Charge
from .rac_checks import RACCheck
from .loan_repayment_schedule import LoanRepaymentSchedule
__all__ = ['Customer', 'Account', 'Loan', 'Transaction', 'Repayment', 'LoanCharge', 'Offer', 'Charge', 'RACCheck']
__all__ = ['Customer', 'Account', 'Loan', 'Transaction', 'Repayment', 'LoanCharge', 'Offer', 'Charge', 'RACCheck', 'LoanRepaymentSchedule']
+11 -1
View File
@@ -5,6 +5,9 @@ from app.models.account import Account
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import relationship
from app.models.loan_charge import LoanCharge
from dateutil.relativedelta import relativedelta
from app.models.loan_repayment_schedule import LoanRepaymentSchedule # Make sure this import exists
class Loan(db.Model):
@@ -47,6 +50,13 @@ class Loan(db.Model):
back_populates="loan",
)
loan_repayent_schedules = relationship(
"LoanRepaymentSchedule",
primaryjoin="Loan.id == LoanRepaymentSchedule.loan_id",
foreign_keys="LoanRepaymentSchedule.loan_id",
back_populates="loan",
)
@classmethod
def create_loan(
cls,
@@ -60,6 +70,7 @@ class Loan(db.Model):
upfront_fee,
repayment_amount,
installment_amount,
tenor,
status="pending",
):
# Check if customer exists
@@ -92,7 +103,6 @@ class Loan(db.Model):
raise ValueError(f"Database integrity error: {err}")
return loan
@classmethod
def has_active_loans(cls, customer_id):
active_loans = cls.query.filter_by(
+74
View File
@@ -0,0 +1,74 @@
from datetime import datetime, timezone
from app.extensions import db
from sqlalchemy.orm import relationship
class LoanRepaymentSchedule(db.Model):
__tablename__ = 'loan_repayment_schedules'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
loan_id = db.Column(db.Integer, nullable=False)
installment_number = db.Column(db.Integer, nullable=False)
due_date = db.Column(db.DateTime, nullable=False)
principal_amount = db.Column(db.Float, default=0.0)
interest_amount = db.Column(db.Float, default=0.0)
total_installment = db.Column(db.Float, default=0.0)
paid = db.Column(db.Boolean, default=False)
paid_at = db.Column(db.DateTime, nullable=True)
created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc))
updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc))
loan = relationship(
"Loan",
primaryjoin="LoanCharge.loan_id == Loan.id",
foreign_keys=[loan_id],
back_populates="loan_charges",
)
@classmethod
def add_repayment_schedule(cls, loan, Offer, charges):
"""
Add repayment schedules for a given loan.
"""
if not loan.amount or not loan.installment_amount:
raise ValueError("Loan must have amount and installment_amount set.")
now = datetime.now(timezone.utc)
schedules = []
interest_fee = charges["interest"]
tenor = Offer.tenor // 30
principal = loan.amount / tenor
interest = interest_fee["fee"] / tenor
for i in range(tenor):
due_date = now + relativedelta(months=i + 1)
schedule = LoanRepaymentSchedule(
loan_id=loan.id,
installment_number=i + 1,
due_date=due_date,
principal_amount=round(principal, 2),
interest_amount=round(interest, 2),
total_installment=round(loan.installment_amount, 2)
)
db.session.add(schedule)
schedules.append(schedule)
return schedules
def to_dict(self):
return {
'id': self.id,
'loanId': self.loan_id,
'installmentNumber': self.installment_number,
'dueDate': self.due_date.isoformat(),
'principalAmount': self.principal_amount,
'interestAmount': self.interest_amount,
'totalInstallment': self.total_installment,
'paid': self.paid,
'paidAt': self.paid_at.isoformat() if self.paid_at else None
}
def __repr__(self):
return f'<LoanRepaymentSchedule Loan:{self.loan_id} Installment:{self.installment_number}>'