From 1081467f6fba6234a6f9557451745d2249680c3f Mon Sep 17 00:00:00 2001 From: VivianDee <115420678+VivianDee@users.noreply.github.com> Date: Thu, 10 Apr 2025 17:50:25 +0100 Subject: [PATCH] [add]: DB migrations fix and Save loan repayment details --- app/api/services/provide_loan.py | 18 ++-- app/api/services/repayment.py | 16 ++++ app/models/__init__.py | 3 +- app/swagger/schemas/RepaymentRequest.json | 4 +- ...8_migration_on_thu_apr_10_16_21_45_utc_.py | 86 +++++++++++++++++++ scripts/entrypoint.sh | 1 + 6 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 migrations/versions/b8f6fd76ead8_migration_on_thu_apr_10_16_21_45_utc_.py diff --git a/app/api/services/provide_loan.py b/app/api/services/provide_loan.py index bfb4f05..495c07b 100644 --- a/app/api/services/provide_loan.py +++ b/app/api/services/provide_loan.py @@ -33,14 +33,6 @@ class ProvideLoanService(BaseService): if (ProvideLoanService.validate_account_ownership(account_id = account_id, customer_id = customer_id)): - 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 - # Save the loan details loan = Loan.create_loan( customer_id=customer_id, @@ -55,6 +47,16 @@ class ProvideLoanService(BaseService): return jsonify({ "message": "Failed to save loan details." }), 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 + else: diff --git a/app/api/services/repayment.py b/app/api/services/repayment.py index 0efd6f9..3129392 100644 --- a/app/api/services/repayment.py +++ b/app/api/services/repayment.py @@ -1,5 +1,6 @@ from flask import request, jsonify from marshmallow import ValidationError +from app.models import Repayment from app.utils.logger import logger from app.api.schemas.repayment import RepaymentSchema from app.api.services.base_service import BaseService @@ -30,6 +31,21 @@ class RepaymentService(BaseService): if (RepaymentService.validate_account_ownership(account_id = account.id, customer_id = customer_id)): + + # Save the repayment details + repayment = Repayment.create_repayment( + customer_id = customer_id, + loan_id = validated_data.get('debtId'), + product_id = validated_data.get('productId') + + ) + + if not repayment: + logger.error(f"Failed to save repayment details") + return jsonify({ + "message": "Failed to save repayment details." + }), 400 + transaction = RepaymentService.log_transaction(validated_data = validated_data) if not transaction: diff --git a/app/models/__init__.py b/app/models/__init__.py index 8fd1277..af5353a 100644 --- a/app/models/__init__.py +++ b/app/models/__init__.py @@ -2,5 +2,6 @@ from .customer import Customer from .account import Account from .loan import Loan from .transaction import Transaction +from .repayment import Repayment -__all__ = ['Customer', 'Account', 'Loan', 'Transaction'] \ No newline at end of file +__all__ = ['Customer', 'Account', 'Loan', 'Transaction', 'Repayment'] \ No newline at end of file diff --git a/app/swagger/schemas/RepaymentRequest.json b/app/swagger/schemas/RepaymentRequest.json index cb959a9..c31d585 100644 --- a/app/swagger/schemas/RepaymentRequest.json +++ b/app/swagger/schemas/RepaymentRequest.json @@ -7,7 +7,7 @@ }, "debtId": { "type": "string", - "example": "273194670" + "example": "10" }, "productId": { "type": "string", @@ -19,7 +19,7 @@ }, "customerId": { "type": "string", - "example": "CN621868" + "example": "CID0000025585" }, "channel": { "type": "string", diff --git a/migrations/versions/b8f6fd76ead8_migration_on_thu_apr_10_16_21_45_utc_.py b/migrations/versions/b8f6fd76ead8_migration_on_thu_apr_10_16_21_45_utc_.py new file mode 100644 index 0000000..69d16e7 --- /dev/null +++ b/migrations/versions/b8f6fd76ead8_migration_on_thu_apr_10_16_21_45_utc_.py @@ -0,0 +1,86 @@ +"""Migration on Thu Apr 10 16:21:45 UTC 2025 + +Revision ID: b8f6fd76ead8 +Revises: +Create Date: 2025-04-10 16:22:15.946157 + +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = 'b8f6fd76ead8' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('repayments', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('loan_id', sa.String(length=50), nullable=False), + sa.Column('customer_id', sa.String(length=50), nullable=False), + sa.Column('product_id', sa.String(length=20), nullable=True), + sa.Column('created_at', sa.DateTime(), nullable=True), + sa.Column('updated_at', sa.DateTime(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.alter_column('id', + existing_type=sa.VARCHAR(length=50), + type_=sa.Integer(), + existing_nullable=False, + autoincrement=True, + existing_server_default=sa.text("nextval('loan_id_seq'::regclass)")) + + with op.batch_alter_table('transactions', schema=None) as batch_op: + batch_op.alter_column('channel', + existing_type=sa.VARCHAR(length=8), + type_=sa.String(length=50), + existing_nullable=False) + batch_op.alter_column('created_at', + existing_type=postgresql.TIMESTAMP(timezone=True), + type_=sa.DateTime(), + existing_nullable=True, + existing_server_default=sa.text('now()')) + batch_op.alter_column('updated_at', + existing_type=postgresql.TIMESTAMP(timezone=True), + type_=sa.DateTime(), + existing_nullable=True, + existing_server_default=sa.text('now()')) + batch_op.drop_constraint('transactions_id_key', type_='unique') + + # ### 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.create_unique_constraint('transactions_id_key', ['id']) + batch_op.alter_column('updated_at', + existing_type=sa.DateTime(), + type_=postgresql.TIMESTAMP(timezone=True), + existing_nullable=True, + existing_server_default=sa.text('now()')) + batch_op.alter_column('created_at', + existing_type=sa.DateTime(), + type_=postgresql.TIMESTAMP(timezone=True), + existing_nullable=True, + existing_server_default=sa.text('now()')) + batch_op.alter_column('channel', + existing_type=sa.String(length=50), + type_=sa.VARCHAR(length=8), + existing_nullable=False) + + with op.batch_alter_table('loans', schema=None) as batch_op: + batch_op.alter_column('id', + existing_type=sa.Integer(), + type_=sa.VARCHAR(length=50), + existing_nullable=False, + autoincrement=True, + existing_server_default=sa.text("nextval('loan_id_seq'::regclass)")) + + op.drop_table('repayments') + # ### end Alembic commands ### diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index 8c7018a..3e73752 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -1,6 +1,7 @@ #!/bin/sh echo "Running DB migrations..." +flask db migrate -m "Migration on $(date)" flask db upgrade echo "Starting Gunicorn server..."