diff --git a/app/models/loan_repayment_schedule.py b/app/models/loan_repayment_schedule.py index dcba841..a892f0a 100644 --- a/app/models/loan_repayment_schedule.py +++ b/app/models/loan_repayment_schedule.py @@ -2,6 +2,7 @@ from datetime import datetime, timedelta, timezone from app.extensions import db from app.utils.logger import logger from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy import or_ from app.enums.repayment_schedule_status import RepaymentScheduleStatus from app.config import settings @@ -122,21 +123,28 @@ class LoanRepaymentSchedule(db.Model): except Exception as e: logger.error(f"Error fetching active overdue repayment schedules: {e}") return [] + + @classmethod def get_overdue_repayment_schedule_with_grace_period(cls, grace_period_days, limit=None): - """ - Get all overdue repayment schedules that are not repaid and beyond the grace period. - """ try: - grace_period_date = datetime.now(timezone.utc) - timedelta(days=grace_period_days) + now = datetime.now(timezone.utc) + grace_period_date = now - timedelta(days=grace_period_days) + penal_interval = timedelta(days=settings.PENAL_CHARGE_INTERVAL_DAYS) + return cls.query.filter( cls.due_date < grace_period_date, - cls.paid == False + cls.paid == False, + or_( + cls.last_penal_date == None, # never penalized before + cls.last_penal_date < now - penal_interval + ) ).order_by(cls.due_date.asc()).limit(limit).all() + except Exception as e: logger.error(f"Error fetching overdue repayment schedules with grace period: {e}") return [] - + @classmethod def get_partially_paid_overdue_repayment_schedule(cls): """ @@ -300,22 +308,26 @@ class LoanRepaymentSchedule(db.Model): db.session.rollback() logger.error(f"Error applying repayment for schedule {schedule_id}: {e}") raise + from decimal import Decimal + @classmethod def apply_penal_to_schedule(cls, schedule_id, penal_amount): schedule = cls.query.get(schedule_id) now = datetime.now(timezone.utc) + penal_amount = Decimal(str(penal_amount)) + + current_penal = Decimal(str(schedule.penal_charge)) if schedule.penal_charge else Decimal("0") schedule.penal_count = (schedule.penal_count or 0) + 1 - schedule.penal_charge = (schedule.penal_charge or 0) + penal_amount + schedule.penal_charge = current_penal + penal_amount schedule.last_penal_date = now schedule.due_process_date = now schedule.updated_at = now db.session.commit() - - + # Calculate penal charge @classmethod def calculate_penal_charge(cls, schedule):