fix(842-3): 범위 잡재료율 기계 둘 · 수식 빌더가 저장본 문서를 조용히 빼던 흠
- 원인: 옮김에서 펌프 준설선 EQ000552 · 553 잡재료율 「13∼18」 이 사라짐 → 옛 엔진 멈춤 · 새 계산기 셈(빈 잡품) → GC000268 옵션 「다름」 → 저장 밖 → 그 식을 부르는 문서 320 개가 저장본에서 지워짐(1,520 → 1,200) - 범위 글 = 잡품 율 글 그대로(from_old · TS fromOld · check 허용) · 두 대 다시 옮김 → 까닭 「범위」 옛 칸과 같음 - 빌더 = 저장본 문서가 저장 밖으로 빠지면 멈춤 · 안 씀 · 키와 까닭 알림(lost) · 시험 802_2 에 lost 0 - 시험 822_2 범위 까닭 기대 되돌림 · 842_3 거울에 범위 값 더함 - 확인: 빌더 --check 저장 1,520 · 기본 다름 0 · 옵션 다름 3(채택) · 저장본 · 목록 같음 · 655 대 시간당(옛 자료 대 새 자료) 다름 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
규칙 = `master_machine_crew.from_old_row`(값 · 단위 · 출처 — 사본 대조와 같은 규칙):
|
||||
인력 = 조종원 > 0 이면 [{키 'LB:<조종원직종>'(직종 없음 = 빈 키 = 식 입력 직종 고르기), 인 = 조종원}] · 0 = []
|
||||
잡품 = 잡재료율 > 0 이면 밑 재료 줄(주연료 · 전력 가운데 값 > 0)마다 {줄, 율 = 잡재료율} · 0 = []
|
||||
수 아닌 잡재료율(범위 글 「13∼18」) = 잡품 없음(원문 글은 `값원문` 그대로)
|
||||
잡재료율 범위 글(「13∼18」) = 잡품 율 글 그대로(식이 못 셈 · 까닭 「범위」 — 옛 칸과 같음)
|
||||
칸 차례 = 옛 조종원 자리에 인력 · 옛 잡재료율 자리에 잡품 · 선원류 칸(선원 · 준설선선장 · 준설선기관사 · 고급선원) ·
|
||||
맨 위 칸(비활성 표지 등) = 그대로 · 다시 돌려도 같음(새 꼴 줄 = 그대로).
|
||||
실행 = `./venv/Scripts/python.exe resources/master_data/scripts/build_기계_인력줄_842_3.py [--dry]`
|
||||
@@ -62,7 +62,7 @@ def main(dry: bool = False) -> Counter:
|
||||
seen[f"인력 {sum(r['인'] for r in vb[mcrew.CREW])}인"] += 1
|
||||
seen["직종 빈 줄(직종 고르기)"] += any(not r["키"] for r in vb[mcrew.CREW])
|
||||
seen["잡품 줄 있음"] += bool(vb.get(mcrew.MISC))
|
||||
seen["잡품 범위 글(잡품 없음)"] += isinstance(va.get("잡재료율"), str)
|
||||
seen["잡품 범위 글(율 글 그대로)"] += isinstance(va.get("잡재료율"), str)
|
||||
seen["선원류 칸 그대로"] += any(k in vb for k in ("선원", "준설선선장", "준설선기관사", "고급선원"))
|
||||
seen["비활성 표지 그대로"] += bool(b.get("비활성"))
|
||||
seen["옛 칸 남음"] += any(k in vb for k in mcrew.OLD)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
`resources/master_data/수식문서/수식_<옛 로직 파일 꼬리>.json`(로직 파일마다
|
||||
· 옛 로직 JSON 은 안 씀).
|
||||
- 목록 = `docs/raw/요구_1104/_목록_802-2_변환대조.xlsx`(로직 · 옵션 · 옛 · 새 · 차이 · 까닭 + 요약).
|
||||
- 이미 저장된 문서가 이번에 저장 밖(다름 · 부르는 문서 빠짐)이면 멈춤 — 안 씀 · 그 문서와 까닭을 알림(`lost`).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -206,6 +207,24 @@ def _keep(docs: dict, runs: list[dict]) -> set[str]:
|
||||
keep -= drop
|
||||
|
||||
|
||||
def saved_keys() -> set[str]:
|
||||
"""지금 저장본 수식 문서 키."""
|
||||
return {
|
||||
str(d.get("키"))
|
||||
for p in ml.FOLDER.glob("수식_*.json")
|
||||
for d in ml.load_file(p).get("줄") or []
|
||||
}
|
||||
|
||||
|
||||
def lost(result: dict) -> list[str]:
|
||||
"""저장본에 있는데 이번 빌드가 저장 밖으로 뺀 문서 — 「키 까닭」(빌더가 조용히 지우지 않게)."""
|
||||
why = {}
|
||||
for one in result["대조"]:
|
||||
if one["로직"] not in result["저장"]:
|
||||
why.setdefault(one["로직"], one.get("까닭") or one.get("빠짐") or "")
|
||||
return [f"{k} {why.get(k) or '저장 밖'}" for k in sorted(saved_keys() - result["저장"])]
|
||||
|
||||
|
||||
def files_of(result: dict) -> dict[str, str]:
|
||||
"""저장 파일 이름 → 글."""
|
||||
out = {}
|
||||
@@ -310,6 +329,11 @@ def main() -> int:
|
||||
print(line)
|
||||
print("같음" if not bad else f"다름 {len(bad)}")
|
||||
return 1 if bad else 0
|
||||
if gone := lost(result):
|
||||
for line in gone:
|
||||
print(f"저장본에서 빠질 문서 {line}")
|
||||
print(f"멈춤 — 저장본 문서 {len(gone)} 개가 빠짐(안 씀) · 까닭을 고친 뒤 다시")
|
||||
return 1
|
||||
ml.FOLDER.mkdir(parents=True, exist_ok=True)
|
||||
want = files_of(result)
|
||||
for path in ml.FOLDER.glob("수식_*.json"):
|
||||
|
||||
@@ -53,20 +53,28 @@ def view(vals):
|
||||
def from_old(vals: dict, base: list[str] | None = None) -> dict:
|
||||
"""옛 꼴 값 → 새 꼴(옛 칸 셋 → 인력 · 잡품) — 옛 칸 없음 = 그대로.
|
||||
인력 = 조종원 > 0 이면 한 줄(직종 없음 = 빈 키) · 0 = 빈 목록 · 없음 = 칸 없음.
|
||||
잡품 = 잡재료율 > 0 이면 밑 재료 줄(`base` · 없으면 주연료 · 전력 가운데 값 있는 줄)마다 그 율 · 0 = 빈 목록."""
|
||||
잡품 = 잡재료율 > 0 이면 밑 재료 줄(`base` · 없으면 주연료 · 전력 가운데 값 있는 줄)마다 그 율 · 0 = 빈 목록 ·
|
||||
원문 범위 글(「13∼18」) = 율 글 그대로(식이 못 셈 · 옛 칸과 같은 까닭)."""
|
||||
if not isinstance(vals, dict) or is_new(vals):
|
||||
return vals
|
||||
out = {k: v for k, v in vals.items() if k not in OLD}
|
||||
n, job, rate = vals.get("조종원"), vals.get("조종원직종"), vals.get("잡재료율")
|
||||
if _isnum(n):
|
||||
out[CREW] = [{"키": f"LB:{job}" if job else "", "인": n}] if n > 0 else []
|
||||
if base is None:
|
||||
base = [b for b in BASE if vals.get(b) not in (None, "", 0)] # 「73.7+」 글도 줄
|
||||
if _isnum(rate):
|
||||
if base is None:
|
||||
base = [b for b in BASE if vals.get(b) not in (None, "", 0)] # 「73.7+」 글도 줄
|
||||
out[MISC] = [{"줄": b, "율": rate} for b in base] if rate > 0 and base else []
|
||||
elif _range(rate) and base: # 원문 범위 「13∼18」 = 율 글 그대로(식이 못 셈 · 까닭 「범위」)
|
||||
out[MISC] = [{"줄": b, "율": rate} for b in base]
|
||||
return out
|
||||
|
||||
|
||||
def _range(v) -> bool:
|
||||
"""원문 범위 글(「13∼18」) — M01 자료에만 · 셈은 못 함."""
|
||||
return isinstance(v, str) and "∼" in v
|
||||
|
||||
|
||||
def _isnum(v) -> bool:
|
||||
return isinstance(v, Number) and not isinstance(v, bool)
|
||||
|
||||
@@ -123,7 +131,9 @@ def check(vals) -> list[str]:
|
||||
out.append(f"{col} — 목록(30 줄까지)")
|
||||
continue
|
||||
for n, r in enumerate(rows, 1):
|
||||
bad = not isinstance(r, dict) or not _isnum(r.get(need)) or r[need] < 0
|
||||
bad = not isinstance(r, dict) or not (
|
||||
_isnum(r.get(need)) and r[need] >= 0 or col == MISC and _range(r.get(need))
|
||||
)
|
||||
if not bad and r.get("수량") is not None:
|
||||
bad = not _isnum(r["수량"]) or r["수량"] < 0
|
||||
if not bad and col == CREW:
|
||||
|
||||
Reference in New Issue
Block a user