Files
digifi-BankToProductCore/app/api/integrations/simbrella.py
T
2026-04-10 10:41:21 +01:00

175 lines
5.9 KiB
Python

from os import access
import httpx
import time
from app.utils.logger import logger
from app.config import settings
class SimbrellaIntegration:
BASE_URL = settings.SIMBRELLA_BASE_URL
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
TIMEOUT = settings.TIMEOUT
_access_token = None # cache token in memory
_token_expiry = 0
@staticmethod
def generate_token():
"""
Generate a new access token using the username and password from settings.
"""
url = f"{SimbrellaIntegration.BASE_URL}{SimbrellaIntegration.AUTH_ENDPOINT}"
payload = {
"username": settings.BANK_CALL_USERNAME,
"password": settings.BANK_CALL_PASSWORD,
"grant_type": "password"
}
headers = {"Content-Type": "application/json"}
try:
logger.info(f"Requesting Bank token from {url}")
response = httpx.post(url, json=payload, headers=headers, timeout=SimbrellaIntegration.TIMEOUT)
response.raise_for_status()
data = response.json()
expires_in = data.get("expires_in", 1800)
SimbrellaIntegration._access_token = data.get("access_token")
SimbrellaIntegration._token_expiry = time.time() + expires_in - 60
if not SimbrellaIntegration._access_token:
raise Exception("Access token not found in Bank Authorization response")
logger.info("Successfully retrieved Bank access token")
return SimbrellaIntegration._access_token
except Exception as e:
logger.error(f"Token generation failed: {str(e)}", exc_info=True)
raise Exception(f"Token generation failed: {str(e)}")
@staticmethod
def _get_token():
"""
Return a valid token, refreshing if expired or missing
"""
if not SimbrellaIntegration._access_token or time.time() >= SimbrellaIntegration._token_expiry:
return SimbrellaIntegration.generate_token()
return SimbrellaIntegration._access_token
@staticmethod
def rac_check(customer_id, account_id, transaction_id):
"""
Calls the RACCheck endpoit
"""
url = f"{SimbrellaIntegration.BASE_URL}/{SimbrellaIntegration.ENDPOINT_RAC_CHECKS}"
logger.info(f"Contacting Rack Checks EndPoint: {str(url)}", exc_info=True)
payload = {
"customerId": customer_id,
"accountId": account_id,
"transactionId": str(transaction_id),
"fbnTransactionId": str(transaction_id),
"countryCode": "NG",
"channel": "USSD"
}
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=SimbrellaIntegration.TIMEOUT)
logger.info(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)}")
@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=SimbrellaIntegration.TIMEOUT,
)
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():
"""
Health check for Bank Service
"""
url = f"{SimbrellaIntegration.BASE_URL}/{SimbrellaIntegration.HEALTH_ENDPOINT}"
logger.info(f"Bank Health Check URL: {url}")
try:
access_token = SimbrellaIntegration._get_token()
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {access_token}"
}
response = httpx.get(url, headers=headers, timeout=SimbrellaIntegration.TIMEOUT)
logger.info(f"Bank Health Check Response: {response.text}")
return response
except Exception as e:
logger.error(f"Bank Health Check API call failed: {str(e)}", exc_info=True)
raise Exception(f"Bank Health Check API call failed: {str(e)}")