128 lines
4.6 KiB
Python
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()
|