168 lines
7.2 KiB
Python
168 lines
7.2 KiB
Python
from flask import request, jsonify
|
|
from marshmallow import ValidationError
|
|
from app.api.helpers.response_helper import ResponseHelper
|
|
from app.api.services.base_service import BaseService
|
|
from app.api.enums import TransactionType
|
|
from app.models.transaction_offers import TransactionOffer
|
|
from app.utils.logger import logger
|
|
from app.api.schemas.select_offer import SelectOfferSchema
|
|
from app.extensions import db
|
|
from app.models import Offer
|
|
from datetime import date
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
class SelectOfferService(BaseService):
|
|
TRANSACTION_TYPE = TransactionType.SELECT_OFFER
|
|
|
|
@staticmethod
|
|
def process_request(data):
|
|
"""
|
|
Process the SelectOffer request.
|
|
|
|
Args:
|
|
data (dict): The request data.
|
|
|
|
Returns:
|
|
dict: A standardized response.
|
|
"""
|
|
try:
|
|
with db.session.begin():
|
|
validated_data = SelectOfferService.validate_data(
|
|
data, SelectOfferSchema()
|
|
)
|
|
account_id = validated_data.get("accountId")
|
|
customer_id = validated_data.get("customerId")
|
|
amount = validated_data.get("requestedAmount")
|
|
product_id = validated_data.get("productId")
|
|
transaction_offer_id = validated_data.get("offerId")
|
|
transaction_id = validated_data.get("transactionId")
|
|
request_id = validated_data.get("requestId")
|
|
|
|
offer_id = int(transaction_offer_id[5:]) # The last part is int
|
|
|
|
#"offerId": "SAL30001129",
|
|
|
|
if SelectOfferService.validate_account_ownership(
|
|
account_id=account_id, customer_id=customer_id
|
|
):
|
|
transaction = SelectOfferService.log_transaction(
|
|
validated_data=validated_data
|
|
)
|
|
|
|
if not transaction:
|
|
logger.error(f"Failed to log transaction")
|
|
return ResponseHelper.error(result_description="Failed to log transaction.")
|
|
else:
|
|
return ResponseHelper.error(result_description="Invalid Customer or Account")
|
|
|
|
# Get the offer by product ID
|
|
offer = Offer.get_offer_by_product_id(product_id)
|
|
|
|
transaction_offer = TransactionOffer.get_transaction_offer(transaction_offer_id=offer_id)
|
|
|
|
if not transaction_offer:
|
|
logger.error(f"offer {offer_id} not found for customer {customer_id} and transaction {transaction_id}.")
|
|
return ResponseHelper.error(result_description="Offer not found.")
|
|
|
|
db.session.flush()
|
|
|
|
if amount < transaction_offer.min_amount:
|
|
logger.error(f"The amount {amount} is less than the minimum allowed offer amount {transaction_offer.min_amount}.")
|
|
return ResponseHelper.error(result_description="The amount is less than the minimum allowed offer amount.")
|
|
elif amount > transaction_offer.eligible_amount:
|
|
logger.error(f"The amount {amount} is greater than the eligible offer amount {transaction_offer.eligible_amount}.")
|
|
return ResponseHelper.error(result_description="The amount is greater than the eligible offer amount.")
|
|
|
|
|
|
|
|
charges = SelectOfferService.calculate_charges(offer, amount)
|
|
upfront_payment = charges["upfront_payment"]
|
|
total_amount = charges["total_amount"]
|
|
installment_amount = charges["installment_amount"]
|
|
interest = charges["interest"]
|
|
management = charges["management"]
|
|
insurance = charges["insurance"]
|
|
vat = charges["vat"]
|
|
repayment_amount = charges["repayment_amount"]
|
|
interest_amount = charges["interest_amount"]
|
|
|
|
|
|
# Calculate the repayment dates
|
|
tenor = offer.tenor
|
|
start_date = date.today()
|
|
|
|
# Convert tenor to months
|
|
months = offer.schedule # tenor // 30
|
|
|
|
recommended_repayment_dates = [
|
|
(start_date + relativedelta(months=i + 1)).isoformat()
|
|
for i in range(months)
|
|
]
|
|
|
|
|
|
|
|
offers = [
|
|
{
|
|
"offerId": transaction_offer_id,
|
|
"productId": product_id,
|
|
"amount": amount,
|
|
"upfrontPayment": upfront_payment,
|
|
"interestRate": offer.interest_rate,
|
|
"interestFee": interest_amount,
|
|
"managementRate": offer.management_rate,
|
|
"managementFee": management["fee"],
|
|
"insuranceRate": offer.insurance_rate,
|
|
"insuranceFee": insurance["fee"],
|
|
"VATRate": offer.vat_rate,
|
|
"VATAmount": vat["fee"],
|
|
"recommendedRepaymentDates": recommended_repayment_dates,
|
|
"repaymentAmount": repayment_amount,
|
|
"installmentAmount": installment_amount,
|
|
"totalRepaymentAmount": total_amount,
|
|
}
|
|
]
|
|
|
|
# "offerId": offer.id,
|
|
# "productId": product_id,
|
|
# "amount": amount,
|
|
# "upfrontPayment": upfront_payment,
|
|
# "interestRate": interest["rate"],
|
|
# "managementRate": management["rate"],
|
|
# "managementFee": management["fee"],
|
|
# "insuranceRate": insurance["rate"],
|
|
# "insuranceFee": insurance["fee"],
|
|
# "VATRate": vat["rate"],
|
|
# "VATAmount": vat["fee"],
|
|
# "recommendedRepaymentDates": recommended_repayment_dates,
|
|
# "installmentAmount": installment_amount,
|
|
# "totalRepaymentAmount": total_amount,
|
|
#
|
|
# Business logic - selecting an offer
|
|
response_data = {
|
|
"outstandingDebtAmount": 0,
|
|
"requestId": request_id,
|
|
"transactionId": transaction_id,
|
|
"customerId": customer_id,
|
|
"accountId": account_id,
|
|
"loan": offers,
|
|
}
|
|
|
|
db.session.commit()
|
|
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()
|
|
|