fix(778-4): 율 줄 화면 = 그 비목 상자 % 줄 — 엔진 줄 비목 · 상세 덧줄 자리

- 율 더한줄 엔진 줄에 비목(묶음 = 경비 등) → 글 보기 · 상자가 「하위 로직」 아닌 그 비목 상자
- 단가산출 상세(hoView) = 율 줄을 덧줄 자리(율 · 「인력의 %」) · 수량 고침 = 율 그대로(화면배 안 나눔)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-04 13:09:58 +09:00
co-authored by Claude Opus 5.5
parent d9a581659f
commit b8772a4172
3 changed files with 20 additions and 5 deletions
+1 -3
View File
@@ -373,9 +373,7 @@ def run(
if detail and one.get("종류") == "로직" and at not in gaps:
mark |= _detail(one, int(hit[1]), whole)
if sd.is_rate(one): # 율 줄 = 율 · 「기준의 %」(화면 % 줄 · `per_unit` 수량 그대로)
rate = one["고정"]["비율"]
group = {"노무비": "인력", "재료비": "재료", "경비": "경비"}[rate["비목"]]
mark |= {"율": Decimal(str(one["수량"])), "규격": _rate_text(rate), "묶음": group}
mark |= {"율": Decimal(str(one["수량"])), "규격": _rate_text(one["고정"]["비율"])}
lines.append(
{**line, "cid": cid, **mark, **({"원값": mine["원값"]} if "원값" in mine else {})}
)
+2
View File
@@ -436,6 +436,8 @@ def _add_item(one: dict) -> dict:
qty = text(one["수량"])
if "참조" in one or "고정" in one:
kept = {k: one[k] for k in ("참조", "고정") if k in one}
if is_rate(one): # 율 줄(778-4) = 그 비목 한 칸(엔진 묶음 · 보기 상자 = 비목)
kept["비목"] = one["고정"]["비율"]["비목"]
return {**head, "종류": "로직", "요소": None, "수량": qty, **kept, "값묶음": None}
if one.get("종류") == "로직":
args = "".join(
@@ -78,6 +78,8 @@ export interface SkLine {
묶음?: string | null;
cid: string;
율?: number;
/** % 줄 밑 이름(「노무비의 %」 · 율 줄 「인력의 %」) */
규격?: string;
/** 못 셈 줄(725) — 금액 없음 · 계에 안 듦 */
까닭?: string;
/** 둘째 기초(727-2) — 세부 줄 · 뺀 세부 · 그 기초 지문 · 원문번호 */
@@ -179,6 +181,13 @@ function flatIds(ans: SkAnswer): string[] {
return ans.정체.flatMap((c) => by.get(c)?.펼침?.map((x) => x.cid) ?? [c]);
}
/** 율 더한줄(778-4) 비율 — `add:#k` 의 고정 `비율` · 아니면 undefined */
const rateOf = (doc: SkDoc, cid: string): { 비목: string } | undefined => {
const hit = ADD_RE.exec(cid);
const one = hit ? doc.더한줄?.[Number(hit[1])] : undefined;
return (one?.고정 as { 비율?: { 비목: string } } | undefined)?.비율;
};
/** 기초 수 — 로직 바탕 · 더한줄 로직 */
const baseCount = (doc: SkDoc): number =>
(doc.바탕?.로직 ? 1 : 0) + (doc.더한줄 ?? []).filter((x) => x.종류 === "로직").length;
@@ -257,7 +266,7 @@ export function rowsOf(ans: SkAnswer, bare: SkAnswer | null, doc: SkDoc): CoverR
const one = added === null ? undefined : doc.더한줄?.[added];
const owner = at ? doc.더한줄?.[at.k] : undefined;
const cover = at ? owner?.덮개?.[at.cid] : added === null ? doc.덮개?.[cid] : undefined;
const pct = (at?.cid ?? cid).startsWith("pct:") || extra.율 !== undefined; // 덧줄 · 율 줄(778-4)
const pct = (at?.cid ?? cid).startsWith("pct:") || !!rateOf(doc, cid); // 덧줄 · 율 줄(778-4)
const keys = Object.keys(parts);
const shown = added === null && !at ? (was.get(cid) ?? null) : null;
const base = at
@@ -514,6 +523,11 @@ export function hoView(
extra.push([cid, { ...((known.get(cid) as HoExtra) ?? { 이름: name, 식: "" }), ...tag }]);
continue;
}
const rate = rateOf(doc, cid); // 율 더한줄(778-4) = 비목 상자 % 줄(식 = 「인력의 %」)
if (rate) {
extra.push([cid, { 이름: name, 식: String(l?.규격 ?? ""), 비목: rate.비목, ...tag }]);
continue;
}
if (at) {
const kind = KIND_OF[at.cid.split(":")[0]] ?? "로직";
const qty = String(l?.율 ?? l?.원문?.수량 ?? l?.수량 ?? ""); // 세부 품 = M01 원문(744-1)
@@ -544,7 +558,8 @@ export function hoView(
const hit = ADD_RE.exec(cid);
const a = hit ? doc.더한줄?.[Number(hit[1])] : undefined;
const part = PART_OF[String(a?.비목 ?? "")];
if (a) covers[i] = { qty: a.수량 / t, ...(a.단가 != null && part ? { [part]: a.단가 } : {}) };
const own = rateOf(doc, cid) ? 1 : t; // 율 = 그대로
if (a) covers[i] = { qty: a.수량 / own, ...(a.단가 != null && part ? { [part]: a.단가 } : {}) };
const at = subOf(cid);
const owner = at ? doc.더한줄?.[at.k] : undefined;
const c = hit ? undefined : at ? owner?.덮개?.[at.cid] : doc.덮개?.[cid];