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:
@@ -4,10 +4,14 @@
|
||||
파일 = 읽은 결과만(원본 엑셀 안 둠) `{키, 파일, 올린때, 올린이, 시트, 호표, 검산}` · 키 `HP-######`
|
||||
(층마다 다음 번호) · 맞춤 기억 = `{줄: {줄 열쇠: {로직?|자재?|빼기?, 입력값, 환산, 확정}}}`.
|
||||
층 종류(`layers.KINDS`) 밖 폴더 — 양식 목록 · 복사 · 프로젝트 씨앗에 안 섞임 · 권한은 길 몫.
|
||||
한시 불러오기(718-1) — 파일에 `지문`(올린 엑셀 sha256) · 목록 = 지문 있는 것(작업 중)만 · 옛 HP 는
|
||||
파일 그대로 목록에서만 숨김 · 끝낸 기록 `실무자료/불러옴.json`
|
||||
`{번, 지문 {지문: {파일, 키, 끝낸때, 만든}}}` · 번 = 낸 키 가장 큰 번(지운 뒤에도 키를 다시 안 씀).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import threading
|
||||
@@ -21,6 +25,7 @@ from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
||||
DIRNAME = "실무자료"
|
||||
MEMORY = "맞춤"
|
||||
GRID = "격자"
|
||||
DONE = "불러옴"
|
||||
NO_GRID = "격자 없음 — 다시 올리면 보임"
|
||||
_KEY = re.compile(r"^HP-(\d{6})$")
|
||||
# ponytail: 프로세스 안 잠금 — 서버를 여럿 띄우면 파일 잠금으로
|
||||
@@ -58,16 +63,33 @@ def brief(doc: dict[str, Any]) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def fingerprint(data: bytes) -> str:
|
||||
"""올린 엑셀 지문 — 같은 파일 다시 올림을 알아봄."""
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
|
||||
def rows(folder: str | Path) -> list[dict[str, Any]]:
|
||||
"""층 실무자료 목록(키 차례)."""
|
||||
"""층 실무자료 목록(키 차례) — 작업 중(지문 있음)만 · 옛 HP 는 숨김."""
|
||||
out = []
|
||||
for path in sorted(_dir(folder).glob("HP-*.json")):
|
||||
doc = _load(path)
|
||||
if isinstance(doc, dict) and _KEY.match(path.stem):
|
||||
out.append(brief(doc))
|
||||
if isinstance(doc, dict) and _KEY.match(path.stem) and doc.get("지문"):
|
||||
out.append({**brief(doc), "지문": doc["지문"]})
|
||||
return out
|
||||
|
||||
|
||||
def done(folder: str | Path) -> dict[str, Any]:
|
||||
"""끝낸 기록 `{번, 지문 {지문: {파일, 키, 끝낸때, 만든}}}`."""
|
||||
doc = _load(_dir(folder) / f"{DONE}.json")
|
||||
doc = doc if isinstance(doc, dict) else {}
|
||||
marks = doc.get("지문")
|
||||
return {"번": int(doc.get("번") or 0), "지문": marks if isinstance(marks, dict) else {}}
|
||||
|
||||
|
||||
def _put_done(folder: str | Path, got: dict[str, Any]) -> None:
|
||||
atomic_write_json(_dir(folder) / f"{DONE}.json", got)
|
||||
|
||||
|
||||
def read(folder: str | Path, key: str) -> dict[str, Any]:
|
||||
doc = _load(_path(folder, key))
|
||||
if not isinstance(doc, dict):
|
||||
@@ -81,25 +103,30 @@ def save(
|
||||
parsed: dict[str, Any],
|
||||
who: Any,
|
||||
grid: dict[str, Any] | None = None,
|
||||
mark: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""읽은 결과(+ 격자) → 새 키로 씀 → 목록 한 줄."""
|
||||
"""읽은 결과(+ 격자) → 새 키로 씀 → 목록 한 줄 · `mark` = 올린 엑셀 지문."""
|
||||
with _LOCK:
|
||||
have = [
|
||||
int(m.group(1)) for p in _dir(folder).glob("HP-*.json") if (m := _KEY.match(p.stem))
|
||||
]
|
||||
key = f"HP-{max(have, default=0) + 1:06d}"
|
||||
log = done(folder)
|
||||
log["번"] = max(*have, log["번"], 0) + 1
|
||||
key = f"HP-{log['번']:06d}"
|
||||
doc = {
|
||||
"키": key,
|
||||
"파일": name,
|
||||
"올린때": utc_now_text(),
|
||||
"올린이": who,
|
||||
**({"지문": mark} if mark else {}),
|
||||
**parsed,
|
||||
}
|
||||
if grid is not None:
|
||||
book = {**grid["책"], "열": key}
|
||||
atomic_write_json(_grid_path(folder, key), {**grid, "책": book})
|
||||
atomic_write_json(_path(folder, key), doc)
|
||||
return brief(doc)
|
||||
_put_done(folder, log)
|
||||
return {**brief(doc), **({"지문": mark} if mark else {})}
|
||||
|
||||
|
||||
def grid(folder: str | Path, key: str) -> dict[str, Any]:
|
||||
@@ -110,11 +137,22 @@ def grid(folder: str | Path, key: str) -> dict[str, Any]:
|
||||
return doc
|
||||
|
||||
|
||||
def delete(folder: str | Path, key: str) -> None:
|
||||
def delete(folder: str | Path, key: str, made: list[str] | None = None) -> None:
|
||||
"""HP · 격자 지움 · 만든 것(`made` SC 키)이 있으면 지문을 끝낸 기록에 남김(다시 올림 막음)."""
|
||||
path = _path(folder, key)
|
||||
with _LOCK:
|
||||
if not path.is_file():
|
||||
doc = _load(path)
|
||||
if not isinstance(doc, dict):
|
||||
raise store.StoreError(404, f"없는 실무자료 「{key}」")
|
||||
if made and doc.get("지문"):
|
||||
log = done(folder)
|
||||
log["지문"][doc["지문"]] = {
|
||||
"파일": doc.get("파일"),
|
||||
"키": key,
|
||||
"끝낸때": utc_now_text(),
|
||||
"만든": made,
|
||||
}
|
||||
_put_done(folder, log)
|
||||
path.unlink()
|
||||
_grid_path(folder, key).unlink(missing_ok=True)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user