Files
Aislo/resources/tester/test_b09_hourly_wage.py
T
eomsangdonandClaude Opus 5 fd30227b73 fix(b09): 조종원 시간당 노임을 식 좌→우 순차 + 절사로 — 골든셋 시험 첫 벌
- 계수로 미리 접으면 267,360 → 55,699 로 1원 틀림 — 식 1/8*16/12*25/20 을 차례로 풀어 55,700
- 중기 호표 운전원 줄은 시간당 노임 제목(#시간) × 인수로 부름(STmate 운전원 1 × 55,700 모양)
- 골든셋 시험 test_b09_golden_stmate — 실무 6건 환율및기초자료 시간당 칸 전수 재현
  (다섯 건 원 미만 절사 · 2025 울진 소광 0.1원 미만 절사 — 자리는 설정값)
- 28자리 끝 반올림 차례만 다른 합 비교 시험을 허용 오차로

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
2026-09-13 23:13:20 +09:00

70 lines
2.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""조종원 시간당 노임 — 식 좌→우 순차 + 원 미만 절사 (2026-09-13, PLAN 6장 · 명세 7장).
기준점 — STmate 분석 18번 §2.1: 6건 × 3직종 18/18 이 좌→우일 때만 일치(계수 선계산 14/18).
건설기계운전사 267,360 → 55,700 · 화물차운전사 226,709 → 47,231 ·
일반기계운전사 161,142 → 33,571
"""
from __future__ import annotations
from decimal import Decimal
from functools import lru_cache
import pytest
from B09_Estimation.B09_Estimation_MachineCost import (
OPERATOR_ALLOWANCE_FACTOR,
OPERATOR_WAGE_FORMULA,
hourly_operator_wage,
)
from B09_Estimation.B09_Estimation_UnitPrice import HOURLY_WAGE_SUFFIX, build_unit_prices
@pytest.mark.parametrize(
("daily", "hourly"),
[(267360, 55700), (226709, 47231), (161142, 33571)],
)
def test_좌에서_우로_차례로_풀고_원_미만_절사(daily: int, hourly: int) -> None:
assert OPERATOR_WAGE_FORMULA == "1/8*16/12*25/20"
assert hourly_operator_wage(Decimal(daily)) == Decimal(hourly)
def test_계수를_미리_접으면_1원_틀린다() -> None:
"""회귀 막이 — 접은 계수 곱은 55,699.99… 라 절사하면 55,699(STmate 55,700)."""
folded = (Decimal(267360) / 8 * OPERATOR_ALLOWANCE_FACTOR).to_integral_value(
rounding="ROUND_FLOOR"
)
assert folded == Decimal(55699) # 종전 코드 — 계수 1.666…6 이 끝자리에서 잘려 55,699.99…
assert hourly_operator_wage(Decimal(267360), digits=None) == Decimal(55700)
@lru_cache(maxsize=1)
def _build():
return build_unit_prices()
def test_중기_호표의_운전원은_시간당_노임_제목을_1시간분_부른다() -> None:
book = _build().book
hourly = [code for code in book.titles if code.endswith(HOURLY_WAGE_SUFFIX)]
assert hourly, "조종원 시간당 제목이 한 벌도 안 섬"
for code in hourly:
daily = (
book.titles[code.removesuffix(HOURLY_WAGE_SUFFIX)].adopted_price()
if code.removesuffix(HOURLY_WAGE_SUFFIX) in book.titles
else None
)
price = book.titles[code].adopted_price()
assert price == price.to_integral_value() # 원 미만 절사
if daily is not None:
assert price == hourly_operator_wage(daily)
# X 층 운전원 줄은 계수 접은 수량이 아니라 시간당 제목 × 인수.
operator_rows = [
detail
for details in book.details.values()
for detail in details
if detail.ref_code.endswith(HOURLY_WAGE_SUFFIX)
]
assert operator_rows and all(
d.quantity == d.quantity.to_integral_value() for d in operator_rows
)