From 038c5323b0950132805f88f92a993a3d537cd718 Mon Sep 17 00:00:00 2001 From: VivianDee <115420678+VivianDee@users.noreply.github.com> Date: Wed, 30 Jul 2025 05:16:47 +0100 Subject: [PATCH] [add]: eco endpoints and dummy responses --- .DS_Store | Bin 6148 -> 6148 bytes README.md | 7 +- app/__init__.py | 29 +++- app/config.py | 17 ++- app/eco/enums/__init__.py | 1 + app/eco/enums/installment_status.py | 7 + app/eco/enums/loan_status.py | 8 ++ app/eco/enums/transaction_type.py | 7 + app/eco/helpers/response_helper.py | 112 +++++++++++++++ app/eco/routes/__init__.py | 1 + app/eco/routes/routes.py | 87 ++++++++++++ app/eco/schemas/__init__.py | 5 + app/eco/schemas/authorization.py | 6 + app/eco/schemas/collect_loan.py | 13 ++ app/eco/schemas/debt_closure_notification.py | 11 ++ app/eco/schemas/disbursement.py | 15 ++ app/eco/schemas/send_sms.py | 10 ++ app/eco/services/__init__.py | 5 + app/eco/services/authorization.py | 102 ++++++++++++++ app/eco/services/base_service.py | 32 +++++ app/eco/services/collect_loan.py | 33 +++++ app/eco/services/debt_closure_notification.py | 27 ++++ app/eco/services/disbursement.py | 32 +++++ app/eco/services/send_sms.py | 31 +++++ app/swagger/eco_digifi_swagger.json | 128 ++++++++++++++++++ app/swagger/paths/eco/Authentication.json | 32 +++++ app/swagger/paths/eco/CollectLoan.json | 33 +++++ .../paths/eco/DebtClosureNotification.json | 33 +++++ app/swagger/paths/eco/Disbursement.json | 33 +++++ app/swagger/paths/eco/SendSMS.json | 33 +++++ .../schemas/eco/AuthenticationRequest.json | 12 ++ .../schemas/eco/AuthenticationResponse.json | 14 ++ .../schemas/eco/CollectLoanRequest.json | 13 ++ .../schemas/eco/CollectLoanResponse.json | 9 ++ .../eco/DebtClosureNotificationRequest.json | 11 ++ .../eco/DebtClosureNotificationResponse.json | 7 + .../schemas/eco/DisbursementRequest.json | 15 ++ .../schemas/eco/DisbursementResponse.json | 8 ++ app/swagger/schemas/eco/SendSMSRequest.json | 13 ++ app/swagger/schemas/eco/SendSMSResponse.json | 11 ++ requirements.txt | 2 + 41 files changed, 998 insertions(+), 7 deletions(-) create mode 100644 app/eco/enums/__init__.py create mode 100644 app/eco/enums/installment_status.py create mode 100644 app/eco/enums/loan_status.py create mode 100644 app/eco/enums/transaction_type.py create mode 100644 app/eco/helpers/response_helper.py create mode 100644 app/eco/routes/__init__.py create mode 100644 app/eco/routes/routes.py create mode 100644 app/eco/schemas/__init__.py create mode 100644 app/eco/schemas/authorization.py create mode 100644 app/eco/schemas/collect_loan.py create mode 100644 app/eco/schemas/debt_closure_notification.py create mode 100644 app/eco/schemas/disbursement.py create mode 100644 app/eco/schemas/send_sms.py create mode 100644 app/eco/services/__init__.py create mode 100644 app/eco/services/authorization.py create mode 100644 app/eco/services/base_service.py create mode 100644 app/eco/services/collect_loan.py create mode 100644 app/eco/services/debt_closure_notification.py create mode 100644 app/eco/services/disbursement.py create mode 100644 app/eco/services/send_sms.py create mode 100644 app/swagger/eco_digifi_swagger.json create mode 100644 app/swagger/paths/eco/Authentication.json create mode 100644 app/swagger/paths/eco/CollectLoan.json create mode 100644 app/swagger/paths/eco/DebtClosureNotification.json create mode 100644 app/swagger/paths/eco/Disbursement.json create mode 100644 app/swagger/paths/eco/SendSMS.json create mode 100644 app/swagger/schemas/eco/AuthenticationRequest.json create mode 100644 app/swagger/schemas/eco/AuthenticationResponse.json create mode 100644 app/swagger/schemas/eco/CollectLoanRequest.json create mode 100644 app/swagger/schemas/eco/CollectLoanResponse.json create mode 100644 app/swagger/schemas/eco/DebtClosureNotificationRequest.json create mode 100644 app/swagger/schemas/eco/DebtClosureNotificationResponse.json create mode 100644 app/swagger/schemas/eco/DisbursementRequest.json create mode 100644 app/swagger/schemas/eco/DisbursementResponse.json create mode 100644 app/swagger/schemas/eco/SendSMSRequest.json create mode 100644 app/swagger/schemas/eco/SendSMSResponse.json diff --git a/.DS_Store b/.DS_Store index e81c242592628868a41ba832ff3693730f757c78..42c677d31de85f370a0a32eb9b39d010dcf996f2 100644 GIT binary patch literal 6148 zcmeHKJ#Q015PgenVZ}{~M1msHRVgF6Om|o&f4~i*!SNkQES+^H#S|1s_ah=&_zj4L zDg`1)u4pKeCN&Zz9lY7y#Jjo}DxxTwv3B3xeC*7<)9rWxn8B;O53B>|atOB9INcy( zm(h?1Ub9IwvPN;(A7$mNYIv$b8Bhl9A_Ma6wy}dlOfiqX-;Ix1Xq%P8;iM=h)OEiv zEy`Z(Emm2f%8#>R zQkF%aib`&6pDvxl5_g}!HH%-iM88y6Qqvlh(6zgI3ws!05aq+^fz4+vVZQg{i>p`V zH4C*CjhSUYs#Fg7#S@tKW3p%|N;`oy}!qz-jf29$xA zftI^nm;V2B_4z*z(mQ298Ms#rnD%fq9Pp8RZ*4rB^xA}D%poFvwL=@i$+u&BA+7ik bhZWiqxge$AjHF;Uo 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) \ No newline at end of file diff --git a/app/eco/routes/__init__.py b/app/eco/routes/__init__.py new file mode 100644 index 0000000..4b3e6c4 --- /dev/null +++ b/app/eco/routes/__init__.py @@ -0,0 +1 @@ +from .routes import eco diff --git a/app/eco/routes/routes.py b/app/eco/routes/routes.py new file mode 100644 index 0000000..26d3734 --- /dev/null +++ b/app/eco/routes/routes.py @@ -0,0 +1,87 @@ +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/") +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 \ No newline at end of file diff --git a/app/eco/schemas/__init__.py b/app/eco/schemas/__init__.py new file mode 100644 index 0000000..591a1da --- /dev/null +++ b/app/eco/schemas/__init__.py @@ -0,0 +1,5 @@ +from .authorization import AuthorizeRequestSchema +from .disbursement import DisbursementSchema +from .debt_closure_notification import DebtClosureNotificationSchema +from .send_sms import SendSmsSchema +from .collect_loan import CollectLoanSchema \ No newline at end of file diff --git a/app/eco/schemas/authorization.py b/app/eco/schemas/authorization.py new file mode 100644 index 0000000..785dd2b --- /dev/null +++ b/app/eco/schemas/authorization.py @@ -0,0 +1,6 @@ +from marshmallow import Schema, fields + + +class AuthorizeRequestSchema(Schema): + username = fields.Str(required=True) + password = fields.Str(required=True) diff --git a/app/eco/schemas/collect_loan.py b/app/eco/schemas/collect_loan.py new file mode 100644 index 0000000..94f51ab --- /dev/null +++ b/app/eco/schemas/collect_loan.py @@ -0,0 +1,13 @@ +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 \ No newline at end of file diff --git a/app/eco/schemas/debt_closure_notification.py b/app/eco/schemas/debt_closure_notification.py new file mode 100644 index 0000000..b3564b3 --- /dev/null +++ b/app/eco/schemas/debt_closure_notification.py @@ -0,0 +1,11 @@ +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 diff --git a/app/eco/schemas/disbursement.py b/app/eco/schemas/disbursement.py new file mode 100644 index 0000000..93d8574 --- /dev/null +++ b/app/eco/schemas/disbursement.py @@ -0,0 +1,15 @@ +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 \ No newline at end of file diff --git a/app/eco/schemas/send_sms.py b/app/eco/schemas/send_sms.py new file mode 100644 index 0000000..4c1302d --- /dev/null +++ b/app/eco/schemas/send_sms.py @@ -0,0 +1,10 @@ +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 \ No newline at end of file diff --git a/app/eco/services/__init__.py b/app/eco/services/__init__.py new file mode 100644 index 0000000..5c31e3b --- /dev/null +++ b/app/eco/services/__init__.py @@ -0,0 +1,5 @@ +from .authorization import AuthorizationService +from .disbursement import DisbursementService +from .debt_closure_notification import DebtClosureNotificationService +from .send_sms import SendSMSService +from .collect_loan import CollectLoanService diff --git a/app/eco/services/authorization.py b/app/eco/services/authorization.py new file mode 100644 index 0000000..7a7c04d --- /dev/null +++ b/app/eco/services/authorization.py @@ -0,0 +1,102 @@ +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}" + ) diff --git a/app/eco/services/base_service.py b/app/eco/services/base_service.py new file mode 100644 index 0000000..ca39ecb --- /dev/null +++ b/app/eco/services/base_service.py @@ -0,0 +1,32 @@ +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, + # ) diff --git a/app/eco/services/collect_loan.py b/app/eco/services/collect_loan.py new file mode 100644 index 0000000..008a0a4 --- /dev/null +++ b/app/eco/services/collect_loan.py @@ -0,0 +1,33 @@ +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() diff --git a/app/eco/services/debt_closure_notification.py b/app/eco/services/debt_closure_notification.py new file mode 100644 index 0000000..3aa3204 --- /dev/null +++ b/app/eco/services/debt_closure_notification.py @@ -0,0 +1,27 @@ +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() diff --git a/app/eco/services/disbursement.py b/app/eco/services/disbursement.py new file mode 100644 index 0000000..efd038e --- /dev/null +++ b/app/eco/services/disbursement.py @@ -0,0 +1,32 @@ +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() diff --git a/app/eco/services/send_sms.py b/app/eco/services/send_sms.py new file mode 100644 index 0000000..245fb33 --- /dev/null +++ b/app/eco/services/send_sms.py @@ -0,0 +1,31 @@ +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() diff --git a/app/swagger/eco_digifi_swagger.json b/app/swagger/eco_digifi_swagger.json new file mode 100644 index 0000000..1d7a4e0 --- /dev/null +++ b/app/swagger/eco_digifi_swagger.json @@ -0,0 +1,128 @@ +{ + "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": "./schemas/eco/AuthenticationRequest.json" + }, + "AuthenticationResponse": { + "$ref": "./schemas/eco/AuthenticationResponse.json" + }, + "DebtClosureNotificationRequest": { + "$ref": "./schemas/eco/DebtClosureNotificationRequest.json" + }, + "DebtClosureNotificationResponse": { + "$ref": "./schemas/eco/DebtClosureNotificationResponse.json" + }, + "SendSMSRequest": { + "$ref": "./schemas/eco/SendSMSRequest.json" + }, + "SendSMSResponse": { + "$ref": "./schemas/eco/SendSMSResponse.json" + } + }, + "securitySchemes": { + "basicAuth": { + "type": "http", + "scheme": "basic" + }, + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + }, + "security": [ + { + "basicAuth": [], + "bearerAuth": [] + } + ] +} \ No newline at end of file diff --git a/app/swagger/paths/eco/Authentication.json b/app/swagger/paths/eco/Authentication.json new file mode 100644 index 0000000..89cb05f --- /dev/null +++ b/app/swagger/paths/eco/Authentication.json @@ -0,0 +1,32 @@ +{ + "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" } + } + } +} diff --git a/app/swagger/paths/eco/CollectLoan.json b/app/swagger/paths/eco/CollectLoan.json new file mode 100644 index 0000000..733f54c --- /dev/null +++ b/app/swagger/paths/eco/CollectLoan.json @@ -0,0 +1,33 @@ +{ + "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" } + } + } +} diff --git a/app/swagger/paths/eco/DebtClosureNotification.json b/app/swagger/paths/eco/DebtClosureNotification.json new file mode 100644 index 0000000..b051cc3 --- /dev/null +++ b/app/swagger/paths/eco/DebtClosureNotification.json @@ -0,0 +1,33 @@ +{ + "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" } + } + } +} diff --git a/app/swagger/paths/eco/Disbursement.json b/app/swagger/paths/eco/Disbursement.json new file mode 100644 index 0000000..efaf8d8 --- /dev/null +++ b/app/swagger/paths/eco/Disbursement.json @@ -0,0 +1,33 @@ +{ + "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" } + } + } +} diff --git a/app/swagger/paths/eco/SendSMS.json b/app/swagger/paths/eco/SendSMS.json new file mode 100644 index 0000000..b1234bb --- /dev/null +++ b/app/swagger/paths/eco/SendSMS.json @@ -0,0 +1,33 @@ +{ + "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" } + } + } +} diff --git a/app/swagger/schemas/eco/AuthenticationRequest.json b/app/swagger/schemas/eco/AuthenticationRequest.json new file mode 100644 index 0000000..20a0ee6 --- /dev/null +++ b/app/swagger/schemas/eco/AuthenticationRequest.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "required": ["username", "password"], + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + } + } +} diff --git a/app/swagger/schemas/eco/AuthenticationResponse.json b/app/swagger/schemas/eco/AuthenticationResponse.json new file mode 100644 index 0000000..6441ec0 --- /dev/null +++ b/app/swagger/schemas/eco/AuthenticationResponse.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "properties": { + "resultCode": { + "type": "string" + }, + "resultDescription": { + "type": "string" + }, + "token": { + "type": "string" + } + } +} diff --git a/app/swagger/schemas/eco/CollectLoanRequest.json b/app/swagger/schemas/eco/CollectLoanRequest.json new file mode 100644 index 0000000..b56a42c --- /dev/null +++ b/app/swagger/schemas/eco/CollectLoanRequest.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "required": ["requestId", "affiliateCode", "debtId", "principal", "interest", "penalty", "collectAmount"], + "properties": { + "requestId": { "type": "string" }, + "affiliateCode": { "type": "string" }, + "debtId": { "type": "integer" }, + "principal": { "type": "number" }, + "interest": { "type": "number" }, + "penalty": { "type": "number" }, + "collectAmount": { "type": "number" } + } +} diff --git a/app/swagger/schemas/eco/CollectLoanResponse.json b/app/swagger/schemas/eco/CollectLoanResponse.json new file mode 100644 index 0000000..6a1d458 --- /dev/null +++ b/app/swagger/schemas/eco/CollectLoanResponse.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "properties": { + "transactionId": { "type": "string" }, + "amountCollected": { "type": "number" }, + "resultCode": { "type": "integer" }, + "resultDescription": { "type": "string" } + } +} diff --git a/app/swagger/schemas/eco/DebtClosureNotificationRequest.json b/app/swagger/schemas/eco/DebtClosureNotificationRequest.json new file mode 100644 index 0000000..3df3242 --- /dev/null +++ b/app/swagger/schemas/eco/DebtClosureNotificationRequest.json @@ -0,0 +1,11 @@ +{ + "type": "object", + "required": ["requestId", "affiliateCode", "customerId", "accountId", "debtId"], + "properties": { + "requestId": { "type": "string" }, + "affiliateCode": { "type": "string" }, + "customerId": { "type": "string" }, + "accountId": { "type": "string" }, + "debtId": { "type": "integer" } + } +} diff --git a/app/swagger/schemas/eco/DebtClosureNotificationResponse.json b/app/swagger/schemas/eco/DebtClosureNotificationResponse.json new file mode 100644 index 0000000..9aa7844 --- /dev/null +++ b/app/swagger/schemas/eco/DebtClosureNotificationResponse.json @@ -0,0 +1,7 @@ +{ + "type": "object", + "properties": { + "resultCode": { "type": "integer" }, + "resultDescription": { "type": "string" } + } +} diff --git a/app/swagger/schemas/eco/DisbursementRequest.json b/app/swagger/schemas/eco/DisbursementRequest.json new file mode 100644 index 0000000..9ce9ef4 --- /dev/null +++ b/app/swagger/schemas/eco/DisbursementRequest.json @@ -0,0 +1,15 @@ +{ + "type": "object", + "required": ["requestId", "affiliateCode", "debtId", "productId", "customerId", "accountId", "provideAmount", "collectAmount", "interestRate"], + "properties": { + "requestId": { "type": "string" }, + "affiliateCode": { "type": "string" }, + "debtId": { "type": "integer" }, + "productId": { "type": "string" }, + "customerId": { "type": "string" }, + "accountId": { "type": "string" }, + "provideAmount": { "type": "number" }, + "collectAmount": { "type": "number" }, + "interestRate": { "type": "number" } + } +} diff --git a/app/swagger/schemas/eco/DisbursementResponse.json b/app/swagger/schemas/eco/DisbursementResponse.json new file mode 100644 index 0000000..fb32424 --- /dev/null +++ b/app/swagger/schemas/eco/DisbursementResponse.json @@ -0,0 +1,8 @@ +{ + "type": "object", + "properties": { + "transactionId": { "type": "string" }, + "resultCode": { "type": "integer" }, + "resultDescription": { "type": "string" } + } +} diff --git a/app/swagger/schemas/eco/SendSMSRequest.json b/app/swagger/schemas/eco/SendSMSRequest.json new file mode 100644 index 0000000..1d55501 --- /dev/null +++ b/app/swagger/schemas/eco/SendSMSRequest.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "required": ["requestId", "phoneNums", "affiliateCode", "message"], + "properties": { + "requestId": { "type": "string" }, + "phoneNums": { + "type": "array", + "items": { "type": "string" } + }, + "affiliateCode": { "type": "string" }, + "message": { "type": "string" } + } +} diff --git a/app/swagger/schemas/eco/SendSMSResponse.json b/app/swagger/schemas/eco/SendSMSResponse.json new file mode 100644 index 0000000..a373eb6 --- /dev/null +++ b/app/swagger/schemas/eco/SendSMSResponse.json @@ -0,0 +1,11 @@ +{ + "type": "object", + "properties": { + "undelivered": { + "type": "array", + "items": { "type": "string" } + }, + "resultCode": { "type": "integer" }, + "resultDescription": { "type": "string" } + } +} diff --git a/requirements.txt b/requirements.txt index bb8f998..7f6f8f5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,6 +8,8 @@ flask-swagger-ui python-dotenv +flask-jwt-extended +flask-apispec # Logging (Python Standard Library, for reference) \ No newline at end of file