fix(B09): 분류 딱지 행에서 이름을 둘째 칸으로 읽음 — 자재·장비가 통째로 빠지던 자리
배분 창이 「초류종자살포 배합이 네 일위대가에 있나」를 물어 확인하다 **구멍을 찾음.** - 품셈 표 중 **첫 칸이 분류 딱지**(「자재」·「장비」)이고 **이름이 둘째 칸**인 것이 있음: `['자재', '종 자', '', 'kg', '0.025']` · `['장비', '종자살포기', '2,500-3,000ℓ', …]`. 첫 칸만 보고 읽어 **그 표의 자재·장비가 통째로 빠지고 있었음** — 씨앗뿜어붙이기에서 종자·비료·피복제·침식안정제·색소·장비 3종이 다 빠지고 **보통인부 한 줄만** 남았음. - 첫 칸이 분류 딱지면 이름을 둘째 칸에서 읽고, 값도 그 뒤 칸에서 찾게 고침. - **매칭 106 → 116**(노무 100 → 110). 산출 파일 다시 냄. **⚠ 그래도 배합은 아직 못 실림 — 원인은 사급 자재 단가 미결임** - 종자·복합비료·화이버·합성접착제·색소가 **관급 카탈로그에 없음**(임도 자재가 관급에 없다는 앞선 발견과 같은 자리). 장비 3종(종자살포기·트럭·물탱크)도 기종 카탈로그에 없음. - **다만 이제 못 맞춘 목록에는 남음** — 구멍을 목록으로 드러내는 규칙 그대로. 시험으로 못 박음(`test_seeding_materials_are_listed_not_dropped`). - ⇒ 사면 4계열의 배합이 **B09 일위대가 몫**인 것은 맞으나, **사급 단가가 들어오기 전에는 못 세움.** 「자재총괄에 이을 것이 없다」는 메인 판정은 유지되고, 그 자재는 **㉡ 6번 슬롯 수동 입력 목록**으로 감(야면석·막자갈·고임돌·물구멍에 이어). 자체검증 — 신규 2건 포함 `pytest tmp/tests/ -q` **136 passed** · ruff 통과. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -41,6 +41,13 @@ _CATALOG_SUBPATH = ("resources", "data_cost_input_value")
|
||||
_RE_SPEC = re.compile(r"[((]([^))]+)[))]|(\d+(?:\.\d+)?\s*(?:톤|ton|㎥|m3|㎡|㎜|mm|HP|kW))")
|
||||
_RE_NUMBER = re.compile(r"^-?\d+(?:,\d{3})*(?:\.\d+)?$")
|
||||
|
||||
#: 첫 칸이 **분류 딱지**이고 이름이 둘째 칸에 오는 표가 있다.
|
||||
#: 예 — `['자재', '종 자', '', 'kg', '0.025']` · `['장비', '종자살포기', …]`.
|
||||
#: 이 표를 첫 칸만 보고 읽으면 **자재·장비가 통째로 빠진다**(2026-09-07 실측 —
|
||||
#: 씨앗뿜어붙이기에서 종자·비료·피복제·침식안정제·색소·장비 3종이 다 빠지고
|
||||
#: 보통인부 한 줄만 남았다).
|
||||
_GROUP_LABELS = ("자재", "장비", "인력", "노무", "재료", "기계")
|
||||
|
||||
#: 표 머리글·소계 행의 첫 칸에 오는 말. 자원이 아니므로 `unmatched` 로도 안 올린다.
|
||||
#: 이것을 안 거르면 못 맞춘 목록이 머리글로 가득 차 **쓸 수 없는 목록**이 된다.
|
||||
#: ⚠ **부분일치로 보면 안 된다.** 「계」를 부분일치로 잡으면 `건설기계운전사`·`비계공`·
|
||||
@@ -447,11 +454,16 @@ def match_table(
|
||||
cells = [str(c) for c in row]
|
||||
if not cells:
|
||||
continue
|
||||
# 첫 칸이 분류 딱지(「자재」·「장비」)면 **이름은 둘째 칸**이다.
|
||||
name_cell = cells[0]
|
||||
value_cells = cells[1:]
|
||||
if _normalize(name_cell) in _GROUP_LABELS and len(cells) > 1:
|
||||
name_cell = cells[1]
|
||||
value_cells = cells[2:]
|
||||
|
||||
# 숫자 셀이 없는 행은 자원 줄이 아니다(제목·설명 행) — 목록에 안 올린다.
|
||||
amount_cell = next(
|
||||
(parse_amount(c) for c in cells[1:] if parse_amount(c) is not None), None
|
||||
(parse_amount(c) for c in value_cells if parse_amount(c) is not None), None
|
||||
)
|
||||
if amount_cell is None:
|
||||
continue
|
||||
@@ -459,7 +471,7 @@ def match_table(
|
||||
# ⚠ **카탈로그 조회를 먼저 한다.** 이름 필터를 앞에 두면 필터가 넓을 때
|
||||
# 정상 자원이 조용히 사라진다(2026-09-07 실측 — 부분일치 필터가 매칭 14건을
|
||||
# 지우고 있었음). 카탈로그에 있는 이름은 **정의상 자원**이다.
|
||||
entry = _resolve_cell(catalog, name_cell, cells)
|
||||
entry = _resolve_cell(catalog, name_cell, [name_cell, *value_cells])
|
||||
if entry is None:
|
||||
if is_non_resource_label(name_cell):
|
||||
continue # 머리글·소계 — 못 맞춘 목록에도 안 올린다
|
||||
|
||||
@@ -211,6 +211,18 @@
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-05-23-03"
|
||||
},
|
||||
{
|
||||
"amount": "0.0007",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0135",
|
||||
"raw_row_index": 8,
|
||||
"resource_code": "1038",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "조경공",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-05-24-01"
|
||||
},
|
||||
{
|
||||
"amount": "0.0004",
|
||||
"amount_unit": "",
|
||||
@@ -223,6 +235,18 @@
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-05-24-01"
|
||||
},
|
||||
{
|
||||
"amount": "0.0007",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0136",
|
||||
"raw_row_index": 8,
|
||||
"resource_code": "1038",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "조경공",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-05-24-02"
|
||||
},
|
||||
{
|
||||
"amount": "0.0004",
|
||||
"amount_unit": "",
|
||||
@@ -235,6 +259,18 @@
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-05-24-02"
|
||||
},
|
||||
{
|
||||
"amount": "0.002",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0139",
|
||||
"raw_row_index": 1,
|
||||
"resource_code": "1038",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "조경공",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-05-25"
|
||||
},
|
||||
{
|
||||
"amount": "0.0007",
|
||||
"amount_unit": "",
|
||||
@@ -415,6 +451,18 @@
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-09-05-01"
|
||||
},
|
||||
{
|
||||
"amount": "0.02",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0251",
|
||||
"raw_row_index": 0,
|
||||
"resource_code": "1012",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "용접공",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-09-08-01"
|
||||
},
|
||||
{
|
||||
"amount": "0.08",
|
||||
"amount_unit": "",
|
||||
@@ -559,6 +607,30 @@
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-09-13-18"
|
||||
},
|
||||
{
|
||||
"amount": "0.019",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0290",
|
||||
"raw_row_index": 0,
|
||||
"resource_code": "1002",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "보통인부",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-09-19-02"
|
||||
},
|
||||
{
|
||||
"amount": "0.0328",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0291",
|
||||
"raw_row_index": 0,
|
||||
"resource_code": "1002",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "보통인부",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-09-19-03"
|
||||
},
|
||||
{
|
||||
"amount": "0.80",
|
||||
"amount_unit": "",
|
||||
@@ -943,6 +1015,18 @@
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-12-18"
|
||||
},
|
||||
{
|
||||
"amount": "0.034",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0368",
|
||||
"raw_row_index": 1,
|
||||
"resource_code": "1026",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "방수공",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-12-21"
|
||||
},
|
||||
{
|
||||
"amount": "0.04",
|
||||
"amount_unit": "",
|
||||
@@ -955,6 +1039,18 @@
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-12-21"
|
||||
},
|
||||
{
|
||||
"amount": "0.003",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0370",
|
||||
"raw_row_index": 2,
|
||||
"resource_code": "1002",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "보통인부",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-12-23"
|
||||
},
|
||||
{
|
||||
"amount": "4.0",
|
||||
"amount_unit": "",
|
||||
@@ -991,6 +1087,30 @@
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-12-24-01"
|
||||
},
|
||||
{
|
||||
"amount": "0.004",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0384",
|
||||
"raw_row_index": 1,
|
||||
"resource_code": "1002",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "보통인부",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-12-33"
|
||||
},
|
||||
{
|
||||
"amount": "3.8",
|
||||
"amount_unit": "",
|
||||
"pum_form": "requirement",
|
||||
"pum_table_id": "F0387",
|
||||
"raw_row_index": 1,
|
||||
"resource_code": "1008",
|
||||
"resource_kind": "labor",
|
||||
"resource_name": "철근공",
|
||||
"resource_spec": "",
|
||||
"work_item_code": "FP-12-34-03"
|
||||
},
|
||||
{
|
||||
"amount": "2.2",
|
||||
"amount_unit": "",
|
||||
@@ -1288,12 +1408,12 @@
|
||||
"sha256": "111208fd482dcfc3b8c8dd58004b153382fc46555d0d00985c19b45ebbc2e0dd"
|
||||
},
|
||||
"stats": {
|
||||
"rows": 106,
|
||||
"rows": 116,
|
||||
"skipped_forms": {
|
||||
"coefficient": 19,
|
||||
"reference": 94,
|
||||
"undetermined": 83
|
||||
},
|
||||
"unmatched": 344
|
||||
"unmatched": 348
|
||||
}
|
||||
}
|
||||
@@ -417,7 +417,7 @@
|
||||
"work_item_code": "FP-05-22-04"
|
||||
},
|
||||
{
|
||||
"cell": "자재",
|
||||
"cell": "종 자",
|
||||
"pum_table_id": "F0135",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-05-24-01"
|
||||
@@ -446,6 +446,12 @@
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-05-24-01"
|
||||
},
|
||||
{
|
||||
"cell": "종자살포기",
|
||||
"pum_table_id": "F0135",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-05-24-01"
|
||||
},
|
||||
{
|
||||
"cell": "트 럭",
|
||||
"pum_table_id": "F0135",
|
||||
@@ -459,7 +465,7 @@
|
||||
"work_item_code": "FP-05-24-01"
|
||||
},
|
||||
{
|
||||
"cell": "자재",
|
||||
"cell": "종 자",
|
||||
"pum_table_id": "F0136",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-05-24-02"
|
||||
@@ -488,6 +494,12 @@
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-05-24-02"
|
||||
},
|
||||
{
|
||||
"cell": "종자살포기",
|
||||
"pum_table_id": "F0136",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-05-24-02"
|
||||
},
|
||||
{
|
||||
"cell": "트 럭",
|
||||
"pum_table_id": "F0136",
|
||||
@@ -501,7 +513,7 @@
|
||||
"work_item_code": "FP-05-24-02"
|
||||
},
|
||||
{
|
||||
"cell": "자재",
|
||||
"cell": "거 적",
|
||||
"pum_table_id": "F0139",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-05-25"
|
||||
@@ -999,7 +1011,7 @@
|
||||
"work_item_code": "FP-09-04-01"
|
||||
},
|
||||
{
|
||||
"cell": "자재",
|
||||
"cell": "폭 약",
|
||||
"pum_table_id": "F0243",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-09-05-01"
|
||||
@@ -1016,6 +1028,18 @@
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-09-05-01"
|
||||
},
|
||||
{
|
||||
"cell": "화 약 공",
|
||||
"pum_table_id": "F0243",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-09-05-01"
|
||||
},
|
||||
{
|
||||
"cell": "착 암 기",
|
||||
"pum_table_id": "F0243",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-09-05-01"
|
||||
},
|
||||
{
|
||||
"cell": "공기압축기",
|
||||
"pum_table_id": "F0243",
|
||||
@@ -1047,7 +1071,7 @@
|
||||
"work_item_code": "FP-09-06-01"
|
||||
},
|
||||
{
|
||||
"cell": "자재",
|
||||
"cell": "아세틸렌",
|
||||
"pum_table_id": "F0251",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-09-08-01"
|
||||
@@ -1079,7 +1103,7 @@
|
||||
{
|
||||
"cell": "아스팔트",
|
||||
"pum_table_id": "F0255",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"reason": "규격이 없어 같은 이름 여럿 중 고를 수 없음",
|
||||
"work_item_code": "FP-09-10-02"
|
||||
},
|
||||
{
|
||||
@@ -1478,6 +1502,18 @@
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-09-19-01"
|
||||
},
|
||||
{
|
||||
"cell": "유압식백호우 (무한궤도,0.7㎥)",
|
||||
"pum_table_id": "F0290",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-09-19-02"
|
||||
},
|
||||
{
|
||||
"cell": "공기압축기(3.5㎥/min)",
|
||||
"pum_table_id": "F0291",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-09-19-03"
|
||||
},
|
||||
{
|
||||
"cell": "소형브레이커",
|
||||
"pum_table_id": "F0291",
|
||||
@@ -1601,19 +1637,19 @@
|
||||
{
|
||||
"cell": "각 재",
|
||||
"pum_table_id": "F0336",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"reason": "규격이 없어 같은 이름 여럿 중 고를 수 없음",
|
||||
"work_item_code": "FP-12-04"
|
||||
},
|
||||
{
|
||||
"cell": "철 선",
|
||||
"pum_table_id": "F0336",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"reason": "규격이 없어 같은 이름 여럿 중 고를 수 없음",
|
||||
"work_item_code": "FP-12-04"
|
||||
},
|
||||
{
|
||||
"cell": "박 리 제",
|
||||
"pum_table_id": "F0336",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"reason": "규격이 없어 같은 이름 여럿 중 고를 수 없음",
|
||||
"work_item_code": "FP-12-04"
|
||||
},
|
||||
{
|
||||
@@ -1737,13 +1773,13 @@
|
||||
"work_item_code": "FP-12-18"
|
||||
},
|
||||
{
|
||||
"cell": "자재",
|
||||
"cell": "아스팔트(㏊-500)",
|
||||
"pum_table_id": "F0368",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"reason": "규격이 없어 같은 이름 여럿 중 고를 수 없음",
|
||||
"work_item_code": "FP-12-21"
|
||||
},
|
||||
{
|
||||
"cell": "자재",
|
||||
"cell": "부 직 포",
|
||||
"pum_table_id": "F0370",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-12-23"
|
||||
@@ -1796,12 +1832,6 @@
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-12-24-01"
|
||||
},
|
||||
{
|
||||
"cell": "자재",
|
||||
"pum_table_id": "F0376",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-12-27-02"
|
||||
},
|
||||
{
|
||||
"cell": "접착제",
|
||||
"pum_table_id": "F0376",
|
||||
@@ -1815,13 +1845,7 @@
|
||||
"work_item_code": "FP-12-27-02"
|
||||
},
|
||||
{
|
||||
"cell": "재료",
|
||||
"pum_table_id": "F0384",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-12-33"
|
||||
},
|
||||
{
|
||||
"cell": "자재",
|
||||
"cell": "결속선(R-0.9mm)",
|
||||
"pum_table_id": "F0387",
|
||||
"reason": "카탈로그에 없는 이름 (기계·자재 카탈로그 미확보 포함)",
|
||||
"work_item_code": "FP-12-34-03"
|
||||
|
||||
Reference in New Issue
Block a user