From e2eea4d4559c29915466ebf9edc47474cbed593a Mon Sep 17 00:00:00 2001 From: VivianDee <115420678+VivianDee@users.noreply.github.com> Date: Mon, 23 Feb 2026 16:45:17 +0100 Subject: [PATCH] [add]: Account Balance check --- app/api/integrations/simbrella.py | 53 +++++++++++++++++++++++++++++++ app/api/services/repayment.py | 35 ++++++++++++++++++++ app/config.py | 2 ++ 3 files changed, 90 insertions(+) diff --git a/app/api/integrations/simbrella.py b/app/api/integrations/simbrella.py index 58171f4..9e9d5f9 100644 --- a/app/api/integrations/simbrella.py +++ b/app/api/integrations/simbrella.py @@ -10,6 +10,7 @@ class SimbrellaIntegration: ENDPOINT_RAC_CHECKS = settings.SIMBRELLA_ENDPOINT_RAC_CHECKS HEALTH_ENDPOINT = settings.SIMBRELLA_HEALTH AUTH_ENDPOINT = settings.BANK_CALL_AUTH_ENDPOINT + SIMBRELLA_VERIFY_BALANCE_ENDPOINT = settings.SIMBRELLA_VERIFY_BALANCE_ENDPOINT _access_token = None # cache token in memory _token_expiry = 0 @@ -94,6 +95,58 @@ class SimbrellaIntegration: 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)}") + + + @staticmethod + def verify_account_balance(account_id: str, amount: float, request_id: str): + """ + Calls the Verify Account Balance endpoint + """ + url = f"{SimbrellaIntegration.BASE_URL}/{SimbrellaIntegration.SIMBRELLA_VERIFY_BALANCE_ENDPOINT}" + logger.info(f"Contacting Verify Account Balance Endpoint: {url}") + + payload = { + "accountId": account_id, + "amount": amount, + "requestId": str(request_id), + } + + try: + access_token = SimbrellaIntegration._get_token() + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {access_token}", + } + + response = httpx.post( + url, + json=payload, + headers=headers, + timeout=10.0, + ) + + logger.info( + f"Verify Account Balance Response: " + f"status={response.status_code}, body={response.text}" + ) + + response.raise_for_status() + return response + + except httpx.HTTPStatusError as e: + logger.error( + f"Verify Account Balance failed with status " + f"{e.response.status_code}: {e.response.text}", + exc_info=True, + ) + raise Exception("Verify Account Balance API returned an error") + + except Exception as e: + logger.error( + f"Verify Account Balance API call failed: {str(e)}", + exc_info=True, + ) + raise Exception(f"Verify Account Balance API call failed: {str(e)}") @staticmethod def health_check(): diff --git a/app/api/services/repayment.py b/app/api/services/repayment.py index cf58315..ee90568 100644 --- a/app/api/services/repayment.py +++ b/app/api/services/repayment.py @@ -1,3 +1,4 @@ +from app.api.integrations.simbrella import SimbrellaIntegration from flask import request, jsonify from marshmallow import ValidationError from app.api.enums.loan_status import LoanStatus @@ -12,9 +13,11 @@ from app.api.enums import TransactionType from threading import Thread from app.extensions import db from app.api.integrations import EventServiceIntegration +from app.config import settings class RepaymentService(BaseService): TRANSACTION_TYPE = TransactionType.REPAYMENT + ENABLE_ACCOUNT_BALANCE_CHECK = settings.ENABLE_ACCOUNT_BALANCE_CHECK @staticmethod def process_request(data): @@ -46,6 +49,38 @@ class RepaymentService(BaseService): # Check loan exists load_loan = Loan.get_customer_loan(loan_id = loan_id, customer_id = customer_id) + + # Check Customer Account Balance if enabled + if RepaymentService.ENABLE_ACCOUNT_BALANCE_CHECK: + response = SimbrellaIntegration.verify_account_balance( + account_id = account_id, + amount = load_loan.balance, + request_id = request_id, + ) + + # this check for error is not valid + if response.status_code != 200: + return ResponseHelper.error(result_description="Balance Check failed") + + response = response.json() + + logger.info(f"This is Response (Balance Check): {str(response)}", exc_info=True) + + + if not response or response['responseCode'] != '00': + + if response: + logger.error(f"{response['responseMessage']}") + + return ResponseHelper.error(result_description=f"Balance Check failed") + + verify_account_balance_response = response['isSufficient'] + + if not verify_account_balance_response or verify_account_balance_response in [False, "false"]: + logger.error(f"Balance Check failed: Insufficient Account Balance") + return ResponseHelper.error(result_description=f"Insufficient Account Balance") + + # Save the repayment details repayment = Repayment.create_repayment( customer_id = customer_id, diff --git a/app/config.py b/app/config.py index 8cf31c2..f95899e 100644 --- a/app/config.py +++ b/app/config.py @@ -46,6 +46,8 @@ class Config: VALID_API_KEY = os.getenv("SIMBRELLA_API_KEY", "test-api-key-12345") SIMBRELLA_BASE_URL = os.getenv("SIMBRELLA_BASE_URL", "http://127.0.0.1:6337") SIMBRELLA_ENDPOINT_RAC_CHECKS = os.getenv("SIMBRELLA_ENDPOINT_RAC_CHECKS","api/rac-check") + SIMBRELLA_VERIFY_BALANCE_ENDPOINT = os.getenv("SIMBRELLA_VERIFY_BALANCE_ENDPOINT", "api/VerifyAccountBalance") + ENABLE_ACCOUNT_BALANCE_CHECK = os.getenv("ENABLE_ACCOUNT_BALANCE_CHECK", True) SIMBRELLA_HEALTH = os.getenv("SIMBRELLA_ENDPOINT_RAC_CHECKS","api/system-health-check") BANK_CALL_AUTH_ENDPOINT = os.getenv("BANK_CALL_AUTH_ENDPOINT", "/api/Auth/generate-token") BANK_CALL_USERNAME = os.getenv("BANK_CALL_USERNAME", "simbrella")