feat(vacation): 관리자는 모든 상태(승인/취소 포함) 휴가 삭제 가능

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-05-30 21:27:10 +09:00
parent cb43fe1257
commit e2c6a50b46
2 changed files with 31 additions and 18 deletions
+10 -5
View File
@@ -352,15 +352,20 @@ class VacationDBStore:
return self._req_serialize(row) return self._req_serialize(row)
def hard_delete(self, *, request_id: str, user_email: str, is_admin: bool) -> None: def hard_delete(self, *, request_id: str, user_email: str, is_admin: bool) -> None:
"""완전 삭제. 승인 전(작성중/제출/반려)만 허용. owner 또는 admin.""" """완전 삭제.
- 관리자(is_admin): 모든 상태 삭제 가능.
- 일반 사용자: 본인 + 승인 전(작성중/제출/반려)만. 승인/취소 건은 불가.
"""
user_email = user_email.lower().strip() user_email = user_email.lower().strip()
current = self.get_request(request_id=request_id) current = self.get_request(request_id=request_id)
if not current: if not current:
raise KeyError(request_id) raise KeyError(request_id)
if not is_admin and current["owner"] != user_email: if not is_admin:
raise PermissionError("본인 신청만 삭제할 수 있습니다.") if current["owner"] != user_email:
if current["status"] == "승인": raise PermissionError("본인 신청만 삭제할 수 있습니다.")
raise ValueError("승인된 휴가는 삭제할 수 없습니다. 취소 처리하세요.") if current["status"] not in ("작성중", "제출", "반려"):
raise ValueError("승인/취소된 휴가는 삭제할 수 없습니다. (관리자 문의)")
with self._pool.connection() as conn: with self._pool.connection() as conn:
cur = conn.execute( cur = conn.execute(
"DELETE FROM vacation_requests WHERE id = %s", (request_id,) "DELETE FROM vacation_requests WHERE id = %s", (request_id,)
@@ -1,6 +1,6 @@
{% extends "erp_base.html" %} {% extends "erp_base.html" %}
{% block head_extra %}<link rel="stylesheet" href="/static/vacation.css?v=20260530i" />{% endblock %} {% block head_extra %}<link rel="stylesheet" href="/static/vacation.css?v=20260530j" />{% endblock %}
{% block content %} {% block content %}
<section class="vac"> <section class="vac">
@@ -65,18 +65,26 @@
</form> </form>
{% endif %} {% endif %}
{% if (is_owner or is_admin) %} {# 승인 건: 취소처리(owner/admin). 미승인: 삭제(owner/admin). 관리자는 모든 상태 삭제 가능. #}
{% if req.status == '승인' %} {% if req.status == '승인' and (is_owner or is_admin) %}
<form method="post" action="/vacation/{{ req.id }}/cancel" class="vac-inline-form" <form method="post" action="/vacation/{{ req.id }}/cancel" class="vac-inline-form"
onsubmit="return confirm('승인된 휴가를 취소 처리할까요?');"> onsubmit="return confirm('승인된 휴가를 취소 처리할까요?');">
<button type="submit" class="erp-btn erp-btn-outline">취소처리</button> <button type="submit" class="erp-btn erp-btn-outline">취소처리</button>
</form> </form>
{% elif req.status in ('작성중', '제출', '반려') %} {% endif %}
<form method="post" action="/vacation/{{ req.id }}/delete" class="vac-inline-form"
onsubmit="return confirm('이 휴가 신청을 삭제할까요? (복구 불가)');"> {% if req.status in ('작성중', '제출', '반려') and (is_owner or is_admin) %}
<button type="submit" class="erp-btn erp-btn-danger">삭제</button> <form method="post" action="/vacation/{{ req.id }}/delete" class="vac-inline-form"
</form> onsubmit="return confirm('이 휴가 신청을 삭제할까요? (복구 불가)');">
{% endif %} <button type="submit" class="erp-btn erp-btn-danger">삭제</button>
</form>
{% endif %}
{% if is_admin and req.status in ('승인', '취소') %}
<form method="post" action="/vacation/{{ req.id }}/delete" class="vac-inline-form"
onsubmit="return confirm('[관리자] 이 휴가({{ req.status }})를 완전 삭제할까요? (복구 불가)');">
<button type="submit" class="erp-btn erp-btn-danger">삭제</button>
</form>
{% endif %} {% endif %}
{% if can_edit %} {% if can_edit %}