diff --git a/app/config.py b/app/config.py index ff2ffb8..9a20816 100644 --- a/app/config.py +++ b/app/config.py @@ -14,8 +14,6 @@ class Config: KAFKA_PAYMENT_TOPIC = "PROCESS_PAYMENT" KAFKA_TIMEOUT = float( os.getenv("KAFKA_TIMEOUT", 1000.0) ) - - JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "secret-key") JWT_ACCESS_TOKEN_EXPIRES = os.getenv("JWT_ACCESS_TOKEN_EXPIRES", timedelta(hours=1)) JWT_REFRESH_TOKEN_EXPIRES = os.getenv( "JWT_REFRESH_TOKEN_EXPIRES", timedelta(days=30) diff --git a/app/integrations/kafka.py b/app/integrations/kafka.py index 34513d9..8a35a7c 100644 --- a/app/integrations/kafka.py +++ b/app/integrations/kafka.py @@ -59,7 +59,7 @@ class KafkaIntegration: logger.info( f"Waiting for messages from topic {topic} with this timeout: {timeout}..." ) - message =[] + message = [] try: msg = consumer.poll(timeout=timeout) @@ -100,10 +100,10 @@ class KafkaIntegration: current_topic = msg.topic() if current_topic=="PROCESS_PAYMENT": - KafkaIntegration._call_disbursement_endpoint(message) + KafkaIntegration._call_disbursement_service(message) if current_topic=="LOAN_REPAYMENT": - # Do loan repayment call here + KafkaIntegration._call_collect_loan_service(message) logger.info( f"Loan Repayment message from {msg.topic()} [{msg.partition()}] @ offset {msg.offset()}: {message}" ) @@ -124,15 +124,29 @@ class KafkaIntegration: logger.info("Kafka consumer closed") @staticmethod - def _call_disbursement_endpoint(message): - """Call the disbursement endpoint with the received message""" - logger.info(f"Calling disbursement endpoint with message: {message}") + def _call_disbursement_service(message): + """Call the disbursement service with the received message""" + logger.info(f"Calling disbursement service with message: {message}") try: response = SimbrellaClient.disbursement(message) logger.info( - f"Successfully sent message to disbursement endpoint: {response.status_code}" + f"Successfully sent message to disbursement service: {response.status_code}" ) except Exception as e: - logger.info(f"Failed to call disbursement endpoint: {e}") + logger.info(f"Failed to call disbursement service: {e}") #raise + + @staticmethod + def _call_collect_loan_service(message): + """Call the collect loan service with the received message""" + logger.info(f"Calling collect_loan service with message: {message}") + + try: + response = SimbrellaClient.collect_loan(message) + logger.info( + f"Successfully sent message to collect_loan service: {response.status_code}" + ) + except Exception as e: + logger.info(f"Failed to call collect_loan service: {e}") + # raise diff --git a/app/integrations/simbrella.py b/app/integrations/simbrella.py index df1c2b6..073e7d2 100644 --- a/app/integrations/simbrella.py +++ b/app/integrations/simbrella.py @@ -6,15 +6,13 @@ from flask import jsonify class SimbrellaClient: - BASE_URL = settings.BANK_CALL_BASE_URL BANK_CALL_BASE_URL = settings.BANK_CALL_BASE_URL @staticmethod def disbursement(data): - BANK_CALL_BASE_URL = "https://bank-emulator.dev.simbrellang.net" - api_url = f"{BANK_CALL_BASE_URL}/Disbursement" - logger.info(f"BANK_CALL_BASE_URL = {BANK_CALL_BASE_URL}") - logger.info(f"Calling disbursement endpoint with data: {data}") + api_url = f"{SimbrellaClient.BANK_CALL_BASE_URL}/Disbursement" + logger.info(f"BANK_CALL_BASE_URL = {SimbrellaClient.BANK_CALL_BASE_URL}") + logger.info(f"Calling Disbursement endpoint with data: {data}") data={ "requestId": "RQID1743987402764", @@ -47,9 +45,96 @@ class SimbrellaClient: logger.info(f"Disbursement response: {response.json()}") except Exception as e: - logger.info(f"Failed to call disbursement endpoint: {e}") + logger.info(f"Failed to call Disbursement endpoint: {e}") #raise return 0 # return jsonify(response.json()), response.status_code - return 1 \ No newline at end of file + return 1 + + @staticmethod + def collect_loan(data): + api_url = f"{SimbrellaClient.BANK_CALL_BASE_URL}/CollectLoan" + logger.info(f"BANK_CALL_BASE_URL = {SimbrellaClient.BANK_CALL_BASE_URL}") + logger.info(f"Calling CollectLoan endpoint with data: {data}") + + collect_loan_data = { + "transactionId": "T002", + "fbnTransactionId": "FBN20231123", + "debtId": "273194670", + "customerId": "CN621868", + "accountId": "2017821799", + "productId": "101", + "collectAmount": 80000, + "penalCharge": 0, + "collectionMethod": 1, + "lienAmount": 80000, + "countryId": "01", + "comment": "Testing CollectionLoanRequest" + } + + try: + logger.info(f"Here is your CollectLoan Request data ***** : {collect_loan_data}") + response = requests.post(api_url, json=collect_loan_data, headers=get_headers()) + logger.info(f"CollectLoan response: {response.json()}") + + except Exception as e: + logger.info(f"Failed to call CollectLoan endpoint: {e}") + return 0 + + return 1 + + @staticmethod + def verify_transaction(data): + api_url = f"{SimbrellaClient.BANK_CALL_BASE_URL}/TransactionVerify" + logger.info(f"BANK_CALL_BASE_URL = {SimbrellaClient.BANK_CALL_BASE_URL}") + logger.info(f"Calling TransactionVerify endpoint with data: {data}") + + try: + logger.info(f"Here is your TransactionVerify Request data ***** : {data}") + response = requests.post(api_url, json=data, headers=get_headers()) + logger.info(f"TransactionVerify response: {response.json()}") + + return response.json() + + except Exception as e: + logger.info(f"Failed to call TransactionVerify endpoint: {e}") + raise + + @staticmethod + def refresh_disbursement(data): + api_url = f"{SimbrellaClient.BANK_CALL_BASE_URL}/Disbursement" + logger.info(f"BANK_CALL_BASE_URL = {SimbrellaClient.BANK_CALL_BASE_URL}") + logger.info(f"Calling Disbursement endpoint with data: {data}") + + try: + logger.info(f"Here is your Disbursement Request data ***** : {data}") + # response = requests.post(api_url, json=data, headers=get_headers()) + # logger.info(f"Disbursement response: {response.json()}") + + # return response.json() + + return data + + except Exception as e: + logger.info(f"Failed to call Disbursement endpoint: {e}") + raise + + @staticmethod + def payment_callback(data): + api_url = f"{SimbrellaClient.BANK_CALL_BASE_URL}/Payment" + logger.info(f"BANK_CALL_BASE_URL = {SimbrellaClient.BANK_CALL_BASE_URL}") + logger.info(f"Calling Payment Callback endpoint with data: {data}") + + try: + logger.info(f"Here is your Payment Callback Request data ***** : {data}") + # response = requests.post(api_url, json=data, headers=get_headers()) + # logger.info(f"Payment Callback response: {response.json()}") + + # return response.json() + + return data + + except Exception as e: + logger.info(f"Failed to call Payment Callback endpoint: {e}") + raise \ No newline at end of file diff --git a/app/routes/__init__.py b/app/routes/__init__.py index cd8181e..7fe2df0 100644 --- a/app/routes/__init__.py +++ b/app/routes/__init__.py @@ -1,4 +1,2 @@ from .authentication import auth_bp -from .eligibility import eligibility_bp -from .loan import loan_bp from .autocall import autocall_bp diff --git a/app/routes/autocall.py b/app/routes/autocall.py index 530b8cc..75eddf3 100644 --- a/app/routes/autocall.py +++ b/app/routes/autocall.py @@ -3,24 +3,34 @@ import requests from app.config import settings from app.utils.auth import get_headers from app.utils.logger import logger +from app.integrations.simbrella import SimbrellaClient autocall_bp = Blueprint("autocall", __name__) @autocall_bp.route("/refresh-verify-disbursement", methods=["GET"]) def verify_transaction(): data = request.json() - logger.info(f"Calling Verify Components") - return jsonify(data), 200 + logger.info(f"Calling VerifyTransaction Components") + + response = SimbrellaClient.verify_transaction(data) + + return jsonify(response), 200 @autocall_bp.route("/refresh-disbursement", methods=["GET"]) def disbursement(): data = request.json() logger.info(f"Calling Disbursement Components") - return jsonify(data), 200 + + response = SimbrellaClient.verify_transaction(data) + + return jsonify(response), 200 @autocall_bp.route("/payment-callback", methods=["POST"]) def payment_callback(): data = request.json() logger.info(f"Calling Callback Components") - return jsonify(data), 200 \ No newline at end of file + + response = SimbrellaClient.payment_callback(data) + + return jsonify(response), 200 \ No newline at end of file diff --git a/app/routes/eligibility.py b/app/routes/eligibility.py deleted file mode 100644 index 9ad0fcc..0000000 --- a/app/routes/eligibility.py +++ /dev/null @@ -1,43 +0,0 @@ -from flask import Blueprint, request, jsonify, current_app -from app.config import settings -import requests -from app.utils.auth import get_headers - -eligibility_bp = Blueprint("eligibility", __name__) - -BASE_URL = settings.BANK_CALL_BASE_URL - - -@eligibility_bp.route("/check", methods=["POST"]) -def eligibility_check(): - data = request.json - api_url = f"{BASE_URL}/EligibilityCheck" - - # response = requests.post(api_url, json=data, headers=get_headers()) - # return jsonify(response.json()), response.status_code - response = { - "customerId": "CN621868", - "transactionId": "Tr201712RK9232P115", - "countryCode": "NGR", - "msisdn": "2348012345678", - "eligibleOffers": [ - { - "offerId": 101, - "minAmount": 5000, - "maxAmount": 20000, - "productId": 2030, - "tenor": 30, - }, - { - "offerId": 102, - "minAmount": 20000, - "maxAmount": 50000, - "productId": 2090, - "tenor": 90, - }, - ], - "resultCode": "00", - "resultDescription": "Successful", - } - - return jsonify(response), 200 diff --git a/app/routes/loan.py b/app/routes/loan.py deleted file mode 100644 index ea28cd0..0000000 --- a/app/routes/loan.py +++ /dev/null @@ -1,253 +0,0 @@ -from flask import Blueprint, request, jsonify, current_app -import requests -from app.config import settings -from app.utils.auth import get_headers -from app.utils.logger import logger - -loan_bp = Blueprint("loan", __name__) - -BASE_URL = settings.BANK_CALL_BASE_URL - - -@loan_bp.route("/select-offer", methods=["POST"]) -def select_offer(): - data = request.json - api_url = f"{BASE_URL}/SelectOffer" - - # response = requests.post(api_url, json=data, headers=get_headers()) - # return jsonify(response.json()), response.status_code - response = { - "transactionId": "1231231321232", - "customerId": "1256907", - "accountId": "5948306019", - "outstandingDebtAmount": 0, - "loan": [ - { - "offerId": "14451", - "productId": "2030", - "amount": 10000, - "upfrontPayment": 1000, - "interestRate": 3, - "Interest": 300, - "ManagementRate": 1, - "ManagementFee": 100, - "InsuranceRate": 1, - "InsuranceFee": 100, - "VATRate": 7.5, - "VATamount": 100, - "recommendedRepaymentDates": ["2022-11-30"], - "installmentAmount": 11000, - "totalRepaymentAmount": 11000, - } - ], - "resultCode": "00", - "resultDescription": "Successful", - } - - return jsonify(response), 200 - - -@loan_bp.route("/provide-loan", methods=["POST"]) -def provide_loan(): - data = request.json - api_url = f"{BASE_URL}/ProvideLoan" - - # response = requests.post(api_url, json=data, headers=get_headers()) - # return jsonify(response.json()), response.status_code - response = { - "requestId": "202111170001371256908", - "transactionId": "Tr201712RK9232P115", - "customerId": "CN621868", - "accountId": "ACN8263457", - "msisdn": "3451342", - "resultCode": "00", - "resultDescription": "Successful", - } - - return jsonify(response), 200 - - -@loan_bp.route("/status", methods=["POST"]) -def status(): - data = request.json - api_url = f"{BASE_URL}/LoanStatus" - - # response = requests.post(api_url, json=data, headers=get_headers()) - # return jsonify(response.json()), response.status_code - response = { - "customerId": "CN621868", - "transactionId": "Tr201712RK9232P115", - "loans": [ - { - "debtId": "123456789", - "loanDate": "2019-10-18 14:26:21.063", - "dueDate": "2019-11-20 14:26:21.063", - "currentLoanAmount": 8500, - "initialLoanAmount": 10000, - "defaultPenaltyFee": 0, - "continuousFee": 0, - "productId": "101", - } - ], - "totalDebtAmount": 8500, - "resultCode": "00", - "resultDescription": "Successful", - } - - return jsonify(response), 200 - - -@loan_bp.route("/repayment", methods=["POST"]) -def repayment(): - data = request.json - api_url = f"{BASE_URL}/Repayment" - - # response = requests.post(api_url, json=data, headers=get_headers()) - # return jsonify(response.json()), response.status_code - response = { - "requestId": "R02802", - "countryCode": "NGR", - "transactionId": "Tr201712RK9232P115", - "debtId": "273194670", - "customerId": "CN621868", - "accountId": "2017821799", - "productId": "101", - "collectedAmount": 60000, - "penalCharge": 0, - "lienAmount": 20000, - "comment": "Testing CollectionLoanRequest", - "resultCode": "00", - "resultDescription": "Loan Collection Successful", - } - - return jsonify(response), 200 - - -# @loan_bp.route("/rac-check", methods=["POST"]) -# def rac_check(): -# data = request.json -# api_url = f"{BASE_URL}/RACCheck" -# -# # response = requests.post(api_url, json=data, headers=get_headers()) -# # return jsonify(response.json()), response.status_code -# response = { -# "transactionId": "T001", -# "customerId": "CN621868", -# "accountId": "2017821799", -# "RACResponse": { -# "Salary account": "1", -# "BVN": "1", -# "BVNAttachedToAccount": "1", -# "CRMS": "1", -# "CRC": "1", -# "AccountStatus": "1", -# "Lien": "1", -# "NoBouncedCheck": "1", -# "Whitelist": "1", -# "NoPastDueSalaryLoan": "1", -# "NoPastDueOtherLoan": "1", -# }, -# "resultDescription": "RAC Check Successful", -# } -# -# return jsonify(response), 200 -# - -@loan_bp.route("/refresh-disbursement", methods=["GET"]) -def disbursement(): - - data = request.json() - - api_url = f"{BASE_URL}/Disbursement" - - logger.info(f"Calling disbursement endpoint with data: {data}") - - return jsonify(data), 200 - # - # response = requests.post( - # api_url, - # json=data, - # headers=get_headers(), - # ) - # - # logger.info(f"Disbursement response: {response.json()}") - - # return jsonify(response.json()), response.status_code - -# @loan_bp.route("/collect-loan", methods=["POST"]) -# def collect_loan(): -# data = request.json -# api_url = f"{BASE_URL}/CollectLoan" -# -# # response = requests.post(api_url, json=data, headers=get_headers()) -# # return jsonify(response.json()), response.status_code -# response = { -# "transactionId": "T002", -# "debtId": "273194670", -# "customerId": "CN621868", -# "accountId": "2017821799", -# "productId": "101", -# "collectAmount": 60000, -# "penalCharge": 0, -# "lienAmount": 20000, -# "countryId": "01", -# "comment": "Testing CollectionLoanRequest", -# "resultCode": "00", -# "resultDescription": "Loan Collection Successful", -# } -# -# return jsonify(response), 200 - - -# @loan_bp.route("/verify-transactions", methods=["GET"]) -# def transaction_verify(): -# data = request.json -# api_url = f"{BASE_URL}/TransactionVerify" -# -# # response = requests.post(api_url, json=data, headers=get_headers()) -# # return jsonify(response.json()), response.status_code -# response = { -# "requestId": "R02802", -# "countryCode": "NGR", -# "transactionId": "Tr201712RK9232P115", -# "transactionType": "Disbursement", -# "customerId": "CN621868", -# "accountId": "2017821799", -# "providedAmount": 100, -# "collectedAmount": 7.5, -# "resultCode": "00", -# "resultDescription": "Collect Status retrieved successfully.", -# } -# -# return jsonify(response), 200 - - -# @loan_bp.route("/penal-charge", methods=["POST"]) -# def penal_charge(): -# data = request.json -# api_url = f"{BASE_URL}/PenalCharge" -# -# # response = requests.post(api_url, json=data, headers=get_headers()) -# # return jsonify(response.json()), response.status_code -# response = { -# "resultCode": "00", -# "resultDescription": "Penal charge debited successfully", -# } -# -# return jsonify(response), 200 - - -# @loan_bp.route("/lien-check", methods=["POST"]) -# def lien_check(): -# data = request.json -# api_url = f"{BASE_URL}/LienCheck" -# -# # response = requests.post(api_url, json=data, headers=get_headers()) -# # return jsonify(response.json()), response.status_code -# response = { -# "lienAmount": 20000, -# "resultCode": "00", -# "resultDescription": "Successful", -# } -# -# return jsonify(response), 200 diff --git a/docker-compose.yml b/docker-compose.yml index 33ec9ff..9189c69 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,7 +17,7 @@ services: - digital swagger: - image: swaggerapi/swagger-ui + image: swaggerapi/swagger-ui:v5.1.0 ports: - "9000:8080" volumes: diff --git a/openapi.yml b/openapi.yml index ba7ab31..8db5711 100644 --- a/openapi.yml +++ b/openapi.yml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: - title: Sample Flask API - description: A simple Flask API with Swagger documentation running in Docker + title: Event Manager API + description: The documentation for Event Manager API version: 1.0.0 contact: name: API Support @@ -97,435 +97,4 @@ paths: example: true responses: 200: - description: A successful response - /eligibility/check: - post: - summary: Performs eligibility check on a user - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - transactionId: - type: string - description: The transaction ID - example: Tr201712RK9232P115 - customerId: - type: string - description: The customer ID - example: CN621868 - countryCode: - type: string - description: The country code - example: NGR - accountId: - type: string - description: The account ID - example: ACN8263457 - msisdn: - type: string - description: The MSISDN - example: 8012345678 - channel: - type: string - description: The channel - example: 100 - responses: - 200: - description: A successful response - /loans/select-offer: - post: - summary: Selects an offer for a loan - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - requestId: - type: string - example: "202111170001371256908" - transactionId: - type: string - example: "1231231321232" - customerId: - type: string - example: "1256907" - accountId: - type: string - example: "5948306019" - msisdn: - type: string - example: "123456789" - requestedAmount: - type: integer - example: 10000 - productId: - type: string - example: "101" - channel: - type: string - example: "USSD" - responses: - 200: - description: A successful response - /loans/provide-loan: - post: - summary: Provides a loan - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - requestId: - type: string - example: "202111170001371256908" - transactionId: - type: string - example: "Tr201712RK9232P115" - customerId: - type: string - example: "CN621868" - accountId: - type: string - example: "ACN8263457" - msisdn: - type: string - example: "3451342" - productId: - type: string - example: "101" - requestedAmount: - type: integer - example: 900 - collectionType: - type: integer - example: 1 - offerId: - type: integer - example: 1127 - channel: - type: string - example: "100" - responses: - 200: - description: A successful response - /loans/status: - post: - summary: Returns the status of a loan - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - transactionId: - type: string - example: "Tr201712RK9232P115" - customerId: - type: string - example: "CN621868" - msisdn: - type: string - example: "3451342" - channel: - type: string - example: "100" - responses: - 200: - description: A successful response - /loans/repayment: - post: - summary: Repays a loan - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - requestId: - type: string - example: "R02802" - countryCode: - type: string - example: "NGR" - transactionId: - type: string - example: "Tr201712RK9232P115" - debtId: - type: string - example: "273194670" - customerId: - type: string - example: "CN621868" - accountId: - type: string - example: "2017821799" - productId: - type: string - example: "101" - collectedAmount: - type: integer - example: 80000 - penalCharge: - type: integer - example: 0 - collectionMethod: - type: integer - example: 1 - lienAmount: - type: integer - example: 80000 - comment: - type: string - example: "Testing CollectionLoanRequest" - responses: - 200: - description: A successful response - /loans/raccheck: - post: - summary: Performs RAC check on a user - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - transactionId: - type: string - example: "T001" - fbnTransactionId: - type: string - example: "Tr201712RK9232P115" - customerId: - type: string - example: "CN621868" - accountId: - type: string - example: "2017821799" - RAC_Array: - type: array - items: - type: string - example: - - "SalaryAccount" - - "BVN" - - "BVNAttachedtoAccount" - - "CRC" - - "CRMS" - - "AccountStatus" - - "Lien" - - "NoBouncedCheck" - - "Whitelist" - - "NoPastDueSalaryLoan" - - "NoPastDueOtherLoan" - responses: - 200: - description: A successful response - /loans/refresh-disbursement: - get: - summary: Refresh disburse of a loan - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - requestId: - type: string - example: "R02802" - countryCode: - type: string - example: "NGR" - transactionId: - type: string - example: "Tr201712RK9232P115" - debtId: - type: string - example: "273194670" - customerId: - type: string - example: "CN621868" - accountId: - type: string - example: "2017821799" - productId: - type: string - example: "101" - provideAmount: - type: integer - example: 100000 - totalFees: - type: integer - example: 7075 - feesDetails: - type: object - properties: - collectAmountInterest: - type: integer - example: 5000 - collectAmountMgtFee: - type: integer - example: 1000 - collectAmountInsurance: - type: integer - example: 1000 - collectAmountVAT: - type: integer - example: 75 - responses: - 200: - description: A successful response - /loans/collect-loan: - post: - summary: Collect loan from a customer - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - transactionId: - type: string - example: "T002" - fbnTransactionId: - type: string - example: "Tr201712RK9232P115" - debtId: - type: string - example: "273194670" - customerId: - type: string - example: "CN621868" - accountId: - type: string - example: "2017821799" - productId: - type: string - example: "101" - collectAmount: - type: integer - example: 80000 - penalCharge: - type: integer - example: 0 - collectionMethod: - type: integer - example: 1 - lienAmount: - type: integer - example: 80000 - countryId: - type: string - example: "01" - comment: - type: string - example: "Testing CollectionLoanRequest" - responses: - 200: - description: A successful response - /loans/verify-transactions: - get: - summary: Verify a transaction - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - requestId: - type: string - example: "R02802" - countryCode: - type: string - example: "NGR" - counter: - type: string - example: "2" - transactionId: - type: string - example: "Tr201712RK9232P115" - customerId: - type: string - example: "CN621868" - accountId: - type: string - example: "2017821799" - transactionType: - type: string - example: "Disbursement" - responses: - 200: - description: A successful response - /loans/penal-charge: - post: - summary: A penalty charge on a customer - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - transactionId: - type: string - example: "T004" - fbnTransactionId: - type: string - example: "Tr201712RK9232P115" - debtId: - type: string - example: "273194670" - customerId: - type: string - example: "CN621868" - accountId: - type: string - example: "2017821799" - penalCharge: - type: number - format: float - example: 101.2 - lienAmount: - type: number - format: float - example: 101.2 - comment: - type: string - example: "Testing PenalChargeRequest" - responses: - 200: - description: A successful response - /loans/lien-check: - post: - summary: Perform a lien check - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - transactionId: - type: string - example: "SMB1234567" - customerId: - type: string - example: "123456" - accountId: - type: string - example: "E9F77222920BAAB1C5ACF2253C6D6113" - responses: - 200: - description: A successful response + description: A successful response \ No newline at end of file