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 logging
|
||||||
import time
|
import time
|
||||||
from typing import Optional
|
from typing import Literal, Optional
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Response
|
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
|
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(
|
def _validate_sheet_query_params(
|
||||||
form_type_code: FormTypeEnum,
|
form_type_code: FormTypeEnum,
|
||||||
sheet: str,
|
sheet: str,
|
||||||
@ -63,16 +77,23 @@ def _validate_sheet_query_params(
|
|||||||
async def get_forms(
|
async def get_forms(
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
limit: int = 100,
|
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),
|
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[BudgetFormResponse]:
|
) -> BaseListResponse[BudgetFormResponse]:
|
||||||
"""Все строки v3.budget_form для UI-выпадашки."""
|
"""Все строки v3.budget_form для UI-выпадашки."""
|
||||||
|
org_unit_ids = _parse_org_units_csv(org_units)
|
||||||
bf_service = BudgetFormService(db)
|
bf_service = BudgetFormService(db)
|
||||||
count, forms = await bf_service.get_list(
|
count, forms = await bf_service.get_list(
|
||||||
user=current_user,
|
user=current_user,
|
||||||
with_count=True,
|
with_count=True,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
|
org_unit=org_unit_ids,
|
||||||
|
form_type=form_type,
|
||||||
|
year=year,
|
||||||
load_org=True,
|
load_org=True,
|
||||||
)
|
)
|
||||||
return BaseListResponse(
|
return BaseListResponse(
|
||||||
|
|||||||
@ -18,6 +18,8 @@ class BudgetFormRepository:
|
|||||||
org_unit: int | list[int] | None = None,
|
org_unit: int | list[int] | None = None,
|
||||||
with_count: bool = False,
|
with_count: bool = False,
|
||||||
load_org: bool = False,
|
load_org: bool = False,
|
||||||
|
form_type: FormTypeEnum | str | None = None,
|
||||||
|
year: int | None = None,
|
||||||
) -> list[BudgetForm] | tuple[int, list[BudgetForm]]:
|
) -> list[BudgetForm] | tuple[int, list[BudgetForm]]:
|
||||||
if with_count:
|
if with_count:
|
||||||
query = select(func.count().over().label("total_count"), BudgetForm)
|
query = select(func.count().over().label("total_count"), BudgetForm)
|
||||||
@ -30,13 +32,18 @@ class BudgetFormRepository:
|
|||||||
else:
|
else:
|
||||||
where.append(BudgetForm.org_unit_id.in_(org_unit))
|
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)
|
query = query.where(*where)
|
||||||
if load_org:
|
if load_org:
|
||||||
query = query.options(
|
query = query.options(
|
||||||
joinedload(BudgetForm.org_unit)
|
joinedload(BudgetForm.org_unit)
|
||||||
)
|
)
|
||||||
query = query.order_by(BudgetForm.id)
|
query = query.order_by(BudgetForm.id.desc())
|
||||||
|
|
||||||
if offset is not None:
|
if offset is not None:
|
||||||
query = query.offset(offset)
|
query = query.offset(offset)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
@ -24,6 +25,9 @@ class BudgetFormService:
|
|||||||
limit: int | None = None,
|
limit: int | None = None,
|
||||||
with_count: bool = False,
|
with_count: bool = False,
|
||||||
load_org: 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]]:
|
) -> list[BudgetForm] | tuple[int, list[BudgetForm]]:
|
||||||
if user.role_id == UserRoleEnum.ADMIN:
|
if user.role_id == UserRoleEnum.ADMIN:
|
||||||
return await self.bf_repo.get_list(
|
return await self.bf_repo.get_list(
|
||||||
@ -31,17 +35,29 @@ class BudgetFormService:
|
|||||||
limit=limit,
|
limit=limit,
|
||||||
with_count=with_count,
|
with_count=with_count,
|
||||||
load_org=load_org,
|
load_org=load_org,
|
||||||
|
org_unit=org_unit,
|
||||||
|
form_type=form_type,
|
||||||
|
year=year,
|
||||||
)
|
)
|
||||||
user = await self.user_repo.get(
|
user = await self.user_repo.get(
|
||||||
user_id=user.id,
|
user_id=user.id,
|
||||||
load_orgs=True,
|
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(
|
return await self.bf_repo.get_list(
|
||||||
offset=offset,
|
offset=offset,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
org_unit=[ou.id for ou in user.org_units],
|
org_unit=allowed_org_units,
|
||||||
with_count=with_count,
|
with_count=with_count,
|
||||||
load_org=load_org,
|
load_org=load_org,
|
||||||
|
form_type=form_type,
|
||||||
|
year=year,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def get(
|
async def get(
|
||||||
|
|||||||
@ -10,6 +10,36 @@ def test_forms_list_smoke(client, admin_tokens, auth_headers):
|
|||||||
assert isinstance(payload["result"], list)
|
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):
|
def test_form_smoke(client, admin_tokens, auth_headers):
|
||||||
response = client.get("/api/v1/form/1", headers=auth_headers(admin_tokens))
|
response = client.get("/api/v1/form/1", headers=auth_headers(admin_tokens))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user