feat(778-4): 율 줄을 단가산출(SK)에 담음 — 고정 비율 더한줄 · 기준 묶음 · 줄 목록 · 율 위 율
- SK 더한줄 율 줄 허용(일위대가 비율 줄과 같은 꼴 `고정 비율 {기준, 비목}` · 수량 = 율)
- 기준 = 비목(노무비 · 재료비 · 경비) · 묶음(인력 · 재료 · 장비 = 그 줄 종류만 · 기계 노무 섞인 블록도 인력 줄만) ·
줄 목록(cid · add:#k · 앞 율 줄 = 율 위 율) · 검사 = 자기 · 뒤 율 줄 막음
- 밑 공용 함수 `M02_Labor_Fixed.rate_base` ↔ 짝 `Labor_Calc.ts` `rateBase`(일위대가 비율 줄 · Expand 같이 씀)
- SK 셈 `_rated` = 엔진 한 번 돈 줄로 밑 → 율 줄 값묶음 → 엔진 다시(율 줄 없는 문서 = 한 번 · 값 그대로)
- B09 pct 밑수 `bundle:` · `rows:`(파이썬 · TS 짝) · SK 블록 율 줄 = pct
- 굳힘 — 바탕 없는 SK 율 줄은 한 줄로 안 펼침(참조 그대로) · 겹침 때 기준 열쇠 새 차례
- 화면 — [율 줄 추가] 창(새 `M02_MasterTemplete_Sangeun_Rate.ts` · 부품 상자만) · 율 줄 = % 줄로 보임 ·
더한줄 지움 · 되살림 때 기준 열쇠 옮김
- 시험 — 새 test_778_4_rate_line(25) · 거울 헬퍼에 rateBase 길 · 전후 대조 SK 16 · 일위대가 118 · B09 대가 입력 14 같음
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,8 +7,11 @@
|
||||
(노임 새 판 때 따라감) · 품(수량)은 그대로.
|
||||
M02 셈(층 · 사본) = 노임 「값」 · 자재 기준단가로 이음 · 기계 = 줄 단가(기계 시간 단가 = B09 단가 책 몫).
|
||||
출처 = `{파일, 호표, 줄, 판}`(글 · 수만) · 줄 가름 = 「고정|이름|규격|단위」(짝 `Labor_Calc.ts` `lineId`).
|
||||
비율 줄(705-3 · 엑셀 % 줄) = `비율 {기준, 비목}` · 수량 = 율(%) — 반영[비목] = 다른 줄 반영합[기준] × 율 ÷ 100
|
||||
(`ratios` · 짝 `Labor_Calc.ts` `ratioLines` · B09 = `pct` 줄).
|
||||
비율 줄(705-3 · 엑셀 % 줄) = `비율 {기준, 비목}` · 수량 = 율(%) — 반영[비목] = 밑 × 율 ÷ 100
|
||||
(`ratios` · 짝 `Labor_Calc.ts` `ratioLines` · B09 = `pct` 줄) · 단가산출(SK) 율 더한줄(778-4)도 이 꼴.
|
||||
기준(778-4 · 밑 = `rate_base` · 짝 `Labor_Calc.ts` `rateBase`) = 비목(노무비 · 재료비 · 경비 = 율 줄 뺀
|
||||
그 비목 합) · 묶음(인력 · 재료 · 장비 = 그 묶음 줄 노 · 재 · 경 합 · 고정 줄 묶음 = 이음) ·
|
||||
줄 목록 [열쇠](그 줄 합 · 앞 율 줄 넣으면 율 위 율 · SC 열쇠 = 줄 가름 · SK = cid).
|
||||
B09 대가 갈래 `fixed` = `B09_Estimation_Labor_Source.fixed_line` · 셈 `B09_Estimation_Calc_Labor`.
|
||||
"""
|
||||
|
||||
@@ -27,6 +30,8 @@ COSTS = mf.COST_ITEMS # 노무비 · 재료비 · 경비
|
||||
FIXED = "고정"
|
||||
LINKS = {"노임": "LB", "자재": "MT", "기계": "EQ"}
|
||||
SOURCE_KEYS = ("파일", "호표", "줄", "판")
|
||||
GROUPS = {"노임": "인력", "자재": "재료", "기계": "장비"} # 율 기준 묶음(778-4) ← 고정 줄 이음
|
||||
BASES = (*COSTS, *GROUPS.values())
|
||||
|
||||
|
||||
def _bad(text: str) -> Exception:
|
||||
@@ -82,9 +87,9 @@ def clean(fx: Any, where: str, whole: Any) -> dict[str, Any]:
|
||||
link[k] = code or None
|
||||
rate = fx.get("비율")
|
||||
if rate is not None and not (
|
||||
isinstance(rate, dict) and rate.get("기준") in COSTS and rate.get("비목") in COSTS
|
||||
isinstance(rate, dict) and _basis(rate.get("기준")) and rate.get("비목") in COSTS
|
||||
):
|
||||
raise _bad(f"{where} · 고정 줄 비율은 {{기준, 비목}} — 노무비 · 재료비 · 경비")
|
||||
raise _bad(f"{where} · 고정 줄 비율은 {{기준, 비목}} — 기준 = 비목 · 묶음 · 줄 목록")
|
||||
src = fx.get("출처") if isinstance(fx.get("출처"), dict) else {}
|
||||
kept = {k: v for k in SOURCE_KEYS if isinstance(v := src.get(k), (str, int, float))}
|
||||
out = {"이름": name, "규격": str(fx.get("규격") or ""), "단위": str(fx.get("단위") or "")}
|
||||
@@ -92,6 +97,42 @@ def clean(fx: Any, where: str, whole: Any) -> dict[str, Any]:
|
||||
return {**out, "비율": {k: rate[k] for k in ("기준", "비목")}} if rate else out
|
||||
|
||||
|
||||
def _basis(raw: Any) -> bool:
|
||||
"""율 기준 — 비목 · 묶음 이름 · 줄 열쇠 목록(글 · 빈 목록 = 밑 0 · 기준 줄을 지운 뒤)."""
|
||||
if isinstance(raw, list):
|
||||
return all(isinstance(x, str) and x for x in raw)
|
||||
return raw in BASES
|
||||
|
||||
|
||||
def group_of(fx: dict) -> str | None:
|
||||
"""고정 줄 묶음 — 첫 이음(노임 · 자재 · 기계) · 이음 없음 = None."""
|
||||
link = fx.get("이음") or {}
|
||||
return next((g for k, g in GROUPS.items() if link.get(k)), None)
|
||||
|
||||
|
||||
def _all(money: dict | None) -> Decimal:
|
||||
return sum((Decimal(str((money or {}).get(k) or 0)) for k in COSTS), Decimal(0))
|
||||
|
||||
|
||||
def rate_base(basis: Any, rows: list[dict]) -> Decimal:
|
||||
"""율 줄 밑(778-4 · 짝 `Labor_Calc.ts` `rateBase`) — `rows` [{키, 묶음, 비목 {노 · 재 · 경}, 율?}] ·
|
||||
비목 = 율 줄 뺀 그 비목 합 · 묶음 = 율 줄 뺀 그 묶음 줄 셋 합 · 목록 = 그 열쇠 줄 셋 합."""
|
||||
if isinstance(basis, list):
|
||||
keep = set(basis)
|
||||
return sum((_all(r["비목"]) for r in rows if r.get("키") in keep), Decimal(0))
|
||||
rows = [r for r in rows if not r.get("율")]
|
||||
if basis in COSTS:
|
||||
return sum((Decimal(str((r["비목"] or {}).get(basis) or 0)) for r in rows), Decimal(0))
|
||||
return sum((_all(r["비목"]) for r in rows if r.get("묶음") == basis), Decimal(0))
|
||||
|
||||
|
||||
def rate_row(one: dict, key: Any, money: dict | None, rate: bool = False) -> dict[str, Any]:
|
||||
"""`rate_base` 줄 하나 — 고정 줄 묶음 = 이음 · 그 밖 = 줄 `묶음`(SK 엔진 줄 · 자재 = 재료)."""
|
||||
fx = one.get(FIXED)
|
||||
group = group_of(fx) if isinstance(fx, dict) else one.get("묶음")
|
||||
return {"키": key, "묶음": group, "비목": money, "율": rate}
|
||||
|
||||
|
||||
def _has(whole: Any, code: str) -> bool:
|
||||
try:
|
||||
return bool(whole.get(code))
|
||||
@@ -136,26 +177,35 @@ def line(whole: Any, fx: dict) -> dict[str, Any]:
|
||||
return {**head, "기준": money, "이은": used, "까닭": None}
|
||||
|
||||
|
||||
def ratio_row(rate: dict, qty: Decimal | None, under: dict) -> tuple[dict, dict | None]:
|
||||
"""비율 줄 (기준, 반영) — 기준[비목] = 밑[기준] · 반영 = 기준 × 율 ÷ 100 ·
|
||||
def ratio_row(rate: dict, qty: Decimal | None, under: Decimal) -> tuple[dict, dict | None]:
|
||||
"""비율 줄 (기준, 반영) — 기준[비목] = 밑(`rate_base`) · 반영 = 기준 × 율 ÷ 100 ·
|
||||
0.1 원 버림(751-3) · 수량 없음 = None."""
|
||||
base = dict.fromkeys((*COSTS, "계"), Decimal(0))
|
||||
base[rate["비목"]] = base["계"] = under[rate["기준"]]
|
||||
base[rate["비목"]] = base["계"] = under
|
||||
return base, None if qty is None else mcut.row({k: base[k] * qty / 100 for k in COSTS})
|
||||
|
||||
|
||||
def ratios(lines: list[dict], reflects: list[dict | None], bases: list[dict | None]) -> None:
|
||||
"""비율 줄(705-3) — `settle` 끝에 · 밑 = 비율 줄 뺀 반영합(줄 · 자재) · 배 100 · 기준합엔 안 셈 ·
|
||||
`lines` · `reflects` · `bases` 앞 줄 = 같은 차례(짝 `Labor_Calc.ts` `ratioLines`)."""
|
||||
at = {i for i, x in enumerate(lines) if (x.get(FIXED) or {}).get("비율")}
|
||||
under = {
|
||||
k: sum((r[k] for i, r in enumerate(reflects) if r and i not in at), Decimal(0))
|
||||
for k in COSTS
|
||||
}
|
||||
for i in sorted(at):
|
||||
base, done = ratio_row(lines[i][FIXED]["비율"], lines[i].get("수량"), under)
|
||||
"""비율 줄(705-3) — `settle` 끝에 · 밑 = `rate_base`(율 줄 뺀 반영(줄 · 자재) · 앞 율 줄은 목록만) ·
|
||||
배 100 · 기준합엔 안 셈 · `lines` · `reflects` · `bases` 앞 줄 = 같은 차례(짝 `Labor_Calc.ts`
|
||||
`ratioLines`) · 자재 줄 = 묶음 재료 · 열쇠 없음."""
|
||||
from M02_MasterTemplete import M02_Labor_Doc as labor
|
||||
|
||||
at = [i for i, x in enumerate(lines) if (x.get(FIXED) or {}).get("비율")]
|
||||
rows = [
|
||||
rate_row(lines[i], labor.line_id(lines[i]), r)
|
||||
if i < len(lines)
|
||||
else {"키": None, "묶음": "재료", "비목": r}
|
||||
for i, r in enumerate(reflects)
|
||||
if r and i not in at
|
||||
]
|
||||
for i in at:
|
||||
rate = lines[i][FIXED]["비율"]
|
||||
base, done = ratio_row(rate, lines[i].get("수량"), rate_base(rate["기준"], rows))
|
||||
lines[i], reflects[i], bases[i] = (
|
||||
{**lines[i], "기준": base, "배": 100, "반영": done},
|
||||
done,
|
||||
None,
|
||||
)
|
||||
if done:
|
||||
rows.append(rate_row(lines[i], labor.line_id(lines[i]), done, True))
|
||||
|
||||
Reference in New Issue
Block a user