From 61e580b74abf9f00536baec2f1bf0943d3103f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=9C=EC=9D=B8?= Date: Mon, 4 May 2026 10:10:54 +0900 Subject: [PATCH] fix(management): classify applied/common admin expense by construction linkage --- server/ptc_api_server.py | 69 +++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/server/ptc_api_server.py b/server/ptc_api_server.py index f4c697a..b773cbc 100644 --- a/server/ptc_api_server.py +++ b/server/ptc_api_server.py @@ -3487,46 +3487,48 @@ class Handler(BaseHTTPRequestHandler): } ) - construction_project_rows = conn.execute( + management_split_rows = conn.execute( """ select - pm.project_code, - pm.start_date, - pm.end_date, - min(case when coalesce(t.transaction_date, '') <> '' then t.transaction_date end) as min_tx_date, - max(case when coalesce(t.transaction_date, '') <> '' then t.transaction_date end) as max_tx_date - from project_master pm - left join ptc_transactions t on t.project_code = pm.project_code - where coalesce(pm.project_type, '') = '시공' - group by pm.project_code, pm.start_date, pm.end_date - """ - ).fetchall() - active_counts_by_month: dict[str, int] = defaultdict(int) - for row in construction_project_rows: - start_ym = _to_year_month(row["start_date"]) or _to_year_month(row["min_tx_date"]) - end_ym = _to_year_month(row["end_date"]) or _to_year_month(row["max_tx_date"]) or start_ym - if not start_ym or not end_ym: - continue - for ym in _iter_year_months(start_ym, end_ym): - active_counts_by_month[ym] += 1 - - monthly_management_pool_rows = conn.execute( - f""" - select - substr(coalesce(transaction_date, ''), 1, 7) as ym, + substr(coalesce(transaction_date, ''), 1, 4) as year, + coalesce(project_code, '') as project_code, account_code_final as account_code, coalesce(sum(case when in_out = '출금' then supply_amount else 0 end), 0) as expense_supply from ptc_transactions {where} - group by substr(coalesce(transaction_date, ''), 1, 7), account_code_final - having ym <> '' + group by substr(coalesce(transaction_date, ''), 1, 4), coalesce(project_code, ''), account_code_final + having year <> '' """, values, ).fetchall() + relation_rows = conn.execute( + """ + select + pr.project_code as project_code, + pr.related_project_code as related_project_code, + coalesce(pm.project_type, '') as project_type, + coalesce(rpm.project_type, '') as related_project_type + from project_relations pr + left join project_master pm on pm.project_code = pr.project_code + left join project_master rpm on rpm.project_code = pr.related_project_code + """ + ).fetchall() + connected_codes: set[str] = set() + for rel in relation_rows: + left_code = (rel["project_code"] or "").strip() + right_code = (rel["related_project_code"] or "").strip() + left_type = (rel["project_type"] or "").strip() + right_type = (rel["related_project_type"] or "").strip() + if left_type == "시공" and right_code: + connected_codes.add(right_code) + connected_codes.add(left_code) + if right_type == "시공" and left_code: + connected_codes.add(left_code) + connected_codes.add(right_code) - for row in monthly_management_pool_rows: - ym = (row["ym"] or "").strip() - year = ym[:4] if len(ym) >= 4 else "미상" + for row in management_split_rows: + year = (row["year"] or "").strip() or "미상" + project_code = (row["project_code"] or "").strip() account_code = (row["account_code"] or "").strip() expense_supply = float(row["expense_supply"] or 0) if not account_code or expense_supply == 0: @@ -3549,8 +3551,11 @@ class Handler(BaseHTTPRequestHandler): "excluded_expense_total": 0.0, "excluded_accounts": [], } - active_count = int(active_counts_by_month.get(ym) or 0) - if active_count > 0: + is_project_applied = ( + (bool(project_code) and "-시공-" in project_code) + or (project_code in connected_codes) + ) + if is_project_applied: by_year[year]["project_applied_admin_expense"] += expense_supply else: by_year[year]["common_admin_expense"] += expense_supply