diff --git a/api/src/api/v1/projects.py b/api/src/api/v1/projects.py index 15d6a2e..3b9e3a6 100644 --- a/api/src/api/v1/projects.py +++ b/api/src/api/v1/projects.py @@ -75,15 +75,22 @@ async def get_projects( async def get_projects_with_reports( year: Optional[int] = None, branch_id: Optional[int] = None, + limit: Optional[int] = None, + offset: Optional[int] = None, + status_in: Optional[str] = None, db: AsyncSession = Depends(get_db), current_user: AppUser = Depends(get_current_active_user_with_set_db), ) -> BaseListResponse[dict]: project_service = ProjectService(db) + status_in = status_in.split(",") if status_in is not None else None count, projects = await project_service.get_list_with_reports( user=current_user, with_count=True, year=year, branch_id=branch_id, + limit=limit, + offset=offset, + status_in=status_in, ) return BaseListResponse(result=projects, count=count) diff --git a/api/src/repository/project_repository.py b/api/src/repository/project_repository.py index b70089c..18bd82f 100644 --- a/api/src/repository/project_repository.py +++ b/api/src/repository/project_repository.py @@ -39,7 +39,13 @@ class ProjectRepository: } @staticmethod - def _apply_project_filters(query, year: int | None, branch_id: int | None, org_unit_ids: list[int] | None): + def _apply_project_filters( + query, + year: int | None, + branch_id: int | None, + org_unit_ids: list[int] | None, + status_in: list[str] | None = None, + ): if year is not None: query = query.where( exists( @@ -54,6 +60,8 @@ class ProjectRepository: ) if branch_id is not None: query = query.where(Project.org_unit_id == branch_id) + if status_in is not None: + query = query.where(Project.status.in_(status_in)) if org_unit_ids is not None: if len(org_unit_ids) == 0: query = query.where(false()) @@ -162,9 +170,12 @@ class ProjectRepository: limit: int | None = None, with_count: bool = False, org_unit_ids: list[int] | None = None, + status_in: list[str] | None = None, ) -> list[dict] | tuple[int, list[dict]]: project_query = select(Project).order_by(Project.id) - project_query = self._apply_project_filters(project_query, year, branch_id, org_unit_ids) + project_query = self._apply_project_filters( + project_query, year, branch_id, org_unit_ids, status_in + ) if offset is not None: project_query = project_query.offset(offset) if limit is not None: @@ -193,7 +204,9 @@ class ProjectRepository: return payload count_query = select(func.count(Project.id)) - count_query = self._apply_project_filters(count_query, year, branch_id, org_unit_ids) + count_query = self._apply_project_filters( + count_query, year, branch_id, org_unit_ids, status_in + ) total = int((await self.db.execute(count_query)).scalar() or 0) return total, payload diff --git a/api/src/services/project_service.py b/api/src/services/project_service.py index e468c17..0c73834 100644 --- a/api/src/services/project_service.py +++ b/api/src/services/project_service.py @@ -43,6 +43,7 @@ class ProjectService: offset: int | None = None, limit: int | None = None, with_count: bool = False, + status_in: list[str] | None = None, ) -> list[dict] | tuple[int, list[dict]]: org_unit_ids = await self._allowed_org_unit_ids(user) return await self.project_repo.get_with_reports( @@ -52,6 +53,7 @@ class ProjectService: limit=limit, with_count=with_count, org_unit_ids=org_unit_ids, + status_in=status_in, ) async def get(self, project_id: int, user: AppUser) -> dict | None: diff --git a/api/tests/integration/test_projects_api_smoke.py b/api/tests/integration/test_projects_api_smoke.py index 6fcef53..2b042d4 100644 --- a/api/tests/integration/test_projects_api_smoke.py +++ b/api/tests/integration/test_projects_api_smoke.py @@ -276,6 +276,57 @@ def _get_project_with_reports(client, auth_headers, admin_tokens, project_id): return next((p for p in response.json()["result"] if p["id"] == project_id), None) +def test_projects_with_reports_filters_by_single_status(client, admin_tokens, auth_headers): + created_project_id, _ = _create_project(client, admin_tokens, auth_headers) + agreed_project_id, agreed_project_name = _create_project(client, admin_tokens, auth_headers) + update_response = client.patch( + f"/api/v1/project/{agreed_project_id}", + json={"name": agreed_project_name, "status": "agreed"}, + headers=auth_headers(admin_tokens), + ) + assert update_response.status_code == 200 + + response = client.get( + "/api/v1/projects/with-reports", + params={"status_in": "agreed"}, + headers=auth_headers(admin_tokens), + ) + + assert response.status_code == 200 + payload = response.json() + project_ids = {project["id"] for project in payload["result"]} + project_statuses = {project["status"] for project in payload["result"]} + assert len(project_statuses) == 1 + assert agreed_project_id in project_ids + assert created_project_id not in project_ids + assert {project["status"] for project in payload["result"]} == {"agreed"} + assert payload["count"] == len(payload["result"]) + + +def test_projects_with_reports_filters_by_multiple_statuses(client, admin_tokens, auth_headers): + created_project_id, _ = _create_project(client, admin_tokens, auth_headers) + agreed_project_id, agreed_project_name = _create_project(client, admin_tokens, auth_headers) + update_response = client.patch( + f"/api/v1/project/{agreed_project_id}", + json={"name": agreed_project_name, "status": "agreed"}, + headers=auth_headers(admin_tokens), + ) + assert update_response.status_code == 200 + + response = client.get( + "/api/v1/projects/with-reports", + params={"status_in": "created,agreed"}, + headers=auth_headers(admin_tokens), + ) + + assert response.status_code == 200 + payload = response.json() + project_ids = {project["id"] for project in payload["result"]} + assert {created_project_id, agreed_project_id} <= project_ids + assert {project["status"] for project in payload["result"]} <= {"created", "agreed"} + assert payload["count"] == len(payload["result"]) + + def test_upd_project_smoke(client, admin_tokens, auth_headers): project_id, name = _create_project(client, admin_tokens, auth_headers)