feat(718-1): 일위대가 불러오기 = 한시 마법사 — 결과 층 고름 · [끝내기] 때 올린 파일 지움 · 같은 엑셀 겹침 막음

- 좌측 「일위대가 실무자료」 → 「일위대가 불러오기」(locale M02_HopyoImport) · 옛 파일 목록 걷고 [불러오기] → 본 칸 마법사(새 M02_MasterTemplete_Hopyo_Wizard.ts)
- 마법사 = ① 결과 층(쓸 수 있는 층만 · 기본 개인) · 결과 체크(일위대가 · 단가산출은 715-2 뒤) · 엑셀 고르기 · 작업 중 이어서 → ② 엑셀 보기 창(모두 고정으로 들여오기 · 구조물 조합으로 그대로) → ③ 끝내기
- 서버: 올림 지문(sha256) · 작업 중 같은 엑셀 = 이어서 · 끝낸 같은 엑셀 409 · 지우기 = 끝내기(HP · 격자 · 맞춤셈 캐시 지움 · 만든 일위대가 있으면 지문 기록 · 별칭 장부 남음) · HP 번 다시 안 씀 · 목록 = 지문 있는 것만(옛 HP · 붙여넣기 HP 파일 그대로 숨김)
- 시험: 새 지킴 test_718_1_hopyo_import(임시 storage) · 낡은 시험 고침 — 같은 엑셀 다시 올림이 새 키를 내던 가정(excel · grid · flow) · 붙여넣기 HP 목록 가정(705_2) · 좌측 판 글 대조(screen)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-01 15:08:17 +09:00
co-authored by Claude Opus 5.5
parent 9827926a20
commit f49b55a3d8
11 changed files with 421 additions and 148 deletions
+35 -5
View File
@@ -6,7 +6,9 @@
사전조합 나무 자유 폴더(158-1 · `M02_Precombo_Folders` · 읽기 = 층 읽기 · 고침 = 층 쓰기) +
일위대가 실무자료(324 · `M02_Hopyo_*` · 올리기 · 지우기 = 층 쓰기 · 목록 · 읽기 = 층 읽기) ·
338 = 확인한 줄만 만들기(몸 없음 400 · 옛 즉시 확정 길 없앰) · 별칭 장부 보기 · 고치기 ·
올린 뒤 맞춤 뒤 셈(`M02_Hopyo_Fit.ensure`) · 시동 때 우리 지문 데움(`M02_Hopyo_Ours.warm`).
올린 뒤 맞춤 뒤 셈(`M02_Hopyo_Fit.ensure`) · 시동 때 우리 지문 데움(`M02_Hopyo_Ours.warm`) ·
718-1 한시 불러오기 = 올림 지문(끝낸 같은 엑셀 409 · 작업 중 같은 엑셀 = 그 파일 `이어서`) ·
지우기 = [끝내기](HP · 격자 · 맞춤셈 캐시 지움 · 만든 일위대가가 있으면 지문 기록 · 별칭 장부 남음).
층 권한 = `Router_Items._root`(`M02_Layer_Access` 한 벌).
⚠ 등록은 `main.py`(로그인만).
"""
@@ -198,6 +200,16 @@ def _who(session: Session) -> dict[str, Any]:
def _upload(name: str, data: bytes, who: dict[str, Any]) -> dict[str, Any]:
mark = hopyo_store.fingerprint(data)
if old := hopyo_store.done(store.root())["지문"].get(mark):
made = len(old.get("만든") or [])
when = str(old.get("끝낸때") or "")[:10]
raise store.StoreError(
409,
f"이미 불러온 엑셀 「{old.get('파일')}」({when} · 일위대가 {made}) — 다시 만들지 않음",
)
if same := next((r for r in hopyo_store.rows(store.root()) if r.get("지문") == mark), None):
return {**same, "이어서": True}
try:
parsed = hopyo_excel.read_book(name, data)
except hopyo_excel.ExcelError as error:
@@ -206,7 +218,7 @@ def _upload(name: str, data: bytes, who: dict[str, Any]) -> dict[str, Any]:
grid = hopyo_grid.read(name, data, parsed)
except Exception: # 격자는 보기용 덤 — 못 만들어도 올리기는 됨(보기 창 404)
grid = None
row = hopyo_store.save(store.root(), name, parsed, who, grid)
row = hopyo_store.save(store.root(), name, parsed, who, grid, mark)
if (ensure := _later("M02_Hopyo_Fit", "ensure")) is not None:
ensure(store.root(), row["키"]) # 맞춤 뒤 셈(일감 줄 · 화면 안 기다림)
return row
@@ -441,10 +453,28 @@ def hopyo_ledger_write(
def hopyo_delete(
layer: Layer, key: str, owner: str | None = None, session: Session = Depends(verify_session)
) -> dict:
"""실무자료 지우기(만든 사전조합 · 맞춤 기억은 그대로)."""
"""실무자료 지우기 = 불러오기 [끝내기](718-1) — HP · 격자 · 맞춤셈 캐시 지움 · 만든 일위대가
(이 층 확인된 본뜬 「키 제N호표」)는 그대로 · 있으면 지문 기록(같은 엑셀 다시 올림 막음) ·
별칭 장부 그대로 → `{지움, 만든}`."""
folder = _root(session, layer, owner, write=True)
_call(folder, hopyo_store.delete, folder, key)
return {"지움": key}
return _call(folder, _finish, folder, key)
def _finish(folder: Path, key: str) -> dict[str, Any]:
head = f"{key} 제"
made = sorted(
{sc for mark, sc in hopyo_build.confirmed(folder).items() if mark.startswith(head)}
)
if (cache_path := _later("M02_Hopyo_Fit", "cache_path")) is not None:
try:
got = cache_path(folder, key)
except (OSError, store.StoreError):
got = None
# ponytail: 뒤 셈이 도는 중이면 끝낸 뒤 캐시를 다시 쓸 수 있음 — tmp 캐시라 둠
for old in got.parent.glob(f"{'_'.join(got.name.split('_')[:2])}_*.json") if got else []:
old.unlink(missing_ok=True)
hopyo_store.delete(folder, key, made)
return {"지움": key, "만든": len(made)}
class PasteBody(_Strict):