Merge branch 'bank-simbrella-calls' of DigiFi/digifi-BankToProductCore into master

This commit is contained in:
2025-03-26 01:25:17 +00:00
committed by Gogs
81 changed files with 1496 additions and 1012 deletions
+17 -5
View File
@@ -32,8 +32,10 @@ Then, open the `.env` file and add the following:
```ini ```ini
# Environment Variables # Environment Variables
VALID_API_KEY=testtest-api-key-12345 BASIC_AUTH_USERNAME=user
VALID_APP_ID=app1 BASIC_AUTH_PASSWORD=password
SWAGGER_URL="/documentation"
API_URL="/swagger.json"
``` ```
This ensures that the application uses secure API keys and app IDs. This ensures that the application uses secure API keys and app IDs.
@@ -46,14 +48,14 @@ Once you have the repository cloned, you can easily set up and run the applicati
docker-compose up --build docker-compose up --build
``` ```
This command will build the Docker image and start the Flask application in a container. By default, the application will be accessible at `http://localhost:5000`. This command will build the Docker image and start the Flask application in a container. By default, the application will be accessible at `http://localhost:4500`.
### 4. Health Check ### 4. Health Check
You can check if the Flask application is running by accessing the `/health` endpoint. To perform a health check, run the following command: You can check if the Flask application is running by accessing the `/health` endpoint. To perform a health check, run the following command:
```bash ```bash
curl http://localhost:7200/health curl http://localhost:4500/health
``` ```
If the application is running properly, you should receive a response similar to this: If the application is running properly, you should receive a response similar to this:
@@ -64,7 +66,17 @@ If the application is running properly, you should receive a response similar to
} }
``` ```
### 5. Stop the Application
### 5. Documentation
You can check the Swagger Doc by accessing the `/documentation` endpoint. Run the following command:
```bash
curl http://localhost:4500/documentation
```
### 6. Stop the Application
To stop the application, use: To stop the application, use:
+18 -5
View File
@@ -1,8 +1,10 @@
from flask import Flask from flask import Flask
import os
from flask_swagger_ui import get_swaggerui_blueprint
from flask_cors import CORS from flask_cors import CORS
from app.config import Config from app.config import Config
from app.routes import api from app.api.routes import api
from app.errors import method_not_allowed, unsupported_media_type from app.errors import register_error_handlers
def create_app(): def create_app():
""" Factory function to create a Flask app instance """ """ Factory function to create a Flask app instance """
@@ -14,11 +16,22 @@ def create_app():
CORS(app) CORS(app)
# Swagger Doc
SWAGGER_URL = app.config.get("SWAGGER_URL")
API_URL = app.config.get("API_URL")
# Register blueprints # Register blueprints
app.register_blueprint(api) app.register_blueprint(api)
# Error Handlers swagger_ui_blueprint = get_swaggerui_blueprint(SWAGGER_URL, API_URL)
app.register_error_handler(405, method_not_allowed) app.register_blueprint(swagger_ui_blueprint, url_prefix=SWAGGER_URL)
app.register_error_handler(415, unsupported_media_type)
# Error Handlers
register_error_handlers(app)
return app return app
@@ -1,3 +1,4 @@
from .verify_api_key import require_api_key from .verify_api_key import require_api_key
from .app_id_checker import require_app_id from .app_id_checker import require_app_id
from .cors import enforce_json from .cors import enforce_json
from .basic_auth import require_auth
@@ -1,10 +1,11 @@
from functools import wraps from functools import wraps
from flask import request, jsonify from flask import request, jsonify
from app.utils.logger import logger from app.utils.logger import logger
import os from app.config import Config
# Load valid App-IDs from environment variables (comma-separated list)
VALID_APP_ID = os.getenv("VALID_APP_ID", "app1,app2,app3").split(",")
VALID_APP_ID = Config.VALID_APP_ID
def require_app_id(f): def require_app_id(f):
"""Decorator to enforce App-ID validation.""" """Decorator to enforce App-ID validation."""
@@ -17,7 +18,7 @@ def require_app_id(f):
return jsonify({"message": "Invalid request parameters"}), 400 return jsonify({"message": "Invalid request parameters"}), 400
if app_id not in VALID_APP_ID: if app_id != VALID_APP_ID:
logger.error(f"Unauthorized access: Invalid App-ID {app_id}.") logger.error(f"Unauthorized access: Invalid App-ID {app_id}.")
return jsonify({"message": "Invalid request parameters"}), 400 return jsonify({"message": "Invalid request parameters"}), 400
+30
View File
@@ -0,0 +1,30 @@
from functools import wraps
from flask import request, jsonify
import base64
from app.config import Config
USERNAME = Config.BASIC_AUTH_USERNAME
PASSWORD = Config.BASIC_AUTH_PASSWORD
def require_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
auth = request.headers.get('Authorization')
if not auth or not check_auth(auth):
return jsonify({"message": "Invalid request parameters"}), 401
return f(*args, **kwargs)
return decorated
def check_auth(auth_header):
if not auth_header:
return False
try:
auth_type, credentials = auth_header.split()
if auth_type.lower() != "basic":
return False
decoded_credentials = base64.b64decode(credentials).decode("utf-8")
user, pwd = decoded_credentials.split(":", 1)
return user == USERNAME and pwd == PASSWORD
except Exception:
return False
@@ -1,10 +1,10 @@
from functools import wraps from functools import wraps
from flask import request, jsonify from flask import request, jsonify
from app.utils.logger import logger from app.utils.logger import logger
import os from app.config import Config
# Load valid API key from environment variables (fallback for testing) # Load valid API key from environment variables (fallback for testing)
VALID_API_KEY = os.getenv("VALID_API_KEY", "test-api-key-12345") VALID_API_KEY = Config.VALID_API_KEY
def require_api_key(f): def require_api_key(f):
"""Decorator to enforce API key authentication.""" """Decorator to enforce API key authentication."""
+111
View File
@@ -0,0 +1,111 @@
from flask import Blueprint, request, jsonify, send_from_directory
from app.api.services import (
EligibilityCheckService,
SelectOfferService,
ProvideLoanService,
LoanStatusService,
RepaymentService,
CustomerConsentService,
NotificationCallbackService
)
from app.utils.logger import logger
from app.api.middlewares import enforce_json, require_auth
import os
api = Blueprint("api", __name__)
@api.before_request
def cors_middleware():
"""Middleware applied globally to all API routes in this blueprint"""
return enforce_json()
# Swagger JSON file
@api.route("/swagger.json", methods=['GET'])
def swagger_json():
swagger_dir = os.path.join("swagger")
return send_from_directory(swagger_dir, "digifi_swagger.json")
@api.route('/swagger/<path:filename>')
def serve_paths(filename):
swagger_dir = os.path.join("swagger")
return send_from_directory(swagger_dir, filename)
# EligibilityCheck Endpoint
@api.route('/EligibilityCheck', methods=['POST'])
@require_auth
def eligibility_check():
data = request.get_json()
# logger.info(f"EligibilityCheck request received: {data}")
response = EligibilityCheckService.process_request(data)
return response
# SelectOffer Endpoint
@api.route('/SelectOffer', methods=['POST'])
@require_auth
def select_offer():
data = request.get_json()
# logger.info(f"SelectOffer request received: {data}")
response = SelectOfferService.process_request(data)
return response
# ProvideLoan Endpoint
@api.route('/ProvideLoan', methods=['POST'])
@require_auth
def provide_loan():
data = request.get_json()
# logger.info(f"ProvideLoan request received: {data}")
response = ProvideLoanService.process_request(data)
return response
# LoanStatus Endpoint
@api.route('/LoanStatus', methods=['POST'])
@require_auth
def loan_status():
data = request.get_json()
# logger.info(f"LoanStatus request received: {data}")
response = LoanStatusService.process_request(data)
return response
# Repayment Endpoint
@api.route('/Repayment', methods=['POST'])
@require_auth
def repayment():
data = request.get_json()
# logger.info(f"Repayment request received: {data}")
response = RepaymentService.process_request(data)
return response
# CustomerConsent Endpoint
@api.route('/CustomerConsent', methods=['POST'])
@require_auth
def customer_consent():
data = request.get_json()
# logger.info(f"CustomerConsent request received: {data}")
response = CustomerConsentService.process_request(data)
return response
# NotificationCallback Endpoint
@api.route('/NotificationCallback', methods=['POST'])
@require_auth
def notification_callback():
data = request.get_json()
# logger.info(f"NotificationCallback request received: {data}")
response = NotificationCallbackService.process_request(data)
return response
# Health Check Endpoint
@api.route('/health', methods=['GET'])
def health_check():
return {"status": "ok"} , 200
@@ -1,11 +1,10 @@
from marshmallow import Schema, fields from marshmallow import Schema, fields
class EligibilityCheckSchema(Schema): class EligibilityCheckSchema(Schema):
type = fields.Str(required=True)
transactionId = fields.Str(required=True) transactionId = fields.Str(required=True)
countryCode = fields.Str(required=True) countryCode = fields.Str(required=True)
customerId = fields.Str(required=True) customerId = fields.Str(required=True)
accountId = fields.Str(required=True) accountId = fields.Str(required=True)
msisdn = fields.Str(required=True) msisdn = fields.Str(required=True)
lienAmount = fields.Float(required=True) accountId = fields.Str(required=True)
channel = fields.Str(required=True) channel = fields.Str(required=True)
+8
View File
@@ -0,0 +1,8 @@
from marshmallow import Schema, fields
# Loan Information Schema
class LoanStatusSchema(Schema):
transactionId = fields.Str(required=True)
customerId = fields.Str(required=True)
msisdn = fields.Str(required=False)
channel = fields.Str(required=True)
@@ -2,7 +2,7 @@ from marshmallow import Schema, fields
# Provide Loan Schema # Provide Loan Schema
class ProvideLoanSchema(Schema): class ProvideLoanSchema(Schema):
type = fields.Str(required=True) type = fields.Str(required=False)
requestId = fields.Str(required=True) requestId = fields.Str(required=True)
transactionId = fields.Str(required=True) transactionId = fields.Str(required=True)
customerId = fields.Str(required=True) customerId = fields.Str(required=True)
@@ -12,5 +12,5 @@ class ProvideLoanSchema(Schema):
lienAmount = fields.Float(required=True) lienAmount = fields.Float(required=True)
requestedAmount = fields.Float(required=True) requestedAmount = fields.Float(required=True)
collectionType = fields.Int(required=True) collectionType = fields.Int(required=True)
loanType = fields.Int(required=True) offerId = fields.Int(required=True)
channel = fields.Str(required=True) channel = fields.Str(required=True)
@@ -2,7 +2,7 @@ from marshmallow import Schema, fields
# Repayment Schema # Repayment Schema
class RepaymentSchema(Schema): class RepaymentSchema(Schema):
type = fields.Str(required=True) type = fields.Str(required=False)
msisdn = fields.Str(required=False) #optional msisdn = fields.Str(required=False) #optional
debtId = fields.Str(required=True) debtId = fields.Str(required=True)
productId = fields.Str(required=True) productId = fields.Str(required=True)
+7
View File
@@ -0,0 +1,7 @@
from app.api.services.eligibility_check import EligibilityCheckService
from app.api.services.select_offer import SelectOfferService
from app.api.services.provide_loan import ProvideLoanService
from app.api.services.loan_status import LoanStatusService
from app.api.services.repayment import RepaymentService
from app.api.services.customer_consent import CustomerConsentService
from app.api.services.notification_callback import NotificationCallbackService
@@ -1,7 +1,7 @@
from flask import request, jsonify from flask import request, jsonify
from marshmallow import ValidationError from marshmallow import ValidationError
from app.utils.logger import logger from app.utils.logger import logger
from app.schemas.customer_consent import CustomerConsentSchema from app.api.schemas.customer_consent import CustomerConsentSchema
class CustomerConsentService: class CustomerConsentService:
@@ -1,7 +1,6 @@
from flask import session, jsonify from flask import session, jsonify
from app.utils.logger import logger from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper from app.api.schemas.eligibility_check import EligibilityCheckSchema
from app.schemas.eligibility_check import EligibilityCheckSchema
from marshmallow import ValidationError from marshmallow import ValidationError
class EligibilityCheckService: class EligibilityCheckService:
@@ -23,34 +22,34 @@ class EligibilityCheckService:
schema = EligibilityCheckSchema() schema = EligibilityCheckSchema()
validated_data = schema.load(data) # Raises an error if invalid validated_data = schema.load(data) # Raises an error if invalid
# Example: Validate data, perform calculations, etc. offers = [
if not data: {
return ResponseHelper.error("Invalid input data", status_code=400) "offerId": "Offer1",
"productId": "Product1",
"minAamount": 100,
"maxAamount": 1000,
"tenor": 12
},
{
"offerId": "Offer2",
"productId": "Product2",
"minAamount": 200,
"maxAamount": 2000,
"tenor": 24
}
]
# Simulate processing # Simulate processing
response_data = { response_data = {
"customerId": "CN621868", "customerId": "CN621868",
"transactionId": "Tr201712RK9232P115", "transactionId": "TX12345",
"countryCode": "NG",
"msisdn": "3451342", "msisdn": "3451342",
"eligibleOffers": [ "eligibleOffers": offers,
{ "resultDescription": "Successful",
"minamount": 5000,
"maxamount": 20000,
"productId": 101,
"offerid": 101,
"Tenor": 30
},
{
"minamount": 20000,
"maxamount": 50000,
"productId": 102,
"offerid": 102,
"Tenor": 60
}
],
"resultCode": "00", "resultCode": "00",
"resultDescription": "Successful" "accountId": "ACN8263457"
} }
# Return a success response # Return a success response
@@ -1,10 +1,9 @@
from flask import request, jsonify from flask import request, jsonify
from marshmallow import ValidationError from marshmallow import ValidationError
from app.utils.logger import logger from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper from app.api.schemas.loan_status import LoanStatusSchema
from app.schemas.loan_information import LoanInformationSchema
class LoanInformationService: class LoanStatusService:
@staticmethod @staticmethod
def process_request(data): def process_request(data):
""" """
@@ -17,27 +16,31 @@ class LoanInformationService:
dict: A standardized response. dict: A standardized response.
""" """
try: try:
logger.info("Processing LoanInformation request") logger.info("Processing LoanStatus request")
# Validate input data using the imported schema # Validate input data using the imported schema
schema = LoanInformationSchema() schema = LoanStatusSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid validated_data = schema.load(data) # Raises ValidationError if invalid
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"
}
]
# Simulated processing logic # Simulated processing logic
response_data = { response_data = {
"customerId": "CN621868", "customerId": "CN621868",
"loans": [ "transactionId": "Tr201712RK9232P115",
{ "loans": loans,
"debtId": "123456789", "totalDebtAmount": 8500,
"loanDate": "2019-10-18 14:26:21.063",
"dueDate": "2019-11-20 14:26:21.063",
"currentLoanAmount": 8500.0,
"initialLoanAmount": 10000.0,
"defaultFee": 0.0,
"continuousFee": 0.0,
"productId": "101"
}
],
"resultCode": "00", "resultCode": "00",
"resultDescription": "Successful" "resultDescription": "Successful"
} }
@@ -1,8 +1,7 @@
from flask import request, jsonify from flask import request, jsonify
from marshmallow import ValidationError from marshmallow import ValidationError
from app.utils.logger import logger from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper from app.api.schemas.notification_callback import NotificationCallbackSchema
from app.schemas.notification_callback import NotificationCallbackSchema
class NotificationCallbackService: class NotificationCallbackService:
@staticmethod @staticmethod
@@ -1,8 +1,7 @@
from flask import request, jsonify from flask import request, jsonify
from marshmallow import ValidationError from marshmallow import ValidationError
from app.utils.logger import logger from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper from app.api.schemas.provide_loan import ProvideLoanSchema
from app.schemas.provide_loan import ProvideLoanSchema
class ProvideLoanService: class ProvideLoanService:
@staticmethod @staticmethod
@@ -24,7 +23,7 @@ class ProvideLoanService:
validated_data = schema.load(data) # Raises ValidationError if invalid validated_data = schema.load(data) # Raises ValidationError if invalid
# Business logic - providing a loan # Business logic - providing a loan
response_data ={ response_data = {
"requestId": "202111170001371256908", "requestId": "202111170001371256908",
"transactionId": "Tr201712RK9232P115", "transactionId": "Tr201712RK9232P115",
"customerId": "CN621868", "customerId": "CN621868",
@@ -1,8 +1,7 @@
from flask import request, jsonify from flask import request, jsonify
from marshmallow import ValidationError from marshmallow import ValidationError
from app.utils.logger import logger from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper from app.api.schemas.repayment import RepaymentSchema
from app.schemas.repayment import RepaymentSchema
class RepaymentService: class RepaymentService:
@staticmethod @staticmethod
@@ -25,9 +24,11 @@ class RepaymentService:
# Simulated processing logic # Simulated processing logic
response_data = { response_data = {
"repayment_id": "67890", "customerId": "CN621868",
"status": "Paid", "productId": "101",
"amount": validated_data.get("amount", 0), # Example: Use validated field "debtId": "273194670",
"resultCode": "00",
"resultDescription": "Successful"
} }
# return ResponseHelper.success( # return ResponseHelper.success(
@@ -1,8 +1,7 @@
from flask import request, jsonify from flask import request, jsonify
from marshmallow import ValidationError from marshmallow import ValidationError
from app.utils.logger import logger from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper from app.api.schemas.select_offer import SelectOfferSchema
from app.schemas.select_offer import SelectOfferSchema
class SelectOfferService: class SelectOfferService:
@staticmethod @staticmethod
@@ -34,43 +33,11 @@ class SelectOfferService:
"managementFee": 1.0, "managementFee": 1.0,
"insuranceRate": 1.0, "insuranceRate": 1.0,
"insuranceFee": 100.0, "insuranceFee": 100.0,
"vatRate": 7.5, "VATRate": 7.5,
"vatAmount": 100.0, "VATAmount": 100.0,
"recommendedRepaymentDates": ["2022-11-30"], "recommendedRepaymentDates": ["2022-11-30"],
"installmentAmount": 11000.0, "installmentAmount": 11000.0,
"totalRepaymentAmount": 11000.0 "totalRepaymentAmount": 11000.0
},
{
"offerId": "16645",
"productId": "2060",
"amount": 10000.0,
"upfrontPayment": 0.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", "2023-12-30"],
"installmentAmount": 5761.9,
"totalRepaymentAmount": 11523.8
},
{
"offerId": "122212",
"productId": "2090",
"amount": 10000.0,
"upfrontPayment": 0.0,
"interestRate": 10.0,
"managementRate": 1.0,
"managementFee": 1.0,
"insuranceRate": 1.0,
"insuranceFee": 100.0,
"vatRate": 7.5,
"vatAmount": 100.0,
"recommendedRepaymentDates": ["2022-11-30", "2022-12-30", "2023-01-29"],
"installmentAmount": 4021.15,
"totalRepaymentAmount": 12063.45
} }
] ]
@@ -81,7 +48,7 @@ class SelectOfferService:
"transactionId": "1231231321232", "transactionId": "1231231321232",
"customerId": "1256907", "customerId": "1256907",
"accountId": "5948306019", "accountId": "5948306019",
"offers": offers, "loan": offers,
"resultCode": "00", "resultCode": "00",
"resultDescription": "Successful" "resultDescription": "Successful"
} }
+8 -1
View File
@@ -7,4 +7,11 @@ class Config:
# SQLALCHEMY_TRACK_MODIFICATIONS = False # SQLALCHEMY_TRACK_MODIFICATIONS = False
# SECRET_KEY = os.environ.get("SECRET_KEY", "your_secret_key") # SECRET_KEY = os.environ.get("SECRET_KEY", "your_secret_key")
DEBUG = True SWAGGER_URL = os.getenv("SWAGGER_URL", "/documentation")
API_URL = os.getenv("API_URL", "/swagger.json")
DEBUG = True
VALID_APP_ID = os.getenv("VALID_APP_ID", "app1")
VALID_API_KEY = os.getenv("VALID_API_KEY", "test-api-key-12345")
BASIC_AUTH_USERNAME = os.environ.get("BASIC_AUTH_USERNAME", "user")
BASIC_AUTH_PASSWORD = os.environ.get("BASIC_AUTH_PASSWORD", "password")
+1 -1
View File
@@ -1 +1 @@
from .handlers import method_not_allowed, unsupported_media_type from .handlers import register_error_handlers
+19 -9
View File
@@ -1,14 +1,24 @@
from werkzeug.exceptions import HTTPException
from flask import jsonify from flask import jsonify
from app.helpers.response_helper import ResponseHelper from app.api.helpers.response_helper import ResponseHelper
def method_not_allowed(error): def register_error_handlers(app):
return jsonify({"message": "Method Not Allowed"}), 405 @app.errorhandler(HTTPException)
def handle_http_exception(e):
return jsonify({'error': e.description}), e.code
@app.errorhandler(405)
def method_not_allowed(error):
return jsonify({"message": "Method Not Allowed"}), 405
def not_found(error): @app.errorhandler(404)
return jsonify({"message": "Resource not found"}), 404 def not_found(error):
return jsonify({"message": "Resource not found"}), 404
def bad_request(error): @app.errorhandler(400)
return jsonify({"message": "Bad Request"}), 400 def bad_request(error):
return jsonify({"message": "Bad Request"}), 400
def unsupported_media_type(error): @app.errorhandler(415)
return jsonify({"message": "Unsupported Media Type"}), 415 def unsupported_media_type(error):
return jsonify({"message": "Unsupported Media Type"}), 415
-211
View File
@@ -1,211 +0,0 @@
from flask import Blueprint, request, jsonify
from app.services import (
EligibilityCheckService,
SelectOfferService,
ProvideLoanService,
LoanInformationService,
RepaymentService,
CustomerConsentService,
NotificationCallbackService,
RACCheckService,
DisbursementService,
CollectLoanService,
TransactionVerifyService,
PenalChargeService,
RevokeEnableConsentService,
TokenValidationService,
LienCheckService,
NewTransactionCheckService
)
from app.utils.logger import logger
from app.middlewares import require_api_key, require_app_id, enforce_json
api = Blueprint("api", __name__)
@api.before_request
def cors_middleware():
"""Middleware applied globally to all API routes in this blueprint"""
return enforce_json()
# EligibilityCheck Endpoint
@api.route('/EligibilityCheck', methods=['POST'])
@require_api_key
@require_app_id
def eligibility_check():
data = request.get_json()
# logger.info(f"EligibilityCheck request received: {data}")
response = EligibilityCheckService.process_request(data)
return response
# SelectOffer Endpoint
@api.route('/SelectOffer', methods=['POST'])
@require_api_key
@require_app_id
def select_offer():
data = request.get_json()
# logger.info(f"SelectOffer request received: {data}")
response = SelectOfferService.process_request(data)
return response
# ProvideLoan Endpoint
@api.route('/ProvideLoan', methods=['POST'])
@require_api_key
@require_app_id
def provide_loan():
data = request.get_json()
# logger.info(f"ProvideLoan request received: {data}")
response = ProvideLoanService.process_request(data)
return response
# LoanInformation Endpoint
@api.route('/LoanInformation', methods=['GET'])
@require_api_key
@require_app_id
def loan_information():
data = request.args.to_dict()
# logger.info(f"LoanInformation request received: {data}")
response = LoanInformationService.process_request(data)
return response
# Repayment Endpoint
@api.route('/Repayment', methods=['POST'])
@require_api_key
@require_app_id
def repayment():
data = request.get_json()
# logger.info(f"Repayment request received: {data}")
response = RepaymentService.process_request(data)
return response
# CustomerConsent Endpoint
@api.route('/CustomerConsent', methods=['POST'])
@require_api_key
@require_app_id
def customer_consent():
data = request.get_json()
# logger.info(f"CustomerConsent request received: {data}")
response = CustomerConsentService.process_request(data)
return response
# NotificationCallback Endpoint
@api.route('/NotificationCallback', methods=['POST'])
@require_api_key
@require_app_id
def notification_callback():
data = request.get_json()
# logger.info(f"NotificationCallback request received: {data}")
response = NotificationCallbackService.process_request(data)
return response
# RACCheck Endpoint
@api.route('/RACCheck', methods=['POST'])
@require_api_key
@require_app_id
def rac_check():
data = request.get_json()
# logger.info(f"RACCheck request received: {data}")
response = RACCheckService.process_request(data)
return response
# Disbursement Endpoint
@api.route('/Disbursement', methods=['POST'])
@require_api_key
@require_app_id
def disbursement():
data = request.get_json()
# logger.info(f"Disbursement request received: {data}")
response = DisbursementService.process_request(data)
return response
# CollectLoan Endpoint
@api.route('/CollectLoan', methods=['POST'])
@require_api_key
@require_app_id
def collect_loan():
data = request.get_json()
# logger.info(f"CollectLoan request received: {data}")
response = CollectLoanService.process_request(data)
return response
# TransactionVerify Endpoint
@api.route('/TransactionVerify', methods=['POST'])
@require_api_key
@require_app_id
def transaction_verify():
data = request.get_json()
# logger.info(f"TransactionVerify request received: {data}")
response = TransactionVerifyService.process_request(data)
return response
# PenalCharge Endpoint
@api.route('/PenalCharge', methods=['POST'])
@require_api_key
@require_app_id
def penal_charge():
data = request.get_json()
# logger.info(f"PenalCharge request received: {data}")
response = PenalChargeService.process_request(data)
return response
# RevokeEnableConsent Endpoint
@api.route('/RevokeEnableConsent', methods=['POST'])
@require_api_key
@require_app_id
def revoke_enable_consent():
data = request.get_json()
# logger.info(f"RevokeEnableConsent request received: {data}")
response = RevokeEnableConsentService.process_request(data)
return response
# TokenValidation Endpoint
@api.route('/TokenValidation', methods=['POST'])
@require_api_key
@require_app_id
def token_validation():
data = request.get_json()
# logger.info(f"TokenValidation request received: {data}")
response = TokenValidationService.process_request(data)
return response
# LienCheck Endpoint
@api.route('/LienCheck', methods=['POST'])
@require_api_key
@require_app_id
def lien_check():
data = request.get_json()
# logger.info(f"LienCheck request received: {data}")
response = LienCheckService.process_request(data)
return response
# NewTransactionCheck Endpoint
@api.route('/NewTransactionCheck', methods=['POST'])
@require_api_key
@require_app_id
def new_transaction_check():
data = request.get_json()
# logger.info(f"NewTransactionCheck request received: {data}")
response = NewTransactionCheckService.process_request(data)
return response
# Health Check Endpoint
@api.route('/health', methods=['GET'])
def health_check():
return {"status": "ok"} , 200
-6
View File
@@ -1,6 +0,0 @@
from marshmallow import Schema, fields
from .sms import SMSSchema
# Bulk SMS Schema
class BulkSMSSchema(Schema):
requests = fields.List(fields.Nested(SMSSchema), required=True)
-16
View File
@@ -1,16 +0,0 @@
from marshmallow import Schema, fields
# Collect Loan Schema
class CollectLoanSchema(Schema):
transactionId = fields.Str(required=True)
fbnTransactionId = fields.Str(required=True)
debtId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
productId = fields.Str(required=True)
collectAmount = fields.Float(required=True)
penalCharge = fields.Float(required=False) # Optional
collectionMethod = fields.Int(required=True)
lienAmount = fields.Float(required=True)
countryId = fields.Str(required=True)
comment = fields.Str(required=False) # Optional
-18
View File
@@ -1,18 +0,0 @@
from marshmallow import Schema, fields
# Disbursement Schema
class DisbursementSchema(Schema):
requestId = fields.Str(required=True)
debtId = fields.Str(required=True)
transactionId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
productId = fields.Str(required=True)
provideAmount = fields.Float(required=True)
collectAmountInterest = fields.Float(required=False) # Optional
collectAmountMgtFee = fields.Float(required=True)
collectAmountInsurance = fields.Float(required=True)
collectAmountVAT = fields.Float(required=True)
countryId = fields.Str(required=True)
comment = fields.Str(required=False) # Optional
-8
View File
@@ -1,8 +0,0 @@
from marshmallow import Schema, fields
# Lien Check Schema
class LienCheckSchema(Schema):
transactionId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
countryId = fields.Str(required=True)
-5
View File
@@ -1,5 +0,0 @@
from marshmallow import Schema, fields
# Loan Information Schema
class LoanInformationSchema(Schema):
loan_id = fields.Str(required=True)
-12
View File
@@ -1,12 +0,0 @@
from marshmallow import Schema, fields
# New Transaction Check Schema
class NewTransactionCheckSchema(Schema):
transactionId = fields.Str(required=True)
debtId = fields.Str(required=True)
transactionType = fields.Str(required=True, metadata={
"allowed_values": ["Disbursement", "Collection", "PenalCharge"]
})
fbnTransactionId = fields.Str(required=True)
origTransactionId = fields.Str(required=True)
customerId = fields.Str(required=True)
-14
View File
@@ -1,14 +0,0 @@
from marshmallow import Schema, fields
# Penal Charge Schema
class PenalChargeSchema(Schema):
transactionId = fields.Str(required=True)
fbnTransactionId = fields.Str(required=True)
debtId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
penalCharge = fields.Decimal(required=True)
lienAmount = fields.Decimal(required=True)
countryId = fields.Str(required=True)
comment = fields.Str(required=False)
-23
View File
@@ -1,23 +0,0 @@
from marshmallow import Schema, fields
class RACItemSchema(Schema):
salaryAccount = fields.Bool(required=True)
bvn = fields.Str(required=True)
crc = fields.Bool(required=True)
crms = fields.Bool(required=True)
accountStatus = fields.Str(required=True)
lien = fields.Bool(required=True)
noBouncedCheck = fields.Bool(required=True)
existingLoan = fields.Bool(required=True)
whitelist = fields.Bool(required=True)
noPastDueSalaryLoan = fields.Bool(required=True)
noPastDueOtherLoans = fields.Bool(required=True)
# RAC Check Schema
class RACCheckSchema(Schema):
transactionId = fields.Str(required=True)
fbnTransactionId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
RAC_Array = fields.List(fields.Nested(RACItemSchema), required=True)
-13
View File
@@ -1,13 +0,0 @@
from marshmallow import Schema, fields
# Revoke Enable Consent Schema
class RevokeEnableConsentSchema(Schema):
transactionId = fields.Str(required=True)
fbnTransactionId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
processTime = fields.DateTime(required=True)
consentType = fields.Str(required=True)
countryId = fields.Str(required=True)
comment = fields.Str(required=False)
-7
View File
@@ -1,7 +0,0 @@
from marshmallow import Schema, fields
# SMS Schema
class SMSSchema(Schema):
text = fields.Str(required=True)
dest = fields.Str(required=True)
unicode = fields.Bool(required=True)
-8
View File
@@ -1,8 +0,0 @@
from marshmallow import Schema, fields
# Token Validation Schema
class TokenValidationSchema(Schema):
RequestId = fields.Str(required=True)
UserId = fields.Str(required=True)
CountryId = fields.Str(required=True)
TokenCode = fields.Str(required=True)
-12
View File
@@ -1,12 +0,0 @@
from marshmallow import Schema, fields
# Transaction Verify Schema
class TransactionVerifySchema(Schema):
counter = fields.Str(required=True)
TransactionId = fields.Str(required=True)
requestID = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
countryId = fields.Str(required=True) # Static value “01”
transactionType = fields.Str(required=True)
-16
View File
@@ -1,16 +0,0 @@
from app.services.eligibility_check import EligibilityCheckService
from app.services.select_offer import SelectOfferService
from app.services.provide_loan import ProvideLoanService
from app.services.loan_information import LoanInformationService
from app.services.repayment import RepaymentService
from app.services.customer_consent import CustomerConsentService
from app.services.notification_callback import NotificationCallbackService
from app.services.rac_check import RACCheckService
from app.services.disbursement import DisbursementService
from app.services.collect_loan import CollectLoanService
from app.services.transaction_verify import TransactionVerifyService
from app.services.penal_charge import PenalChargeService
from app.services.revoke_enable_consent import RevokeEnableConsentService
from app.services.token_validation import TokenValidationService
from app.services.lien_check import LienCheckService
from app.services.new_transaction_check import NewTransactionCheckService
-59
View File
@@ -1,59 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper
from app.schemas.collect_loan import CollectLoanSchema
class CollectLoanService:
@staticmethod
def process_request(data):
"""
Process the CollectLoan request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing CollectLoan request")
# Validate input data using CollectLoanSchema
schema = CollectLoanSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
response_data = {
"transactionId": "T002",
"debtId": "273194670",
"customerId": "CN621868",
"accountId": "2017821799",
"productId": "101",
"collectAmount": 60000.00,
"penalCharge": 0,
"lienAmount": 20000,
"countryId": "01",
"comment": "Testing CollectionLoanRequest",
"resultCode": "00",
"resultDescription": "Loan Collection Successful"
}
# return ResponseHelper.success(
# data=response_data,
# message="Loan collection completed successfully"
# )
return jsonify(response_data), 200
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
-62
View File
@@ -1,62 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper
from app.schemas.disbursement import DisbursementSchema
class DisbursementService:
@staticmethod
def process_request(data):
"""
Process the Disbursement request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing Disbursement request")
# Validate input data using DisbursementSchema
schema = DisbursementSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
response_data = {
"transactionId": "T001",
"TransactionId": "Tr201712RK9232P115",
"debtId": "273194670",
"customerId": "CN621868",
"accountId": "2017821799",
"productId": "101",
"provideAmount": 100000.0,
"collectAmountInterest": 5000,
"collectAmountMgtFee": 1000,
"collectAmountInsurance": 1000,
"collectAmountVAT": 75,
"countryId": "01",
"resultCode": "00",
"resultDescription": "Loan Request Completed Successfully!"
}
# return ResponseHelper.success(
# data=response_data,
# message="Disbursement completed successfully"
# )
return response_data
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
-51
View File
@@ -1,51 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper
from app.schemas.lien_check import LienCheckSchema
class LienCheckService:
@staticmethod
def process_request(data):
"""
Process the LienCheck request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing LienCheck request")
# Validate input data using LienCheckSchema
schema = LienCheckSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated lien check logic
response_data = {
"lienAmount": 20000.0,
"resultCode": "00",
"resultDescription": "Successful"
}
# return ResponseHelper.success(
# data=response_data,
# message="Lien check completed successfully"
# )
return response_data
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
-58
View File
@@ -1,58 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper
from app.schemas.new_transaction_check import NewTransactionCheckSchema
class NewTransactionCheckService:
@staticmethod
def process_request(data):
"""
Process the NewTransactionCheck request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing NewTransactionCheck request")
# Validate input data using NewTransactionCheckSchema
schema = NewTransactionCheckSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated transaction check logic
response_data = {
"transactionId": "24110114545374721",
"data": {
"transactionId": "241101",
"providedAmount": 1000.00,
"collectedAmount": 0.00,
"resultCode": "00",
"resultDescription": "Loan Provision is successful"
},
"resultCode": "00",
"resultDescription": "SUCCESS"
}
# return ResponseHelper.success(
# data=response_data,
# message="New transaction check completed successfully"
# )
return response_data
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
-51
View File
@@ -1,51 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper
from app.schemas.penal_charge import PenalChargeSchema
class PenalChargeService:
@staticmethod
def process_request(data):
"""
Process the PenalCharge request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing PenalCharge request")
# Validate input data using PenalChargeSchema
schema = PenalChargeSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
response_data = {
"resultCode": "00",
"resultDescription": "Penal charge debited successfully"
}
# return ResponseHelper.success(
# data=response_data,
# message="Penal charge applied successfully"
# )
return response_data
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
-63
View File
@@ -1,63 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper
from app.schemas.rac_check import RACCheckSchema
class RACCheckService:
@staticmethod
def process_request(data):
"""
Process the RACCheck request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing RACCheck request")
# Validate input data using RACCheckSchema
schema = RACCheckSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
response_data = {
"resultCode": "00",
"RACResponse": {
"SalaryAccount": "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 ResponseHelper.success(
# data=response_data,
# message="RAC check completed successfully"
# )
return response_data
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
-54
View File
@@ -1,54 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper
from app.schemas.revoke_enable_consent import RevokeEnableConsentSchema
class RevokeEnableConsentService:
@staticmethod
def process_request(data):
"""
Process the RevokeEnableConsent request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing RevokeEnableConsent request")
# Validate input data using RevokeEnableConsentSchema
schema = RevokeEnableConsentSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
response_data = {
"type": "RevokeEnableConsentResponse",
"customerId": "CN621868",
"accountId": "2017821799",
"resultCode": "00",
"resultDescription": "Success"
}
# return ResponseHelper.success(
# data=response_data,
# message="Consent revocation processed successfully"
# )
return response_data
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
-54
View File
@@ -1,54 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper
from app.schemas.token_validation import TokenValidationSchema
class TokenValidationService:
@staticmethod
def process_request(data):
"""
Process the TokenValidation request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing TokenValidation request")
# Validate input data using TokenValidationSchema
schema = TokenValidationSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated token validation logic
response_data = {
"Authenticated": True,
"AuthenticatedMessage": "The user Oluwole Olusoga has successfully authenticated!",
"ResponseCode": "00",
"ResponseMessage": "Successful",
"RequestId": "SMB1234567"
}
# return ResponseHelper.success(
# data=response_data,
# message="Token validation completed successfully"
# )
return response_data
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
-57
View File
@@ -1,57 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.helpers.response_helper import ResponseHelper
from app.schemas.transaction_verify import TransactionVerifySchema
class TransactionVerifyService:
@staticmethod
def process_request(data):
"""
Process the TransactionVerify request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing TransactionVerify request")
# Validate input data using TransactionVerifySchema
schema = TransactionVerifySchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
response_data = {
"type": "TransactionCheckResponse",
"nativeId": "FBN20191031104405CN621868",
"customerId": "CN621868",
"accountId": "2017821799",
"providedAmount": 0.0,
"collectedAmount": 7.50,
"resultCode": "00",
"resultDescription": "Collect Status retrieved successfully."
}
# return ResponseHelper.success(
# data=response_data,
# message="Transaction verification completed successfully"
# )
return response_data
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
View File
View File
+156
View File
@@ -0,0 +1,156 @@
{
"openapi": "3.0.3",
"info": {
"title": "Swagger Simbrella FirstAdvance - OpenAPI 3.0",
"description": "This is a Simbrella FirstAdvance Backend Server with the OpenAPI 3.0 specification. \n\n\nSome useful links:\n- [Web Simulated Demo Page](https://digifi-salaryloan.chiefsoft.net/)\n- [Web Management Support Portal](https://digifi-office.chiefsoft.net/auth/login)",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"email": "support@chiefsoft.com"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "1.0.11"
},
"servers": [
{
"url": "http://localhost:4500"
}
],
"tags": [
{
"name": "EligibilityCheck",
"description": "Eligibility Check Request",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "SelectOffer",
"description": "This method is used the send the offer the customer selected to Simbrella.",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "ProvideLoan",
"description": "Provide Loan Request.",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "LoanStatus",
"description": "Loan Information Request.",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "Repayment",
"description": "Repayment Request.",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "CustomerConsent",
"description": "CustomerConsent Request.",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "NotificationCallback",
"description": "This new feature will be used for informing Simbrella about status of the transactions that FBN have processed.",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
}
],
"paths": {
"/EligibilityCheck": {
"$ref": "swagger/paths/EligibilityCheck.json"
},
"/SelectOffer": {
"$ref": "swagger/paths/SelectOffer.json"
},
"/ProvideLoan": {
"$ref": "swagger/paths/ProvideLoan.json"
},
"/LoanStatus": {
"$ref": "swagger/paths/LoanStatus.json"
},
"/Repayment": {
"$ref": "swagger/paths/Repayment.json"
},
"/CustomerConsent": {
"$ref": "swagger/paths/CustomerConsent.json"
},
"/NotificationCallback": {
"$ref": "swagger/paths/NotificationCallback.json"
}
},
"components": {
"schemas": {
"EligibilityCheckRequest": {
"$ref": "swagger/schemas/EligibilityCheckRequest.json"
},
"EligibilityCheckResponse": {
"$ref": "swagger/schemas/EligibilityCheckResponse.json"
},
"SelectOfferRequest": {
"$ref": "swagger/schemas/SelectOfferRequest.json"
},
"SelectOfferResponse": {
"$ref": "swagger/schemas/SelectOfferResponse.json"
},
"LoanStatusRequest": {
"$ref": "swagger/schemas/LoanStatusRequest.json"
},
"LoanStatusResponse": {
"$ref": "swagger/schemas/LoanStatusResponse.json"
},
"RepaymentRequest": {
"$ref": "swagger/schemas/RepaymentRequest.json"
},
"RepaymentResponse": {
"$ref": "swagger/schemas/RepaymentResponse.json"
},
"CustomerConsentRequest": {
"$ref": "swagger/schemas/CustomerConsentRequest.json"
},
"CustomerConsentResponse": {
"$ref": "swagger/schemas/CustomerConsentResponse.json"
},
"NotificationCallbackRequest": {
"$ref": "swagger/schemas/NotificationCallbackRequest.json"
},
"NotificationCallbackResponse": {
"$ref": "swagger/schemas/NotificationCallbackResponse.json"
},
"ApiResponse": {
"$ref": "swagger/schemas/ApiResponse.json"
}
},
"securitySchemes": {
"basicAuth": {
"type": "http",
"scheme": "basic"
}
}
},
"security": [
{
"basicAuth": []
}
]
}
+56
View File
@@ -0,0 +1,56 @@
{
"post": {
"tags": [
"CustomerConsent"
],
"summary": "Customer Consent Request",
"description": "Customer Consent Request",
"operationId": "CustomerConsent",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/CustomerConsentRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/CustomerConsentRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/CustomerConsentRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "Successful",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/CustomerConsentResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/CustomerConsentResponse.json"
}
}
}
},
"400": {
"description": "Invalid request parameters"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
}
}
+57
View File
@@ -0,0 +1,57 @@
{
"post": {
"tags": [
"EligibilityCheck"
],
"summary": "Start the process - initiate steps to eligibility RAC Checks ",
"description": "Initiate Eligibility Check Request",
"operationId": "startEligibilityCheck",
"requestBody": {
"description": "Post JSON to conduct eligibility tests",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/EligibilityCheckRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/EligibilityCheckRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/EligibilityCheckRequest.json"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/EligibilityCheckResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/EligibilityCheckResponse.json"
}
}
}
},
"400": {
"description": "Invalid request parameters"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
}
}
+57
View File
@@ -0,0 +1,57 @@
{
"post": {
"tags": [
"LoanStatus"
],
"summary": "Loan Information Request ",
"description": "Loan Information Request",
"operationId": "LoanStatus",
"requestBody": {
"description": "Post JSON to conduct eligibility tests",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/LoanStatusRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/LoanStatusRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/LoanStatusRequest.json"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/LoanStatusResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/LoanStatusResponse.json"
}
}
}
},
"400": {
"description": "Invalid request parameters"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
}
}
@@ -0,0 +1,57 @@
{
"post": {
"tags": [
"NotificationCallback"
],
"summary": "Loan Information Request ",
"description": "Loan Information Request",
"operationId": "NotificationCallback",
"requestBody": {
"description": "Post JSON to conduct eligibility tests",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/NotificationCallbackRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/NotificationCallbackRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/NotificationCallbackRequest.json"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/NotificationCallbackResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/NotificationCallbackResponse.json"
}
}
}
},
"400": {
"description": "Invalid request parameters"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
}
}
+57
View File
@@ -0,0 +1,57 @@
{
"post": {
"tags": [
"ProvideLoan"
],
"summary": "Provide Loan Request ",
"description": "Provide Loan Request",
"operationId": "ProvideLoan",
"requestBody": {
"description": "Post JSON to conduct eligibility tests",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/ProvideLoanRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/ProvideLoanRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/ProvideLoanRequest.json"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/ProvideLoanResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/ProvideLoanResponse.json"
}
}
}
},
"400": {
"description": "Invalid request parameters"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
}
}
+56
View File
@@ -0,0 +1,56 @@
{
"post": {
"tags": [
"Repayment"
],
"summary": "Repayment Request",
"description": "Repayment Request",
"operationId": "Repayment",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/RepaymentRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/RepaymentRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/RepaymentRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "Repayment Successful",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/RepaymentResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/RepaymentResponse.json"
}
}
}
},
"400": {
"description": "Invalid request parameters"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
}
}
+57
View File
@@ -0,0 +1,57 @@
{
"post": {
"tags": [
"SelectOffer"
],
"summary": "This method is used the send the offer the customer selected to Simbrella ",
"description": "This method is used the send the offer the customer selected to Simbrella",
"operationId": "SelectOffer",
"requestBody": {
"description": "Post JSON to conduct eligibility tests",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/SelectOfferRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/SelectOfferRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/SelectOfferRequest.json"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/SelectOfferResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/SelectOfferResponse.json"
}
}
}
},
"400": {
"description": "Invalid request parameters"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
}
}
+18
View File
@@ -0,0 +1,18 @@
{
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"type": {
"type": "string"
},
"message": {
"type": "string"
}
},
"xml": {
"name": "##default"
}
}
@@ -0,0 +1,37 @@
{
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "CustomerConsentRequest"
},
"transactionId": {
"type": "string",
"example": "20171209232177"
},
"customerId": {
"type": "string",
"example": "CN621868"
},
"accountId": {
"type": "string",
"example": "ACN8263457"
},
"requestTime": {
"type": "string",
"format": "date-time",
"example": "2019-10-18 14:26:21.063"
},
"consentType": {
"type": "string",
"example": "Revoke"
},
"channel": {
"type": "string",
"example": "USSD"
}
},
"xml": {
"name": "CustomerConsentRequest"
}
}
@@ -0,0 +1,16 @@
{
"type": "object",
"properties": {
"resultCode": {
"type": "string",
"example": "00"
},
"resultDescription": {
"type": "string",
"example": "Request is received"
}
},
"xml": {
"name": "CustomerConsentResponse"
}
}
@@ -0,0 +1,32 @@
{
"type": "object",
"properties": {
"transactionId": {
"type": "string",
"example": "Tr201712RK9232P115"
},
"countryCode": {
"type": "string",
"example": "NGR"
},
"customerId": {
"type": "string",
"example": "CN621868"
},
"msisdn": {
"type": "string",
"example": "8093451342"
},
"channel": {
"type": "string",
"example": "100"
},
"accountId": {
"type": "string",
"example": "ACN8263457"
}
},
"xml": {
"name": "EligibilityCheckRequest"
}
}
@@ -0,0 +1,82 @@
{
"type": "object",
"properties": {
"customerId": {
"type": "string",
"example": "CN621868"
},
"transactionId": {
"type": "string",
"example": "TX12345"
},
"countryCode": {
"type": "string",
"example": "NG"
},
"msisdn": {
"type": "string",
"example": "3451342"
},
"eligibleOffers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"offerId": {
"type": "string",
"example": "Offer1"
},
"productId": {
"type": "string",
"example": "Product1"
},
"minAamount": {
"type": "number",
"format": "decimal",
"example": 100.00
},
"maxAamount": {
"type": "number",
"format": "decimal",
"example": 1000.00
},
"tenor": {
"type": "integer",
"example": 12
}
}
},
"example": [
{
"offerId": "Offer1",
"productId": "Product1",
"minAamount": 100.00,
"maxAamount": 1000.00,
"tenor": 12
},
{
"offerId": "Offer2",
"productId": "Product2",
"minAamount": 200.00,
"maxAamount": 2000.00,
"tenor": 24
}
]
},
"resultDescription": {
"type": "string",
"example": "Successful"
},
"resultCode": {
"type": "string",
"example": "00"
},
"accountId": {
"type": "string",
"example": "ACN8263457"
}
},
"xml": {
"name": "EligibilityCheckResponse"
}
}
@@ -0,0 +1,24 @@
{
"type": "object",
"properties": {
"transactionId": {
"type": "string",
"example": "Tr201712RK9232P115"
},
"customerId": {
"type": "string",
"example": "CN621868"
},
"msisdn": {
"type": "string",
"example": "3451342"
},
"channel": {
"type": "string",
"example": "USSD"
}
},
"xml": {
"name": "LoanStatusRequest"
}
}
@@ -0,0 +1,70 @@
{
"type": "object",
"properties": {
"customerId": {
"type": "string",
"example": "CN621868"
},
"transactionId": {
"type": "string",
"example": "Tr201712RK9232P115"
},
"loans": {
"type": "array",
"items": {
"type": "object",
"properties": {
"debtId": {
"type": "string",
"example": "123456789"
},
"loanDate": {
"type": "string",
"format": "date-time",
"example": "2019-10-18 14:26:21.063"
},
"dueDate": {
"type": "string",
"format": "date-time",
"example": "2019-11-20 14:26:21.063"
},
"currentLoanAmount": {
"type": "integer",
"example": 8500
},
"initialLoanAmount": {
"type": "integer",
"example": 10000
},
"defaultPenaltyFee": {
"type": "integer",
"example": 0
},
"continuousFee": {
"type": "integer",
"example": 0
},
"productId": {
"type": "string",
"example": "101"
}
}
}
},
"totalDebtAmount": {
"type": "integer",
"example": 8500
},
"resultCode": {
"type": "string",
"example": "00"
},
"resultDescription": {
"type": "string",
"example": "Successful"
}
},
"xml": {
"name": "LoanStatusResponse"
}
}
@@ -0,0 +1,50 @@
{
"type": "object",
"properties": {
"fbnTransactionId": {
"type": "string",
"example": "123456789"
},
"transactionId": {
"type": "string",
"example": "123456789"
},
"customerId": {
"type": "string",
"example": "CN621868"
},
"accountId": {
"type": "string",
"example": "ACN8263457"
},
"debtId": {
"type": "string",
"example": "987654321"
},
"transactionType": {
"type": "string",
"example": "Disbursement"
},
"amountProvided": {
"type": "number",
"format": "float",
"example": 1000.00
},
"amountCollected": {
"type": "number",
"format": "float",
"example": 0.00
},
"responseCode": {
"type": "string",
"example": "00"
},
"responseDescription": {
"type": "string",
"example": "Successful"
}
},
"xml": {
"name": "NotificationCallbackRequest"
}
}
@@ -0,0 +1,16 @@
{
"type": "object",
"properties": {
"resultCode": {
"type": "string",
"example": "00"
},
"resultDescription": {
"type": "string",
"example": "Successful"
}
},
"xml": {
"name": "NotificationCallbackResponse"
}
}
@@ -0,0 +1,58 @@
{
"type": "object",
"properties": {
"type": {
"type": "string",
"example": "ProvideLoanRequest"
},
"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"
},
"lienAmount": {
"type": "number",
"format": "decimal",
"example": 400
},
"requestedAmount": {
"type": "number",
"format": "decimal",
"example": 900
},
"collectionType": {
"type": "integer",
"example": 1
},
"offerId": {
"type": "integer",
"example": 1127
},
"channel": {
"type": "string",
"example": "100"
}
},
"xml": {
"name": "ProvideLoanRequest"
}
}
@@ -0,0 +1,36 @@
{
"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"
},
"resultCode": {
"type": "string",
"example": "00"
},
"resultDescription": {
"type": "string",
"example": "Successful"
}
},
"xml": {
"name": "ProvideLoanResponse"
}
}
+32
View File
@@ -0,0 +1,32 @@
{
"type": "object",
"properties": {
"msisdn": {
"type": "string",
"example": "3451342"
},
"debtId": {
"type": "string",
"example": "273194670"
},
"productId": {
"type": "string",
"example": "101"
},
"transactionId": {
"type": "string",
"example": "20171209232115"
},
"customerId": {
"type": "string",
"example": "CN621868"
},
"channel": {
"type": "string",
"example": "USSD"
}
},
"xml": {
"name": "RepaymentRequest"
}
}
@@ -0,0 +1,28 @@
{
"type": "object",
"properties": {
"customerId": {
"type": "string",
"example": "CN621868"
},
"productId": {
"type": "string",
"example": "101"
},
"debtId": {
"type": "string",
"example": "273194670"
},
"resultCode": {
"type": "string",
"example": "00"
},
"resultDescription": {
"type": "string",
"example": "Successful"
}
},
"xml": {
"name": "RepaymentResponse"
}
}
@@ -0,0 +1,41 @@
{
"type": "object",
"properties": {
"requestId": {
"type": "string",
"example": "202111170001371256908"
},
"transactionId": {
"type": "string",
"example": "1231231321232"
},
"customerId": {
"type": "string",
"example": "CN621868"
},
"msisdn": {
"type": "string",
"example": "123456789"
},
"requestedAmount": {
"type": "number",
"format": "double",
"example": 10000.55
},
"accountId": {
"type": "string",
"example": "ACN8263457"
},
"productId": {
"type": "string",
"example": "101"
},
"channel": {
"type": "string",
"example": ""
}
},
"xml": {
"name": "SelectOffersRequest"
}
}
@@ -0,0 +1,112 @@
{
"type": "object",
"properties": {
"requestId": {
"type": "string",
"example": "202111170001371256908"
},
"transactionId": {
"type": "string",
"example": "1231231321232"
},
"customerId": {
"type": "string",
"example": "1256907"
},
"accountId": {
"type": "string",
"example": "5948306019"
},
"loan": {
"type": "array",
"items": {
"type": "object",
"properties": {
"offerId": {
"type": "string",
"example": "14451"
},
"productId": {
"type": "string",
"example": "2030"
},
"amount": {
"type": "number",
"format": "float",
"example": 10000.0
},
"upfrontPayment": {
"type": "number",
"format": "float",
"example": 1000.0
},
"interestRate": {
"type": "number",
"format": "float",
"example": 3.0
},
"ManagementRate": {
"type": "number",
"format": "float",
"example": 1.0
},
"ManagementFee": {
"type": "number",
"format": "float",
"example": 1.0
},
"InsuranceRate": {
"type": "number",
"format": "float",
"example": 1.0
},
"InsuranceFee": {
"type": "number",
"format": "float",
"example": 100.0
},
"VATRate": {
"type": "number",
"format": "float",
"example": 7.5
},
"VATamount": {
"type": "number",
"format": "float",
"example": 100.0
},
"recommendedRepaymentDates": {
"type": "array",
"items": {
"type": "string"
},
"example": [
"2022-11-30"
]
},
"installmentAmount": {
"type": "number",
"format": "float",
"example": 11000.0
},
"totalRepaymentAmount": {
"type": "number",
"format": "float",
"example": 11000.0
}
}
}
},
"resultCode": {
"type": "string",
"example": "00"
},
"resultDescription": {
"type": "string",
"example": "Successful"
}
},
"xml": {
"name": "SelectOffersResponse"
}
}
-11
View File
@@ -1,11 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
</head>
<body>
</body>
</html>
+1 -1
View File
@@ -2,7 +2,7 @@ services:
digifi-flaska002: digifi-flaska002:
build: . build: .
ports: ports:
- "7200:5000" - "4500:5000"
environment: environment:
- FLASK_APP=app.py - FLASK_APP=app.py
- FLASK_RUN_HOST=0.0.0.0 - FLASK_RUN_HOST=0.0.0.0
+1
View File
@@ -4,6 +4,7 @@ Flask-Marshmallow==0.15.0
marshmallow==3.19.0 marshmallow==3.19.0
Flask-Cors==3.0.10 Flask-Cors==3.0.10
gunicorn gunicorn
flask-swagger-ui