Class: HrLite::Expense

Inherits:
ApplicationRecord show all
Includes:
Approvable, Audited, EncryptedMoney
Defined in:
app/models/hr_lite/expense.rb

Overview

A claim. Routed through the approval engine rather than growing a fifth approve/reject of its own — configure a flow for it and it gets manager then finance for free.

Constant Summary collapse

STATUSES =
%w[draft submitted approved rejected reimbursed cancelled].freeze

Constants included from Audited

Audited::REDACTED, Audited::SKIPPED_ATTRIBUTES

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



40
41
42
43
44
# File 'app/models/hr_lite/expense.rb', line 40

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

  settle!("approved", actor, note)
end

#reimburse!(actor:, period_month:) ⇒ Object

Paid out with a payroll month. Kept separate from approved because agreeing to pay somebody and actually paying them are different days, and the person waiting cares about the second one.

Raises:

  • (ActiveRecord::RecordInvalid.new(self))


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'app/models/hr_lite/expense.rb', line 56

def reimburse!(actor:, period_month:)
  raise ActiveRecord::RecordInvalid.new(self), "not approved" unless approved?

  transaction do
    update!(status: "reimbursed", reimbursed_in: period_month.beginning_of_month)
    AuditLog.record!(action: "expense.reimbursed", subject: self, actor: actor,
                     changes: { "employee" => HrLite.display_name(user),
                                "period" => period_month.strftime("%B %Y") })
  end
  Notifications.publish(
    "expense.reimbursed",
    title: "Your #{category.name} claim was reimbursed with #{period_month.strftime('%B %Y')} payroll",
    path: "/expenses", bell_to: [ user ], email_to: [ user ]
  )
  true
end

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

Raises:

  • (ArgumentError)


46
47
48
49
50
51
# File 'app/models/hr_lite/expense.rb', line 46

def reject!(actor:, note:)
  raise ArgumentError, "a rejection needs a reason" if note.blank?
  return record_routed!(actor, note, :rejected) if awaiting?(actor)

  settle!("rejected", actor, note)
end

#submit!(actor:) ⇒ Object

Raises:

  • (ActiveRecord::RecordInvalid.new(self))


32
33
34
35
36
37
38
# File 'app/models/hr_lite/expense.rb', line 32

def submit!(actor:)
  raise ActiveRecord::RecordInvalid.new(self), "not a draft" unless draft? || rejected?

  update!(status: "submitted", submitted_at: Time.current)
  notify_deciders
  true
end