Files
Aislo/D04_PlanConfirm/D04_PlanConfirm_Repository.py
T
eomsangdonandClaude Opus 5.5 54e08d0d65 feat(D 예정노선): 설계 내용 = 프로젝트 폴더 한 파일 D03_PlanAnalysis/plan_network.json — 저장 모듈 · 서버 길 옮김 · 업체 연도 = 파일 조각 (PLAN 590-1 · 요구 452 · 453)
- 저장 모듈 D03_PlanAnalysis_Store — 읽기 · 원자 쓰기 · 판 · 옛 DB 칸 읽을 때 옮김(지점 셋 꼴 · 연도 행 접기 · 옛 연도 노선) · plan_state(조각 · 연도 지문 · 확정 = 지문 같을 때만)
- D03 [저장] · [초기화] · D02 지점 = 파일만 + 연도 상태 줄(지문 · 확정) · 프로젝트 잠금 · 파일 쓰기 실패 = DB 되돌림 · 빈 연도 줄 지움
- D04 요약 · 업체 지정 · 확정 메일 · 내보내기 · 대시보드 [연결] · 받은 예정노선 · 산림청 홈 · 개요 연결 = 파일에서 · 업체 줄 연도 칸 안 읽음(⑤)
- 산림청 홈 「분석 전」 = 노선 안 그은 예정노선 프로젝트 수 · plan-source 지운 원본 거름
- 옛 연도 단위 지정 · 옛 연도 행 노선 길 걷음(DB 실측 0) · 연결 때 설계속도 씨앗 걷음(591-1 이음)
- SQL 023 = 업체 줄 year NULL 허용(옛 칸은 590-3 에서 지움)
- 시험: 새 지킴 590_1(옮김 · 원자 쓰기 · 연도 읽기 · 잠금) · 낡은 시험 고침 — 529_3 · 530_2 · 531_3 · 531_d04 · 547_2 · 563_2(DB 조각 · 연도 행 흉내 → 파일 흉내 · 옛 연도 지정 시험 · 설계속도 씨앗 시험 지움 = 그 길 걷음)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 09:52:51 +09:00

129 lines
5.0 KiB
Python

"""D04 확정 · 업체 지정 DB (Raw SQL · 표는 db_management/020_project_groups.sql · 023).
노선 · 조각 · 연도 = 설계 내용 파일(`D03_PlanAnalysis_Store`) · 여기는 업체 줄 · 연도 상태 줄만.
업체 줄 `year` 칸은 읽지 않음(연도 = 파일 조각 연도 · 590-3 에서 지움)."""
from __future__ import annotations
from typing import Any
import aiomysql
from config.config_db import get_db_pool
async def get_plan_project(project_id: str) -> dict[str, Any] | None:
async with (
get_db_pool().acquire() as connection,
connection.cursor(aiomysql.DictCursor) as cursor,
):
await cursor.execute(
"SELECT id, name, region, project_kind, route_start_m FROM projects"
" WHERE id = %s AND deleted_at IS NULL",
(project_id,),
)
return await cursor.fetchone()
def line_names(lines: list[dict[str, Any]]) -> list[str]:
"""선 이름 — 갈래 없는 선 = 본선(둘 이상이면 본선 1 · 2 …) · 갈래 = 갈래 1 · 2 …(선 차례).
⚠ 짝 = TS `D03_PlanAnalysis/logic/D03_PlanAnalysis_Plan.ts` `lineNames` — 거울 시험 530-3."""
roots = sum(1 for line in lines if not line.get("branch"))
out, root, branch = [], 0, 0
for line in lines:
if line.get("branch"):
branch += 1
out.append(f"갈래 {branch}")
else:
root += 1
out.append(f"본선 {root}" if roots > 1 else "본선")
return out
async def list_assignees(project_id: str) -> list[dict[str, Any]]:
async with (
get_db_pool().acquire() as connection,
connection.cursor(aiomysql.DictCursor) as cursor,
):
await cursor.execute(
"SELECT id, piece_id, company_id, company_name, email, notified_at, linked_project_id"
" FROM plan_route_assignees WHERE project_id = %s ORDER BY id",
(project_id,),
)
return await cursor.fetchall()
async def get_company_contact(company_id: int) -> dict[str, Any] | None:
"""등록 회사 이름 + 대표 메일(회사 마스터 사용자)."""
async with (
get_db_pool().acquire() as connection,
connection.cursor(aiomysql.DictCursor) as cursor,
):
await cursor.execute(
"SELECT c.id, c.name, u.email FROM companies c"
" LEFT JOIN users u ON u.id = c.master_user_id AND u.deleted_at IS NULL"
" WHERE c.id = %s AND c.deleted_at IS NULL",
(company_id,),
)
return await cursor.fetchone()
async def apply_assignee_changes(
project_id: str, delete_ids: list[int], updates: list[dict], inserts: list[dict]
) -> None:
async with get_db_pool().acquire() as connection, connection.cursor() as cursor:
await connection.begin()
try:
for assignee_id in delete_ids:
await cursor.execute(
"DELETE FROM plan_route_assignees WHERE id = %s AND project_id = %s",
(assignee_id, project_id),
)
for row in updates:
await cursor.execute(
"UPDATE plan_route_assignees SET company_name = %s, email = %s"
" WHERE id = %s AND project_id = %s",
(row["company_name"], row["email"], row["id"], project_id),
)
for row in inserts:
await cursor.execute(
"INSERT INTO plan_route_assignees"
" (project_id, piece_id, company_id, company_name, email)"
" VALUES (%s,%s,%s,%s,%s)",
(
project_id,
row["piece_id"],
row["company_id"],
row["company_name"],
row["email"],
),
)
await connection.commit()
except Exception:
await connection.rollback()
raise
async def mark_confirmed(project_id: str, fingerprints: dict[int, str]) -> None:
"""연도 확정 — {연도: 파일 지문} · 상태 줄이 없거나 지문이 낡았으면 새로 맞춤."""
if not fingerprints:
return
async with get_db_pool().acquire() as connection, connection.cursor() as cursor:
for year, fingerprint in fingerprints.items():
await cursor.execute(
"INSERT INTO plan_route_years (project_id, year, fingerprint, confirmed_at)"
" VALUES (%s, %s, %s, NOW()) ON DUPLICATE KEY UPDATE"
" fingerprint = VALUES(fingerprint), confirmed_at = NOW()",
(project_id, year, fingerprint),
)
await connection.commit()
async def mark_notified(assignee_id: int) -> None:
async with get_db_pool().acquire() as connection, connection.cursor() as cursor:
await cursor.execute(
"UPDATE plan_route_assignees SET notified_at = NOW() WHERE id = %s", (assignee_id,)
)
await connection.commit()