Merge pull request 'tasks-filter: фильтры для задач форм 1 2 4 и обратная сортировка' (#143) from tasks-filters into test
Reviewed-on: #143
This commit is contained in:
commit
a26125b439
@ -1,6 +1,6 @@
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional
|
||||
from typing import Literal, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response
|
||||
|
||||
@ -41,6 +41,20 @@ def _parse_sections_csv(sections: Optional[str]) -> Optional[list[str]]:
|
||||
return parsed or None
|
||||
|
||||
|
||||
def _parse_org_units_csv(org_units: Optional[str]) -> Optional[list[int]]:
|
||||
if org_units is None:
|
||||
return None
|
||||
|
||||
values = [value.strip() for value in org_units.split(",") if value.strip()]
|
||||
if not values:
|
||||
return None
|
||||
|
||||
try:
|
||||
return [int(value) for value in values]
|
||||
except ValueError as exc:
|
||||
raise HTTPException(400, "org_units должен содержать ID через запятую") from exc
|
||||
|
||||
|
||||
def _validate_sheet_query_params(
|
||||
form_type_code: FormTypeEnum,
|
||||
sheet: str,
|
||||
@ -63,16 +77,23 @@ def _validate_sheet_query_params(
|
||||
async def get_forms(
|
||||
offset: int = 0,
|
||||
limit: int = 100,
|
||||
org_units: str | None = None,
|
||||
form_type: Literal["FORM_1", "FORM_2", "FORM_4"] | None = None,
|
||||
year: int | None = None,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: AppUser = Depends(get_current_active_user_with_set_db),
|
||||
) -> BaseListResponse[BudgetFormResponse]:
|
||||
"""Все строки v3.budget_form для UI-выпадашки."""
|
||||
org_unit_ids = _parse_org_units_csv(org_units)
|
||||
bf_service = BudgetFormService(db)
|
||||
count, forms = await bf_service.get_list(
|
||||
user=current_user,
|
||||
with_count=True,
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
org_unit=org_unit_ids,
|
||||
form_type=form_type,
|
||||
year=year,
|
||||
load_org=True,
|
||||
)
|
||||
return BaseListResponse(
|
||||
|
||||
@ -18,6 +18,8 @@ class BudgetFormRepository:
|
||||
org_unit: int | list[int] | None = None,
|
||||
with_count: bool = False,
|
||||
load_org: bool = False,
|
||||
form_type: FormTypeEnum | str | None = None,
|
||||
year: int | None = None,
|
||||
) -> list[BudgetForm] | tuple[int, list[BudgetForm]]:
|
||||
if with_count:
|
||||
query = select(func.count().over().label("total_count"), BudgetForm)
|
||||
@ -30,13 +32,18 @@ class BudgetFormRepository:
|
||||
else:
|
||||
where.append(BudgetForm.org_unit_id.in_(org_unit))
|
||||
|
||||
if form_type is not None:
|
||||
where.append(BudgetForm.form_type_code == form_type)
|
||||
|
||||
if year is not None:
|
||||
where.append(BudgetForm.year == year)
|
||||
|
||||
query = query.where(*where)
|
||||
if load_org:
|
||||
query = query.options(
|
||||
joinedload(BudgetForm.org_unit)
|
||||
)
|
||||
query = query.order_by(BudgetForm.id)
|
||||
query = query.order_by(BudgetForm.id.desc())
|
||||
|
||||
if offset is not None:
|
||||
query = query.offset(offset)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
|
||||
import asyncio
|
||||
from typing import Literal
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@ -24,6 +25,9 @@ class BudgetFormService:
|
||||
limit: int | None = None,
|
||||
with_count: bool = False,
|
||||
load_org: bool = False,
|
||||
org_unit: list[int] | None = None,
|
||||
form_type: Literal["FORM_1", "FORM_2", "FORM_4"] | None = None,
|
||||
year: int | None = None,
|
||||
) -> list[BudgetForm] | tuple[int, list[BudgetForm]]:
|
||||
if user.role_id == UserRoleEnum.ADMIN:
|
||||
return await self.bf_repo.get_list(
|
||||
@ -31,17 +35,29 @@ class BudgetFormService:
|
||||
limit=limit,
|
||||
with_count=with_count,
|
||||
load_org=load_org,
|
||||
org_unit=org_unit,
|
||||
form_type=form_type,
|
||||
year=year,
|
||||
)
|
||||
user = await self.user_repo.get(
|
||||
user_id=user.id,
|
||||
load_orgs=True,
|
||||
)
|
||||
allowed_org_units = [ou.id for ou in user.org_units]
|
||||
if org_unit is not None:
|
||||
allowed_org_units = [
|
||||
org_unit_id
|
||||
for org_unit_id in org_unit
|
||||
if org_unit_id in allowed_org_units
|
||||
]
|
||||
return await self.bf_repo.get_list(
|
||||
offset=offset,
|
||||
limit=limit,
|
||||
org_unit=[ou.id for ou in user.org_units],
|
||||
org_unit=allowed_org_units,
|
||||
with_count=with_count,
|
||||
load_org=load_org,
|
||||
form_type=form_type,
|
||||
year=year,
|
||||
)
|
||||
|
||||
async def get(
|
||||
|
||||
@ -10,6 +10,36 @@ def test_forms_list_smoke(client, admin_tokens, auth_headers):
|
||||
assert isinstance(payload["result"], list)
|
||||
|
||||
|
||||
def test_forms_list_filters_and_orders_by_created_at_desc(
|
||||
client, admin_tokens, auth_headers
|
||||
):
|
||||
response = client.get(
|
||||
"/api/v1/form/",
|
||||
params={"org_units": "1,2", "form_type": "FORM_2", "year": 2026},
|
||||
headers=auth_headers(admin_tokens),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["count"] == 1
|
||||
assert [form["id"] for form in payload["result"]] == [4]
|
||||
|
||||
response = client.get("/api/v1/form/", headers=auth_headers(admin_tokens))
|
||||
assert response.status_code == 200
|
||||
forms = response.json()["result"]
|
||||
assert [form["id"] for form in forms] == sorted(
|
||||
(form["id"] for form in forms), reverse=True
|
||||
)
|
||||
|
||||
|
||||
def test_forms_list_rejects_invalid_org_units(client, admin_tokens, auth_headers):
|
||||
response = client.get(
|
||||
"/api/v1/form/",
|
||||
params={"org_units": "1,invalid"},
|
||||
headers=auth_headers(admin_tokens),
|
||||
)
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_form_smoke(client, admin_tokens, auth_headers):
|
||||
response = client.get("/api/v1/form/1", headers=auth_headers(admin_tokens))
|
||||
assert response.status_code == 200
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user