Files
Aislo/resources/tester/test_739_1_alias_central.py
T
eomsangdonandClaude Opus 5.5 b1b9794946 feat(739-1): 별칭 장부 중앙 관리 — 자동 짝 = 마스터(승인) · 이 불러오기에서 이은 짝만 · 회사 · 개인 층 짝 = 내 제안
- 장부 읽는 차례: 자동 정확 열쇠(마스터 · 같은 불러오기 `불러오기` 표시) → 제안 정확 열쇠(`제안` True · 자동 아님) → 품명|단위 느슨
- 만들기 · 단가산출 만들기가 이은 짝에 불러오기 열쇠(`doc_id` 층/주인/HP 키) 남김 · 장부 화면 고침은 그 표시 그대로 둠
- 줄 맞춤: 내 제안 = 숫자 판정 그대로 + 꼬리표 「내 제안」 + `제안`(고르기 창 맨 위 · 한 번 눌러 짝 통째) · 호표 통째 제안 = 체크 안 함
- 장부 화면(회사 · 개인 층) = 「내 제안 목록」 · 승인 칸(대기 · 승인 · 반려 = M01 서명 · 반려 기억) · [삭제] → [거두기] · 마스터 층(M01) 그대로
- M01 별칭 장부 모으기 · 승인 · 반려 길 그대로 · 기존 층 장부 파일 안 지움(제안으로 읽힘)
- 낡은 시험 고침: hopyo ledger(아래 층이 이김 → 마스터만 자동 · 제안 · 승인 상태) · hopyo match(별칭 자동 규칙 = 마스터 층 장부로) · hopyo screen(머리 글 · 거두기 단추)
- 새 시험 test_739_1_alias_central(층 짝 자동 0 · 내 제안 · 이은 짝 → 제안 · M01 후보 · 승인 뒤 자동 · 반려 상태)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 18:40:45 +09:00

148 lines
7.7 KiB
Python

