Class: HrLite::ApprovalRoute
- Inherits:
-
Object
- Object
- HrLite::ApprovalRoute
- 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
-
#subject ⇒ Object
readonly
Returns the value of attribute subject.
Instance Method Summary collapse
- #cancel_all! ⇒ Object
- #current_position ⇒ Object
-
#decide!(approval, status:, actor:, note: nil) ⇒ Object
Records one decision and works out what it means for the record.
- #flow ⇒ Object
-
#initialize(subject) ⇒ ApprovalRoute
constructor
A new instance of ApprovalRoute.
-
#open! ⇒ Object
Opens the first rung that has anybody on it.
- #pending_rows ⇒ Object
- #routed? ⇒ Boolean
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
#subject ⇒ Object (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_position ⇒ Object
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 |
#flow ⇒ Object
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_rows ⇒ Object
40 |
# File 'app/services/hr_lite/approval_route.rb', line 40 def pending_rows = Approval.pending.where(subject: subject) |
#routed? ⇒ Boolean
19 |
# File 'app/services/hr_lite/approval_route.rb', line 19 def routed? = flow.present? |