[update]: Select Offer #14
@@ -49,10 +49,8 @@ class SimbrellaIntegration:
|
||||
logger.error(f"This is Response: {str(response)}", exc_info=True)
|
||||
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"RACCheck API call failed: {str(e)}", exc_info=True)
|
||||
raise Exception(f"RACCheck API call failed: {str(e)}")
|
||||
# return httpx.Response(
|
||||
# status_code=200,
|
||||
# json={}
|
||||
# )
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ from app.utils.logger import logger
|
||||
from app.api.schemas.select_offer import SelectOfferSchema
|
||||
from app.extensions import db
|
||||
from app.models import Offer
|
||||
|
||||
from datetime import date
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
class SelectOfferService(BaseService):
|
||||
TRANSACTION_TYPE = TransactionType.SELECT_OFFER
|
||||
@@ -29,8 +30,10 @@ class SelectOfferService(BaseService):
|
||||
)
|
||||
account_id = validated_data.get("accountId")
|
||||
customer_id = validated_data.get("customerId")
|
||||
amount = validated_data.get("amount")
|
||||
amount = validated_data.get("requestedAmount")
|
||||
product_id = validated_data.get("productId")
|
||||
transaction_id = validated_data.get("transactionId")
|
||||
request_id = validated_data.get("requestId")
|
||||
|
||||
if SelectOfferService.validate_account_ownership(
|
||||
account_id=account_id, customer_id=customer_id
|
||||
@@ -60,52 +63,57 @@ class SelectOfferService(BaseService):
|
||||
|
||||
logger.error(f"{loan_charges}")
|
||||
|
||||
fees_and_dues = {
|
||||
charge.code: {
|
||||
"rate": charge.percent,
|
||||
"fee": amount * charge.percent / 100,
|
||||
"due_days": charge.due,
|
||||
}
|
||||
for charge in loan_charges
|
||||
}
|
||||
|
||||
db.session.flush()
|
||||
interest = SelectOfferService.get_charge_detail(loan_charges, "INTEREST", amount)
|
||||
management = SelectOfferService.get_charge_detail(loan_charges, "MGTFEE", amount)
|
||||
insurance = SelectOfferService.get_charge_detail(loan_charges, "INSURANCE", amount)
|
||||
vat = SelectOfferService.get_charge_detail(loan_charges, "VAT", amount)
|
||||
|
||||
|
||||
# Up-front payment: (principal + only those fees due immediately i.e due_days == 0)
|
||||
upfront_payment = amount + sum(
|
||||
amount * charge.percent / 100
|
||||
for charge in loan_charges
|
||||
if charge.due == 0
|
||||
)
|
||||
|
||||
# Total amount (principal + all fees)
|
||||
total_amount = amount + sum(item["fee"] for item in fees_and_dues.values())
|
||||
|
||||
# Up-front payment: only those fees due immediately (due_days == 0)
|
||||
upfront_payment = sum(
|
||||
item["fee"]
|
||||
for item in fees_and_dues.values()
|
||||
if item["due_days"] == 0
|
||||
total_amount = amount + sum(
|
||||
amount * charge.percent / 100
|
||||
for charge in loan_charges
|
||||
)
|
||||
|
||||
|
||||
# Calculate the repayment dates
|
||||
tenor = offer.tenor
|
||||
start_date = date.today()
|
||||
|
||||
# Convert tenor to months
|
||||
months = tenor // 30
|
||||
|
||||
recommended_repayment_dates = [
|
||||
(start_date + relativedelta(months=i + 1)).isoformat()
|
||||
for i in range(tenor)
|
||||
for i in range(months)
|
||||
]
|
||||
|
||||
# Calculate the installment amount
|
||||
# Calculate the installment amount
|
||||
installment_amount = total_amount / tenor
|
||||
|
||||
|
||||
offers = [
|
||||
{
|
||||
"offerId": Offer.id,
|
||||
"offerId": offer.id,
|
||||
"productId": product_id,
|
||||
"amount": amount,
|
||||
"upfrontPayment": upfront_payment,
|
||||
"interestRate": fees_and_dues["INTEREST"]["rate"],
|
||||
"managementRate": fees_and_dues["MGTFEE"]["rate"],
|
||||
"managementFee": fees_and_dues["MGTFEE"]["fee"],
|
||||
"insuranceRate": fees_and_dues["INSURANCE"]["rate"],
|
||||
"insuranceFee": fees_and_dues["INSURANCE"]["fee"],
|
||||
"VATRate": fees_and_dues["VAT"]["rate"],
|
||||
"VATAmount": fees_and_dues["VAT"]["fee"],
|
||||
"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,
|
||||
@@ -115,8 +123,8 @@ class SelectOfferService(BaseService):
|
||||
# Business logic - selecting an offer
|
||||
response_data = {
|
||||
"outstandingDebtAmount": 0,
|
||||
"requestId": "202111170001371256908",
|
||||
"transactionId": transaction.id,
|
||||
"requestId": request_id,
|
||||
"transactionId": transaction_id,
|
||||
"customerId": customer_id,
|
||||
"accountId": account_id,
|
||||
"loan": offers,
|
||||
@@ -142,3 +150,25 @@ class SelectOfferService(BaseService):
|
||||
logger.error(f"An error occurred: {str(e)}", exc_info=True)
|
||||
db.session.rollback()
|
||||
return jsonify({"message": "Internal Server Error"}), 500
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_charge_detail(charges, code, amount):
|
||||
"""
|
||||
Get details for a specific charge code from a list of loan charges.
|
||||
|
||||
Returns default values if not found.
|
||||
"""
|
||||
|
||||
|
||||
for charge in charges:
|
||||
if charge.code == code:
|
||||
return {
|
||||
"rate": charge.percent,
|
||||
"fee": amount * charge.percent / 100,
|
||||
"due_days": charge.due,
|
||||
}
|
||||
|
||||
return {"rate": 0, "fee": 0, "due_days": 0}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
from datetime import datetime, timezone
|
||||
from app.extensions import db
|
||||
|
||||
class RACCheck(Base):
|
||||
__tablename__ = "rac_checks"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid4)
|
||||
transaction_id = Column(UUID, ForeignKey('transactions.id'), nullable=False)
|
||||
customer_id = Column(String, nullable=False)
|
||||
account_id = Column(String, nullable=False)
|
||||
rac_response = Column(JSON, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
@@ -35,3 +35,7 @@ flask-jwt-extended
|
||||
# Kafka
|
||||
confluent-kafka==1.9.2
|
||||
|
||||
|
||||
|
||||
python-dateutil>=2.8.0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user