loapi/tests/test_payoff.py
2025-12-31 12:13:43 -06:00

128 lines
4.6 KiB
Python

"""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()