feat(vacation): 상세 — 승인은 취소처리, 미승인(작성중/제출/반려)은 삭제(hard)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -351,6 +351,23 @@ class VacationDBStore:
|
|||||||
).fetchone()
|
).fetchone()
|
||||||
return self._req_serialize(row)
|
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]]:
|
def list_pending(self) -> list[dict[str, Any]]:
|
||||||
with self._pool.connection() as conn:
|
with self._pool.connection() as conn:
|
||||||
rows = conn.execute(
|
rows = conn.execute(
|
||||||
|
|||||||
@@ -800,3 +800,28 @@ async def cancel(
|
|||||||
except PermissionError as exc:
|
except PermissionError as exc:
|
||||||
raise HTTPException(status_code=403, detail=str(exc))
|
raise HTTPException(status_code=403, detail=str(exc))
|
||||||
return RedirectResponse(url=f"/vacation/{request_id}", status_code=303)
|
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)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% extends "erp_base.html" %}
|
{% extends "erp_base.html" %}
|
||||||
|
|
||||||
{% block head_extra %}<link rel="stylesheet" href="/static/vacation.css?v=20260530d" />{% endblock %}
|
{% block head_extra %}<link rel="stylesheet" href="/static/vacation.css?v=20260530e" />{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="vac">
|
<section class="vac">
|
||||||
@@ -65,11 +65,18 @@
|
|||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if req.status != '취소' and (is_owner or is_admin) %}
|
{% if (is_owner or is_admin) %}
|
||||||
|
{% if req.status == '승인' %}
|
||||||
<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 ('작성중', '제출', '반려') %}
|
||||||
|
<form method="post" action="/vacation/{{ req.id }}/delete" class="vac-inline-form"
|
||||||
|
onsubmit="return confirm('이 휴가 신청을 삭제할까요? (복구 불가)');">
|
||||||
|
<button type="submit" class="erp-btn erp-btn-danger">삭제</button>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if can_edit %}
|
{% if can_edit %}
|
||||||
|
|||||||
Reference in New Issue
Block a user