diff --git a/app/modules/expense/router.py b/app/modules/expense/router.py index f9e48ef..9dab588 100644 --- a/app/modules/expense/router.py +++ b/app/modules/expense/router.py @@ -402,19 +402,12 @@ async def approved_page(request: Request) -> HTMLResponse: ) -@router.get("/api/approved/export.xlsx") -async def approved_export( - request: Request, - user: dict[str, Any] = Depends(_require_approver), -) -> StreamingResponse: +def _build_approved_xlsx( + items: list[dict[str, Any]], names: dict[str, str] +) -> io.BytesIO: + """승인완료 목록 + 직원별합계 시트 xlsx 바이트 생성.""" from openpyxl import Workbook # 지연 import - store = _store(request) - _require_db_store(store) - year, mon, raw = _parse_month(request) - items = store.list_approved(year=year, month=mon) - names = _name_map(request) - wb = Workbook() ws = wb.active ws.title = "승인완료" @@ -453,6 +446,20 @@ async def approved_export( buf = io.BytesIO() wb.save(buf) buf.seek(0) + return buf + + +@router.get("/api/approved/export.xlsx") +async def approved_export( + request: Request, + user: dict[str, Any] = Depends(_require_approver), +) -> StreamingResponse: + store = _store(request) + _require_db_store(store) + year, mon, raw = _parse_month(request) + items = store.list_approved(year=year, month=mon) + names = _name_map(request) + buf = _build_approved_xlsx(items, names) fname = f"expense_approved_{raw}.xlsx" return StreamingResponse( buf, @@ -470,6 +477,7 @@ async def approved_attachments_zip( store = _store(request) _require_db_store(store) year, mon, raw = _parse_month(request) + items = store.list_approved(year=year, month=mon) atts = store.approved_attachments(year=year, month=mon) names = _name_map(request) upload_root = _upload_dir(request) @@ -495,6 +503,10 @@ async def approved_attachments_zip( buf = io.BytesIO() used: dict[str, int] = {} with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as zf: + # 1) 승인 목록 엑셀 동봉 + xlsx_buf = _build_approved_xlsx(items, names) + zf.writestr(f"승인목록_{raw}.xlsx", xlsx_buf.getvalue()) + # 2) 첨부 파일들 for a in atts: path = _resolve(a) if path is None: