diff --git a/app/api/services/base_service.py b/app/api/services/base_service.py index aa678e0..55d03c3 100644 --- a/app/api/services/base_service.py +++ b/app/api/services/base_service.py @@ -44,15 +44,16 @@ class BaseService: return is_valid @classmethod - def log_transaction(cls, validated_data): + def log_transaction(cls, validated_data,): """ Create a new transaction. """ return Transaction.create_transaction( - transaction_id =validated_data.get("transactionId"), - account_id=validated_data.get("accountId"), - type=cls.TRANSACTION_TYPE, - channel=validated_data.get("channel"), + transaction_id = validated_data.get("transactionId"), + ref_id = validated_data.get("refId") or validated_data.get("accountId"), + ref_model = validated_data.get("refModel", "Account"), + type = cls.TRANSACTION_TYPE, + channel = validated_data.get("channel"), ) @classmethod diff --git a/app/api/services/customer_consent.py b/app/api/services/customer_consent.py index 2d1048a..da50864 100644 --- a/app/api/services/customer_consent.py +++ b/app/api/services/customer_consent.py @@ -4,7 +4,8 @@ from marshmallow import ValidationError from app.utils.logger import logger from app.api.schemas.customer_consent import CustomerConsentSchema 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): @@ -28,13 +29,14 @@ class CustomerConsentService(BaseService): 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) + with db.session.begin(): + transaction = CustomerConsentService.log_transaction(validated_data = validated_data) - if not transaction: - logger.error(f"Failed to log transaction") - return jsonify({ - "message": "Failed to log transaction." - }), 400 + if not transaction: + logger.error(f"Failed to log transaction") + return jsonify({ + "message": "Failed to log transaction." + }), 400 else: return jsonify({ "message": "Invalid Customer or Account" diff --git a/app/api/services/eligibility_check.py b/app/api/services/eligibility_check.py index d7dff72..840424b 100644 --- a/app/api/services/eligibility_check.py +++ b/app/api/services/eligibility_check.py @@ -5,6 +5,7 @@ from app.api.schemas.eligibility_check import EligibilityCheckSchema from marshmallow import ValidationError from app.api.enums import TransactionType from app.api.integrations import SimbrellaIntegration +from app.extensions import db class EligibilityCheckService(BaseService): TRANSACTION_TYPE = TransactionType.ELIGIBILITY_CHECK @@ -31,13 +32,14 @@ class EligibilityCheckService(BaseService): customer = EligibilityCheckService.get_or_create_customer(validated_data = validated_data) 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: - logger.error(f"Failed to log transaction") - return jsonify({ - "message": "Failed to log transaction." - }), 400 + if not transaction: + logger.error(f"Failed to log transaction") + return jsonify({ + "message": "Failed to log transaction." + }), 400 else: return jsonify({ "message": "Invalid Customer or Account" diff --git a/app/api/services/loan_status.py b/app/api/services/loan_status.py index cdd161c..2e03b29 100644 --- a/app/api/services/loan_status.py +++ b/app/api/services/loan_status.py @@ -3,7 +3,8 @@ from marshmallow import ValidationError from app.utils.logger import logger from app.api.schemas.loan_status import LoanStatusSchema 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): @@ -27,13 +28,14 @@ class LoanStatusService(BaseService): account = customer.accounts[0] 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: - logger.error(f"Failed to log transaction") - return jsonify({ - "message": "Failed to log transaction." - }), 400 + if not transaction: + logger.error(f"Failed to log transaction") + return jsonify({ + "message": "Failed to log transaction." + }), 400 else: return jsonify({ "message": "Invalid Customer or Account" diff --git a/app/api/services/notification_callback.py b/app/api/services/notification_callback.py index b3a1c8b..6257b2b 100644 --- a/app/api/services/notification_callback.py +++ b/app/api/services/notification_callback.py @@ -3,7 +3,8 @@ from marshmallow import ValidationError from app.api.services.base_service import BaseService from app.api.enums import TransactionType 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): TRANSACTION_TYPE = TransactionType.NOTIFICATION_CALLBACK diff --git a/app/api/services/provide_loan.py b/app/api/services/provide_loan.py index e268a92..e62fa04 100644 --- a/app/api/services/provide_loan.py +++ b/app/api/services/provide_loan.py @@ -8,6 +8,7 @@ from app.api.schemas.provide_loan import ProvideLoanSchema from threading import Thread from app.models.loan import Loan from app.api.enums import LoanStatus +from app.extensions import db class ProvideLoanService(BaseService): 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)): - # 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 - ) + with db.session.begin(): + # 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: - logger.error(f"Failed to save loan details") - return jsonify({ - "message": "Failed to save loan details." - }), 400 - - # Log Transaction - transaction = ProvideLoanService.log_transaction(validated_data = validated_data) + if not loan: + logger.error(f"Failed to save loan details") + return jsonify({ + "message": "Failed to save loan details." + }), 400 + + 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 + if not transaction: + logger.error(f"Failed to log transaction") + return jsonify({ + "message": "Failed to log transaction." + }), 400 diff --git a/app/api/services/repayment.py b/app/api/services/repayment.py index d92f8b8..f914310 100644 --- a/app/api/services/repayment.py +++ b/app/api/services/repayment.py @@ -7,7 +7,8 @@ from app.utils.logger import logger from app.api.schemas.repayment import RepaymentSchema from app.api.services.base_service import BaseService from app.api.enums import TransactionType -from threading import Thread +from threading import Thread +from app.extensions import db class RepaymentService(BaseService): TRANSACTION_TYPE = TransactionType.REPAYMENT @@ -26,20 +27,17 @@ class RepaymentService(BaseService): try: validated_data = RepaymentService.validate_data(data, RepaymentSchema()) 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') 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)): - - # Save the repayment details + + with db.session.begin(): + # Save the repayment details repayment = Repayment.create_repayment( customer_id = customer_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." }), 400 + validated_data['refId'] = repayment.id + validated_data['refModel'] = "repayment" + #Update Loan status Loan.update_status(loan_id = loan_id, status = LoanStatus.REPAID) @@ -59,16 +60,13 @@ class RepaymentService(BaseService): return jsonify({ "message": "Failed to log transaction." }), 400 - else: - return jsonify({ - "message": "Invalid Customer or Account" - }), 400 + # Simulated processing logic response_data = { - "customerId": "CN621868", - "productId": "101", - "debtId": "273194670", + "customerId": customer_id, + "productId": product_id, + "debtId": loan_id, "resultCode": "00", "resultDescription": "Successful" } diff --git a/app/api/services/select_offer.py b/app/api/services/select_offer.py index 1f07cd5..4b4c4bb 100644 --- a/app/api/services/select_offer.py +++ b/app/api/services/select_offer.py @@ -4,6 +4,7 @@ from app.api.services.base_service import BaseService from app.api.enums import TransactionType from app.utils.logger import logger from app.api.schemas.select_offer import SelectOfferSchema +from app.extensions import db class SelectOfferService(BaseService): TRANSACTION_TYPE = TransactionType.SELECT_OFFER @@ -25,13 +26,14 @@ class SelectOfferService(BaseService): customer_id = validated_data.get('customerId') 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: - logger.error(f"Failed to log transaction") - return jsonify({ - "message": "Failed to log transaction." - }), 400 + if not transaction: + logger.error(f"Failed to log transaction") + return jsonify({ + "message": "Failed to log transaction." + }), 400 else: return jsonify({ "message": "Invalid Customer or Account" diff --git a/app/models/account.py b/app/models/account.py index af4501e..e8a90ce 100644 --- a/app/models/account.py +++ b/app/models/account.py @@ -31,9 +31,7 @@ class Account(db.Model): try: db.session.add(account) - db.session.commit() except IntegrityError as err: - db.session.rollback() raise ValueError(f"Database integrity error: {err}") return account diff --git a/app/models/customer.py b/app/models/customer.py index e0fb316..c36a11a 100644 --- a/app/models/customer.py +++ b/app/models/customer.py @@ -44,9 +44,7 @@ class Customer(db.Model): account_type=account_type ) - db.session.commit() except IntegrityError as err: - db.session.rollback() raise ValueError(f"Database integrity error: {err}") return customer diff --git a/app/models/loan.py b/app/models/loan.py index 0fec3d2..252fe74 100644 --- a/app/models/loan.py +++ b/app/models/loan.py @@ -47,9 +47,7 @@ class Loan(db.Model): try: db.session.add(loan) - db.session.commit() except IntegrityError as err: - db.session.rollback() raise ValueError(f"Database integrity error: {err}") return loan @@ -92,8 +90,7 @@ class Loan(db.Model): # Update loan status and the updated_at timestamp loan.status = status - - db.session.commit() + def __repr__(self): return f'' \ No newline at end of file diff --git a/app/models/repayment.py b/app/models/repayment.py index 06b872c..f58e1a8 100644 --- a/app/models/repayment.py +++ b/app/models/repayment.py @@ -44,9 +44,7 @@ class Repayment(db.Model): try: db.session.add(repayment) - db.session.commit() except IntegrityError as err: - db.session.rollback() raise ValueError(f"Database integrity error: {err}") return repayment diff --git a/app/models/transaction.py b/app/models/transaction.py index 5bde2db..1775d2c 100644 --- a/app/models/transaction.py +++ b/app/models/transaction.py @@ -10,9 +10,9 @@ class Transaction(db.Model): primary_key=True, autoincrement=True, ) - #id = db.Column(db.Int, primary_key=True) 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) channel = db.Column(db.String(50), nullable=False) created_at = db.Column(db.DateTime, default=datetime.now(timezone.utc)) @@ -22,7 +22,7 @@ class Transaction(db.Model): return f'' @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(): # raise ValueError("Duplicate Transaction") @@ -33,17 +33,16 @@ class Transaction(db.Model): transaction = cls( - transaction_id=transaction_id, - account_id=account_id, - type=type, - channel=channel + transaction_id = transaction_id, + ref_id = ref_id, + ref_model = ref_model, + type = type, + channel = channel ) try: db.session.add(transaction) - db.session.commit() except IntegrityError as err: - db.session.rollback() raise ValueError(f"Database integrity error: {err}") return transaction diff --git a/migrations/versions/1340e7e578b9_migration_on_thu_apr_10_21_50_01_utc_.py b/migrations/versions/1340e7e578b9_migration_on_thu_apr_10_21_50_01_utc_.py new file mode 100644 index 0000000..92e0eef --- /dev/null +++ b/migrations/versions/1340e7e578b9_migration_on_thu_apr_10_21_50_01_utc_.py @@ -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 ###