From cb0d9938c654d5bde00423abf77a752d712ba559 Mon Sep 17 00:00:00 2001 From: VivianDee <115420678+VivianDee@users.noreply.github.com> Date: Fri, 25 Jul 2025 15:14:30 +0100 Subject: [PATCH] [add]: eco routes, services and enums --- app/__init__.py | 2 + 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 | 10 ++ app/eco/helpers/response_helper.py | 112 +++++++++++++++++++ app/eco/routes/__init__.py | 1 + app/eco/routes/routes.py | 109 ++++++++++++++++++ app/eco/schemas/__init__.py | 8 ++ app/eco/schemas/authorization.py | 6 + app/eco/schemas/eligibility_check.py | 14 +++ app/eco/schemas/get_offer.py | 17 +++ app/eco/schemas/inflow_notification.py | 18 +++ app/eco/schemas/loan_information.py | 13 +++ app/eco/schemas/low_balance_notification.py | 16 +++ app/eco/schemas/provide_loan.py | 20 ++++ app/eco/schemas/repayment.py | 16 +++ app/eco/services/__init__.py | 8 ++ app/eco/services/authorization.py | 102 +++++++++++++++++ app/eco/services/base_service.py | 37 ++++++ app/eco/services/eligibility_check.py | 63 +++++++++++ app/eco/services/get_offer.py | 67 +++++++++++ app/eco/services/inflow_notification.py | 38 +++++++ app/eco/services/loan_information.py | 50 +++++++++ app/eco/services/low_balance_notification.py | 38 +++++++ app/eco/services/provide_loan.py | 38 +++++++ app/eco/services/repayment.py | 38 +++++++ 27 files changed, 857 insertions(+) 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/eligibility_check.py create mode 100644 app/eco/schemas/get_offer.py create mode 100644 app/eco/schemas/inflow_notification.py create mode 100644 app/eco/schemas/loan_information.py create mode 100644 app/eco/schemas/low_balance_notification.py create mode 100644 app/eco/schemas/provide_loan.py create mode 100644 app/eco/schemas/repayment.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/eligibility_check.py create mode 100644 app/eco/services/get_offer.py create mode 100644 app/eco/services/inflow_notification.py create mode 100644 app/eco/services/loan_information.py create mode 100644 app/eco/services/low_balance_notification.py create mode 100644 app/eco/services/provide_loan.py create mode 100644 app/eco/services/repayment.py diff --git a/app/__init__.py b/app/__init__.py index 84ef02b..52dec1f 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -5,6 +5,7 @@ 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_sqlalchemy import SQLAlchemy from flask_migrate import Migrate @@ -39,6 +40,7 @@ def create_app(): # Register blueprints app.register_blueprint(api) + app.register_blueprint(eco) swagger_ui_blueprint = get_swaggerui_blueprint(SWAGGER_URL, API_URL) app.register_blueprint(swagger_ui_blueprint, url_prefix=SWAGGER_URL) diff --git a/app/eco/enums/__init__.py b/app/eco/enums/__init__.py new file mode 100644 index 0000000..2e3a1d8 --- /dev/null +++ b/app/eco/enums/__init__.py @@ -0,0 +1 @@ +from .transaction_type import TransactionType \ No newline at end of file diff --git a/app/eco/enums/installment_status.py b/app/eco/enums/installment_status.py new file mode 100644 index 0000000..209c1f1 --- /dev/null +++ b/app/eco/enums/installment_status.py @@ -0,0 +1,7 @@ +from enum import Enum + +class InstallmentStatus(str, Enum): + PENDING = 'PENDING' + PAID = 'PAID' + OVERDUE = 'OVERDUE' + PARTIALLY_PAID = 'PARTIALLY_PAID' \ No newline at end of file diff --git a/app/eco/enums/loan_status.py b/app/eco/enums/loan_status.py new file mode 100644 index 0000000..c0cf7bd --- /dev/null +++ b/app/eco/enums/loan_status.py @@ -0,0 +1,8 @@ +from enum import Enum + +class LoanStatus(str, Enum): + PENDING = 'PENDING' + ACTIVE = 'ACTIVE' + PAID = 'PAID' + DEFAULTED = 'DEFAULTED' + CLOSED = 'CLOSED' \ No newline at end of file diff --git a/app/eco/enums/transaction_type.py b/app/eco/enums/transaction_type.py new file mode 100644 index 0000000..8445e95 --- /dev/null +++ b/app/eco/enums/transaction_type.py @@ -0,0 +1,10 @@ +from enum import Enum + +class TransactionType(str, Enum): + ELIGIBILITY_CHECK = "eligibility_check" + GET_OFFERS = "get_offers" + LOAN_INFORMATION = "loan_information" + INFLOW_NOTIFICATION = "inflow_notification" + LOW_BALANCE_NOTIFICATION = "low_balance_notification" + PROVIDE_LOAN = "provide_loan" + REPAYMENT = "repayment" diff --git a/app/eco/helpers/response_helper.py b/app/eco/helpers/response_helper.py new file mode 100644 index 0000000..d2158f0 --- /dev/null +++ b/app/eco/helpers/response_helper.py @@ -0,0 +1,112 @@ +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) \ 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..f73f0d0 --- /dev/null +++ b/app/eco/routes/routes.py @@ -0,0 +1,109 @@ +from flask import Blueprint, request, jsonify, send_from_directory +from app.eco.services import ( + AuthorizationService, + EligibilityCheckService, + GetOfferService, + ProvideLoanService, + LoanInformationService, + RepaymentService, + InflowNotificationService, + LowBalanceNotificationService +) +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, "digifi_swagger.json") + +@eco.route("/swagger/") +def serve_paths(filename): + swagger_dir = os.path.join("swagger") + return send_from_directory(swagger_dir, filename) + + + + +# Simbrella Request API Endpoints +@eco.route("/EligibilityCheck", methods=["POST"]) +@jwt_required() +def eligibility_check(): + data = request.get_json() + response = EligibilityCheckService.process_request(data) + return jsonify(response) + +@eco.route("/GetOffers", methods=["POST"]) +@jwt_required() +def get_offers(): + data = request.get_json() + response = GetOfferService.process_request(data) + return jsonify(response) + +@eco.route("/ProvideLoan", methods=["POST"]) +@jwt_required() +def provide_loan(): + data = request.get_json() + response = ProvideLoanService.process_request(data) + return jsonify(response) + +@eco.route("/LoanInformation", methods=["POST"]) +@jwt_required() +def loan_information(): + data = request.get_json() + response = LoanInformationService.process_request(data) + return jsonify(response) + +@eco.route("/Repayment", methods=["POST"]) +@jwt_required() +def repayment(): + data = request.get_json() + response = RepaymentService.process_request(data) + return jsonify(response) + +@eco.route("/InflowNotification", methods=["POST"]) +@jwt_required() +def inflow_notification(): + data = request.get_json() + response = InflowNotificationService.process_request(data) + return jsonify(response) + +@eco.route("/LowBalanceNotification", methods=["POST"]) +@jwt_required() +def low_balance_notification(): + data = request.get_json() + response = LowBalanceNotificationService.process_request(data) + return jsonify(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..e15313d --- /dev/null +++ b/app/eco/schemas/__init__.py @@ -0,0 +1,8 @@ +from .authorization import AuthorizeRequestSchema +from .eligibility_check import EligibilityCheckSchema +from .get_offer import GetOfferSchema +from .provide_loan import ProvideLoanSchema +from .loan_information import LoanInformationSchema +from .repayment import RepaymentSchema +from .inflow_notification import InflowNotificationSchema +from .low_balance_notification import LowBalanceNotificationSchema \ 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/eligibility_check.py b/app/eco/schemas/eligibility_check.py new file mode 100644 index 0000000..14797f5 --- /dev/null +++ b/app/eco/schemas/eligibility_check.py @@ -0,0 +1,14 @@ +from marshmallow import Schema, fields, EXCLUDE + + +class EligibilityCheckSchema(Schema): + requestId = fields.Str(required=True) + sessionId = fields.Str(required=True) + affiliateCode = fields.Str(required=True) + customerId = fields.Str(required=True) + accountId = fields.Str(required=True) + msisdn = fields.Str(required=True) + lienAmount = fields.Str(required=True) + + class Meta: + unknown = EXCLUDE diff --git a/app/eco/schemas/get_offer.py b/app/eco/schemas/get_offer.py new file mode 100644 index 0000000..fe0ea6a --- /dev/null +++ b/app/eco/schemas/get_offer.py @@ -0,0 +1,17 @@ +from marshmallow import Schema, fields, validate, validates_schema, EXCLUDE +from marshmallow.validate import OneOf +from datetime import datetime + +class GetOfferSchema(Schema): + requestId = fields.Str(required=True) + sessionId = fields.Str(required=True) + affiliateCode = fields.Str(required=True) + customerId = fields.Str(required=True) + accountId = fields.Str(required=True) + msisdn = fields.Str(required=True) + lienAmount = fields.Decimal(required=True) + requestedAmount = fields.Decimal(required=True) + channel = fields.Str(required=True) + + class Meta: + unknown = EXCLUDE \ No newline at end of file diff --git a/app/eco/schemas/inflow_notification.py b/app/eco/schemas/inflow_notification.py new file mode 100644 index 0000000..1dc71ef --- /dev/null +++ b/app/eco/schemas/inflow_notification.py @@ -0,0 +1,18 @@ +from marshmallow import Schema, fields, EXCLUDE +from datetime import datetime + +class InflowItemSchema(Schema): + customerId = fields.Str(required=True) + accountId = fields.Str(required=True) + amount = fields.Decimal(required=True, places=2) + transactionId = fields.Str(required=True) + transactionDate = fields.Str(required=True) + + +class InflowNotificationSchema(Schema): + batchTime = fields.Str(required=True) + affiliateCode = fields.Str(required=True) + inflows = fields.List(fields.Nested(InflowItemSchema), required=True) + + class Meta: + unknown = EXCLUDE \ No newline at end of file diff --git a/app/eco/schemas/loan_information.py b/app/eco/schemas/loan_information.py new file mode 100644 index 0000000..c7ce8b5 --- /dev/null +++ b/app/eco/schemas/loan_information.py @@ -0,0 +1,13 @@ +from marshmallow import Schema, fields, validate, EXCLUDE +from marshmallow.validate import OneOf, Range + +class LoanInformationSchema(Schema): + requestId = fields.Str(required=True) + sessionId = fields.Str(required=True) + affiliateCode = fields.Str(required=True) + customerId = fields.Str(required=True) + msisdn = fields.Str(required=True) + channel = fields.Str(required=True) + + class Meta: + unknown = EXCLUDE \ No newline at end of file diff --git a/app/eco/schemas/low_balance_notification.py b/app/eco/schemas/low_balance_notification.py new file mode 100644 index 0000000..f6c9ec2 --- /dev/null +++ b/app/eco/schemas/low_balance_notification.py @@ -0,0 +1,16 @@ +from marshmallow import Schema, fields, validate, EXCLUDE + +class LowBalanceItemSchema(Schema): + customerId = fields.Str(required=True) + accountId = fields.Str(required=True) + balance = fields.Decimal(required=True, places=2) + transactionId = fields.Str(required=True) + transactionDate = fields.Str(required=True) + +class LowBalanceNotificationSchema(Schema): + batchTime = fields.Str(required=True) + affiliateCode = fields.Str(required=True) + lbns = fields.List(fields.Nested(LowBalanceItemSchema), required=True) + + class Meta: + unknown = EXCLUDE diff --git a/app/eco/schemas/provide_loan.py b/app/eco/schemas/provide_loan.py new file mode 100644 index 0000000..13ed22f --- /dev/null +++ b/app/eco/schemas/provide_loan.py @@ -0,0 +1,20 @@ +from marshmallow import Schema, fields, validate, EXCLUDE +from marshmallow.validate import OneOf, Range + +class ProvideLoanSchema(Schema): + requestId = fields.Str(required=True) + sessionId = fields.Str(required=True) + affiliateCode = fields.Str(required=True) + customerId = fields.Str(required=True) + accountId = fields.Str(required=True) + msisdn = fields.Str(required=True) + offerId = fields.Int(required=True, validate=Range(min=1)) + upfrontPayment = fields.Decimal(required=True) + interestRate = fields.Decimal(required=True) + requestedAmount = fields.Decimal(required=True) + lienAmount = fields.Decimal(required=True) + productId = fields.Str( required=True) + channel = fields.Str(required=True) + + class Meta: + unknown = EXCLUDE \ No newline at end of file diff --git a/app/eco/schemas/repayment.py b/app/eco/schemas/repayment.py new file mode 100644 index 0000000..809bce0 --- /dev/null +++ b/app/eco/schemas/repayment.py @@ -0,0 +1,16 @@ +from marshmallow import Schema, fields, validate, EXCLUDE +from marshmallow.validate import OneOf, Range + +class RepaymentSchema(Schema): + requestId = fields.Str(required=True) + sessionId = fields.Str(required=True) + affiliateCode = fields.Str(required=True) + customerId = fields.Str(required=True) + msisdn = fields.Str(required=True) + debtId = fields.Int(required=True, validate=Range(min=1)) + repaymentAmount = fields.Decimal(required=False) # Optional, required for "Manual" repaymentType + repaymentType = fields.Str(required=True) # "Full", "Due", "Manual", "Overdue" + channel = 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..58da847 --- /dev/null +++ b/app/eco/services/__init__.py @@ -0,0 +1,8 @@ +from app.eco.services.authorization import AuthorizationService +from app.eco.services.eligibility_check import EligibilityCheckService +from app.eco.services.get_offer import GetOfferService +from app.eco.services.provide_loan import ProvideLoanService +from app.eco.services.loan_information import LoanInformationService +from app.eco.services.repayment import RepaymentService +from app.eco.services.inflow_notification import InflowNotificationService +from app.eco.services.low_balance_notification import LowBalanceNotificationService 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..f12450e --- /dev/null +++ b/app/eco/services/base_service.py @@ -0,0 +1,37 @@ +from app.eco.enums import TransactionType +from flask import jsonify +from marshmallow import ValidationError +import logging +from app.utils.mail import send_report_email, get_report_data + +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 send_mail(cls, report_data, recipients): + send_report_email(report_data, recipients) + + # @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/eligibility_check.py b/app/eco/services/eligibility_check.py new file mode 100644 index 0000000..54d32ee --- /dev/null +++ b/app/eco/services/eligibility_check.py @@ -0,0 +1,63 @@ +from flask import session, jsonify +from app.utils.logger import logger +from app.eco.services.base_service import BaseService +from app.eco.schemas.eligibility_check import EligibilityCheckSchema +from marshmallow import ValidationError +from app.eco.enums import TransactionType +from app.eco.helpers.response_helper import ResponseHelper + +import random + + +class EligibilityCheckService(BaseService): + TRANSACTION_TYPE = TransactionType.ELIGIBILITY_CHECK + + @staticmethod + def process_request(data): + """ + Process the EligibilityCheck request. + + Args: + data (dict): The request data. + + Returns: + dict: A standardized response. + """ + try: + # with db.session.begin(): + + validated_data = EligibilityCheckService.validate_data( + data, EligibilityCheckSchema() + ) + + account_id = validated_data.get("accountId") + customer_id = validated_data.get("customerId") + sessionId = validated_data.get("sessionId") + msisdn = validated_data.get("msisdn") + + # Simulate processing + response_data = { + "minEligibleAmount": 1000.0, + "maxEligibleAmount": 50000.0, + "outstandingDebtAmount": 1000.0, + } + + return ResponseHelper.success(data=response_data) + + except ValidationError as err: + + logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") + # db.session.rollback() + return ResponseHelper.unprocessable_entity( + result_description="Validation exception" + ) + + except ValueError as err: + logger.error(f"{getattr(err, 'messages', str(err))}") + # db.session.rollback() + return ResponseHelper.error(result_description=str(err)) + + except Exception as e: + logger.error(f"An error occurred: {str(e)}", exc_info=True) + # db.session.rollback() + return ResponseHelper.internal_server_error() diff --git a/app/eco/services/get_offer.py b/app/eco/services/get_offer.py new file mode 100644 index 0000000..b85eeff --- /dev/null +++ b/app/eco/services/get_offer.py @@ -0,0 +1,67 @@ +from urllib import response +from app.utils.logger import logger +from app.eco.services.base_service import BaseService +from app.eco.schemas.get_offer import GetOfferSchema +from marshmallow import ValidationError +from app.eco.enums import TransactionType +from app.eco.helpers.response_helper import ResponseHelper + +import random + +class GetOfferService(BaseService): + TRANSACTION_TYPE = TransactionType.GET_OFFERS + + @staticmethod + def process_request(data): + """ + Process the GetOffer request. + + Args: + data (dict): The request data. + + Returns: + dict: A standardized response. + """ + try: + validated_data = GetOfferService.validate_data( + data, GetOfferSchema() + ) + + # Simulate processing + offers = [ + { + "offerId": 14451, + "productId": "2030", + "amount": 10000.0, + "upfrontPayment": 1000.0, + "interestRate": 10.0, + "recommendedRepaymentDates": ["2022-11-30"], + "installmentAmount": 11000.0, + "totalRepaymentAmount": 11000.0 + }, + { + "offerId": 16645, + "productId": "2060", + "amount": 10000.0, + "upfrontPayment": 0.0, + "interestRate": 10.0, + "recommendedRepaymentDates": ["2022-11-30", "2023-12-30"], + "installmentAmount": 5761.9, + "totalRepaymentAmount": 11523.8 + } + ] + + response_data = { + "outstandingDebtAmount": 0, + "offers": offers + } + + return ResponseHelper.success(data=response_data) + + except ValidationError as err: + logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") + return ResponseHelper.unprocessable_entity(result_description="Validation exception") + + except Exception as e: + logger.error(f"An error occurred: {str(e)}", exc_info=True) + return ResponseHelper.internal_server_error() \ No newline at end of file diff --git a/app/eco/services/inflow_notification.py b/app/eco/services/inflow_notification.py new file mode 100644 index 0000000..360a2b9 --- /dev/null +++ b/app/eco/services/inflow_notification.py @@ -0,0 +1,38 @@ +from urllib import response +from app.utils.logger import logger +from app.eco.services.base_service import BaseService +from app.eco.schemas.inflow_notification import InflowNotificationSchema +from marshmallow import ValidationError +from app.eco.enums import TransactionType +from app.eco.helpers.response_helper import ResponseHelper + +import random + +class InflowNotificationService(BaseService): + TRANSACTION_TYPE = TransactionType.INFLOW_NOTIFICATION + + @staticmethod + def process_request(data): + """ + Process the InflowNotification request. + + Args: + data (dict): The request data. + + Returns: + dict: A standardized response. + """ + try: + validated_data = InflowNotificationService.validate_data( + data, InflowNotificationSchema() + ) + + return ResponseHelper.success() + + except ValidationError as err: + logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") + return ResponseHelper.unprocessable_entity(result_description="Validation exception") + + except Exception as e: + logger.error(f"An error occurred: {str(e)}", exc_info=True) + return ResponseHelper.internal_server_error() \ No newline at end of file diff --git a/app/eco/services/loan_information.py b/app/eco/services/loan_information.py new file mode 100644 index 0000000..05916b7 --- /dev/null +++ b/app/eco/services/loan_information.py @@ -0,0 +1,50 @@ +from app.utils.logger import logger +from app.eco.services.base_service import BaseService +from app.eco.schemas.loan_information import LoanInformationSchema +from marshmallow import ValidationError +from app.eco.enums import TransactionType +from app.eco.helpers.response_helper import ResponseHelper + +class LoanInformationService(BaseService): + TRANSACTION_TYPE = TransactionType.LOAN_INFORMATION + + + @staticmethod + def process_request(data): + """ + Process the LoanInformation request. + + Args: + data (dict): The request data. + + Returns: + dict: A standardized response. + """ + try: + # Validate the input data + validated_data = LoanInformationService.validate_data( + data, LoanInformationSchema() + ) + + logger.info(f"Fetching loan information for customer {validated_data['customerId']}") + + # Simulate fetching loan information + debts = LoanInformationService._generate_sample_debts(validated_data['customerId']) + + response_data = { + "debts": debts, + "totalCurrentPayment": sum(debt['currentPaymentAmount'] for debt in debts), + "totalDebtAmount": sum(debt['totalRepaymentAmount'] for debt in debts), + "resultCode": "00", + "resultDescription": "Successful" + } + + return ResponseHelper.success(result=loan_data) + + except ValidationError as err: + logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") + return ResponseHelper.unprocessable_entity(result_description="Validation exception") + + except Exception as e: + logger.error(f"An error occurred: {str(e)}", exc_info=True) + return ResponseHelper.internal_server_error() diff --git a/app/eco/services/low_balance_notification.py b/app/eco/services/low_balance_notification.py new file mode 100644 index 0000000..28b1bfc --- /dev/null +++ b/app/eco/services/low_balance_notification.py @@ -0,0 +1,38 @@ +from urllib import response +from app.utils.logger import logger +from app.eco.services.base_service import BaseService +from app.eco.schemas.low_balance_notification import LowBalanceNotificationSchema +from marshmallow import ValidationError +from app.eco.enums import TransactionType +from app.eco.helpers.response_helper import ResponseHelper + +import random + +class LowBalanceNotificationService(BaseService): + TRANSACTION_TYPE = TransactionType.LOW_BALANCE_NOTIFICATION + + @staticmethod + def process_request(data): + """ + Process the LowBalanceNotification request. + + Args: + data (dict): The request data. + + Returns: + dict: A standardized response. + """ + try: + validated_data = LowBalanceNotificationService.validate_data( + data, LowBalanceNotificationSchema() + ) + + return ResponseHelper.success() + + except ValidationError as err: + logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") + return ResponseHelper.unprocessable_entity(result_description="Validation exception") + + except Exception as e: + logger.error(f"An error occurred: {str(e)}", exc_info=True) + return ResponseHelper.internal_server_error() \ No newline at end of file diff --git a/app/eco/services/provide_loan.py b/app/eco/services/provide_loan.py new file mode 100644 index 0000000..434ef47 --- /dev/null +++ b/app/eco/services/provide_loan.py @@ -0,0 +1,38 @@ +from urllib import response +from app.utils.logger import logger +from app.eco.services.base_service import BaseService +from app.eco.schemas.provide_loan import ProvideLoanSchema +from marshmallow import ValidationError +from app.eco.enums import TransactionType +from app.eco.helpers.response_helper import ResponseHelper + +import random + +class ProvideLoanService(BaseService): + TRANSACTION_TYPE = TransactionType.PROVIDE_LOAN + + @staticmethod + def process_request(data): + """ + Process the ProvideLoan request. + + Args: + data (dict): The request data. + + Returns: + dict: A standardized response. + """ + try: + validated_data = ProvideLoanService.validate_data( + data, ProvideLoanSchema() + ) + + return ResponseHelper.success() + + except ValidationError as err: + logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") + return ResponseHelper.unprocessable_entity(result_description="Validation exception") + + except Exception as e: + logger.error(f"An error occurred: {str(e)}", exc_info=True) + return ResponseHelper.internal_server_error() \ No newline at end of file diff --git a/app/eco/services/repayment.py b/app/eco/services/repayment.py new file mode 100644 index 0000000..2d7b0ff --- /dev/null +++ b/app/eco/services/repayment.py @@ -0,0 +1,38 @@ +from urllib import response +from app.utils.logger import logger +from app.eco.services.base_service import BaseService +from app.eco.schemas.repayment import RepaymentSchema +from marshmallow import ValidationError +from app.eco.enums import TransactionType +from app.eco.helpers.response_helper import ResponseHelper + +import random + +class RepaymentService(BaseService): + TRANSACTION_TYPE = TransactionType.REPAYMENT + + @staticmethod + def process_request(data): + """ + Process the Repayment request. + + Args: + data (dict): The request data. + + Returns: + dict: A standardized response. + """ + try: + validated_data = RepaymentService.validate_data( + data, RepaymentSchema() + ) + + return ResponseHelper.success() + + except ValidationError as err: + logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") + return ResponseHelper.unprocessable_entity(result_description="Validation exception") + + except Exception as e: + logger.error(f"An error occurred: {str(e)}", exc_info=True) + return ResponseHelper.internal_server_error() \ No newline at end of file