Skip to content

Commit

Permalink
Merge pull request #962 from marveldo/feat/transaction-history
Browse files Browse the repository at this point in the history
feat : endpoint To to [GET] transaction history for a user by the user ID
  • Loading branch information
johnson-oragui authored Aug 24, 2024
2 parents 1fda8cf + d2e1ac2 commit 39ad0a6
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 13 deletions.
39 changes: 34 additions & 5 deletions api/v1/routes/payment.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
from fastapi import Depends, APIRouter, status, Query, HTTPException
from sqlalchemy.orm import Session
from typing import Annotated

from fastapi.encoders import jsonable_encoder
from api.utils.success_response import success_response
from api.v1.schemas.payment import PaymentListResponse, PaymentResponse
from api.v1.services.payment import PaymentService
from api.v1.services.user import user_service
from api.db.database import get_db
from api.v1.models import User

payment = APIRouter(prefix="/payments", tags=["Payments"])
payment = APIRouter(prefix="/transactions", tags=["Transactions"])

payment_service = PaymentService()

@payment.get(
"/current-user", status_code=status.HTTP_200_OK, response_model=PaymentListResponse
Expand All @@ -28,7 +29,7 @@ def get_payments_for_current_user(
- limit: Number of payment per page (default: 10, minimum: 1)
- page: Page number (starts from 1)
"""
payment_service = PaymentService()


# FETCH all payments for current user
payments = payment_service.fetch_by_user(
Expand Down Expand Up @@ -78,14 +79,42 @@ def get_payments_for_current_user(
data=data,
)

@payment.get("/user/{user_id}", response_model=success_response, status_code=status.HTTP_200_OK)
def get_user_payments_by_id(
user_id : str,
current_user : Annotated[User , Depends(user_service.get_current_user)],
db : Annotated[Session, Depends(get_db)],
page_size: Annotated[int, Query(ge=1, description="Number of payments per page")] = 10,
page_number: Annotated[int, Query(ge=1, description="Page number (starts from 1)")] = 1
):
"""Functions that handles get all transactions for a user by id with endpoint
Args:
user_id (str): Identifier of the user
current_user (Annotated[User , Depends): Dependency to get the current User
page_size (Annotated[int, Query, optional): The total amount of instances to be returned per page. Defaults to 1, description="Number of payments per page")]=10.
page_number (Annotated[int, Query, optional): page number to be viewed. Defaults to 1, description="Page number (starts from 1)")]=1.
"""
payments = payment_service.fetch_by_user(
db=db,
user_id=user_id,
limit=page_size,
page=page_number
)
return success_response(
status_code=status.HTTP_200_OK,
message='Payments retrieved',
data=[jsonable_encoder(payment) for payment in payments]
)


@payment.get("/{payment_id}", response_model=PaymentResponse)
async def get_payment(payment_id: str, db: Session = Depends(get_db)):
'''
Endpoint to retrieve a payment by its ID.
'''

payment_service = PaymentService()
payment = payment_service.get_payment_by_id(db, payment_id)
return payment

10 changes: 5 additions & 5 deletions tests/v1/payment/test_get_payments_for_current_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def test_get_payments_successfully(
# Make request
params = {'page': 1, 'limit': 10}
headers = {'Authorization': f'Bearer {access_token_user}'}
response = client.get("/api/v1/payments/current-user", params=params, headers=headers)
response = client.get("/api/v1/transactions/current-user", params=params, headers=headers)

resp_d = response.json()

Expand Down Expand Up @@ -107,7 +107,7 @@ def test_get_payments_successfully(
# Make request, with limit set to 2, to get 3 pages
params = {'page': 1, 'limit': 2}
headers = {'Authorization': f'Bearer {access_token_user}'}
response = client.get("/api/v1/payments/current-user", params=params, headers=headers)
response = client.get("/api/v1/transactions/current-user", params=params, headers=headers)

resp_d = response.json()

Expand Down Expand Up @@ -139,14 +139,14 @@ def test_for_unauthenticated_get_payments(

# Make request || WRONG Authorization
headers = {'Authorization': f'Bearer {random_access_token}'}
response = client.get("/api/v1/payments/current-user", params=params, headers=headers)
response = client.get("/api/v1/transactions/current-user", params=params, headers=headers)

assert response.status_code == 401
assert response.json()['message'] == "Could not validate credentials"
assert not response.json().get('data')

# Make request || NO Authorization
response = client.get("/api/v1/payments/current-user", params=params)
response = client.get("/api/v1/transactions/current-user", params=params)

assert response.status_code == 401
assert response.json()['message'] == "Not authenticated"
Expand All @@ -170,7 +170,7 @@ def test_for_no_payments_for_user(
# Make request
params = {'page': 1, 'limit': 10}
headers = {'Authorization': f'Bearer {access_token_user}'}
response = client.get("/api/v1/payments/current-user", params=params, headers=headers)
response = client.get("/api/v1/transactions/current-user", params=params, headers=headers)

assert response.status_code == 404
assert response.json()['message'] == "Payments not found for user"
Expand Down
49 changes: 46 additions & 3 deletions tests/v1/payment/test_payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
from datetime import datetime
from fastapi.testclient import TestClient
from main import app
from unittest.mock import MagicMock
from api.v1.services.user import user_service
from api.v1.services.payment import PaymentService
from api.v1.schemas.payment import PaymentResponse
from api.utils.db_validators import check_model_existence

from api.db.database import get_db
from uuid_extensions import uuid7
from datetime import timezone
from api.v1.models.user import User
client = TestClient(app)

mock_payment = {
Expand All @@ -21,16 +26,54 @@
"updated_at": datetime(2024, 7, 28, 12, 31, 36, 650997)
}

@pytest.fixture
def db_session_mock():
db = MagicMock()
yield db

@pytest.fixture(autouse=True)
def override_get_db(db_session_mock):
def get_db_override():
yield db_session_mock

app.dependency_overrides[get_db] = get_db_override
yield
# Clean up after the test by removing the override
app.dependency_overrides = {}


mock_user = User(
id=str(uuid7()),
email="[email protected]",
password=user_service.hash_password("Testpassword@123"),
first_name="Mr",
last_name="Dummy",
is_active=True,
is_superadmin=False,
created_at=datetime.now(timezone.utc),
updated_at=datetime.now(timezone.utc),
)


def test_get_payment(mocker):
mocker.patch.object(PaymentService, 'get_payment_by_id', return_value=mock_payment)

response = client.get(f"/api/v1/payments/{mock_payment['id']}")
response = client.get(f"/api/v1/transactions/{mock_payment['id']}")
assert response.status_code == 200
# assert response.json() == PaymentResponse(**mock_payment).model_dump()

def test_get_payment_not_found(mocker):
mocker.patch.object(PaymentService, 'get_payment_by_id', side_effect=HTTPException(status_code=404, detail='Payment does not exist'))

response = client.get("/api/v1/payments/non_existent_id")
response = client.get("/api/v1/transactions/non_existent_id")
assert response.status_code == 404

def test_get_payments_by_user_id(db_session_mock):
app.dependency_overrides[user_service.get_current_user] = lambda : mock_user
db_session_mock.get.return_value = mock_user
db_session_mock.query().all.return_value = [mock_payment]
response = client.get(f'/api/v1/transactions/user/{mock_user.id}')
assert response.status_code == 200



0 comments on commit 39ad0a6

Please sign in to comment.