import pytest from fastapi.testclient import TestClient class TestTransactionDetailsCreation: """Test transaction details creation endpoints.""" def test_create_transaction_details_with_admin_access(self, client: TestClient, admin_token: str, sample_partner, sample_product): """Test transaction details creation with admin token.""" details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": 10, "selling_price": 150, "total_value": 1500 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 201 data = response.json() assert data["partner_id"] == sample_partner.id assert data["product_id"] == sample_product.id assert data["qty"] == 10 assert data["selling_price"] == 150 assert data["total_value"] == 1500 assert "id" in data assert "created_by" in data assert "updated_by" in data assert "created_at" in data assert "updated_at" in data def test_create_transaction_details_with_write_access(self, client: TestClient, write_token: str, sample_partner, sample_product): """Test transaction details creation with write token.""" details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": 5, "selling_price": 200, "total_value": 1000 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {write_token}"}) assert response.status_code == 201 data = response.json() assert data["qty"] == 5 assert data["selling_price"] == 200 def test_create_transaction_details_unauthorized(self, client: TestClient, sample_partner, sample_product): """Test transaction details creation without authentication.""" details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": 3, "selling_price": 100, "total_value": 300 } response = client.post("/api/v1/transaction-details/", json=details_data) assert response.status_code == 403 def test_create_transaction_details_read_only_forbidden(self, client: TestClient, read_only_token: str, sample_partner, sample_product): """Test transaction details creation with read-only access should fail.""" details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": 2, "selling_price": 75, "total_value": 150 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {read_only_token}"}) assert response.status_code == 403 def test_create_transaction_details_nonexistent_partner(self, client: TestClient, admin_token: str, sample_product): """Test creating transaction details with non-existent partner.""" details_data = { "partner_id": 99999, # Non-existent partner "product_id": sample_product.id, "qty": 1, "selling_price": 100, "total_value": 100 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 400 assert "Partner not found" in response.json()["detail"] def test_create_transaction_details_nonexistent_product(self, client: TestClient, admin_token: str, sample_partner): """Test creating transaction details with non-existent product.""" details_data = { "partner_id": sample_partner.id, "product_id": 99999, # Non-existent product "qty": 1, "selling_price": 100, "total_value": 100 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 400 assert "Product not found" in response.json()["detail"] class TestTransactionDetailsRetrieval: """Test transaction details retrieval endpoints.""" @pytest.fixture def sample_transaction_details(self, client: TestClient, admin_token: str, sample_partner, sample_product): """Create sample transaction details for testing.""" details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": 5, "selling_price": 100, "total_value": 500 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) return response.json() def test_get_all_transaction_details_with_auth(self, client: TestClient, admin_token: str, sample_transaction_details): """Test retrieving all transaction details with authentication.""" response = client.get("/api/v1/transaction-details/", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert isinstance(data, list) assert len(data) >= 1 def test_get_all_transaction_details_read_only_access(self, client: TestClient, read_only_token: str, sample_transaction_details): """Test read-only user can retrieve transaction details.""" response = client.get("/api/v1/transaction-details/", headers={"Authorization": f"Bearer {read_only_token}"}) assert response.status_code == 200 data = response.json() assert isinstance(data, list) def test_get_transaction_details_unauthorized(self, client: TestClient): """Test retrieving transaction details without authentication.""" response = client.get("/api/v1/transaction-details/") assert response.status_code == 403 def test_get_transaction_details_with_pagination(self, client: TestClient, admin_token: str, sample_transaction_details): """Test transaction details retrieval with pagination.""" response = client.get("/api/v1/transaction-details/?skip=0&limit=1", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert len(data) <= 1 def test_get_single_transaction_details_by_id(self, client: TestClient, admin_token: str, sample_transaction_details): """Test retrieving single transaction details by ID.""" details_id = sample_transaction_details["id"] response = client.get(f"/api/v1/transaction-details/{details_id}", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert data["id"] == details_id assert data["qty"] == sample_transaction_details["qty"] def test_get_transaction_details_by_partner(self, client: TestClient, admin_token: str, sample_transaction_details, sample_partner): """Test retrieving transaction details by partner.""" response = client.get(f"/api/v1/transaction-details/partner/{sample_partner.id}", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert isinstance(data, list) # All returned details should belong to the specified partner for detail in data: assert detail["partner_id"] == sample_partner.id def test_get_transaction_details_by_product(self, client: TestClient, admin_token: str, sample_transaction_details, sample_product): """Test retrieving transaction details by product.""" response = client.get(f"/api/v1/transaction-details/product/{sample_product.id}", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert isinstance(data, list) # All returned details should belong to the specified product for detail in data: assert detail["product_id"] == sample_product.id def test_get_transaction_details_by_nonexistent_partner(self, client: TestClient, admin_token: str): """Test retrieving transaction details by non-existent partner.""" response = client.get("/api/v1/transaction-details/partner/99999", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 404 assert "Partner not found" in response.json()["detail"] def test_get_transaction_details_by_nonexistent_product(self, client: TestClient, admin_token: str): """Test retrieving transaction details by non-existent product.""" response = client.get("/api/v1/transaction-details/product/99999", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 404 assert "Product not found" in response.json()["detail"] def test_get_nonexistent_transaction_details(self, client: TestClient, admin_token: str): """Test retrieving non-existent transaction details.""" response = client.get("/api/v1/transaction-details/99999", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 404 assert "Transaction details not found" in response.json()["detail"] class TestTransactionDetailsUpdate: """Test transaction details update endpoints.""" @pytest.fixture def sample_transaction_details(self, client: TestClient, admin_token: str, sample_partner, sample_product): """Create sample transaction details for testing.""" details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": 10, "selling_price": 100, "total_value": 1000 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) return response.json() def test_update_transaction_details_with_write_access(self, client: TestClient, write_token: str, sample_transaction_details): """Test updating transaction details with write access.""" details_id = sample_transaction_details["id"] update_data = { "qty": 15, "selling_price": 120, "total_value": 1800 } response = client.put(f"/api/v1/transaction-details/{details_id}", json=update_data, headers={"Authorization": f"Bearer {write_token}"}) assert response.status_code == 200 data = response.json() assert data["qty"] == 15 assert data["selling_price"] == 120 assert data["total_value"] == 1800 assert data["partner_id"] == sample_transaction_details["partner_id"] # Unchanged def test_update_transaction_details_partner_and_product(self, client: TestClient, admin_token: str, sample_transaction_details, multiple_partners, multiple_products): """Test updating partner and product in transaction details.""" details_id = sample_transaction_details["id"] new_partner = multiple_partners[1] # Different partner new_product = multiple_products[1] # Different product update_data = { "partner_id": new_partner.id, "product_id": new_product.id } response = client.put(f"/api/v1/transaction-details/{details_id}", json=update_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 200 data = response.json() assert data["partner_id"] == new_partner.id assert data["product_id"] == new_product.id def test_update_transaction_details_read_only_forbidden(self, client: TestClient, read_only_token: str, sample_transaction_details): """Test updating transaction details with read-only access should fail.""" details_id = sample_transaction_details["id"] update_data = { "qty": 20 } response = client.put(f"/api/v1/transaction-details/{details_id}", json=update_data, headers={"Authorization": f"Bearer {read_only_token}"}) assert response.status_code == 403 def test_update_transaction_details_nonexistent_partner(self, client: TestClient, admin_token: str, sample_transaction_details): """Test updating transaction details with non-existent partner.""" details_id = sample_transaction_details["id"] update_data = { "partner_id": 99999 # Non-existent partner } response = client.put(f"/api/v1/transaction-details/{details_id}", json=update_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 400 assert "Partner not found" in response.json()["detail"] def test_update_transaction_details_nonexistent_product(self, client: TestClient, admin_token: str, sample_transaction_details): """Test updating transaction details with non-existent product.""" details_id = sample_transaction_details["id"] update_data = { "product_id": 99999 # Non-existent product } response = client.put(f"/api/v1/transaction-details/{details_id}", json=update_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 400 assert "Product not found" in response.json()["detail"] def test_update_nonexistent_transaction_details(self, client: TestClient, admin_token: str): """Test updating non-existent transaction details.""" update_data = { "qty": 5 } response = client.put("/api/v1/transaction-details/99999", json=update_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 404 assert "Transaction details not found" in response.json()["detail"] class TestTransactionDetailsDeletion: """Test transaction details deletion endpoints.""" @pytest.fixture def sample_transaction_details(self, client: TestClient, admin_token: str, sample_partner, sample_product): """Create sample transaction details for testing.""" details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": 2, "selling_price": 50, "total_value": 100 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) return response.json() def test_delete_transaction_details_with_admin_access(self, client: TestClient, admin_token: str, sample_transaction_details): """Test deleting transaction details with admin access.""" details_id = sample_transaction_details["id"] response = client.delete(f"/api/v1/transaction-details/{details_id}", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 204 # Verify transaction details is deleted get_response = client.get(f"/api/v1/transaction-details/{details_id}", headers={"Authorization": f"Bearer {admin_token}"}) assert get_response.status_code == 404 def test_delete_transaction_details_write_access_forbidden(self, client: TestClient, write_token: str, sample_transaction_details): """Test deleting transaction details with write access should fail.""" details_id = sample_transaction_details["id"] response = client.delete(f"/api/v1/transaction-details/{details_id}", headers={"Authorization": f"Bearer {write_token}"}) assert response.status_code == 403 def test_delete_transaction_details_read_only_forbidden(self, client: TestClient, read_only_token: str, sample_transaction_details): """Test deleting transaction details with read-only access should fail.""" details_id = sample_transaction_details["id"] response = client.delete(f"/api/v1/transaction-details/{details_id}", headers={"Authorization": f"Bearer {read_only_token}"}) assert response.status_code == 403 def test_delete_nonexistent_transaction_details(self, client: TestClient, admin_token: str): """Test deleting non-existent transaction details.""" response = client.delete("/api/v1/transaction-details/99999", headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 404 assert "Transaction details not found" in response.json()["detail"] def test_delete_transaction_details_unauthorized(self, client: TestClient, sample_transaction_details): """Test deleting transaction details without authentication.""" details_id = sample_transaction_details["id"] response = client.delete(f"/api/v1/transaction-details/{details_id}") assert response.status_code == 403 class TestTransactionDetailsValidation: """Test transaction details data validation.""" def test_create_transaction_details_missing_required_fields(self, client: TestClient, admin_token: str): """Test creating transaction details with missing required fields.""" # Missing partner_id details_data = { "product_id": 1, "qty": 1, "selling_price": 100, "total_value": 100 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 422 # Validation error def test_create_transaction_details_negative_values(self, client: TestClient, admin_token: str, sample_partner, sample_product): """Test creating transaction details with negative values.""" details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": -1, # Negative quantity "selling_price": -50, # Negative price "total_value": -50 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) # Note: This test assumes validation constraints exist for negative values # If not implemented, this test will fail and indicate missing validation assert response.status_code in [422, 201] # Either validation error or creation def test_create_transaction_details_zero_quantity(self, client: TestClient, admin_token: str, sample_partner, sample_product): """Test creating transaction details with zero quantity.""" details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": 0, # Zero quantity "selling_price": 100, "total_value": 0 } response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) # Zero quantity might be allowed depending on business rules assert response.status_code in [422, 201] def test_update_transaction_details_invalid_data_types(self, client: TestClient, admin_token: str, sample_partner, sample_product): """Test updating transaction details with invalid data types.""" # First create a transaction detail details_data = { "partner_id": sample_partner.id, "product_id": sample_product.id, "qty": 1, "selling_price": 100, "total_value": 100 } create_response = client.post("/api/v1/transaction-details/", json=details_data, headers={"Authorization": f"Bearer {admin_token}"}) details_id = create_response.json()["id"] # Try to update with invalid data types update_data = { "qty": "not_a_number", "selling_price": "also_not_a_number" } response = client.put(f"/api/v1/transaction-details/{details_id}", json=update_data, headers={"Authorization": f"Bearer {admin_token}"}) assert response.status_code == 422 # Validation error