"""별칭 장부 중앙 관리(PLAN 739-1 · `M02_Hopyo_Ledger` · `M02_Hopyo_Line` ·
`M01_MasterData_Alias`) — 자동 짝 = 마스터(승인) · 이 불러오기에서 이은 짝만 · 회사 · 개인 층 짝 =
「내 제안」(자동 0 · 꼬리표 · 고르기 맨 위 `제안`) · 이은 짝 → 층 장부(불러오기 표시) → M01 후보 ·
승인 뒤 다음 불러오기 자동 · 장부 화면 승인 상태(대기 · 승인 · 반려) · master_data 원본 그대로.
층 · storage 는 임시 폴더.
"""
from M01_MasterData import M01_MasterData_Alias as alias
from M02_MasterTemplete import M02_Hopyo_Fit as fit
from M02_MasterTemplete import M02_Hopyo_Ledger as ledger
from M02_MasterTemplete import M02_Hopyo_Store as hs
from M02_MasterTemplete import M02_Template_Layers as layers
# 올리기 길 시험의 `client` 마당(임시 storage · 마스터 층)을 같이 씀
# ruff: noqa: F811
from resources.tester.test_m02_hopyo_excel import URL, _post, client, master_hash # noqa: F401
DIG = {"이름": "구조물터파기(인력100%)", "규격": "토사", "단위": "㎥"}
DIG_KEY = "구조물터파기(인력100%)|토사|m3"
WHO = {"id": 42, "이름": "갑"}
ADMIN = {"id": 1, "이름": "관리자"}
LEDGER = "/api/m02/layers/{}/hopyo-ledger"
FROM_LEDGER = ("별칭", "뺌") # 장부가 자동으로 정한 줄 상태
def _pair(code):
return ledger.check(DIG_KEY, {"갈래": "짝", "짝": [{"로직": code, "배": 1}]})
def _candidate(key, code):
got = [
x
for x in alias.gather()["후보"]
if x["열쇠"] == key and x["종류"] == alias.ALIAS and x["짝"][0]["로직"] == code
]
assert len(got) == 1, got
return got[0]
def test_장부_층_짝은_제안_이_불러오기_짝은_자동_승인_뒤_모두_자동(client):
before = master_hash()
mine = layers.personal_dir(7, 42)
here = ledger.doc_id(mine, "HP-000001")
assert here == "personal/7/42/HP-000001"
ledger.write(mine, {DIG_KEY: _pair("GF000101")}, WHO, "가.xls", here)
got = ledger.recall(DIG, mine, doc=here)
assert (got["층"], got["제안"]) == ("personal", False) # 이 불러오기에서 이은 짝 = 바로 씀
later = ledger.doc_id(mine, "HP-000002") # 다음 불러오기
for doc in (later, None):
got = ledger.recall(DIG, mine, doc=doc)
assert (got["층"], got["짝"][0]["로직"], got["제안"]) == ("personal", "GF000101", True)
ledger.put(mine, {DIG_KEY: {**_pair("GF000101"), "엑셀조항": []}}, WHO) # 장부 화면 고침
assert ledger.read(mine)[DIG_KEY]["불러오기"] == here # 이은 불러오기 표시는 남음
assert [r["상태"] for r in ledger.rows(mine, True)] == ["대기"]
# M01 후보에 보임 → 승인 → 마스터 → 다음 불러오기 · 다른 회사 새 사용자도 자동
sig = _candidate(DIG_KEY, "GF000101")["서명"]
alias.approve(alias.ALIAS, DIG_KEY, sig, ADMIN)
for folder, doc in ((mine, later), (layers.personal_dir(9, 99), None)):
got = ledger.recall(DIG, folder, doc=doc)
assert (got["층"], got["짝"][0]["로직"], got["제안"]) == ("system", "GF000101", False)
assert [(r["층"], r["상태"]) for r in ledger.rows(mine, True)] == [
("personal", "승인"),
("system", "승인"),
]
# 다른 짝 제안 → 반려 = 상태 반려 · 여전히 내 제안(자동 아님)
other = layers.personal_dir(7, 43)
ledger.write(other, {DIG_KEY: _pair("GF000103")}, {"id": 43}, "나.xls")
alias.reject(alias.ALIAS, DIG_KEY, _candidate(DIG_KEY, "GF000103")["서명"], ADMIN)
assert ledger.rows(other, True)[0]["상태"] == "반려"
got = ledger.recall(DIG, other)
assert (got["층"], got["짝"][0]["로직"]) == ("system", "GF000101") # 자동 = 마스터
assert master_hash() == before
def _hopyo(client, no):
res = client.get(f"{URL.format('personal')}/HP-000001/{no}")
assert res.status_code == 200, res.text
return res.json()["호표"]
def _lines(client, no):
return {one["이름"]: one["맞춤"] for one in _hopyo(client, no)["줄"]}
def _auto(client, no):
"""장부가 자동으로 정한 줄 수."""
return sum(1 for m in _lines(client, no).values() if m["상태"] in FROM_LEDGER)
def test_불러오기_내_제안_후보_이은_짝_승인_흐름(client):
before = master_hash()
assert _post(client).status_code == 200
mine = layers.personal_dir(7, 42)
fit.run_job(mine, "HP-000001")
plain = _lines(client, 3)["구조물터파기(인력100%)"]
assert plain["상태"] not in FROM_LEDGER and "제안" not in plain
# 개인 층 장부 짝(옛 층 장부 · 승인 전) = 자동 0 · 꼬리표 「내 제안」 · 고르기 맨 위 `제안`
row = {"갈래": "짝", "짝": [{"로직": "GC000083", "배": 1}]}
res = client.put(LEDGER.format("personal"), json={"줄": {DIG_KEY: row}})
assert res.status_code == 200, res.text
assert _auto(client, 3) == 0
got = _lines(client, 3)["구조물터파기(인력100%)"]
assert (got["상태"], got["체크"]) == (plain["상태"], plain["체크"]) # 숫자 판정 그대로
assert "내 제안" in got["꼬리표"] and "별칭" not in got
assert got["제안"]["짝"][0]["로직"] == "GC000083" and got["제안"]["층"] == "personal"
assert got["제안"]["대상"][0]["로직"] == "GC000083"
# 확인하고 만들기 = 이은 짝 → 이 불러오기 안에서는 바로 자동 · 층 장부(제안)에 불러오기 표시
hopyo = _hopyo(client, 3)
at = next(x["차례"] for x in hopyo["줄"] if x["이름"] == "구조물터파기(인력100%)")
body = {"층": "personal", "키": "HP-000001", "번": 3}
lines = [{"차례": at, "대상": [{"로직": "GC000083", "입력값": {}, "배": 1}]}]
left = client.post(
"/api/m02/layers/personal/hopyo-unlinked", json={**body, "줄": lines}
).json()["남은줄"]
lines += [{"차례": x["차례"], "뺌": "우리에 없음"} for x in left]
res = client.post("/api/m02/layers/personal/hopyo-build", json={**body, "줄": lines})
assert res.status_code == 200, res.text
book = ledger.read(mine)
assert book[DIG_KEY]["불러오기"] == "personal/7/42/HP-000001"
got = _lines(client, 3)["구조물터파기(인력100%)"]
assert got["상태"] == "별칭" and got["별칭"]["층"] == "personal"
# 다음 불러오기(다른 HP) = 승인 전 자동 0
nxt = {k: {**v, "불러오기": "personal/7/42/HP-000009"} for k, v in book.items()}
hs.remember(mine, nxt) # 장부 파일 그대로 — 다른 불러오기에서 이은 짝
assert _auto(client, 3) == 0
# M01 후보에 보임 → 승인 → 다음 불러오기 자동(마스터)
sig = _candidate(DIG_KEY, "GC000083")["서명"]
alias.approve(alias.ALIAS, DIG_KEY, sig, ADMIN)
got = _lines(client, 3)["구조물터파기(인력100%)"]
assert got["상태"] == "별칭" and got["별칭"]["층"] == "system" and "제안" not in got
assert _auto(client, 3) == 1
assert master_hash() == before
def test_화면_내_제안_글():
"""고르기 창 맨 위 「내 제안」(한 번 눌러 짝 통째) · 장부 화면 = 내 제안 목록 · 승인 칸."""
from pathlib import Path
m02 = Path(__file__).resolve().parents[2] / "M02_MasterTemplete"
choose = (m02 / "M02_MasterTemplete_Hopyo_Choose.ts").read_text(encoding="utf-8")
assert choose.index("...(mineRow ? [mineRow] : [])") < choose.index("...sections")
assert '"data-group": "내 제안"' in choose and "mine.짝.map((p)" in choose
rows = (m02 / "M02_MasterTemplete_Hopyo_CheckRows.ts").read_text(encoding="utf-8")
assert '"고르기 · 내 제안"' in rows
book = (m02 / "M02_MasterTemplete_Hopyo_Ledger.ts").read_text(encoding="utf-8")
assert 'MINE_TITLE = "내 제안 목록"' in book and '"승인",' in book
assert "createBadge(r.상태, STATE_TONE[r.상태])" in book