added a new penal charge endpoint #63

Merged
ameye merged 1 commits from test into master 2026-01-23 01:04:23 +00:00
5 changed files with 68 additions and 3 deletions
+3
View File
@@ -60,6 +60,9 @@ class Config:
OVERDUE_LOAN_BATCH_DELAY_SECONDS = int(
os.getenv("OVERDUE_LOAN_BATCH_DELAY_SECONDS", 5)
)
OVERDUE_GRACE_PERIOD_DAYS = int(os.getenv("OVERDUE_GRACE_PERIOD_DAYS", 30))
BANK_CALL_API_TIME_OUT = os.getenv("BANK_CALL_API_TIME_OUT", 100)
BANK_CALL_BASE_URL = os.getenv("BANK_CALL_BASE_URL", "https://bank-emulator.dev.simbrellang.net/api")
BANK_CALL_SMS_BASE_URL= os.getenv("BANK_CALL_SMS_BASE_URL","https://first-advance-middleware-develop.fbn-devops-dev-asenv.appserviceenvironment.net/SMS")
+16 -1
View File
@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import datetime, timedelta, timezone
from app.extensions import db
from app.utils.logger import logger
from sqlalchemy.exc import SQLAlchemyError
@@ -115,6 +115,21 @@ class LoanRepaymentSchedule(db.Model):
logger.error(f"Error fetching active overdue repayment schedules: {e}")
return []
@classmethod
def get_overdue_repayment_schedule_with_grace_period(cls, grace_period_days):
"""
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)
return cls.query.filter(
cls.due_date < grace_period_date,
cls.paid == False
).order_by(cls.due_date.asc()).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):
"""
Get all overdue repayment schedules that are partially paid.
+40 -1
View File
@@ -440,7 +440,46 @@ def report():
except Exception as e:
logger.error(f"Error generating or sending report: {e}")
return ResponseHelper.error("Failed to send report", status_code=500, error=str(e))
@autocall_bp.route("/process-penal-charges", methods=["GET"])
def process_penal_charges():
try:
OVERDUE_GRACE_PERIOD_DAYS = settings.OVERDUE_GRACE_PERIOD_DAYS
overdue_loans = (
LoanRepaymentScheduleService
.get_overdue_repayment_schedule_with_grace_period(OVERDUE_GRACE_PERIOD_DAYS)
)
logger.info(f"Found {len(overdue_loans)} overdue loans.")
if not overdue_loans:
return ResponseHelper.success(
message="No overdue loans found",
status_code=200
)
processed_loans = []
for loan in overdue_loans:
# TODO: apply penal charge logic here
# PenalChargeService.apply_penal_charge(loan)
processed_loans.append(loan.to_dict())
return ResponseHelper.success(
message="Penal Charges Processed Successfully",
status_code=200,
data=processed_loans
)
except Exception as e:
logger.exception(f"Error processing penal charges: {e}")
return ResponseHelper.error(
"Failed to process penal charges",
status_code=500,
error=str(e)
)
@autocall_bp.route("/overdue-loans", methods=["GET"])
def overdue_loans():
+3 -1
View File
@@ -47,7 +47,9 @@ class LoanRepaymentScheduleService:
"""
return LoanRepaymentSchedule.update_repayment_schedule_description(schedule_id, description)
@classmethod
def get_overdue_repayment_schedule_with_grace_period(cls, grace_period_days):
return LoanRepaymentSchedule.get_overdue_repayment_schedule_with_grace_period(grace_period_days)
@staticmethod
def handle_schedule_updates(updated_loan, data, amount_collected, message, loan_data):
"""
+6
View File
@@ -216,6 +216,12 @@ paths:
responses:
200:
description: A successful response
/autocall/process-penal-charges:
get:
summary: Get all overdue loans with grace period
responses:
200:
description: A successful response
/autocall/direct/loan:
post:
summary: Direct call for loan disbursement