diff --git a/app/api/services/loan_status.py b/app/api/services/loan_status.py index 4ec7740..6a2c01a 100644 --- a/app/api/services/loan_status.py +++ b/app/api/services/loan_status.py @@ -1,5 +1,6 @@ from flask import request, jsonify from marshmallow import ValidationError +from app.api.enums.loan_status import LoanStatus from app.models import Customer from app.utils.logger import logger from app.api.schemas.loan_status import LoanStatusSchema @@ -33,7 +34,7 @@ class LoanStatusService(BaseService): transactionId = validated_data.get('transactionId') # Get loans - loans = [loan.to_dict() for loan in customer.loans] + loans = [loan.to_dict() for loan in customer.loans if loan.status == LoanStatus.ACTIVE] transaction = LoanStatusService.log_transaction(validated_data = validated_data) @@ -57,12 +58,17 @@ class LoanStatusService(BaseService): # } # ] + total_debt_amount = sum( + loan.get("currentLoanAmount") or 0 + for loan in loans + ) + # Simulated processing logic response_data = { "customerId": customer_id, "transactionId": transactionId, "loans": loans, - "totalDebtAmount": 8500, + "totalDebtAmount": total_debt_amount, "resultCode": "00", "resultDescription": "Successful" } diff --git a/app/api/services/provide_loan.py b/app/api/services/provide_loan.py index a4abf64..15b3607 100644 --- a/app/api/services/provide_loan.py +++ b/app/api/services/provide_loan.py @@ -31,6 +31,7 @@ class ProvideLoanService(BaseService): account_id = validated_data.get('accountId') customer_id = validated_data.get('customerId') request_id = validated_data.get('requestId') + collection_type = validated_data.get('collectionType') transaction_id = validated_data.get('transactionId') if (ProvideLoanService.validate_account_ownership(account_id = account_id, customer_id = customer_id)): @@ -38,11 +39,13 @@ class ProvideLoanService(BaseService): # 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 + customer_id = customer_id, + account_id = account_id, + offer_id = validated_data.get('offerId'), + collection_type = collection_type, + transaction_id = validated_data.get('transactionId'), + initial_loan_amount = validated_data.get('requestedAmount'), + status= LoanStatus.ACTIVE ) if not loan: diff --git a/app/config.py b/app/config.py index b23548a..4a3e597 100644 --- a/app/config.py +++ b/app/config.py @@ -32,7 +32,6 @@ class Config: ) KAFKA_BROKER = 'dev-events.simbrellang.net:9085' - KAFKA_PAYMENT_TOPIC = 'PROCESS_PAYMENT' settings = Config() diff --git a/app/models/loan.py b/app/models/loan.py index 33256e4..ab8e89f 100644 --- a/app/models/loan.py +++ b/app/models/loan.py @@ -16,10 +16,16 @@ class Loan(db.Model): autoincrement=True, ) customer_id = db.Column(db.String(50), nullable=False) + transaction_id = db.Column(db.String(50), nullable=True) account_id = db.Column(db.String(50), nullable=False) offer_id = db.Column(db.String(20), nullable=False) - principal_amount = db.Column(db.Float, nullable=False) + collection_type = db.Column(db.String(20), nullable=True) + current_loan_amount = db.Column(db.Float, nullable=True) + initial_loan_amount = db.Column(db.Float, nullable=False) + default_penalty_fee = db.Column(db.Float, default=0) + continuous_fee = db.Column(db.Float, default=0) status = db.Column(db.String(20), default='pending') + due_date = db.Column(db.DateTime, nullable=True) 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)) @@ -31,26 +37,26 @@ class Loan(db.Model): ) @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, initial_loan_amount, collection_type, transaction_id, status='pending'): # Check if customer exists is_valid = Customer.is_valid_customer(customer_id) if not is_valid: raise ValueError("Customer does not exist") - - # # Check for active loans - # has_active_loans = cls.has_active_loans(customer_id) - # if has_active_loans: - # raise ValueError("Customer has active loans") + now = datetime.now(timezone.utc) # Create and save the loan loan = cls( - customer_id=customer_id, - account_id=account_id, - offer_id=offer_id, - principal_amount=principal_amount, - status=status + customer_id = customer_id, + account_id = account_id, + offer_id = offer_id, + collection_type = collection_type, + transaction_id = transaction_id, + initial_loan_amount = initial_loan_amount, + current_loan_amount = initial_loan_amount, + due_date=now, + status = status ) try: @@ -104,14 +110,15 @@ class Loan(db.Model): 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, + 'debtId': self.id, + 'initialLoanAmount': self.initial_loan_amount, + 'currentLoanAmount': self.current_loan_amount, + 'defaultPenaltyFee': self.default_penalty_fee, + 'continuousFee': self.continuous_fee, + 'collectionType': self.collection_type, '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 + 'dueDate': self.due_date.isoformat() if self.due_date else None, + 'loanDate': self.created_at.isoformat() if self.created_at else None, } def __repr__(self): diff --git a/migrations/versions/610b7e9d15a6_migration_on_fri_apr_11_14_15_19_utc_.py b/migrations/versions/610b7e9d15a6_migration_on_fri_apr_11_14_15_19_utc_.py new file mode 100644 index 0000000..ab24390 --- /dev/null +++ b/migrations/versions/610b7e9d15a6_migration_on_fri_apr_11_14_15_19_utc_.py @@ -0,0 +1,32 @@ +"""Migration on Fri Apr 11 14:15:19 UTC 2025 + +Revision ID: 610b7e9d15a6 +Revises: 9bb0367eb486 +Create Date: 2025-04-11 14:16:12.533227 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '610b7e9d15a6' +down_revision = '9bb0367eb486' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.add_column(sa.Column('transaction_id', sa.String(length=50), nullable=True)) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.drop_column('transaction_id') + + # ### end Alembic commands ### diff --git a/migrations/versions/9bb0367eb486_migration_on_fri_apr_11_12_48_01_utc_.py b/migrations/versions/9bb0367eb486_migration_on_fri_apr_11_12_48_01_utc_.py new file mode 100644 index 0000000..be5e457 --- /dev/null +++ b/migrations/versions/9bb0367eb486_migration_on_fri_apr_11_12_48_01_utc_.py @@ -0,0 +1,40 @@ +"""Migration on Fri Apr 11 12:48:01 UTC 2025 + +Revision ID: 9bb0367eb486 +Revises: fd447d78b161 +Create Date: 2025-04-11 12:48:36.145311 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '9bb0367eb486' +down_revision = 'fd447d78b161' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.add_column(sa.Column('product_id', sa.String(length=20), nullable=True)) + batch_op.add_column(sa.Column('current_loan_amount', sa.Float(), nullable=True)) + batch_op.add_column(sa.Column('default_penalty_fee', sa.Float(), nullable=True)) + batch_op.add_column(sa.Column('continuous_fee', sa.Float(), nullable=True)) + batch_op.add_column(sa.Column('due_date', sa.DateTime(), nullable=True)) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.drop_column('due_date') + batch_op.drop_column('continuous_fee') + batch_op.drop_column('default_penalty_fee') + batch_op.drop_column('current_loan_amount') + batch_op.drop_column('product_id') + + # ### end Alembic commands ### diff --git a/migrations/versions/f6cd1bfc8832_migration_on_fri_apr_11_14_34_36_utc_.py b/migrations/versions/f6cd1bfc8832_migration_on_fri_apr_11_14_34_36_utc_.py new file mode 100644 index 0000000..498ede0 --- /dev/null +++ b/migrations/versions/f6cd1bfc8832_migration_on_fri_apr_11_14_34_36_utc_.py @@ -0,0 +1,34 @@ +"""Migration on Fri Apr 11 14:34:36 UTC 2025 + +Revision ID: f6cd1bfc8832 +Revises: 610b7e9d15a6 +Create Date: 2025-04-11 14:35:07.093967 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f6cd1bfc8832' +down_revision = '610b7e9d15a6' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.add_column(sa.Column('collection_type', sa.String(length=20), nullable=True)) + batch_op.drop_column('product_id') + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.add_column(sa.Column('product_id', sa.VARCHAR(length=20), autoincrement=False, nullable=True)) + batch_op.drop_column('collection_type') + + # ### end Alembic commands ###