projects-summary-handler: ручка для таблицы снизу страницы навигации #93
82
api/alembic/versions/0017_project_summary.py
Normal file
82
api/alembic/versions/0017_project_summary.py
Normal file
@ -0,0 +1,82 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
from alembic import op
|
||||
|
||||
|
||||
revision = "0017"
|
||||
down_revision = "0016"
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
_DOLLAR_TAG_RE = re.compile(r"\$\w+\$")
|
||||
|
||||
|
||||
def _find_dollar_tag(line: str) -> str | None:
|
||||
m = _DOLLAR_TAG_RE.search(line.strip())
|
||||
return m.group(0) if m else None
|
||||
|
||||
|
||||
def _split_statements(sql: str) -> list[str]:
|
||||
statements: list[str] = []
|
||||
current: list[str] = []
|
||||
in_dollar = False
|
||||
dollar_tag: str | None = None
|
||||
|
||||
for line in sql.split("\n"):
|
||||
stripped = line.strip()
|
||||
if stripped.startswith("--"):
|
||||
continue
|
||||
|
||||
if not in_dollar:
|
||||
tag = _find_dollar_tag(stripped)
|
||||
if tag and tag.endswith("$") and tag.startswith("$"):
|
||||
dollar_tag = tag
|
||||
in_dollar = True
|
||||
current.append(line)
|
||||
continue
|
||||
|
||||
if in_dollar and dollar_tag and stripped.startswith(dollar_tag):
|
||||
after = stripped[len(dollar_tag):].strip()
|
||||
if after == ";" or after == "":
|
||||
in_dollar = False
|
||||
dollar_tag = None
|
||||
if after == ";":
|
||||
current.append(line)
|
||||
statements.append("\n".join(current))
|
||||
current = []
|
||||
continue
|
||||
|
||||
if not in_dollar and stripped.rstrip().endswith(";"):
|
||||
current.append(line)
|
||||
statements.append("\n".join(current))
|
||||
current = []
|
||||
continue
|
||||
|
||||
current.append(line)
|
||||
|
||||
remaining = "\n".join(current).strip()
|
||||
if remaining:
|
||||
statements.append(remaining)
|
||||
|
||||
return statements
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
ddl_path = os.path.join(os.path.dirname(__file__), "sql", "0017_project_summary.sql")
|
||||
with open(ddl_path) as f:
|
||||
content = f.read()
|
||||
|
||||
statements = _split_statements(content)
|
||||
for stmt in statements:
|
||||
stripped = stmt.strip().rstrip(";").strip()
|
||||
if not stripped:
|
||||
continue
|
||||
if all(l.strip().startswith("--") or not l.strip() for l in stripped.split("\n")):
|
||||
continue
|
||||
op.execute(stripped)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
pass
|
||||
149
api/alembic/versions/sql/0017_project_summary.sql
Normal file
149
api/alembic/versions/sql/0017_project_summary.sql
Normal file
@ -0,0 +1,149 @@
|
||||
-- DROP FUNCTION v3.v_project_summary_jsonb(int4);
|
||||
|
||||
CREATE OR REPLACE FUNCTION v3.v_project_summary_jsonb(p_project_id integer)
|
||||
RETURNS TABLE(row_type character varying, depth integer, sort_order bigint, data jsonb)
|
||||
LANGUAGE sql
|
||||
STABLE
|
||||
AS $function$
|
||||
WITH
|
||||
project AS (
|
||||
SELECT p.id, p.name
|
||||
FROM v3.project p
|
||||
WHERE p.id = p_project_id
|
||||
),
|
||||
base AS (
|
||||
SELECT
|
||||
rpy.year,
|
||||
r.report_type,
|
||||
ei.sheet,
|
||||
q.quarter,
|
||||
q.adj_by_items,
|
||||
q.adj_increase,
|
||||
q.actual_m1, q.actual_m2, q.actual_m3
|
||||
FROM v3.rf_project_year rpy
|
||||
LEFT JOIN v3.rf_project_report r ON r.rf_project_year_id = rpy.id
|
||||
LEFT JOIN v3.rf_project_report_line l ON l.rf_project_report_id = r.id
|
||||
LEFT JOIN v3.rf_project_report_quarter q ON q.rf_project_report_line_id = l.id
|
||||
LEFT JOIN v3.expense_item ei ON ei.id = l.expense_item_id
|
||||
WHERE rpy.project_id = p_project_id
|
||||
),
|
||||
py AS (
|
||||
SELECT
|
||||
year,
|
||||
-- Объем финансирования по контрольному листу (годовой базовый план = adj_by_items)
|
||||
COALESCE(SUM(adj_by_items) FILTER (WHERE sheet = 'AHR'), 0) AS fin_ahr,
|
||||
COALESCE(SUM(adj_by_items) FILTER (WHERE sheet = 'AHR' AND report_type = 'LIMIT'), 0) AS fin_ahr_limit,
|
||||
COALESCE(SUM(adj_by_items) FILTER (WHERE sheet = 'AHR' AND report_type = 'CURRENT_EXPENSES'), 0) AS fin_ahr_current,
|
||||
COALESCE(SUM(adj_by_items) FILTER (WHERE sheet = 'CAP' AND report_type = 'LIMIT'), 0) AS fin_kv,
|
||||
-- Базовый период 01.01-31.03 (базовый план, квартал 1)
|
||||
COALESCE(SUM(adj_by_items) FILTER (WHERE sheet = 'AHR' AND quarter = 1), 0) AS bq1_ahr,
|
||||
COALESCE(SUM(adj_by_items) FILTER (WHERE sheet = 'AHR' AND quarter = 1 AND report_type = 'LIMIT'), 0) AS bq1_ahr_limit,
|
||||
COALESCE(SUM(adj_by_items) FILTER (WHERE sheet = 'AHR' AND quarter = 1 AND report_type = 'CURRENT_EXPENSES'), 0) AS bq1_ahr_current,
|
||||
COALESCE(SUM(adj_by_items) FILTER (WHERE sheet = 'CAP' AND quarter = 1 AND report_type = 'LIMIT'), 0) AS bq1_kv,
|
||||
-- Скорректированный период 01.04-30.06 (квартал 2, corrected_plan = adj_by_items + adj_increase)
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 2), 0) AS cq2_ahr,
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 2 AND report_type = 'LIMIT'), 0) AS cq2_ahr_limit,
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 2 AND report_type = 'CURRENT_EXPENSES'), 0) AS cq2_ahr_current,
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 2 AND report_type = 'LIMIT'), 0) AS cq2_kv,
|
||||
-- Скорректированный период 01.07-30.09 (квартал 3)
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 3), 0) AS cq3_ahr,
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 3 AND report_type = 'LIMIT'), 0) AS cq3_ahr_limit,
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 3 AND report_type = 'CURRENT_EXPENSES'), 0) AS cq3_ahr_current,
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 3 AND report_type = 'LIMIT'), 0) AS cq3_kv,
|
||||
-- Скорректированный период 01.10-31.12 (квартал 4)
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 4), 0) AS cq4_ahr,
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 4 AND report_type = 'LIMIT'), 0) AS cq4_ahr_limit,
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 4 AND report_type = 'CURRENT_EXPENSES'), 0) AS cq4_ahr_current,
|
||||
COALESCE(SUM(COALESCE(adj_by_items,0)+COALESCE(adj_increase,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 4 AND report_type = 'LIMIT'), 0) AS cq4_kv,
|
||||
-- Фактические расходы АХР по кварталам (actual = m1+m2+m3)
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 1), 0) AS aq1_ahr,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 1 AND report_type = 'LIMIT'), 0) AS aq1_ahr_limit,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 1 AND report_type = 'CURRENT_EXPENSES'), 0) AS aq1_ahr_current,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 2), 0) AS aq2_ahr,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 2 AND report_type = 'LIMIT'), 0) AS aq2_ahr_limit,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 2 AND report_type = 'CURRENT_EXPENSES'), 0) AS aq2_ahr_current,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 3), 0) AS aq3_ahr,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 3 AND report_type = 'LIMIT'), 0) AS aq3_ahr_limit,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 3 AND report_type = 'CURRENT_EXPENSES'), 0) AS aq3_ahr_current,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 4), 0) AS aq4_ahr,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 4 AND report_type = 'LIMIT'), 0) AS aq4_ahr_limit,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'AHR' AND quarter = 4 AND report_type = 'CURRENT_EXPENSES'), 0) AS aq4_ahr_current,
|
||||
-- Фактические расходы КВ по кварталам
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 1), 0) AS aq1_kv,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 1 AND report_type = 'LIMIT'), 0) AS aq1_kv_limit,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 1 AND report_type = 'CURRENT_EXPENSES'), 0) AS aq1_kv_current,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 2), 0) AS aq2_kv,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 2 AND report_type = 'LIMIT'), 0) AS aq2_kv_limit,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 2 AND report_type = 'CURRENT_EXPENSES'), 0) AS aq2_kv_current,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 3), 0) AS aq3_kv,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 3 AND report_type = 'LIMIT'), 0) AS aq3_kv_limit,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 3 AND report_type = 'CURRENT_EXPENSES'), 0) AS aq3_kv_current,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 4), 0) AS aq4_kv,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 4 AND report_type = 'LIMIT'), 0) AS aq4_kv_limit,
|
||||
COALESCE(SUM(COALESCE(actual_m1,0)+COALESCE(actual_m2,0)+COALESCE(actual_m3,0)) FILTER (WHERE sheet = 'CAP' AND quarter = 4 AND report_type = 'CURRENT_EXPENSES'), 0) AS aq4_kv_current
|
||||
FROM base
|
||||
GROUP BY year
|
||||
),
|
||||
rows AS (
|
||||
SELECT 'PROJECT'::varchar AS row_type, NULL::int AS year,
|
||||
NULL::numeric AS fin_ahr, NULL::numeric AS fin_ahr_limit, NULL::numeric AS fin_ahr_current, NULL::numeric AS fin_kv,
|
||||
NULL::numeric AS bq1_ahr, NULL::numeric AS bq1_ahr_limit, NULL::numeric AS bq1_ahr_current, NULL::numeric AS bq1_kv,
|
||||
NULL::numeric AS cq2_ahr, NULL::numeric AS cq2_ahr_limit, NULL::numeric AS cq2_ahr_current, NULL::numeric AS cq2_kv,
|
||||
NULL::numeric AS cq3_ahr, NULL::numeric AS cq3_ahr_limit, NULL::numeric AS cq3_ahr_current, NULL::numeric AS cq3_kv,
|
||||
NULL::numeric AS cq4_ahr, NULL::numeric AS cq4_ahr_limit, NULL::numeric AS cq4_ahr_current, NULL::numeric AS cq4_kv,
|
||||
NULL::numeric AS aq1_ahr, NULL::numeric AS aq1_ahr_limit, NULL::numeric AS aq1_ahr_current,
|
||||
NULL::numeric AS aq2_ahr, NULL::numeric AS aq2_ahr_limit, NULL::numeric AS aq2_ahr_current,
|
||||
NULL::numeric AS aq3_ahr, NULL::numeric AS aq3_ahr_limit, NULL::numeric AS aq3_ahr_current,
|
||||
NULL::numeric AS aq4_ahr, NULL::numeric AS aq4_ahr_limit, NULL::numeric AS aq4_ahr_current,
|
||||
NULL::numeric AS aq1_kv, NULL::numeric AS aq1_kv_limit, NULL::numeric AS aq1_kv_current,
|
||||
NULL::numeric AS aq2_kv, NULL::numeric AS aq2_kv_limit, NULL::numeric AS aq2_kv_current,
|
||||
NULL::numeric AS aq3_kv, NULL::numeric AS aq3_kv_limit, NULL::numeric AS aq3_kv_current,
|
||||
NULL::numeric AS aq4_kv, NULL::numeric AS aq4_kv_limit, NULL::numeric AS aq4_kv_current
|
||||
UNION ALL
|
||||
SELECT 'YEAR'::varchar, year,
|
||||
fin_ahr, fin_ahr_limit, fin_ahr_current, fin_kv,
|
||||
bq1_ahr, bq1_ahr_limit, bq1_ahr_current, bq1_kv,
|
||||
cq2_ahr, cq2_ahr_limit, cq2_ahr_current, cq2_kv,
|
||||
cq3_ahr, cq3_ahr_limit, cq3_ahr_current, cq3_kv,
|
||||
cq4_ahr, cq4_ahr_limit, cq4_ahr_current, cq4_kv,
|
||||
aq1_ahr, aq1_ahr_limit, aq1_ahr_current,
|
||||
aq2_ahr, aq2_ahr_limit, aq2_ahr_current,
|
||||
aq3_ahr, aq3_ahr_limit, aq3_ahr_current,
|
||||
aq4_ahr, aq4_ahr_limit, aq4_ahr_current,
|
||||
aq1_kv, aq1_kv_limit, aq1_kv_current,
|
||||
aq2_kv, aq2_kv_limit, aq2_kv_current,
|
||||
aq3_kv, aq3_kv_limit, aq3_kv_current,
|
||||
aq4_kv, aq4_kv_limit, aq4_kv_current
|
||||
FROM py
|
||||
)
|
||||
SELECT
|
||||
r.row_type,
|
||||
CASE r.row_type WHEN 'PROJECT' THEN 0 ELSE 1 END AS depth,
|
||||
ROW_NUMBER() OVER (
|
||||
ORDER BY CASE r.row_type WHEN 'PROJECT' THEN 0 WHEN 'YEAR' THEN 1 ELSE 2 END,
|
||||
COALESCE(r.year, 0)
|
||||
) AS sort_order,
|
||||
jsonb_build_object(
|
||||
'header', jsonb_build_object('project_id', p_project_id, 'name', p.name, 'year', r.year),
|
||||
'financing', jsonb_build_object('ahr', r.fin_ahr, 'ahr_limit', r.fin_ahr_limit, 'ahr_current', r.fin_ahr_current, 'kv', r.fin_kv),
|
||||
'base_q1', jsonb_build_object('ahr', r.bq1_ahr, 'ahr_limit', r.bq1_ahr_limit, 'ahr_current', r.bq1_ahr_current, 'kv', r.bq1_kv),
|
||||
'corrected_q2', jsonb_build_object('ahr', r.cq2_ahr, 'ahr_limit', r.cq2_ahr_limit, 'ahr_current', r.cq2_ahr_current, 'kv', r.cq2_kv),
|
||||
'corrected_q3', jsonb_build_object('ahr', r.cq3_ahr, 'ahr_limit', r.cq3_ahr_limit, 'ahr_current', r.cq3_ahr_current, 'kv', r.cq3_kv),
|
||||
'corrected_q4', jsonb_build_object('ahr', r.cq4_ahr, 'ahr_limit', r.cq4_ahr_limit, 'ahr_current', r.cq4_ahr_current, 'kv', r.cq4_kv),
|
||||
'actual_ahr', jsonb_build_object(
|
||||
'q1', jsonb_build_object('ahr', r.aq1_ahr, 'ahr_limit', r.aq1_ahr_limit, 'ahr_current', r.aq1_ahr_current),
|
||||
'q2', jsonb_build_object('ahr', r.aq2_ahr, 'ahr_limit', r.aq2_ahr_limit, 'ahr_current', r.aq2_ahr_current),
|
||||
'q3', jsonb_build_object('ahr', r.aq3_ahr, 'ahr_limit', r.aq3_ahr_limit, 'ahr_current', r.aq3_ahr_current),
|
||||
'q4', jsonb_build_object('ahr', r.aq4_ahr, 'ahr_limit', r.aq4_ahr_limit, 'ahr_current', r.aq4_ahr_current)
|
||||
),
|
||||
'actual_kv', jsonb_build_object(
|
||||
'q1', jsonb_build_object('kv', r.aq1_kv, 'kv_limit', r.aq1_kv_limit, 'kv_current', r.aq1_kv_current),
|
||||
'q2', jsonb_build_object('kv', r.aq2_kv, 'kv_limit', r.aq2_kv_limit, 'kv_current', r.aq2_kv_current),
|
||||
'q3', jsonb_build_object('kv', r.aq3_kv, 'kv_limit', r.aq3_kv_limit, 'kv_current', r.aq3_kv_current),
|
||||
'q4', jsonb_build_object('kv', r.aq4_kv, 'kv_limit', r.aq4_kv_limit, 'kv_current', r.aq4_kv_current)
|
||||
)
|
||||
) AS data
|
||||
FROM rows r
|
||||
CROSS JOIN project p;
|
||||
$function$
|
||||
;
|
||||
@ -175,6 +175,32 @@ async def get_rf_rollup(
|
||||
return BaseListResponse(count=len(rows), result=_rows_to_payload(rows))
|
||||
|
||||
|
||||
@router.get("/projects/{project_id}/summary")
|
||||
async def get_project_summary(
|
||||
project_id: int,
|
||||
response: Response,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: AppUser = Depends(get_current_active_user_with_set_db),
|
||||
) -> BaseListResponse[SheetResponse]:
|
||||
project_service = ProjectService(db)
|
||||
t0 = time.perf_counter()
|
||||
rows = await project_service.get_project_summary_rows(
|
||||
project_id=project_id,
|
||||
user=current_user,
|
||||
)
|
||||
db_ms = (time.perf_counter() - t0) * 1000
|
||||
response.headers["X-DB-Time-Ms"] = f"{db_ms:.2f}"
|
||||
extra = {
|
||||
"type": "db_time",
|
||||
"time_ms": f"{db_ms:.2f}",
|
||||
"handler": "get_project_summary",
|
||||
"project_id": project_id,
|
||||
"user": current_user.id,
|
||||
}
|
||||
logger.info(f"db_time: {extra}", extra=extra)
|
||||
return BaseListResponse(count=len(rows), result=_rows_to_payload(rows))
|
||||
|
||||
|
||||
@router.patch("/projects/{project_id}/report/{year}/{report_type}/cell")
|
||||
async def upd_form3_cell(
|
||||
project_id: int,
|
||||
|
||||
@ -334,6 +334,17 @@ class ProjectRepository:
|
||||
)
|
||||
).all()
|
||||
|
||||
async def get_project_summary_rows(self, project_id: int) -> list[tuple]:
|
||||
query = text(
|
||||
"""
|
||||
SELECT row_type, depth, sort_order, data
|
||||
FROM v3.v_project_summary_jsonb(CAST(:project_id AS INT))
|
||||
"""
|
||||
)
|
||||
return (
|
||||
await self.db.execute(query, {"project_id": project_id})
|
||||
).all()
|
||||
|
||||
async def upd_form3_cell(
|
||||
self,
|
||||
report_id: int,
|
||||
|
||||
@ -113,6 +113,16 @@ class ProjectService:
|
||||
sections=sections,
|
||||
)
|
||||
|
||||
async def get_project_summary_rows(
|
||||
self,
|
||||
project_id: int,
|
||||
user: AppUser,
|
||||
) -> list[tuple]:
|
||||
project = await self.get_instance(project_id, user)
|
||||
if not project:
|
||||
raise ValidationException("Проект не найден")
|
||||
return await self.project_repo.get_project_summary_rows(project_id=project_id)
|
||||
|
||||
async def upd_form3_cell(
|
||||
self,
|
||||
project_id: int,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user