redmine-workflow-engine/app/controllers/issue_workflows_controller.rb
ioresponse e67fb92189 Initial commit: Redmine Workflow Engine Plugin
Features:
- Custom workflow creation per project/tracker
- Step-by-step workflow definition
- Assignees per step (user, role group, department)
- Next/Previous step navigation
- Reject to first step
- Skip step (admin only)
- Step deadline settings
- Workflow dashboard
- Group member selection when proceeding

🤖 Generated with Claude Code
2025-12-23 00:16:43 +09:00

178 lines
5.7 KiB
Ruby

class IssueWorkflowsController < ApplicationController
before_action :find_issue
before_action :find_or_create_workflow_state
def show
@steps = @workflow_state.custom_workflow.workflow_steps.ordered
@current_step = @workflow_state.current_step
end
def next_step
if @workflow_state.can_proceed?(User.current)
selected_assignee_id = params[:assignee_id]
if @workflow_state.proceed!(User.current, selected_assignee_id)
flash[:notice] = '다음 단계로 이동했습니다.'
else
flash[:error] = '다음 단계로 이동할 수 없습니다.'
end
else
flash[:error] = '이 단계를 완료할 권한이 없습니다.'
end
redirect_to issue_path(@issue)
end
def prev_step
if @workflow_state.can_go_back?(User.current)
if @workflow_state.go_back!(User.current)
flash[:notice] = '이전 단계로 되돌렸습니다.'
else
flash[:error] = '이전 단계로 이동할 수 없습니다.'
end
else
flash[:error] = '이전 단계로 되돌릴 권한이 없습니다.'
end
redirect_to issue_path(@issue)
end
def complete
current_step = @workflow_state.current_step
if current_step&.is_end && (User.current.admin? || current_step.assignee?(User.current))
@issue.init_journal(User.current, "워크플로우 완료 처리")
@issue.status_id = 5 # 완료 상태
if @issue.save(validate: false)
@workflow_state.update(completed_at: Time.current, completed_by: User.current)
flash[:notice] = '이슈가 완료 처리되었습니다.'
else
flash[:error] = '완료 처리에 실패했습니다.'
end
else
flash[:error] = '완료 처리 권한이 없습니다.'
end
redirect_to issue_path(@issue)
end
def reject
current_step = @workflow_state.current_step
reason = params[:reason].to_s.strip
unless current_step && !current_step.is_start && (User.current.admin? || current_step.assignee?(User.current))
flash[:error] = '반려 권한이 없습니다.'
redirect_to issue_path(@issue)
return
end
if reason.blank?
flash[:error] = '반려 사유를 입력해주세요.'
redirect_to issue_path(@issue)
return
end
# 항상 최초 단계로 반려
first_step = @workflow_state.custom_workflow.workflow_steps.ordered.first
if first_step
# 이력 남기기
@issue.init_journal(User.current, "[반려] #{current_step.name}#{first_step.name}\n사유: #{reason}")
# 상태 변경 (최초 단계의 상태로)
if first_step.issue_status_id.present?
@issue.status_id = first_step.issue_status_id
end
# 담당자 변경 - 개인 사용자일 때만, 그룹/부서는 미지정
user_assignees = first_step.workflow_step_assignees.where(assignee_type: 'user')
if user_assignees.any?
@issue.assigned_to_id = user_assignees.first.assignee_id
elsif first_step.workflow_step_assignees.any?
@issue.assigned_to_id = nil
end
@issue.save(validate: false)
@workflow_state.update(current_step: first_step, completed_at: nil, completed_by: nil)
flash[:notice] = "#{first_step.name} 단계로 반려되었습니다."
else
flash[:error] = '반려 대상 단계를 찾을 수 없습니다.'
end
redirect_to issue_path(@issue)
end
def skip_step
# 관리자만 단계 건너뛰기 가능
unless User.current.admin?
flash[:error] = '관리자만 단계를 건너뛸 수 있습니다.'
redirect_to issue_path(@issue)
return
end
current_step = @workflow_state.current_step
target_step_id = params[:target_step_id]
reason = params[:reason].to_s.strip
if target_step_id.blank?
flash[:error] = '이동할 단계를 선택해주세요.'
redirect_to issue_path(@issue)
return
end
target_step = WorkflowStep.find_by(id: target_step_id)
if target_step && target_step.custom_workflow_id == @workflow_state.custom_workflow_id
# 이력 남기기
note = "[단계 건너뛰기] #{current_step&.name || '(시작)'}#{target_step.name}"
note += "\n사유: #{reason}" if reason.present?
@issue.init_journal(User.current, note)
# 상태 변경
if target_step.issue_status_id.present?
@issue.status_id = target_step.issue_status_id
end
# 담당자 변경 - 개인 사용자일 때만, 그룹/부서는 미지정
user_assignees = target_step.workflow_step_assignees.where(assignee_type: 'user')
if user_assignees.any?
@issue.assigned_to_id = user_assignees.first.assignee_id
elsif target_step.workflow_step_assignees.any?
@issue.assigned_to_id = nil
end
@issue.save(validate: false)
@workflow_state.update(current_step: target_step, completed_at: nil, completed_by: nil)
flash[:notice] = "#{target_step.name} 단계로 이동했습니다."
else
flash[:error] = '이동할 단계를 찾을 수 없습니다.'
end
redirect_to issue_path(@issue)
end
private
def find_issue
@issue = Issue.find(params[:issue_id])
rescue ActiveRecord::RecordNotFound
render_404
end
def find_or_create_workflow_state
@workflow_state = IssueWorkflowState.find_by(issue_id: @issue.id)
unless @workflow_state
workflow = CustomWorkflow.find_for_issue(@issue)
if workflow
@workflow_state = IssueWorkflowState.create!(
issue: @issue,
custom_workflow: workflow,
current_step: workflow.start_step,
started_at: Time.current
)
else
flash[:warning] = '이 이슈에 적용할 워크플로우가 없습니다.'
redirect_to issue_path(@issue)
end
end
end
end