fix(form4): перенумеровать миграцию 1938 в 0055 и пересобрать _apply_form_cell поверх 0050 (СПОД, AURORA-1906)
Миграция 0050_form4_transfer_econ_calc -> 0055 (down 0054): номер 0050 занят на test. Тело v3._apply_form_cell = актуальное тело из 0050_form2_ahr_spod_column + только дельта AURORA-1938 (запрет ручной записи FORM_4 q*.transfer_econ); раньше копия опиралась на 0023 и откатывала СПОД. v_form4_sheet_sections после 0033 на test не менялась — тело без изменений. Добавлен тест на сохранение обеих правок в итоговом определении функции. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
37c2b96d61
commit
e75ed6d44f
@ -1,14 +1,14 @@
|
||||
from sql_migration import run_sql_file_migration
|
||||
|
||||
|
||||
revision = "0050"
|
||||
down_revision = "0049"
|
||||
revision = "0055"
|
||||
down_revision = "0054"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
run_sql_file_migration("0050_form4_transfer_econ_calc.sql")
|
||||
run_sql_file_migration("0055_form4_transfer_econ_calc.sql")
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
@ -11,6 +11,9 @@
|
||||
-- Буквальный Excel-перенос (ещё и минус transfer_q2 для Q1 / transfer_q3 для Q2)
|
||||
-- задваивал бы вычитание — residual_after_actual_QN уже его учитывает.
|
||||
--
|
||||
-- 0055: пересобрано поверх 0050_form2_ahr_spod_column (AURORA-1906): тело _apply_form_cell = актуальное
|
||||
-- на test + только дельта AURORA-1938 (v_form4_sheet_sections на test после 0033 не менялась).
|
||||
--
|
||||
-- 2) v3._apply_form_cell: для FORM_4 q*.transfer_econ больше нельзя писать напрямую —
|
||||
-- поле стало вычисляемым, как residual_after_actual.
|
||||
|
||||
@ -900,7 +903,7 @@ BEGIN
|
||||
ELSE
|
||||
RAISE EXCEPTION 'unknown_column: %', p_column;
|
||||
END CASE;
|
||||
|
||||
|
||||
IF (v_target_type = 'NUMERIC' OR v_target_type = 'INTEGER') AND p_value = '""'::jsonb THEN
|
||||
p_value := '"0"'::jsonb;
|
||||
END IF;
|
||||
@ -940,7 +943,7 @@ BEGIN
|
||||
IF (v_parts[1]='fact_q1' AND v_parts[2] NOT IN ('jan','feb','mar')) OR
|
||||
(v_parts[1]='fact_q2' AND v_parts[2] NOT IN ('apr','may','jun')) OR
|
||||
(v_parts[1]='fact_q3' AND v_parts[2] NOT IN ('jul','aug','sep')) OR
|
||||
(v_parts[1]='fact_q4' AND v_parts[2] NOT IN ('oct','nov','dec')) THEN
|
||||
(v_parts[1]='fact_q4' AND v_parts[2] NOT IN ('oct','nov','dec','spod')) THEN
|
||||
RAISE EXCEPTION 'unknown_column: % (месяц вне квартала)', p_column;
|
||||
END IF;
|
||||
v_target_col := 'actual_' || v_parts[2];
|
||||
@ -949,7 +952,7 @@ BEGIN
|
||||
RAISE EXCEPTION 'unknown_column: %', p_column;
|
||||
END IF;
|
||||
|
||||
|
||||
|
||||
IF v_target_type = 'NUMERIC' AND p_value = '""'::jsonb THEN
|
||||
p_value := '"0"'::jsonb;
|
||||
END IF;
|
||||
@ -1228,9 +1231,9 @@ BEGIN
|
||||
|
||||
ELSIF v_key_kind = 'line_quarter' THEN
|
||||
IF v_q IS NULL THEN RAISE EXCEPTION 'internal: quarter not set for %', p_column; END IF;
|
||||
|
||||
|
||||
IF v_target_type = 'DATE' THEN
|
||||
|
||||
|
||||
v_sql := format(
|
||||
'INSERT INTO v3.%1$I (line_id, quarter, %2$I) VALUES ($1, $2, to_date($3->>0, ''DD.MM.YYYY'')) '
|
||||
|| 'ON CONFLICT (line_id, quarter) DO UPDATE SET %2$I = EXCLUDED.%2$I',
|
||||
@ -1245,12 +1248,12 @@ BEGIN
|
||||
);
|
||||
END IF;
|
||||
|
||||
|
||||
|
||||
EXECUTE v_sql USING p_line_id, v_q, p_value;
|
||||
|
||||
ELSIF v_key_kind = 'line_actor' THEN
|
||||
IF v_actor IS NULL THEN RAISE EXCEPTION 'internal: actor not set for %', p_column; END IF;
|
||||
|
||||
|
||||
IF v_target_type = 'DATE' THEN
|
||||
v_sql := format(
|
||||
'INSERT INTO v3.%1$I (line_id, actor, %2$I) VALUES ($1, $2, to_date($3->>0, ''DD.MM.YYYY'')) '
|
||||
@ -231,3 +231,34 @@ def test_form4_ahr_transfer_econ_cell_is_read_only(client, admin_tokens, auth_he
|
||||
payload = response.json()
|
||||
assert "message" in payload
|
||||
assert "computed_field" in payload["message"] or "transfer_econ" in payload["message"]
|
||||
|
||||
|
||||
async def test_apply_form_cell_keeps_aurora_1906_spod_and_aurora_1938_guard():
|
||||
"""Регрессия на порядок миграций: 0055 (AURORA-1938) пересобирает
|
||||
v3._apply_form_cell поверх 0050_form2_ahr_spod_column (AURORA-1906), а не
|
||||
поверх старого тела 0023 — иначе CREATE OR REPLACE тихо откатил бы СПОД.
|
||||
Проверяем итоговое определение функции в БД: в нём одновременно есть
|
||||
разрешение fact_q4.spod (1906) и запрет ручной записи transfer_econ (1938)."""
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
from sqlalchemy.pool import NullPool
|
||||
|
||||
from src.core.config import settings
|
||||
|
||||
engine = create_async_engine(settings.DATABASE_URL, poolclass=NullPool)
|
||||
try:
|
||||
async with engine.connect() as conn:
|
||||
definition = (
|
||||
await conn.execute(
|
||||
text(
|
||||
"SELECT pg_get_functiondef(p.oid) FROM pg_proc p "
|
||||
"JOIN pg_namespace n ON n.oid = p.pronamespace "
|
||||
"WHERE n.nspname = 'v3' AND p.proname = '_apply_form_cell'"
|
||||
)
|
||||
)
|
||||
).scalar_one()
|
||||
finally:
|
||||
await engine.dispose()
|
||||
|
||||
assert "'oct','nov','dec','spod'" in definition, "AURORA-1906 (СПОД) откачен"
|
||||
assert "v_field = 'transfer_econ'" in definition, "AURORA-1938 (computed transfer_econ) потерян"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user