feat(stmate-test): 3차 화면·데이터 마무리 — 보호표시 · 공종번호 · 직종·노임 · 제비율표 편집 · 차수 칸 저장 · 계약 변환등록 = 울진 계약 STC · 장부 87.6%

- 시험 615 통과 · 브라우저 화면 13개·메뉴 90개 오류 0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-13 21:00:14 +09:00
co-authored by Claude Opus 5.5
parent e8b76dd65b
commit ffc2401870
36 changed files with 1907 additions and 78 deletions
+23 -1
View File
@@ -17,6 +17,7 @@
from __future__ import annotations
import pathlib
import re
from dbf_rw import DbfTable
from fastapi import APIRouter, HTTPException
@@ -133,12 +134,33 @@ def _boq_codes(files: dict, req: dict, log: list) -> None:
files[name] = bt.to_bytes()
def _rates(files: dict, req: dict, log: list) -> None:
"""제비율표 수정(wM_KAN_RATE) — rate_tables{표 이름: 행[_recno · RATE_n 칸]} 중 바뀐 칸만."""
for name, rows in (req.get("rate_tables") or {}).items():
name = str(name).upper()
if not re.fullmatch(r"RATE[_A-Z0-9]*\.DBF", name) or name not in files:
continue
tbl = DbfTable(files[name])
for r in rows or []:
i = int(r.get("_recno", -1)) if str(r.get("_recno", "")).isdigit() else -1
if not 0 <= i < len(tbl):
continue
for k, v in r.items():
if k.startswith("_") or k.endswith("_HEX") or tbl.fields.get(k) is None:
continue
if tbl.fields[k].type in ("N", "F"):
_put(tbl, i, k, v, log, name)
if tbl.dirty:
files[name] = tbl.to_bytes()
def apply_struct(files: dict[str, bytes], req: dict) -> tuple[dict[str, bytes], list]:
"""구조 손질만 — 새 files 와 바뀐 목록(코드 칸·끼움·지움)."""
"""구조 손질만 — 새 files 와 바뀐 목록(코드 칸·끼움·지움 · 제비율표 칸)."""
out = dict(files)
log: list = []
_costn(out, req, log)
_boq_codes(out, req, log)
_rates(out, req, log)
return out, log