Merge pull request 'delete-sattelite-rows' (#175) from delete-sattelite-rows into test
Reviewed-on: #175
This commit is contained in:
commit
469cd0e8c4
15
api/alembic/versions/0036_ahr_satellite_delete_guard.py
Normal file
15
api/alembic/versions/0036_ahr_satellite_delete_guard.py
Normal file
@ -0,0 +1,15 @@
|
||||
from sql_migration import run_sql_file_migration
|
||||
|
||||
|
||||
revision = "0036"
|
||||
down_revision = "0035"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
run_sql_file_migration("0036_ahr_satellite_delete_guard.sql")
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
pass
|
||||
128
api/alembic/versions/sql/0036_ahr_satellite_delete_guard.sql
Normal file
128
api/alembic/versions/sql/0036_ahr_satellite_delete_guard.sql
Normal file
@ -0,0 +1,128 @@
|
||||
CREATE OR REPLACE FUNCTION v3.del_budget_line(p_id integer, p_direction character varying DEFAULT NULL::character varying, p_sheet character varying DEFAULT NULL::character varying)
|
||||
RETURNS TABLE(row_type character varying, depth integer, sort_order bigint, data jsonb)
|
||||
LANGUAGE plpgsql
|
||||
AS $function$
|
||||
DECLARE
|
||||
v_form_id INT;
|
||||
v_org_id INT;
|
||||
v_sheet VARCHAR;
|
||||
v_sat_table TEXT;
|
||||
v_eid INT;
|
||||
v_line_id INT;
|
||||
v_ei_path INT[];
|
||||
BEGIN
|
||||
IF p_sheet IN ('AHR_RENT','AHR_UTILITY','AHR_SECURITY') THEN
|
||||
v_sat_table := CASE p_sheet
|
||||
WHEN 'AHR_RENT' THEN 'rent_detail'
|
||||
WHEN 'AHR_UTILITY' THEN 'utility_detail'
|
||||
WHEN 'AHR_SECURITY' THEN 'security_detail'
|
||||
END;
|
||||
|
||||
EXECUTE format(
|
||||
'SELECT bl.budget_form_id FROM v3.%I s
|
||||
JOIN v3.budget_line bl ON bl.id = s.line_id
|
||||
WHERE s.id = $1', v_sat_table
|
||||
) USING p_id INTO v_form_id;
|
||||
|
||||
IF v_form_id IS NULL THEN
|
||||
RAISE EXCEPTION '%.id=% не существует', v_sat_table, p_id;
|
||||
END IF;
|
||||
|
||||
SELECT m.target_line_id
|
||||
INTO v_line_id
|
||||
FROM v3.form2_ahr_satellite_line_source m
|
||||
WHERE m.source_sheet = p_sheet
|
||||
AND m.source_id = p_id;
|
||||
|
||||
EXECUTE format('DELETE FROM v3.%I WHERE id = $1', v_sat_table) USING p_id;
|
||||
|
||||
IF v_line_id IS NOT NULL THEN
|
||||
SELECT bl.expense_item_id
|
||||
INTO v_eid
|
||||
FROM v3.budget_line bl
|
||||
WHERE bl.id = v_line_id;
|
||||
|
||||
DELETE FROM v3.plan WHERE line_id = v_line_id;
|
||||
DELETE FROM v3.budget_line_quarter WHERE line_id = v_line_id;
|
||||
DELETE FROM v3.budget_line WHERE id = v_line_id;
|
||||
|
||||
SELECT org_unit_id INTO v_org_id FROM v3.budget_form WHERE id = v_form_id;
|
||||
|
||||
PERFORM v3.log_event(
|
||||
'ROW_DELETE', 'ROW',
|
||||
jsonb_build_object(
|
||||
'sheet', 'AHR',
|
||||
'line_id', v_line_id,
|
||||
'entity_id', v_line_id,
|
||||
'expense_item_id', v_eid,
|
||||
'direction', 'Support',
|
||||
'source_sheet', p_sheet,
|
||||
'source_id', p_id
|
||||
),
|
||||
v_form_id, NULL, v_org_id
|
||||
);
|
||||
END IF;
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
SELECT bl.budget_form_id, ei.sheet, bl.expense_item_id
|
||||
INTO v_form_id, v_sheet, v_eid
|
||||
FROM v3.budget_line bl
|
||||
JOIN v3.expense_item ei ON ei.id = bl.expense_item_id
|
||||
WHERE bl.id = p_id;
|
||||
|
||||
IF v_form_id IS NULL THEN
|
||||
RAISE EXCEPTION 'budget_line id=% не существует', p_id;
|
||||
END IF;
|
||||
|
||||
IF v_sheet = 'AHR' AND EXISTS (
|
||||
SELECT 1
|
||||
FROM v3.form2_ahr_satellite_line_source m
|
||||
WHERE m.target_line_id = p_id
|
||||
) THEN
|
||||
RAISE EXCEPTION 'Строку АХР, созданную из листа-сателлита, нельзя удалить напрямую'
|
||||
USING ERRCODE = '23503',
|
||||
HINT = 'Удалите строку на исходном листе АХР Аренда / АХР Коммунальные услуги / АХР Безопасность';
|
||||
END IF;
|
||||
|
||||
v_ei_path := v3._expense_item_path_set(ARRAY[v_eid]);
|
||||
|
||||
DELETE FROM v3.plan WHERE line_id = p_id;
|
||||
DELETE FROM v3.sequestration WHERE line_id = p_id;
|
||||
DELETE FROM v3.reserve WHERE line_id = p_id;
|
||||
DELETE FROM v3.allocation WHERE line_id = p_id;
|
||||
DELETE FROM v3.contract_summary WHERE line_id = p_id;
|
||||
DELETE FROM v3.collegial_approval WHERE line_id = p_id;
|
||||
DELETE FROM v3.ckk WHERE line_id = p_id;
|
||||
DELETE FROM v3.contract_detail WHERE line_id = p_id;
|
||||
DELETE FROM v3.booking WHERE line_id = p_id;
|
||||
DELETE FROM v3.budget_line_quarter WHERE line_id = p_id;
|
||||
DELETE FROM v3.rent_detail WHERE line_id = p_id;
|
||||
DELETE FROM v3.utility_detail WHERE line_id = p_id;
|
||||
DELETE FROM v3.security_detail WHERE line_id = p_id;
|
||||
|
||||
DELETE FROM v3.budget_line WHERE id = p_id;
|
||||
|
||||
SELECT org_unit_id INTO v_org_id FROM v3.budget_form WHERE id = v_form_id;
|
||||
|
||||
PERFORM v3.log_event(
|
||||
'ROW_DELETE', 'ROW',
|
||||
jsonb_build_object(
|
||||
'sheet', v_sheet,
|
||||
'line_id', p_id,
|
||||
'entity_id', p_id,
|
||||
'expense_item_id', v_eid,
|
||||
'direction', p_direction
|
||||
),
|
||||
v_form_id, NULL, v_org_id
|
||||
);
|
||||
|
||||
RETURN QUERY
|
||||
SELECT v.row_type, v.depth, v.sort_order, v.data
|
||||
FROM v3.v_form_view(v_form_id, v_sheet, NULL, p_direction) v
|
||||
WHERE v.row_type IN ('ROOT','GROUP','ITEM','SUB_ITEM')
|
||||
AND (v.data->'header'->>'expense_item_id')::INT = ANY(v_ei_path)
|
||||
ORDER BY v.sort_order;
|
||||
END;
|
||||
$function$;
|
||||
|
||||
@ -9,6 +9,7 @@ import time
|
||||
from typing import Any, Optional
|
||||
|
||||
#
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, status
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@ -800,6 +801,49 @@ async def notify_ahr_about_satellite_change(
|
||||
user_id: int,
|
||||
):
|
||||
try:
|
||||
if source_event == "row_deleted":
|
||||
async with get_db_session(user_id=user_id) as db:
|
||||
deleted_line_id = (
|
||||
await db.execute(
|
||||
text(
|
||||
"""
|
||||
SELECT (event_data->>'line_id')::int
|
||||
FROM v3.audit_log
|
||||
WHERE form_id = :form_id
|
||||
AND event = 'ROW_DELETE'
|
||||
AND event_type = 'ROW'
|
||||
AND event_data->>'sheet' = 'AHR'
|
||||
AND event_data->>'source_sheet' = :source_sheet
|
||||
AND (event_data->>'source_id')::int = :source_row_id
|
||||
ORDER BY id DESC
|
||||
LIMIT 1
|
||||
"""
|
||||
),
|
||||
{
|
||||
"form_id": form_id,
|
||||
"source_sheet": source_sheet,
|
||||
"source_row_id": source_row_id,
|
||||
},
|
||||
)
|
||||
).scalar_one_or_none()
|
||||
|
||||
if deleted_line_id is None:
|
||||
return
|
||||
|
||||
await manager.broadcast_to_form_sheet(
|
||||
data={
|
||||
"event": "row_deleted",
|
||||
"data": {
|
||||
"row_id": deleted_line_id,
|
||||
"source_sheet": source_sheet,
|
||||
},
|
||||
"result": [],
|
||||
},
|
||||
form_id=form_id,
|
||||
sheet="AHR",
|
||||
)
|
||||
return
|
||||
|
||||
async with get_db_session(user_id=user_id) as db:
|
||||
ahr_delta = await SheetService(db).get_form2_ahr_satellite_delta(
|
||||
form_id=form_id,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user