feat(727-1): 고르기 창 기초 = 로직마다 한 줄 · [기본 로직 선택] 단추 걷음 · 첫 기초 = 바탕

- 기준 목록 옵션 줄(바꿈) 뺀 바탕 줄만 · 규격 칸 = 「옵션 N」(새 순수 함수 logic/M02_Find_Heads.ts) — 찾아 넣기 창 · 옛 창(Labor_Pick) 같이 · 옵션 줄 골라도 옵션 버리던 흠 걷음 · 서버 목록 그대로
- 단가산출 상세 [항목 추가] 기초 = 바탕 비었으면 바탕(옛 단추 동작 · 단위 비거나 식이면 기초 결과단위) · logicOnly 걷음 · locale M02_SangeunPickBase 지움
- 낡은 시험 test_721_find_pick 721-1 · 721-2 = 단추 걷음 · logicOnly 없음으로 고침 · 새 시험 test_727_sk_base_add
- 기초 줄 1,461(옛 10,053) · GF000099 한 줄 「옵션 1」

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-02 10:14:07 +09:00
co-authored by Claude Opus 5.5
parent 638d3f446d
commit 76ac1c499e
7 changed files with 160 additions and 74 deletions
+7 -6
View File
@@ -1,7 +1,7 @@
"""721 M02 찾아 넣기 창 — 단추 이름 · 자리 · 부르는 곳 · 인력 · 재료 줄 꼴(요구서_내역16 1장 5~7 · 2장 1 · 2 · 8).
- 721-1 단가산출 상세 = [기본 로직 선택]이 둘째 줄 [항목 추가] 왼쪽
- 721-2 M02 세 곳(기본 로직 선택 · 항목 추가 · 일위대가 [로직 추가])만 새 창 · B09 · 불러오기는 옛 창
- 721-1 단가산출 상세 = 둘째 줄 [항목 추가](727-2 [기본 로직 선택] 걷음 — 첫 기초가 바탕)
- 721-2 M02 두 곳(항목 추가 · 일위대가 [로직 추가])만 새 창 · B09 · 불러오기는 옛 창
- M01 전체 = 로직 · 인력(job) · 재료(price) · 기계 · 실무 호표 없음
- 고른 인력 · 재료 = 단가산출 더한줄 `{종류, 요소}` · 일위대가 고정 줄(705-1 이음 꼴) — 둘 다 서버가 받아 노임 · 자재 값으로 셈
"""
@@ -26,10 +26,10 @@ def _text(path: Path) -> str:
def test_721_1_단추_이름과_자리():
detail = _text(M02 / "M02_MasterTemplete_Sangeun_Detail.ts")
assert "children: [views.root, pick, addButton, baseHint]" in detail
assert " pick,\n );" not in detail # 머리 줄에서 뺌
assert "children: [views.root, addButton, baseHint]" in detail
assert "M02_SangeunPickBase" not in detail # 727-2 단추 걷음
locale = _text(ROOT / "ui_template" / "ui_template_locale_m2.ts")
assert 'M02_SangeunPickBase: ["기본 로직 선택"' in locale
assert "M02_SangeunPickBase" not in locale
assert 'M02_SangeunAddLine: ["항목 추가"' in locale
@@ -39,7 +39,8 @@ def test_721_2_부르는_곳_셋만_새_창():
assert 'if (lib?.sangeun && lib.layer !== "project")' in labor_pick
assert "return openFindPicker({" in labor_pick
assert "findSangeun" not in labor_pick # 옛 창의 단가산출 탭 걷음
assert "logicOnly: true," in _text(M02 / "M02_MasterTemplete_Sangeun_Detail.ts")
assert "logicOnly" not in _text(M02 / "M02_MasterTemplete_Sangeun_Detail.ts") # 727-2
assert "logicOnly" not in find
assert "openFindPicker({" in _text(M02 / "M02_MasterTemplete_Sangeun_Pick.ts")
assert "sangeun: true," in _text(M02 / "M02_MasterTemplete_Hopyo_Pick.ts") # 일위대가
# 옛 창 그대로 — B09 · 불러오기는 sangeun 없이 부름
+67
View File
@@ -0,0 +1,67 @@
"""727 M02 단가산출 기초 넣기(요구서_내역19 · 내역 20-1) — 임시 storage · 실제 M01 읽기만.
- 727-1 고르기 창 기초 = 로직마다 한 줄(`logic/M02_Find_Heads.ts` · 옛 창도) · 규격 칸 = 「옵션 N」
- 727-2 첫 기초 = 바탕 · 둘째부터 = 더한줄 세부 펼침(덮개 · 뺀줄 · M01 개정 지문 · 꼬리표) · B09 굳힘 같은 값
- 727-3 넣은 뒤 고른 옵션 = SK `입력값` → 일위대가(펼침) · 굳힘도 그 옵션
"""
from __future__ import annotations
import json
import re
import subprocess
from pathlib import Path
from M01_MasterData import M01_MasterData_Store as m01
from M02_MasterTemplete import M02_Logic_Standard as standard
ROOT = Path(__file__).resolve().parents[2]
M02 = ROOT / "M02_MasterTemplete"
IMPORTS = re.compile(r"^import[^;]*;\n", re.MULTILINE)
GF = "GF000099" # 측구터파기 토사 · 원/㎥ · 입력 지역 · 보정작업
def _node(files: list[str], body: str):
code = "".join(IMPORTS.sub("", (ROOT / f).read_text("utf-8")) for f in files)
got = subprocess.run(
["node", "--experimental-strip-types", "--no-warnings",
"--input-type=module-typescript", "-"],
input=code + body, capture_output=True, text=True, encoding="utf-8", timeout=60,
) # fmt: skip
assert got.returncode == 0, got.stderr
return json.loads(got.stdout)
def _heads(rows):
body = (
f"\nconst rows = {json.dumps(rows, ensure_ascii=False, default=str)};"
"\nconsole.log(JSON.stringify(logicHeads(rows, (n) => `옵션 ${n}`)));"
)
return _node(["M02_MasterTemplete/logic/M02_Find_Heads.ts"], body)
def test_727_1_기초마다_한_줄():
whole = m01.loaded()[1]
rows = []
for key in (GF, "GC000269", "GC001109"):
rows += standard._rows_of(whole, whole.logic(key), False)
assert sum(r["키"] == GF for r in rows) == 3 # 옵션 축 보정작업 두 값 + 바탕
got = _heads(rows)
assert [r["키"] for r in got] == [GF, "GC000269", "GC001109"]
assert all(r["바꿈"] == {} for r in got)
one = got[0]
assert one["규격"] == "옵션 1" and one["금액"] == next(r for r in rows if r["키"] == GF)["금액"]
assert got[2]["규격"] == "" # 옵션 없는 기초
listed = standard.listing()
if listed["준비"]: # 파생 저장본이 있을 때 — 1,461 안팎(로직 수)
heads = _heads([{k: r[k] for k in ("키", "규격", "바꿈")} for r in listed["줄"]])
assert len(heads) == len({r["키"] for r in listed["줄"]})
assert 1400 <= len(heads) <= 1600
def test_727_1_두_창_모두_기초_한_줄():
find = (M02 / "M02_MasterTemplete_Find_Pick.ts").read_text("utf-8")
old = (M02 / "M02_MasterTemplete_Labor_Pick.ts").read_text("utf-8")
assert "std = s?.줄.length ? logicHeads(s.줄) : null;" in find
assert "std = got.줄.length ? logicHeads(got.줄) : null;" in old
assert "logicOnly" not in find