added penal charge to schedule
This commit was merged in pull request #67.
This commit is contained in:
+84
-9
@@ -12,9 +12,11 @@ from app.services.loan import LoanService
|
||||
from app.services.repayment import RepaymentService
|
||||
from app.services.salary import SalaryService
|
||||
from app.services.loan_repayment_schedule import LoanRepaymentScheduleService
|
||||
from app.services.loan_charge import LoanChargesService
|
||||
from app.enums.loan_status import LoanStatus
|
||||
from app.enums.repayment_schedule_status import RepaymentScheduleStatus
|
||||
from app.utils.mail import send_report_email, get_report_data
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from app.config import settings
|
||||
|
||||
autocall_bp = Blueprint("autocall", __name__)
|
||||
@@ -446,26 +448,99 @@ def process_penal_charges():
|
||||
try:
|
||||
OVERDUE_GRACE_PERIOD_DAYS = settings.OVERDUE_GRACE_PERIOD_DAYS
|
||||
OVERDUE_PROCESSING_LIST_LIMIT = settings.OVERDUE_PROCESSING_LIST_LIMIT
|
||||
PENAL_CHARGE_MAXIMUM_COUNT = settings.PENAL_CHARGE_MAXIMUM_COUNT
|
||||
PENAL_CHARGE_INTERVAL_DAYS = settings.PENAL_CHARGE_INTERVAL_DAYS
|
||||
|
||||
overdue_loans = (
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
overdue_schedules = (
|
||||
LoanRepaymentScheduleService
|
||||
.get_overdue_repayment_schedule_with_grace_period(OVERDUE_GRACE_PERIOD_DAYS,OVERDUE_PROCESSING_LIST_LIMIT)
|
||||
.get_overdue_repayment_schedule_with_grace_period(
|
||||
OVERDUE_GRACE_PERIOD_DAYS,
|
||||
OVERDUE_PROCESSING_LIST_LIMIT
|
||||
)
|
||||
)
|
||||
|
||||
logger.info(f"Found {len(overdue_loans)} overdue loans.")
|
||||
logger.info(f"Found {len(overdue_schedules)} overdue loan schedule.")
|
||||
|
||||
if not overdue_loans:
|
||||
if not overdue_schedules:
|
||||
return ResponseHelper.success(
|
||||
message="No overdue loans found",
|
||||
message="No overdue loan schedule found",
|
||||
status_code=200
|
||||
)
|
||||
|
||||
processed_loans = []
|
||||
|
||||
for loan in overdue_loans:
|
||||
# TODO: apply penal charge logic here
|
||||
# PenalChargeService.apply_penal_charge(loan)
|
||||
LoanRepaymentScheduleService.update_due_process_date_and_count(loan.id)
|
||||
for schedule in overdue_schedules:
|
||||
|
||||
loan = LoanService.get_loan_by_loan_id(schedule.loan_id)
|
||||
|
||||
if not loan:
|
||||
logger.info(f"Loan with id {schedule.loan_id} not found")
|
||||
continue
|
||||
|
||||
penal_count = schedule.penal_count or 0
|
||||
|
||||
# MAX PENAL CHECK
|
||||
if penal_count >= PENAL_CHARGE_MAXIMUM_COUNT:
|
||||
logger.info(
|
||||
f"Penal count for schedule {schedule.id} has reached the maximum limit."
|
||||
)
|
||||
continue
|
||||
|
||||
# INTERVAL CHECK (PER SCHEDULE)
|
||||
if schedule.last_penal_date:
|
||||
# ensure last_penal_date is timezone-aware
|
||||
last_penal = schedule.last_penal_date
|
||||
if last_penal.tzinfo is None:
|
||||
last_penal = last_penal.replace(tzinfo=timezone.utc)
|
||||
|
||||
next_allowed_date = last_penal + timedelta(days=PENAL_CHARGE_INTERVAL_DAYS)
|
||||
|
||||
if now < next_allowed_date:
|
||||
logger.info(
|
||||
f"Penal interval for schedule {schedule.id} has not passed yet."
|
||||
)
|
||||
continue
|
||||
|
||||
# NEXT PENAL NUMBER
|
||||
next_penal_no = penal_count + 1
|
||||
|
||||
# CALCULATE PENAL
|
||||
penal_amount = LoanRepaymentScheduleService.calculate_penal_charge(schedule)
|
||||
|
||||
# CREATE PENAL CHARGE
|
||||
new_penal_charge = LoanChargesService.create_penal_charges_for_loan(
|
||||
loan_id=schedule.loan_id,
|
||||
transaction_id=schedule.transaction_id,
|
||||
percent=settings.PENAL_CHARGE_PERCENTAGE,
|
||||
penal_no=next_penal_no,
|
||||
schedule_number=schedule.installment_number,
|
||||
penal_amount=penal_amount
|
||||
)
|
||||
|
||||
if not new_penal_charge:
|
||||
logger.error(f"Failed to create penal charge for loan ID: {loan.id}")
|
||||
continue
|
||||
|
||||
logger.info(f"Penal charge created: {new_penal_charge.to_dict()}")
|
||||
|
||||
# UPDATE SCHEDULE
|
||||
LoanRepaymentScheduleService.apply_penal_to_schedule(
|
||||
schedule.id,
|
||||
penal_amount
|
||||
)
|
||||
|
||||
logger.info(f"Penal charge applied to schedule {schedule.id}")
|
||||
|
||||
# UPDATE LOAN TOTAL
|
||||
LoanService.apply_penal_to_loan(
|
||||
loan.id,
|
||||
penal_amount
|
||||
)
|
||||
|
||||
logger.info(f"Penal charge applied to loan {loan.id}")
|
||||
|
||||
processed_loans.append(loan.to_dict())
|
||||
|
||||
return ResponseHelper.success(
|
||||
|
||||
Reference in New Issue
Block a user