projects-filters: offset, limit, status_in фильтры для проектов в ручке with-reports #121

Merged
tsygankoviva merged 1 commits from projects-filters into test 2026-08-26 09:14:51 +03:00
4 changed files with 76 additions and 3 deletions

View File

@ -75,15 +75,22 @@ async def get_projects(
async def get_projects_with_reports( async def get_projects_with_reports(
year: Optional[int] = None, year: Optional[int] = None,
branch_id: 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), db: AsyncSession = Depends(get_db),
current_user: AppUser = Depends(get_current_active_user_with_set_db), current_user: AppUser = Depends(get_current_active_user_with_set_db),
) -> BaseListResponse[dict]: ) -> BaseListResponse[dict]:
project_service = ProjectService(db) 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( count, projects = await project_service.get_list_with_reports(
user=current_user, user=current_user,
with_count=True, with_count=True,
year=year, year=year,
branch_id=branch_id, branch_id=branch_id,
limit=limit,
offset=offset,
status_in=status_in,
) )
return BaseListResponse(result=projects, count=count) return BaseListResponse(result=projects, count=count)

View File

@ -39,7 +39,13 @@ class ProjectRepository:
} }
@staticmethod @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: if year is not None:
query = query.where( query = query.where(
exists( exists(
@ -54,6 +60,8 @@ class ProjectRepository:
) )
if branch_id is not None: if branch_id is not None:
query = query.where(Project.org_unit_id == branch_id) 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 org_unit_ids is not None:
if len(org_unit_ids) == 0: if len(org_unit_ids) == 0:
query = query.where(false()) query = query.where(false())
@ -162,9 +170,12 @@ class ProjectRepository:
limit: int | None = None, limit: int | None = None,
with_count: bool = False, with_count: bool = False,
org_unit_ids: list[int] | None = None, org_unit_ids: list[int] | None = None,
status_in: list[str] | None = None,
) -> list[dict] | tuple[int, list[dict]]: ) -> list[dict] | tuple[int, list[dict]]:
project_query = select(Project).order_by(Project.id) 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: if offset is not None:
project_query = project_query.offset(offset) project_query = project_query.offset(offset)
if limit is not None: if limit is not None:
@ -193,7 +204,9 @@ class ProjectRepository:
return payload return payload
count_query = select(func.count(Project.id)) 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) total = int((await self.db.execute(count_query)).scalar() or 0)
return total, payload return total, payload

View File

@ -43,6 +43,7 @@ class ProjectService:
offset: int | None = None, offset: int | None = None,
limit: int | None = None, limit: int | None = None,
with_count: bool = False, with_count: bool = False,
status_in: list[str] | None = None,
) -> list[dict] | tuple[int, list[dict]]: ) -> list[dict] | tuple[int, list[dict]]:
org_unit_ids = await self._allowed_org_unit_ids(user) org_unit_ids = await self._allowed_org_unit_ids(user)
return await self.project_repo.get_with_reports( return await self.project_repo.get_with_reports(
@ -52,6 +53,7 @@ class ProjectService:
limit=limit, limit=limit,
with_count=with_count, with_count=with_count,
org_unit_ids=org_unit_ids, org_unit_ids=org_unit_ids,
status_in=status_in,
) )
async def get(self, project_id: int, user: AppUser) -> dict | None: async def get(self, project_id: int, user: AppUser) -> dict | None:

View File

@ -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) 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): def test_upd_project_smoke(client, admin_tokens, auth_headers):
project_id, name = _create_project(client, admin_tokens, auth_headers) project_id, name = _create_project(client, admin_tokens, auth_headers)