- B09_Estimation_Edits: 고친 값 한 벌 — 기본 조립(cached_build) 복사본에 얹음(캐시 키에 고친 값) · 기본 벌은 그대로(골든셋 무관)
· 얹지 못한 값은 edit_skipped 로 남김 · 값 없는 슬롯은 받지 않음(422 + 까닭)
- 새 라우터 B09_Estimation_Router_Edits(GET/PUT /estimation/edits) — Router.py 는 _build_for 가 고친 값을 얹게만 바꿈
- 화면: 줄마다 채택 슬롯 고르개 · 일괄(변동없음/1~5 단가/최소단가) · 고친 줄 「사용자」 + ↺(지우면 계산값으로)
- 곁: 사용자 식 셈(B09_Estimation_Expression — ROUND·ROUNDDOWN·INT·SQRT, eval 없음)과 본표 편집 칸(UI_DetailEdit)을 먼저 둠 — 서버 편집 문이 서기 전까지 잠자 있음
- 검증: 시험 1656 통과 · ORCA 채택 저장 → 「사용자」·↺ → ↺ 뒤 고친 값 {} 로 복구 · 값 없는 슬롯 422 「경유: 1번 원천에 값이 없어」
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
25 lines
1021 B
Python
25 lines
1021 B
Python
"""B09 사용자 식 셈 — Q 식 편집 칸이 받는 식(PLAN 12장 2차 ③ · STmate `wM_Edit_San` 함수)."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from decimal import Decimal
|
||
|
||
import pytest
|
||
|
||
from B09_Estimation.B09_Estimation_Expression import ExpressionError, evaluate
|
||
|
||
|
||
def test_실무_Q_식을_그대로_센다() -> None:
|
||
# 18번 §2.2 — 3600 × q 0.2 × K 0.7 × f 0.85 × E 0.55 ÷ Cm 15 = 15.708
|
||
assert evaluate("3600*0.2*0.7*ROUND(1/1.175,2)*0.55/15") == Decimal("15.708")
|
||
# 울진 대흥 제15호표 되메우기 Q 68.04
|
||
assert evaluate("ROUND(3600*0.7*0.9*(1/1.25)*0.75/20, 2)") == Decimal("68.04")
|
||
assert evaluate("INT(7.9) + SQRT(16) - ROUNDDOWN(1.239, 2)") == Decimal("9.77")
|
||
assert evaluate("60 ÷ 4 × 0.45 × 0.8") == Decimal("5.40")
|
||
|
||
|
||
@pytest.mark.parametrize("text", ["__import__('os')", "a+1", "1/0", "2**3", "", "ROUND(1)"])
|
||
def test_모르는_글·0_나누기·빈_식은_거절한다(text: str) -> None:
|
||
with pytest.raises(ExpressionError):
|
||
evaluate(text)
|