[add]: ref_id and ref_model for transactions. And db session and rollback for transactions

This commit is contained in:
VivianDee
2025-04-10 23:06:51 +01:00
parent e5320c075e
commit a196d4d3c4
14 changed files with 123 additions and 88 deletions
+6 -5
View File
@@ -44,15 +44,16 @@ class BaseService:
return is_valid return is_valid
@classmethod @classmethod
def log_transaction(cls, validated_data): def log_transaction(cls, validated_data,):
""" """
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
+9 -7
View File
@@ -4,7 +4,8 @@ from marshmallow import ValidationError
from app.utils.logger import logger 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):
@@ -28,13 +29,14 @@ class CustomerConsentService(BaseService):
customer_id = validated_data.get('customerId') customer_id = validated_data.get('customerId')
if(CustomerConsentService.validate_account_ownership(account_id = account_id, customer_id = customer_id)): if(CustomerConsentService.validate_account_ownership(account_id = account_id, customer_id = customer_id)):
transaction = CustomerConsentService.log_transaction(validated_data = validated_data) with db.session.begin():
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({ return jsonify({
"message": "Failed to log transaction." "message": "Failed to log transaction."
}), 400 }), 400
else: else:
return jsonify({ return jsonify({
"message": "Invalid Customer or Account" "message": "Invalid Customer or Account"
+8 -6
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
@@ -31,13 +32,14 @@ class EligibilityCheckService(BaseService):
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) with db.session.begin():
transaction = EligibilityCheckService.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." "message": "Failed to log transaction."
}), 400 }), 400
else: else:
return jsonify({ return jsonify({
"message": "Invalid Customer or Account" "message": "Invalid Customer or Account"
+9 -7
View File
@@ -3,7 +3,8 @@ from marshmallow import ValidationError
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):
@@ -27,13 +28,14 @@ class LoanStatusService(BaseService):
account = customer.accounts[0] account = customer.accounts[0]
if (LoanStatusService.validate_account_ownership(account_id = account.id, customer_id = customer_id)): if (LoanStatusService.validate_account_ownership(account_id = account.id, customer_id = customer_id)):
transaction = LoanStatusService.log_transaction(validated_data = validated_data) with db.session.begin():
transaction = LoanStatusService.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." "message": "Failed to log transaction."
}), 400 }), 400
else: else:
return jsonify({ return jsonify({
"message": "Invalid Customer or Account" "message": "Invalid Customer or Account"
+2 -1
View File
@@ -3,7 +3,8 @@ from marshmallow import ValidationError
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.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
+26 -21
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
@@ -33,29 +34,33 @@ class ProvideLoanService(BaseService):
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 with db.session.begin():
loan = Loan.create_loan( # Save the loan details
customer_id=customer_id, loan = Loan.create_loan(
account_id=account_id, customer_id=customer_id,
offer_id=validated_data.get('offerId'), account_id=account_id,
principal_amount=validated_data.get('requestedAmount'), offer_id=validated_data.get('offerId'),
status=LoanStatus.ACTIVE principal_amount=validated_data.get('requestedAmount'),
) status=LoanStatus.ACTIVE
)
if not loan: if not loan:
logger.error(f"Failed to save loan details") logger.error(f"Failed to save loan details")
return jsonify({ return jsonify({
"message": "Failed to save loan details." "message": "Failed to save loan details."
}), 400 }), 400
# Log Transaction validated_data['refId'] = loan.id
transaction = ProvideLoanService.log_transaction(validated_data = validated_data) validated_data['refModel'] = "loan"
# Log Transaction
transaction = ProvideLoanService.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." "message": "Failed to log transaction."
}), 400 }), 400
+14 -16
View File
@@ -7,7 +7,8 @@ from app.utils.logger import logger
from app.api.schemas.repayment import RepaymentSchema 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
@@ -26,20 +27,17 @@ class RepaymentService(BaseService):
try: try:
validated_data = RepaymentService.validate_data(data, RepaymentSchema()) validated_data = RepaymentService.validate_data(data, RepaymentSchema())
customer_id = validated_data.get('customerId') customer_id = validated_data.get('customerId')
customer = RepaymentService.get_or_create_customer(validated_data)
account = customer.accounts[0]
validated_data['accountId'] = account.id
request_id = validated_data.get('requestId') request_id = validated_data.get('requestId')
loan_id = validated_data.get('debtId') loan_id = validated_data.get('debtId')
product_id = validated_data.get('productId')
if (RepaymentService.validate_account_ownership(account_id = account.id, customer_id = customer_id)): with db.session.begin():
# 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 +47,9 @@ class RepaymentService(BaseService):
"message": "Failed to save repayment details." "message": "Failed to save repayment details."
}), 400 }), 400
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,16 +60,13 @@ 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 # Simulated processing logic
response_data = { response_data = {
"customerId": "CN621868", "customerId": customer_id,
"productId": "101", "productId": product_id,
"debtId": "273194670", "debtId": loan_id,
"resultCode": "00", "resultCode": "00",
"resultDescription": "Successful" "resultDescription": "Successful"
} }
+8 -6
View File
@@ -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.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
@@ -25,13 +26,14 @@ class SelectOfferService(BaseService):
customer_id = validated_data.get('customerId') customer_id = validated_data.get('customerId')
if (SelectOfferService.validate_account_ownership(account_id = account_id, customer_id = customer_id)): if (SelectOfferService.validate_account_ownership(account_id = account_id, customer_id = customer_id)):
transaction = SelectOfferService.log_transaction(validated_data = validated_data) with db.session.begin():
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." "message": "Failed to log transaction."
}), 400 }), 400
else: else:
return jsonify({ return jsonify({
"message": "Invalid Customer or Account" "message": "Invalid Customer or Account"
-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
-2
View File
@@ -44,9 +44,7 @@ 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
+1 -4
View File
@@ -47,9 +47,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
@@ -92,8 +90,7 @@ 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 __repr__(self): def __repr__(self):
return f'<Loan {self.id}>' return f'<Loan {self.id}>'
-2
View File
@@ -44,9 +44,7 @@ class Repayment(db.Model):
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 ###