Merge remote-tracking branches 'origin/CODEX' and 'origin/sub_laptop_1' into main_laptop_1
This commit is contained in:
@@ -44,6 +44,10 @@ from B09_Estimation.B09_Estimation_UnitPrice import (
|
||||
|
||||
_ZERO = Decimal(0)
|
||||
|
||||
#: 총 절취량으로 셀 공종 — 9-3 토사깎기 · 9-4 암절취 · 9-5 발파암(인계 대응표 「흙깎기」 셋).
|
||||
#: ⚠ 판에 묶인 절 번호임(명세 17장) — 판이 바뀌면 대응표와 함께 고칠 것.
|
||||
CUT_CODE_PREFIXES = ("FP-09-03", "FP-09-04", "FP-09-05")
|
||||
|
||||
#: 자재 공급 구분이 안 갈린 값. B08 이 실제로 이 값을 보낸다(2026-09-08 실물 확인).
|
||||
#: **관급자재대에도, 도급 재료비에도 넣지 않는다** — 어느 쪽에 넣어도 총액이 틀린다.
|
||||
SUPPLY_UNKNOWN = "unknown"
|
||||
@@ -353,7 +357,6 @@ def _number_of(path: tuple[int, ...]) -> str:
|
||||
from B09_Estimation.B09_Estimation_BillOfQuantities_Rows import ( # noqa: E402
|
||||
_composite_row,
|
||||
_excluded_row,
|
||||
_haul_price_of,
|
||||
_leaf_row,
|
||||
_material_row,
|
||||
)
|
||||
@@ -413,6 +416,9 @@ def build_bill(
|
||||
|
||||
emitted: dict[str, str] = {} # 코드 → ITEM NO.
|
||||
counters: dict[str, int] = {} # 부모 ITEM NO. → 마지막 번호
|
||||
# 인계 줄 → 그 줄로 선 내역 줄. ⚠ 이름으로 되찾지 않음 — 도자운반 토사·리핑암처럼
|
||||
# 이름이 같은 줄이 둘이면 **첫 줄 단가**가 둘째에도 붙음(2026-09-13 축 C 조사 실결함).
|
||||
row_of: dict[int, BillRow] = {}
|
||||
|
||||
def next_number(parent_no: str) -> str:
|
||||
counters[parent_no] = counters.get(parent_no, 0) + 1
|
||||
@@ -442,12 +448,14 @@ def build_bill(
|
||||
# 물려주면 ITEM NO. 가 겹쳐 어느 줄인지 못 가린다. 머리글만 물려준다.
|
||||
item_no = next_number(parent_no)
|
||||
emitted.setdefault(leaf.code, item_no)
|
||||
result.rows.append(_leaf_row(item_no, leaf, item, unit_prices, result))
|
||||
row_of[id(item)] = _leaf_row(item_no, leaf, item, unit_prices, result)
|
||||
result.rows.append(row_of[id(item)])
|
||||
|
||||
# ── 1-2) 묶음 줄 ──────────────────────────────────────────────────────────
|
||||
for item in composites:
|
||||
counters[""] = counters.get("", 0) + 1
|
||||
result.rows.append(_composite_row(str(counters[""]), item, unit_prices, result))
|
||||
row_of[id(item)] = _composite_row(str(counters[""]), item, unit_prices, result)
|
||||
result.rows.append(row_of[id(item)])
|
||||
|
||||
# ── 2) 공종을 못 고른 줄 — 이름째 남긴다 ────────────────────────────────────
|
||||
for item in orphans:
|
||||
@@ -502,7 +510,8 @@ def build_bill(
|
||||
haul_rows = [
|
||||
{
|
||||
"equipment": item.haul_equipment,
|
||||
"unit_price_krw": _haul_price_of(item, result),
|
||||
# 그 줄에 실제로 붙은 단가. 안 선 줄은 0 — ㉡ 검사에 넘길 값이다.
|
||||
"unit_price_krw": getattr(row_of.get(id(item)), "unit_price_krw", None) or _ZERO,
|
||||
}
|
||||
for item in work_items
|
||||
if item.haul_equipment
|
||||
@@ -510,8 +519,14 @@ def build_bill(
|
||||
check_free_haul_not_priced(haul_rows=haul_rows)
|
||||
|
||||
# ㉡ 보조 — 운반토량 합이 총 절취량을 넘지 않는가(같은 흙을 두 번 세지 않았는가).
|
||||
# 절취 = **코드로** 가름(9-3 토사깎기 · 9-4 암절취 · 9-5 발파암 — 인계 대응표의 「흙깎기」 셋).
|
||||
# ⚠ 종전엔 줄 이름에 「깎기」·「절취」가 드는지로 셌음 — 이름이 바뀌면 검산이 조용히 멈춤.
|
||||
cut_total = sum(
|
||||
(item.quantity for item in work_items if "깎기" in item.name or "절취" in item.name),
|
||||
(
|
||||
item.quantity
|
||||
for item in work_items
|
||||
if str(item.work_item_code or "").startswith(CUT_CODE_PREFIXES)
|
||||
),
|
||||
_ZERO,
|
||||
)
|
||||
haul_total = sum((item.quantity for item in work_items if item.haul_equipment), _ZERO)
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
from B09_Estimation.B09_Estimation_BillOfQuantities import (
|
||||
SUPPLY_OWNER,
|
||||
SUPPLY_UNKNOWN,
|
||||
@@ -25,16 +23,6 @@ from B09_Estimation.B09_Estimation_BillOfQuantities import (
|
||||
from B09_Estimation.B09_Estimation_Rounding import OutputPlace, round_at
|
||||
from B09_Estimation.B09_Estimation_UnitPrice import UnitPriceBuild, find_variant_code
|
||||
|
||||
_ZERO = Decimal(0)
|
||||
|
||||
|
||||
def _haul_price_of(item: HandoffWorkItem, result: BillResult) -> Decimal:
|
||||
"""그 운반 줄에 실제로 붙은 단가. 안 붙었으면 0 — ㉡ 검사에 넘길 값이다."""
|
||||
for row in result.rows:
|
||||
if row.name == item.name and row.unit_price_krw is not None:
|
||||
return row.unit_price_krw
|
||||
return _ZERO
|
||||
|
||||
|
||||
def _composite_row(
|
||||
item_no: str,
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
# STmate 원가·수량 화면 구조 정리
|
||||
|
||||
작성일: 2026-09-13
|
||||
|
||||
근거: `30_원자료/ui_form_catalog.txt` · `30_원자료/print_form_map.txt` · `30_원자료/TWM_KANJUB.dfm` · `30_원자료/TPM_KAN_RATE.dfm` · `30_원자료/TWM_KAN_RATE.dfm` · `20_분석/22_UI_폼_분석.md` · `20_분석/19_진행률_장부.md` §3
|
||||
|
||||
## 1. 범위와 판정
|
||||
|
||||
- 카탈로그의 STmate 고유 폼 150개 가운데 원가·수량 입력, 기초단가, 일위대가·단가산출, 제잡비, 출력에 직접 참여하는 **48개 화면**을 추렸다.
|
||||
- `PM_*` 인쇄 폼은 실제 출력 시트와 이어지는 화면만 포함했다. 같은 출력의 세로·가로·수공 변형은 한 행에 묶었다.
|
||||
- 계약·실행·기성 화면은 설계 원가 흐름과 맞닿은 것만 `보조`로 표시했다.
|
||||
- 조림·방제 등 사업별 설계 화면, 유지보수·다운로드·복구·암호·정보창은 제외했다.
|
||||
- 화면 이름과 선택지는 카탈로그 원문을 유지했다. 기능 또는 출력 연결이 원자료에서 확인되지 않은 곳은 `미확인`이다.
|
||||
|
||||
## 2. 화면 갈래
|
||||
|
||||
### 2.1 내역 입력 — 11개
|
||||
|
||||
| 화면 | 무엇을 하나 | 주요 입력 칸·선택지 |
|
||||
|---|---|---|
|
||||
| `wBoq` | 공종목록에서 내역서로 항목을 넣는 중심 화면 | `cBox01/02`: `= 이상`~`====== 이상`; `RGrpTo`: `내역서 / 열린 보관함` |
|
||||
| `wKongJong` | 공종 목록 조회·선택 | `RdoLevel`: `소계(+=)`~`총대계(+======)`; `RdoIndex`: `코드번호 순 / 명칭 순 / 분류번호 순`; `RdoFilt`: `일위대가/산근전체 / 대공종 해당목록만` |
|
||||
| `wMBoq` | 주공종 집계와 계표시 확인 | `CBox01`: `1레벨(소계) 이상`~`6레벨(총대계) 이상` |
|
||||
| `wITNum` | 내역서 공종번호 자동입력 | 첫 글자 `공란 / . / ( / - / 추가입력`; 끝 글자 `공란 / . / )`; 번호형식 `가..하… / a..z…`; `Fmt_Typ`: `0 / 00 / 000` |
|
||||
| `wBoqRate` | 내역 항목에 할증율 적용 | `Rdo`: `전체(재,노,경 같은 비율) / 비목별(재,노,경 각각)` |
|
||||
| `wM_Rate` | 선택 범위의 수량·비목 금액 일괄 보정 | 범위 `내역서 전체 / 선택된 항목만`; 비목별 `절사 / 반올림`; `소수 0위`~`소수 4위값을 적용` |
|
||||
| `wExpnd` | 일위대가를 내역 행으로 풀기 | `RGrpToT`: `소계(=) / 계(==) / 합계(===)`; `절삭하여 / 반올림하여`; `소수 4위`~`소수 0위값을 적용` |
|
||||
| `wM_Expnd` | 일위대가와 단가산출근거를 내역에 풀어넣기 | 재료·노무·경비·일식 각각 `절사 / 반올림`, `소수 0위`~`소수 4위값을 적용` |
|
||||
| `wM_Expnd10` | 일위대가 풀기와 가산 비목 지정 | `입력안함 / 소계(=) / 계(==) / 합계(===)`; 입력 비목 `재료비 / 노무비 / 경비 / 전체`; 결과 비목 `재료비 / 노무비 / 경비 / 해당비목` |
|
||||
| `wM_From_XLS` | XLS 자료를 내역으로 불러오기 | 주요 입력 칸·선택지 `미확인` |
|
||||
| `wSameCode` | 내역의 동일 코드 처리 | 주요 입력 칸·선택지 `미확인` |
|
||||
|
||||
### 2.2 수량 — 2개
|
||||
|
||||
| 화면 | 무엇을 하나 | 주요 입력 칸·선택지 |
|
||||
|---|---|---|
|
||||
| `wQtyList` | 별도 수량산출서에서 코드별 수량을 조회·연결 | `cBoxCode`: `모든단가 / 노무비 / 재료비 / 경비 / 일위대가 / 중기비 / 단가산출 / 견적단가 / 대가,산근` |
|
||||
| `uM_ConQTY` | 수량 자료 변환·연결 | 구체적인 칸과 변환 방향 `미확인` |
|
||||
|
||||
### 2.3 일위대가·단가산출 — 7개
|
||||
|
||||
| 화면 | 무엇을 하나 | 주요 입력 칸·선택지 |
|
||||
|---|---|---|
|
||||
| `wM_Edit_iLWi` | 일위대가표 구성행 수정 | 노임계수 `초기값설정 개별적용 / 기본 / 기타 / 기타-1`~`기타-4 노임산출계수`; 저장비목 `각 해당비목 / 재료비 / 노무비 / 경비` |
|
||||
| `wM_Edit_San` | 단가산출근거와 Q식 수정 | 블록 `열블럭 / 행블럭 / 일반`; 함수 `∏ / INT / SIN / COS / TAN / SQRT / √ / ROUND / ROUNDDOWN …`; 연산 `/ / *`; 수량기호 `Q / A / T / N`; 저장비목 4택 |
|
||||
| `wM_Edit_EQ` | 표준중기공식 편집 | 삽입 `공식 / 공식+코드` |
|
||||
| `wM_Edit_USER` | 사용자 단가산출식 편집 | 주요 입력 칸·선택지 `미확인` |
|
||||
| `wM_iLWi_San` | 일위대가·단가산출 자료 조회/연결 | 구체적인 칸과 편집 범위 `미확인` |
|
||||
| `wM_Conv_A2W` | 실적단가를 일식단가로 변환등록 | `비목율(단가 => 노,재,경) / 조달청 발표단가 변환적용`; 연결 `공종코드↔분류번호 / 공종코드↔시설코드 / 명칭·규격·단위` |
|
||||
| `wM_Boq_ExecX` | 시간·단위당 중기 실행단가 계산·입력 | 절사 단위 `1원 / 10원 / 100원 / 1,000원 / 10,000원 / 100,000원`; 보정 `기본보정 / 노무비 / 재료비 / 경비` |
|
||||
|
||||
### 2.4 기준자료(단가·노임·중기) — 10개
|
||||
|
||||
| 화면 | 무엇을 하나 | 주요 입력 칸·선택지 |
|
||||
|---|---|---|
|
||||
| `wM_JabPum` | 기준 단가 목록 조회·선택 | 코드종류 `모든단가 / 노무비 / 재료비 / 경비 / 일위대가 / 중기비 / 단가산출 / 견적단가 / 대가,산근 / 그림코드`; 검색 `명칭,규격 / 산근내용` |
|
||||
| `wM_Edt_Hal` | 기준단가를 비율로 일괄 수정 | `절사 / 반올림`; 화면 안내상 적용단가 0원과 보호표시 항목은 제외 |
|
||||
| `wM_Edit_XRate` | 시간당 손료계수 수정 | `계 입력 / 각계수 입력` |
|
||||
| `wM_Boxa` | 단가목록 조회·비교 | `변동없음 / 1 단가`~`5 단가 / 최소단가`; 자재·공종 분류 필터 |
|
||||
| `wM_Box_H` | 불러간 단가 목록 확인 | `변동없음 / 1 단가`~`5 단가 / 최소단가` |
|
||||
| `wM_JDCode` | 공사원가 호환규정코드 검색·입력 | 기준 `명칭 / 명칭·규격 / 분류번호 / 시설코드 / 선택안함`; 검색 `명칭·규격·단위 / 호환규정코드 / 군급목록번호 / 중기품셈코드 / 시설코드번호`; 종류 `기본 / 자재 / 경비 / 중기 / 실적·기타` |
|
||||
| `wM_Mrg_BSC` | 새 기준자료로 프로젝트 자료 갱신 | 매칭 `호환규정코드 / 시설코드 / 명칭·규격·단위 / 호환+명+규+단 / 명칭·단위 / 설정안함`; 명칭·단가·조달코드별 복사처/복사원 적용 |
|
||||
| `wM_JajeXLS` | 자재 기준자료를 XLS로 내보내거나 불러오기 | 방향과 주요 선택지 `미확인` |
|
||||
| `PM_iLWi`·`PM_iLWi_S` | 일위대가표 인쇄 원장을 구성 | 인쇄 전용 폼; 입력 칸 `미확인` |
|
||||
| `PM_JOONG`·`PM_JOONG2`·`PM_JOONG_L` | 중기목록·시간당중기사용료 인쇄 원장을 구성 | 일반·변형·가로형 구분 외 입력 칸 `미확인` |
|
||||
|
||||
### 2.5 원가계산·제비율 — 6개
|
||||
|
||||
| 화면 | 무엇을 하나 | 주요 입력 칸·선택지 |
|
||||
|---|---|---|
|
||||
| `wM_KanJub` | 설계 제잡비를 계산하고 원가계산서를 만든다 | `원설계 / 1차변경 / 2차변경 / 3차변경`; `제잡비 원가계산방식 / 제잡비 표준시장방식`; 간접비·총공사비 절사 단위; `당초/변경 대비인쇄 / 변경분만 인쇄` |
|
||||
| `wM_KAN_RATE` | 제잡비 요율표를 조회·수정·저장·출력 | 상단 `수정 / 취소 / 저장 / 출력 / 종료 / 불러오기`; 요율표 선택 콤보; 실제 탭은 DFM §4 참조 |
|
||||
| `PM_KAN_RATE` | 제잡비 요율표 인쇄 | 공사규모 구간별 기초액·요율, 일반관리비 등 출력; 입력 화면 아님 |
|
||||
| `wM_GetAMT` | 내역에서 잡비 계산 기초금액을 불러온다 | `모두보기 / 소계(+=) / 계(+==) / 합계(+===) / 총계(+====) / 총합계(+=====)` |
|
||||
| `wM_KanJub_K` | 기성 제잡비 계산 | 집계수준 `소계`~`총합계 이상`; 부가세 `(0) 직접입력 / (1) 공급가액의 10% / (2) 재료비의 10% / (3) 재료비+산출경비의 10%`; 절사 단위 |
|
||||
| `PM_Won_A`·`PM_Won_A_C`·`PM_Won_A_L` | 공사원가계산서 출력 원장을 구성 | 일반·변경·가로형 구분 외 입력 칸 `미확인` |
|
||||
|
||||
### 2.6 인쇄·출력 — 7개
|
||||
|
||||
| 화면 | 무엇을 하나 | 주요 입력 칸·선택지 |
|
||||
|---|---|---|
|
||||
| `PM_Prt` | 전체 인쇄 메뉴와 출력 모양 설정 | 글꼴 `굴림체 / 궁서체 / 바탕체 / 돋움체`; 코드·호표·분류번호 등 인쇄 필드; `수량/단위 / 단위/수량 / 표준`; `일반 / 토개공 / 수자원공사`; `세로 / 가로`; `일반 / 산근` |
|
||||
| `PM_Prn_Ord` | 보고서 인쇄순서 지정 | `당초 설계 / 변경 설계 / 분할 설계 / 실적 공사 / 할증 내역 / 견적 내역 / 계약 내역 / 실행 예산 / 기성 내역 / 설계 변경 / 굴착·복구 / 굴착 변경` |
|
||||
| `PM_Sel_St` | 인쇄할 공종과 집계수준 선택 | `소계(+=) 이상`~`총합계(+=====)`; 방향 `아래로 / 위로` |
|
||||
| `wM_Sel_Prn` | 선택 영역·설계차수·표준시장단가 보정 후 인쇄 | `당초설계 / 변경설계 / 분할설계`; `7레벨공종이하 내역전체 / 해당레벨`; 비노무비 처리 3택; 노무비 끝전 보정 3택; `1차변경`~`8차변경` |
|
||||
| `PM_Nae*` 계열 | 총괄·설계·분할·관급·견적·계약 내역서 출력 | 일반·가로·변경·계약 등 변형; 세부 입력 칸 `미확인` |
|
||||
| `PM_Col_Dan*`·`PM_Col_X*` | 재료·노무·경비·중기·일위·산근 수량금액 집계표 출력 | 일반·가로·X 변형; 세부 입력 칸 `미확인` |
|
||||
| `PM_SanMok*`·`PM_Dan*` | 단가 목록·단가대비·단가산출 목록 출력 | 일반·가로·인쇄 변형; 세부 입력 칸 `미확인` |
|
||||
|
||||
### 2.7 설정 — 5개
|
||||
|
||||
| 화면 | 무엇을 하나 | 주요 입력 칸·선택지 |
|
||||
|---|---|---|
|
||||
| `wM_Set_Sys` | 계산 초기값과 표시 자리수 설정 | `KCD/ACD/JCD/ECD/BPN`: `0 / 1 / 2 자리`; `ZCD`: `2 / 3 자리`; 환율범위 `시간당중기사용료 단독 / 중기 / 대가 / 산근 / 내역 전체`; 노임계수 `터널 / 장대터널 / 펌프준설선 / GRAB준설선 / 버켓준설선` |
|
||||
| `wM_Set_Init` | 프로젝트 계산 초기값 설정 | 구체적인 탭·칸 `미확인` |
|
||||
| `wM_Set_JLab` | 직종·노임 관련 초기 설정 | 구체적인 칸 `미확인` |
|
||||
| `uM_XML_Info` | 공사원가 호환규정 XML 변환 설정 | 공사유형 `토목 / 건축 / 설비 / 전기 / 통신 / 조경 / 소방 / 국가유산수리공사` |
|
||||
| `wSrch_PL` | 프로젝트 DATA 검색 | 종류 `노무비 / 재료비 / 경비 / 중기비 / 일위대가 / 단가산출 / 일식·표준시장 / 내역서` |
|
||||
|
||||
## 3. 화면 ↔ 출력 시트 30종
|
||||
|
||||
`print_form_map.txt`의 export 연결과 19번 §3의 실제 시트명을 합쳤다. `PM_*`은 인쇄용 폼이며 편집 화면에서 직접 호출되는지는 정적 자료만으로 확인되지 않은 경우가 있다.
|
||||
|
||||
| 화면·폼 계열 | 실제 출력 시트 |
|
||||
|---|---|
|
||||
| `wM_KanJub` → `PM_Won_A*` | 공사원가계산서 |
|
||||
| `wBoq` → `PM_Nae*` | 설계내역서 · 착공내역서 · 총괄설계내역서 · 총괄내역서 |
|
||||
| `wBoq`/변경 내역 → `PM_Nae*` 또는 `CHANGE_*` | 설계변경내역서 · 설계변경금액대비표 · 설계변경증감대비표 |
|
||||
| `wM_Edit_iLWi` → `PM_iLWi*` | 일위대가표 |
|
||||
| `wM_Edit_San` → `Calq_San`·`Edit_SanKun` | 단가산출근거 |
|
||||
| `wM_JabPum`/중기 원장 → `PM_JOONG*` | 중기사용료 |
|
||||
| `wM_Boxa` 또는 단가비교 → `PM_Col_Dan*` | 자재단가대비표 |
|
||||
| `wM_Set_Sys` 관련 설정 출력 | 환율및기초자료 · `〓 INITIAL 〓` — 정확한 `PM_*` 호출은 `미확인` |
|
||||
| `wM_JabPum` → `PM_SanMok*` | 재료비목록표 · 노무비목록표 · 경비목록표 · 일식견적목록표 |
|
||||
| 일위대가 원장 → `PM_SanMok*` | 일위대가목록표 |
|
||||
| 단가산출 원장 → `PM_SanMok*` | 단가산출근거목록표 |
|
||||
| 중기 원장 → `PM_JOONG*` | 중기목록표 |
|
||||
| 내역 집계 → `PM_Col_Dan*` | 재료비수량금액집계표 · 노무비수량금액집계표 · 경비수량금액집계표 |
|
||||
| 중기 집계 → `PM_Col_Dan*` | 중기시간금액집계표 |
|
||||
| 일위대가 집계 → `PM_Col_Dan*` | 일위대가수량금액집계표 |
|
||||
| 단가산출 집계 → `Calq_San`·`Edit_SanKun`·`PM_Col_Dan*` | 단가산출근거수량금액집계표 |
|
||||
| 일식견적 집계 → `PM_Col_Dan*` | 일식견적수량금액집계표 |
|
||||
| 인쇄 메뉴의 보고서 목록 | `〓 목 차 〓` · `※※안내※※` — 생성 폼 `미확인` |
|
||||
|
||||
30종은 위 대응에 모두 들어간다. 다만 `환율및기초자료`, `〓 INITIAL 〓`, `〓 목 차 〓`, `※※안내※※`의 정확한 생성 폼 **4개 연결은 미확인**이다.
|
||||
|
||||
## 4. DFM 3벌의 실제 배치
|
||||
|
||||
### 4.1 `TWM_KANJUB.dfm` — 제잡비 계산 입력 화면
|
||||
|
||||
- 상단 고정 패널 다음에 본문 `TPageControl(Pg_Ctrl)`이 놓인다.
|
||||
- 상단 칸 차례는 기본값 설정, 차수 선택, 계산방식, 요율, 출력, 변경/계산, 종료 계열이다. 확인되는 콤보는 `Cmbx_PORD1_H` → `cBx_K_JeolSa` → `cBx_Chasu` → `cBx_W_Type` 순이다.
|
||||
- `cBx_Chasu`: `원설계 / 1차변경 / 2차변경 / 3차변경`; `cBx_W_Type`: `제잡비 원가계산방식 / 제잡비 표준시장방식`.
|
||||
- 본문 탭은 아래쪽 탭바(`TabPosition=tpBottom`)이고 여러 줄 탭(`MultiLine=True`)이다. DFM에서 `TbSh_T`, `TbSh_TA` 등 원가 형식별 탭 객체가 확인된다. 탭 캡션 전체와 탭별 항목 수는 `미확인`이다.
|
||||
- 각 탭 안은 `TScrollBox`로 구성되어 긴 제잡비 항목을 세로로 스크롤한다.
|
||||
|
||||
### 4.2 `TWM_KAN_RATE.dfm` — 요율 조회·편집 화면
|
||||
|
||||
- 상단 고정 도구막대: `수정(&E)` → `취소(&C)` → `저장(&S)` → `출력(&P)` → `종료(&Q)` 순이며 `불러오기` 버튼과 요율표 선택 콤보가 함께 있다.
|
||||
- 본문은 `TPageControl(Pg_Ctrl)`이며 탭바가 아래쪽에 있다. 확인되는 첫 탭 객체는 `Tab_Rn`이다.
|
||||
- 탭 안은 흰색 `TScrollBox`와 여러 요율 그리드로 구성된다. 확인되는 묶음은 고용 관련 요율(`rGrd_Rate_Kobo`), 산업안전 관련 요율(`rGrd_Rate_Anjun`) 등이다.
|
||||
- 그리드 열은 공사규모 구간과 `요율`, `기초액`, `% + 천원` 형식을 함께 가진다. 즉 한 화면에서 단순 단일요율뿐 아니라 규모별 기초액 가산식도 편집한다.
|
||||
- 전체 탭 캡션과 모든 그리드의 화면상 정확한 순서는 바이너리 DFM 문자열만으로 복원되지 않아 `미확인`이다.
|
||||
|
||||
### 4.3 `TPM_KAN_RATE.dfm` — 요율표 인쇄 화면
|
||||
|
||||
- 편집 위젯이 아니라 `THRPage` 기반 보고서 한 장이다. `ReportHeader` 뒤에 요율표가 이어진다.
|
||||
- 제목·구간 라벨 → 금액 구간 → 기초액 → 요율 순으로 열이 반복된다.
|
||||
- 확인되는 구간 예시는 `10억~50억 미만`, `70억~120억`이며 표시 형식은 `00.00 %` 또는 `(#,0 천원 + …)`이다.
|
||||
- `일반관리비` 등 항목별 표가 인쇄 좌표에 고정 배치된다. `TWM_KAN_RATE`의 편집 그리드를 종이용 규모구간 표로 펼친 구조다.
|
||||
|
||||
## 5. B08·B09 화면 구조에 주는 근거
|
||||
|
||||
```text
|
||||
수량산출서(wQtyList/uM_ConQTY)
|
||||
→ 내역 입력(wBoq)
|
||||
→ 일위대가·단가산출 편집
|
||||
→ 기준자료(단가·노임·중기)
|
||||
→ 제잡비 계산(wM_KanJub)
|
||||
→ 인쇄 메뉴(PM_Prt)에서 30종 시트 선택
|
||||
```
|
||||
|
||||
- B08 근거: 수량산출서는 코드 종류로 필터한 별도 화면이고, 내역서와 분리되어 있다.
|
||||
- B09 근거: 직접비 편집, 기초단가, 일위대가·단가산출, 제잡비 요율, 출력이 각각 별도 화면이며 마지막에 인쇄 메뉴가 묶는다.
|
||||
- 제잡비 입력 화면과 요율 관리 화면도 분리된다. 요율 관리 화면은 수정·저장·출력의 독립 흐름을 가진다.
|
||||
- 출력은 계산 화면을 그대로 인쇄하지 않고 `PM_*` 보고서 폼을 따로 거친다.
|
||||
|
||||
## 6. 미확인
|
||||
|
||||
화면 단위 미확인 **10개**:
|
||||
|
||||
1. `wM_From_XLS`의 열 매핑·불러오기 옵션
|
||||
2. `wSameCode`의 동일 코드 처리 선택지
|
||||
3. `uM_ConQTY`의 변환 방향·연결 키
|
||||
4. `wM_Edit_USER`의 사용자식 편집 범위
|
||||
5. `wM_iLWi_San`의 조회·편집 경계
|
||||
6. `wM_JajeXLS`의 입력·출력 방향
|
||||
7. `wM_Set_Init`의 탭과 칸
|
||||
8. `wM_Set_JLab`의 직종·노임 설정 칸
|
||||
9. `TWM_KANJUB`의 전체 탭 캡션·항목 수
|
||||
10. `TWM_KAN_RATE`의 전체 탭 캡션·그리드 순서
|
||||
|
||||
출력 연결 미확인 **4개**: `환율및기초자료` · `〓 INITIAL 〓` · `〓 목 차 〓` · `※※안내※※`의 정확한 생성 폼.
|
||||
|
||||
이 문서는 화면 구조 근거만 정리한다. Aislo B08·B09의 구현안이나 화면 설계는 포함하지 않는다.
|
||||
@@ -0,0 +1,67 @@
|
||||
"""B08 → B09 내역 받는 문 — 이름이 아니라 코드로 잇기 (2026-09-13, PLAN 6장 첫 일감 ①).
|
||||
|
||||
겨누는 것
|
||||
① 운반 줄 단가는 **그 줄로 선 내역 줄**에서 — 이름이 같은 줄(도자운반 토사·리핑암)이 둘이어도
|
||||
첫 줄 단가가 둘째에 안 붙음(종전 `row.name == item.name` 실결함)
|
||||
② 총 절취량은 **코드**(9-3·9-4·9-5)로 셈 — 줄 이름에 「깎기」가 없어도 검산이 돎
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
from functools import lru_cache
|
||||
|
||||
import pytest
|
||||
|
||||
import B09_Estimation.B09_Estimation_BillOfQuantities as bill_module
|
||||
from B09_Estimation.B09_Estimation_BillOfQuantities import build_bill
|
||||
from B09_Estimation.B09_Estimation_UnitPrice import build_unit_prices
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _build():
|
||||
return build_unit_prices()
|
||||
|
||||
|
||||
def _row(code: str, name: str, quantity: float, **extra) -> dict:
|
||||
return {"work_item_code": code, "name": name, "unit": "㎥", "quantity": quantity, **extra}
|
||||
|
||||
|
||||
def test_운반_줄_단가는_이름이_아니라_그_줄에서_읽는다(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
seen: list[list[dict]] = []
|
||||
monkeypatch.setattr(
|
||||
bill_module, "check_free_haul_not_priced", lambda haul_rows: seen.append(haul_rows)
|
||||
)
|
||||
payload = {
|
||||
"work_items": [
|
||||
_row("FP-10-11", "dozer 운반", 10, haul_equipment="dozer", variant_value="토사"),
|
||||
# 같은 이름 · 표에 없는 갈래라 단가가 안 섬.
|
||||
_row("FP-10-11", "dozer 운반", 4, haul_equipment="dozer", variant_value="없는갈래"),
|
||||
],
|
||||
"materials": [],
|
||||
}
|
||||
bill = build_bill(payload, build=_build())
|
||||
priced = [r for r in bill.rows if not r.is_group]
|
||||
assert priced[0].unit_price_krw and priced[0].unit_price_krw > 0
|
||||
assert priced[1].unit_price_krw is None
|
||||
prices = [row["unit_price_krw"] for row in seen[0]]
|
||||
assert prices == [priced[0].unit_price_krw, Decimal(0)] # 종전엔 둘 다 첫 줄 단가
|
||||
|
||||
|
||||
def test_총_절취량은_코드로_센다(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
calls: list[dict] = []
|
||||
monkeypatch.setattr(
|
||||
bill_module, "check_haul_volume_within_cut", lambda **kwargs: calls.append(kwargs)
|
||||
)
|
||||
payload = {
|
||||
"work_items": [
|
||||
# 이름에 「깎기」가 없음(마스터 표기 「토사깍기」) — 코드로만 절취임을 앎.
|
||||
_row("FP-09-03-02", "토사깍기", 10),
|
||||
_row("FP-09-12-01", "측구터파기", 3), # 절취 셈에 안 듦(종전과 같음)
|
||||
_row("FP-10-11", "dozer 운반", 5, haul_equipment="dozer", variant_value="토사"),
|
||||
],
|
||||
"materials": [],
|
||||
}
|
||||
build_bill(payload, build=_build())
|
||||
assert calls and calls[0]["total_cut_volume_m3"] == Decimal(10)
|
||||
assert calls[0]["haul_volume_total_m3"] == Decimal(5)
|
||||
Reference in New Issue
Block a user