Class: HrLite::ApprovalRoute

Inherits:
Object
  • Object
show all
Defined in:
app/services/hr_lite/approval_route.rb

Overview

Drives one record through its flow: opens the first rung, advances when a rung is satisfied, and reports when the whole thing is settled.

It decides NOTHING about the subject itself. Approvable owns what "approved" means for a leave request; this class only knows whose turn it is. That split is why adding expenses later needs no change here.

Defined Under Namespace

Classes: Result

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(subject) ⇒ ApprovalRoute

Returns a new instance of ApprovalRoute.



11
12
13
# File 'app/services/hr_lite/approval_route.rb', line 11

def initialize(subject)
  @subject = subject
end

Instance Attribute Details

#subjectObject (readonly)

Returns the value of attribute subject.



15
16
17
# File 'app/services/hr_lite/approval_route.rb', line 15

def subject
  @subject
end

Instance Method Details

#cancel_all!Object



62
63
64
# File 'app/services/hr_lite/approval_route.rb', line 62

def cancel_all!
  pending_rows.update_all(status: "cancelled", decided_at: Time.current) # rubocop:disable Rails/SkipsModelValidations
end

#current_positionObject



42
# File 'app/services/hr_lite/approval_route.rb', line 42

def current_position = pending_rows.minimum(:position)

#decide!(approval, status:, actor:, note: nil) ⇒ Object

Records one decision and works out what it means for the record.

:pending  — the rung still needs somebody
:approved — every rung is satisfied
:rejected — one refusal ends it
:returned — sent back to the requester for correction


50
51
52
53
54
55
56
57
58
59
60
# File 'app/services/hr_lite/approval_route.rb', line 50

def decide!(approval, status:, actor:, note: nil)
  approval.decide!(status: status, actor: actor, note: note)

  case status.to_s
  when "rejected", "returned"
    cancel_remaining!(approval.position)
    Result.new(outcome: status.to_sym, approval: approval)
  else
    advance_from(approval)
  end
end

#flowObject



17
# File 'app/services/hr_lite/approval_route.rb', line 17

def flow = @flow ||= ApprovalFlow.for(subject.class.name)

#open!Object

Opens the first rung that has anybody on it. A rung whose rule resolves to nobody — no manager recorded, say — is SKIPPED rather than left waiting for a person who does not exist.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'app/services/hr_lite/approval_route.rb', line 24

def open!
  return Result.new(outcome: :unrouted) unless routed?

  flow.approval_steps.ordered.each do |step|
    approvers = step.approvers_for(subject)
    next skip!(step) if approvers.empty?

    create_rows(step, approvers)
    return Result.new(outcome: :pending)
  end

  # Every rung skipped: nobody in the flow can decide, so the request
  # carries itself. Better than a request that can never be answered.
  Result.new(outcome: :approved)
end

#pending_rowsObject



40
# File 'app/services/hr_lite/approval_route.rb', line 40

def pending_rows = Approval.pending.where(subject: subject)

#routed?Boolean

Returns:

  • (Boolean)


19
# File 'app/services/hr_lite/approval_route.rb', line 19

def routed? = flow.present?