fix(M02): 조합 갈라 내기 같은 내용 판정에 차례 · 메모 포함 · 서버 거절 까닭 그대로 알림
- 일위대가 조합: 담은 로직 차례 · 메모까지 같아야 있는 키(원래 키 먼저) — 차례 · 메모만 바꿔도 새 조합 - 자재 조합: 담은 자재 차례까지 비교 - M02 Api_Fetch: detail 문장 · errors 목록 · 입력 검사 목록을 알림 글로(HTTP 422 대신) - 새 조합 자동 이름: 원래 이름 끝 「 (n)」 뗌(겹친 (2) (2) 막음) - test_m02_combo_branch.py 새 규칙으로 고침 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Kyw9qnkJ94pC1A4PfpDtA
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
· 일위대가 조합(UA · `일위대가조합.json`) — 새 줄은 M01 조합 저장소가 만듦(부르기만)
|
||||
· 자재 조합(UM · `자재조합.json`) — M01 마스터 저장(`save`)으로 더함(키 = 대장 다음 번호)
|
||||
|
||||
조합은 여러 열 · 모든 프로젝트가 같이 씀 — 제자리 고치지 않음. 담은 것의 집합(차례 · 메모 무시)이
|
||||
이미 있는 조합과 같으면 새로 안 만들고 그 키 · 새 줄의 본뜬키 = 원래 키 · 소유 현장.
|
||||
조합은 여러 열 · 모든 프로젝트가 같이 씀 — 제자리 고치지 않음. 담은 것(차례 · 메모까지)이
|
||||
이미 있는 조합과 같으면 새로 안 만들고 그 키(원래 키 먼저) · 새 줄의 본뜬키 = 원래 키 · 소유 현장.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -41,14 +41,14 @@ def _branch(
|
||||
field: str,
|
||||
file: str,
|
||||
slot: str,
|
||||
ident: str,
|
||||
ident: tuple[str, ...],
|
||||
items: list[dict],
|
||||
source: str,
|
||||
make: Callable[[str, list[dict]], dict],
|
||||
name: str,
|
||||
) -> dict[str, Any]:
|
||||
"""집계표 판 검사 → 같은 내용 찾기 · 없으면 `make(이름, 줄들)` 로 새 줄 → 집계표 그 열 `field`.
|
||||
`slot` = 담은 칸(담은로직 · 담은자재) · `ident` = 담은 줄의 알맹이 칸(로직 · 코드)."""
|
||||
`slot` = 담은 칸(담은로직 · 담은자재) · `ident` = 담은 줄에서 견주는 칸(로직 · 메모 / 코드)."""
|
||||
table = store.read("table", store.STRUCTURE_TABLE)
|
||||
if version and table["판"] != version:
|
||||
raise store.StoreError(409, {"stale": [store.STRUCTURE_TABLE], "판": table["판"]})
|
||||
@@ -58,8 +58,10 @@ def _branch(
|
||||
if not isinstance(items, list) or not items:
|
||||
raise store.StoreError(400, "담은 것이 비었음")
|
||||
|
||||
def body(got) -> frozenset[str]:
|
||||
return frozenset(str(x.get(ident) or "") for x in got or [] if isinstance(x, dict))
|
||||
def body(got) -> tuple: # 차례대로 · 빈 메모 = null
|
||||
return tuple(
|
||||
tuple(str(x.get(k) or "") for k in ident) for x in got or [] if isinstance(x, dict)
|
||||
)
|
||||
|
||||
rows = _m01(m01.read, file)[0].get("줄") or []
|
||||
same = [r for r in rows if body(r.get(slot)) == body(items)]
|
||||
@@ -102,7 +104,16 @@ def branch_combo(
|
||||
|
||||
name = name.strip() or str(was.get("이름") or source)
|
||||
return _branch(
|
||||
column, version, "일위대가", combo_store.FILE, "담은로직", "로직", items, source, make, name
|
||||
column,
|
||||
version,
|
||||
"일위대가",
|
||||
combo_store.FILE,
|
||||
"담은로직",
|
||||
("로직", "메모"),
|
||||
items,
|
||||
source,
|
||||
make,
|
||||
name,
|
||||
)
|
||||
|
||||
|
||||
@@ -147,5 +158,5 @@ def branch_material_combo(
|
||||
default = " ".join(h for h in store._heads(heads) if h) if heads else column
|
||||
name = name.strip() or str(was.get("이름") or default or column)
|
||||
return _branch(
|
||||
column, version, "자재조합", MATERIAL_FILE, "담은자재", "코드", items, source, make, name
|
||||
column, version, "자재조합", MATERIAL_FILE, "담은자재", ("코드",), items, source, make, name
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user