10 Commits

Author SHA1 Message Date
Azeez Muibi a66fea65ee simulator 2025-05-06 11:11:34 +01:00
Azeez Muibi a5ef85d331 simulator 2025-05-06 10:55:52 +01:00
Azeez Muibi b6250230c9 simulator 2025-05-06 10:45:53 +01:00
Azeez Muibi b6d233564a simulator 2025-04-04 03:44:15 +01:00
Azeez Muibi 71a5e78f5d Updated Jmeter 2025-04-02 15:19:16 +01:00
Azeez Muibi dce58babc2 Major update 2025-03-27 08:25:50 +01:00
Azeez Muibi ba4d878daf Major update 2025-03-27 08:21:20 +01:00
Azeez Muibi 1a36416094 Updated Select Offer 2025-03-26 15:15:16 +01:00
Azeez Muibi f52de3d8f8 Updated Disbursement 2025-03-26 15:05:52 +01:00
Azeez Muibi 183c1bf46f Updated Docs 2025-03-26 14:48:32 +01:00
144 changed files with 6420 additions and 4559 deletions
Vendored
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -2,7 +2,7 @@
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.13" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13" project-jdk-type="Python SDK" />
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
-1
View File
@@ -1 +0,0 @@
https://first-advance-middleware-develop.fbn-devops-dev-asenv.appserviceenvironment.net/swagger/v1/swagger.json
-1916
View File
File diff suppressed because it is too large Load Diff
-18
View File
@@ -1,18 +0,0 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
flask = "==2.3.3"
flask-marshmallow = "==0.15.0"
marshmallow = "==3.19.0"
flask-cors = "==3.0.10"
gunicorn = "*"
flask-swagger-ui = "*"
python-dotenv = "*"
[dev-packages]
[requires]
python_version = "3.13"
Generated
-213
View File
@@ -1,213 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "4729a28392b881795159ff885c9db5ee8ce14e84697fd7343f4999f53cfbac22"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.13"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"blinker": {
"hashes": [
"sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf",
"sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc"
],
"markers": "python_version >= '3.9'",
"version": "==1.9.0"
},
"click": {
"hashes": [
"sha256:6b303f0b2aa85f1cb4e5303078fadcbcd4e476f114fab9b5007005711839325c",
"sha256:f5452aeddd9988eefa20f90f05ab66f17fce1ee2a36907fd30b05bbb5953814d"
],
"markers": "python_version >= '3.10'",
"version": "==8.2.0"
},
"colorama": {
"hashes": [
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'",
"version": "==0.4.6"
},
"flask": {
"hashes": [
"sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc",
"sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b"
],
"index": "pypi",
"markers": "python_version >= '3.8'",
"version": "==2.3.3"
},
"flask-cors": {
"hashes": [
"sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438",
"sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"
],
"index": "pypi",
"version": "==3.0.10"
},
"flask-marshmallow": {
"hashes": [
"sha256:2083ae55bebb5142fff98c6bbd483a2f5dbc531a8bc1be2180ed5f75e7f3fccc",
"sha256:ce08a153f74da6ebfffd8065d1687508b0179df37fff7fc0c8f28ccfb64f1b56"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
"version": "==0.15.0"
},
"flask-swagger-ui": {
"hashes": [
"sha256:5ecff6c284d7c5559f3473bd534a31fa5dfc0022502d63f4a04728c2b10596f6",
"sha256:872d038dc11a68eacab88f6f05be3c533aa300453e273775dad3e029b31e03d4"
],
"index": "pypi",
"version": "==5.21.0"
},
"gunicorn": {
"hashes": [
"sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d",
"sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
"version": "==23.0.0"
},
"itsdangerous": {
"hashes": [
"sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef",
"sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"
],
"markers": "python_version >= '3.8'",
"version": "==2.2.0"
},
"jinja2": {
"hashes": [
"sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d",
"sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"
],
"markers": "python_version >= '3.7'",
"version": "==3.1.6"
},
"markupsafe": {
"hashes": [
"sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4",
"sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30",
"sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0",
"sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9",
"sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396",
"sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13",
"sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028",
"sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca",
"sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557",
"sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832",
"sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0",
"sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b",
"sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579",
"sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a",
"sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c",
"sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff",
"sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c",
"sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22",
"sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094",
"sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb",
"sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e",
"sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5",
"sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a",
"sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d",
"sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a",
"sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b",
"sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8",
"sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225",
"sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c",
"sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144",
"sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f",
"sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87",
"sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d",
"sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93",
"sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf",
"sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158",
"sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84",
"sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb",
"sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48",
"sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171",
"sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c",
"sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6",
"sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd",
"sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d",
"sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1",
"sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d",
"sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca",
"sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a",
"sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29",
"sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe",
"sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798",
"sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c",
"sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8",
"sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f",
"sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f",
"sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a",
"sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178",
"sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0",
"sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79",
"sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430",
"sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"
],
"markers": "python_version >= '3.9'",
"version": "==3.0.2"
},
"marshmallow": {
"hashes": [
"sha256:90032c0fd650ce94b6ec6dc8dfeb0e3ff50c144586462c389b81a07205bedb78",
"sha256:93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b"
],
"index": "pypi",
"markers": "python_version >= '3.7'",
"version": "==3.19.0"
},
"packaging": {
"hashes": [
"sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484",
"sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"
],
"markers": "python_version >= '3.8'",
"version": "==25.0"
},
"python-dotenv": {
"hashes": [
"sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5",
"sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==1.1.0"
},
"six": {
"hashes": [
"sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
"sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'",
"version": "==1.17.0"
},
"werkzeug": {
"hashes": [
"sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e",
"sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"
],
"markers": "python_version >= '3.9'",
"version": "==3.1.3"
}
},
"develop": {}
}
+3 -6
View File
@@ -45,7 +45,7 @@ This ensures that the application uses secure API keys and app IDs.
Once you have the repository cloned, you can easily set up and run the application using Docker Compose. Simply execute the following command:
```bash
docker-compose up -d --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:6337`.
@@ -55,8 +55,7 @@ This command will build the Docker image and start the Flask application in a co
You can check if the Flask application is running by accessing the `/health` endpoint. To perform a health check, run the following command:
```bash
curl http://localhost:6337/api/health
curl http://localhost:6337/eco/health
curl http://localhost:6337/health
```
If the application is running properly, you should receive a response similar to this:
@@ -72,9 +71,7 @@ If the application is running properly, you should receive a response similar to
You can check the Swagger Doc by accessing the `/documentation` endpoint. Run the following command:
```bash
curl http://localhost:6337/api/documentation
curl http://localhost:6337/eco/documentation
curl http://localhost:6337/documentation
```
+11 -29
View File
@@ -1,18 +1,10 @@
from re import S
from flask import Flask
import os
from flask_swagger_ui import get_swaggerui_blueprint
from flask_cors import CORS
from app.config import Config
from app.api.routes import api
from app.eco.routes import eco
from app.errors import register_error_handlers
from flask_jwt_extended import (
JWTManager,
jwt_required,
create_access_token,
get_jwt_identity,
)
def create_app():
""" Factory function to create a Flask app instance """
@@ -21,35 +13,25 @@ def create_app():
# Load configuration
app.config.from_object(Config)
CORS(app)
JWTManager(app)
CORS(app, supports_credentials=True)
CORS(app)
# Swagger Doc
SWAGGER_URL = app.config.get("SWAGGER_URL")
API_URL = app.config.get("API_URL")
# Register blueprints with /api prefix for the main API routes
app.register_blueprint(api, url_prefix="/api")
app.register_blueprint(eco, url_prefix="/eco")
# Swagger UI Blueprint
api_docs = "/api" + SWAGGER_URL
api_url = "/api" + API_URL
swagger_ui_api = get_swaggerui_blueprint(api_docs, api_url)
swagger_ui_api.name = 'swagger_ui_api' # Rename blueprint
app.register_blueprint(swagger_ui_api, url_prefix=api_docs)
# Second UI (ECO)
eco_docs = "/eco" + SWAGGER_URL
eco_api = "/eco" + API_URL
swagger_ui_eco = get_swaggerui_blueprint(eco_docs, eco_api)
swagger_ui_eco.name = 'swagger_ui_eco' # Rename blueprint
app.register_blueprint(swagger_ui_eco, url_prefix=eco_docs)
# Register blueprints
app.register_blueprint(api)
swagger_ui_blueprint = get_swaggerui_blueprint(SWAGGER_URL, API_URL)
app.register_blueprint(swagger_ui_blueprint, url_prefix=SWAGGER_URL)
# Error Handlers
register_error_handlers(app)
return app
+1 -1
View File
@@ -11,7 +11,7 @@ def require_api_key(f):
@wraps(f)
def decorated_function(*args, **kwargs):
api_key = request.headers.get("X-API-KEY")
logger.info(f"Received API key: {api_key}")
if not api_key:
logger.error("Unauthorized access: Missing API key.")
+78 -109
View File
@@ -1,5 +1,4 @@
from flask import Flask, Blueprint, request, jsonify, send_from_directory
import sys
from flask import Flask, Blueprint, request, jsonify, send_from_directory
import os
from app.api.services import (
RACCheckService,
@@ -7,15 +6,16 @@ from app.api.services import (
CollectLoanService,
TransactionVerifyService,
PenalChargeService,
RevokeEnableConsentService,
TokenValidationService,
LienCheckService,
NewTransactionCheckService,
RepaymentService,
StatusCallService,
LoanStatusService,
SMSService,
BulkSMSService,
CompleteRACcheckService
)
from app.utils.logger import logger
from app.api.middlewares import require_api_key, require_app_id, enforce_json
from app.api.middlewares import require_api_key, require_app_id, enforce_json
api = Blueprint("api", __name__)
@@ -35,113 +35,79 @@ def swagger_json():
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)
# RACCheck Endpoint
@api.route('/rac-check', methods=['POST'])
@api.route('/RACCheck', methods=['POST'])
@require_api_key
@require_app_id
def rac_check():
try:
data = request.get_json()
response = RACCheckService.process_request(data)
return response
except Exception as e:
logger.exception("Unhandled exception in /RACCheck route")
return jsonify({"message": "Unhandled server error"}), 500
data = request.get_json()
# logger.info(f"RACCheck request received: {data}")
response = RACCheckService.process_request(data)
return response
# CompleteRACcheck Endpoint
@api.route('/CompleteRACcheck', methods=['POST'])
@require_api_key
@require_app_id
def complete_rac_check():
try:
data = request.get_json()
response = CompleteRACcheckService.process_request(data)
return response
except Exception as e:
logger.exception("Unhandled exception in /CompleteRACcheck route")
return jsonify({"message": "Unhandled server error"}), 500
data = request.get_json()
# logger.info(f"CompleteRACcheck request received: {data}")
response = CompleteRACcheckService.process_request(data)
return response
# Disbursement Endpoint
@api.route('/DisburseLoan', methods=['POST'])
@api.route('/Disbursement', methods=['POST'])
@require_api_key
@require_app_id
def disbursement():
try:
data = request.get_json()
# logger.info(f"Disbursement request received: {data}")
response = DisbursementService.process_request(data)
return response
except Exception as e:
logger.exception("Unhandled exception in /Disbursement route")
return jsonify({"message": "Unhandled server error"}), 500
data = request.get_json()
# logger.info(f"Disbursement request received: {data}")
response = DisbursementService.process_request(data)
return response
# LoanStatus Endpoint
@api.route('/LoanStatus', methods=['POST'])
@require_api_key
@require_app_id
def loan_status():
data = request.get_json()
# logger.info(f"LoanStatus request received: {data}")
response = LoanStatusService.process_request(data)
return response
# CollectLoan Endpoint
@api.route('/CollectLoan', methods=['POST'])
@require_api_key
@require_app_id
def collect_loan():
try:
data = request.get_json()
# logger.info(f"CollectLoan request received: {data}")
response = CollectLoanService.process_request(data)
return response
except Exception as e:
logger.exception("Unhandled exception in /CollectLoan route")
return jsonify({"message": "Unhandled server error"}), 500
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():
try:
data = request.get_json()
# logger.info(f"TransactionVerify request received: {data}")
response = TransactionVerifyService.process_request(data)
return response
except Exception as e:
logger.exception("Unhandled exception in /TransactionVerify route")
return jsonify({"message": "Unhandled server error"}), 500
data = request.get_json()
# logger.info(f"TransactionVerify request received: {data}")
response = TransactionVerifyService.process_request(data)
return response
# PenalCharge Endpoint
@api.route('/CollectPenalFee', methods=['POST'])
@api.route('/PenalCharge', methods=['POST'])
@require_api_key
@require_app_id
def penal_charge():
try:
data = request.get_json()
# logger.info(f"PenalCharge request received: {data}")
response = PenalChargeService.process_request(data)
return response
except Exception as e:
logger.exception("Unhandled exception in /PenalCharge route")
return jsonify({"message": "Unhandled server error"}), 500
# 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)
# logger.info(f"PenalCharge request received: {data}")
response = PenalChargeService.process_request(data)
return response
# LienCheck Endpoint
@@ -154,44 +120,47 @@ def lien_check():
response = LienCheckService.process_request(data)
return response
# NewTransactionCheck Endpoint
@api.route('/NewTransactionCheck', methods=['POST'])
# Repayment Endpoint - Added based on updated Repayment.json
@api.route('/Repayment', methods=['POST'])
@require_api_key
@require_app_id
def new_transaction_check():
def repayment():
data = request.get_json()
# logger.info(f"NewTransactionCheck request received: {data}")
response = NewTransactionCheckService.process_request(data)
# logger.info(f"Repayment request received: {data}")
response = RepaymentService.process_request(data)
return response
# StatusCall Endpoint - Added based on updated StatusCall.json
@api.route('/StatusCall', methods=['POST'])
@require_api_key
@require_app_id
def status_call():
data = request.get_json()
# logger.info(f"StatusCall request received: {data}")
response = StatusCallService.process_request(data)
return response
# SMS Endpoint - Added based on Swagger JSON
@api.route('/SMS', methods=['POST'])
@require_api_key
@require_app_id
def sms():
data = request.get_json()
# logger.info(f"SMS request received: {data}")
response = SMSService.process_request(data)
return response
# BulkSMS Endpoint - Added based on Swagger JSON
@api.route('/BulkSMS', methods=['POST'])
@require_api_key
@require_app_id
def bulk_sms():
data = request.get_json()
# logger.info(f"BulkSMS request received: {data}")
response = BulkSMSService.process_request(data)
return response
# Health Check Endpoint
@api.route('/system-health-check', methods=['GET'])
@api.route('/health', methods=['GET'])
def health_check():
"""Basic system health check"""
try:
checks = {
"python_version": sys.version_info >= (3, 6),
"disk_space": os.statvfs('/').f_bavail * os.statvfs('/').f_frsize > 500 * 1024 * 1024,
"system_operational": True
}
if all(checks.values()):
return jsonify({
"status": "Active",
"responseCode": "00",
"responseMessage": "Successful"
}), 200
else:
return jsonify({
"status": "Degraded",
"responseCode": "01",
"responseMessage": "System check failed"
}), 200
except Exception as e:
return jsonify({
"status": "Error",
"responseCode": "99",
"responseMessage": f"Health check failed: {str(e)}"
}), 500
return {"status": "ok"}, 200
+18
View File
@@ -0,0 +1,18 @@
from marshmallow import Schema, fields
# Individual SMS item schema for BulkSMS
class BulkSMSItemSchema(Schema):
text = fields.Str(required=True, description="Message to send to customer")
dest = fields.Str(required=True, description="Phone Number in international format")
unicode = fields.Bool(required=True, description="Character encoding standard (set as True for bulk SMS)")
# BulkSMS Request Schema (list of SMS items)
class BulkSMSSchema(Schema):
_schema = fields.List(fields.Nested(BulkSMSItemSchema), required=True)
# BulkSMS Response Schema
class BulkSMSResponseSchema(Schema):
data = fields.Str(required=True, description="Any additional data in response")
statusCode = fields.Int(required=True, description="Result code of executed process (200 = Success)")
IsSuccessful = fields.Bool(required=True, description="An Indicator that the process was successful or not")
errorMessage = fields.Str(required=True, allow_none=True, description="Description of status code if process is failed, null if successful")
+28 -26
View File
@@ -1,30 +1,32 @@
from marshmallow import Schema, fields
from marshmallow import Schema, fields, validate
# CollectLoan Request Schema
class CollectLoanSchema(Schema):
channel = fields.Str(allow_none=True)
transactionId = fields.Str(allow_none=True)
fbnTransactionId = fields.Str(allow_none=True)
debtId = fields.Str(allow_none=True)
accountId = fields.Str(allow_none=True)
customerId = fields.Str(allow_none=True)
productId = fields.Str(allow_none=True)
collectAmount = fields.Float(required=True)
penalCharge = fields.Float(required=True)
collectionMethod = fields.Str(allow_none=True)
lienAmount = fields.Float(required=True)
countryId = fields.Str(allow_none=True)
comment = fields.Str(allow_none=True)
transactionId = fields.Str(required=True, description="Unique identifier of transaction in Simbrella system")
fbnTransactionId = fields.Str(required=True, description="Unique id of the transaction received from FBN in Eligibility or Provision requests")
debtId = fields.Str(required=True, description="Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
productId = fields.Str(required=True, description="Identifier of a product for which collection to be made")
collectAmount = fields.Float(required=True, description="Amount to be collected from user's account (penalCharge is not included)")
penalCharge = fields.Float(required=False, description="Amount of penalty to be collected from user's account. If there is no penalty, amount is '0'")
collectionMethod = fields.Int(required=True, description="1 - on deposit of salary; 2 - on due date; 3 - initiated by user",
validate=validate.OneOf([1, 2, 3]))
lienAmount = fields.Float(required=True, description="Aggregated (summed up) lien amount")
countryId = fields.Str(required=True, description="Set to static value '01'")
comment = fields.Str(required=False, description="Any additional comment for provided loan operation")
# CollectLoan Response Schema
class CollectLoanResponseSchema(Schema):
responseCode = fields.Str(allow_none=True)
responseDescr = fields.Str(allow_none=True)
fullDescription = fields.Str(allow_none=True)
transactionId = fields.Str(allow_none=True)
debtId = fields.Str(allow_none=True)
customerId = fields.Str(allow_none=True)
accountId = fields.Str(allow_none=True)
productId = fields.Str(allow_none=True)
amountCollected = fields.Float(required=True)
countryId = fields.Str(allow_none=True)
comment = fields.Str(allow_none=True)
responseMessage = fields.Str(allow_none=True)
transactionId = fields.Str(required=True, description="Unique identifier of transaction in Simbrella system")
debtId = fields.Str(required=True, description="Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
productId = fields.Str(required=True, description="Identifier of a product for which collection to be made")
collectAmount = fields.Float(required=True, description="Amount collected from user's account (penalCharge is not included)")
penalCharge = fields.Float(required=True, description="Amount of penalty collected from user's account. If there is no penalty, amount is '0'")
lienAmount = fields.Float(required=True, description="Aggregated (summed up) lien amount")
countryId = fields.Str(required=False, description="Set to static value '01'")
comment = fields.Str(required=False, description="Any additional comment for provided loan operation")
resultCode = fields.Str(required=True, description="Result code of executed transaction, e.g. (00 Success etc.) see result codes table")
resultDescription = fields.Str(required=True, description="Description of provided result code")
-1
View File
@@ -3,7 +3,6 @@ from marshmallow import Schema, fields, validate
# CompleteRACcheck Request Schema
class CompleteRACcheckSchema(Schema):
transactionId = fields.Str(required=True, description="Unique identifier of transaction. This transaction Id must be consistent across all platforms")
fbnTransactionId = fields.Str(required=True, description="Unique identifier of transaction in FBN system")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
RAC_Array = fields.Dict(required=True, description="Risk Acceptance Criteria array")
+35 -40
View File
@@ -1,43 +1,38 @@
from marshmallow import Schema, fields
from marshmallow import Schema, fields, validate
# Schema for the fees details object
class FeesDetailsSchema(Schema):
collectAmountInterest = fields.Float(required=True, description="Interest Amount to be collected immediately after loan is provided (Only for 30 days)")
collectAmountMgtFee = fields.Float(required=True, description="Management Fee Amount to be collected immediately after loan is provided")
collectAmountInsurance = fields.Float(required=True, description="Insurance Amount to be collected immediately after loan is provided")
collectAmountVAT = fields.Float(required=True, description="VAT Amount to be collected immediately after loan is provided")
# Disbursement Request Schema
class DisbursementSchema(Schema):
transactionId = fields.Str(required=False, allow_none=True)
FbnTransactionId = fields.Str(required=False, allow_none=True)
debtId = fields.Str(required=False, allow_none=True)
customerId = fields.Str(required=False, allow_none=True)
accountId = fields.Str(required=False, allow_none=True)
productId = fields.Str(required=False, allow_none=True)
provideAmount = fields.Float(required=True)
collectAmountInterest = fields.Float(required=True)
collectAmountMgtFee = fields.Float(required=True)
collectAmountInsurance = fields.Float(required=True)
collectAmountVAT = fields.Float(required=True)
countryId = fields.Str(required=False, allow_none=True)
comment = fields.Str(required=False, allow_none=True)
requestId = fields.Str(required=True, description="Unique identifier of request")
countryCode = fields.Str(required=True, description="Unique country code. Please refer to Country Codes table")
transactionId = fields.Str(required=True, description="Unique identifier of transaction in Simbrella system")
debtId = fields.Str(required=True, description="Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
productId = fields.Str(required=True, description="Identifier of a product to be provided to a user")
provideAmount = fields.Float(required=True, description="Amount of loan (including service fee) to be provided on a specific account of a user")
totalFees = fields.Float(required=True, description="Total amount of all fees combined")
feesDetails = fields.Nested(FeesDetailsSchema, required=True, description="Detailed breakdown of all fees")
countryId = fields.Str(required=True, description="Set to static value '01'")
comment = fields.Str(required=False, description="Any additional comment for provided loan operation")
class DisburseLoanResponseSchema(Schema):
transactionId = fields.Str(allow_none=True)
fbnTransactionId = fields.Str(allow_none=True)
debtId = fields.Str(allow_none=True)
customerId = fields.Str(allow_none=True)
accountId = fields.Str(allow_none=True)
productId = fields.Str(allow_none=True)
provideAmount = fields.Float(required=True)
collectAmountInterest = fields.Float(required=True)
collectAmountMgtFee = fields.Float(required=True)
collectAmountInsurance = fields.Float(required=True)
collectAmountVAT = fields.Float(required=True)
countryId = fields.Str(allow_none=True)
responseCode = fields.Str(allow_none=True)
responseMessage = fields.Str(allow_none=True)
disburseMessage = fields.Str(allow_none=True)
disburseDate = fields.Str(allow_none=True)
disburseVerify = fields.Str(allow_none=True)
disburseDescription = fields.Str(allow_none=True)
verifyResult = fields.Str(allow_none=True)
verifyDescription = fields.Str(allow_none=True)
# Disbursement Response Schema
class DisbursementResponseSchema(Schema):
requestId = fields.Str(required=True, description="Unique identifier of request")
countryCode = fields.Str(required=True, description="Unique country code.")
transactionId = fields.Str(required=True, description="Unique ID of customer's USSD session. Must be consistent throughout whole USSD journey")
debtId = fields.Str(required=True, description="Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
productId = fields.Str(required=True, description="Identifier of a product to be provided to a user")
provideAmount = fields.Float(required=True, description="Amount of loan (including service fee) to be provided on a specific account of a user")
totalFees = fields.Float(required=True, description="Total amount of all fees combined")
feesDetails = fields.Nested(FeesDetailsSchema, required=True, description="Detailed breakdown of all fees")
resultCode = fields.Str(required=True, description="Result code of executed transaction, e.g. (00 Success etc.) see result codes table")
resultDescription = fields.Str(required=True, description="Description of provided result code")
+10 -5
View File
@@ -1,8 +1,13 @@
from marshmallow import Schema, fields
# Lien Check Schema
# LienCheck Request Schema
class LienCheckSchema(Schema):
transactionId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
countryId = fields.Str(required=True)
transactionId = fields.Str(required=True, description="Unique Identifier in Simbrella system")
customerId = fields.Str(required=True, description="Unique identifier of customer")
accountId = fields.Str(required=True, description="Unique identifier of account")
# LienCheck Response Schema
class LienCheckResponseSchema(Schema):
lienAmount = fields.Float(required=True, description="Lien amount applied to the account")
resultCode = fields.Str(required=True, description="Result code of response")
resultDescription = fields.Str(required=True, description="Response description")
+29
View File
@@ -0,0 +1,29 @@
from marshmallow import Schema, fields, validate
# Schema for the loan item in the response
class LoanItemSchema(Schema):
debtId = fields.Str(required=True, description="Unique identifier of a debt of a user")
loanDate = fields.Str(required=True, description="Date and time of provided loan")
dueDate = fields.Str(required=True, description="Due date of provided loan")
currentLoanAmount = fields.Float(required=True, description="Outstanding debt amount of the user")
initialLoanAmount = fields.Float(required=True, description="Initial loan amount")
defaultPenaltyFee = fields.Float(required=True, description="Penalty fee amount")
continuousFee = fields.Float(required=True, description="Interest fee charged continuously. First occurs when payment is delayed")
productId = fields.Str(required=True, description="Identifier of a provided product to a user")
# LoanStatus Request Schema
class LoanStatusSchema(Schema):
transactionId = fields.Str(required=True, description="Unique identifier of transaction. This transaction Id must be consistent across all platforms")
customerId = fields.Str(required=True, description="Unique identifier of a customer")
msisdn = fields.Str(required=False, description="User's mobile number in an international format")
channel = fields.Str(required=True, description="Request channel: USSD, MobileApp, or Web",
validate=validate.OneOf(["USSD", "MobileApp", "Web", "100", "101", "102", "103"])) # Added numeric channel codes
# LoanStatus Response Schema
class LoanStatusResponseSchema(Schema):
customerId = fields.Str(required=True, description="Unique identifier of a user")
transactionId = fields.Str(required=True, description="Unique identifier of transaction. This transaction Id must be consistent across all platforms")
loans = fields.List(fields.Nested(LoanItemSchema), required=True, description="Array of loan entities. If customer doesn't have a loan, this array will be empty")
totalDebtAmount = fields.Float(required=False, description="Sum amount of all existing debts of a user")
resultCode = fields.Str(required=True, description="Result code of executed transaction, e.g. (00 Success etc.) see result codes table")
resultDescription = fields.Str(required=True, description="Description of provided result code")
+13 -21
View File
@@ -1,25 +1,17 @@
from marshmallow import Schema, fields
# This file contains the schema for penal charge operations
# PenalCharge Request Schema
class PenalChargeSchema(Schema):
channel = fields.Str(allow_none=True)
transactionId = fields.Str(allow_none=True)
fbnTransactionId = fields.Str(allow_none=True)
debtId = fields.Str(allow_none=True)
accountId = fields.Str(allow_none=True)
penalCharge = fields.Float(required=True)
customerId = fields.Str(allow_none=True)
lienAmount = fields.Float(required=True)
comment = fields.Str(allow_none=True)
countryId = fields.Str(allow_none=True)
transactionId = fields.Str(required=True, description="Unique identifier of transaction in Simbrella system")
fbnTransactionId = fields.Str(required=True, description="Unique id of the transaction received from FBN in Eligibility or Provision requests")
debtId = fields.Str(required=True, description="Unique identifier of providing loan in Simbrella system")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
penalCharge = fields.Float(required=True, description="Penalty amount that needs to be collected from user's account")
lienAmount = fields.Float(required=True, description="Aggregated (summed up) lien amount")
comment = fields.Str(required=False, description="Any additional comment for provided loan operation")
#represents the response schema for penal charge
class CollectPenalFeeResponseSchema(Schema):
customerId = fields.Str(allow_none=True)
transactionId = fields.Str(allow_none=True)
amountCollected = fields.Float(required=True)
accountId = fields.Str(allow_none=True)
responseCode = fields.Str(allow_none=True)
responseMessage = fields.Str(allow_none=True)
# PenalCharge Response Schema
class PenalChargeResponseSchema(Schema):
resultCode = fields.Str(required=True, description="Result code of executed transaction, e.g. (00 Success etc.) see result codes table")
resultDescription = fields.Str(required=True, description="Description of provided result code")
+26
View File
@@ -0,0 +1,26 @@
from marshmallow import Schema, fields, validate
# ProvideLoan Request Schema
class ProvideLoanSchema(Schema):
requestId = fields.Str(required=False, description="Unique identifier of request")
transactionId = fields.Str(required=True, description="Unique identifier of transaction. This transaction Id must be consistent across all platforms")
customerId = fields.Str(required=True, description="Unique identifier of a customer")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
msisdn = fields.Str(required=False, description="User's mobile number in an international format")
productId = fields.Str(required=True, description="Identifier of a product chosen by user")
requestedAmount = fields.Float(required=True, description="Amount of loan that requested by user")
collectionType = fields.Int(required=True, description="Type of collection that user is preferred. 0 as soon as salary inflow occurs; 1- as soon as any new inflow occurs, 1 collection after XX days.",
validate=validate.OneOf([0, 1]))
offerId = fields.Int(required=True, description="Offer ID of the loan selected by Customer")
channel = fields.Str(required=True, description="Request channel: 'USSD' or 'MobileApp' or 'Web' - Reference Channel types",
validate=validate.OneOf(["USSD", "MobileApp", "Web", "100", "101", "102", "103"])) # Added numeric channel codes
# ProvideLoan Response Schema
class ProvideLoanResponseSchema(Schema):
requestId = fields.Str(required=True, description="Unique identifier of request")
transactionId = fields.Str(required=True, description="Unique identifier of transaction. This transaction Id must be consistent across all platforms")
customerId = fields.Str(required=True, description="Unique identifier of a customer")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
msisdn = fields.Str(required=False, description="User's mobile number in an international format")
resultCode = fields.Str(required=True, description="Result code of executed transaction, e.g. (00 Success etc.) see result codes table")
resultDescription = fields.Str(required=True, description="Description of provided result code")
+26 -51
View File
@@ -1,57 +1,32 @@
from marshmallow import Schema, fields
from marshmallow import Schema, fields
from datetime import date
# RACResponse Schema
class RACResponseSchema(Schema):
Salary_account = fields.Str(data_key="Salary account", required=True, description="Has Salary account or Not (1 = Yes, 0 = No)")
BVN = fields.Str(required=False, description="BVN Ok (1 = Yes, 0 = No)")
BVNAttachedToAccount = fields.Str(required=True, description="BVN attached to account (1 = Yes, 0 = No)")
CRMS = fields.Str(required=True, description="No Delinquent loan in CRMS (1 = Yes, 0 = No)")
CRC = fields.Str(required=True, description="No Delinquent loan in CRC (1 = Yes, 0 = No)")
AccountStatus = fields.Str(required=True, description="Has 'Regular' account status (1 = Yes, 0 = No)")
Lien = fields.Str(required=True, description="No Lien on account (1 = Yes, 0 = No)")
NoBouncedCheck = fields.Str(required=True, description="No Bounced Check (1 = Yes, 0 = No)")
Whitelist = fields.Str(required=True, description="Not blacklisted (1 = Yes, 0 = No)")
NoPastDueSalaryLoan = fields.Str(required=True, description="No Past Due Salary Loan (1 = Yes, 0 = No)")
NoPastDueOtherLoan = fields.Str(required=True, description="No Past Due Other Loans (1 = Yes, 0 = No)")
class RACItemSchema(Schema):
PROCESS_DATE = fields.Date(required=True, default=date.today)
CIF_ID = fields.Str(required=True)
CUSTOMER_id = fields.Str(required=True)
SALACCT_1 = fields.Str(required=True)
ALERT_PHONE = fields.Str(required=True)
AVERAGE_SALARY = fields.Decimal(required=True, as_string=True)
LOAN_OUSTANDING_BAL = fields.Decimal(required=True, as_string=True)
EMI = fields.Decimal(required=True, as_string=True)
ELIG_AMT = fields.Decimal(required=True, as_string=True)
rule1_45day_sal = fields.Bool(required=True)
rule2_2m_sal = fields.Bool(required=True)
rule3_no_bounced_check = fields.Bool(required=True)
rule4_current_loan_payments = fields.Bool(required=True)
rule5_no_past_due_fadv_loan = fields.Bool(required=True)
rule6_no_past_due_other_loan = fields.Bool(required=True)
rule7_consistent_salary_amount = fields.Bool(required=True)
rule8_whitelisted = fields.Bool(required=True)
rule9_regular_account = fields.Bool(required=True)
rule10_bvn_validation = fields.Bool(required=True)
rule11_CRC_no_delinquency = fields.Bool(required=True)
rule12_CRMS_no_delinquency = fields.Bool(required=True)
rule13_BVN_ignore = fields.Bool(required=True)
rule14_no_lien = fields.Bool(required=True)
rule15_null_ignore = fields.Bool(required=True)
OVERALL_ELIG = fields.Bool(required=True)
SALARYPAYMENT_1 = fields.Decimal(required=True, as_string=True)
SALARYPAYMENT_2 = fields.Decimal(required=True, as_string=True)
SALARYPAYMENT_3 = fields.Decimal(required=True, as_string=True)
SALARYPAYMENT_4 = fields.Decimal(required=True, as_string=True)
SALARYPAYMENT_5 = fields.Decimal(required=True, as_string=True)
SALARYPAYMENT_6 = fields.Decimal(required=True, as_string=True)
# RAC Check Schema
# RACCheck Request Schema
class RACCheckSchema(Schema):
transactionId = fields.Str(required=True)
fbnTransactionId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
channel = fields.Str(required=True)
countryCode = fields.Str(required=True)
transactionId = fields.Str(required=True, description="Unique identifier of transaction. This transaction Id must be consistent across all platforms")
fbnTransactionId = fields.Str(required=True, description="Unique id of the transaction received from FBN in Eligibility or Provision requests")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
RAC_Array = fields.List(fields.Str(), required=True, description="Array of RAC items to check (BVN, CRC, CRMS, Salary account, lien, whitelist, lien, account status, no bounced check and existing loan)")
# RACCheck Response Schema
class RACCheckResponseSchema(Schema):
transactionId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
racResponse = fields.Nested(RACItemSchema, required=True)
transactionId = fields.Str(required=True, description="Unique identifier of transaction in Simbrella system")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
RACResponse = fields.Nested(RACResponseSchema, required=True, description="Object containing binary responses for each RAC check")
resultCode = fields.Str(required=False, description="Result code of executed transaction")
resultDescription = fields.Str(required=True, description="Description of provided result code")
+33
View File
@@ -0,0 +1,33 @@
from marshmallow import Schema, fields, validate
# Repayment Request Schema
class RepaymentSchema(Schema):
requestId = fields.Str(required=True, description="Unique identifier of request")
countryCode = fields.Str(required=True, description="Unique country code. Please refer to Country Codes table")
transactionId = fields.Str(required=True, description="Unique identifier of transaction in Simbrella system")
debtId = fields.Str(required=True, description="Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
productId = fields.Str(required=True, description="Identifier of a product for which collection to be made")
collectedAmount = fields.Float(required=True, description="Amount to be collected from user's account (penalCharge is not included)")
penalCharge = fields.Float(required=False, description="Amount of penalty to be collected from user's account. If there is no penalty, amount is '0'")
collectionMethod = fields.Int(required=True, description="1 - on deposit of salary, 2 - on due date, 3 - initiated by user",
validate=validate.OneOf([1, 2, 3]))
lienAmount = fields.Float(required=True, description="Aggregated (summed up) lien amount")
comment = fields.Str(required=False, description="Any additional comment for provided loan operation")
# Repayment Response Schema
class RepaymentResponseSchema(Schema):
requestId = fields.Str(required=True, description="Unique identifier of request")
countryCode = fields.Str(required=True, description="Unique country code. Please refer to Country Codes table")
transactionId = fields.Str(required=True, description="Unique identifier of transaction in Simbrella system")
debtId = fields.Str(required=True, description="Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
productId = fields.Str(required=True, description="Identifier of a product for which collection to be made")
collectedAmount = fields.Float(required=True, description="Amount to be collected from user's account (penalCharge is not included)")
penalCharge = fields.Float(required=False, description="Amount of penalty to be collected from user's account. If there is no penalty, amount is '0'")
lienAmount = fields.Float(required=True, description="Aggregated (summed up) lien amount")
comment = fields.Str(required=False, description="Any additional comment for provided loan operation")
resultCode = fields.Str(required=True, description="Result code of executed transaction, e.g. (00 Success etc.) see result codes table")
resultDescription = fields.Str(required=True, description="Description of provided result code")
+42
View File
@@ -0,0 +1,42 @@
from marshmallow import Schema, fields, validate
# Schema for the loan item in the response
class LoanItemSchema(Schema):
offerId = fields.Str(required=True, description="Unique identifier of the offer")
productId = fields.Str(required=True, description="Product identifier")
amount = fields.Float(required=True, description="Amount of loan customer is eligible for")
upfrontPayment = fields.Float(required=True, description="Amount to be deducted upfront")
interestRate = fields.Float(required=True, description="Percentage (%) of interest rate")
Interest = fields.Float(required=True, description="Amount of interest")
ManagementRate = fields.Float(required=True, description="Percentage (%) of management fee")
ManagementFee = fields.Float(required=True, description="Amount of management fee")
InsuranceRate = fields.Float(required=True, description="Percentage (%) of insurance")
InsuranceFee = fields.Float(required=True, description="Amount of insurance")
VATRate = fields.Float(required=True, description="Percentage (%) of VAT")
VATamount = fields.Float(required=True, description="Amount of VAT")
recommendedRepaymentDates = fields.List(fields.Str(), required=True, description="Array of recommended payment dates for all installments in yyyy-mm-dd format")
installmentAmount = fields.Float(required=True, description="Amount to be paid each month (upfrontPayment not included)")
totalRepaymentAmount = fields.Float(required=True, description="Total amount to be paid by customer. All installment amounts + upfront payment")
# SelectOffer Request Schema
class SelectOfferSchema(Schema):
requestId = fields.Str(required=True, description="Unique identifier of request")
transactionId = fields.Str(required=True, description="Unique identifier of transaction. This transaction Id must be consistent across all platforms")
customerId = fields.Str(required=True, description="Unique identifier of a customer")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
msisdn = fields.Str(required=True, description="User's mobile number in an international format")
requestedAmount = fields.Float(required=True, description="Amount of loan requested by user")
productId = fields.Str(required=True, description="Product ID")
channel = fields.Str(required=True, description="Channel of incoming request",
validate=validate.OneOf(["USSD", "FistMobile LitApp", "Web"]))
# SelectOffer Response Schema
class SelectOfferResponseSchema(Schema):
requestId = fields.Str(required=True, description="Unique identifier of request")
transactionId = fields.Str(required=True, description="Unique identifier of transaction. This transaction Id must be consistent across all platform")
customerId = fields.Str(required=True, description="Unique identifier of a customer")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
outstandingDebtAmount = fields.Float(required=False, description="Outstanding debt amount if any")
loan = fields.List(fields.Nested(LoanItemSchema), required=True, description="Array of loan offers")
resultCode = fields.Str(required=True, description="Result code of executed transaction, e.g. (00 Success etc.) see result codes table")
resultDescription = fields.Str(required=True, description="Description of provided result code")
+14
View File
@@ -0,0 +1,14 @@
from marshmallow import Schema, fields
# SMS Request Schema
class SMSSchema(Schema):
text = fields.Str(required=True, description="Message to send to customer")
dest = fields.Str(required=True, description="Phone Number in international format")
unicode = fields.Bool(required=True, description="Character encoding standard (set as False for single SMS)")
# SMS Response Schema
class SMSResponseSchema(Schema):
data = fields.Str(required=True, description="Any additional data in response")
statusCode = fields.Int(required=True, description="Result code of executed process (200 = Success)")
IsSuccessful = fields.Bool(required=True, description="An Indicator that the process was successful or not")
errorMessage = fields.Str(required=True, allow_none=True, description="Description of status code if process is failed, null if successful")
+27
View File
@@ -0,0 +1,27 @@
from marshmallow import Schema, fields, validate
# Nested data schema for StatusCallResponse
class StatusCallDataSchema(Schema):
transactionId = fields.Str(required=True, description="Unique identifier of transaction in Simbrella system that was sent for transaction check")
providedAmount = fields.Float(required=True, description="Amount collected from user's account within disbursement operation. Amount should always be equal to zero if operation is of any type other than Disbursement")
collectedAmount = fields.Float(required=True, description="Amount collected from user's account. In case of Disbursement this value will be equal to 0. In case of Collection this value will represent amount successfully collected from customers account. In case of Penal charge this value will represent penalty amount collected from customer's account.")
resultCode = fields.Str(required=True, description="Result code of the operation one sent for transaction check, e.g. (00 Success etc.)")
resultDescription = fields.Str(required=True, description="Description of provided result code that was sent for transaction check")
# StatusCall Request Schema
class StatusCallSchema(Schema):
requestId = fields.Str(required=True, description="RequestId for transaction sent by Simbrella within initial request to Firstbank API")
countryCode = fields.Str(required=True, description="Unique country code.")
transactionId = fields.Str(required=True, description="Unique identifier of transaction. This transaction Id must be consistent across all platforms")
debtId = fields.Str(required=True, description="Unique identifier of provided loan in Simbrella system")
transactionType = fields.Str(required=True,
description="Type of Transaction Simbrella is sending Transaction Check for",
validate=validate.OneOf(["Disbursement", "Collection", "PenalCharge"]))
customerId = fields.Str(required=True, description="Unique identifier of a user")
# StatusCall Response Schema
class StatusCallResponseSchema(Schema):
transactionId = fields.Str(required=True, description="Unique identifier of request in Simbrella system")
data = fields.Nested(StatusCallDataSchema, required=True, description="Object containing details of transaction Simbrella querying")
resultCode = fields.Str(required=True, description="Result code of executed transaction, e.g. (00 Success etc.)")
resultDescription = fields.Str(required=True, description="Description of provided result code")
+23 -21
View File
@@ -1,25 +1,27 @@
from marshmallow import Schema, fields
from marshmallow import Schema, fields, validate
# TransactionVerify Request Schema
class TransactionVerifySchema(Schema):
channel = fields.Str(allow_none=True)
accountId = fields.Str(allow_none=True)
customerId = fields.Str(allow_none=True)
transactionId = fields.Str(allow_none=True)
transactionType = fields.Str(allow_none=True)
countryId = fields.Str(allow_none=True)
requestId = fields.Str(allow_none=True)
requestId = fields.Str(required=True, description="Unique identifier of request")
countryCode = fields.Str(required=True, description="Unique country code. Please refer to Country Codes table")
counter = fields.Str(required=True, description="Unique counter for number of attempts of the API call. Original attempt is 1")
transactionId = fields.Str(required=True, description="Id of the transaction we are checking")
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
transactionType = fields.Str(required=True,
description="To check state of loan disbursal transaction, value must be 'Disbursement', to check state of loan collection transaction, value must be 'Collection', to check state of penalty charge transaction, value must be 'Penalty'",
validate=validate.OneOf(["Disbursement", "Collection", "Penalty"]))
# TransactionVerify Response Schema
class TransactionVerifyResponseSchema(Schema):
responseCode = fields.Str(allow_none=True)
responseDescr = fields.Str(allow_none=True)
fullDescription = fields.Str(allow_none=True)
customerId = fields.Str(allow_none=True)
accountId = fields.Str(allow_none=True)
providedAmount = fields.Float(required=True)
collectedAmount = fields.Float(required=True)
transactionId = fields.Str(allow_none=True)
transactionType = fields.Str(allow_none=True)
disburseVerify = fields.Str(allow_none=True)
verifyDescription = fields.Str(allow_none=True)
verifyResult = fields.Str(allow_none=True)
requestId = fields.Str(required=True, description="Unique identifier of request")
countryCode = fields.Str(required=True, description="Unique country code. Please refer to Country Codes table")
transactionId = fields.Str(required=True, description="Unique identifier of transaction in Simbrella system")
transactionType = fields.Str(required=True, description="Type of transaction: Disbursement, Collection, or Penalty",
validate=validate.OneOf(["Disbursement", "Collection", "Penalty"]))
customerId = fields.Str(required=True, description="Unique identifier of a user")
accountId = fields.Str(required=True, description="Specific identifier of a user's account")
providedAmount = fields.Float(required=True, description="Amount provided to a user within loan provision operation")
collectedAmount = fields.Float(required=True, description="Amount collected from user's account within collection operation")
resultCode = fields.Str(required=True, description="Result code of executed transaction, e.g. (00 Success etc.) see result codes table")
resultDescription = fields.Str(required=True, description="Description of provided result code")
+9 -5
View File
@@ -1,10 +1,14 @@
from app.api.services.rac_check import RACCheckService
from app.api.services.disbursement import DisbursementService
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.collect_loan import CollectLoanService
from app.api.services.rac_check import RACCheckService
from app.api.services.transaction_verify import TransactionVerifyService
from app.api.services.penal_charge import PenalChargeService
from app.api.services.revoke_enable_consent import RevokeEnableConsentService
from app.api.services.token_validation import TokenValidationService
from app.api.services.lien_check import LienCheckService
from app.api.services.new_transaction_check import NewTransactionCheckService
from app.api.services.complete_rac_check_service import CompleteRACcheckService
from app.api.services.status_call import StatusCallService
from app.api.services.sms import SMSService
from app.api.services.bulk_sms import BulkSMSService
from app.api.services.complete_rac_check_service import CompleteRACcheckService
+78
View File
@@ -0,0 +1,78 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.schemas.bulk_sms import BulkSMSSchema, BulkSMSResponseSchema
class BulkSMSService:
@staticmethod
def process_request(data):
"""
Process the BulkSMS request.
Args:
data (list): The request data as a list of SMS items.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing BulkSMS request")
# Check if the data is a list and not too large
if not isinstance(data, list):
return jsonify({
"data": "",
"statusCode": 400,
"IsSuccessful": False,
"errorMessage": "Request must be a list of SMS items"
}), 400
if len(data) > 20:
return jsonify({
"data": "",
"statusCode": 400,
"IsSuccessful": False,
"errorMessage": "Maximum of 20 SMS items allowed"
}), 400
# Validate each item in the list
schema = BulkSMSSchema()
# We need to wrap the list in a dictionary with a key that matches the schema field name
validated_data = schema.load({"_schema": data}) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to send bulk SMS messages to customers
# For demonstration, we'll simulate a successful bulk SMS send
response_data = {
"data": "",
"statusCode": 200,
"IsSuccessful": True,
"errorMessage": None
}
# Validate the response using the response schema
response_schema = BulkSMSResponseSchema()
validated_response = response_schema.dump(response_data)
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"data": "",
"statusCode": 400,
"IsSuccessful": False,
"errorMessage": f"Validation error: {err.messages}"
}), 400
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"data": "",
"statusCode": 500,
"IsSuccessful": False,
"errorMessage": f"Error occurred: {str(e)}"
}), 500
+38 -61
View File
@@ -1,90 +1,67 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.helpers.response_helper import ResponseHelper
from app.api.schemas.collect_loan import CollectLoanSchema, CollectLoanResponseSchema
"""
Process the CollectLoan request.
Args:
data (dict): The request data.
Returns:
tuple: JSON response and status code.
"""
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)
amountForCollection = validated_data.get("collectAmount")
amountCollected = amountForCollection
responseDescr= "Loan Collection Successful EMULATOR"
fullDescription= "Loan collection completed successfully EMULATOR"
responseMessage= "Loan collection completed successfully EMULATOR"
if amountForCollection in [5555.0, 6666.0, 7777.0, 8888.0 , 9999.0, 22222.0] :
amountCollected = amountForCollection * 0.85
responseDescr = "Partial Loan Collection Successful EMULATOR"
fullDescription = "Partial Loan collection completed successfully EMULATOR"
responseMessage = "Partial Loan collection completed successfully EMULATOR"
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to process the loan collection
# For demonstration, we'll simulate a partial collection
collect_amount = validated_data.get('collectAmount') * 0.75 # 75% of requested amount
lien_amount = validated_data.get('lienAmount') * 0.25 # 25% of requested amount as lien
response_data = {
"transactionId": validated_data.get("transactionId"),
"debtId": validated_data.get("debtId"),
"customerId": validated_data.get("customerId"),
"accountId": validated_data.get("accountId"),
"productId": validated_data.get("productId"),
"amountCollected": amountCollected,
"countryId": validated_data.get("countryId"),
"comment": validated_data.get("comment", "Testing CollectionLoanRequest EMULATOR"),
"responseCode": "00",
"responseDescr": responseDescr,
"fullDescription": fullDescription,
"responseMessage": responseMessage
"transactionId": validated_data.get('transactionId'),
"debtId": validated_data.get('debtId'),
"customerId": validated_data.get('customerId'),
"accountId": validated_data.get('accountId'),
"productId": validated_data.get('productId'),
"collectAmount": collect_amount,
"penalCharge": validated_data.get('penalCharge', 0),
"lienAmount": lien_amount,
"countryId": validated_data.get('countryId'),
"comment": validated_data.get('comment', ""),
"resultCode": "00",
"resultDescription": "Loan Collection Successful"
}
# # Simulated processing logic
# response_data = {
# "transactionId": validated_data.get("transactionId", "T002"),
# "debtId": validated_data.get("debtId", "273194670"),
# "customerId": validated_data.get("customerId", "CN621868"),
# "accountId": validated_data.get("accountId", "2017821799"),
# "productId": validated_data.get("productId", "101"),
# "amountCollected": validated_data.get("collectAmount", 60000.00),
# "countryId": validated_data.get("countryId", "01"),
# "comment": validated_data.get("comment", "Testing CollectionLoanRequest"),
# "responseCode": "00",
# "responseDescr": "Loan Collection Successful",
# "fullDescription": "Loan collection completed successfully",
# "responseMessage": "Loan collection completed successfully"
# }
#
# Validate and serialize the response data
# Validate the response using the response schema
response_schema = CollectLoanResponseSchema()
result = response_schema.dump(response_data)
validated_response = response_schema.dump(response_data)
return jsonify(result), 200
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception",
"errors": err.messages
}) , 422
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
@@ -17,6 +17,8 @@ class CompleteRACcheckService:
dict: A standardized response.
"""
try:
logger.info("Processing CompleteRACcheck request")
# Validate input data using CompleteRACcheckSchema
schema = CompleteRACcheckSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
+33 -30
View File
@@ -1,8 +1,7 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.schemas.disbursement import DisbursementSchema, DisburseLoanResponseSchema
import datetime
from app.api.schemas.disbursement import DisbursementSchema, DisbursementResponseSchema
class DisbursementService:
@staticmethod
@@ -14,7 +13,7 @@ class DisbursementService:
data (dict): The request data.
Returns:
tuple: JSON response and HTTP status code.
dict: A standardized response.
"""
try:
logger.info("Processing Disbursement request")
@@ -23,43 +22,47 @@ class DisbursementService:
schema = DisbursementSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# For demo purposes, we simulate a response using the validated data
# Extract fees details for easier access
fees_details = validated_data.get('feesDetails', {})
# Simulated processing logic
# In a real implementation, this would interact with your business logic
response_data = {
"transactionId": validated_data.get("transactionId"),
"fbnTransactionId": validated_data.get("fbnTransactionId"), # Example or generated value
"debtId": validated_data.get("debtId"),
"customerId": validated_data.get("customerId"),
"accountId": validated_data.get("accountId"),
"productId": validated_data.get("productId"),
"provideAmount": validated_data.get("provideAmount"),
"collectAmountInterest": validated_data.get("collectAmountInterest"),
"collectAmountMgtFee": validated_data.get("collectAmountMgtFee"),
"collectAmountInsurance": validated_data.get("collectAmountInsurance"),
"collectAmountVAT": validated_data.get("collectAmountVAT"),
"countryId": validated_data.get("countryId"),
"responseCode": "00", # success code example
"responseMessage": "Loan Request Completed Successfully!",
"disburseDate": datetime.datetime.now().isoformat(),
"disburseResult": "00",
"disburseDescription": "Loan Request Completed Successfully!",
"requestId": validated_data.get('requestId'),
"countryCode": validated_data.get('countryCode'),
"transactionId": validated_data.get('transactionId'),
"debtId": validated_data.get('debtId'),
"customerId": validated_data.get('customerId'),
"accountId": validated_data.get('accountId'),
"productId": validated_data.get('productId'),
"provideAmount": validated_data.get('provideAmount'),
"totalFees": validated_data.get('totalFees'),
"feesDetails": {
"collectAmountInterest": fees_details.get('collectAmountInterest'),
"collectAmountMgtFee": fees_details.get('collectAmountMgtFee'),
"collectAmountInsurance": fees_details.get('collectAmountInsurance'),
"collectAmountVAT": fees_details.get('collectAmountVAT')
},
"resultCode": "00",
"resultDescription": "Loan Request Completed Successfully!"
}
# Serialize response
response_schema = DisburseLoanResponseSchema()
result = response_schema.dump(response_data)
# Validate the response using the response schema
response_schema = DisbursementResponseSchema()
validated_response = response_schema.dump(response_data)
return jsonify(result), 200
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception",
"errors": err.messages
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}), 500
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+18 -14
View File
@@ -1,8 +1,8 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.helpers.response_helper import ResponseHelper
from app.api.schemas.lien_check import LienCheckSchema
from flask import request, jsonify
from app.api.schemas.lien_check import LienCheckSchema, LienCheckResponseSchema
class LienCheckService:
@staticmethod
@@ -23,29 +23,33 @@ class LienCheckService:
schema = LienCheckSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated lien check logic
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to check the lien amount on the account
# For demonstration, we'll simulate a lien amount of 20000.0
response_data = {
"lienAmount": 20000.0,
"resultCode": "00",
"resultDescription": "Successful"
}
# Validate the response using the response schema
response_schema = LienCheckResponseSchema()
validated_response = response_schema.dump(response_data)
# return ResponseHelper.success(
# data=response_data,
# message="Lien check completed successfully"
# )
return response_data
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception"
}) , 422
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}) , 500
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+77
View File
@@ -0,0 +1,77 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.schemas.loan_status import LoanStatusSchema, LoanStatusResponseSchema
from datetime import datetime, timedelta
class LoanStatusService:
@staticmethod
def process_request(data):
"""
Process the LoanStatus request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing LoanStatus request")
# Validate input data using LoanStatusSchema
schema = LoanStatusSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to retrieve the customer's loan status
# For demonstration, we'll create a sample response with one loan
# In a real implementation, you would query your database for actual loan data
current_date = datetime.now()
loan_date = (current_date - timedelta(days=30)).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
due_date = (current_date + timedelta(days=30)).strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
# Sample loan data
loan_data = {
"debtId": "123456789",
"loanDate": loan_date,
"dueDate": due_date,
"currentLoanAmount": 8500.0,
"initialLoanAmount": 10000.0,
"defaultPenaltyFee": 0.0,
"continuousFee": 0.0,
"productId": "101"
}
# Create response with the loan data
response_data = {
"customerId": validated_data.get('customerId'),
"transactionId": validated_data.get('transactionId'),
"loans": [loan_data], # Array with one loan
"totalDebtAmount": 8500.0, # Same as currentLoanAmount for this example
"resultCode": "00",
"resultDescription": "Successful"
}
# Validate the response using the response schema
response_schema = LoanStatusResponseSchema()
validated_response = response_schema.dump(response_data)
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+17 -17
View File
@@ -1,8 +1,7 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.helpers.response_helper import ResponseHelper
from app.api.schemas.penal_charge import PenalChargeSchema, CollectPenalFeeResponseSchema
from app.api.schemas.penal_charge import PenalChargeSchema, PenalChargeResponseSchema
class PenalChargeService:
@@ -22,33 +21,34 @@ class PenalChargeService:
# Validate input data using PenalChargeSchema
schema = PenalChargeSchema()
validated_data = schema.load(data)
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to process the penal charge
# For demonstration, we'll simulate a successful penal charge
response_data = {
"customerId": validated_data.get("customerId"),
"transactionId": validated_data.get("transactionId"),
"amountCollected": validated_data.get("penalCharge", 0.0),
"accountId": validated_data.get("accountId"),
"responseCode": "00",
"responseMessage": "Penal charge debited successfully"
"resultCode": "00",
"resultDescription": "Penal charge debited successfully"
}
# Optionally validate/serialize response using schema
response_schema = CollectPenalFeeResponseSchema()
result = response_schema.dump(response_data)
# Validate the response using the response schema
response_schema = PenalChargeResponseSchema()
validated_response = response_schema.dump(response_data)
return result
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception",
"errors": err.messages
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}), 500
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+56
View File
@@ -0,0 +1,56 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.schemas.provide_loan import ProvideLoanSchema, ProvideLoanResponseSchema
class ProvideLoanService:
@staticmethod
def process_request(data):
"""
Process the ProvideLoan request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing ProvideLoan request")
# Validate input data using ProvideLoanSchema
schema = ProvideLoanSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to process the loan provision request
response_data = {
"requestId": validated_data.get('requestId', f"REQ-{validated_data.get('transactionId')}"),
"transactionId": validated_data.get('transactionId'),
"customerId": validated_data.get('customerId'),
"accountId": validated_data.get('accountId'),
"msisdn": validated_data.get('msisdn', ""),
"resultCode": "00",
"resultDescription": "Successful"
}
# Validate the response using the response schema
response_schema = ProvideLoanResponseSchema()
validated_response = response_schema.dump(response_data)
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+35 -79
View File
@@ -1,10 +1,8 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.helpers.response_helper import ResponseHelper
from app.api.schemas.rac_check import RACCheckSchema, RACCheckResponseSchema
from datetime import datetime
from decimal import Decimal
class RACCheckService:
@staticmethod
@@ -16,101 +14,59 @@ class RACCheckService:
data (dict): The request data.
Returns:
tuple: JSON response and status code.
dict: A standardized response.
"""
try:
logger.info("Processing RACCheck request")
# Validate input data
# Validate input data using RACCheckSchema
schema = RACCheckSchema()
validated_data = schema.load(data)
customer_id = validated_data["customerId"]
is_valid = not (
int(customer_id[-1]) in [2, 7, 9]
)
try:
salary_count = int(str(customer_id)[-1]) + 1
if salary_count < 1 or salary_count > 6:
salary_count = 3
except ValueError:
salary_count = 3
salary_payments = {}
total_salary = 0
for i in range(1, salary_count + 1):
salary = ((salary_count + i ) * 7919) % 200000 + 10000
salary_payments[f"salarypaymenT_{i}"] = salary
total_salary += salary
average_salary = total_salary // salary_count if salary_count > 0 else 0
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to check the RAC criteria
# For demonstration, we'll simulate all checks passing
rac_response = {
"procesS_DATE": datetime.strptime("2025-06-05", "%Y-%m-%d").date(),
"ciF_ID": "416405737",
"customeR_id": customer_id,
"salaccT_1": "4142904114",
"alerT_PHONE": "2348039301606",
"averagE_SALARY": average_salary,
"loaN_OUSTANDING_BAL": 0,
"emi": 1000,
"eliG_AMT": 25000,
"rule1_45day_sal": is_valid,
"rule2_2m_sal": is_valid,
"rule3_no_bounced_check": is_valid,
"rule4_current_loan_payments": True if is_valid is False else is_valid,
"rule5_no_past_due_fadv_loan": is_valid,
"rule6_no_past_due_other_loan": is_valid,
"rule7_consistent_salary_amount": is_valid,
"rule8_whitelisted": True if is_valid is False else is_valid,
"rule9_regular_account": True if is_valid is False else is_valid,
"rule10_bvn_validation": is_valid,
"rule11_CRC_no_delinquency": is_valid,
"rule12_CRMS_no_delinquency": True if is_valid is False else is_valid,
"rule13_BVN_ignore": is_valid,
"rule14_no_lien": is_valid,
"rule15_null_ignore": True if is_valid is False else is_valid,
"overalL_ELIG": is_valid
# "salarypaymenT_1": 180000,
# "salarypaymenT_2": 50000,
# "salarypaymenT_3": 70000,
# "salarypaymenT_4": 0,
# "salarypaymenT_5": 0,
# "salarypaymenT_6": 0
"Salary account": "1",
"BVN": "1",
"BVNAttachedToAccount": "1",
"CRMS": "1",
"CRC": "1",
"AccountStatus": "1",
"Lien": "1",
"NoBouncedCheck": "1",
"Whitelist": "1",
"NoPastDueSalaryLoan": "1",
"NoPastDueOtherLoan": "1"
}
rac_response.update(salary_payments)
full_response = {
"transactionId": validated_data["transactionId"],
"customerId": validated_data["customerId"],
"accountId": validated_data["accountId"],
"racResponse": rac_response
response_data = {
"transactionId": validated_data.get('transactionId'),
"customerId": validated_data.get('customerId'),
"accountId": validated_data.get('accountId'),
"RACResponse": rac_response,
"resultCode": "00",
"resultDescription": "RAC Check Successful"
}
# response_schema = RACCheckResponseSchema()
result = {
"responseCode": "00",
"responseMessage": "Operation Successful",
"data": full_response
}
# Validate the response using the response schema
response_schema = RACCheckResponseSchema()
validated_response = response_schema.dump(response_data)
return jsonify(result), 200
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception",
"errors": err.messages
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}), 500
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+68
View File
@@ -0,0 +1,68 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.schemas.repayment import RepaymentSchema, RepaymentResponseSchema
class RepaymentService:
@staticmethod
def process_request(data):
"""
Process the Repayment request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing Repayment request")
# Validate input data using RepaymentSchema
schema = RepaymentSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to process the repayment
# For demonstration, we'll simulate a partial repayment
collected_amount = validated_data.get('collectedAmount') * 0.75 # 75% of requested amount
lien_amount = validated_data.get('lienAmount') * 0.25 # 25% of requested amount as lien
response_data = {
"requestId": validated_data.get('requestId'),
"countryCode": validated_data.get('countryCode'),
"transactionId": validated_data.get('transactionId'),
"debtId": validated_data.get('debtId'),
"customerId": validated_data.get('customerId'),
"accountId": validated_data.get('accountId'),
"productId": validated_data.get('productId'),
"collectedAmount": collected_amount,
"penalCharge": validated_data.get('penalCharge', 0),
"lienAmount": lien_amount,
"comment": validated_data.get('comment', ""),
"resultCode": "00",
"resultDescription": "Loan Collection Successful"
}
# Validate the response using the response schema
response_schema = RepaymentResponseSchema()
validated_response = response_schema.dump(response_data)
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+75
View File
@@ -0,0 +1,75 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.schemas.select_offer import SelectOfferSchema, SelectOfferResponseSchema
class SelectOfferService:
@staticmethod
def process_request(data):
"""
Process the SelectOffer request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing SelectOffer request")
# Validate input data using SelectOfferSchema
schema = SelectOfferSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to determine eligible loan offers based on the requested amount and product
response_data = {
"requestId": validated_data.get('requestId'),
"transactionId": validated_data.get('transactionId'),
"customerId": validated_data.get('customerId'),
"accountId": validated_data.get('accountId'),
"outstandingDebtAmount": 0,
"loan": [
{
"offerId": "14451",
"productId": "2030",
"amount": validated_data.get('requestedAmount'),
"upfrontPayment": validated_data.get('requestedAmount') * 0.1, # 10% upfront
"interestRate": 3.0,
"Interest": validated_data.get('requestedAmount') * 0.03, # 3% interest
"ManagementRate": 1.0,
"ManagementFee": validated_data.get('requestedAmount') * 0.01, # 1% management fee
"InsuranceRate": 1.0,
"InsuranceFee": validated_data.get('requestedAmount') * 0.01, # 1% insurance
"VATRate": 7.5,
"VATamount": (validated_data.get('requestedAmount') * 0.01) * 0.075, # 7.5% VAT on management fee
"recommendedRepaymentDates": ["2023-12-30"], # Example date
"installmentAmount": validated_data.get('requestedAmount') * 1.1, # Principal + 10% fees
"totalRepaymentAmount": validated_data.get('requestedAmount') * 1.1 # Principal + 10% fees
}
],
"resultCode": "00",
"resultDescription": "Successful"
}
# Validate the response using the response schema
response_schema = SelectOfferResponseSchema()
validated_response = response_schema.dump(response_data)
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+60
View File
@@ -0,0 +1,60 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.schemas.sms import SMSSchema, SMSResponseSchema
class SMSService:
@staticmethod
def process_request(data):
"""
Process the SMS request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing SMS request")
# Validate input data using SMSSchema
schema = SMSSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to send an SMS to the customer
# For demonstration, we'll simulate a successful SMS send
response_data = {
"data": "",
"statusCode": 200,
"IsSuccessful": True,
"errorMessage": None
}
# Validate the response using the response schema
response_schema = SMSResponseSchema()
validated_response = response_schema.dump(response_data)
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"data": "",
"statusCode": 400,
"IsSuccessful": False,
"errorMessage": f"Validation error: {err.messages}"
}), 400
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"data": "",
"statusCode": 500,
"IsSuccessful": False,
"errorMessage": f"Error occurred: {str(e)}"
}), 500
+77
View File
@@ -0,0 +1,77 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.schemas.status_call import StatusCallSchema, StatusCallResponseSchema
class StatusCallService:
@staticmethod
def process_request(data):
"""
Process the StatusCall request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing StatusCall request")
# Validate input data using StatusCallSchema
schema = StatusCallSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to check the status of a transaction
# For demonstration, we'll simulate different responses based on transaction type
transaction_type = validated_data.get('transactionType')
if transaction_type == "Disbursement":
provided_amount = 1000.00
collected_amount = 0.00
inner_result_description = "Loan Provision is successful"
elif transaction_type == "Collection":
provided_amount = 0.00
collected_amount = 1050.00
inner_result_description = "Loan Collection is successful"
else: # PenalCharge
provided_amount = 0.00
collected_amount = 50.00
inner_result_description = "Penal Charge is successful"
response_data = {
"transactionId": "24110114545374721", # This would be generated in a real system
"data": {
"transactionId": validated_data.get('transactionId'),
"providedAmount": provided_amount,
"collectedAmount": collected_amount,
"resultCode": "00",
"resultDescription": inner_result_description
},
"resultCode": "00",
"resultDescription": "SUCCESS"
}
# Validate the response using the response schema
response_schema = StatusCallResponseSchema()
validated_response = response_schema.dump(response_data)
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+38 -25
View File
@@ -1,12 +1,7 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.utils.logger import logger
from app.api.helpers.response_helper import ResponseHelper
from app.api.schemas.transaction_verify import (
TransactionVerifySchema,
TransactionVerifyResponseSchema
)
import datetime
from app.api.schemas.transaction_verify import TransactionVerifySchema, TransactionVerifyResponseSchema
class TransactionVerifyService:
@@ -29,36 +24,54 @@ class TransactionVerifyService:
validated_data = schema.load(data) # Raises ValidationError if invalid
# Simulated processing logic
# In a real implementation, this would interact with your business logic
# to verify the transaction status
# For demonstration, we'll simulate different responses based on transaction type
transaction_type = validated_data.get('transactionType')
if transaction_type == "Disbursement":
provided_amount = 100.0
collected_amount = 0.0
result_description = "Disbursement Status retrieved successfully."
elif transaction_type == "Collection":
provided_amount = 0.0
collected_amount = 75.0
result_description = "Collection Status retrieved successfully."
else: # Penalty
provided_amount = 0.0
collected_amount = 7.50
result_description = "Penalty Status retrieved successfully."
response_data = {
"responseCode": "00",
"responseDescr": "Success",
"fullDescription": "Collect Status retrieved successfully.",
"customerId": validated_data.get("customerId"),
"accountId": validated_data.get("accountId"),
"providedAmount": 0.0,
"collectedAmount": 7.50,
"transactionId": validated_data.get("transactionId"),
"transactionType": validated_data.get("transactionType"),
"disburseVerify": datetime.datetime.now().isoformat(),
"verifyResult": "00",
"verifyDescription": "Collect Status retrieved successfully.",
"requestId": validated_data.get('requestId'),
"countryCode": validated_data.get('countryCode'),
"transactionId": validated_data.get('transactionId'),
"transactionType": transaction_type,
"customerId": validated_data.get('customerId'),
"accountId": validated_data.get('accountId'),
"providedAmount": provided_amount,
"collectedAmount": collected_amount,
"resultCode": "00",
"resultDescription": result_description
}
# Validate and serialize response with TransactionVerifyResponseSchema
# Validate the response using the response schema
response_schema = TransactionVerifyResponseSchema()
serialized_response = response_schema.dump(response_data)
validated_response = response_schema.dump(response_data)
return jsonify(serialized_response), 200
return jsonify(validated_response)
except ValidationError as err:
logger.error(f"Validation Error: {err.messages}")
return jsonify({
"message": "Validation exception",
"errors": err.messages
"resultCode": "01",
"resultDescription": f"Validation error: {err.messages}"
}), 422
except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({
"message": "Internal Server Error"
}), 500
"resultCode": "08",
"resultDescription": f"Error occurred: {str(e)}"
}), 500
+3 -19
View File
@@ -1,12 +1,10 @@
import os
from dotenv import load_dotenv
from datetime import timedelta
class Config:
"""Base configuration for Flask app"""
load_dotenv()
SWAGGER_URL = os.getenv("SWAGGER_URL")
API_URL = os.getenv("API_URL")
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")
@@ -16,18 +14,4 @@ class Config:
# SQLALCHEMY_TRACK_MODIFICATIONS = False
# SECRET_KEY = os.environ.get("SECRET_KEY", "your_secret_key")
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)
)
BASIC_AUTH_USERNAME = os.environ.get("BASIC_AUTH_USERNAME", "user")
BASIC_AUTH_PASSWORD = os.environ.get("BASIC_AUTH_PASSWORD", "password")
DEBUG = True
def configure():
load_dotenv()
settings = Config()
-1
View File
@@ -1 +0,0 @@
from .transaction_type import TransactionType
-7
View File
@@ -1,7 +0,0 @@
from enum import Enum
class InstallmentStatus(str, Enum):
PENDING = 'PENDING'
PAID = 'PAID'
OVERDUE = 'OVERDUE'
PARTIALLY_PAID = 'PARTIALLY_PAID'
-8
View File
@@ -1,8 +0,0 @@
from enum import Enum
class LoanStatus(str, Enum):
PENDING = 'PENDING'
ACTIVE = 'ACTIVE'
PAID = 'PAID'
DEFAULTED = 'DEFAULTED'
CLOSED = 'CLOSED'
-7
View File
@@ -1,7 +0,0 @@
from enum import Enum
class TransactionType(str, Enum):
DEBT_CLOSURE_NOTIFICATION = "debt_closure_notification"
DISBURSEMENT = "disbursement"
SEND_SMS = "send_sms"
COLLECT_LOAN = "collect_loan"
-112
View File
@@ -1,112 +0,0 @@
from flask import jsonify
from typing import Optional, Union, Dict, List, Any
class ResponseHelper:
"""
A helper class for building standardized JSON responses using resultCode and resultDescription.
"""
@staticmethod
def build_response(
result_code: str,
result_description: str,
data: Optional[Union[Dict, List, str]] = None
) -> Dict[str, Any]:
response = {
"resultCode": result_code,
"resultDescription": result_description
}
if isinstance(data, dict):
response.update(data)
return jsonify(response)
@staticmethod
def success(
result_description: str = "Successful",
result_code: str = "00",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def error(
result_description: str = "An error occurred",
result_code: str = "01",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def created(
result_description: str = "Resource created successfully",
result_code: str = "00",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def updated(
result_description: str = "Resource updated successfully",
result_code: str = "00",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def internal_server_error(
result_description: str = "Internal Server Error",
result_code: str = "500",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def unauthorized(
result_description: str = "Unauthorized",
result_code: str = "401",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def forbidden(
result_description: str = "Forbidden",
result_code: str = "403",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def not_found(
result_description: str = "Resource not found",
result_code: str = "404",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def unprocessable_entity(
result_description: str = "Unprocessable entity",
result_code: str = "422",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def method_not_allowed(
result_description: str = "Method Not Allowed",
result_code: str = "405",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
@staticmethod
def bad_request(
result_description: str = "Bad Request",
result_code: str = "400",
data: Optional[Dict[str, Any]] = None
) -> Dict[str, Any]:
return ResponseHelper.build_response(result_code, result_description, data)
-1
View File
@@ -1 +0,0 @@
from .routes import eco
-87
View File
@@ -1,87 +0,0 @@
from flask import Blueprint, request, jsonify, send_from_directory
from app.eco.services import (
AuthorizationService,
DisbursementService,
CollectLoanService,
DebtClosureNotificationService,
SendSMSService
)
from app.utils.logger import logger
from flask_jwt_extended import jwt_required
import os
eco = Blueprint("eco", __name__)
# Swagger JSON file
@eco.route("/swagger.json", methods=["GET"])
def swagger_json():
swagger_dir = os.path.join("swagger")
return send_from_directory(swagger_dir, "eco_digifi_swagger.json")
@eco.route("/swagger/<path:filename>")
def serve_paths(filename):
swagger_dir = os.path.join("swagger")
return send_from_directory(swagger_dir, filename)
# Disbursement (Simbrella -> EcoBank)
@eco.route("/Disbursement", methods=["POST"])
@jwt_required()
def disbursement():
data = request.get_json()
response = DisbursementService.process_request(data)
return response
# CollectLoan (Simbrella -> EcoBank)
@eco.route("/CollectLoan", methods=["POST"])
@jwt_required()
def collect_loan():
data = request.get_json()
response = CollectLoanService.process_request(data)
return response
# Debt Closure Notification (Simbrella -> EcoBank)
@eco.route("/DebtClosureNotification", methods=["POST"])
@jwt_required()
def debt_closure():
data = request.get_json()
response = DebtClosureNotificationService.process_request(data)
return response
# Send SMS (Simbrella -> EcoBank)
@eco.route("/SendSMS", methods=["POST"])
@jwt_required()
def send_sms():
data = request.get_json()
response = SendSMSService.process_request(data)
return response
# Health Check
@eco.route("/health", methods=["GET"])
def health_check():
return jsonify({"status": "ok"}), 200
# Authorize endpoint
@eco.route("/Authorize", methods=["POST"])
def authorize():
data = request.get_json()
response = AuthorizationService.process_request(data)
return response
# Authorize refresh endpoint
@eco.route("/AuthorizeRefresh", methods=["POST"])
@jwt_required(refresh=True)
def refresh():
response = AuthorizationService.process_refresh_request()
return response
-5
View File
@@ -1,5 +0,0 @@
from .authorization import AuthorizeRequestSchema
from .disbursement import DisbursementSchema
from .debt_closure_notification import DebtClosureNotificationSchema
from .send_sms import SendSmsSchema
from .collect_loan import CollectLoanSchema
-6
View File
@@ -1,6 +0,0 @@
from marshmallow import Schema, fields
class AuthorizeRequestSchema(Schema):
username = fields.Str(required=True)
password = fields.Str(required=True)
-13
View File
@@ -1,13 +0,0 @@
from marshmallow import Schema, fields, EXCLUDE
class CollectLoanSchema(Schema):
requestId = fields.Str(required=True)
affiliateCode = fields.Str(required=True)
debtId = fields.Int(required=True)
principal = fields.Decimal(required=True)
interest = fields.Decimal(required=True)
penalty = fields.Decimal(required=True)
collectAmount = fields.Decimal(required=True)
class Meta:
unknown = EXCLUDE
@@ -1,11 +0,0 @@
from marshmallow import Schema, fields, EXCLUDE
class DebtClosureNotificationSchema(Schema):
requestId = fields.Str(required=True)
affiliateCode = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
debtId = fields.Int(required=True)
class Meta:
unknown = EXCLUDE
-15
View File
@@ -1,15 +0,0 @@
from marshmallow import Schema, fields, EXCLUDE
class DisbursementSchema(Schema):
requestId = fields.Str(required=True)
affiliateCode = fields.Str(required=True)
debtId = fields.Int(required=True)
productId = fields.Str(required=True)
customerId = fields.Str(required=True)
accountId = fields.Str(required=True)
provideAmount = fields.Decimal(required=True)
collectAmount = fields.Decimal(required=True)
interestRate = fields.Decimal(required=True)
class Meta:
unknown = EXCLUDE
-10
View File
@@ -1,10 +0,0 @@
from marshmallow import Schema, fields, EXCLUDE
class SendSmsSchema(Schema):
requestId = fields.Str(required=True)
phoneNums = fields.List(fields.Str(), required=True)
affiliateCode = fields.Str(required=True)
message = fields.Str(required=True)
class Meta:
unknown = EXCLUDE
-5
View File
@@ -1,5 +0,0 @@
from .authorization import AuthorizationService
from .disbursement import DisbursementService
from .debt_closure_notification import DebtClosureNotificationService
from .send_sms import SendSMSService
from .collect_loan import CollectLoanService
-102
View File
@@ -1,102 +0,0 @@
from flask import request, jsonify
from marshmallow import ValidationError
from app.eco.services.base_service import BaseService
from app.utils.logger import logger
from app.eco.schemas.authorization import AuthorizeRequestSchema
from app.eco.helpers.response_helper import ResponseHelper
from flask_jwt_extended import (
JWTManager,
jwt_required,
create_access_token,
create_refresh_token,
get_jwt_identity,
)
from app.config import Config
USERNAME = Config.BASIC_AUTH_USERNAME
PASSWORD = Config.BASIC_AUTH_PASSWORD
class AuthorizationService(BaseService):
@staticmethod
def process_request(data):
"""
Process the Authorization request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing Authorization request")
if not data:
return ResponseHelper.bad_request(result_description="Missing JSON in request")
# Validate input data using the Authorization schema
schema = AuthorizeRequestSchema()
validated_data = schema.load(data) # Raises ValidationError if invalid
if (
validated_data["username"] != USERNAME
or validated_data["password"] != PASSWORD
):
return ResponseHelper.unauthorized(result_description="Invalid credentials")
access_token = create_access_token(identity=validated_data["username"])
refresh_token = create_refresh_token(identity=validated_data["username"])
# Simulated processing logic
response_data = {
"access_token": access_token,
"refresh_token": refresh_token,
}
return ResponseHelper.success(
data={"data": response_data}, result_description="Authorization processed successfully"
)
except ValidationError as e:
logger.error(f"Validation error: {e}")
return ResponseHelper.bad_request(result_description=f"Validation error: {e}")
except Exception as e:
logger.error(f"Error processing Authorization request: {e}")
return ResponseHelper.internal_server_error(
result_description=f"Error processing Authorization request: {e}"
)
@staticmethod
def process_refresh_request():
"""
Process the RefreshToken request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
logger.info("Processing RefreshToken request")
identity = get_jwt_identity()
access_token = create_access_token(identity=identity)
# Simulated processing logic
response_data = {
"access_token": access_token,
}
return ResponseHelper.success(
data={"data": response_data}, result_description="RefreshToken processed successfully"
)
except Exception as e:
logger.error(f"Error processing RefreshToken request: {e}")
return ResponseHelper.internal_server_error(
result_description=f"Error processing RefreshToken request: {e}"
)
-32
View File
@@ -1,32 +0,0 @@
from app.eco.enums import TransactionType
from flask import jsonify
from marshmallow import ValidationError
import logging
logger = logging.getLogger(__name__)
class BaseService:
TRANSACTION_TYPE = None
@classmethod
def validate_data(cls, data, schema):
"""
Validate input data based on the provided schema.
"""
logger.info(f"Processing {cls.TRANSACTION_TYPE} request")
return schema.load(data)
# @classmethod
# def log_session(cls, validated_data):
# """
# Create a new session.
# """
# channel = "USSD" if validated_data.get("channel") is None else validated_data.get("channel")
# return Session.create_session(
# session_id = validated_data.get("transactionId"),
# customer_id = validated_data.get('customerId', None),
# account_id = validated_data.get("accountId", None),
# type = cls.TRANSACTION_TYPE,
# channel = channel,
# )
-33
View File
@@ -1,33 +0,0 @@
from app.eco.enums.transaction_type import TransactionType
from app.eco.services.base_service import BaseService
from app.eco.schemas.collect_loan import CollectLoanSchema
from marshmallow import ValidationError
from app.eco.helpers.response_helper import ResponseHelper
class CollectLoanService(BaseService):
TRANSACTION_TYPE = TransactionType.COLLECT_LOAN
@staticmethod
def process_request(data):
"""
Process the loan collection request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
validated_data = CollectLoanService.validate_data(data, CollectLoanSchema())
response_data = {
"transactionId": "01135062",
"amountCollected": 900.0,
}
return ResponseHelper.success(data=response_data)
except ValidationError as err:
return ResponseHelper.unprocessable_entity(result_description="Validation exception")
except Exception as e:
return ResponseHelper.internal_server_error()
@@ -1,27 +0,0 @@
from app.eco.enums.transaction_type import TransactionType
from app.eco.services.base_service import BaseService
from app.eco.schemas.debt_closure_notification import DebtClosureNotificationSchema
from marshmallow import ValidationError
from app.eco.helpers.response_helper import ResponseHelper
class DebtClosureNotificationService(BaseService):
TRANSACTION_TYPE = TransactionType.DEBT_CLOSURE_NOTIFICATION
@staticmethod
def process_request(data):
"""
Process the debt closure notification request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
validated_data = DebtClosureNotificationService.validate_data(data, DebtClosureNotificationSchema())
return ResponseHelper.success()
except ValidationError as err:
return ResponseHelper.unprocessable_entity(result_description="Validation exception")
except Exception as e:
return ResponseHelper.internal_server_error()
-32
View File
@@ -1,32 +0,0 @@
from app.eco.enums.transaction_type import TransactionType
from app.eco.services.base_service import BaseService
from app.eco.schemas.disbursement import DisbursementSchema
from marshmallow import ValidationError
from app.eco.helpers.response_helper import ResponseHelper
class DisbursementService(BaseService):
TRANSACTION_TYPE = TransactionType.DISBURSEMENT
@staticmethod
def process_request(data):
"""
Process the disbursement request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
validated_data = DisbursementService.validate_data(data, DisbursementSchema())
response_data = {
"transactionId": "SIM01135042",
}
return ResponseHelper.success(data=response_data)
except ValidationError as err:
return ResponseHelper.unprocessable_entity(result_description="Validation exception")
except Exception as e:
return ResponseHelper.internal_server_error()
-31
View File
@@ -1,31 +0,0 @@
from app.eco.enums.transaction_type import TransactionType
from app.eco.services.base_service import BaseService
from app.eco.schemas.send_sms import SendSmsSchema
from marshmallow import ValidationError
from app.eco.helpers.response_helper import ResponseHelper
class SendSMSService(BaseService):
TRANSACTION_TYPE = TransactionType.SEND_SMS
@staticmethod
def process_request(data):
"""
Process the SMS sending request.
Args:
data (dict): The request data.
Returns:
dict: A standardized response.
"""
try:
validated_data = SendSMSService.validate_data(data, SendSmsSchema())
response_data = {
"undelivered": []
}
return ResponseHelper.success(data=response_data)
except ValidationError as err:
return ResponseHelper.unprocessable_entity(result_description="Validation exception")
except Exception as e:
return ResponseHelper.internal_server_error()
+151 -80
View File
@@ -16,9 +16,6 @@
"servers": [
{
"url": "http://localhost:6337"
},
{
"url": "http://localhost:5000"
},
{
"url": "http://10.10.11.17:6337"
@@ -28,6 +25,46 @@
}
],
"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 Status 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": "RACCheck",
"description": "Risk Acceptance Criteria Request",
@@ -76,22 +113,6 @@
"url": "https://www.simbrellang.net"
}
},
{
"name": "RevokeEnableConsent",
"description": "Revoke Enable Consent Request",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "TokenValidation",
"description": "Token Validation",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "LienCheck",
"description": "Lien Check",
@@ -101,8 +122,24 @@
}
},
{
"name": "NewTransactionCheck",
"description": "New Transaction Check",
"name": "StatusCall",
"description": "Status Call",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "SMS",
"description": "SMSRequest",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "BulkSMS",
"description": "Bulk SMS Request",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
@@ -110,42 +147,78 @@
}
],
"paths": {
"/api/system-health-check": {
"$ref": "swagger/paths/HealthCheck.json"
"/EligibilityCheck": {
"$ref": "./paths/EligibilityCheck.json"
},
"/api/rac-check": {
"$ref": "swagger/paths/RACCheck.json"
"/SelectOffer": {
"$ref": "./paths/SelectOffer.json"
},
"/api/CompleteRACcheck": {
"$ref": "swagger/paths/CompleteRACcheck.json"
"/ProvideLoan": {
"$ref": "./paths/ProvideLoan.json"
},
"/api/DisburseLoan": {
"$ref": "swagger/paths/Disbursement.json"
"/LoanStatus": {
"$ref": "./paths/LoanStatus.json"
},
"/api/CollectLoan": {
"$ref": "swagger/paths/CollectLoan.json"
"/Repayment": {
"$ref": "./paths/Repayment.json"
},
"/api/TransactionVerify": {
"$ref": "swagger/paths/TransactionVerify.json"
"/RACCheck": {
"$ref": "./paths/RACCheck.json"
},
"/api/CollectPenalFee": {
"$ref": "swagger/paths/PenalCharge.json"
"/CompleteRACcheck": {
"$ref": "./paths/CompleteRACcheck.json"
},
"/api/RevokeEnableConsent": {
"$ref": "swagger/paths/RevokeEnableConsent.json"
"/Disbursement": {
"$ref": "./paths/Disbursement.json"
},
"/api/TokenValidation": {
"$ref": "swagger/paths/TokenValidation.json"
"/CollectLoan": {
"$ref": "./paths/CollectLoan.json"
},
"/api/LienCheck": {
"$ref": "swagger/paths/LienCheck.json"
"/TransactionVerify": {
"$ref": "./paths/TransactionVerify.json"
},
"/api/NewTransactionCheck": {
"$ref": "swagger/paths/NewTransactionCheck.json"
"/PenalCharge": {
"$ref": "./paths/PenalCharge.json"
},
"/LienCheck": {
"$ref": "./paths/LienCheck.json"
},
"/StatusCall": {
"$ref": "./paths/StatusCall.json"
},
"/SMS": {
"$ref": "./paths/SMS.json"
},
"/BulkSMS": {
"$ref": "./paths/BulkSMS.json"
}
},
"components": {
"schemas": {
"EligibilityCheckRequest": {
"$ref": "./schemas/EligibilityCheckRequest.json"
},
"EligibilityCheckResponse": {
"$ref": "./schemas/EligibilityCheckResponse.json"
},
"SelectOfferRequest": {
"$ref": "./schemas/SelectOfferRequest.json"
},
"SelectOfferResponse": {
"$ref": "./schemas/SelectOfferResponse.json"
},
"LoanStatusRequest": {
"$ref": "./schemas/LoanStatusRequest.json"
},
"LoanStatusResponse": {
"$ref": "./schemas/LoanStatusResponse.json"
},
"RepaymentRequest": {
"$ref": "./schemas/RepaymentRequest.json"
},
"RepaymentResponse": {
"$ref": "./schemas/RepaymentResponse.json"
},
"RACCheckRequest": {
"$ref": "./schemas/RACCheckRequest.json"
},
@@ -158,12 +231,6 @@
"CompleteRACcheckResponse": {
"$ref": "./schemas/CompleteRACcheckResponse.json"
},
"CustomerConsentRequest": {
"$ref": "./schemas/CustomerConsentRequest.json"
},
"CustomerConsentResponse": {
"$ref": "./schemas/CustomerConsentResponse.json"
},
"DisbursementRequest": {
"$ref": "./schemas/DisbursementRequest.json"
},
@@ -188,23 +255,11 @@
"PenalChargeResponse": {
"$ref": "./schemas/PenalChargeResponse.json"
},
"RevokeEnableConsentRequest": {
"$ref": "./schemas/RevokeEnableConsentRequest.json"
"StatusCallRequest": {
"$ref": "./schemas/StatusCallRequest.json"
},
"RevokeEnableConsentResponse": {
"$ref": "./schemas/RevokeEnableConsentResponse.json"
},
"TokenValidationRequest": {
"$ref": "./schemas/TokenValidationRequest.json"
},
"TokenValidationResponse": {
"$ref": "./schemas/TokenValidationResponse.json"
},
"NewTransactionCheckRequest": {
"$ref": "./schemas/NewTransactionCheckRequest.json"
},
"NewTransactionCheckResponse": {
"$ref": "./schemas/NewTransactionCheckResponse.json"
"StatusCallResponse": {
"$ref": "./schemas/StatusCallResponse.json"
},
"LienCheckRequest": {
"$ref": "./schemas/LienCheckRequest.json"
@@ -212,29 +267,45 @@
"LienCheckResponse": {
"$ref": "./schemas/LienCheckResponse.json"
},
"SMSRequest": {
"$ref": "./schemas/SMSRequest.json"
},
"SMSResponse": {
"$ref": "./schemas/SMSResponse.json"
},
"BulkSMSRequest": {
"$ref": "./schemas/BulkSMSRequest.json"
},
"BulkSMSResponse": {
"$ref": "./schemas/BulkSMSResponse.json"
},
"ApiResponse": {
"$ref": "./schemas/ApiResponse.json"
}
},
"securitySchemes": {
"petstore_auth": {
"type": "oauth2",
"flows": {
"implicit": {
"authorizationUrl": "https://petstore3.swagger.io/oauth/authorize",
"scopes": {
"write:pets": "modify pets in your account",
"read:pets": "read your pets"
}
}
}
},
"api_key": {
"type": "apiKey",
"name": "x-api-key",
"name": "api_key",
"in": "header"
},
"app_id": {
"type": "apiKey",
"name": "App-Id",
"in": "header"
"basic_auth": {
"type": "http",
"scheme": "basic",
"description": "Basic authentication with username and password"
}
}
},
"security": [
{
"api_key": []
},
{
"app_id": []
}
]
}
}
}
-128
View File
@@ -1,128 +0,0 @@
{
"openapi": "3.0.3",
"info": {
"title": "bank Emulator Swagger Simbrella EcoBank - OpenAPI 3.0",
"description": "This is a Simbrella EcoBank bank Backend Server Emulator 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:6337"
},
{
"url": "http://localhost:5000"
},
{
"url": "http://10.10.11.17:6337"
},
{
"url": "https://bank-emulator.dev.simbrellang.net"
}
],
"tags": [
{
"name": "Authentication",
"description": "EcoBank Authentication Token Request",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "Disbursement",
"description": "Loan Disbursement Request to EcoBank",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "CollectLoan",
"description": "Collect Loan Repayment from EcoBank Customer",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "DebtClosureNotification",
"description": "Notify EcoBank of Loan Closure",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
},
{
"name": "SendSMS",
"description": "Send SMS to EcoBank Customers",
"externalDocs": {
"description": "Find out more",
"url": "https://www.simbrellang.net"
}
}
],
"paths": {
"/eco/Authorize": {
"$ref": "swagger/paths/eco/Authentication.json"
},
"/eco/Disbursement": {
"$ref": "swagger/paths/eco/Disbursement.json"
},
"/eco/CollectLoan": {
"$ref": "swagger/paths/eco/CollectLoan.json"
},
"/eco/DebtClosureNotification": {
"$ref": "swagger/paths/eco/DebtClosureNotification.json"
},
"/eco/SendSMS": {
"$ref": "swagger/paths/eco/SendSMS.json"
}
},
"components": {
"schemas": {
"AuthenticationRequest": {
"$ref": "swagger/schemas/eco/AuthenticationRequest.json"
},
"AuthenticationResponse": {
"$ref": "swagger/schemas/eco/AuthenticationResponse.json"
},
"DebtClosureNotificationRequest": {
"$ref": "swagger/schemas/eco/DebtClosureNotificationRequest.json"
},
"DebtClosureNotificationResponse": {
"$ref": "swagger/schemas/eco/DebtClosureNotificationResponse.json"
},
"SendSMSRequest": {
"$ref": "swagger/schemas/eco/SendSMSRequest.json"
},
"SendSMSResponse": {
"$ref": "swagger/schemas/eco/SendSMSResponse.json"
}
},
"securitySchemes": {
"basicAuth": {
"type": "http",
"scheme": "basic"
},
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
}
}
},
"security": [
{
"basicAuth": [],
"bearerAuth": []
}
]
}
+58
View File
@@ -0,0 +1,58 @@
{
"post": {
"tags": [
"BulkSMS"
],
"summary": "Send Bulk SMS",
"description": "This request is used to send Bulk SMS messages to multiple customers. The max length of the array should equal 20. The API is hosted in FIRSTBANK and it is the HTTP wrapper for the real SMS sending interface.",
"operationId": "bulkSmsNotification",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/BulkSMSRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/BulkSMSRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/BulkSMSRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "Bulk SMS sent successfully",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/BulkSMSResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/BulkSMSResponse.json"
}
}
}
},
"400": {
"description": "Unsuccessful Response with Client Error"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"api_key": []
}
]
}
}
+10 -8
View File
@@ -4,8 +4,8 @@
"CollectLoan"
],
"summary": "Collect Loan Request",
"description": "Collect Loan Request",
"operationId": "CollectLoan",
"description": "This request is to collect money from user accounts. When request is received, FIRSTBANK should check all user accounts and collect as much as possible money to cover existing loan either partially or fully. In response, FIRSTBANK should return total amount that is actually collected from user accounts. First FBN collects body amount, then penal charge. If requested amount is not collected or collected partially FBN places a lien on user account. FBN places lien for body amount and penal charge separately.",
"operationId": "collectLoan",
"requestBody": {
"required": true,
"content": {
@@ -28,7 +28,7 @@
},
"responses": {
"200": {
"description": "CollectLoan Successful",
"description": "Loan Collection Successful",
"content": {
"application/json": {
"schema": {
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"api_key": []
}
]
}
}
}
+6 -2
View File
@@ -50,7 +50,11 @@
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"basic_auth": []
}
]
}
}
+10 -8
View File
@@ -4,8 +4,8 @@
"CustomerConsent"
],
"summary": "Customer Consent Request",
"description": "Customer Consent Request",
"operationId": "CustomerConsent",
"description": "This endpoint allows FirstBank to send customer consent requests to Simbrella",
"operationId": "customerConsent",
"requestBody": {
"required": true,
"content": {
@@ -28,7 +28,7 @@
},
"responses": {
"200": {
"description": "Successful",
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"basic_auth": []
}
]
}
}
}
+11 -9
View File
@@ -3,9 +3,9 @@
"tags": [
"Disbursement"
],
"summary": "Disbursement Request",
"description": "Disbursement Request",
"operationId": "Disbursement",
"summary": "Loan Disbursement Request",
"description": "This request should be executed as a simultaneous operation where loan provision and collection are executed together in same API call. If one of the operations is failed, the whole transaction should be rolled back.",
"operationId": "disbursement",
"requestBody": {
"required": true,
"content": {
@@ -28,7 +28,7 @@
},
"responses": {
"200": {
"description": "Disbursement Successful",
"description": "Disbursement request accepted",
"content": {
"application/json": {
"schema": {
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"api_key": []
}
]
}
}
}
+62
View File
@@ -0,0 +1,62 @@
{
"post": {
"tags": [
"EligibilityCheck"
],
"summary": "Check customer eligibility for loan products",
"description": "This endpoint is used by FirstBank to check if a customer is eligible for loan products and returns available offers",
"operationId": "eligibilityCheck",
"requestBody": {
"description": "Customer information for eligibility check",
"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"
},
"401": {
"description": "Authentication failed"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"basic_auth": []
}
]
}
}
-19
View File
@@ -1,19 +0,0 @@
{
"get": {
"tags": ["System"],
"summary": "System Health Check",
"description": "Returns the current health status of the system",
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/HealthCheckResponse.json"
}
}
}
}
}
}
}
+10 -8
View File
@@ -4,8 +4,8 @@
"LienCheck"
],
"summary": "Lien Check Request",
"description": "Lien Check Request",
"operationId": "LienCheck",
"description": "This method is to check the amount of the lien on a specific account",
"operationId": "lienCheck",
"requestBody": {
"required": true,
"content": {
@@ -28,7 +28,7 @@
},
"responses": {
"200": {
"description": "LienCheck Successful",
"description": "Lien check successful",
"content": {
"application/json": {
"schema": {
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"api_key": []
}
]
}
}
}
+65
View File
@@ -0,0 +1,65 @@
{
"post": {
"tags": [
"LoanStatus"
],
"summary": "Get information about customer's existing loans",
"description": "Loan Information Request to retrieve details about customer's existing loans",
"operationId": "loanInformation",
"requestBody": {
"description": "Customer information for loan details",
"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"
},
"401": {
"description": "Authentication failed"
},
"404": {
"description": "No loans found"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"basic_auth": []
}
]
}
}
@@ -0,0 +1,59 @@
{
"post": {
"tags": [
"NotificationCallback"
],
"summary": "Notification Callback",
"description": "This new feature will be used for informing Simbrella about status of the transactions that FBN have processed. Retry mechanism should be implemented by FirstBank in case of connection issues, sending notification should be repeated for 5 minutes in case of there is connection issues, after which Simbrella will try to check the status of transaction with New Transaction Check endpoint.",
"operationId": "notificationCallback",
"requestBody": {
"description": "Transaction status notification from FirstBank to Simbrella",
"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": "Notification received successfully",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/NotificationCallbackResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/NotificationCallbackResponse.json"
}
}
}
},
"400": {
"description": "Invalid request"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"basic_auth": []
}
]
}
}
+10 -8
View File
@@ -4,8 +4,8 @@
"PenalCharge"
],
"summary": "Penal Charge Request",
"description": "Penal Charge Request",
"operationId": "PenalCharge",
"description": "This request is used to charge customers for penalty as per existing debt",
"operationId": "penalCharge",
"requestBody": {
"required": true,
"content": {
@@ -28,7 +28,7 @@
},
"responses": {
"200": {
"description": "PenalCharge Successful",
"description": "Penal Charge Request Accepted",
"content": {
"application/json": {
"schema": {
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"api_key": []
}
]
}
}
}
+59
View File
@@ -0,0 +1,59 @@
{
"post": {
"tags": [
"ProvideLoan"
],
"summary": "Provide Loan Request",
"description": "This endpoint is used by FirstBank to request a loan provision for a customer. It allows FirstBank to specify the loan details including the amount, collection type, and loan type.",
"operationId": "provideLoan",
"requestBody": {
"description": "Loan provision request details",
"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": "Loan provision request processed successfully",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/ProvideLoanResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/ProvideLoanResponse.json"
}
}
}
},
"400": {
"description": "Invalid request"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"basic_auth": []
}
]
}
}
+8 -6
View File
@@ -4,7 +4,7 @@
"RACCheck"
],
"summary": "Risk Acceptance Criteria Check",
"description": "Check if a customer passes the Risk Acceptance Criteria defined by the bank",
"description": "This request is used to check if a customer passes the Risk Acceptance Criteria defined by the bank",
"operationId": "racCheck",
"requestBody": {
"required": true,
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"api_key": []
}
]
}
}
}
+65
View File
@@ -0,0 +1,65 @@
{
"post": {
"tags": [
"Repayment"
],
"summary": "Process a loan repayment request",
"description": "Repayment Request to initiate loan repayment",
"operationId": "repayment",
"requestBody": {
"description": "Repayment request details",
"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"
}
}
},
"required": true
},
"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"
},
"401": {
"description": "Authentication failed"
},
"404": {
"description": "Debt not found"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"basic_auth": []
}
]
}
}
+11 -9
View File
@@ -3,9 +3,9 @@
"tags": [
"RevokeEnableConsent"
],
"summary": "Revoke Enable Consent Request",
"description": "Revoke Enable Consent Request",
"operationId": "RevokeEnableConsent",
"summary": "Revoke or Enable Consent Request",
"description": "This endpoint is used to notify FirstBank about the processing of a customer consent request. It allows Simbrella to inform FirstBank when a customer's consent has been either enabled or revoked.",
"operationId": "revokeEnableConsent",
"requestBody": {
"required": true,
"content": {
@@ -28,7 +28,7 @@
},
"responses": {
"200": {
"description": "RevokeEnableConsent Successful",
"description": "Consent status update successful",
"content": {
"application/json": {
"schema": {
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"api_key": []
}
]
}
}
}
+58
View File
@@ -0,0 +1,58 @@
{
"post": {
"tags": [
"SMS"
],
"summary": "Send Single SMS",
"description": "This request is used to send a single SMS message to a customer. The API is hosted in FIRSTBANK and it is the HTTP wrapper for the real SMS sending interface.",
"operationId": "smsNotification",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/SMSRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/SMSRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/SMSRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "SMS sent successfully",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/SMSResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/SMSResponse.json"
}
}
}
},
"400": {
"description": "Unsuccessful Response with Client Error"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"api_key": []
}
]
}
}
+62
View File
@@ -0,0 +1,62 @@
{
"post": {
"tags": [
"SelectOffer"
],
"summary": "Send the offer the customer selected to Simbrella",
"description": "This method is used to send the offer the customer selected to Simbrella",
"operationId": "selectOffer",
"requestBody": {
"description": "Customer selected offer details",
"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"
},
"401": {
"description": "Authentication failed"
},
"500": {
"description": "Internal server error"
}
},
"security": [
{
"basic_auth": []
}
]
}
}
@@ -1,43 +1,43 @@
{
"post": {
"tags": [
"NewTransactionCheck"
"StatusCall"
],
"summary": "New Transaction Check Request",
"description": "New Transaction Check Request",
"operationId": "NewTransactionCheck",
"summary": "Status Call Request",
"description": "This will be used to check the status of a transaction by Simbrella to Firstabank if there is no initial response after 2mins.",
"operationId": "statusCall",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/NewTransactionCheckRequest.json"
"$ref": "../schemas/StatusCallRequest.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/NewTransactionCheckRequest.json"
"$ref": "../schemas/StatusCallRequest.json"
}
},
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "../schemas/NewTransactionCheckRequest.json"
"$ref": "../schemas/StatusCallRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "NewTransactionCheck Successful",
"description": "Transaction check successful",
"content": {
"application/json": {
"schema": {
"$ref": "../schemas/NewTransactionCheckResponse.json"
"$ref": "../schemas/StatusCallResponse.json"
}
},
"application/xml": {
"schema": {
"$ref": "../schemas/NewTransactionCheckResponse.json"
"$ref": "../schemas/StatusCallResponse.json"
}
}
}
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"api_key": []
}
]
}
}
}
+10 -8
View File
@@ -4,8 +4,8 @@
"TokenValidation"
],
"summary": "Token Validation Request",
"description": "Token Validation Request",
"operationId": "TokenValidation",
"description": "This method is used while users from FBN access Customer Care Portal. User will enter soft/hard token code. This will be captured and sent to this endpoint for validation.",
"operationId": "validateToken",
"requestBody": {
"required": true,
"content": {
@@ -28,7 +28,7 @@
},
"responses": {
"200": {
"description": "TokenValidation Successful",
"description": "Token validation successful",
"content": {
"application/json": {
"schema": {
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"api_key": []
}
]
}
}
}
+11 -9
View File
@@ -3,9 +3,9 @@
"tags": [
"TransactionVerify"
],
"summary": "Transaction Verify Request",
"description": "Transaction Verify Request",
"operationId": "TransactionVerify",
"summary": "Transaction Verification Request",
"description": "This request is to double check the response received from DisburseLoan and CollectLoan Synchronous APIs. This request is required to check transaction results on FIRSTBANK.",
"operationId": "transactionVerify",
"requestBody": {
"required": true,
"content": {
@@ -28,7 +28,7 @@
},
"responses": {
"200": {
"description": "TransactionVerify Successful",
"description": "Transaction Verification Successful",
"content": {
"application/json": {
"schema": {
@@ -45,12 +45,14 @@
"400": {
"description": "Invalid request"
},
"422": {
"description": "Validation exception"
},
"500": {
"description": "Internal server error"
}
}
},
"security": [
{
"api_key": []
}
]
}
}
}
-32
View File
@@ -1,32 +0,0 @@
{
"post": {
"tags": ["Authentication"],
"summary": "EcoBank Authentication",
"description": "Get bearer token from EcoBank",
"operationId": "authenticate",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/AuthenticationRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "Authentication Successful",
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/AuthenticationResponse.json"
}
}
}
},
"400": { "description": "Invalid request" },
"500": { "description": "Internal server error" }
}
}
}
-33
View File
@@ -1,33 +0,0 @@
{
"post": {
"tags": ["CollectLoan"],
"summary": "Collect Loan Repayment",
"description": "Collect repayment amount from EcoBank customer",
"operationId": "collectLoan",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/CollectLoanRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "Loan Collection Successful",
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/CollectLoanResponse.json"
}
}
}
},
"400": { "description": "Invalid request" },
"422": { "description": "Validation exception" },
"500": { "description": "Internal server error" }
}
}
}
@@ -1,33 +0,0 @@
{
"post": {
"tags": ["DebtClosureNotification"],
"summary": "Debt Closure Notification",
"description": "Notify EcoBank that debt has been fully repaid",
"operationId": "notifyDebtClosure",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/DebtClosureNotificationRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "Debt Closure Acknowledged",
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/DebtClosureNotificationResponse.json"
}
}
}
},
"400": { "description": "Invalid request" },
"422": { "description": "Validation exception" },
"500": { "description": "Internal server error" }
}
}
}
-33
View File
@@ -1,33 +0,0 @@
{
"post": {
"tags": ["Disbursement"],
"summary": "Loan Disbursement",
"description": "Disburse loan to EcoBank customer account",
"operationId": "disburseLoan",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/DisbursementRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "Disbursement Successful",
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/DisbursementResponse.json"
}
}
}
},
"400": { "description": "Invalid request" },
"422": { "description": "Validation exception" },
"500": { "description": "Internal server error" }
}
}
}
-33
View File
@@ -1,33 +0,0 @@
{
"post": {
"tags": ["SendSMS"],
"summary": "Send SMS Notification",
"description": "Send a message to one or more EcoBank customers",
"operationId": "sendSms",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/SendSMSRequest.json"
}
}
}
},
"responses": {
"200": {
"description": "SMS Sent Successfully",
"content": {
"application/json": {
"schema": {
"$ref": "../../schemas/eco/SendSMSResponse.json"
}
}
}
},
"400": { "description": "Invalid request" },
"422": { "description": "Validation exception" },
"500": { "description": "Internal server error" }
}
}
}
+32
View File
@@ -0,0 +1,32 @@
{
"type": "array",
"maxItems": 20,
"items": {
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "Message to send to customer",
"example": "This is a test message for SMS request method."
},
"dest": {
"type": "string",
"description": "Phone Number in international format",
"example": "+2348039409144"
},
"unicode": {
"type": "boolean",
"description": "Character encoding standard (set as True for bulk SMS)",
"example": true
}
},
"required": [
"text",
"dest",
"unicode"
]
},
"xml": {
"name": "BulkSMSRequest"
}
}
+34
View File
@@ -0,0 +1,34 @@
{
"type": "object",
"properties": {
"data": {
"type": "string",
"description": "Any additional data in response",
"example": ""
},
"statusCode": {
"type": "integer",
"description": "Result code of executed process (200 = Success)",
"example": 200
},
"IsSuccessful": {
"type": "boolean",
"description": "An Indicator that the process was successful or not",
"example": true
},
"errorMessage": {
"type": "string",
"description": "Description of status code if process is failed, null if successful",
"example": null
}
},
"required": [
"data",
"statusCode",
"IsSuccessful",
"errorMessage"
],
"xml": {
"name": "BulkSMSResponse"
}
}
+81 -64
View File
@@ -1,67 +1,84 @@
{
"type": "object",
"properties": {
"transactionId": {
"type": "string",
"example": "T002"
"type": "object",
"properties": {
"transactionId": {
"type": "string",
"description": "Unique identifier of transaction in Simbrella system",
"example": "T002"
},
"fbnTransactionId": {
"type": "string",
"description": "Unique id of the transaction received from FBN in Eligibility or Provision requests",
"example": "Tr201712RK9232P115"
},
"debtId": {
"type": "string",
"description": "Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)",
"example": "273194670"
},
"customerId": {
"type": "string",
"description": "Unique identifier of a user",
"example": "CN621868"
},
"accountId": {
"type": "string",
"description": "Specific identifier of a user's account",
"example": "2017821799"
},
"productId": {
"type": "string",
"description": "Identifier of a product for which collection to be made",
"example": "101"
},
"collectAmount": {
"type": "number",
"format": "double",
"description": "Amount to be collected from user's account (penalCharge is not included)",
"example": 80000.0
},
"penalCharge": {
"type": "number",
"format": "double",
"description": "Amount of penalty to be collected from user's account. If there is no penalty, amount is '0'",
"example": 0.0
},
"collectionMethod": {
"type": "integer",
"description": "1 - on deposit of salary; 2 - on due date; 3 - initiated by user",
"enum": [1, 2, 3],
"example": 1
},
"lienAmount": {
"type": "number",
"format": "double",
"description": "Aggregated (summed up) lien amount",
"example": 80000.0
},
"countryId": {
"type": "string",
"description": "Set to static value '01'",
"example": "01"
},
"comment": {
"type": "string",
"description": "Any additional comment for provided loan operation",
"example": "Testing CollectionLoanRequest"
}
},
"fbnTransactionId": {
"type": "string",
"example": "FBN20231123"
},
"debtId": {
"type": "string",
"example": "273194670"
},
"customerId": {
"type": "string",
"example": "CN621868"
},
"accountId": {
"type": "string",
"example": "2017821799"
},
"productId": {
"type": "string",
"example": "101"
},
"collectAmount": {
"type": "number",
"format": "double",
"example": 80000.0
},
"penalCharge": {
"type": "number",
"format": "double",
"example": 0.0
},
"collectionMethod": {
"type": "string",
"example": "string"
},
"lienAmount": {
"type": "number",
"format": "double",
"example": 80000.0
},
"countryId": {
"type": "string",
"example": "01"
},
"comment": {
"type": "string",
"example": "Testing CollectionLoanRequest"
},
"channel": {
"type": "string",
"example": "string"
"required": [
"transactionId",
"fbnTransactionId",
"debtId",
"customerId",
"accountId",
"productId",
"collectAmount",
"collectionMethod",
"lienAmount",
"countryId"
],
"xml": {
"name": "CollectLoanRequest"
}
},
"required": [
"collectAmount",
"penalCharge",
"lienAmount"
],
"additionalProperties": false
}
}
+80 -66
View File
@@ -1,69 +1,83 @@
{
"type": "object",
"properties": {
"responseCode": {
"type": "string",
"nullable": true,
"example": "00"
"type": "object",
"properties": {
"transactionId": {
"type": "string",
"description": "Unique identifier of transaction in Simbrella system",
"example": "T002"
},
"debtId": {
"type": "string",
"description": "Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)",
"example": "273194670"
},
"customerId": {
"type": "string",
"description": "Unique identifier of a user",
"example": "CN621868"
},
"accountId": {
"type": "string",
"description": "Specific identifier of a user's account",
"example": "2017821799"
},
"productId": {
"type": "string",
"description": "Identifier of a product for which collection to be made",
"example": "101"
},
"collectAmount": {
"type": "number",
"format": "double",
"description": "Amount collected from user's account (penalCharge is not included)",
"example": 60000.0
},
"penalCharge": {
"type": "number",
"format": "double",
"description": "Amount of penalty collected from user's account. If there is no penalty, amount is '0'",
"example": 0.0
},
"lienAmount": {
"type": "number",
"format": "double",
"description": "Aggregated (summed up) lien amount",
"example": 20000.0
},
"countryId": {
"type": "string",
"description": "Set to static value '01'",
"example": "01"
},
"comment": {
"type": "string",
"description": "Any additional comment for provided loan operation",
"example": "Testing CollectionLoanRequest"
},
"resultCode": {
"type": "string",
"description": "Result code of executed transaction, e.g. (00 Success etc.) see result codes table",
"example": "00"
},
"resultDescription": {
"type": "string",
"description": "Description of provided result code",
"example": "Loan Collection Successful"
}
},
"responseDescr": {
"type": "string",
"nullable": true,
"example": "Success"
},
"fullDescription": {
"type": "string",
"nullable": true,
"example": "Loan Collection Successful"
},
"transactionId": {
"type": "string",
"nullable": true,
"example": "T002"
},
"debtId": {
"type": "string",
"nullable": true,
"example": "273194670"
},
"customerId": {
"type": "string",
"nullable": true,
"example": "CN621868"
},
"accountId": {
"type": "string",
"nullable": true,
"example": "2017821799"
},
"productId": {
"type": "string",
"nullable": true,
"example": "101"
},
"amountCollected": {
"type": "number",
"format": "double",
"example": 60000.0
},
"countryId": {
"type": "string",
"nullable": true,
"example": "01"
},
"comment": {
"type": "string",
"nullable": true,
"example": "Testing CollectionLoanRequest"
},
"responseMessage": {
"type": "string",
"nullable": true,
"example": "Loan processed successfully"
"required": [
"transactionId",
"debtId",
"customerId",
"accountId",
"productId",
"collectAmount",
"penalCharge",
"lienAmount",
"resultCode",
"resultDescription"
],
"xml": {
"name": "CollectLoanResponse"
}
},
"required": [
"amountCollected"
],
"additionalProperties": false
}
}
@@ -1,34 +1,37 @@
{
"type": "object",
"properties": {
"$type": {
"type": "string",
"example": "CustomerConsentRequest"
},
"transactionId": {
"type": "string",
"description": "Unique identifier of transaction in FIRSTBANK system",
"example": "20171209232177"
},
"customerId": {
"type": "string",
"description": "Unique identifier of a customer",
"example": "CN621868"
},
"accountId": {
"type": "string",
"description": "Specific identifier of a user's account",
"example": "ACN8263457"
},
"requestTime": {
"type": "string",
"format": "date-time",
"description": "Date and time of consent request",
"example": "2019-10-18 14:26:21.063"
},
"consentType": {
"type": "string",
"description": "Type of consent: 'Enable' or 'Revoke'",
"enum": ["Enable", "Revoke"],
"example": "Revoke"
},
"channel": {
"type": "string",
"example": "USSD"
"description": "Request channel: 'USSD' or 'APP'",
"example": "100"
}
},
"required": [
@@ -39,5 +42,8 @@
"requestTime",
"consentType",
"channel"
]
],
"xml": {
"name": "CustomerConsentRequest"
}
}
@@ -3,15 +3,20 @@
"properties": {
"resultCode": {
"type": "string",
"description": "Result code of executed transaction, e.g. (00 Success etc.) see result codes table",
"example": "00"
},
"resultDescription": {
"type": "string",
"description": "Description of provided result code",
"example": "Request is received"
}
},
"required": [
"resultCode",
"resultDescription"
]
],
"xml": {
"name": "CustomerConsentResponse"
}
}
+121 -74
View File
@@ -1,78 +1,125 @@
{
"type": "object",
"properties": {
"transactionId": {
"type": "string",
"example": "T001",
"nullable": true
"type": "object",
"properties": {
"requestId": {
"type": "string",
"description": "Unique identifier of request",
"example": "R02802"
},
"countryCode": {
"type": "string",
"description": "Unique country code. Please refer to Country Codes table",
"example": "NGR"
},
"transactionId": {
"type": "string",
"description": "Unique identifier of transaction in Simbrella system",
"example": "Tr201712RK9232P115"
},
"debtId": {
"type": "string",
"description": "Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)",
"example": "273194670"
},
"customerId": {
"type": "string",
"description": "Unique identifier of a user",
"example": "CN621868"
},
"accountId": {
"type": "string",
"description": "Specific identifier of a user's account",
"example": "2017821799"
},
"productId": {
"type": "string",
"description": "Identifier of a product to be provided to a user",
"example": "101"
},
"provideAmount": {
"type": "number",
"format": "double",
"description": "Amount of loan (including service fee) to be provided on a specific account of a user",
"example": 100000.0
},
"totalFees": {
"type": "number",
"format": "double",
"description": "Total amount of all fees combined",
"example": 7075
},
"feesDetails": {
"type": "object",
"description": "Detailed breakdown of all fees",
"properties": {
"collectAmountInterest": {
"type": "number",
"format": "double",
"description": "Interest Amount to be collected immediately after loan is provided (Only for 30 days)",
"example": 5000
},
"collectAmountMgtFee": {
"type": "number",
"format": "double",
"description": "Management Fee Amount to be collected immediately after loan is provided",
"example": 1000
},
"collectAmountInsurance": {
"type": "number",
"format": "double",
"description": "Insurance Amount to be collected immediately after loan is provided",
"example": 1000
},
"collectAmountVAT": {
"type": "number",
"format": "double",
"description": "VAT Amount to be collected immediately after loan is provided",
"example": 75
}
},
"required": [
"collectAmountInterest",
"collectAmountMgtFee",
"collectAmountInsurance",
"collectAmountVAT"
]
},
"countryId": {
"type": "string",
"description": "Set to static value '01'",
"example": "01"
}
},
"fbnTransactionId": {
"type": "string",
"example": "Tr201712RK9232P115",
"nullable": true
"required": [
"requestId",
"countryCode",
"transactionId",
"debtId",
"customerId",
"accountId",
"productId",
"provideAmount",
"totalFees",
"feesDetails"
],
"example": {
"requestId": "R02802",
"countryCode": "NGR",
"transactionId": "Tr201712RK9232P115",
"debtId": "273194670",
"customerId": "CN621868",
"accountId": "2017821799",
"productId": "101",
"provideAmount": 100000.0,
"totalFees": 7075,
"feesDetails": {
"collectAmountInterest": 5000,
"collectAmountMgtFee": 1000,
"collectAmountInsurance": 1000,
"collectAmountVAT": 75
}
},
"debtId": {
"type": "string",
"example": "273194670",
"nullable": true
},
"customerId": {
"type": "string",
"example": "CN621868",
"nullable": true
},
"accountId": {
"type": "string",
"example": "2017821799",
"nullable": true
},
"productId": {
"type": "string",
"example": "101",
"nullable": true
},
"provideAmount": {
"type": "number",
"format": "double",
"example": 100000.0
},
"collectAmountInterest": {
"type": "number",
"format": "double",
"example": 5000.0
},
"collectAmountMgtFee": {
"type": "number",
"format": "double",
"example": 1000.0
},
"collectAmountInsurance": {
"type": "number",
"format": "double",
"example": 1000.0
},
"collectAmountVAT": {
"type": "number",
"format": "double",
"example": 75.0
},
"countryId": {
"type": "string",
"example": "01",
"nullable": true
},
"comment": {
"type": "string",
"example": "Testing LoanRequest",
"nullable": true
"xml": {
"name": "DisbursementRequest"
}
},
"required": [
"provideAmount",
"collectAmountInterest",
"collectAmountMgtFee",
"collectAmountInsurance",
"collectAmountVAT"
],
"additionalProperties": false
}
}
+130 -94
View File
@@ -1,98 +1,134 @@
{
"type": "object",
"properties": {
"transactionId": {
"type": "string",
"example": "T001",
"nullable": true
"type": "object",
"properties": {
"requestId": {
"type": "string",
"description": "Unique identifier of request",
"example": "R02802"
},
"countryCode": {
"type": "string",
"description": "Unique country code.",
"example": "NGR"
},
"transactionId": {
"type": "string",
"description": "Unique ID of customers USSD session. Must be consistent throughout whole USSD journey",
"example": "Tr201712RK9232P115"
},
"debtId": {
"type": "string",
"description": "Unique identifier of a loan in Simbrella system that is going to be collected (it correlates with provision request)",
"example": "273194670"
},
"customerId": {
"type": "string",
"description": "Unique identifier of a user",
"example": "CN621868"
},
"accountId": {
"type": "string",
"description": "Specific identifier of a user's account",
"example": "2017821799"
},
"productId": {
"type": "string",
"description": "Identifier of a product to be provided to a user",
"example": "101"
},
"provideAmount": {
"type": "number",
"format": "double",
"description": "Amount of loan (including service fee) to be provided on a specific account of a user",
"example": 100000.0
},
"totalFees": {
"type": "number",
"format": "double",
"description": "Total amount of all fees combined",
"example": 7075
},
"feesDetails": {
"type": "object",
"description": "Detailed breakdown of all fees",
"properties": {
"collectAmountInterest": {
"type": "number",
"format": "double",
"description": "Interest Amount to be collected immediately after loan is provided (Only for 30 days)",
"example": 5000
},
"collectAmountMgtFee": {
"type": "number",
"format": "double",
"description": "Management Fee Amount to be collected immediately after loan is provided",
"example": 1000
},
"collectAmountInsurance": {
"type": "number",
"format": "double",
"description": "Insurance Amount to be collected immediately after loan is provided",
"example": 1000
},
"collectAmountVAT": {
"type": "number",
"format": "double",
"description": "VAT Amount to be collected immediately after loan is provided",
"example": 75
}
},
"required": [
"collectAmountInterest",
"collectAmountMgtFee",
"collectAmountInsurance",
"collectAmountVAT"
]
},
"resultCode": {
"type": "string",
"description": "Result code of executed transaction, e.g. (00 Success etc.) see result codes table",
"example": "00"
},
"resultDescription": {
"type": "string",
"description": "Description of provided result code",
"example": "Loan Request Completed Successfully!"
}
},
"fbnTransactionId": {
"type": "string",
"example": "Tr201712RK9232P115",
"nullable": true
"required": [
"requestId",
"countryCode",
"transactionId",
"debtId",
"customerId",
"accountId",
"productId",
"provideAmount",
"totalFees",
"feesDetails",
"resultCode",
"resultDescription"
],
"example": {
"requestId": "R02802",
"countryCode": "NGR",
"transactionId": "Tr201712RK9232P115",
"debtId": "273194670",
"customerId": "CN621868",
"accountId": "2017821799",
"productId": "101",
"provideAmount": 100000.0,
"totalFees": 7075,
"feesDetails": {
"collectAmountInterest": 5000,
"collectAmountMgtFee": 1000,
"collectAmountInsurance": 1000,
"collectAmountVAT": 75
},
"resultCode": "00",
"resultDescription": "Loan Request Completed Successfully!"
},
"debtId": {
"type": "string",
"example": "273194670",
"nullable": true
},
"customerId": {
"type": "string",
"example": "CN621868",
"nullable": true
},
"accountId": {
"type": "string",
"example": "2017821799",
"nullable": true
},
"productId": {
"type": "string",
"example": "101",
"nullable": true
},
"provideAmount": {
"type": "number",
"format": "double",
"example": 100000.0
},
"collectAmountInterest": {
"type": "number",
"format": "double",
"example": 5000.0
},
"collectAmountMgtFee": {
"type": "number",
"format": "double",
"example": 1000.0
},
"collectAmountInsurance": {
"type": "number",
"format": "double",
"example": 1000.0
},
"collectAmountVAT": {
"type": "number",
"format": "double",
"example": 75.0
},
"countryId": {
"type": "string",
"example": "01",
"nullable": true
},
"responseCode": {
"type": "string",
"example": "00",
"nullable": true
},
"responseMessage": {
"type": "string",
"example": "Loan Request Completed Successfully!",
"nullable": true
},
"disburseDate": {
"type": "string",
"format": "date-time",
"example": "2023-10-01T12:00:00Z",
"nullable": true
},
"disburseResult": {
"type": "string",
"example": "00",
"nullable": true
},
"disburseDescription": {
"type": "string",
"example": "Loan Request Completed Successfully!",
"nullable": true
"xml": {
"name": "DisbursementResponse"
}
},
"required": [
"provideAmount",
"collectAmountInterest",
"collectAmountMgtFee",
"collectAmountInsurance",
"collectAmountVAT"
]
}
}
@@ -0,0 +1,45 @@
{
"type": "object",
"required": [
"transactionId",
"countryCode",
"customerId",
"accountId",
"channel"
],
"properties": {
"transactionId": {
"type": "string",
"description": "Unique identifier of transaction. This transaction Id must be consistent across all platforms",
"example": "Tr201712RK9232P115"
},
"countryCode": {
"type": "string",
"description": "Unique country code. Please refer to Country Codes table",
"example": "NGR"
},
"customerId": {
"type": "string",
"description": "Unique identifier of a customer",
"example": "CN621868"
},
"accountId": {
"type": "string",
"description": "Specific identifier of a user's account",
"example": "ACN8263457"
},
"msisdn": {
"type": "string",
"description": "User's mobile number in an international format",
"example": "8012345678"
},
"channel": {
"type": "string",
"description": "Request channel: USSD, MobApp, or Web - type Channel",
"example": "100"
}
},
"xml": {
"name": "EligibilityCheckRequest"
}
}
@@ -0,0 +1,105 @@
{
"type": "object",
"required": [
"customerId",
"transactionId",
"countryCode",
"eligibleOffers",
"resultCode",
"resultDescription"
],
"properties": {
"customerId": {
"type": "string",
"description": "Unique identifier of a customer",
"example": "CN621868"
},
"transactionId": {
"type": "string",
"description": "Unique identifier of transaction. This transaction Id must be consistent across all platforms",
"example": "Tr201712RK9232P115"
},
"countryCode": {
"type": "string",
"description": "Unique country code. Please refer to “Country Codes” table",
"example": "NGR"
},
"msisdn": {
"type": "string",
"description": "User's mobile number in an international format",
"example": "2348012345678"
},
"eligibleOffers": {
"type": "array",
"description": "Array of loan offers the customer is eligible for",
"items": {
"type": "object",
"properties": {
"offerId": {
"type": "integer",
"description": "Offer identifier",
"example": 101
},
"minAmount": {
"type": "number",
"format": "double",
"description": "Minimum loan amount",
"example": 5000
},
"maxAmount": {
"type": "number",
"format": "double",
"description": "Maximum loan amount",
"example": 20000
},
"productId": {
"type": "integer",
"description": "Product identifier",
"example": 2030101
},
"tenor": {
"type": "integer",
"description": "Loan tenor in days",
"example": 30
}
},
"required": [
"offerId",
"minAmount",
"maxAmount",
"productId",
"tenor"
]
},
"example": [
{
"offerId": 101,
"minAmount": 5000,
"maxAmount": 20000,
"productId": 2030,
"tenor": 30
},
{
"offerId": 102,
"minAmount": 20000,
"maxAmount": 50000,
"productId": 2090,
"tenor": 90
}
]
},
"resultCode": {
"type": "string",
"description": "Result code of executed transaction, e.g. (00 Success etc.) see result codes table",
"example": "00"
},
"resultDescription": {
"type": "string",
"description": "Textual description of provided result code. In case if customer is not eligible (where resultCode is «05») this parameter contains end-user message that can be show directly to the customer.",
"example": "Successful"
}
},
"xml": {
"name": "EligibilityCheckResponse"
}
}
@@ -1,17 +0,0 @@
{
"type": "object",
"properties": {
"status": {
"type": "string",
"example": "Active"
},
"responseCode": {
"type": "string",
"example": "00"
},
"responseMessage": {
"type": "string",
"example": "Successful"
}
}
}

Some files were not shown because too many files have changed in this diff Show More