merge(707): sub_laptop_8(sub5 707-1 내역 줄 불러오기) 합침 — 불러오기 길 · 화면 한 파일 · file_key 하나 (PLAN 707-1 · 707-2 · 707-3)

- Router_Import = import/bill · bill/apply(sub5) + import/rates · import/prices · 올린 파일 = 프로젝트 import/{표지} 한 자리
- UI_Import = [엑셀 내역 불러오기] + [엑셀에서 요율 · 단가표 불러오기] · 마지막 표지 함께 씀
- test_145_3 · test_166_2 TS 거울 = 글 stdin(Calc_Base · Calc_Bill 길어져 node -e 32 K 넘김)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 16:30:43 +09:00
co-authored by Claude Opus 5.5
16 changed files with 1208 additions and 96 deletions
+19 -1
View File
@@ -155,9 +155,22 @@ def _clean_ref(ref: Any) -> dict[str, Any] | None:
return None
def _fixed_cells(row: dict[str, Any]) -> dict[str, Any]:
"""707-1 고정 단가 칸 `price` {노 · 재 · 경 수(빈 = 0)} · 불러온 수량 `src_qty` — 있는 것만."""
out: dict[str, Any] = {}
if isinstance(row.get("price"), dict):
out["price"] = {
p: _num(row["price"].get(p)) or 0.0 for p in ("labor", "material", "expense")
}
if _num(row.get("src_qty")) is not None:
out["src_qty"] = _num(row["src_qty"])
return out
def _clean_v2(raw: dict[str, Any]) -> dict[str, Any]:
"""184 덮개 v2 — 표 차례(겹친 키 · `fee` 버림) · 새 줄(`hand:`) = 모든 칸 ·
자동 줄 = 고친 칸만(값 · null = 일부러 빈칸 · 못 쓰는 값 = 칸 버림) · `gone` = 자동 줄 키."""
자동 줄 = 고친 칸만(값 · null = 일부러 빈칸 · 못 쓰는 값 = 칸 버림) · `gone` = 자동 줄 키 ·
고정 단가 칸 · 불러온 수량(707-1) = 항목 줄만 · 새 줄 비고 `note` 글."""
rows, seen = [], set()
for row in raw.get("rows") if isinstance(raw.get("rows"), list) else []:
key = row.get("key") if isinstance(row, dict) else None
@@ -177,6 +190,10 @@ def _clean_v2(raw: dict[str, Any]) -> dict[str, Any]:
out.update({k: _text(row.get(k)) for k in ("name", "spec", "unit")})
out["qty"] = None if group else _num(row.get("qty"))
out["ref"] = None if group else _clean_ref(row.get("ref"))
if not group:
out.update(_fixed_cells(row))
if _text(row.get("note")):
out["note"] = _text(row["note"])
else:
for k in ("name", "spec", "unit"):
if k in row:
@@ -185,6 +202,7 @@ def _clean_v2(raw: dict[str, Any]) -> dict[str, Any]:
out["qty"] = _num(row["qty"])
if "ref" in row and (row["ref"] is None or _clean_ref(row["ref"]) is not None):
out["ref"] = _clean_ref(row["ref"])
out.update(_fixed_cells(row))
rows.append(out)
given = raw.get("gone") if isinstance(raw.get("gone"), list) else []
gone = list(