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
61 lines
1.7 KiB
Ruby
61 lines
1.7 KiB
Ruby
class WorkflowStep < ActiveRecord::Base
|
|
belongs_to :custom_workflow
|
|
belongs_to :issue_status, optional: true
|
|
has_many :workflow_step_assignees, dependent: :destroy
|
|
has_many :issue_workflow_states, foreign_key: :current_step_id
|
|
|
|
validates :name, presence: true
|
|
validates :custom_workflow_id, presence: true
|
|
|
|
scope :ordered, -> { order(:position) }
|
|
|
|
before_create :set_position
|
|
|
|
def next_step
|
|
custom_workflow.workflow_steps.where('position > ?', position).order(:position).first
|
|
end
|
|
|
|
def prev_step
|
|
custom_workflow.workflow_steps.where('position < ?', position).order(position: :desc).first
|
|
end
|
|
|
|
def first_step?
|
|
is_start || position == custom_workflow.workflow_steps.minimum(:position)
|
|
end
|
|
|
|
def last_step?
|
|
is_end || position == custom_workflow.workflow_steps.maximum(:position)
|
|
end
|
|
|
|
# 이 단계의 모든 담당자 (사람, 역할그룹 멤버, 부서원 포함)
|
|
def all_assignee_users
|
|
users = []
|
|
workflow_step_assignees.each do |assignee|
|
|
case assignee.assignee_type
|
|
when 'user'
|
|
user = User.find_by(id: assignee.assignee_id)
|
|
users << user if user
|
|
when 'role_group'
|
|
role_group = RoleGroup.find_by(id: assignee.assignee_id)
|
|
users.concat(role_group.users.to_a) if role_group
|
|
when 'department'
|
|
department = Department.find_by(id: assignee.assignee_id)
|
|
users.concat(department.users.to_a) if department
|
|
end
|
|
end
|
|
users.uniq
|
|
end
|
|
|
|
# 특정 사용자가 이 단계의 담당자인지 확인
|
|
def assignee?(user)
|
|
all_assignee_users.include?(user)
|
|
end
|
|
|
|
private
|
|
|
|
def set_position
|
|
max_position = custom_workflow.workflow_steps.maximum(:position) || -1
|
|
self.position = max_position + 1
|
|
end
|
|
end
|