Merge branch 'loan_repayment_event' of DigiFi/digifi-BankToProductCore into master

This commit is contained in:
2025-04-11 08:25:15 +00:00
committed by Gogs
14 changed files with 378 additions and 275 deletions
+5 -4
View File
@@ -49,10 +49,11 @@ class BaseService:
Create a new transaction. Create a new transaction.
""" """
return Transaction.create_transaction( return Transaction.create_transaction(
transaction_id =validated_data.get("transactionId"), transaction_id = validated_data.get("transactionId"),
account_id=validated_data.get("accountId"), ref_id = validated_data.get("refId") or validated_data.get("accountId"),
type=cls.TRANSACTION_TYPE, ref_model = validated_data.get("refModel", "account"),
channel=validated_data.get("channel"), type = cls.TRANSACTION_TYPE,
channel = validated_data.get("channel"),
) )
@classmethod @classmethod
+25 -19
View File
@@ -5,6 +5,7 @@ from app.utils.logger import logger
from app.api.schemas.customer_consent import CustomerConsentSchema from app.api.schemas.customer_consent import CustomerConsentSchema
from app.api.services.base_service import BaseService from app.api.services.base_service import BaseService
from app.api.enums import TransactionType from app.api.enums import TransactionType
from app.extensions import db
class CustomerConsentService(BaseService): class CustomerConsentService(BaseService):
@@ -22,36 +23,39 @@ class CustomerConsentService(BaseService):
dict: A standardized response. dict: A standardized response.
""" """
try: try:
with db.session.begin():
validated_data = CustomerConsentService.validate_data(data, CustomerConsentSchema())
account_id = validated_data.get('accountId')
customer_id = validated_data.get('customerId')
validated_data = CustomerConsentService.validate_data(data, CustomerConsentSchema()) if(CustomerConsentService.validate_account_ownership(account_id = account_id, customer_id = customer_id)):
account_id = validated_data.get('accountId')
customer_id = validated_data.get('customerId')
if(CustomerConsentService.validate_account_ownership(account_id = account_id, customer_id = customer_id)): transaction = CustomerConsentService.log_transaction(validated_data = validated_data)
transaction = CustomerConsentService.log_transaction(validated_data = validated_data)
if not transaction: if not transaction:
logger.error(f"Failed to log transaction") logger.error(f"Failed to log transaction")
return jsonify({
"message": "Failed to log transaction."
}), 400
else:
return jsonify({ return jsonify({
"message": "Failed to log transaction." "message": "Invalid Customer or Account"
}), 400 }), 400
else:
return jsonify({
"message": "Invalid Customer or Account"
}), 400
# Simulated processing logic # Simulated processing logic
response_data = { response_data = {
"resultCode": "00", "resultCode": "00",
"resultDescription": "Request is received" "resultDescription": "Request is received"
} }
return response_data db.session.commit()
return response_data
except ValidationError as err: except ValidationError as err:
logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({ return jsonify({
"message": "Validation exception" "message": "Validation exception"
@@ -59,6 +63,7 @@ class CustomerConsentService(BaseService):
except ValueError as err: except ValueError as err:
logger.error(f"{getattr(err, 'messages', str(err))}") logger.error(f"{getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({ return jsonify({
"message": str(err) "message": str(err)
@@ -66,6 +71,7 @@ class CustomerConsentService(BaseService):
except Exception as e: except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True) logger.error(f"An error occurred: {str(e)}", exc_info=True)
db.session.rollback()
return jsonify({ return jsonify({
"message": "Internal Server Error" "message": "Internal Server Error"
}) , 500 }) , 500
+60 -55
View File
@@ -5,6 +5,7 @@ from app.api.schemas.eligibility_check import EligibilityCheckSchema
from marshmallow import ValidationError from marshmallow import ValidationError
from app.api.enums import TransactionType from app.api.enums import TransactionType
from app.api.integrations import SimbrellaIntegration from app.api.integrations import SimbrellaIntegration
from app.extensions import db
class EligibilityCheckService(BaseService): class EligibilityCheckService(BaseService):
TRANSACTION_TYPE = TransactionType.ELIGIBILITY_CHECK TRANSACTION_TYPE = TransactionType.ELIGIBILITY_CHECK
@@ -21,71 +22,75 @@ class EligibilityCheckService(BaseService):
dict: A standardized response. dict: A standardized response.
""" """
try: try:
with db.session.begin():
validated_data = EligibilityCheckService.validate_data(data, EligibilityCheckSchema()) validated_data = EligibilityCheckService.validate_data(data, EligibilityCheckSchema())
account_id = validated_data.get('accountId') account_id = validated_data.get('accountId')
customer_id = validated_data.get('customerId') customer_id = validated_data.get('customerId')
transactionId = validated_data.get('transactionId') transactionId = validated_data.get('transactionId')
msisdn = validated_data.get('msisdn') msisdn = validated_data.get('msisdn')
customer = EligibilityCheckService.get_or_create_customer(validated_data = validated_data) customer = EligibilityCheckService.get_or_create_customer(validated_data = validated_data)
if (EligibilityCheckService.validate_account_ownership(account_id = account_id, customer_id = customer_id)): if (EligibilityCheckService.validate_account_ownership(account_id = account_id, customer_id = customer_id)):
transaction = EligibilityCheckService.log_transaction(validated_data = validated_data)
if not transaction: transaction = EligibilityCheckService.log_transaction(validated_data = validated_data)
logger.error(f"Failed to log transaction")
if not transaction:
logger.error(f"Failed to log transaction")
return jsonify({
"message": "Failed to log transaction."
}), 400
else:
return jsonify({ return jsonify({
"message": "Failed to log transaction." "message": "Invalid Customer or Account"
}), 400 }), 400
else:
return jsonify({
"message": "Invalid Customer or Account"
}), 400
# Call RACCheck # Call RACCheck
response = SimbrellaIntegration.rac_check( response = SimbrellaIntegration.rac_check(
customer_id = customer_id, customer_id = customer_id,
account_id = account_id, account_id = account_id,
transaction_id = transaction.id, transaction_id = transaction.id,
) )
logger.error(f"This is Response Returned ****** : {str(response)}") logger.error(f"This is Response Returned ****** : {str(response)}")
# this chck for error is not valid # this chck for error is not valid
logger.error(f"Check for ERROR is not valid ****** FIX THIS !!!!!") logger.error(f"Check for ERROR is not valid ****** FIX THIS !!!!!")
#if "error" in response or response.get("status") != 200: #if "error" in response or response.get("status") != 200:
# return jsonify({"message": "RACCheck failed"}), 400 # return jsonify({"message": "RACCheck failed"}), 400
offers = [ offers = [
{ {
"offerId": "SAL90", "offerId": "SAL90",
"productId": "2030", "productId": "2030",
"minAmount": 5000, "minAmount": 5000,
"maxAmount": 100000, "maxAmount": 100000,
"tenor": 30 "tenor": 30
}, },
{ {
"offerId": "SAL30", "offerId": "SAL30",
"productId": "2090", "productId": "2090",
"minAmount": 3000, "minAmount": 3000,
"maxAmount": 500000, "maxAmount": 500000,
"tenor": 90 "tenor": 90
} }
] ]
# Simulate processing # Simulate processing
response_data = { response_data = {
"customerId": customer_id, "customerId": customer_id,
"transactionId": transactionId, "transactionId": transactionId,
"countryCode": "NG", "countryCode": "NG",
"msisdn": msisdn, "msisdn": msisdn,
"eligibleOffers": offers, "eligibleOffers": offers,
"resultDescription": "Successful", "resultDescription": "Successful",
"resultCode": "00", "resultCode": "00",
"accountId": account_id "accountId": account_id
} }
return response_data
return response_data
except ValidationError as err: except ValidationError as err:
logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}")
+44 -32
View File
@@ -1,9 +1,11 @@
from flask import request, jsonify from flask import request, jsonify
from marshmallow import ValidationError from marshmallow import ValidationError
from app.models import Customer
from app.utils.logger import logger from app.utils.logger import logger
from app.api.schemas.loan_status import LoanStatusSchema from app.api.schemas.loan_status import LoanStatusSchema
from app.api.services.base_service import BaseService from app.api.services.base_service import BaseService
from app.api.enums import TransactionType from app.api.enums import TransactionType
from app.extensions import db
class LoanStatusService(BaseService): class LoanStatusService(BaseService):
@@ -21,12 +23,23 @@ class LoanStatusService(BaseService):
dict: A standardized response. dict: A standardized response.
""" """
try: try:
validated_data = LoanStatusService.validate_data(data, LoanStatusSchema()) with db.session.begin():
customer_id = validated_data.get('customerId') # Validate data
customer = LoanStatusService.get_or_create_customer(validated_data) validated_data = LoanStatusService.validate_data(data, LoanStatusSchema())
account = customer.accounts[0]
customer_id = validated_data.get('customerId')
customer = Customer.get_customer(customer_id)
transactionId = validated_data.get('transactionId')
# Get loans
loans = [loan.to_dict() for loan in customer.loans]
validated_data['refId'] = customer.id
validated_data['refModel'] = "customer"
if (LoanStatusService.validate_account_ownership(account_id = account.id, customer_id = customer_id)):
transaction = LoanStatusService.log_transaction(validated_data = validated_data) transaction = LoanStatusService.log_transaction(validated_data = validated_data)
if not transaction: if not transaction:
@@ -34,41 +47,38 @@ class LoanStatusService(BaseService):
return jsonify({ return jsonify({
"message": "Failed to log transaction." "message": "Failed to log transaction."
}), 400 }), 400
else:
return jsonify({
"message": "Invalid Customer or Account"
}), 400
loans = [ # loans = [
{ # {
"debtId": "123456789", # "debtId": "123456789",
"loanDate": "2019-10-18 14:26:21.063", # "loanDate": "2019-10-18 14:26:21.063",
"dueDate": "2019-11-20 14:26:21.063", # "dueDate": "2019-11-20 14:26:21.063",
"currentLoanAmount": 8500, # "currentLoanAmount": 8500,
"initialLoanAmount": 10000, # "initialLoanAmount": 10000,
"defaultPenaltyFee": 0, # "defaultPenaltyFee": 0,
"continuousFee": 0, # "continuousFee": 0,
"productId": "101" # "productId": "101"
# }
# ]
# Simulated processing logic
response_data = {
"customerId": customer_id,
"transactionId": transactionId,
"loans": loans,
"totalDebtAmount": 8500,
"resultCode": "00",
"resultDescription": "Successful"
} }
]
# Simulated processing logic db.session.commit()
response_data = { return response_data
"customerId": "CN621868",
"transactionId": "Tr201712RK9232P115",
"loans": loans,
"totalDebtAmount": 8500,
"resultCode": "00",
"resultDescription": "Successful"
}
return response_data
except ValidationError as err: except ValidationError as err:
logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({ return jsonify({
"message": "Validation exception" "message": "Validation exception"
@@ -76,6 +86,7 @@ class LoanStatusService(BaseService):
except ValueError as err: except ValueError as err:
logger.error(f"{getattr(err, 'messages', str(err))}") logger.error(f"{getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({ return jsonify({
"message": str(err) "message": str(err)
@@ -83,6 +94,7 @@ class LoanStatusService(BaseService):
except Exception as e: except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True) logger.error(f"An error occurred: {str(e)}", exc_info=True)
db.session.rollback()
return jsonify({ return jsonify({
"message": "Internal Server Error" "message": "Internal Server Error"
}) , 500 }) , 500
@@ -4,6 +4,7 @@ from app.api.services.base_service import BaseService
from app.api.enums import TransactionType from app.api.enums import TransactionType
from app.utils.logger import logger from app.utils.logger import logger
from app.api.schemas.notification_callback import NotificationCallbackSchema from app.api.schemas.notification_callback import NotificationCallbackSchema
from app.extensions import db
class NotificationCallbackService(BaseService): class NotificationCallbackService(BaseService):
TRANSACTION_TYPE = TransactionType.NOTIFICATION_CALLBACK TRANSACTION_TYPE = TransactionType.NOTIFICATION_CALLBACK
+59 -48
View File
@@ -8,6 +8,7 @@ from app.api.schemas.provide_loan import ProvideLoanSchema
from threading import Thread from threading import Thread
from app.models.loan import Loan from app.models.loan import Loan
from app.api.enums import LoanStatus from app.api.enums import LoanStatus
from app.extensions import db
class ProvideLoanService(BaseService): class ProvideLoanService(BaseService):
TRANSACTION_TYPE = TransactionType.PROVIDE_LOAN TRANSACTION_TYPE = TransactionType.PROVIDE_LOAN
@@ -25,67 +26,75 @@ class ProvideLoanService(BaseService):
dict: A standardized response. dict: A standardized response.
""" """
try: try:
validated_data = ProvideLoanService.validate_data(data, ProvideLoanSchema()) with db.session.begin():
account_id = validated_data.get('accountId') validated_data = ProvideLoanService.validate_data(data, ProvideLoanSchema())
customer_id = validated_data.get('customerId') account_id = validated_data.get('accountId')
request_id = validated_data.get('requestId') customer_id = validated_data.get('customerId')
transaction_id = validated_data.get('transactionId') request_id = validated_data.get('requestId')
transaction_id = validated_data.get('transactionId')
if (ProvideLoanService.validate_account_ownership(account_id = account_id, customer_id = customer_id)): if (ProvideLoanService.validate_account_ownership(account_id = account_id, customer_id = customer_id)):
# Save the loan details
loan = Loan.create_loan(
customer_id=customer_id,
account_id=account_id,
offer_id=validated_data.get('offerId'),
principal_amount=validated_data.get('requestedAmount'),
status=LoanStatus.ACTIVE
)
if not loan: # Save the loan details
logger.error(f"Failed to save loan details") loan = Loan.create_loan(
customer_id=customer_id,
account_id=account_id,
offer_id=validated_data.get('offerId'),
principal_amount=validated_data.get('requestedAmount'),
status=LoanStatus.ACTIVE
)
if not loan:
logger.error(f"Failed to save loan details")
return jsonify({
"message": "Failed to save loan details."
}), 400
db.session.flush()
validated_data['refId'] = loan.id
validated_data['refModel'] = "loan"
# Log Transaction
transaction = ProvideLoanService.log_transaction(validated_data = validated_data)
if not transaction:
logger.error(f"Failed to log transaction")
return jsonify({
"message": "Failed to log transaction."
}), 400
else:
return jsonify({ return jsonify({
"message": "Failed to save loan details." "message": "Invalid Customer or Account"
}), 400 }), 400
# Log Transaction
transaction = ProvideLoanService.log_transaction(validated_data = validated_data)
if not transaction:
logger.error(f"Failed to log transaction")
return jsonify({
"message": "Failed to log transaction."
}), 400
response_data = {
else: "requestId": request_id,
return jsonify({ "transactionId": transaction_id,
"message": "Invalid Customer or Account" "customerId": customer_id,
}), 400 "accountId": account_id,
"msisdn": "3451342",
"resultCode": "00",
"resultDescription": "Successful"
}
response_data = { # KafkaIntegration.send_loan_request(loan_data = response_data, request_id = request_id)
"requestId": request_id, # Call Kafka in a background thread
"transactionId": transaction_id, thread = Thread(target=ProvideLoanService.async_send_to_kafka, args=(response_data, request_id, "PROCESS_PAYMENT"))
"customerId": customer_id, thread.start()
"accountId": account_id,
"msisdn": "3451342",
"resultCode": "00",
"resultDescription": "Successful"
}
db.session.commit()
# KafkaIntegration.send_loan_request(loan_data = response_data, request_id = request_id) return response_data
# Call Kafka in a background thread
thread = Thread(target=ProvideLoanService.async_send_to_kafka, args=(response_data, request_id, "PROCESS_PAYMENT"))
thread.start()
return response_data
except ValidationError as err: except ValidationError as err:
logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({ return jsonify({
"message": "Validation exception" "message": "Validation exception"
@@ -93,6 +102,7 @@ class ProvideLoanService(BaseService):
except ValueError as err: except ValueError as err:
logger.error(f"{getattr(err, 'messages', str(err))}") logger.error(f"{getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({ return jsonify({
"message": str(err) "message": str(err)
@@ -100,6 +110,7 @@ class ProvideLoanService(BaseService):
except Exception as e: except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True) logger.error(f"An error occurred: {str(e)}", exc_info=True)
db.session.rollback()
return jsonify({ return jsonify({
"message": "Internal Server Error" "message": "Internal Server Error"
}) , 500 }) , 500
+35 -30
View File
@@ -8,6 +8,7 @@ from app.api.schemas.repayment import RepaymentSchema
from app.api.services.base_service import BaseService from app.api.services.base_service import BaseService
from app.api.enums import TransactionType from app.api.enums import TransactionType
from threading import Thread from threading import Thread
from app.extensions import db
class RepaymentService(BaseService): class RepaymentService(BaseService):
TRANSACTION_TYPE = TransactionType.REPAYMENT TRANSACTION_TYPE = TransactionType.REPAYMENT
@@ -24,22 +25,20 @@ class RepaymentService(BaseService):
dict: A standardized response. dict: A standardized response.
""" """
try: try:
validated_data = RepaymentService.validate_data(data, RepaymentSchema()) with db.session.begin():
customer_id = validated_data.get('customerId') validated_data = RepaymentService.validate_data(data, RepaymentSchema())
customer = RepaymentService.get_or_create_customer(validated_data) customer_id = validated_data.get('customerId')
account = customer.accounts[0] request_id = validated_data.get('requestId')
validated_data['accountId'] = account.id loan_id = validated_data.get('debtId')
request_id = validated_data.get('requestId') product_id = validated_data.get('productId')
loan_id = validated_data.get('debtId')
if (RepaymentService.validate_account_ownership(account_id = account.id, customer_id = customer_id)):
# Save the repayment details # Save the repayment details
repayment = Repayment.create_repayment( repayment = Repayment.create_repayment(
customer_id = customer_id, customer_id = customer_id,
loan_id = loan_id, loan_id = loan_id,
product_id = validated_data.get('productId') product_id = product_id
) )
@@ -49,6 +48,11 @@ class RepaymentService(BaseService):
"message": "Failed to save repayment details." "message": "Failed to save repayment details."
}), 400 }), 400
db.session.flush()
validated_data['refId'] = repayment.id
validated_data['refModel'] = "repayment"
#Update Loan status #Update Loan status
Loan.update_status(loan_id = loan_id, status = LoanStatus.REPAID) Loan.update_status(loan_id = loan_id, status = LoanStatus.REPAID)
@@ -59,34 +63,33 @@ class RepaymentService(BaseService):
return jsonify({ return jsonify({
"message": "Failed to log transaction." "message": "Failed to log transaction."
}), 400 }), 400
else:
return jsonify({
"message": "Invalid Customer or Account"
}), 400
# Simulated processing logic
response_data = {
"customerId": "CN621868",
"productId": "101",
"debtId": "273194670",
"resultCode": "00",
"resultDescription": "Successful"
}
# return ResponseHelper.success( # Simulated processing logic
# data=response_data, response_data = {
# message="Repayment processed successfully" "customerId": customer_id,
# ) "productId": product_id,
"debtId": loan_id,
"resultCode": "00",
"resultDescription": "Successful"
}
# Call Kafka in a background thread # return ResponseHelper.success(
thread = Thread(target=RepaymentService.async_send_to_kafka, args=(response_data, request_id, "LOAN_REPAYMENT")) # data=response_data,
thread.start() # message="Repayment processed successfully"
# )
return response_data # Call Kafka in a background thread
thread = Thread(target=RepaymentService.async_send_to_kafka, args=(response_data, request_id, "LOAN_REPAYMENT"))
thread.start()
db.session.commit()
return response_data
except ValidationError as err: except ValidationError as err:
logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({ return jsonify({
"message": "Validation exception" "message": "Validation exception"
@@ -94,6 +97,7 @@ class RepaymentService(BaseService):
except ValueError as err: except ValueError as err:
logger.error(f"{getattr(err, 'messages', str(err))}") logger.error(f"{getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({ return jsonify({
"message": str(err) "message": str(err)
@@ -101,6 +105,7 @@ class RepaymentService(BaseService):
except Exception as e: except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True) logger.error(f"An error occurred: {str(e)}", exc_info=True)
db.session.rollback()
return jsonify({ return jsonify({
"message": "Internal Server Error" "message": "Internal Server Error"
}) , 500 }) , 500
+53 -53
View File
@@ -4,6 +4,8 @@ from app.api.services.base_service import BaseService
from app.api.enums import TransactionType from app.api.enums import TransactionType
from app.utils.logger import logger from app.utils.logger import logger
from app.api.schemas.select_offer import SelectOfferSchema from app.api.schemas.select_offer import SelectOfferSchema
from app.extensions import db
class SelectOfferService(BaseService): class SelectOfferService(BaseService):
TRANSACTION_TYPE = TransactionType.SELECT_OFFER TRANSACTION_TYPE = TransactionType.SELECT_OFFER
@@ -20,74 +22,72 @@ class SelectOfferService(BaseService):
dict: A standardized response. dict: A standardized response.
""" """
try: try:
validated_data = SelectOfferService.validate_data(data, SelectOfferSchema()) with db.session.begin():
account_id = validated_data.get('accountId') validated_data = SelectOfferService.validate_data(
customer_id = validated_data.get('customerId') data, SelectOfferSchema()
)
account_id = validated_data.get("accountId")
customer_id = validated_data.get("customerId")
if (SelectOfferService.validate_account_ownership(account_id = account_id, customer_id = customer_id)): if SelectOfferService.validate_account_ownership(
transaction = SelectOfferService.log_transaction(validated_data = validated_data) account_id=account_id, customer_id=customer_id
):
transaction = SelectOfferService.log_transaction(
validated_data=validated_data
)
if not transaction: if not transaction:
logger.error(f"Failed to log transaction") logger.error(f"Failed to log transaction")
return jsonify({ return jsonify({"message": "Failed to log transaction."}), 400
"message": "Failed to log transaction." else:
}), 400 return jsonify({"message": "Invalid Customer or Account"}), 400
else:
return jsonify({
"message": "Invalid Customer or Account"
}), 400
offers = [ offers = [
{ {
"offerId": "14451", "offerId": "14451",
"productId": "2030", "productId": "2030",
"amount": 10000.0, "amount": 10000.0,
"upfrontPayment": 1000.0, "upfrontPayment": 1000.0,
"interestRate": 3.0, "interestRate": 3.0,
"managementRate": 1.0, "managementRate": 1.0,
"managementFee": 1.0, "managementFee": 1.0,
"insuranceRate": 1.0, "insuranceRate": 1.0,
"insuranceFee": 100.0, "insuranceFee": 100.0,
"VATRate": 7.5, "VATRate": 7.5,
"VATAmount": 100.0, "VATAmount": 100.0,
"recommendedRepaymentDates": ["2022-11-30"], "recommendedRepaymentDates": ["2022-11-30"],
"installmentAmount": 11000.0, "installmentAmount": 11000.0,
"totalRepaymentAmount": 11000.0 "totalRepaymentAmount": 11000.0,
} }
] ]
# Business logic - selecting an offer # Business logic - selecting an offer
response_data = { response_data = {
"outstandingDebtAmount": 0, "outstandingDebtAmount": 0,
"requestId": "202111170001371256908", "requestId": "202111170001371256908",
"transactionId": transaction.id, "transactionId": transaction.id,
"customerId": customer_id, "customerId": customer_id,
"accountId": account_id, "accountId": account_id,
"loan": offers, "loan": offers,
"resultCode": "00", "resultCode": "00",
"resultDescription": "Successful" "resultDescription": "Successful",
} }
db.session.commit()
return response_data return response_data
except ValidationError as err: except ValidationError as err:
logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}") logger.error(f"Validation Error: {getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({"message": "Validation exception"}), 422
return jsonify({ except ValueError as err:
"message": "Validation exception"
}) , 422
except ValueError as err:
logger.error(f"{getattr(err, 'messages', str(err))}") logger.error(f"{getattr(err, 'messages', str(err))}")
db.session.rollback()
return jsonify({ return jsonify({"message": str(err)}), 400
"message": str(err)
}) , 400
except Exception as e: except Exception as e:
logger.error(f"An error occurred: {str(e)}", exc_info=True) logger.error(f"An error occurred: {str(e)}", exc_info=True)
return jsonify({ db.session.rollback()
"message": "Internal Server Error" return jsonify({"message": "Internal Server Error"}), 500
}) , 500
-2
View File
@@ -31,9 +31,7 @@ class Account(db.Model):
try: try:
db.session.add(account) db.session.add(account)
db.session.commit()
except IntegrityError as err: except IntegrityError as err:
db.session.rollback()
raise ValueError(f"Database integrity error: {err}") raise ValueError(f"Database integrity error: {err}")
return account return account
+18 -2
View File
@@ -20,6 +20,13 @@ class Customer(db.Model):
back_populates="customer", back_populates="customer",
) )
loans = relationship(
"Loan",
primaryjoin="Customer.id == Loan.customer_id",
foreign_keys="Loan.customer_id",
back_populates="customer",
)
@classmethod @classmethod
def is_valid_customer(cls, customer_id): def is_valid_customer(cls, customer_id):
customer = cls.query.filter_by(id=customer_id).first() customer = cls.query.filter_by(id=customer_id).first()
@@ -44,11 +51,20 @@ class Customer(db.Model):
account_type=account_type account_type=account_type
) )
db.session.commit()
except IntegrityError as err: except IntegrityError as err:
db.session.rollback()
raise ValueError(f"Database integrity error: {err}") raise ValueError(f"Database integrity error: {err}")
return customer return customer
@classmethod
def get_customer(cls, customer_id):
"""
Get customer by ID.
"""
customer = cls.query.filter_by(id=customer_id).first()
if not customer:
raise ValueError(f"Customer does not exist")
return customer
def __repr__(self): def __repr__(self):
return f'<Customer {self.id}>' return f'<Customer {self.id}>'
+22 -3
View File
@@ -3,6 +3,8 @@ from app.extensions import db
from app.models.customer import Customer from app.models.customer import Customer
from app.models.account import Account from app.models.account import Account
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import relationship
from app.models import Customer
class Loan(db.Model): class Loan(db.Model):
@@ -21,6 +23,12 @@ class Loan(db.Model):
created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc))
updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc)) updated_at = db.Column(db.DateTime, default=datetime.now(timezone.utc), onupdate=datetime.now(timezone.utc))
customer = relationship(
"Customer",
primaryjoin="Customer.id == Loan.customer_id",
foreign_keys=[customer_id],
back_populates="loans",
)
@classmethod @classmethod
def create_loan(cls, customer_id, account_id, offer_id, principal_amount, status='pending'): def create_loan(cls, customer_id, account_id, offer_id, principal_amount, status='pending'):
@@ -47,9 +55,7 @@ class Loan(db.Model):
try: try:
db.session.add(loan) db.session.add(loan)
db.session.commit()
except IntegrityError as err: except IntegrityError as err:
db.session.rollback()
raise ValueError(f"Database integrity error: {err}") raise ValueError(f"Database integrity error: {err}")
return loan return loan
@@ -93,7 +99,20 @@ class Loan(db.Model):
# Update loan status and the updated_at timestamp # Update loan status and the updated_at timestamp
loan.status = status loan.status = status
db.session.commit() def to_dict(self):
"""
Convert the Loan object to a dictionary format for JSON serialization.
"""
return {
'id': self.id,
'customer_id': self.customer_id,
'account_id': self.account_id,
'offer_id': self.offer_id,
'principal_amount': self.principal_amount,
'status': self.status,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
def __repr__(self): def __repr__(self):
return f'<Loan {self.id}>' return f'<Loan {self.id}>'
+1 -3
View File
@@ -38,15 +38,13 @@ class Repayment(db.Model):
repayment = cls( repayment = cls(
customer_id=customer_id, customer_id=customer_id,
loan_id=loan.id, loan_id=loan_id,
product_id=product_id, product_id=product_id,
) )
try: try:
db.session.add(repayment) db.session.add(repayment)
db.session.commit()
except IntegrityError as err: except IntegrityError as err:
db.session.rollback()
raise ValueError(f"Database integrity error: {err}") raise ValueError(f"Database integrity error: {err}")
return repayment return repayment
+8 -9
View File
@@ -10,9 +10,9 @@ class Transaction(db.Model):
primary_key=True, primary_key=True,
autoincrement=True, autoincrement=True,
) )
#id = db.Column(db.Int, primary_key=True)
transaction_id = db.Column(db.String(50), nullable=False) transaction_id = db.Column(db.String(50), nullable=False)
account_id = db.Column(db.String(50), nullable=False) ref_id = db.Column(db.String(50), nullable=False)
ref_model = db.Column(db.String(50), nullable=True, default='account')
type = db.Column(db.String(50), nullable=False) type = db.Column(db.String(50), nullable=False)
channel = db.Column(db.String(50), nullable=False) channel = db.Column(db.String(50), nullable=False)
created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc))
@@ -22,7 +22,7 @@ class Transaction(db.Model):
return f'<Transaction {self.id}>' return f'<Transaction {self.id}>'
@classmethod @classmethod
def create_transaction(cls, transaction_id, account_id, type, channel): def create_transaction(cls, transaction_id, ref_id, ref_model, type, channel):
# if cls.query.filter_by(transaction_id=transaction_id).first(): # if cls.query.filter_by(transaction_id=transaction_id).first():
# raise ValueError("Duplicate Transaction") # raise ValueError("Duplicate Transaction")
@@ -33,17 +33,16 @@ class Transaction(db.Model):
transaction = cls( transaction = cls(
transaction_id=transaction_id, transaction_id = transaction_id,
account_id=account_id, ref_id = ref_id,
type=type, ref_model = ref_model,
channel=channel type = type,
channel = channel
) )
try: try:
db.session.add(transaction) db.session.add(transaction)
db.session.commit()
except IntegrityError as err: except IntegrityError as err:
db.session.rollback()
raise ValueError(f"Database integrity error: {err}") raise ValueError(f"Database integrity error: {err}")
return transaction return transaction
@@ -0,0 +1,32 @@
"""Migration on Thu Apr 10 21:50:01 UTC 2025
Revision ID: 1340e7e578b9
Revises: b8f6fd76ead8
Create Date: 2025-04-10 21:50:32.113149
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '1340e7e578b9'
down_revision = 'b8f6fd76ead8'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('transactions', schema=None) as batch_op:
batch_op.add_column(sa.Column('ref_model', sa.String(length=50), nullable=True))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('transactions', schema=None) as batch_op:
batch_op.drop_column('ref_model')
# ### end Alembic commands ###