feat(malaysia): 재고조사에 '이전값 불러오기' 버튼 추가

작성중 재고조사 상세에서 직전 조사의 랙 저장값을 한 번에 불러와 채운다.
사용자는 이어서 수정 후 저장/확정. 직전 조사에 랙 입력이 있을 때만 버튼 노출.

- db.previous_rack_entries: 현재 제외·취소 제외, 랙 있는 가장 최근 조사의
  랙 항목 반환(replace_rack 입력 형식과 호환)
- POST /stocktakes/{id}/rack/load-previous: 이전 랙을 현재 조사로 replace_rack
  적용 후 리다이렉트(화면 복원). 작성중만 허용, 이전값 없으면 400
- 상세 핸들러에 has_prev_rack 플래그, 템플릿에 formaction 버튼(덮어쓰기 confirm)
- i18n '이전값 불러오기'→'Load previous', JS 캐시버스트 v20260615b

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 17:29:54 +09:00
parent 4d05c7fad5
commit 6e32c68590
5 changed files with 67 additions and 2 deletions
+37 -1
View File
@@ -507,6 +507,12 @@ async def stocktake_detail(request: Request, stocktake_id: int) -> HTMLResponse:
rack_by_cell: dict[str, list[dict[str, Any]]] = {}
for e in st.list_rack_entries(stocktake_id=stocktake_id):
rack_by_cell.setdefault(e["cell_code"], []).append(e)
is_draft = head["status"] == "draft"
# 작성중일 때만 '이전값 불러오기' 가능 여부 계산(직전 조사에 랙 입력이 있을 때)
has_prev_rack = bool(
is_draft
and st.previous_rack_entries(warehouse_code=wh, exclude_stocktake_id=stocktake_id)
)
ctx = _base_ctx(request, user, st, wh=wh)
ctx.update(
{
@@ -519,7 +525,8 @@ async def stocktake_detail(request: Request, stocktake_id: int) -> HTMLResponse:
"entered": entered,
"result_rows": computed["rows"],
"missing_bom": computed["missing_bom"],
"is_draft": head["status"] == "draft",
"is_draft": is_draft,
"has_prev_rack": has_prev_rack,
}
)
return render_template(request, "malaysia/stocktake_detail.html", ctx)
@@ -606,6 +613,35 @@ async def stocktake_rack_bulk(
return RedirectResponse(url=f"/malaysia/stocktakes/{stocktake_id}", status_code=303)
@router.post("/stocktakes/{stocktake_id:int}/rack/load-previous")
async def stocktake_rack_load_previous(
request: Request, stocktake_id: int, user: dict[str, Any] = Depends(_require_user)
) -> RedirectResponse:
"""직전 재고조사의 랙 저장값을 현재(작성중) 조사로 불러와 채운다.
이전 랙 항목을 그대로 replace_rack 으로 적용 → 화면에 복원되어 표시된다.
사용자는 이어서 수정 후 저장/확정한다. 현재 입력은 덮어쓰므로 화면에서 confirm.
"""
st = _store(request)
if st is None:
raise HTTPException(status_code=503, detail="malaysia_stock_db 미설정")
head = st.get_stocktake(stocktake_id=stocktake_id, with_lines=False)
if head is None:
raise HTTPException(status_code=404, detail="재고조사를 찾을 수 없습니다.")
if head["status"] != "draft":
raise HTTPException(status_code=400, detail="작성중인 조사만 불러올 수 있습니다.")
entries = st.previous_rack_entries(
warehouse_code=head["warehouse_code"], exclude_stocktake_id=stocktake_id
)
if not entries:
raise HTTPException(status_code=400, detail="불러올 이전 재고조사 랙 데이터가 없습니다.")
try:
st.replace_rack(stocktake_id=stocktake_id, entries=entries)
except (KeyError, ValueError) as exc:
raise HTTPException(status_code=400, detail=str(exc))
return RedirectResponse(url=f"/malaysia/stocktakes/{stocktake_id}", status_code=303)
@router.post("/stocktakes/{stocktake_id:int}/rack/finalize")
async def stocktake_rack_finalize(
request: Request, stocktake_id: int, user: dict[str, Any] = Depends(_require_user)