feat(B09 설계내역서): 경쟁사 내역 엑셀 줄 불러오기 서버 — 읽기 · 짜기 · 고정 단가 칸 (PLAN 707-1)
- 읽기(Bill_Excel) — STmate 「설계내역서」 숨은 코드 · 부모 코드 열 · EST 「내역서」 공종 번호 깊이 · 비고 대가 · 산근 · 단산 · 일위 · 제외 묶음(관급 · 제외금액) · 조달수수료 = 율 · DRM = 「읽을 수 없음」 · 열 머리 = M02 실무자료 칸 읽기 재사용 - 짜기(Bill_Import) — 공종 = 새 묶음 · 항목 = 새 줄 + 고정 단가 칸 · 수량 갈래 take · price · 이름 같은 자동 줄 붙임 · 남은 자동 줄 지움 · 같은 파일 다시 = 갈아 끼움 · 어긋난 줄 목록 - 길(Router_Import) — import/bill(file · file_key) 미리 보기 · import/bill/apply(같은 파일 이름 실무자료 사전조합 → 서고 사본 연결 · 층 쓰기 0) · 저장 안 함 - 셈 짝(Calc_Bill py · ts) — 줄 price = 연결이 단가를 못 낼 때 금액 · fixed · src_qty · Store 다듬기 - 확인 = 기번3 710,359,136 · 영월 767,148,700 · 봉화 781,283,415 · 거창 384,916,227 직접비 합 = 엑셀 · 빈 줄 0 · 어긋남 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -27,7 +27,10 @@
|
||||
(제목 `sec:*` = name 만 · `mat:` = ref 없음 ·
|
||||
`fee` = 덮개 없음 · 차례에 안 넣음 — `sec:G` 끝 고정)
|
||||
새 줄(`hand:*`) = 모든 칸 + "kind": "group"(묶음 · 수량 · 연결 없음) | 없음 = 항목 ·
|
||||
"cost": "direct"(맨 위 새 묶음 · 없음도 direct)}],
|
||||
"cost": "direct"(맨 위 새 묶음 · 없음도 direct) ·
|
||||
고정 단가 칸(707-1 · 새 줄 · 자동 줄 둘 다) = "price" {labor, material, expense}(제 단가 ·
|
||||
연결이 단가를 못 내면 이것으로 금액 · 줄 `fixed`) · "src_qty"(불러온 수량 = 비교 칸) ·
|
||||
"note"(새 줄 비고 · 연결 비고가 이김)}],
|
||||
"gone": [지운 자동 줄 키 — `sec:G` · `fee` · `mat:` 는 안 받음(자재 줄 주인 = 대비표 표시)]}
|
||||
덮개 없음 = 기본 표 그대로 · [초기화] = `bill` 지움 ·
|
||||
`rows` 에 없고 `gone` 에도 없는 자동 줄(B08 새 열 · 대비표 새 표시) =
|
||||
@@ -113,6 +116,8 @@ def _item_row(item: dict[str, Any], prices: dict[str, Any] | None) -> dict[str,
|
||||
"ref": item.get("ref"),
|
||||
**{k: v for k, v in item.items() if k.startswith("auto_")},
|
||||
**({"hand": True} if item.get("hand") else {"auto": True}),
|
||||
**({"fixed": True} if item.get("fixed") else {}),
|
||||
**({"src_qty": item["src_qty"]} if num(item.get("src_qty")) is not None else {}),
|
||||
**_amounts(qty, prices),
|
||||
}
|
||||
row["_gaps"] = []
|
||||
@@ -170,16 +175,27 @@ def ref_price(
|
||||
return hopyo.get(key) if key else None
|
||||
|
||||
|
||||
def fixed_price(price: Any) -> dict[str, Any] | None:
|
||||
"""고정 단가 칸(707-1) → 1 단위 단가 — 빈 비목 0 · 칸 없음 = None."""
|
||||
if not isinstance(price, dict):
|
||||
return None
|
||||
out = {p: num(price.get(p)) or 0.0 for p in PARTS}
|
||||
return {"no": "", **out, "sum": out["labor"] + out["material"] + out["expense"]}
|
||||
|
||||
|
||||
def hand_items(user: dict[str, Any], books: dict[str, Any], hopyo: dict) -> list[tuple]:
|
||||
"""새 줄(`hand:`) → (항목, 단가) — 연결 = 고른 호표(로직 = 새 산근 키로 풀어 둠)."""
|
||||
"""새 줄(`hand:`) → (항목, 단가) — 연결 = 고른 호표(로직 = 새 산근 키로 풀어 둠) ·
|
||||
연결이 단가를 못 내면 고정 단가 칸(707-1)."""
|
||||
out = []
|
||||
for hand in (user.get("bill") or {}).get("rows") or []:
|
||||
if not str(hand.get("key") or "").startswith("hand:"):
|
||||
continue
|
||||
price = ref_price(hand.get("ref"), books, hopyo, hand["key"])
|
||||
ref = {"tab": price["tab"], "key": price["key"]} if price and price.get("tab") else None
|
||||
fixed = price is None and (price := fixed_price(hand.get("price"))) is not None
|
||||
why = WHY_LOGIC if (hand.get("ref") or {}).get("tab") == "logic" else WHY_HAND
|
||||
item = {**hand, "hand": True, "note": (price or {}).get("no") or "", "ref": ref}
|
||||
note = (price or {}).get("no") or hand.get("note") or ""
|
||||
item = {**hand, "hand": True, "note": note, "ref": ref, "fixed": fixed}
|
||||
out.append((item, price, why))
|
||||
return out
|
||||
|
||||
@@ -209,6 +225,10 @@ def _covered(
|
||||
out["note"] = (prices or {}).get("no") or ""
|
||||
if (cover["ref"] or {}).get("tab") == "logic":
|
||||
out["why"] = WHY_LOGIC
|
||||
if prices is None and (prices := fixed_price(cover.get("price"))) is not None:
|
||||
out["fixed"] = True # 707-1 연결이 단가를 못 냄 = 고정 단가 칸
|
||||
if num(cover.get("src_qty")) is not None:
|
||||
out["src_qty"] = num(cover["src_qty"])
|
||||
return out, prices
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user