"""Tests for payoff endpoints.""" from datetime import date, timedelta from decimal import Decimal from unittest.mock import patch, MagicMock import pytest from fastapi.testclient import TestClient from sqlalchemy.orm import Session from main import create_app from app.database import PO10DAY from app.resources.payoff import PayoffStatus class TestPayoffEndpoint: """Test cases for payoff endpoint.""" @pytest.fixture def client(self) -> TestClient: """Create test client.""" app = create_app() return TestClient(app) @pytest.fixture def valid_payoff_data(self) -> dict: """Valid payoff request data.""" return { "loan_id": "LOAN123", "payoff_amount": "10000.50", "payoff_date": str(date.today()), "borrower_name": "John Doe", "payment_method": "check", "notes": "Test payoff" } @patch('app.resources.payoff.get_db') def test_create_payoff_success(self, mock_get_db, client, valid_payoff_data): """Test successful payoff creation.""" # Mock database session mock_db = MagicMock(spec=Session) mock_get_db.return_value = mock_db # Mock no existing payoff mock_db.query.return_value.filter.return_value.first.return_value = None response = client.post("/payoff", json=valid_payoff_data) assert response.status_code == 201 data = response.json() assert data["status"] == PayoffStatus.PROCESSED assert data["loan_id"] == "LOAN123" assert data["payoff_amount"] == "10000.50" assert "transaction_id" in data # Verify database operations mock_db.add.assert_called_once() mock_db.commit.assert_called_once() mock_db.refresh.assert_called_once() @patch('app.resources.payoff.get_db') def test_create_payoff_duplicate_loan_id(self, mock_get_db, client, valid_payoff_data): """Test payoff creation with duplicate loan_id.""" # Mock database session mock_db = MagicMock(spec=Session) mock_get_db.return_value = mock_db # Mock existing payoff existing_payoff = MagicMock(spec=PO10DAY) mock_db.query.return_value.filter.return_value.first.return_value = existing_payoff response = client.post("/payoff", json=valid_payoff_data) assert response.status_code == 409 assert "already exists" in response.json()["detail"] def test_create_payoff_invalid_payment_method(self, client, valid_payoff_data): """Test payoff creation with invalid payment method.""" valid_payoff_data["payment_method"] = "invalid_method" response = client.post("/payoff", json=valid_payoff_data) assert response.status_code == 422 def test_create_payoff_future_date(self, client, valid_payoff_data): """Test payoff creation with future payoff date.""" future_date = date.today() + timedelta(days=1) valid_payoff_data["payoff_date"] = str(future_date) response = client.post("/payoff", json=valid_payoff_data) assert response.status_code == 422 def test_create_payoff_negative_amount(self, client, valid_payoff_data): """Test payoff creation with negative amount.""" valid_payoff_data["payoff_amount"] = "-1000.00" response = client.post("/payoff", json=valid_payoff_data) assert response.status_code == 422 def test_create_payoff_missing_required_fields(self, client): """Test payoff creation with missing required fields.""" incomplete_data = { "loan_id": "LOAN123" # Missing required fields } response = client.post("/payoff", json=incomplete_data) assert response.status_code == 422 @patch('app.resources.payoff.get_db') def test_create_payoff_database_error(self, mock_get_db, client, valid_payoff_data): """Test payoff creation with database error.""" # Mock database session mock_db = MagicMock(spec=Session) mock_get_db.return_value = mock_db # Mock no existing payoff mock_db.query.return_value.filter.return_value.first.return_value = None # Mock database error on commit mock_db.commit.side_effect = Exception("Database error") with pytest.raises(Exception): response = client.post("/payoff", json=valid_payoff_data) mock_db.rollback.assert_called_once()