added a new penal charge endpoint #63
@@ -60,6 +60,9 @@ class Config:
|
|||||||
OVERDUE_LOAN_BATCH_DELAY_SECONDS = int(
|
OVERDUE_LOAN_BATCH_DELAY_SECONDS = int(
|
||||||
os.getenv("OVERDUE_LOAN_BATCH_DELAY_SECONDS", 5)
|
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_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_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")
|
BANK_CALL_SMS_BASE_URL= os.getenv("BANK_CALL_SMS_BASE_URL","https://first-advance-middleware-develop.fbn-devops-dev-asenv.appserviceenvironment.net/SMS")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.utils.logger import logger
|
from app.utils.logger import logger
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
@@ -115,6 +115,21 @@ class LoanRepaymentSchedule(db.Model):
|
|||||||
logger.error(f"Error fetching active overdue repayment schedules: {e}")
|
logger.error(f"Error fetching active overdue repayment schedules: {e}")
|
||||||
return []
|
return []
|
||||||
@classmethod
|
@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):
|
def get_partially_paid_overdue_repayment_schedule(cls):
|
||||||
"""
|
"""
|
||||||
Get all overdue repayment schedules that are partially paid.
|
Get all overdue repayment schedules that are partially paid.
|
||||||
|
|||||||
@@ -441,6 +441,45 @@ def report():
|
|||||||
logger.error(f"Error generating or sending report: {e}")
|
logger.error(f"Error generating or sending report: {e}")
|
||||||
return ResponseHelper.error("Failed to send report", status_code=500, error=str(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"])
|
@autocall_bp.route("/overdue-loans", methods=["GET"])
|
||||||
def overdue_loans():
|
def overdue_loans():
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ class LoanRepaymentScheduleService:
|
|||||||
"""
|
"""
|
||||||
return LoanRepaymentSchedule.update_repayment_schedule_description(schedule_id, description)
|
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
|
@staticmethod
|
||||||
def handle_schedule_updates(updated_loan, data, amount_collected, message, loan_data):
|
def handle_schedule_updates(updated_loan, data, amount_collected, message, loan_data):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -216,6 +216,12 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: A successful response
|
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:
|
/autocall/direct/loan:
|
||||||
post:
|
post:
|
||||||
summary: Direct call for loan disbursement
|
summary: Direct call for loan disbursement
|
||||||
|
|||||||
Reference in New Issue
Block a user