fix(729-4): 단가산출 만들기 단위 성격 다름 500 걷음 · 못옮김 잇기 서버 길

- 728-2 단위 환산 뒤 [단가산출 만들기] 500 · 400(100개 ↔ ㎡ · ㎥ ↔ m2 · 본 ↔ M · 개소 ↔ m) 걷음 — 견줌 SK 배 = ratio_of(728 규칙) · 성격 다름 = 환산 계수 = 우리 품 ÷ 엑셀 품(인력 · 장비 둘 이상 같은 비일 때만) · 못 구함 = 고름 대기(까닭 「단위 성격 다름 · 계수 필요」 · 후보[].계수 칸)
- 맞음 블록도 단위 견줌(전엔 셈 없이 기초로 써서 뒤 셈에서 막힘)
- 못옮김 = [{id, 갈래 노임|기계|자재, 이름, 규격, 단위, 수량, 글, 후보}] · 응답 만듦[].못옮김 · 환산
- 몸 바탕[번] = {로직?, 입력값?, 환산?, 잇기?} · 잇기 [{id, 노임|기계|자재: 키} | {id, 뺌}] → SK 더한줄 인력 · 기계 · 재료(엑셀 수량 × 배) · 뺌 = 본뜬 놓음 · 틀린 id · 키 400
- 못옮김 남은 SK 를 쓰는 일위대가 = 남은줄(단산 · SK · 못옮김) · hopyo-build · build-all 409
- 못옮김 남은 블록 = SK(같지 않음)
- 시험 test_729 에 단위 · 잇기 · 409 시험 하나 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-02 11:33:31 +09:00
co-authored by Claude Opus 5.5
parent a70539c161
commit b63d000822
4 changed files with 246 additions and 39 deletions
@@ -5,6 +5,7 @@
SK 품 = 엑셀 품(차이는 엑셀 값 그대로) · 같은 단가산출 = 기초(덮개 없음) + 별칭 제안(짝 = 기초까지만) ·
고름 대기 = SK 안 만듦 → 고른 기초로 SK · 안 이은 줄 남으면 만들기 409(미리 보기 = 같은 줄) ·
사용자가 고르면 만듦 · 노임 = 이름 이음 · 기계 = EQ 이음 · master_data 원본 그대로. 층 = 임시 폴더.
729-4 = 단위 성격 다름(계수 · 고름 대기) · 못옮김 잇기 · 남은 못옮김 = 일위대가 막음.
"""
import json
@@ -18,6 +19,7 @@ from M02_MasterTemplete import M02_Hopyo_Ours as ours
from M02_MasterTemplete import M02_Hopyo_SkPatch as skpatch
from M02_MasterTemplete import M02_Hopyo_Store as hs
from M02_MasterTemplete import M02_MasterTemplete_Store as store
from M02_MasterTemplete import M02_Sangeun_Calc as calc
from M02_MasterTemplete import M02_Template_Layers as layers
from resources.tester.test_m02_hopyo_excel import URL, _post, client, master_hash # noqa: F401
@@ -129,6 +131,61 @@ def test_실무_단가산출_기초_SK_고름대기_일위대가_막음(client):
assert master_hash() == before
def test_단위_성격_다름_계수_못옮김_잇기_남으면_일위대가_막음(client):
"""729-4 — 728-2 단위 환산 뒤 500 0 · 성격 다른 단위 = 계수 거꾸로(자신 있을 때) · 아니면 고름 대기
(후보 계수 칸) · 못옮김 잇기 = SK 더한줄 · 뺌 = 놓음 · 남으면 그 SK 를 쓰는 일위대가 막음."""
before = master_hash()
folder, whole = layers.personal_dir(7, 42), m01.loaded()[1]
key = _post(client).json()["키"]
url = f"{URL.format('personal')}/{key}/sangeun"
fit.run_job(folder, key)
got = client.post(url, json={})
assert got.status_code == 200, got.text
got = got.json()
wait = {x["번"]: x for x in got["고름대기"]}
assert wait[30]["까닭"].startswith(skpatch.UNIT_WHY) # 큰돌채집운반 ㎡ ↔ 100개
assert wait[30]["후보"][0]["계수"] == {"가": "100개", "나": "㎡", "갈래": "사용자"}
docs = _sk_docs(folder)
coef = [d for d in docs.values() if d.get("환산")]
assert coef # 계수 거꾸로 = 셈 됨 · 엑셀 품 그대로
for d in coef:
with store.at(folder):
mine = skpatch.measure(d, whole)
assert all(_same(q, mine["인력"][t]) for t, q in d["본뜬"]["엑셀품"]["인력"].items())
lost = {x["번"]: x["못옮김"] for x in got["만듦"] if x["못옮김"]}
a, b = lost[95] # 도장 — 엑셀만 자재 둘
assert a["갈래"] == "자재" and a["id"] != b["id"] and a["수량"] == 0.322
hp = hs.read(folder, key)
no = next(h["번"] for h in hp["호표"] for x in h["줄"]
if (x.get("참조") or {}).get("종류") == "단산" and int(x["참조"]["번"]) == 95) # fmt: skip
body = {"층": "personal", "키": key, "번": no, "줄": []}
def left() -> list:
return [x for x in client.post(LEFT, json=body).json()["남은줄"] if x.get("단산") == 95]
assert [len(x["못옮김"]) for x in left()] == [2]
assert client.post(BUILD, json=body).status_code == 409
def link(*rows: dict):
return client.post(url, json={"바탕": {"95": {"잇기": list(rows)}}})
assert link({"id": "자재:없음", "자재": "MT000010"}).status_code == 400
assert link({"id": a["id"], "기계": "EQ000001"}).status_code == 400
assert link({"id": a["id"], "자재": "MT999999"}).status_code == 400
one = link({"id": a["id"], "자재": "MT000010"}).json()
assert [x["못옮김"] for x in one["만듦"]] == [[b]]
doc = _sk_docs(folder)[95]
tb = float(calc.ratio_of(doc, whole.logic(doc["바탕"]["로직"]), whole))
add = doc["더한줄"][-1]
assert add["종류"] == "재료" and add["요소"] == "MT000010" and _same(add["수량"], 0.322 * tb)
assert [len(x["못옮김"]) for x in left()] == [1]
two = link({"id": a["id"], "자재": "MT000010"}, {"id": b["id"], "뺌": "현장 지급"}).json()
assert two["만듦"][0]["못옮김"] == []
assert _sk_docs(folder)[95]["본뜬"]["놓음"][0]["id"] == b["id"]
assert left() == []
assert master_hash() == before
def _eq(one: dict) -> str:
return str((one.get("입력값") or {}).get("기계") or "")