fix(expense): zip 버튼 라벨 변경 + 경로 폴백/진단 헤더
- "첨부 일괄(zip)" → "전부 다운로드(zip)" - stored_path 깨진 경우 업로드루트/item_id/파일명 으로 폴백 탐색 - X-Attachment-Stats 헤더(total/added/missing)로 빈 zip 원인 진단 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -472,13 +472,33 @@ async def approved_attachments_zip(
|
||||
year, mon, raw = _parse_month(request)
|
||||
atts = store.approved_attachments(year=year, month=mon)
|
||||
names = _name_map(request)
|
||||
upload_root = _upload_dir(request)
|
||||
|
||||
def _resolve(a: dict[str, Any]) -> Path | None:
|
||||
"""stored_path 우선, 없으면 현재 업로드 루트/item_id/파일명 으로 폴백."""
|
||||
raw_path = a.get("stored_path") or ""
|
||||
p = Path(raw_path)
|
||||
if p.exists():
|
||||
return p
|
||||
# DATA_DIR 변경 등으로 절대경로가 깨진 경우 — basename 으로 재구성
|
||||
item_id = a.get("item_id", "")
|
||||
base = os.path.basename(raw_path) or a.get("filename", "")
|
||||
if item_id and base:
|
||||
alt = upload_root / item_id / base
|
||||
if alt.exists():
|
||||
return alt
|
||||
return None
|
||||
|
||||
total = len(atts)
|
||||
added = 0
|
||||
missing = 0
|
||||
buf = io.BytesIO()
|
||||
used: dict[str, int] = {}
|
||||
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||
for a in atts:
|
||||
path = Path(a.get("stored_path", ""))
|
||||
if not path.exists():
|
||||
path = _resolve(a)
|
||||
if path is None:
|
||||
missing += 1
|
||||
continue
|
||||
nm = _display_name(a.get("owner", ""), names)
|
||||
fname = _att_download_name(a.get("uploaded_at"), nm, a.get("filename", ""))
|
||||
@@ -491,12 +511,17 @@ async def approved_attachments_zip(
|
||||
used[fname] = 1
|
||||
arcname = fname
|
||||
zf.write(str(path), arcname=arcname)
|
||||
added += 1
|
||||
buf.seek(0)
|
||||
zipname = f"expense_approved_{raw}.zip"
|
||||
return StreamingResponse(
|
||||
buf,
|
||||
media_type="application/zip",
|
||||
headers={"Content-Disposition": f'attachment; filename="{zipname}"'},
|
||||
headers={
|
||||
"Content-Disposition": f'attachment; filename="{zipname}"',
|
||||
# 진단용: 첨부 총개수 / 담긴 개수 / 디스크에서 못 찾은 개수
|
||||
"X-Attachment-Stats": f"total={total};added={added};missing={missing}",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<button type="submit" class="erp-btn erp-btn-outline">조회</button>
|
||||
</form>
|
||||
<a class="erp-btn erp-btn-primary" href="/expense/api/approved/export.xlsx?month={{ month }}">엑셀 다운</a>
|
||||
<a class="erp-btn erp-btn-outline" href="/expense/api/approved/attachments.zip?month={{ month }}">첨부 일괄(zip)</a>
|
||||
<a class="erp-btn erp-btn-outline" href="/expense/api/approved/attachments.zip?month={{ month }}">전부 다운로드(zip)</a>
|
||||
</div>
|
||||
|
||||
<!-- ── 직원별 합계 ── -->
|
||||
|
||||
Reference in New Issue
Block a user