feat(master_data): 관급 제조사별 최저가 채움 · 조달청 2차 받기 · 짝짓기 갈래 · 새 줄 380

- 제조사별로 값이 갈리면 같은 규격 최저가 + 비고에 제조사 (보류 394 채움)
- 조달청 분류 23개 더 받음 (원본 gz 보관) · 시멘트 · 조경석 · 주철관 · 이음관 · 골재 · 측구수로관 · 볼라드 · 맨홀 · 용접철망 · 돌망태 · 매트 짝짓기
- 조달청에만 있는 금속돌망태 372 · 토목용부직포 8 을 자재품목에 새 줄로 들임 (키대장 갱신)
- 다산 값 대조 기준 ±5% · 짝짓기 시험 11건 · 설계 문서 갱신

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
This commit is contained in:
2026-09-20 18:06:15 +09:00
co-authored by Claude Sonnet 5
parent ce38094e91
commit e44365365b
38 changed files with 2061 additions and 946 deletions
@@ -4,8 +4,9 @@
- **관급 단가는 조달청 종합쇼핑몰 API 3종에서 「분류명 부분 글자」로 받을 수 있음** — 레미콘·아스콘은 「조합공통품목」 줄이 지역별 관급 단가(다산소프트 관급 열과 같은 것). 인증키 = 기존 공공데이터포털 일반 인증키 하나(활용신청 끝남).
- 지난번 「시설공통자재 6,999줄」(`PriceInfoService`)에는 관급 자재가 없음 — 잘못 고른 API.
- **레미콘 2,095줄 중 2,028줄이 다산소프트 값과 똑같음**(97%). 아스콘은 짝은 서고 값은 기준일이 달라 다름. 철근·파형강관·흄관은 제조사별 값이 갈려 **채우지 않고 보류**.
- 정본 `재료_자재품목.json` 관급 열을 다산소프트 값 → 조달청 값으로 바꿈: 관급 열이 있던 4,552줄 중 **채움 3,045 · null 1,507**(다산 값 남기지 않음).
- **값 비교 기준 = 다산소프트 값 ±5% 안이면 「맞음」**(받는 시점이 달라 생기는 차이).
- **제조사별로 값이 갈리면 같은 규격의 가장 낮은 값**을 관급 열에 넣고 비고에 그 제조사(「관급: 조달청 다수공급자계약 <제조사> 최저 <날짜> · …」) — 줄·열은 안 늘림. 보류 394 → 0.
- 정본 `재료_자재품목.json` 관급 열: 옛 4,552줄 중 **채움 3,752 · null 800**(맞음 3,232 · 5% 넘게 다름 520 · 못 채움 800) + **조달청에서 새로 들인 줄 380**(모두 채움) = 4,932줄 중 **채움 4,132 · null 800**. 다산 값은 남기지 않음.
- 다시 돌리기 — `./venv/Scripts/python.exe resources/master_data/scripts/update_관급단가.py update`
## 조달청 API (공공데이터포털 15129471 `at/ShoppingMallPrdctInfoService`)
@@ -15,11 +16,12 @@
| `getMASCntrctPrdctInfoList` | 다수공급자계약(MAS) — 제조사·조합별 | 레미콘 · 아스팔트콘크리트 · 봉강 · H빔 · 파형강관 · 콘크리트관 | 26,384 · 17,949 · 1,039 · 181 · 6,970 · 504 |
| `getUcntrctPrdctInfoList` | 일반단가계약 | 아스팔트콘크리트 · 콘크리트관 | 17 · 10 |
| `getThptyUcntrctPrdctInfoList` | 3자단가계약 | 레미콘 · 아스팔트콘크리트 · 파형강관 | 128 · 13 · 1,573 |
| 2차 (세 오퍼레이션 섞임) | — | 시멘트 · 골재 · 조경석 · 주철관 · 파형강관이음관 · 배수로 · 블록 · 돌망태 · 합성목재 · 볼라드 · 교량받침 · 용접철망 · 섬유 · 폴리에틸렌 · 맨홀 · 매트 · 낙석 · 그레이팅 · 벽돌 · 시트 · 비료 · 압륜 · 부직포 | 파일 43개(원본 3MB) — 목록·줄 수는 `_meta.md` |
- 조건 = `inqryDiv=2` + `prdctClsfcNoNm=<글자>` — **부분 글자 조회**(분류 통째가 아님). 「철근」은 암거블록·배수로가 섞여 옴 → 「봉강」(철근콘크리트용봉강) · H형강은 「H빔」 · 「형강」은 파형강관이 걸림.
- 응답 칸(쓰는 것) — `prdctSpecNm`(품명·규격) · `cntrctPrceAmt`(단가·VAT 포함) · `prdctSplyRgnNm`(공급지역) · `prdctDlvryCndtnNm`(인도조건) · `prdctMakrNm`(「조합공통품목」 = 조합 공통 관급단가) · `cntrctCorpNm`(계약 조합·업체) · `cntrctBgnDate`·`cntrctEndDate`(계약 기간) · `prdctUnit`.
- 갱신 주기 — 계약 기간 단위(레미콘 조합공통 2026-06-01~, 아스콘 2026-08-01~ 등) · 일별 조회 · 쪽당 999 · 인증키 일일 호출 한도 안.
- 없는 것(이번 조사에서 못 찾음) — 시멘트 지역별 관급 · 골재 · 조경석 · 벤치플륨 · 주철관 · 측구수로관 등 648줄(다산소프트 관급 열에는 있음) → 「짝짓기 아직 없음」으로 null.
- 이번에 찾음(2차) — 시멘트 · 골재 · 조경석 · 주철관 · 이음관 · 측구수로관 · 볼라드 · 맨홀 · 용접철망 · 돌망태 · 매트. 조달청에 같은 품명이 없어 못 이음 — 벤치플륨 · 무게수로관 · HI-VP(다산 이름 그대로는 분류 없음).
- 원본 보관 — `resources/knowledge/original/원가계산/자재단가/관급/<받은 날>/*.json.gz` + `_meta.md`(받은 칸만 남김 — 첨부·이미지 뺌).
## 짝짓기 방법
@@ -33,29 +35,31 @@
| 파형강관 | `파형강관(관급)` · 「D300×1.6T (1RS)」 | MAS·3자 파형강관 | 지름 + 두께 + RS |
| 흄관 | `흄 관(B형)(관급)` · 「Φ250mm」 | MAS·일반 콘크리트관 「보통관」 | 지름 |
- 2차 갈래(`update_관급단가_기타.py`) — 자재품목 규격의 숫자 조각(치수·종별)과 글자 조각(제품·산지)이 조달청 품명·규격에 모두 있을 때만 짝 · 이름 끝 「-지역」은 지역 · 지역이 아니면 제조사 · 주철관은 이름의 종별(2종·3종)도 맞아야.
- 지역 — 지명 낱말로 쪼개 약칭을 풀고(경기 → 경기도) 「시·군·구」·「전지역(구 나열)」·조합 이름을 뺀 뒤, 같은 묶음 → 겹침 0.5 이상 하나뿐일 때만 짝(동점은 못 채움). 이름에 조합이 붙은 줄(제주…레미콘(협))은 그 조합 줄만.
- 후보가 여럿이면 — 값이 하나(같은 값 여럿 포함)일 때만 채움. **제조사별로 값이 갈리면 null(보류)** — 고르는 기준 미정(다산 값은 H형강 26줄에서 최저값과 같았음 · 철근 8/81 · 파형강관 15/98).
- 후보가 여럿이면 — 값이 하나면 그 값 · **제조사별로 값이 갈리면 가장 낮은 값 + 비고에 그 제조사**(확정 · `pick()` 한 곳).
## 다산소프트 값과 맞대기 (사본에서 관급 열을 지우고 다시 채움 — 2026-09-20)
## 다산소프트 값과 맞대기 (±5% 안 = 맞음 — 사본에서 관급 열을 지우고 다시 채움 · 2026-09-20)
| 갈래 | 전체 | 짝 서고 채움 | 값 같음 | 값 다름 | 보류(제조사별 값 갈림) | 못 채움 |
| 갈래 | 전체 | 짝 서고 채움 | 맞음(±5%) | 5% 넘게 다름 | 보류 | 못 채움 |
|---|---|---|---|---|---|---|
| 레미콘 | 2,095 | 2,078 | **2,028** | 50 | 0 | 17 |
| 아스콘 | 1,430 | 966 | 0 | 966 | 162 | 302 |
| 철근 | 81 | 0 | 0 | 0 | 81 | 0 |
| H형강 | 57 | 1 | 0 | 1 | 26 | 30 |
| 파형강관 | 214 | 0 | 0 | 0 | 98 | 116 |
| 흄관 | 27 | 0 | 0 | 0 | 27 | 0 |
| 그 밖(벤치플륨 · 조경석 · 주철관 등) | 648 | 0 | 0 | 0 | 0 | 648 |
| **합계** | **4,552** | **3,045** | 2,028 | 1,017 | 394 | 1,113 |
| 레미콘 | 2,095 | 2,078 | **2,033** | 45 | 0 | 17 |
| 아스콘 | 1,430 | 1,128 | 855 | 273 | 0 | 302 |
| 철근 | 81 | 81 | **81** | 0 | 0 | 0 |
| H형강 | 57 | 27 | 26 | 1 | 0 | 30 |
| 파형강관 | 214 | 98 | 32 | 66 | 0 | 116 |
| 흄관 | 27 | 27 | 10 | 17 | 0 | 0 |
| 조경석 | 48 | 48 | **48** | 0 | 0 | 0 |
| 파형강관이음관 | 108 | 102 | 87 | 15 | 0 | 6 |
| 주철관 · 부속 | 116 | 116 | 34 | 82 | 0 | 0 |
| 측구수로관 | 23 | 17 | 8 | 9 | 0 | 6 |
| 시멘트 · 골재 · 볼라드 · 맨홀 · 용접철망 · 돌망태 · 매트 | 56 | 30 | 18 | 12 | 0 | 26 |
| 그 밖(벤치플륨 · 블록 · 폴리에틸렌 · 교량받침 · 합성목재 · 무게수로관 등) | 297 | 0 | 0 | 0 | 0 | 296 |
| **합계** | **4,552** | **3,752** | **3,232** | **520** | **0** | **800** |
(정본 null 1,507 = 보류 394 + 못 채움 1,113 — 「못 채움」 = 짝 자체가 안 선 줄 · 「보류」 = 짝은 서나 값이 갈려 채우지 않은 줄.)
- **레미콘 값 다름 50** — 광주·전남 25-30-180(다산 117,800 · 조달청 118,710) · 충남 25-33-150(130,800 · 131,000) 등 소수 규격 + 제주 세 조합(다산 119,130 · 조달청 125,940~126,000). 지역·규격은 같음 → **기준일 차이(다산 2026-07 · 조달청 계약 2026-06-01~)나 다산 원문 값 차이** — 이 조사로는 어느 쪽인지 못 가림.
- **아스콘 값 다름 966 전부** — 조달청 계약 시작이 **2026-08-01**(다산 「조달 26.7」보다 새 기준). 지역·배합·등급은 같음 → 기준일 차이. 비율 1.003~1.033.
- **철근** — 다산 값(SD400 D10 827,640 · D13~ 819,500)은 조달청 제조사별 값(5~8가지) 중 최저와 8/81만 같음 → 다산이 어느 제조사·조건을 골랐는지 원문에 없음 → 보류.
- **H형강** — 다산 1,228,830 = 동국제강(SS275) 값, 현대제철은 1,301,590 → 다산은 최저 제조사 값. 그러나 규칙으로 못박지 않음(보류 26). 못 채움 30 = 다산 규격 중 조달청 H빔에 없는 치수.
- **못 채움 까닭** — 지역 못 찾음(레미콘 16 · 아스콘 240: 조달청 지역 묶음이 다산과 다름) · 규격 없음(아스콘 62 · 레미콘 1) · 후보 없음(H형강 30 · 파형강관 116 — 「-거양」 제조사 줄·D 규격이 조달청 목록에 없음) · 짝짓기 아직 없음(648).
- 「5% 넘게 다름」 = 제조사별 최저값이 다산이 고른 제조사·조건 값보다 낮은 경우가 대부분(주철관 0.60~1.00 · 이음관 0.45~1.00 · 흄관·파형강관) + 아스콘 기준일 차이(조달청 계약 2026-08-01~ · 다산 「조달 26.7」).
- 레미콘 다름 45 — 광주·전남 25-30-180(다산 117,800 · 조달청 118,710) · 제주 세 조합(다산 119,130 · 조달청 125,940~126,000) — 지역·규격 같음 → 기준일 차이 또는 다산 원문 값.
- 못 채움 800 — 아스콘 302(지역 240 · 규격 62) · 그 밖 297(짝 규칙 없음 · 조달청에 같은 품명 없음) · 파형강관 116(「-거양」 규격이 조달청 목록에 없음) · H형강 30 · 돌망태·매트 20 · 레미콘 17 · 이음관 6 · 측구수로관 6 · 골재 6.
## 짝짓기 규칙 넓힘 (2차)
@@ -63,32 +67,36 @@
- 지역 묶음 — 다산 줄이 여러 시군 묶음(「강원도(동해,삼척,영월,…)」)이고 묶음 안 시군마다 조달청 시군 줄이 **모두** 있을 때만, 그 줄들 값이 하나면 채움(갈리면 보류 · 「제외」 묶음 · 시군 이름 붙은 글 · 조달청에 없는 시군은 그대로 못 채움). 30줄 채움 · 옛값 대비 0.999~1.071.
- 못 넓힌 것 — 아스콘 240(「경남(진주사천남해…」 시군 구분 없는 글 · 「서울,경기(…구 제외)」) · R3-H 순환 규격 62 · 레미콘 16(여수시 읍면 묶음).
## 제조사별 값 — 고르는 선택지 (관리자가 정함 · 지금은 보류 394)
## 제조사별 값 — 확정(사용자)
| 선택지 | 뜻 | 확인된 것 |
|---|---|---|
| 최저가 | 제조사·조합 값 중 가장 낮은 값 | H형강 26줄에서 다산 값과 같았음 · 철근은 8/81 · 파형강관 15/98 |
| 최신 계약 | 계약 시작일이 가장 늦은 줄 | 아직 대조 안 함 |
| 특정 제조사 고정 | 예: 동국제강 | 다산이 어느 곳을 골랐는지 원문에 없음 |
| 평균 | 제조사 값 평균 | 관급 단가 성격(조합 공통)과 안 맞음 |
- 같은 규격이 제조사·조합별로 값이 갈리면 **가장 낮은 값**을 관급 열에 · 비고에 그 제조사(「… 다수공급자계약 동국제강 최저 2026-09-20 · …」) — 제조사별로 줄·열을 늘리지 않음. 채운 줄 523(철근 81 · 파형강관 98 · 흄관 27 · H형강 26 · 아스콘 162 · 이음관 16 · 주철관 등).
- 고쳐 쓴 곳 = `update_관급단가.py` 의 `decide()` 한 곳(`pick()` 은 이미 최저를 돌려줌).
- 어느 쪽이든 `update_관급단가.py` 의 `pick()` 한 곳만 고침.
## 조달청에만 있는 품목 — 자재품목에 새 줄
- 자재품목에 같은 품목·규격 줄이 있으면 관급 열만 채우고(위 짝짓기) · **없으면 새 줄**: 키 = `_키대장` 다음 번호(MT023981~) · 물가지 네 열 null · 관급만 · 출처 「자재품목 조달청 <계약방식>」(검사 도구 출처 모양에 맞춤) · 비고 = 관급 비고 · 원문번호 = 「조달청 <품명> <규격>」(다시 돌려도 같은 줄을 갱신).
- 이름·규격·단위 = 조달청 표기 그대로(「품명, 제조사, 모델, 규격…」 에서 제조사·모델을 뺌) · 같은 품명·규격은 최저가.
- 이번에 들인 것 **380줄** — 금속돌망태 372(사각·육각 상자형·매트리스형 · 규격별) · 토목용부직포 8(두께별). 파형강관·흄관은 자재품목에 이미 다 있어 새 줄 없음(Φ800·1000·1200 포함).
- 품셈재료 못 이은 343 가운데 조달청에서 찾은 것 = 파형강관 · 흄관 · 부직포 · 돌망태 · 시멘트벽돌(자재품목에 이미 있음)뿐 — 연결(품셈재료 → 자재품목)은 화면에서 사람이 이음(이번에 안 건드림). 조달청 분류에서 못 찾음 = 유공관 · 폼타이 · 각재·합판 · 철선 · 못 · 종자 · VR관(소켓식) · 거푸집(1줄) · 낙석방지망(펜스만) · 벤토나이트·지오콤포지트·HDPE시트 등.
- 받아 두고 아직 안 쓴 분류(다음 후보) — 블록 · 교량받침 · 폴리에틸렌 · 합성목재 · 그레이팅 · 낙석 · 시트 · 비료 · 매트: 다산 규격과 조달청 규격이 달라 짝이 안 섬(원본만 보관). 받지 않은 분류 — 가드레일 · 표지판 · 목재덱 · 종자(0줄).
## 로직 일괄 시험 계산 (전후)
- 방법 — 로직 줄마다 입력 조합(최대 40)으로 `master_formula.run` 을 돌려 하나라도 통과하면 통과 · 아니면 멈춤.
- 관급 열 교체 전(다산소프트 값) **통과 1,024 · 멈춤 327** → 후(조달청 값) **통과 1,024 · 멈춤 327** — 변화 없음(멈춤 까닭 = 값 없음 285 · 맞는 줄 없음 25 · 지역 값 없음 16 · 칸 없음 1).
- 관급 열 교체 전(다산소프트 값) **통과 1,024 · 멈춤 327** → 후(조달청 값 · 최저 채움 · 새 줄 380 포함) **통과 1,024 · 멈춤 327** — 변화 없음(멈춤 까닭 = 값 없음 285 · 맞는 줄 없음 25 · 지역 값 없음 16 · 칸 없음 1 — 관급이 멈춤 까닭이 아님).
- check_master — 틀 0 · 본문 1(기존) · 로직 0.
## 갱신 절차
1. `update` — 받기(`fetch_all`) → 원본 보관(gz · `_meta.md`).
2. 짝짓기(`refill`) → 정본 관급 열·비고만 바꿈(`apply` · 다른 열·서식 그대로 · 줄 수 안 변함).
3. 바뀐 줄 목록 = `tmp/관급_바뀐줄.json`(옛값 · 새값 · 비고) — 검토 뒤 커밋.
4. 비고 형식 — 「관급: 조달청 <계약방식> <받은 날> · 계약 <시작>~ · <지역> · <인도조건> · <부가세>」 · 못 채운 줄 = 「관급: 조달청 값 못 채움 — <까닭> (<받은 날>)」.
1. `update` — 받기(`fetch_all` · 같은 날 받은 파일은 건너뜀 · 호출 5회 재시도) → 원본 보관(gz · `_meta.md`).
2. 짝짓기(`refill`) → 정본 관급 열·비고만 바꿈(`apply` · 다른 열·서식·줄바꿈 그대로).
3. 조달청에만 있는 품목 새 줄(`add_rows`) — 키대장 갱신 · 다시 돌려도 중복 없음.
4. 바뀐 줄 목록 = `tmp/관급_바뀐줄.json`(옛값 · 새값 · 비고) — 검토 뒤 커밋.
5. 비고 형식 — 「관급: 조달청 <계약방식>[ <제조사> 최저] <받은 날> · 계약 <시작>~ · <지역> · <인도조건> · <부가세>」 · 못 채운 줄 = 「관급: 조달청 값 못 채움 — <까닭> (<받은 날>)」.
## 남은 일
- 보류 갈래(철근·파형강관·흄관·H형강·아스콘 일부)는 **제조사 고르는 기준**(최저가 · 특정 조합 등)을 관리자가 정해야 채움.
- 못 찾은 지역·648줄 갈래는 조달청 다른 서비스(가격정보 `getPriceInfoListMrktCnstrctPc` 등) 조사 필요.
- 짝짓기 시험 = `resources/tester/test_masterdata_procure.py`(견본 응답 7건).
- 못 채움 800 — 아스콘 지역 240 · 규격 62 · 그 밖 297 · 파형강관 116 · H형강 30 · 그 밖 소수(위 표).
- 받아 둔 분류(블록 · 교량받침 · 폴리에틸렌 · 합성목재 · 그레이팅 · 낙석 · 시트 · 비료 · 매트)는 다산 규격과 조달청 규격 표기가 달라 짝 규칙을 더 만들어야 채움 — 또는 새 줄로 들임.
- 품셈재료 → 자재품목 연결(343 줄 미연결)은 화면에서 사람이 이음.
- 짝짓기 시험 = `resources/tester/test_masterdata_procure.py`(견본 응답 11건).