fix(규격 표 화면): 열 합계 한 자리 · 규격 줄 칸 폭 · B08 · B09 금액 = 열 수량 × 단가 시험 (PLAN 704-4)

- 격자 합계 줄 규격 칸 = 금액 칸처럼 소수 한 자리
- 규격 이름 · 열 이름 칸 6em — 좁은 카드에서 한 줄
- 임시 storage 시험 — 사본 셈 반영합 = 층 문서 그 열 셈(B08) · 대가 줄 금액 = 열 수량 × 단가(B09)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 14:41:13 +09:00
co-authored by Claude Opus 5.5
parent 56e2c0b515
commit 90273507c5
3 changed files with 29 additions and 1 deletions
@@ -152,6 +152,7 @@ export function specBar(doc: LaborDoc, calc: LaborCalc | null, edit: SpecEdit):
return createToolbar({ items: [createText(TEXT.none, "muted"), add], label: TEXT.name });
const name = createInputField({ value: spec.이름, compact: true, placeholder: TEXT.name });
name.input.title = TEXT.name;
name.root.style.width = "6em"; // 짧은 글 칸 — 열 이름 칸도 같은 폭(카드 한 줄에)
name.input.addEventListener("change", () => {
const v = name.input.value.trim();
if (v && v.length <= 20) spec.이름 = v;
@@ -160,6 +161,7 @@ export function specBar(doc: LaborDoc, calc: LaborCalc | null, edit: SpecEdit):
const cols = spec.열.flatMap((col) => {
const box = createInputField({ value: col, compact: true });
box.input.setAttribute("data-spec-col", col);
box.root.style.width = "6em";
box.input.addEventListener("change", () => {
renameColumn(doc, col, box.input.value);
edit(true);
+23
View File
@@ -224,3 +224,26 @@ console.log(JSON.stringify([toSummary(row, "1.5"), toSummary(one, "1.5"), toSumm
assert single["name"] == "석축 메쌓기" and single["spec"] == "1.5" # 열 하나 = 이름 그대로
assert "spec" not in plain # 규격 없는 옛 항목
assert starts == ["1.5", "2.0", "2.0", None]
def test_B08_B09_금액_열_수량_곱하기_단가(world):
"""B08 = 사본 1 단위 값(사본 셈 반영합) = 층 문서 그 열 셈 · B09 = 대가 줄 금액 = 열 수량 × 단가."""
from M02_MasterTemplete import M02_Item_Prices as item_prices
from M02_MasterTemplete import M02_Labor_Doc as labor
root = world["root"]
_save(root, ["2.5"])
folder = snap.structures_dir(root) / "st0"
read = lambda name: json.loads((folder / name).read_text(encoding="utf-8")) # noqa: E731
copy = item_prices.calc(read("일위대가.json"), read("단가.json"), read("입력값.json"), {}, None)
layer = labor.clean(LABOR)
want = labor.settle(labor.calc(layer, {}), layer, {}, "2.5")["반영합"]
assert copy["반영합"]["계"] == pytest.approx(want["계"]) # B08 1 단위 값 = 2.5 열
first = labor.settle(labor.calc(layer, {}), layer, {}, "1.5")["반영합"]
assert want["계"] != pytest.approx(first["계"])
got, block = _block(root, "st0")
price = {ln["key"]: {"labor": 1000.0, "material": 0.0, "expense": 0.0} for ln in block["lines"]}
sheets = {"labor": [], "material": [], "machine": [], "gaps": []}
out = compute_labor(got, sheets, price, {})
lines = next(b for b in out["daega_blocks"] if b["id"] == block["id"])["lines"]
assert [ln["amounts"]["labor"] for ln in lines] == [3000, 500] # 3 × 1000 · 공통 0.5 × 1000
+4 -1
View File
@@ -195,7 +195,10 @@ export function hopyoGrid(blocks: HopyoBlock[]): HopyoGrid {
const blank = hopyoBlank(b);
titles.add(rows.length);
const sums = Object.fromEntries(
Array.from({ length: specCount }, (_, k) => [hopyoSpecKey(k), b.specs?.totals[k] ?? null]),
Array.from({ length: specCount }, (_, k) => {
const sum = b.specs?.totals[k];
return [hopyoSpecKey(k), sum == null ? null : Math.round(sum * 10) / 10]; // 금액 칸처럼 한 자리
}),
);
rows.push({
...sums,