From b9847c7db86ba0941a02fade853572feef65bf80 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 14 Nov 2026 17:43:12 +0900 Subject: [PATCH] =?UTF-8?q?refactor(stmate-test):=20=EC=9B=90=EB=B3=B8?= =?UTF-8?q?=EC=97=90=20=EC=97=86=EB=8A=94=20=E3=80=8C=EC=9E=90=EC=9E=AC=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=EC=9E=90=EB=A3=8C=20=EC=97=91=EC=85=80=20?= =?UTF-8?q?=EB=82=B4=EB=B3=B4=EB=82=B4=EA=B8=B0=C2=B7=EB=B6=88=EB=9F=AC?= =?UTF-8?q?=EC=98=A4=EA=B8=B0=E3=80=8D=20=EA=B1=B7=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 원본 wM_JajeXLS = 재료비 수량집계표 엑셀 내보내기 한 방향뿐(REA 37 · TWM_JAJEXLS 0x5658bc) — 추측으로 만든 자재 기준자료 왕복 메뉴·API·시험 삭제 - 남김: 「재료비 수량집계표를 엑셀파일로 만들기」(conv_jaje · scr_jaje) - 낡은 시험 test_jaje_xlsx_roundtrip_and_edit · conv_api 의 jaje 왕복 삭제 — 원본에 없는 기능 Co-Authored-By: Claude Opus 5.5 --- resources/tester/test_stmate_conv_api.py | 7 +-- resources/tester/test_stmate_conv_xls.py | 23 --------- tools/stmate-test/PLAN.md | 2 +- tools/stmate-test/api_conv.py | 21 -------- tools/stmate-test/conv_xls_out.py | 61 +----------------------- tools/stmate-test/scr_conv.js | 23 --------- 6 files changed, 3 insertions(+), 134 deletions(-) diff --git a/resources/tester/test_stmate_conv_api.py b/resources/tester/test_stmate_conv_api.py index f50758551..f4db6b3c6 100644 --- a/resources/tester/test_stmate_conv_api.py +++ b/resources/tester/test_stmate_conv_api.py @@ -56,7 +56,7 @@ def test_boq_xlsx_download_reimports(work): assert Source(r["saved_stc"]).files["PRJLST.DBF"] == Source(str(STC)).files["PRJLST.DBF"] -def test_code_and_split_and_jaje_api(work): +def test_code_and_split_api(work): r = A.api_code_change( A.CodeChgReq(source_path=str(STC), mapping={"M00001": "M99991"}, target_folder_name="cc") ) @@ -68,10 +68,5 @@ def test_code_and_split_and_jaje_api(work): assert p.get(0, "K_ORD") == "1" and p.get(0, "TCOST2") == p.get(0, "TCOST1") == _prj( str(STC) ).get(0, "TCOST1") - x = A.api_jaje_xlsx(A.SrcReq(source_path=str(STC))).body - r3 = A.api_jaje_import( - A.JajeImportReq(source_path=str(STC), xlsx=A.FileIn(b64=base64.b64encode(x).decode())) - ) - assert r3["count"] == 0 with pytest.raises(Exception): A.api_jb_read(A.JbReq(path=str(STC))) # 설치 폴더 JB_* 만 diff --git a/resources/tester/test_stmate_conv_xls.py b/resources/tester/test_stmate_conv_xls.py index 734f85cba..2472ef650 100644 --- a/resources/tester/test_stmate_conv_xls.py +++ b/resources/tester/test_stmate_conv_xls.py @@ -19,15 +19,12 @@ from conv_xls_apply import import_boq, register # noqa: E402 from conv_xls_boq import boq_from_xlsx, fill_from_costn, load_book, read_initial # noqa: E402 from conv_xls_out import ( # noqa: E402 export_boq_xlsx, - export_jaje_xlsx, - import_jaje_xlsx, ) from conv_xls_res import comp_from_san, comp_from_sheets, costn_from_lists, memos_from_sheet # noqa: E402 from dbf_rw import DbfTable # noqa: E402 from smt_parser import extract_costn_memos, parse_dbf_bytes # noqa: E402 from stc_project import write_output # noqa: E402 from stc_read import Source # noqa: E402 -from stc_save import apply_save # noqa: E402 DOCS = ROOT / "resources/knowledge/original/실무문서" SO = ( @@ -196,26 +193,6 @@ def test_own_boq_xlsx_roundtrip(stc): assert not bad, f"{tb} {bad[:5]}" -def test_jaje_xlsx_roundtrip_and_edit(tmp_path): - import openpyxl - - files, _xl, _tb = _pair("봉화") - x = export_jaje_xlsx(files) - assert import_jaje_xlsx(files, x) == [] - p = tmp_path / "j.xlsx" - p.write_bytes(x) - wb = openpyxl.load_workbook(p) - ws = wb.worksheets[0] - code = ws.cell(2, 1).value - old = float(ws.cell(2, 10).value or 0) - ws.cell(2, 10).value = old + 100 - wb.save(p) - ups = import_jaje_xlsx(files, p.read_bytes()) - assert ups == [{"CODE": code, "AMT_61": old + 100, "MAMT1": old + 100, "TAMT1": old + 100}] - out, log = apply_save(files, {"costn_updates": ups}) - assert {x["field"] for x in log if x["table"] == "COSTN.DBF"} <= {"AMT_61", "MAMT1", "TAMT1"} - - # 영월 BDQTY 는 복호 칸이 어긋남(UNIT1 깨짐 · TPRPT 전부 4) — 비교 제외 @pytest.mark.parametrize("name", ["봉화", "대흥", "울진", "영덕변경"]) def test_comp_rows_follow_xls_2_bdrec(name): diff --git a/tools/stmate-test/PLAN.md b/tools/stmate-test/PLAN.md index 60b49b64e..5db345b06 100644 --- a/tools/stmate-test/PLAN.md +++ b/tools/stmate-test/PLAN.md @@ -212,7 +212,7 @@ - [x] F4-24 엑셀 → 내역 불러오기 — wM_From_XLS · 현재: 구현(conv_xls_boq · 원본 엑셀 5권 → STC 내역 행 전 칸 일치(test_stmate_conv_xls)) - [x] F4-25 엑셀 역등록(CONV_XLS_2_ST·INITIAL)·엑셀 → BDQTY — 24번 §3 · 현재: 구현(REA 37 — ST_P_XLS 0x5f1078 PRPT「속성」·PRIN「대상」·PROUT「저장」 = PR/RR 줄만 · 원본 BDQTY 대조 4건 일치) - [x] F4-30 BDQTY.DBF 구성표 복호 읽기 — STC_난독화_상태 · 현재: 구현(bdqty.py 자리별 회전·더하기 표 283자리 · 사용자 승인 · 글자 칸 제외) -- [x] F4-26 자재 기준자료 XLS 입출력 — wM_JajeXLS · 현재: 구현(REA 37 — 원본 = 재료비 수량집계표 엑셀 내보내기만(TWM_JAJEXLS) · 주요건설자재현황 시트 · 웹 들여오기는 원본에 없음 · 파일 이름 기본값 미확인) +- [x] F4-26 자재 기준자료 XLS 입출력 — wM_JajeXLS · 현재: 구현(REA 37 — 원본 = 재료비 수량집계표 엑셀 내보내기만(TWM_JAJEXLS) · 주요건설자재현황 시트(conv_jaje·scr_jaje) · 원본에 없는 「자재 기준자료 엑셀 내보내기·불러오기」 걷음 · 파일 이름 기본값 미확인) - [x] F4-27 기준 BOQ·코드 변경 엑셀 왕복 — 24번 §3 · ST_U_ChgCode · 현재: 구현(stc_codechg 내역 8표 엑셀 왕복 · 코드 변경 되돌리면 7건 원래 바이트) - [x] F4-28 구버전 → Win8 자료 변환 — ST_U_Convert ST_ConvToWin8 · 현재: 구현(REA 37 — 판 가리기(Chk_Data 0x459280) · 7.x/DOS COSTN·BDQTY·PRJLST·KONGJONG·BOQ·Start8x.Ini 대응 · B→X 조건 = 단위 X · 합성 자료 시험 · 간접비 이관·RATE·SYSINFO·IFORM 미확인(틀 유지)) - [x] F4-29 자동백업·자료 복원 — wM_D_Restore · wM_ST_Restore · 현재: 구현(api_file 자동 백업·복원) diff --git a/tools/stmate-test/api_conv.py b/tools/stmate-test/api_conv.py index 8202af606..5de054116 100644 --- a/tools/stmate-test/api_conv.py +++ b/tools/stmate-test/api_conv.py @@ -21,9 +21,7 @@ from conv_xls_apply import import_boq, register from conv_xls_out import ( export_boq_xlsx, export_code_xlsx, - export_jaje_xlsx, import_code_xlsx, - import_jaje_xlsx, ) from conv_xml import xml_to_project from conv_xml_cfg import apply_settings, options, validate @@ -118,11 +116,6 @@ class SrcReq(BaseModel): table: str = "" -class JajeImportReq(BaseModel): - source_path: str - xlsx: FileIn - - class CodeChgReq(BaseModel): source_path: str mapping: dict[str, str] = {} @@ -256,20 +249,6 @@ def api_boq_xlsx(req: SrcReq): return _xlsx(_guard(export_boq_xlsx, s.files, req.table), f"{s.path.stem}_기준BOQ.xlsx") -@router.post("/api/conv/jaje-xlsx") -def api_jaje_xlsx(req: SrcReq): - s = _src(req.source_path) - return _xlsx(_guard(export_jaje_xlsx, s.files), f"{s.path.stem}_자재기준자료.xlsx") - - -@router.post("/api/conv/jaje-import") -def api_jaje_import(req: JajeImportReq): - """자재 기준자료 엑셀 → costn_updates(바뀐 칸만) — 화면이 /api/save 로 넘김.""" - s = _src(req.source_path) - ups = _guard(import_jaje_xlsx, s.files, _blob(**req.xlsx.model_dump())) - return {"costn_updates": ups, "count": len(ups)} - - @router.post("/api/conv/code-xlsx") def api_code_xlsx(req: SrcReq): s = _src(req.source_path) diff --git a/tools/stmate-test/conv_xls_out.py b/tools/stmate-test/conv_xls_out.py index e380ec5b2..1ef307995 100644 --- a/tools/stmate-test/conv_xls_out.py +++ b/tools/stmate-test/conv_xls_out.py @@ -17,7 +17,7 @@ import io import re from conv_xls_boq import COLS, INITIAL, LEVEL_NAME, _numv, load_book -from smt_parser import parse_dbf_bytes, parse_ini_bytes +from smt_parser import parse_dbf_bytes from stc_save import STRUCT_RE, pick_boq_table BOQ_HEAD = [ @@ -146,63 +146,6 @@ def export_boq_xlsx(files: dict, table: str = "") -> bytes: return buf.getvalue() -# ── 자재 기준자료 ── -JAJE_HEAD = ["코드", "명 칭", "규 격", "단위"] - - -def export_jaje_xlsx(files: dict) -> bytes: - """COSTN M 코드 → 자재 기준자료 xlsx(출처 5칸 · 적용 단가).""" - ini = parse_ini_bytes(files.get("START8X.INI") or files.get("STINI.MEM") or b"") - src = [ini.get(f"JMOK{i}", f"출처{i}") for i in range(1, 6)] - wb = _wb() - ws = wb.active - ws.title = "자재기준자료" - ws.append(JAJE_HEAD + src + ["적용 단가", "BQCODE", "JDCODE"]) - for r in parse_dbf_bytes(files["COSTN.DBF"])[1]: - if not r["CODE"].strip().startswith("M"): - continue - ws.append( - [r["CODE"].strip(), r["NAME"], r["SIZE"], r["UNIT"].strip()] - + [_numv(r.get(f"AMT_{i}1")) for i in range(1, 7)] - + [r.get("BQCODE", "").strip(), r.get("JDCODE", "").strip()] - ) - buf = io.BytesIO() - wb.save(buf) - return buf.getvalue() - - -def import_jaje_xlsx(files: dict, src) -> list[dict]: - """자재 기준자료 xlsx → 바뀐 칸만 담은 costn_updates(없는 코드는 새 행).""" - ws = load_book(src).worksheets[0] - cur = {r["CODE"].strip(): r for r in parse_dbf_bytes(files["COSTN.DBF"])[1]} - head = [str(v or "").strip() for v in next(ws.iter_rows(max_row=1, values_only=True))] - fields = ( - ["CODE", "NAME", "SIZE", "UNIT"] + [f"AMT_{i}1" for i in range(1, 7)] + ["BQCODE", "JDCODE"] - ) - out = [] - for r in ws.iter_rows(min_row=2, values_only=True): - if not r or not r[0]: - continue - vals = dict(zip(fields, r[: len(fields)])) - code = str(vals["CODE"]).strip() - old = cur.get(code) - upd = {"CODE": code} - for k, v in vals.items(): - if k == "CODE" or k not in fields[: len(head)]: - continue - o = old.get(k) if old else None - if k.startswith("AMT_"): - if old is None or abs(_numv(o) - _numv(v)) > 1e-9: - upd[k] = _numv(v) - elif old is None or str(o or "").strip() != str(v or "").strip(): - upd[k] = "" if v is None else str(v) - if "AMT_61" in upd: # 적용 단가 = 1차 재료비 단가 - upd["MAMT1"] = upd["TAMT1"] = upd["AMT_61"] - if len(upd) > 1: - out.append(upd) - return out - - # ── 코드 변경표 ── def export_code_xlsx(files: dict) -> bytes: wb = _wb() @@ -234,8 +177,6 @@ def level_label(code: str) -> str: __all__ = [ "INITIAL", "export_boq_xlsx", - "export_jaje_xlsx", - "import_jaje_xlsx", "export_code_xlsx", "import_code_xlsx", "level_label", diff --git a/tools/stmate-test/scr_conv.js b/tools/stmate-test/scr_conv.js index 4a9137acf..028039a55 100644 --- a/tools/stmate-test/scr_conv.js +++ b/tools/stmate-test/scr_conv.js @@ -152,27 +152,6 @@ `${pname(ctx)}_기준BOQ.xlsx`, ); }, - async jajeXlsx(ctx) { - download( - await req("/api/conv/jaje-xlsx", { source_path: curPath(ctx) }, true), - `${pname(ctx)}_자재기준자료.xlsx`, - ); - }, - async jajeImport(ctx) { - const f = await pickFile(".xlsx"); - const r = await req("/api/conv/jaje-import", { - source_path: curPath(ctx), - xlsx: { b64: f.b64 }, - }); - const rows = ctx.dbfData.costn_rows || (ctx.dbfData.costn_rows = []); - for (const u of r.costn_updates) { - const row = rows.find((x) => String(x.CODE).trim() === u.CODE); - if (row) Object.assign(row, u); - else rows.push(Object.assign({}, u)); - } - app().cascadeAndRender && app().cascadeAndRender(); - alert(`[자재 기준자료 불러오기] 바뀐 자재 ${r.count}건 — [저장]으로 반영`); - }, async codeXlsx(ctx) { download( await req("/api/conv/code-xlsx", { source_path: curPath(ctx) }, true), @@ -236,8 +215,6 @@ ["Act_ConvXlsBoq", "엑셀 → 내역 불러오기 (wM_From_XLS)", "xlsBoq"], ["Act_ConvXlsRegister", "엑셀 역등록 — 새 공사 (CONV_XLS_2_ST)", "xlsRegister"], ["Act_ConvBoqXlsx", "기준 BOQ 엑셀로 내보내기 (MK_BSCBOQ_EXL)", "boqXlsx"], - ["Act_ConvJajeXlsx", "자재 기준자료 엑셀로 내보내기 (wM_JajeXLS)", "jajeXlsx"], - ["Act_ConvJajeImport", "자재 기준자료 엑셀 불러오기 (wM_JajeXLS)", "jajeImport"], ["Act_ConvCodeXlsx", "코드 변경표 엑셀로 내보내기 (ST_U_ChgCode)", "codeXlsx"], ["Act_ConvCodeChange", "코드 일괄 변경 (ST_U_ChgCode)", "codeChange"], ["Act_ConvSplitChange", "분리형 변경 STC 만들기 — 차수 인계", "splitChange"],