Class: HrLite::LeaveRequest

Inherits:
ApplicationRecord show all
Includes:
Approvable
Defined in:
app/models/hr_lite/leave_request.rb

Constant Summary collapse

STATUSES =
%w[pending approved rejected cancelled].freeze

Instance Method Summary collapse

Methods included from Approvable

#approval_for, #approval_history, #approval_route, #awaiting?, #pending_approvals, #routed_for_approval?

Instance Method Details

#approve!(actor:, note: nil) ⇒ Object

With a flow configured this is ONE RUNG: the request becomes approved only once the last rung is satisfied. With no flow — or from somebody the flow is not waiting on, such as HR overriding — the first approval settles it, exactly as before.

Returns false (leaving the request pending) when the balance no longer covers it; the re-check runs inside the row lock so two concurrent approvals cannot overdraw one balance.



51
52
53
54
55
# File 'app/models/hr_lite/leave_request.rb', line 51

def approve!(actor:, note: nil)
  return record_routed_decision!(actor, note, :approved) if awaiting?(actor)

  approve_outright!(actor: actor, note: note)
end

#balanceObject



107
108
109
# File 'app/models/hr_lite/leave_request.rb', line 107

def balance
  LeaveBalance.for(user, leave_type, LeaveYear.key_for(start_date))
end

#cancel!(actor:) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'app/models/hr_lite/leave_request.rb', line 74

def cancel!(actor:)
  was_approved = approved?
  transaction do
    self.status = "cancelled"
    self.decided_by_id = actor.id
    self.decided_at = Time.current
    save!
    # Cancelling an APPROVED leave hands the days back to the balance, so
    # it is a quota change as much as a status change.
    audit!("cancelled", actor, was_approved ? "was approved" : nil)
    # And nobody should still be asked to decide a request that has been
    # called off — it would sit in their inbox for ever.
    approval_route.cancel_all!
  end

  Notifications.publish(
    "leave.cancelled",
    title: "#{HrLite.display_name(user)} cancelled #{was_approved ? 'approved ' : ''}leave " \
           "(#{date_range_label})",
    path: "/admin/leave_requests",
    bell_to: HrLite.admin_users
  )
  true
end

#cancellable_by?(actor) ⇒ Boolean

Owner may cancel while pending, or an approved future leave (quota returns automatically because used is computed). Admins may cancel any pending/approved future leave.

Returns:

  • (Boolean)


68
69
70
71
72
# File 'app/models/hr_lite/leave_request.rb', line 68

def cancellable_by?(actor)
  return false unless pending? || (approved? && start_date > Date.current)

  user_id == actor.id || HrLite.admin?(actor) || HrLite.leadership?(actor)
end

#date_range_labelObject



99
100
101
102
103
104
105
# File 'app/models/hr_lite/leave_request.rb', line 99

def date_range_label
  if start_date == end_date
    "#{start_date.strftime('%d %b')}#{half_day ? ' (half day)' : ''}"
  else
    "#{start_date.strftime('%d %b')}#{end_date.strftime('%d %b')}"
  end
end

#paid?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'app/models/hr_lite/leave_request.rb', line 37

def paid?
  leave_type.paid
end

#reject!(actor:, note:) ⇒ Object



57
58
59
60
61
62
63
# File 'app/models/hr_lite/leave_request.rb', line 57

def reject!(actor:, note:)
  return record_routed_decision!(actor, note, :rejected) if awaiting?(actor)

  transition!("rejected", actor, note)
  notify_decision("Leave rejected")
  true
end