feat:결재 워크플로우 구현 (Phase 2.3)
- API: submit(DRAFT→PENDING), approve(단계별 승인), reject(반려 사유 필수) - 전체 승인 완료 시 자동 APPROVED, 재제출 시 결재라인 초기화 - edit: 결재 제출 버튼 + submitForApproval() JS - show: 승인/반려 버튼, 반려 사유 모달, 결재 현황 속성 수정, 상태 배지 CSS - 라우트: submit/approve/reject 3개 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -215,6 +215,151 @@ public function destroy(int $id): JsonResponse
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 결재 제출 (DRAFT → PENDING)
|
||||
*/
|
||||
public function submit(int $id): JsonResponse
|
||||
{
|
||||
$tenantId = session('selected_tenant_id');
|
||||
$userId = auth()->id();
|
||||
|
||||
$document = Document::where('tenant_id', $tenantId)->findOrFail($id);
|
||||
|
||||
if ($document->status !== Document::STATUS_DRAFT && $document->status !== Document::STATUS_REJECTED) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '작성중 또는 반려 상태의 문서만 제출할 수 있습니다.',
|
||||
], 422);
|
||||
}
|
||||
|
||||
$document->update([
|
||||
'status' => Document::STATUS_PENDING,
|
||||
'submitted_at' => now(),
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
|
||||
// 결재라인 상태 초기화 (반려 후 재제출 시)
|
||||
$document->approvals()->update([
|
||||
'status' => DocumentApproval::STATUS_PENDING,
|
||||
'comment' => null,
|
||||
'acted_at' => null,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '결재가 제출되었습니다.',
|
||||
'data' => $document->fresh(['approvals']),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 결재 승인 (단계별)
|
||||
*/
|
||||
public function approve(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$tenantId = session('selected_tenant_id');
|
||||
$userId = auth()->id();
|
||||
|
||||
$document = Document::where('tenant_id', $tenantId)->findOrFail($id);
|
||||
|
||||
if ($document->status !== Document::STATUS_PENDING) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '결재중 상태의 문서만 승인할 수 있습니다.',
|
||||
], 422);
|
||||
}
|
||||
|
||||
// 현재 단계의 미처리 결재 찾기
|
||||
$pendingApproval = $document->approvals()
|
||||
->where('status', DocumentApproval::STATUS_PENDING)
|
||||
->orderBy('step')
|
||||
->first();
|
||||
|
||||
if (! $pendingApproval) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '승인 대기 중인 결재 단계가 없습니다.',
|
||||
], 422);
|
||||
}
|
||||
|
||||
$pendingApproval->update([
|
||||
'user_id' => $userId,
|
||||
'status' => DocumentApproval::STATUS_APPROVED,
|
||||
'comment' => $request->input('comment'),
|
||||
'acted_at' => now(),
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
|
||||
// 모든 결재가 완료되었는지 확인
|
||||
$remainingPending = $document->approvals()
|
||||
->where('status', DocumentApproval::STATUS_PENDING)
|
||||
->count();
|
||||
|
||||
if ($remainingPending === 0) {
|
||||
$document->update([
|
||||
'status' => Document::STATUS_APPROVED,
|
||||
'completed_at' => now(),
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => $remainingPending === 0 ? '최종 승인되었습니다.' : '승인되었습니다. (다음 단계 대기)',
|
||||
'data' => $document->fresh(['approvals']),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 결재 반려
|
||||
*/
|
||||
public function reject(Request $request, int $id): JsonResponse
|
||||
{
|
||||
$tenantId = session('selected_tenant_id');
|
||||
$userId = auth()->id();
|
||||
|
||||
$request->validate([
|
||||
'comment' => 'required|string|max:500',
|
||||
]);
|
||||
|
||||
$document = Document::where('tenant_id', $tenantId)->findOrFail($id);
|
||||
|
||||
if ($document->status !== Document::STATUS_PENDING) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => '결재중 상태의 문서만 반려할 수 있습니다.',
|
||||
], 422);
|
||||
}
|
||||
|
||||
// 현재 단계 결재에 반려 기록
|
||||
$pendingApproval = $document->approvals()
|
||||
->where('status', DocumentApproval::STATUS_PENDING)
|
||||
->orderBy('step')
|
||||
->first();
|
||||
|
||||
if ($pendingApproval) {
|
||||
$pendingApproval->update([
|
||||
'user_id' => $userId,
|
||||
'status' => DocumentApproval::STATUS_REJECTED,
|
||||
'comment' => $request->input('comment'),
|
||||
'acted_at' => now(),
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
$document->update([
|
||||
'status' => Document::STATUS_REJECTED,
|
||||
'completed_at' => now(),
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '문서가 반려되었습니다.',
|
||||
'data' => $document->fresh(['approvals']),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 문서 데이터 저장 (기본필드 + 섹션 테이블 데이터)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user