Merge pull request 'create-form-back: в ручку создания задач передается список ссп, поправил падающий тест' (#41) from create-form-back into test
Reviewed-on: #41 Reviewed-by: Raykov-MS <RaykovMS@avt.rshb.ru>
This commit is contained in:
commit
d43b6faa2a
@ -363,24 +363,29 @@ async def add_form(
|
||||
form: FormCreateSchema,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: AppUser = Depends(require_admin),
|
||||
) -> BaseSingleResponse[BudgetFormResponse]:
|
||||
) -> BaseListResponse[BudgetFormResponse]:
|
||||
t0 = time.perf_counter()
|
||||
bf_service = BudgetFormService(db)
|
||||
org_service = OrgUnitService(db)
|
||||
|
||||
org_unit = await org_service.get(org_unit_id=form.org_unit_id, user=current_user)
|
||||
if not org_unit:
|
||||
raise HTTPException(404, f"ССП {form.org_unit_id} не найден")
|
||||
org_units = await org_service.get_list(user=current_user, org_unit_id=form.org_unit_ids)
|
||||
org_unit_ids = [o.id for o in org_units]
|
||||
if len(org_units) != len(form.org_unit_ids):
|
||||
not_found_ids = ", ".join(
|
||||
[str(oid) for oid in set(form.org_unit_ids) - set(org_unit_ids)],
|
||||
)
|
||||
raise HTTPException(404, f"ССП {not_found_ids} не найдены")
|
||||
|
||||
new_form = await bf_service.create(
|
||||
new_forms = await bf_service.bulk_create(
|
||||
form_type_code=form.form_type_code,
|
||||
year=form.year,
|
||||
org_unit_id=org_unit.id,
|
||||
org_unit_ids=org_unit_ids,
|
||||
)
|
||||
|
||||
db_ms = (time.perf_counter() - t0) * 1000
|
||||
response.headers["X-DB-Time-Ms"] = f"{db_ms:.2f}"
|
||||
|
||||
return BaseSingleResponse(
|
||||
result = BudgetFormResponse.model_validate(new_form),
|
||||
return BaseListResponse(
|
||||
result=[BudgetFormResponse.model_validate(new_form) for new_form in new_forms],
|
||||
count=len(new_forms),
|
||||
)
|
||||
|
||||
@ -223,7 +223,7 @@ class FormTypeSchemaEnum(str, enum.Enum):
|
||||
class FormCreateSchema(BaseModel):
|
||||
year: int
|
||||
form_type_code: FormTypeSchemaEnum
|
||||
org_unit_id: int
|
||||
org_unit_ids: list[int] = Field(..., min_length=1)
|
||||
|
||||
|
||||
class OrgUnitBaseSchema(BaseModel):
|
||||
|
||||
@ -20,6 +20,7 @@ class OrgUnitRepository:
|
||||
limit: int | None = None,
|
||||
is_ssp: bool | None = None,
|
||||
is_active: bool | None = None,
|
||||
org_unit_id: int | list[int] | None = None,
|
||||
with_count: bool = False,
|
||||
load_users: bool = False,
|
||||
) -> list[OrgUnit] | tuple[int, list[OrgUnit]]:
|
||||
@ -32,7 +33,11 @@ class OrgUnitRepository:
|
||||
where.append(OrgUnit.is_ssp == is_ssp)
|
||||
if is_active is not None:
|
||||
where.append(OrgUnit.is_active == is_active)
|
||||
|
||||
if org_unit_id is not None:
|
||||
if isinstance(org_unit_id, int):
|
||||
where.append(OrgUnit.id == org_unit_id)
|
||||
else:
|
||||
where.append(OrgUnit.id.in_(org_unit_id))
|
||||
|
||||
query = query.where(*where)
|
||||
if load_users:
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
|
||||
import asyncio
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from src.repository.user_repository import UserRepository
|
||||
@ -77,3 +79,20 @@ class BudgetFormService:
|
||||
year=year,
|
||||
org_unit_id=org_unit_id,
|
||||
)
|
||||
|
||||
async def bulk_create(
|
||||
self,
|
||||
form_type_code: str,
|
||||
year: int,
|
||||
org_unit_ids: list[int],
|
||||
) -> BudgetForm | None:
|
||||
return await asyncio.gather(
|
||||
*[
|
||||
self.create(
|
||||
form_type_code=form_type_code,
|
||||
year=year,
|
||||
org_unit_id=org_unit_id,
|
||||
)
|
||||
for org_unit_id in org_unit_ids
|
||||
]
|
||||
)
|
||||
|
||||
@ -20,6 +20,7 @@ class OrgUnitService:
|
||||
limit: int | None = None,
|
||||
is_ssp: bool | None = None,
|
||||
is_active: bool | None = None,
|
||||
org_unit_id: int | list[int] | None = None,
|
||||
with_count: bool = False,
|
||||
load_users: bool = False,
|
||||
) -> list[OrgUnit] | tuple[int, list[OrgUnit]]:
|
||||
@ -33,6 +34,7 @@ class OrgUnitService:
|
||||
is_ssp=is_ssp,
|
||||
is_active=is_active,
|
||||
load_users=load_users,
|
||||
org_unit_id=org_unit_id,
|
||||
)
|
||||
|
||||
async def get(
|
||||
|
||||
@ -140,17 +140,20 @@ def test_forms_delete_line_not_found_error_shape(client, admin_tokens, auth_head
|
||||
def test_forms_add_form_success(client, admin_tokens, auth_headers):
|
||||
response = client.post(
|
||||
"/api/v1/form/",
|
||||
json={"year": 2025, "form_type_code": "FORM_1", "org_unit_id": 1},
|
||||
json={"year": 2025, "form_type_code": "FORM_1", "org_unit_ids": [1]},
|
||||
headers=auth_headers(admin_tokens),
|
||||
)
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert "result" in payload
|
||||
assert isinstance(payload["result"], dict)
|
||||
assert payload["result"]["year"] == 2025
|
||||
|
||||
assert "id" in payload["result"]
|
||||
form_id = payload["result"]["id"]
|
||||
assert "result" in payload
|
||||
assert isinstance(payload["result"], list)
|
||||
assert len(payload["result"]) == 1
|
||||
assert "year" in payload["result"][0]
|
||||
assert payload["result"][0]["year"] == 2025
|
||||
|
||||
assert "id" in payload["result"][0]
|
||||
form_id = payload["result"][0]["id"]
|
||||
response = client.get(
|
||||
f"/api/v1/form/{form_id}",
|
||||
headers=auth_headers(admin_tokens),
|
||||
@ -161,7 +164,7 @@ def test_forms_add_form_success(client, admin_tokens, auth_headers):
|
||||
def test_forms_add_form_org_unit_not_found(client, admin_tokens, auth_headers):
|
||||
response = client.post(
|
||||
"/api/v1/form/",
|
||||
json={"year": 2025, "form_type_code": "FORM_1", "org_unit_id": 999},
|
||||
json={"year": 2025, "form_type_code": "FORM_1", "org_unit_ids": [1, 999]},
|
||||
headers=auth_headers(admin_tokens),
|
||||
)
|
||||
assert response.status_code == 404
|
||||
@ -173,7 +176,7 @@ def test_forms_add_form_org_unit_not_found(client, admin_tokens, auth_headers):
|
||||
def test_forms_add_form_forbidden_not_admin(client, isp_tokens, auth_headers):
|
||||
response = client.post(
|
||||
"/api/v1/form/",
|
||||
json={"year": 2025, "form_type_code": "FORM_1", "org_unit_id": 1},
|
||||
json={"year": 2025, "form_type_code": "FORM_1", "org_unit_ids": [1]},
|
||||
headers=auth_headers(isp_tokens),
|
||||
)
|
||||
assert response.status_code == 403
|
||||
|
||||
@ -14,6 +14,7 @@ def _build_form(
|
||||
form_type_code: FormTypeEnum = FormTypeEnum.FORM_1,
|
||||
sheet_list: list[str] | None = None,
|
||||
section_list: list[str] | None = None,
|
||||
sheet_list_with_directions: list[dict] | None = None,
|
||||
) -> SimpleNamespace:
|
||||
return SimpleNamespace(
|
||||
id=1,
|
||||
@ -25,6 +26,22 @@ def _build_form(
|
||||
code=form_type_code,
|
||||
sheet_list=sheet_list or ["AHR", "SMETA"],
|
||||
section_list=section_list or ["plan", "q1"],
|
||||
sheet_list_with_directions=sheet_list_with_directions or [
|
||||
{
|
||||
"sheet_name": "AHR",
|
||||
"direction": "Support",
|
||||
},
|
||||
{
|
||||
"sheet_name": "AHR",
|
||||
"direction": "Development",
|
||||
|
||||
},
|
||||
{
|
||||
"sheet_name": "SMETA",
|
||||
"direction": None,
|
||||
|
||||
},
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
@ -50,7 +67,15 @@ async def test_export_sheet_rejects_direction_for_unsupported_sheet():
|
||||
async def test_export_sheet_rejects_sections_for_unsupported_sheet():
|
||||
service = ExportService(AsyncMock())
|
||||
service.budget_form_service.get = AsyncMock(
|
||||
return_value=_build_form(sheet_list=["SMETA"])
|
||||
return_value=_build_form(
|
||||
sheet_list=["SMETA"],
|
||||
sheet_list_with_directions=[
|
||||
{
|
||||
"sheet_name": "SMETA",
|
||||
"direction": None,
|
||||
}
|
||||
],
|
||||
)
|
||||
)
|
||||
service.sheet_service.get = AsyncMock(return_value=[])
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user