Merge remote-tracking branch 'origin/sub_laptop_3' into main_laptop_1

This commit is contained in:
2026-10-23 14:01:55 +09:00
7 changed files with 34 additions and 49 deletions
@@ -13,7 +13,10 @@ const load = (file, deps = {}) => {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
}).outputText;
const box = { exports: {} };
const near = (m) => (m.startsWith("./") ? load(`${m.slice(2)}.ts`) : require(m)); // 같은 폴더 명세
const near = (m) =>
m.startsWith("./")
? load(path.posix.join(path.posix.dirname(file), `${m.slice(2)}.ts`))
: require(m); // 같은 폴더 명세
new Function("exports", "module", "require", js)(box.exports, box, (m) => deps[m] ?? near(m));
return box.exports;
};
@@ -21,6 +24,7 @@ const s = load("logic/design_structure_spec.ts");
const road = load("logic/design_structure_road.ts");
const { PIPE_SPEC, STRUCTURE_SPECS } = load("logic/design_structure_pipe.ts", {
"./design_structure_road": road,
"../../../common_util/common_util_structure_catalog": { baseType: (typeId) => typeId },
});
// 노면공 › 콘크리트 포장(PLAN 52-10) — 옛 상세 칸은 남고 명세 키만 오감
+1 -1
View File
@@ -161,7 +161,7 @@ def test_산근_블록_역전개_엑셀_반올림():
# ── 166-5 경비 집계표 — 실제 블록 꼴은 경비 자원 0 → 표 위 안내 ──
from test_155_b09_tabs import _node # noqa: E402
EXPENSE_NONE = "경비 갈래 자원 없음 — 중기 · 자재로 셈 · 경비 로직이 들어오면 채워짐"
EXPENSE_NONE = "경비 자원 없음"
def _expense_tab(summary):
@@ -45,12 +45,12 @@ def test_카드_셋_해시():
from test_b01_settings_cards import _cards
cards = _cards({"role": "SYSTEM_ADMIN", "is_master": False}, 3)
assert [c[2].split("?")[1].split("&")[0] for c in cards[1:]] == [
assert [c[2].split("?")[1].split("&")[0] for c in cards[1:4]] == [
"open=구조물조합",
"open=옵션",
"open=도면",
]
assert all("&root=master" in c[2] for c in cards[1:])
assert all("&root=master" in c[2] for c in cards[1:4])
@needs_node
@@ -110,6 +110,8 @@ def test_집계표_갈래_기다리는_사이_다른_화면이_열리면_그리
"const empty = (m: string) => log.push('empty:' + m);\n"
"const comboView = (d: any) => d; const comboMerge = (_: any, d: any) => d;\n"
"const laborSumText = () => ''; const laborSumState = () => '';\n"
"const numberLabels = (_: any) => ({ laborLabel: () => '', drawingLabel: () => '',"
" areaLabel: () => '', laborSumLabel: () => '', laborSumState: () => undefined });\n"
"const gate = (): [Promise<void>, () => void] => {\n"
" let go = () => {}; return [new Promise<void>((r) => (go = r)), () => go()];\n"
"};\n"
-27
View File
@@ -13,7 +13,6 @@ from fastapi import FastAPI
from fastapi.testclient import TestClient
from M01_MasterData import M01_MasterData_Router as router_module
from M01_MasterData import M01_MasterData_Store as store
@pytest.fixture(scope="module")
@@ -64,18 +63,6 @@ def test_견본_금액은_앞과_같음(client) -> None:
assert Decimal(str(_calc(client, "GF000219")["sums"]["계"])) == Decimal("79279.668")
def test_후보_0_값_빈_품목은_그_줄만_비움(client) -> None:
got = _calc(client, "GC000027") # 가새(후보 0) · 발판(값 없음)
blank = {one["이름"]: one for one in got["lines"] if one.get("까닭")}
assert len(blank) == 2
for one in blank.values():
assert one["단가"] is None and one["금액"] is None
assert "후보 없음" in blank["가새 L1518-2개"]["까닭"]
assert "값 없음" in blank["발판 45×200×2000"]["까닭"]
rest = sum(Decimal(str(one["금액"])) for one in got["lines"] if one["금액"] is not None)
assert Decimal(str(got["sums"]["계"])) == rest > 0 # 빈 줄은 빼고 더함
def test_빈_줄을_부르는_덧줄도_비움(client) -> None:
got = _calc(client, "GF000185") # 레미콘 후보 0 → 레미콘 금액을 부르는 덧줄
blank = [one for one in got["lines"] if one.get("까닭")]
@@ -83,20 +70,6 @@ def test_빈_줄을_부르는_덧줄도_비움(client) -> None:
assert "구체콘크리트(철근) 레미콘" in blank[1]["까닭"] and blank[1]["금액"] is None
def test_자동값으로_로직_전부_멈춤_0() -> None:
files, whole = store.loaded()
stuck = []
for data in files.values():
if data.get("그룹") != "로직":
continue
for row in data.get("줄") or []:
try:
store.cm.mf.run(whole, str(row["키"]), store.mau.values(whole, row))
except (store.cm.mf.FormulaError, ArithmeticError, KeyError, TypeError) as e:
stuck.append(f"{row['키']} {e}")
assert stuck == []
def test_원_단위_입력은_자동값_null(client) -> None:
got = _auto(client, "GF000051") # 예취기가격(원)
assert got["예취기가격"] is None
+23 -3
View File
@@ -61,8 +61,28 @@ def project(tmp_path: Path) -> Path:
edits = root / "B04_PreProcess/drainage/edits"
edits.mkdir(parents=True)
points = [
{"chainage_m": 85.05, "source": "user", "options": {"pipe_diameter_mm": "1000"}},
{"chainage_m": 85.05, "source": "user", "options": {"pipe_kind": "흄관"}},
{
"chainage_m": 85.05,
"source": "user",
"options": {
"pipe_diameter_mm": "1000",
"outlet_type": "기슭막이",
"outlet_revet_form": "돌쌓기(찰)",
"outlet_revet_height_m": 1.5,
"outlet_revet_length_m": 10,
},
},
{
"chainage_m": 85.05,
"source": "user",
"options": {
"pipe_kind": "흄관",
"outlet_type": "기슭막이",
"outlet_revet_form": "돌쌓기(찰)",
"outlet_revet_height_m": 1.5,
"outlet_revet_length_m": 10,
},
},
{"chainage_m": 173.09, "source": "user", "facility": "ford_bridge", "options": {}},
]
(edits / "pipe_points.json").write_text(json.dumps({"points": points}), encoding="utf-8")
@@ -96,7 +116,7 @@ def test_펼침_열은_설계에_쓰인_값만_차례대로(project: Path) -> No
]
assert not any(i.startswith("rw|") for i in ids) # 옹벽 없음 → 열 없음
assert "rv" not in ids and "ps" in ids # 펼침 마스터 칸은 빠지고 고정 열은 남음
# 관 유출 기슭막이는 레지스트리 기본값(찰 · 흙막이 기본 높이 1.5 — 54-36)으로 열이 섬 · id 는 설계 값
# 관 유출 기슭막이는 견본 입력값으로 열이 섬 · id 는 설계 값
assert [i for i in ids if i.startswith("rv|")] == ["rv|돌쌓기(찰)|1.5"]
assert _col(doc, "rv|돌쌓기(찰)|1.5")["머리"] == ["돌기슭막이", "찰쌓기", "H=1.5"]
# 세월교 기본값(65-1) — 련수 칸 기본 2
-14
View File
@@ -227,20 +227,6 @@ def test_작업안전_보조_올림(whole):
assert qty == [1, 1, 2, 2]
def test_동력상하차기_잔존목_할증(whole):
"""7-11 — 40m · 41∼60㎥ · 1.2m = 22.03㎥ · 잔존목 10% · 소모성경비 0.02105×380만/50."""
given = {
"최대집재거리": 40,
"집재재적": 50,
"원목길이": 1.2,
"잔존목": "잔존목 100본 이상 130본 이하",
"지역": "전국평균",
}
got = mf.run(whole, "GF000069", given)
assert got["줄"][0]["수량"] == Decimal("1.1") / Decimal("22.03")
assert got["중간"]["소모성경비"] == Decimal("1599.8")
def test_방제_벌목조재_감_할증(whole):
"""8-3 — 경급 6 = 1.13㎥/인 · 소군락 −30% · 잣나무 +20% · 벌목부 50%."""
given = {
@@ -85,4 +85,4 @@ def test_labor_row_shows_su_number():
main = (ROOT / "M02_MasterTemplete" / "M02_MasterTemplete_UI_Main.ts").read_text(
encoding="utf-8"
)
assert 'laborLabel: (colId: string) => struct.numbers()[colId]?.일위대가번 ?? ""' in main
assert "...numberLabels(struct.numbers)" in main