diff --git a/api/tests/integration/test_form2_ahr_satellite_spod_integration.py b/api/tests/integration/test_form2_ahr_satellite_spod_integration.py index c94d276..f3d5186 100644 --- a/api/tests/integration/test_form2_ahr_satellite_spod_integration.py +++ b/api/tests/integration/test_form2_ahr_satellite_spod_integration.py @@ -62,7 +62,12 @@ def _get_sheet_rows(client, admin_tokens, form2_id, sheet) -> list[dict]: def _find_row(rows: list[dict], predicate) -> dict: + # v_form_view prepends a META row ({"editable": [...], "role": ..., ...}, + # row_type="META", depth=-1) with no "id"/"header" — only INPUT rows carry + # satellite/AHR line data. for row in rows: + if row.get("row_type") != "INPUT": + continue if predicate(row["data"]): return row raise AssertionError("строка не найдена") @@ -141,14 +146,22 @@ def test_satellite_spod_rejects_other_quarters( @pytest.mark.parametrize("sheet", ["AHR_RENT", "AHR_UTILITY", "AHR_SECURITY"]) -def test_satellite_spod_phase_gates_non_admin_user( +def test_satellite_spod_rejected_before_phase_includes_spod_column( client, admin_tokens, isp_tokens, form2_id, sheet ): - """DFIP-пользователь (isp1): без 'fact_q4.spod' в этапе — отказ, - после появления ключа (как после data-миграции) — успех.""" + """DFIP-пользователь (isp1) с этапом, где column_keys ещё не включает + 'fact_q4.spod' (как до data-миграции): запись отклоняется. + + Note: a failed request (403/400) makes the shared test-session's + `_get_db` override call `db_ref.rollback()`, which would wipe out any + uncommitted setup done earlier in the *same* test (the satellite line, + the phase row) — see conftest.py's `client` fixture. So the "before" + and "after" migration scenarios must be two separate tests, each + ending in exactly one request that is allowed to fail. + """ line_id = _add_satellite_line(client, admin_tokens, form2_id, sheet) - phase_code = f"spod_test_{sheet.lower()}" + phase_code = f"spod_test_before_{sheet.lower()}" create_body = { "budget_form_id": form2_id, "sheet": sheet, @@ -173,9 +186,28 @@ def test_satellite_spod_phase_gates_non_admin_user( ) assert response.status_code in (400, 403, 409), response.text - response = client.patch( - f"/api/v1/stages/form/{form2_id}/{sheet}/{phase_code}", - json={**create_body, "column_keys": ["fact_q4.dec", "fact_q4.spod"]}, + +@pytest.mark.parametrize("sheet", ["AHR_RENT", "AHR_UTILITY", "AHR_SECURITY"]) +def test_satellite_spod_allowed_once_phase_includes_spod_column( + client, admin_tokens, isp_tokens, form2_id, sheet +): + """DFIP-пользователь (isp1) с этапом, где column_keys уже включает + 'fact_q4.spod' (как после data-миграции из этого PR): запись проходит.""" + line_id = _add_satellite_line(client, admin_tokens, form2_id, sheet) + + phase_code = f"spod_test_after_{sheet.lower()}" + response = client.post( + f"/api/v1/stages/form/{form2_id}", + json={ + "budget_form_id": form2_id, + "sheet": sheet, + "phase_code": phase_code, + "role": "DFIP", + "column_keys": ["fact_q4.dec", "fact_q4.spod"], + "opens_at": "2020-01-01T00:00:00", + "closes_at": "2099-01-01T00:00:00", + "direction": None, + }, headers=_auth_headers(admin_tokens), ) assert response.status_code == 200, response.text @@ -186,9 +218,3 @@ def test_satellite_spod_phase_gates_non_admin_user( headers=_auth_headers(isp_tokens), ) assert response.status_code == 200, response.text - - response = client.delete( - f"/api/v1/stages/form/{form2_id}/{sheet}/{phase_code}", - headers=_auth_headers(admin_tokens), - ) - assert response.status_code == 200, response.text