diff --git a/app/api/services/base_service.py b/app/api/services/base_service.py index fa1a77e..d30619b 100644 --- a/app/api/services/base_service.py +++ b/app/api/services/base_service.py @@ -79,11 +79,11 @@ class BaseService: return {"error": "No charges found for the offer"} loan_charges = offer.charges - tenor = offer.tenor // 30 # Convert to months - interest = cls.get_charge_detail(charges = loan_charges, code = "INTEREST", amount = amount) - management = cls.get_charge_detail(charges = loan_charges, code = "MGTFEE", amount = amount) - insurance = cls.get_charge_detail(charges = loan_charges, code = "INSURANCE", amount = amount) - vat = cls.get_charge_detail(charges = loan_charges, code = "VAT", amount = amount, management_fee = management["fee"]) + tenor = offer.schedule # offer.tenor // 30 # Convert to months + interest = cls.get_charge_detail(rates = offer.interest_rate, charges = loan_charges, code = "INTEREST", amount = amount) + management = cls.get_charge_detail(rates = offer.management_rate, charges = loan_charges, code = "MGTFEE", amount = amount) + insurance = cls.get_charge_detail(rates = offer.insurance_rate, charges = loan_charges, code = "INSURANCE", amount = amount) + vat = cls.get_charge_detail(rates = offer.vat_rate, charges = loan_charges, code = "VAT", amount = amount, management_fee = management["fee"]) # Separate fees into upfront and postpaid upfront_fees = [ @@ -97,18 +97,29 @@ class BaseService: for fee in [interest, management, insurance, vat] if fee["due_days"] != 0 ] + vat_test = vat["fee"] + logger.info(f"VAT fee == *************** : {vat_test}") # Up-front payment: (only those fees due immediately i.e due_days == 0) - upfront_payment = sum(upfront_fees) + # upfront_payment = sum(upfront_fees) + if offer.schedule == 1: + upfront_payment = vat["fee"] + management["fee"] + insurance["fee"] + interest["fee"] + interest_amount = interest["fee"] + repayment_amount = amount + else: + upfront_payment = vat["fee"] + insurance["fee"]+management["fee"] + interest_amount = interest["fee"]*offer.schedule + repayment_amount = amount + interest_amount + # Repayment amount: (principal + only those fees not due immediately i.e due_days != 0) - repayment_amount = amount + (sum(postpaid_fees) * tenor) + # repayment_amount = amount + (sum(postpaid_fees) * tenor) # Total amount: (upfront_payment + repayment_amount) total_amount = upfront_payment + repayment_amount # Calculate the installment amount - installment_amount = repayment_amount / tenor + installment_amount = repayment_amount / offer.schedule return { "interest": interest, @@ -123,28 +134,39 @@ class BaseService: @classmethod - def get_charge_detail(cls, charges, code, amount, management_fee=None): + def get_charge_detail(cls, rates, charges, code, amount, management_fee= 0.0): """ Get details for a specific charge code from a list of loan charges. Returns default values if not found. """ + fee = 0.0 - - for charge in charges: - if charge.code == code: - fee = ( - management_fee * charge.percent / 100 - if code == "VAT" and management_fee is not None - else amount * charge.percent / 100 - ) + if code == "VAT" and management_fee > 0: + fee = management_fee * rates / 100 + else: + fee = amount * rates / 100 + + return { + "rate": rates, + "fee": round(fee, 2), + "due_days": 30, + "code": code, + "description" : "have no idea how to get this yet" + } + + # if charge.code == code: + # if code == "VAT" and management_fee > 0: + # fee = management_fee * rates / 100 + # else: + # fee = amount * rates / 100 + # + # return { + # "rate": rates, + # "fee": round(fee, 2), + # "due_days": charge.due + # } - return { - "rate": charge.percent, - "fee": round(fee, 2), - "due_days": charge.due - } - - return {"rate": 0, "fee": 0, "due_days": 0} + # return {"rate": 0, "fee": 0, "due_days": 0} diff --git a/app/api/services/provide_loan.py b/app/api/services/provide_loan.py index da25802..33f8b25 100644 --- a/app/api/services/provide_loan.py +++ b/app/api/services/provide_loan.py @@ -70,8 +70,16 @@ class ProvideLoanService(BaseService): charges = ProvideLoanService.calculate_charges(offer, amount) upfront_fee = charges["upfront_payment"] repayment_amount = charges["repayment_amount"] - installment_amount = charges["installment_amount"] + #installment_amount = charges["installment_amount"] tenor = offer.tenor // 30 # Convert to months + + upfront_payment = charges["upfront_payment"] + total_amount = charges["total_amount"] + installment_amount = charges["installment_amount"] + interest = charges["interest"] + management = charges["management"] + insurance = charges["insurance"] + vat = charges["vat"] @@ -107,9 +115,9 @@ class ProvideLoanService(BaseService): "message": "Failed to generate loan repayment schedule." }), 400 - charges = Charge.get_offer_charges(offer.id) + # charges = Charge.get_offer_charges(offer.id) - # logger.error(f"{charges}") + logger.error(f"{charges}") loan_id = loan.id diff --git a/app/api/services/select_offer.py b/app/api/services/select_offer.py index ddf6bd1..6f22e10 100644 --- a/app/api/services/select_offer.py +++ b/app/api/services/select_offer.py @@ -61,6 +61,7 @@ class SelectOfferService(BaseService): management = charges["management"] insurance = charges["insurance"] vat = charges["vat"] + repayment_amount = charges["repayment_amount"] # Calculate the repayment dates @@ -68,7 +69,7 @@ class SelectOfferService(BaseService): start_date = date.today() # Convert tenor to months - months = tenor // 30 + months = offer.schedule # tenor // 30 recommended_repayment_dates = [ (start_date + relativedelta(months=i + 1)).isoformat() @@ -83,19 +84,35 @@ class SelectOfferService(BaseService): "productId": product_id, "amount": amount, "upfrontPayment": upfront_payment, - "interestRate": interest["rate"], - "managementRate": management["rate"], + "interestRate": offer.interest_rate, + "managementRate": offer.management_rate, "managementFee": management["fee"], - "insuranceRate": insurance["rate"], + "insuranceRate": offer.insurance_rate, "insuranceFee": insurance["fee"], - "VATRate": vat["rate"], + "VATRate": offer.vat_rate, "VATAmount": vat["fee"], "recommendedRepaymentDates": recommended_repayment_dates, + "repaymentAmount": repayment_amount, "installmentAmount": installment_amount, "totalRepaymentAmount": total_amount, } ] + # "offerId": offer.id, + # "productId": product_id, + # "amount": amount, + # "upfrontPayment": upfront_payment, + # "interestRate": interest["rate"], + # "managementRate": management["rate"], + # "managementFee": management["fee"], + # "insuranceRate": insurance["rate"], + # "insuranceFee": insurance["fee"], + # "VATRate": vat["rate"], + # "VATAmount": vat["fee"], + # "recommendedRepaymentDates": recommended_repayment_dates, + # "installmentAmount": installment_amount, + # "totalRepaymentAmount": total_amount, + # # Business logic - selecting an offer response_data = { "outstandingDebtAmount": 0, diff --git a/app/models/loan_charge.py b/app/models/loan_charge.py index 43df5ed..773d32b 100644 --- a/app/models/loan_charge.py +++ b/app/models/loan_charge.py @@ -1,6 +1,7 @@ from datetime import datetime, timezone, timedelta from app.extensions import db from sqlalchemy.orm import relationship +from app.utils.logger import logger class LoanCharge(db.Model): @@ -35,8 +36,8 @@ class LoanCharge(db.Model): charges (list): A list of dictionaries with keys: code (str), amount (float), percent (float), description (str), due (int) """ - if not charges or not isinstance(charges, list): - raise ValueError("Charges must be a non-empty list of dictionaries") + # if not charges or not isinstance(charges, list): + # raise ValueError("Charges must be a non-empty list of dictionaries") if loan_id is None: raise ValueError("loan_id cannot be None") @@ -44,21 +45,23 @@ class LoanCharge(db.Model): loan_charges = [] now = datetime.now(timezone.utc) - for charge in charges: - due_days = getattr(charge, "due", 0) - amount = getattr(charge, "amount", 0.0) - percent = getattr(charge, "percent", 0.0) - if amount == 0.0: - amount = (percent / 100.0) * referenced_amount + subset_keys = ['interest', 'management', 'insurance', 'vat'] + for item in subset_keys: + charge = charges[item] + due_days = charge['due_days'] # getattr(charge, "due_days", 0) + amount = charge['fee'] # getattr(charge, "fee", 0.0) + percent = charge['rate'] # getattr(charge, "rate", 0.0) + code = charge['code'] # getattr(charge, "code","") + description = charge['description'] # getattr(charge, "description", "") charge_obj = cls( loan_id = loan_id, transaction_id = transaction_id, - code = getattr(charge, "code"), + code = code, amount = round(amount, 2), percent = percent, - description = getattr(charge, "description", ""), + description = description, due = due_days, due_date = now + timedelta(days=due_days) ) diff --git a/app/models/offer.py b/app/models/offer.py index 217f6c8..c37d4aa 100644 --- a/app/models/offer.py +++ b/app/models/offer.py @@ -75,7 +75,11 @@ class Offer(db.Model): "productId": self.product_id, "minAmount": self.min_amount, "maxAmount": self.max_amount, - "tenor": self.tenor + "tenor": self.tenor, + "interest_rate": self.interest_rate, + "management_rate": self.management_rate, + "insurance_rate": self.insurance_rate, + "vat_rate": self.vat_rate } def __repr__(self):