auto: 2026-09-20 20:29 (ESD_LAPTOP)

This commit is contained in:
2026-09-20 20:29:34 +09:00
parent 572fb8e5ee
commit 9a47b6cd31
6 changed files with 130 additions and 40 deletions
+34 -1
View File
@@ -126,6 +126,9 @@ def refs_of(rows_: list[dict]) -> dict[str, str]:
return out
_STATES = ("공표", "산정", "미공표", "미확보", "추정") # 인력 「상태」 거름 차례
def subs(file: str = "", group: str = "") -> dict:
"""하위 거름 목록 — 한 테이블 파일은 머리 묶음(인력 「구분」 · 기계 「세부분류」) ·
장 그룹(소요량 · 계수 · 로직)은 장 파일에서 모음(구분 = 원문 + 부문 · 상세구분 = 장 · 차례대로)."""
@@ -144,12 +147,26 @@ def subs(file: str = "", group: str = "") -> dict:
return {"file": "", "version": "", "slot": "구분", "subs": list(found.values())}
data, version = read(file)
slot = next((s for s in ("구분", "세부분류") if isinstance(data.get(s), dict)), "")
lines = data.get(items_key(data)) or []
has_state = any("상태" in r for r in lines)
def details_of(name: str, head: dict) -> list:
"""머리에 상세구분이 없으면 줄에서 모음(재료_유가전력 — 지역 · 계약종별)."""
if head.get("상세구분"):
return head["상세구분"]
return list(
dict.fromkeys(
r["상세구분"] for r in lines if r.get("구분") == name and r.get("상세구분")
)
)
return {
"file": file,
"version": version,
"slot": slot,
"states": list(_STATES) if has_state else [],
"subs": [
{"name": name, "book": head.get("원문"), "details": head.get("상세구분") or []}
{"name": name, "book": head.get("원문"), "details": details_of(name, head)}
for name, head in (data.get(slot) or {}).items()
],
}
@@ -163,6 +180,7 @@ def rows(
unlinked: bool = False,
sub: str = "",
detail: str = "",
state: str = "",
) -> dict:
data, version = read(file)
hits = [r for r in data.get(items_key(data)) or [] if _hit(r, q)]
@@ -170,6 +188,8 @@ def rows(
hits = [r for r in hits if sub in (r.get("구분"), r.get("세부분류"))]
if detail: # 인력 상세구분
hits = [r for r in hits if r.get("상세구분") == detail]
if state: # 인력 상태
hits = [r for r in hits if r.get("상태") == state]
if unlinked: # 품셈재료 — 아직 못 이은 줄
hits = [r for r in hits if not r.get("연결")]
page, size = max(page, 1), min(max(size, 1), 500)
@@ -452,6 +472,17 @@ def _chapter_cols(file: str, data: dict) -> dict:
}
def _follow(row: dict, items: list[dict], file: str) -> dict:
"""인력 줄의 준용 = 그 직종의 값을 다시 읽어 값 칸에 채움(화면이 보낸 값을 믿지 않음)."""
ref = row.get("준용")
if file != "인력.json" or not isinstance(ref, str) or not _REF_KEY.match(ref):
return row
src = next((r for r in items if r.get("키") == ref), None)
if src is None or src.get("값") is None:
return row
return {**row, "값": src["값"]}
def _apply(data: dict, changes: list[dict], file: str, book: dict) -> None:
"""고침 · 더함(키는 대장의 다음 번호 · 원문번호 없으면 빈 글) · 지움 — 키는 바꾸지 않음."""
items = data.setdefault(items_key(data), [])
@@ -466,6 +497,8 @@ def _apply(data: dict, changes: list[dict], file: str, book: dict) -> None:
raise StoreError(404, f"{file} · 없는 키 「{key}」")
if op != "delete" and not isinstance(row, dict):
raise StoreError(400, f"{file} · row 없음")
if op != "delete":
row = _follow(row, items, file)
if op == "add":
number = str(row.get("원문번호") or "")
cols = _chapter_cols(file, data)