- 3 연결 찾기 = 엑셀 이름 규격 · 단위 꼬리 뗀 이름으로 맞댐(`M02_Doc_Match_Note.bare` · 보이는 이름 그대로) · STmate 블록 규격도 가져온 칸에
- 4 기계 세 줄 = 기계 한 줄 — STmate X 코드 노 · 재 · 경 세 참조 줄(같은 수량 · 번지) 묶음(묶어서 셈 못 하는 세 줄만 그대로) ·
문서 단계 묶기 넓힘(차례 아무렇게 · 시간당 경비 이음 없으면 엑셀 값 묶음 · 번지 같을 때) · 조합 다음 줄 = 세 줄 뒤 · 같은 기계 한 항목
- 6 공구손료 율 비목 차이(재료비 ↔ 경비) = 참고(`M02_Doc_Match_Value.tool_cost`) — 확정 안 막음
- 7 못 이은 줄 까닭(`M02_San_Link.why` — 자재 없음 · 운임표 없음 · 기계 표에 없음 · 별칭 대기 · 후보 여럿 · 시간당 경비 없음 · 조합) =
문서 설명 · 이음 없는 자원 띠 · 연결 「없음」 띠 = 「우리 기초 없음 — 우리 정보로 셈 n/m 줄」 · 형제만 = 「조합」
- 8 유가 = 전국평균 줄 + 지역 옵션(`MO:경유:{S_지역}`) · 전력 = 일반용(갑)Ⅰ 저압 + 계약종별 옵션 · 엑셀 값 = 검산 칸
- 9 재료 = 지역 꼬리 뗀 이름 · 규격 정확 일치면 이음(지역 여럿 = 줄 지역 › 서울)
- 10 조합 첫 줄 규격 = 그 기계 · 얼린 줄도 소계 식에(북부청임도 33) · 기계 줄 찾기 판정 늘 붙음 · 올린 직후 409(HP 보이기 전 산근 보관) ·
엑셀 블록 「엑셀 읽기 확정」 글 · 전수 도우미 str() 뗌 · 줄 쌓기 이름에 규격이 들면 한 번만
- M02_San_Link 새 파일(San_Emit 700 줄 막음 — 요소 잇기 · 시간당 · 조합 · 까닭)
- 시험: 새 test_814_1 · 812-2 · 810-4 거푸집 41 = 근접 → 확정(공구손료 비목 = 값 · 요구 744 C1) · 바꾸기 거절 견본 = 19 ·
812-9 조합 첫 줄 규격 「0.7+브레이카」 → 「0.7」(칩 글 · 요구 738 흠 12)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
151 lines
7.1 KiB
Python
151 lines
7.1 KiB
Python
"""가져온 식 SK ↔ 우리 M01 기초 — 연결 찾기 기록 · 「확정」 때만 우리 기초 사본으로 바꾸기 · 되돌리기
|
|
(PLAN 810-4 · 요구 707 · 708 · 709 · 703) — 서버 단독.
|
|
|
|
찾기(`find`) = 가져온 식 문서(우리 단가로 셈) → `M02_Doc_Match.match` → SK `가져온.원본.연결후보` 에 적음.
|
|
바꾸기(`swap`) = 서버가 다시 찾아 「확정」 일 때만 — 같은 SK 키에 M01 사본 SK(바탕 = 그 기초 ·
|
|
입력값 = 찾은 옵션 · 802-4a 꼴 · 수식 사본은 저장 때 서버가 찍음)를 씀 · 원래 가져온 식 SK 몸은
|
|
`가져온보관` 칸에 그대로 둠 · 일위대가 줄 참조 = 키 그대로(SK 내용만 바뀜 → 금액 다시 셈).
|
|
+ 찾은 `바꿈`(같은 기종 규격만 다른 기계 줄 · 812-11 · 요구 733-2) = 사본 문서 그 줄 기계 입력(원문번호)을
|
|
가져온 규격의 우리 기계로 갈아 끼움(수식 길 저장 = 따로) · 품 · 율 · 단가 · 조건 값은 우리 값 그대로 ·
|
|
기계가 옵션 기호 · 식이면 안 바꿈.
|
|
되돌리기(`back`) = `가져온보관` 몸을 그 키에 다시 씀(가져온 식 금액 그대로 · 수식 사본도 보관 몸 그대로).
|
|
우리 M01 기초는 어느 갈래에서도 안 바뀜(708) · 근접 · 없음 · 기계 작업 = 바꾸기 409(703).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import copy as cp
|
|
import re
|
|
from typing import Any
|
|
|
|
from common_util.common_util_time import utc_now_text
|
|
from M02_MasterTemplete import M02_Doc_Copy as dc
|
|
from M02_MasterTemplete import M02_Doc_Import as dim
|
|
from M02_MasterTemplete import M02_Doc_Match as dm
|
|
from M02_MasterTemplete import M02_Doc_Sk as dsk
|
|
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
|
from M02_MasterTemplete import M02_Sangeun_Doc as sd
|
|
from M02_MasterTemplete import M02_Sangeun_Imported as imp
|
|
|
|
KEEP = "가져온보관" # 바꾼 SK 의 원래 가져온 식 몸(되돌리기)
|
|
_INDEX: dict[str, Any] = {"문서": None, "색인": None}
|
|
|
|
|
|
def _bad(why: str, status: int = 400) -> store.StoreError:
|
|
return store.StoreError(status, why)
|
|
|
|
|
|
def index() -> dm.Index:
|
|
"""M01 수식 문서 색인 — 폴더가 바뀌면(M01 관리자 고침) 다시."""
|
|
docs = dc.folder()
|
|
if _INDEX["문서"] is not docs:
|
|
aims = {k: d for k, d in docs.items() if not d.get("부품")} # 부품 문서 = 과녁 아님(813-2)
|
|
_INDEX["문서"], _INDEX["색인"] = docs, dm.Index(aims)
|
|
return _INDEX["색인"]
|
|
|
|
|
|
def _read(key: str) -> dict[str, Any]:
|
|
if not sd.KEY.match(str(key or "")):
|
|
raise _bad("키(SK-######)")
|
|
return store.read(sd.KIND, key)
|
|
|
|
|
|
def judge(sk: dict) -> dict[str, Any]:
|
|
"""가져온 식 SK → 연결후보(저장 없음)."""
|
|
whole = imp._whole()
|
|
links_imp = dim.Links(whole, "우리")
|
|
doc = dim.of(sk)
|
|
links_imp.learn(doc)
|
|
got = dm.match(doc, links_imp, index(), dm.ml.Links(whole, dc.folder()))
|
|
from M02_MasterTemplete import M02_San_Link as san_link # 우리 정보로 셈 줄 수(814-1 띠)
|
|
|
|
return {**got, "우리정보": san_link.tally(sk[imp.KEY].get("로직") or {}), "때": utc_now_text()}
|
|
|
|
|
|
def find(key: str, version: str) -> dict[str, Any]:
|
|
"""연결 찾기 → SK `가져온.원본.연결후보` 에 적음 → {연결후보, 판}."""
|
|
got = _read(key)
|
|
sk = got["문서"]
|
|
if not dim.is_imported(sk):
|
|
raise _bad("가져온 식 단가산출만 연결을 찾음")
|
|
found = judge(sk)
|
|
meta = sk[imp.KEY]
|
|
new = {**sk, imp.KEY: {**meta, "원본": {**(meta.get("원본") or {}), dm.KEY: found}}}
|
|
info = store.write(sd.KIND, key, version or got["판"], new)
|
|
return {dm.KEY: found, "판": info.get("판")}
|
|
|
|
|
|
def copy_body(sk: dict, found: dict) -> dict[str, Any]:
|
|
"""M01 사본 SK 몸(이름 · 단위 · 구분 그대로 · 바탕 = 찾은 기초 · 입력값 = 찾은 옵션)."""
|
|
keep = {k: sk.get(k) for k in ("키", "이름", "단위", "구분", "상세구분") if sk.get(k)}
|
|
old = {k: v for k, v in sk.items() if k not in ("키", "종류", KEEP)}
|
|
body = {
|
|
"덮개": {},
|
|
"뺀줄": [],
|
|
"더한줄": [],
|
|
"고름": {},
|
|
"자재표시": {},
|
|
} # M01 그대로(고침 없음)
|
|
base = {"바탕": {"로직": found["키"]}, "입력값": dict(found.get("옵션") or {})}
|
|
return {**keep, **body, **base, KEEP: old}
|
|
|
|
|
|
def swap(key: str, version: str) -> dict[str, Any]:
|
|
"""「확정」 일 때만 우리 기초 사본으로 — 서버가 다시 찾음(화면 판정을 믿지 않음)."""
|
|
got = _read(key)
|
|
sk = got["문서"]
|
|
if not dim.is_imported(sk):
|
|
raise _bad("가져온 식 단가산출만 바꿈")
|
|
found = judge(sk)
|
|
if found.get("판정") != dm.SURE:
|
|
raise _bad(f"우리 기초와 「확정」 일치가 아님({found.get('판정')}) — 바꾸지 않음", 409)
|
|
info = store.write(sd.KIND, key, version or got["판"], copy_body(sk, found))
|
|
done = refit(key, found.get("바꿈") or [])
|
|
return {dm.KEY: found, "판": done[0] or info.get("판"), "바꾼기계": done[1]}
|
|
|
|
|
|
def refit(key: str, swaps: list[dict]) -> tuple[str | None, list[dict]]:
|
|
"""사본 문서 기계 줄 → 가져온 규격 우리 기계(그 줄 단가 기호 연결의 입력 「기계」 · 줄 이름 · 규격) →
|
|
수식 길 저장 · (판, 바꾼 것)."""
|
|
from M02_MasterTemplete import M02_Doc_Sk_Path as path # 수식 길 — 늦게(돌아 부름 피함)
|
|
|
|
if not swaps:
|
|
return None, []
|
|
got = path.read(key)
|
|
doc = cp.deepcopy(got["문서"])
|
|
done = []
|
|
for one in swaps:
|
|
var = next((v for v in doc.get("변수") or [] if dm.md.var_id(v) == one["기호"]), None)
|
|
link = (var or {}).get("연결") or {}
|
|
given = link.get("입력") or {}
|
|
if link.get("갈래") != "단가산출" or not re.fullmatch(r"'[^']+'", str(given.get("기계"))):
|
|
continue
|
|
link["입력"] = {**given, "기계": f"'{one['기계']}'"}
|
|
for line in doc.get("금액") or []:
|
|
if dm._single(line.get("단가")) == one["기호"]:
|
|
if line.get("묶음") == line.get("이름"): # 그 줄 이름을 단 묶음 제목도
|
|
line["묶음"] = f"{one['이름']} {one['규격']}".strip()
|
|
line["이름"], line["규격"] = one["이름"], one["규격"]
|
|
done.append(one)
|
|
if not done:
|
|
return None, []
|
|
return path.save(key, {"문서": doc, "판": got["판"]})["판"], done
|
|
|
|
|
|
def back(key: str, version: str) -> dict[str, Any]:
|
|
"""우리 기초 사본 → 원래 가져온 식(보관 몸 그대로)."""
|
|
got = _read(key)
|
|
old = got["문서"].get(KEEP)
|
|
if not isinstance(old, dict) or not old.get(imp.KEY):
|
|
raise _bad("되돌릴 가져온 식 없음")
|
|
keep = (
|
|
old.get(dc.KEY) if dc.has(old) else None
|
|
) # 보관 몸 수식 사본 그대로(바꾼 기계 = 따로 버림)
|
|
token = dsk.SAVING.set({"키": key, "사본": keep}) if keep else None
|
|
try:
|
|
info = store.write(sd.KIND, key, version or got["판"], {**old, "키": key})
|
|
finally:
|
|
if token is not None:
|
|
dsk.SAVING.reset(token)
|
|
return {"판": info.get("판")}
|