from datetime import datetime, timezone from app.extensions import db from sqlalchemy.orm import relationship from dateutil.relativedelta import relativedelta from sqlalchemy.sql import func 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) transaction_id = db.Column(db.String(50), nullable=True) product_id = db.Column(db.String(20), nullable=True) installment_number = db.Column(db.Integer, nullable=False) due_date = db.Column(db.DateTime, nullable=False) installment_amount= db.Column(db.Float, default=0.0) total_repayment_amount = 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(timezone=True), server_default=func.now()) updated_at = db.Column(db.DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) loan = relationship( "Loan", primaryjoin="LoanRepaymentSchedule.loan_id == Loan.id", foreign_keys=[loan_id], back_populates="loan_repayment_schedules", ) @classmethod def add_repayment_schedule(cls, loan, num_schedules, transaction_id): """ Add repayment schedules for a given loan. """ now = datetime.now(timezone.utc) schedules = [] for i in range(num_schedules): due_date = now + relativedelta(months=i + 1) schedule = LoanRepaymentSchedule( loan_id=loan.id, installment_number=i + 1, due_date=due_date, total_repayment_amount = round(loan.repayment_amount, 2), installment_amount=round(loan.installment_amount, 2), product_id = loan.product_id, transaction_id = transaction_id, created_at=datetime.now(timezone.utc), updated_at=datetime.now(timezone.utc) ) 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''