fix(751-1): 원화 꼴 흠 — M01 · M02 · 서버 글 — 공용 꼴 갈음 · 율 「4.0」 · 중간 값 · 마법사 콤마 · 서고 금액
- 파이썬 짝을 common_util/common_util_money.py 로 옮김(TS 와 같은 이름 · 서버 어디서나 불러옴) - 시험 계산: 율 글자 「4.0 %」 → 숫자 4(서버 _pct) · 중간 값 경비 · 공구손료 등 비목 이름은 1,000 미만도 돈 꼴(870.2455 → 870) - 기초 편집 단가 = 공용 단가 꼴 · 금액 = 소수 1 · 서고 기준 금액 · 구조물 조합 일위대가 금액 = 공용 정수 꼴(124,419.85 → 124,420) - 마법사(확인 · 고르기 · 별칭 장부 · 엑셀 · 우리 금액): 콤마 없음 · 소수 셋 기본 · 부동소수 꼬리 걷음 · 품 비교 꼬리표 지수 꼴(1.235e+05) 걷음 - 다시 잇기 · 붙여넣기 대조 · 찾아 넣기 금액 열 끝 0 없음(22.9 원이 23 으로 숨지 않음) · 흐름 로직 텍스트 수식 비목 소계 정수 - 낡은 시험 고침: test_m02_hopyo_screen 품 비교 보통인부 0.0364 → 0.03636(수량 꼴 유효숫자 넷 규칙으로 파이썬 · TS 통일) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""숫자 글 꼴 한 벌 — 금액 · 단가 · 수량 · 율 · 빈 값 · 음수. 셈 값은 그대로, 보이는 글만 만듦(반올림 = 절반 올림).
|
||||
|
||||
TS 짝: `common_util/common_util_money.ts` — 두 파일은 같은 글을 냄(거울 시험 `test_588_2_money_fmt.py`).
|
||||
fmt_money 원 단위 정수 (계 · 소계 · 합계 · 내역 금액)
|
||||
fmt_line_money 최대 소수 1 · 끝 0 뗌 (일위대가 줄 금액 · 산근 근거 줄)
|
||||
fmt_price 단가 — 200 원 미만 = 유효숫자 넷 · 그 밖 = 최대 소수 3 · 끝 0 뗌
|
||||
fmt 수량 · 율 · 품 — 소수 넷째 자리 · 유효숫자 넷 중 많은 쪽 · 끝 0 뗌
|
||||
값이 숫자가 아니면 빈 값 = 「」 · 그 밖 = str.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import ROUND_HALF_UP, Decimal, localcontext
|
||||
|
||||
|
||||
def _num(value) -> Decimal | None:
|
||||
"""숫자 → Decimal (불리언 · NaN · 무한대 · 숫자 아님 = None)."""
|
||||
if isinstance(value, bool):
|
||||
return None
|
||||
if isinstance(value, float):
|
||||
value = repr(value) # 짧은 글 → 자바스크립트 숫자와 같은 자리
|
||||
elif not isinstance(value, (Decimal, int)):
|
||||
return None
|
||||
out = Decimal(value)
|
||||
return out if out.is_finite() else None
|
||||
|
||||
|
||||
def _other(value) -> str:
|
||||
return "" if value is None else str(value)
|
||||
|
||||
|
||||
def _fixed(value: Decimal, places: int) -> str:
|
||||
"""소수 `places` 자리까지 절반 올림 · 끝 0 뗌 · 천 단위 쉼표."""
|
||||
with localcontext() as ctx:
|
||||
ctx.prec = 80
|
||||
cut = value.quantize(Decimal(1).scaleb(-min(places, 20)), rounding=ROUND_HALF_UP)
|
||||
sign, digits = ("-", -cut) if cut < 0 else ("", cut)
|
||||
whole, _, rest = f"{digits:f}".partition(".")
|
||||
rest = rest.rstrip("0")
|
||||
return sign + f"{int(whole):,}" + (f".{rest}" if rest else "")
|
||||
|
||||
|
||||
def fmt(value) -> str:
|
||||
d = _num(value)
|
||||
if d is None:
|
||||
return _other(value)
|
||||
return _fixed(d, 4 if not d else max(4, 3 - d.adjusted()))
|
||||
|
||||
|
||||
def fmt_money(value) -> str:
|
||||
d = _num(value)
|
||||
return _other(value) if d is None else _fixed(d, 0)
|
||||
|
||||
|
||||
def fmt_line_money(value) -> str:
|
||||
d = _num(value)
|
||||
return _other(value) if d is None else _fixed(d, 1)
|
||||
|
||||
|
||||
def fmt_price(value) -> str:
|
||||
d = _num(value)
|
||||
if d is None:
|
||||
return _other(value)
|
||||
return fmt(d) if abs(d) < 200 else _fixed(d, 3)
|
||||
@@ -1,4 +1,4 @@
|
||||
"""원화 꼴 한 벌 거울 시험 — `master_fmt.py`(파이썬) ↔ `common_util_money.ts`(TS · Node) 가 같은 글.
|
||||
"""원화 꼴 한 벌 거울 시험 — `common_util_money.py`(파이썬) ↔ `common_util_money.ts`(TS · Node) 가 같은 글.
|
||||
|
||||
CLAUDE.md 5장 ① 짝. 값은 숫자 글(`num`) · 숫자 아닌 글(`text`) · 빈 값(None).
|
||||
"""
|
||||
@@ -10,9 +10,9 @@ import sys
|
||||
from decimal import Decimal
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.join(HERE, "..", "master_data", "scripts"))
|
||||
sys.path.insert(0, os.path.join(HERE, "..", ".."))
|
||||
|
||||
import master_fmt as mf # noqa: E402
|
||||
from common_util import common_util_money as mf # noqa: E402
|
||||
|
||||
NUMS = [
|
||||
"0", "1", "2.5", "-1234.5", "1.00005", "0.12345", "0.00167", "22.9", "1846.39",
|
||||
|
||||
@@ -413,13 +413,13 @@ def test_실물_응답_대역_확인_창():
|
||||
assert remicon["상태"] == "맞음" and remicon["checked"] and remicon["checkable"]
|
||||
assert (
|
||||
remicon["compare"]
|
||||
== "콘크리트공 0.1091 → 0.1091 ✓ · 보통인부 0.0364 → 0.0364 ✓ · 굴착기 0.29 → 0.2909 ✓"
|
||||
== "콘크리트공 0.1091 → 0.1091 ✓ · 보통인부 0.03636 → 0.03636 ✓ · 굴착기 0.29 → 0.2909 ✓"
|
||||
)
|
||||
assert (
|
||||
remicon["inputs"]
|
||||
== "타설방법=장비사용타설(규격), 구조물=철근구조물(규격), 소량감률=50(블록)"
|
||||
)
|
||||
assert remicon["qty"] == "콘크리트공 0.1091 · 보통인부 0.0364 · 굴착기 0.29hr"
|
||||
assert remicon["qty"] == "콘크리트공 0.1091 · 보통인부 0.03636 · 굴착기 0.29hr"
|
||||
assert remicon["cands"][0][1] == "맞음" and remicon["cands"][0][2].startswith("조항 건설품셈")
|
||||
rebar = by["철근가공조립(현장)"]
|
||||
assert rebar["상태"] == "다른 점" and not rebar["checked"] and rebar["checkable"]
|
||||
|
||||
Reference in New Issue
Block a user