diff --git a/api/v1/routes/billing_plan.py b/api/v1/routes/billing_plan.py index e80b30868..064a8157f 100644 --- a/api/v1/routes/billing_plan.py +++ b/api/v1/routes/billing_plan.py @@ -89,3 +89,22 @@ async def delete_a_billing_plan( status_code=status.HTTP_200_OK, message="Plan deleted successfully", ) + + +@bill_plan.get('/billing-plans/{billing_plan_id}', response_model=success_response) +async def retrieve_single_billing_plans( + billing_plan_id: str, + db: Session = Depends(get_db), + current_user: User = Depends(user_service.get_current_user) +): + """ + Endpoint to get single billing plan by id + """ + + billing_plan = billing_plan_service.fetch(db, billing_plan_id) + + return success_response( + status_code=status.HTTP_200_OK, + message="Plan fetched successfully", + data=jsonable_encoder(billing_plan) + ) \ No newline at end of file diff --git a/api/v1/services/billing_plan.py b/api/v1/services/billing_plan.py index dff328faa..664ae44a2 100644 --- a/api/v1/services/billing_plan.py +++ b/api/v1/services/billing_plan.py @@ -4,6 +4,7 @@ from api.core.base.services import Service from api.v1.schemas.plans import CreateSubscriptionPlan from api.utils.db_validators import check_model_existence +from fastapi import HTTPException class BillingPlanService(Service): @@ -30,8 +31,15 @@ def delete(self, db: Session, id: str): db.delete(plan) db.commit() - def fetch(): - pass + def fetch(self, db: Session, billing_plan_id: str): + billing_plan = db.query(BillingPlan).get(billing_plan_id) + + if billing_plan is None: + raise HTTPException( + status_code=404, detail="Billing plan not found." + ) + + return billing_plan def update(self, db: Session, id: str, schema): """ diff --git a/tests/v1/billing_plan/test_get_billing_plan.py b/tests/v1/billing_plan/test_get_billing_plan.py new file mode 100644 index 000000000..5c8344d00 --- /dev/null +++ b/tests/v1/billing_plan/test_get_billing_plan.py @@ -0,0 +1,99 @@ +from datetime import datetime, timezone +from unittest.mock import MagicMock, patch + +import pytest +from fastapi.testclient import TestClient +from sqlalchemy.orm import Session +from uuid_extensions import uuid7 + +from api.db.database import get_db +from api.v1.models.organization import Organization +from api.v1.services.user import user_service +from api.v1.services.billing_plan import billing_plan_service +from api.v1.models.user import User +from api.v1.models.billing_plan import BillingPlan +from main import app + + + +@pytest.fixture +def db_session_mock(): + db_session = MagicMock(spec=Session) + return db_session + +@pytest.fixture +def client(db_session_mock): + app.dependency_overrides[get_db] = lambda: db_session_mock + client = TestClient(app) + yield client + app.dependency_overrides = {} + + +def mock_get_current_user(): + return User( + id=str(uuid7()), + email="test@gmail.com", + password=user_service.hash_password("Testuser@123"), + first_name='Test', + last_name='User', + is_active=True, + is_super_admin=True, + created_at=datetime.now(timezone.utc), + updated_at=datetime.now(timezone.utc) + ) + +def mock_org(): + return Organization( + id=str(uuid7()), + name="Test Organization", + created_at=datetime.now(timezone.utc), + updated_at=datetime.now(timezone.utc) + ) + +def mock_billing_plan(): + return BillingPlan( + id=str(uuid7()), + organization_id=mock_org().id, + name="Premium Plan", + price=49.99, + currency="NGN", # Currency code + duration="1 year", # Duration of the plan + description="This is a premium billing plan with extra features.", + features=["Feature 1", "Feature 2", "Feature 3"], + updated_at=datetime.now(timezone.utc) + ) + + + +def test_get_billing_plan(client, db_session_mock): + '''Test to successfully create a new product category''' + + # Mock the user service to return the current user + app.dependency_overrides[user_service.get_current_user] = lambda: mock_get_current_user + app.dependency_overrides[billing_plan_service.fetch] = lambda: mock_billing_plan + + db_session_mock.add.return_value = None + db_session_mock.commit.return_value = None + db_session_mock.refresh.return_value = None + + mock_plan_instance = mock_billing_plan() + + + with patch("api.v1.services.billing_plan.BillingPlanService.fetch", return_value=mock_plan_instance) as mock_fetch: + + response = client.get(f'/api/v1/organizations/billing-plans/{mock_plan_instance.id}') + + assert response.status_code == 200 + + +def test_get_plan_unauthorized(client, db_session_mock): + '''Test for unauthorized user''' + + mock_plan_instance = mock_billing_plan() + + + with patch("api.v1.services.billing_plan.BillingPlanService.fetch", return_value=mock_plan_instance) as mock_fetch: + + response = client.get(f'/api/v1/organizations/billing-plans/{mock_plan_instance.id}') + + assert response.status_code == 401