From b3207b5ce03d506cef25f5f8442146e0c575a44c 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:05:38 +0900 Subject: [PATCH] fix(management): compute applied/common admin expense by monthly active project distribution --- server/ptc_api_server.py | 42 ++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/server/ptc_api_server.py b/server/ptc_api_server.py index 5f846c7..f4c697a 100644 --- a/server/ptc_api_server.py +++ b/server/ptc_api_server.py @@ -3487,25 +3487,47 @@ class Handler(BaseHTTPRequestHandler): } ) - management_split_rows = conn.execute( + construction_project_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, 4) as year, - coalesce(project_code, '') as project_code, + substr(coalesce(transaction_date, ''), 1, 7) as ym, 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, 4), coalesce(project_code, ''), account_code_final - having year <> '' + group by substr(coalesce(transaction_date, ''), 1, 7), account_code_final + having ym <> '' """, values, ).fetchall() - for row in management_split_rows: - year = (row["year"] or "").strip() or "미상" + for row in monthly_management_pool_rows: + ym = (row["ym"] or "").strip() + year = ym[:4] if len(ym) >= 4 else "미상" account_code = (row["account_code"] or "").strip() - project_code = (row["project_code"] or "").strip() expense_supply = float(row["expense_supply"] or 0) if not account_code or expense_supply == 0: continue @@ -3527,8 +3549,8 @@ class Handler(BaseHTTPRequestHandler): "excluded_expense_total": 0.0, "excluded_accounts": [], } - is_project_applied = bool(project_code) and "-관리-" not in project_code - if is_project_applied: + active_count = int(active_counts_by_month.get(ym) or 0) + if active_count > 0: by_year[year]["project_applied_admin_expense"] += expense_supply else: by_year[year]["common_admin_expense"] += expense_supply