diff --git a/app/api/schemas/select_offer.py b/app/api/schemas/select_offer.py new file mode 100644 index 0000000..9a9cdf2 --- /dev/null +++ b/app/api/schemas/select_offer.py @@ -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") \ No newline at end of file diff --git a/app/api/services/__init__.py b/app/api/services/__init__.py index c58bbf7..e58aec6 100644 --- a/app/api/services/__init__.py +++ b/app/api/services/__init__.py @@ -1,5 +1,6 @@ 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.collect_loan import CollectLoanService from app.api.services.transaction_verify import TransactionVerifyService from app.api.services.penal_charge import PenalChargeService diff --git a/app/api/services/select_offer.py b/app/api/services/select_offer.py new file mode 100644 index 0000000..f2544f9 --- /dev/null +++ b/app/api/services/select_offer.py @@ -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 \ No newline at end of file