175 lines
5.9 KiB
Python
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)}")
|
|
|