diff --git a/resources/tester/helper_est_native.cjs b/resources/tester/helper_est_native.cjs
index 4237ac189..9c387903f 100644
--- a/resources/tester/helper_est_native.cjs
+++ b/resources/tester/helper_est_native.cjs
@@ -38,6 +38,7 @@ for (const file of [
"native-progress-view.js",
"native-annual-copy.js",
"native-print-range.js",
+ "native-work-mode.js",
"native-business-actions.js",
"native-forms.js",
"native-excel-to-est.js",
diff --git a/resources/tester/test_est_work_mode.py b/resources/tester/test_est_work_mode.py
new file mode 100644
index 000000000..f34cfa582
--- /dev/null
+++ b/resources/tester/test_est_work_mode.py
@@ -0,0 +1,57 @@
+"""작업모드: 일반↔표준 원가계산서 묶음 보관·꺼내기, 설치 양식목록 읽기."""
+
+import json
+import subprocess
+from pathlib import Path
+
+import pytest
+
+from test_est_rea_parity import run
+
+ROOT = Path(__file__).resolve().parents[2]
+INSTALL = Path("C:/Dasansoft/Est Plus 2/System/MainSys/SWongaFileList.dat")
+
+
+def test_swap_keeps_each_group_wonga():
+ result = run(
+ "math",
+ """(()=>{
+ const p=EstNative.empty();p.tables.Wonga=[{Name:'일반'}];
+ const a=EstWorkMode.swap(p,3);const std=p.tables.Wonga.length;
+ p.tables.Wonga=[{Name:'표준'}];
+ const b=EstWorkMode.swap(p,4);
+ const c=EstWorkMode.swap(p,1);const back=p.tables.Wonga.map(r=>r.Name);
+ const d=EstWorkMode.swap(p,3);
+ return {a,std,b,c,back,d,now:p.tables.Wonga.map(r=>r.Name),mode:p.options.WorkMode,
+ kept:Object.keys(p.wongaByGroup)};
+ })()""",
+ )
+ assert result["a"] == {"changed": True, "found": False}
+ assert result["std"] == 1
+ assert result["b"] == {"changed": False}
+ assert result["c"] == {"changed": True, "found": True}
+ assert result["back"] == ["일반"]
+ assert result["d"] == {"changed": True, "found": True}
+ assert result["now"] == ["표준"]
+ assert result["mode"] == 3
+ assert result["kept"] == ["general"]
+
+
+@pytest.mark.skipif(not INSTALL.exists(), reason="원본 설치 폴더 없음")
+def test_install_wonga_formats_read():
+ out = subprocess.check_output(
+ [
+ "node",
+ "-e",
+ "const w=require(process.argv[1]);const g=w.get(false),s=w.get(true);"
+ "const f=w.get(true,s[0].index);"
+ "console.log(JSON.stringify({g:g.length,s:s.length,rows:f.rows.length,"
+ "cost:f.rows.some(r=>'Cost' in r),first:f.rows[0].LinkIndex}))",
+ str(ROOT / "tools/est-test/wonga-formats.cjs"),
+ ],
+ text=True,
+ encoding="utf-8",
+ )
+ result = json.loads(out)
+ assert result["g"] == 30 and result["s"] == 30
+ assert result["rows"] > 10 and result["cost"] is False and result["first"] == 54
diff --git a/tools/est-test/PLAN.md b/tools/est-test/PLAN.md
index 2fa80ac81..8d1c71edf 100644
--- a/tools/est-test/PLAN.md
+++ b/tools/est-test/PLAN.md
@@ -503,6 +503,9 @@ ative-standard.js에 표준시장단가 원천(SilJukDat)과 내역 행(EstMainD
- 검증완료: 시험 2개·연차 시험 통과. ORCA 브라우저에서 내역 3·4행 → 1차 10행 복사, 차수 계산 오류 없음 확인, 원복.
- [x] 인쇄범위·인쇄양식목록(spec_pc §6.2·§6.4) — 미리보기 「인쇄범위」: 부수 · 현재면(보이는 쪽) · 현재항목 전체(쪽 범위, 0 = 전체, 넘침·거꾸로 알림, 부수마다 그 서식 간지) · 일괄인쇄(묶음 인쇄). 묶음 인쇄 창 「인쇄양식목록」: 지금 인쇄표·설정·묶음 고르기를 이름 붙여 등록 · 열면 통째로 바꿈 · 삭제 · .pfot 파일 불러오기/저장. 기성·연차 따로 목록은 두지 않음.
- 검증완료: 시험 2개·묶음 인쇄 시험 통과. ORCA 브라우저에서 3쪽 중 1~2쪽 × 2부 = 4쪽, 범위 넘침 알림, 양식 등록·열기(묶음 고르기 되돌아옴)·삭제 확인, 원복.
+ - [x] 작업모드 표준내역서·표준설계변경·최근 계약심사목록(spec_pc §4) — 작업모드 메뉴 내역서·설계변경·표준내역서·표준설계변경이 모드 값(CurrentWorkMode, ESTX 읽기·쓰기)을 바꿈. 일반↔표준 묶음이 바뀌면 지금 원가계산서를 옛 묶음 칸에 두고 새 묶음 것을 꺼냄(없으면 설치 양식목록 — 일반 WongaFileList·표준 SWongaFileList 각 30종 — 에서 고름, 번호 기준 계산). 원본은 모드를 바꿀 때 문서를 닫고 최근 목록을 띄우나 웹은 지금 작업 유지. 최근 계약심사목록 = 저장한 작업 중 계약심사 입력이 있는 것.
+ - 미결: 표준 양식의 산업안전보건관리비 식 「A × 0.496」 의 A 가 무엇인지 미확인 — 웹은 「참조 항목 없음: A」 로 알림(원본 확인 필요).
+ - 검증완료: 작업모드 시험 2개·ESTX 저장 시험 34개 통과. ORCA 브라우저에서 표준내역서로 바꿈 → 표준 양식 30종 → 열기, 내역서로 돌아오면 원래 원가계산서 31행 복원, 계약심사목록 창 확인, 원복.
- [x] 다른 공사 불러오기 창(원본 barbtnSelfLoad → TfrmOtherLoad, 찾기 popSerch) — 저장된 다른 작업을 골라 같은 표를 띄우고 찾기(품명·규격, A&B 둘 다)·고른 줄을 하위 자료와 함께 가져오기(내역서는 고른 줄 아래에 줄, 나머지는 자료·호표 합침, 같은 코드는 이 공사 것). 검증완료: 바인딩 통과, ORCA 브라우저에서 산불진화임도 작업의 일위대가 3개 → 「취수장」 1개 → 가져오기 호표 8→9·하위 41건, 샘플 복구.
- [x] 사용위치 검색 창(원본 TfrmUsesDataSerch btnSerch·btnAllDisplay) — 현재 표 항목을 품명·규격(빈칸·|·괄호 무시)으로 거르고 골라 사용위치 보기. 검증완료: 바인딩 통과, ORCA 브라우저에서 노임 9개 → 「보 통」 1개 → 보통인부 사용위치 11곳.
- [x] 인쇄양식 불러오기·저장하기(원본 mnuPrintFormatLoad·Save 0x10ed318·0x10ed000 — spec_pc §3) — .pfot(인쇄정보표 MIDAS 이진) 읽기·쓰기 `print-format.cjs`(설명 BLOB·빈 칸 표지까지 보존, 원본 파일 그대로 다시 쓰면 바이트 같음). 불러오면 공사 인쇄표를 그 값으로, 저장은 지금 인쇄표를 원본 설치 main.pfot 필드 설명자 위에(`EST_PFOT_TEMPLATE`). .gfot(cxGrid 열 배치)는 웹 격자와 호환되지 않아 하지 않음.
diff --git a/tools/est-test/export-estx.cjs b/tools/est-test/export-estx.cjs
index 8c8a11e78..3631e4b29 100644
--- a/tools/est-test/export-estx.cjs
+++ b/tools/est-test/export-estx.cjs
@@ -192,6 +192,7 @@ function exportEstx(project) {
DollarCostCut: ["TMachOption", "DollarCostCut"],
JDLCalcMethod: ["TCommonOption", "JDLCalcMethod"],
OldRecalcMethod: ["TChangeOption", "OldRecalcMethod"],
+ WorkMode: ["TCommonOption", "CurrentWorkMode"],
};
const optionChanges = {};
const setOption = (cls, name, data) => {
diff --git a/tools/est-test/import-estx.cjs b/tools/est-test/import-estx.cjs
index 4aae2525a..9db77d953 100644
--- a/tools/est-test/import-estx.cjs
+++ b/tools/est-test/import-estx.cjs
@@ -350,6 +350,7 @@ function importEstx(buffer, name = "가져온 내역서") {
DollarCostCut: props.TMachOption?.DollarCostCut || false,
JDLCalcMethod: props.TCommonOption?.JDLCalcMethod || false,
OldRecalcMethod: props.TChangeOption?.OldRecalcMethod || 0,
+ WorkMode: props.TCommonOption?.CurrentWorkMode ?? 1,
};
const quantitySheets = [];
let printCatalog = [];
diff --git a/tools/est-test/index.html b/tools/est-test/index.html
index 499c9d7cc..0f550c118 100644
--- a/tools/est-test/index.html
+++ b/tools/est-test/index.html
@@ -26,6 +26,7 @@
+
@@ -252,6 +253,7 @@
>
+