diff --git a/app/api/integrations/simbrella.py b/app/api/integrations/simbrella.py index 5db7012..d46e5d4 100644 --- a/app/api/integrations/simbrella.py +++ b/app/api/integrations/simbrella.py @@ -49,6 +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)}") + diff --git a/app/api/services/select_offer.py b/app/api/services/select_offer.py index 6f70aeb..a207f2b 100644 --- a/app/api/services/select_offer.py +++ b/app/api/services/select_offer.py @@ -5,7 +5,9 @@ from app.api.enums import TransactionType 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 @@ -28,6 +30,10 @@ class SelectOfferService(BaseService): ) account_id = validated_data.get("accountId") customer_id = validated_data.get("customerId") + 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 @@ -42,30 +48,83 @@ class SelectOfferService(BaseService): else: return jsonify({"message": "Invalid Customer or Account"}), 400 + # Get the offer by product ID + offer = Offer.get_offer_by_product_id(product_id) + + if not offer: + logger.error(f"Offer with product ID {product_id} not found") + return jsonify({"message": "Offer not found"}), 404 + + # Get the loan charges for the offer + loan_charges = offer.charges + if not loan_charges: + logger.error(f"No charges found for offer ID {offer.id}") + return jsonify({"message": "No charges found for the offer"}), 404 + + logger.error(f"{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( + 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(months) + ] + + # Calculate the installment amount + installment_amount = total_amount / tenor + + offers = [ { - "offerId": "SAL90", - "productId": "2030", - "amount": 10000.0, - "upfrontPayment": 1000.0, - "interestRate": 3.0, - "managementRate": 1.0, - "managementFee": 1.0, - "insuranceRate": 1.0, - "insuranceFee": 100.0, - "VATRate": 7.5, - "VATAmount": 100.0, - "recommendedRepaymentDates": ["2022-11-30"], - "installmentAmount": 11000.0, - "totalRepaymentAmount": 11000.0, + "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, - "requestId": "202111170001371256908", - "transactionId": transaction.id, + "requestId": request_id, + "transactionId": transaction_id, "customerId": customer_id, "accountId": account_id, "loan": offers, @@ -91,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} + diff --git a/app/models/offer.py b/app/models/offer.py index b51dc25..a2009e7 100644 --- a/app/models/offer.py +++ b/app/models/offer.py @@ -40,6 +40,28 @@ class Offer(db.Model): if not offer: return False return offer + + @classmethod + def get_offer_by_id(cls, offer_id): + """ + Return an offer by its ID. + """ + offer = cls.query.filter_by(id=str(offer_id)).first() + + if not offer: + raise ValueError(f"Offer with ID {offer_id} not found") + return offer + + @classmethod + def get_offer_by_product_id(cls, product_id): + """ + Return an offer by its product ID. + """ + offer = cls.query.filter_by(product_id=str(product_id)).first() + + if not offer: + raise ValueError(f"Offer with Product ID {product_id} not found") + return offer def to_dict(self): return { diff --git a/app/models/rac_checks.py b/app/models/rac_checks.py new file mode 100644 index 0000000..9e33a84 --- /dev/null +++ b/app/models/rac_checks.py @@ -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) diff --git a/requirements.txt b/requirements.txt index 95d8b87..124ae97 100644 --- a/requirements.txt +++ b/requirements.txt @@ -35,3 +35,7 @@ flask-jwt-extended # Kafka confluent-kafka==1.9.2 + + +python-dateutil>=2.8.0 +