diff --git a/app/modules/vacation/db.py b/app/modules/vacation/db.py
index b2c92b8..cdd7eca 100644
--- a/app/modules/vacation/db.py
+++ b/app/modules/vacation/db.py
@@ -351,6 +351,23 @@ class VacationDBStore:
).fetchone()
return self._req_serialize(row)
+ def hard_delete(self, *, request_id: str, user_email: str, is_admin: bool) -> None:
+ """완전 삭제. 승인 전(작성중/제출/반려)만 허용. owner 또는 admin."""
+ user_email = user_email.lower().strip()
+ current = self.get_request(request_id=request_id)
+ if not current:
+ raise KeyError(request_id)
+ if not is_admin and current["owner"] != user_email:
+ raise PermissionError("본인 신청만 삭제할 수 있습니다.")
+ if current["status"] == "승인":
+ raise ValueError("승인된 휴가는 삭제할 수 없습니다. 취소 처리하세요.")
+ with self._pool.connection() as conn:
+ cur = conn.execute(
+ "DELETE FROM vacation_requests WHERE id = %s", (request_id,)
+ )
+ if cur.rowcount == 0:
+ raise KeyError(request_id)
+
def list_pending(self) -> list[dict[str, Any]]:
with self._pool.connection() as conn:
rows = conn.execute(
diff --git a/app/modules/vacation/router.py b/app/modules/vacation/router.py
index a4601a3..c20fda1 100644
--- a/app/modules/vacation/router.py
+++ b/app/modules/vacation/router.py
@@ -800,3 +800,28 @@ async def cancel(
except PermissionError as exc:
raise HTTPException(status_code=403, detail=str(exc))
return RedirectResponse(url=f"/vacation/{request_id}", status_code=303)
+
+
+@router.post("/{request_id}/delete")
+async def delete(
+ request: Request,
+ request_id: str,
+ user: dict[str, Any] = Depends(_require_user),
+) -> RedirectResponse:
+ """완전 삭제 — 승인 전(작성중/제출/반려)만. 달력으로 복귀."""
+ from app.store import is_admin # noqa: WPS433
+
+ store = _store(request)
+ if store is None:
+ raise HTTPException(status_code=503, detail="vacation_db 미설정")
+ try:
+ store.hard_delete(
+ request_id=request_id, user_email=user["email"], is_admin=is_admin(user)
+ )
+ except KeyError:
+ raise HTTPException(status_code=404, detail="휴가 신청을 찾을 수 없습니다.")
+ except PermissionError as exc:
+ raise HTTPException(status_code=403, detail=str(exc))
+ except ValueError as exc:
+ raise HTTPException(status_code=409, detail=str(exc))
+ return RedirectResponse(url="/vacation/", status_code=303)
diff --git a/app/modules/vacation/templates/vacation/detail.html b/app/modules/vacation/templates/vacation/detail.html
index 0c826c6..89c0b40 100644
--- a/app/modules/vacation/templates/vacation/detail.html
+++ b/app/modules/vacation/templates/vacation/detail.html
@@ -1,6 +1,6 @@
{% extends "erp_base.html" %}
-{% block head_extra %}{% endblock %}
+{% block head_extra %}{% endblock %}
{% block content %}
@@ -65,11 +65,18 @@
{% endif %}
- {% if req.status != '취소' and (is_owner or is_admin) %}
-
+ {% if (is_owner or is_admin) %}
+ {% if req.status == '승인' %}
+
+ {% elif req.status in ('작성중', '제출', '반려') %}
+
+ {% endif %}
{% endif %}
{% if can_edit %}