DFiP_Budget_planing/api/tests/integration/test_projects_api_smoke.py

251 lines
9.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from datetime import datetime
import uuid
import pytest
def test_projects_list_smoke(client, admin_tokens, auth_headers):
response = client.get("/api/v1/projects", headers=auth_headers(admin_tokens))
assert response.status_code == 200
payload = response.json()
assert "result" in payload
assert "count" in payload
assert isinstance(payload["result"], list)
def _create_project(client, admin_tokens, auth_headers, year=2026, branch_id=1) -> tuple[int, str]:
name = f"PT_{uuid.uuid4().hex[:10]}"
response = client.post(
"/api/v1/projects",
json={"name": name, "year": year, "branch_id": branch_id},
headers=auth_headers(admin_tokens),
)
assert response.status_code == 200
payload = response.json()
return payload["project_id"], name
def _add_line(client, admin_tokens, auth_headers, project_id: int, year: int = 2026) -> int:
for expense_item_id in range(1, 80):
response = client.post(
f"/api/v1/projects/{project_id}/report/{year}/LIMIT/line",
json={"expense_item_id": expense_item_id},
headers=auth_headers(admin_tokens),
)
if response.status_code != 200:
continue
rows = response.json()
input_row = next(
(
row
for row in rows
if row.get("row_type") == "INPUT" and row.get("data", {}).get("line_id")
),
None,
)
if input_row:
return int(input_row["data"]["line_id"])
pytest.skip("Не удалось подобрать expense_item_id для add_form3_line в текущей БД")
def test_create_project_smoke(client, admin_tokens, auth_headers):
name = f"PT_{uuid.uuid4().hex[:10]}"
response = client.post(
"/api/v1/projects",
json={"name": name, "year": None, "branch_id": 1},
headers=auth_headers(admin_tokens),
)
assert response.status_code == 200
payload = response.json()
assert "project_id" in payload
assert (project_id := payload["project_id"]) is not None
response = client.get(
f"/api/v1/projects/{project_id}",
headers=auth_headers(admin_tokens),
)
assert response.status_code == 200
payload = response.json()
assert "result" in payload
assert "id" in payload["result"]
assert payload["result"]["id"] == project_id
assert "years" in payload["result"]
assert isinstance(payload["result"]["years"], list)
assert len(payload["result"]["years"]) == 1
def test_projects_write_smoke(client, admin_tokens, auth_headers):
project_id, name = _create_project(client, admin_tokens, auth_headers)
upd_project_response = client.patch(
f"/api/v1/project/{project_id}",
json={"column": "name", "value": f"{name}_U"},
headers=auth_headers(admin_tokens),
)
assert upd_project_response.status_code == 200
line_id = _add_line(client, admin_tokens, auth_headers, project_id)
upd_cell_response = client.patch(
f"/api/v1/projects/{project_id}/report/2026/LIMIT/cell",
json={"line_id": line_id, "column": "q1.m1", "value": 100},
headers=auth_headers(admin_tokens),
)
assert upd_cell_response.status_code == 200
assert isinstance(upd_cell_response.json(), list)
upd_cells_response = client.patch(
f"/api/v1/projects/{project_id}/report/2026/LIMIT/cells",
json={
"changes": [
{"line_id": line_id, "column": "q1.m2", "value": 200},
{"line_id": line_id, "column": "q1.m3", "value": 300},
]
},
headers=auth_headers(admin_tokens),
)
assert upd_cells_response.status_code == 200
assert isinstance(upd_cells_response.json(), list)
del_line_response = client.delete(
f"/api/v1/projects/{project_id}/report/2026/LIMIT/line/{line_id}",
headers=auth_headers(admin_tokens),
)
assert del_line_response.status_code == 200
def test_projects_write_invalid_report_type_error_shape(client, admin_tokens, auth_headers):
project_id, _ = _create_project(client, admin_tokens, auth_headers)
line_id = _add_line(client, admin_tokens, auth_headers, project_id)
response = client.patch(
f"/api/v1/projects/{project_id}/report/2026/BAD_TYPE/cell",
json={"line_id": line_id, "column": "q1.m1", "value": 100},
headers=auth_headers(admin_tokens),
)
assert response.status_code == 400
payload = response.json()
assert isinstance(payload, dict)
assert "message" in payload
assert isinstance(payload["message"], str)
def test_projects_write_report_not_found_error_shape(client, admin_tokens, auth_headers):
project_id, _ = _create_project(client, admin_tokens, auth_headers)
line_id = _add_line(client, admin_tokens, auth_headers, project_id)
response = client.patch(
f"/api/v1/projects/{project_id}/report/2099/LIMIT/cell",
json={"line_id": line_id, "column": "q1.m1", "value": 100},
headers=auth_headers(admin_tokens),
)
assert response.status_code == 400
payload = response.json()
assert isinstance(payload, dict)
assert payload.get("message") == "Отчёт не найден"
def test_delete_project_smoke(client, admin_tokens, auth_headers):
project_id, _ = _create_project(client, admin_tokens, auth_headers, year=datetime.now().year)
response = client.delete(
f"/api/v1/projects/{project_id}",
headers=auth_headers(admin_tokens),
)
assert response.status_code == 200
payload = response.json()
assert payload["success"] is True
assert payload["message"] == "Проект удалён"
def test_delete_project_verify_gone(client, admin_tokens, auth_headers):
project_id, _ = _create_project(client, admin_tokens, auth_headers, year=datetime.now().year)
del_response = client.delete(
f"/api/v1/projects/{project_id}",
headers=auth_headers(admin_tokens),
)
assert del_response.status_code == 200
get_response = client.get(
f"/api/v1/projects/{project_id}",
headers=auth_headers(admin_tokens),
)
assert get_response.status_code == 404
def test_delete_project_not_found(client, admin_tokens, auth_headers):
response = client.delete(
"/api/v1/projects/99999",
headers=auth_headers(admin_tokens),
)
assert response.status_code == 400
payload = response.json()
assert isinstance(payload, dict)
assert "message" in payload
def test_delete_project_unauthorized(client):
response = client.delete("/api/v1/projects/1")
assert response.status_code == 403
#ToDo: вернуть, когда пофиксим смещение фаз в зависимости от года
# def test_delete_project_with_lines_blocked(client, admin_tokens, auth_headers):
# """Проект со строками отчёта нельзя удалить: can_delete_project → false → RAISE EXCEPTION."""
# year = datetime.now().year - 1
# project_id, _ = _create_project(client, admin_tokens, auth_headers, year=year)
# _add_line(client, admin_tokens, auth_headers, project_id, year=year)
# response = client.delete(
# f"/api/v1/projects/{project_id}",
# headers=auth_headers(admin_tokens),
# )
# assert response.status_code == 400
# payload = response.json()
# assert isinstance(payload, dict)
# assert "code" in payload
# assert "message" in payload
# assert "невозможно удалить" in payload["message"]
def test_delete_project_executor_from_other_org(client, admin_tokens, auth_headers, isp_tokens):
"""ISP1 (привязан к РФ id=2) не может удалить проект на ССП id=1 — ACL."""
project_id, _ = _create_project(client, admin_tokens, auth_headers, branch_id=1, year=datetime.now().year)
response = client.delete(
f"/api/v1/projects/{project_id}",
headers=auth_headers(isp_tokens),
)
assert response.status_code == 400
payload = response.json()
assert "message" in payload
assert payload["message"] == "Проект не найден"
#ToDo: вернуть, когда пофиксим смещение фаз в зависимости от года
# def test_delete_project_executor_from_same_org(client, isp_tokens, auth_headers):
# """ISP1 может удалить проект на своём РФ (id=2), если нет строк отчёта."""
# project_id = _create_project(client, isp_tokens, auth_headers, branch_id=2, year=datetime.now().year)
# response = client.delete(
# f"/api/v1/projects/{project_id}",
# headers=auth_headers(isp_tokens),
# )
# assert response.status_code == 200
# payload = response.json()
# assert payload["success"] is True
# assert payload["message"] == "Проект удалён"
def test_delete_seed_project_smoke(client, admin_tokens, auth_headers):
"""Проект из фикстуры (id=2) удаляется: у него нет строк отчёта, can_delete_project → true."""
response = client.delete(
"/api/v1/projects/2",
headers=auth_headers(admin_tokens),
)
assert response.status_code == 200
payload = response.json()
assert payload["success"] is True
assert payload["message"] == "Проект удалён"