Merge pull request 'fix(form2): дельта АХР пуста для статей глубины 4 после правки лимита (AURORA-1850, часть #296)' (#301) from feat/296-ahr-delta-depth4 into test
This commit is contained in:
commit
bf449c5754
15
api/alembic/versions/0058_form2_ahr_delta_depth4.py
Normal file
15
api/alembic/versions/0058_form2_ahr_delta_depth4.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from sql_migration import run_sql_file_migration
|
||||||
|
|
||||||
|
|
||||||
|
revision = "0058"
|
||||||
|
down_revision = "0057"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
run_sql_file_migration("0058_form2_ahr_delta_depth4.sql")
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
pass
|
||||||
86
api/alembic/versions/sql/0058_form2_ahr_delta_depth4.sql
Normal file
86
api/alembic/versions/sql/0058_form2_ahr_delta_depth4.sql
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
-- AURORA-1850 / issue #296: дельта АХР после правки лимита пуста для статей
|
||||||
|
-- глубины 4 (принтеры / МФУ / копировальные аппараты): открытый АХР не
|
||||||
|
-- обновляет сумму до перезагрузки.
|
||||||
|
--
|
||||||
|
-- Причина: 0053 пересоздала v3.get_form2_ahr_satellite_delta по телу из 0031 —
|
||||||
|
-- с сопоставлением лимитного шаблона «ei.depth = 3 AND (item_id = code OR
|
||||||
|
-- num_group_id = code)», то есть откатила правку 0037. По 0037 (и как во всех
|
||||||
|
-- остальных функциях синхронизации, в том числе в 0052/0053) по item_id
|
||||||
|
-- сопоставляется только статья глубины 3, а по num_group_id — статья любой
|
||||||
|
-- глубины. Лимиты с кодом num_group_id статьи глубины 4 в target_lines не
|
||||||
|
-- попадали, и дельта была пустой.
|
||||||
|
--
|
||||||
|
-- Тело — из 0053 (с SUB_SUB_ITEM в заголовках, issue #294) + матчер 0037.
|
||||||
|
-- Позже 0053 функцию никто не переопределял (проверено по 0054–0057).
|
||||||
|
CREATE OR REPLACE FUNCTION v3.get_form2_ahr_satellite_delta(
|
||||||
|
p_form_id integer,
|
||||||
|
p_source_sheet character varying,
|
||||||
|
p_source_row_id integer
|
||||||
|
)
|
||||||
|
RETURNS TABLE(
|
||||||
|
row_type character varying,
|
||||||
|
depth integer,
|
||||||
|
sort_order bigint,
|
||||||
|
data jsonb
|
||||||
|
)
|
||||||
|
LANGUAGE sql
|
||||||
|
STABLE
|
||||||
|
AS $function$
|
||||||
|
WITH target_lines AS (
|
||||||
|
SELECT m.target_line_id AS line_id
|
||||||
|
FROM v3.form2_ahr_satellite_line_source m
|
||||||
|
JOIN v3.budget_line bl ON bl.id = m.target_line_id
|
||||||
|
WHERE m.source_sheet = p_source_sheet
|
||||||
|
AND m.source_id = p_source_row_id
|
||||||
|
AND bl.budget_form_id = p_form_id
|
||||||
|
AND p_source_sheet IN ('AHR_RENT', 'AHR_UTILITY', 'AHR_SECURITY')
|
||||||
|
|
||||||
|
UNION
|
||||||
|
|
||||||
|
SELECT bl.id AS line_id
|
||||||
|
FROM v3.limit_template lt
|
||||||
|
JOIN v3.expense_item ei
|
||||||
|
ON ei.sheet = 'AHR'
|
||||||
|
AND ei.direction = 'Support'
|
||||||
|
AND (
|
||||||
|
(ei.depth = 3 AND ei.item_id = lt.expense_item_code)
|
||||||
|
OR ei.num_group_id = lt.expense_item_code
|
||||||
|
)
|
||||||
|
JOIN v3.budget_line bl
|
||||||
|
ON bl.budget_form_id = p_form_id
|
||||||
|
AND bl.expense_item_id = ei.id
|
||||||
|
AND bl.source_sheet = 'AHR_LIMIT'
|
||||||
|
AND bl.name = regexp_replace(
|
||||||
|
lt.name,
|
||||||
|
'^[[:space:]]*-[[:space:]]*',
|
||||||
|
''
|
||||||
|
)
|
||||||
|
WHERE p_source_sheet = 'AHR_LIMIT'
|
||||||
|
AND lt.id = p_source_row_id
|
||||||
|
AND lt.row_type = 'LEAF'
|
||||||
|
),
|
||||||
|
target_path AS (
|
||||||
|
SELECT unnest(
|
||||||
|
v3._expense_item_path_set(
|
||||||
|
COALESCE(array_agg(bl.expense_item_id), ARRAY[]::integer[])
|
||||||
|
)
|
||||||
|
) AS expense_item_id
|
||||||
|
FROM target_lines tl
|
||||||
|
JOIN v3.budget_line bl ON bl.id = tl.line_id
|
||||||
|
)
|
||||||
|
SELECT v.row_type, v.depth, v.sort_order, v.data
|
||||||
|
FROM v3.v_form_view(p_form_id, 'AHR', NULL, 'Support') v
|
||||||
|
WHERE (
|
||||||
|
v.row_type IN ('ROOT', 'GROUP', 'ITEM', 'SUB_ITEM', 'SUB_SUB_ITEM')
|
||||||
|
AND (v.data->'header'->>'expense_item_id')::INT IN (
|
||||||
|
SELECT expense_item_id FROM target_path
|
||||||
|
)
|
||||||
|
)
|
||||||
|
OR (
|
||||||
|
v.row_type = 'INPUT'
|
||||||
|
AND (v.data->>'line_id')::INT IN (
|
||||||
|
SELECT line_id FROM target_lines
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY v.sort_order;
|
||||||
|
$function$;
|
||||||
@ -31,16 +31,23 @@ OLD_DEPTH3_MATCHER = re.compile(r"ei\.depth\s*=\s*3\s+AND\s*\(") # вид до
|
|||||||
|
|
||||||
def test_ahr_delta_keeps_0037_num_group_matching(client, headers, db_exec):
|
def test_ahr_delta_keeps_0037_num_group_matching(client, headers, db_exec):
|
||||||
found = db_exec(
|
found = db_exec(
|
||||||
"""SELECT lt.id FROM v3.limit_template lt
|
"""SELECT lt.id, ei.id FROM v3.limit_template lt
|
||||||
JOIN v3.expense_item ei ON ei.num_group_id = lt.expense_item_code
|
JOIN v3.expense_item ei ON ei.num_group_id = lt.expense_item_code
|
||||||
AND ei.sheet = 'AHR' AND ei.direction = 'Support' AND ei.depth = 4
|
AND ei.sheet = 'AHR' AND ei.direction = 'Support' AND ei.depth = 4
|
||||||
WHERE lt.row_type = 'LEAF' ORDER BY lt.id LIMIT 1""")
|
WHERE lt.row_type = 'LEAF' ORDER BY lt.id LIMIT 1""")
|
||||||
if not found:
|
if not found:
|
||||||
pytest.skip("нет LEAF шаблона с кодом = num_group_id статьи AHR глубины 4")
|
pytest.skip("нет LEAF шаблона с кодом = num_group_id статьи AHR глубины 4")
|
||||||
lt_id = found[0][0]
|
lt_id, ei_id = found[0]
|
||||||
_patch_cell(client, headers, 4, "AHR_LIMIT", lt_id, "qty_q1", 4)
|
_patch_cell(client, headers, 4, "AHR_LIMIT", lt_id, "qty_q1", 4)
|
||||||
delta = db_exec("SELECT row_type FROM v3.get_form2_ahr_satellite_delta(4, 'AHR_LIMIT', :i)", i=lt_id)
|
delta = db_exec(
|
||||||
assert any(r[0] == "INPUT" for r in delta), "дельта АХР пуста — откат сопоставления 0037"
|
"SELECT row_type, data->'header'->>'expense_item_id' FROM v3.get_form2_ahr_satellite_delta(4, 'AHR_LIMIT', :i)",
|
||||||
|
i=lt_id,
|
||||||
|
)
|
||||||
|
# AURORA-1887 скрыл лимитные INPUT-строки на листе AHR — в дельте остаются
|
||||||
|
# заголовки статьи и её предков; для статьи глубины 4 это SUB_SUB_ITEM.
|
||||||
|
assert any(r[0] == "SUB_SUB_ITEM" and int(r[1]) == ei_id for r in delta), (
|
||||||
|
f"в дельте АХР нет заголовка статьи глубины 4 — откат сопоставления 0037: {delta}"
|
||||||
|
)
|
||||||
src = db_exec("SELECT pg_get_functiondef(CAST(:s AS regprocedure))",
|
src = db_exec("SELECT pg_get_functiondef(CAST(:s AS regprocedure))",
|
||||||
s="v3.get_form2_ahr_satellite_delta(integer,character varying,integer)")[0][0]
|
s="v3.get_form2_ahr_satellite_delta(integer,character varying,integer)")[0][0]
|
||||||
assert "ei.num_group_id = lt.expense_item_code" in src
|
assert "ei.num_group_id = lt.expense_item_code" in src
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user