feat(expense): 승인완료 메뉴 — 전 직원 월별 + 엑셀/첨부 zip
- /expense/approved: 승인자/관리자 전용, 월 선택 + 전 직원 승인완료 항목 - 직원별 승인 금액 합계표 + 총합 - 엑셀 다운(리스트 + 직원별합계 시트) - 첨부 일괄 zip: 파일명 yy년 mm월 dd일(요일)_이름.확장자 (업로드일 기준) - store: APPROVED_STATUSES(승인,정산완료) / db: list_approved, approved_attachments Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ from psycopg_pool import ConnectionPool
|
||||
|
||||
from app.timezone import KST
|
||||
|
||||
from .store import CATEGORIES, METHODS, STATUSES
|
||||
from .store import APPROVED_STATUSES, CATEGORIES, METHODS, STATUSES
|
||||
|
||||
|
||||
class ExpenseDBStore:
|
||||
@@ -370,6 +370,46 @@ class ExpenseDBStore:
|
||||
out["size_bytes"] = int(out.get("size_bytes", 0))
|
||||
return out
|
||||
|
||||
# ── 승인완료 (월별, 전 직원) ──
|
||||
def list_approved(self, *, year: int, month: int) -> list[dict[str, Any]]:
|
||||
"""해당 월(spent_at)의 승인완료 항목 — 전 직원."""
|
||||
with self._pool.connection() as conn:
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT * FROM expense_items
|
||||
WHERE status = ANY(%s)
|
||||
AND EXTRACT(YEAR FROM spent_at) = %s
|
||||
AND EXTRACT(MONTH FROM spent_at) = %s
|
||||
ORDER BY owner ASC, spent_at ASC, created_at ASC
|
||||
""",
|
||||
(list(APPROVED_STATUSES), year, month),
|
||||
).fetchall()
|
||||
return [self._serialize(r) for r in rows]
|
||||
|
||||
def approved_attachments(
|
||||
self, *, year: int, month: int
|
||||
) -> list[dict[str, Any]]:
|
||||
"""해당 월 승인완료 항목의 첨부 — zip 다운로드용.
|
||||
|
||||
uploaded_at(datetime), spent_at(date) 를 가공 없이 반환(파일명 생성용).
|
||||
"""
|
||||
with self._pool.connection() as conn:
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT a.id, a.item_id, a.owner, a.kind, a.filename,
|
||||
a.stored_path, a.content_type, a.uploaded_at,
|
||||
i.spent_at
|
||||
FROM expense_attachments a
|
||||
JOIN expense_items i ON i.id = a.item_id
|
||||
WHERE i.status = ANY(%s)
|
||||
AND EXTRACT(YEAR FROM i.spent_at) = %s
|
||||
AND EXTRACT(MONTH FROM i.spent_at) = %s
|
||||
ORDER BY a.owner ASC, a.uploaded_at ASC
|
||||
""",
|
||||
(list(APPROVED_STATUSES), year, month),
|
||||
).fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
# ── 집계 (월별) ──
|
||||
def monthly_summary(
|
||||
self, *, email: str, year: int
|
||||
|
||||
Reference in New Issue
Block a user