Class: HrLite::RegularizationRequest
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- HrLite::RegularizationRequest
- Defined in:
- app/models/hr_lite/regularization_request.rb
Overview
"I forgot to punch — please fix that day." The employee proposes the times; an admin approves, which applies them to the attendance record with the full regularization audit trail (same fields the manual admin fix writes), or rejects with a note.
Defined Under Namespace
Classes: InvalidMerge
Constant Summary collapse
- STATUSES =
%w[pending approved rejected cancelled].freeze
Instance Method Summary collapse
-
#approve!(actor:, note: nil) ⇒ Object
Applies the proposed times to the day's record (creating it if the person never punched at all).
- #cancel!(actor:) ⇒ Object
-
#punch ⇒ Object
Current punch state for the approver's context.
- #reject!(actor:, note:) ⇒ Object
- #times_label ⇒ Object
Instance Method Details
#approve!(actor:, note: nil) ⇒ Object
Applies the proposed times to the day's record (creating it if the person never punched at all). Only the provided times overwrite — a forgot-checkout ticket keeps the genuine GPS check-in untouched. A merge that would produce a nonsense record (checkout before the existing check-in, or a checkout with no check-in at all) raises InvalidMerge with the real story so the admin knows what to fix.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'app/models/hr_lite/regularization_request.rb', line 50 def approve!(actor:, note: nil) transition!("approved", actor, note) do record = AttendanceRecord.find_or_initialize_by(user_id: user_id, date: date) record.check_in_at = check_in_at if check_in_at record.check_out_at = check_out_at if check_out_at if record.check_in_at.nil? raise InvalidMerge, "the day has no check-in — the ticket needs a check-in time too" end record.status = "present" if record.status.blank? record.regularized_by_id = actor.id record.regularized_at = Time.current record.regularization_note = "Ticket ##{id}: #{reason}" raise InvalidMerge, record.errors..to_sentence unless record.valid? record.save! AuditLog.create!( actor: actor, action: "regularize", subject_type: record.class.name, subject_id: record.id, audited_changes: { "date" => record.date.to_s, "ticket" => id, "note" => reason } ) end Notifications.publish( "regularization.approved", title: "Attendance fixed for #{date.strftime('%d %b')} (#{times_label})", body: decision_note.presence, path: "/regularization_requests", bell_to: [ user ], email_to: [ user ] ) true end |
#cancel!(actor:) ⇒ Object
95 96 97 98 99 100 101 102 103 104 |
# File 'app/models/hr_lite/regularization_request.rb', line 95 def cancel!(actor:) transition!("cancelled", actor, nil) Notifications.publish( "regularization.cancelled", title: "#{HrLite.display_name(user)} cancelled a regularization ticket (#{date.strftime('%d %b')})", path: "/admin/regularization_requests", bell_to: HrLite.admin_users ) true end |
#punch ⇒ Object
Current punch state for the approver's context.
38 39 40 |
# File 'app/models/hr_lite/regularization_request.rb', line 38 def punch AttendanceRecord.find_by(user_id: user_id, date: date) end |
#reject!(actor:, note:) ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 |
# File 'app/models/hr_lite/regularization_request.rb', line 83 def reject!(actor:, note:) transition!("rejected", actor, note) Notifications.publish( "regularization.rejected", title: "Regularization rejected — #{date.strftime('%d %b')}", body: decision_note.presence, path: "/regularization_requests", bell_to: [ user ], email_to: [ user ] ) true end |
#times_label ⇒ Object
33 34 35 |
# File 'app/models/hr_lite/regularization_request.rb', line 33 def times_label [ check_in_at&.strftime("%H:%M"), check_out_at&.strftime("%H:%M") ].compact.join(" – ").presence || "—" end |