hr_lite 0.26.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54c475874de00a0db443998c37e4caeb3340e202584e094db29ef423c4902698
4
- data.tar.gz: 849526338af6b16a5648a5163d140f0cda40b2fa3c34ef2a63a3d2f454761132
3
+ metadata.gz: 8d6e999438a679338ca82e170c4e71ac3519476913ce34b86d5783c3a0f97671
4
+ data.tar.gz: 9a3ef8a6d6a6451f0563ff0f99979460d958e3d47f594d0e6de3b916cc4e8b41
5
5
  SHA512:
6
- metadata.gz: 38bf1cd87f1e283d7e8a54e60a18a19020fae7ff52feca24941f94dc40673c29d3a08a99d8c82699353f9958a99ffaf39ab8ae0a6c2e5e237ee1d96a567ae0c7
7
- data.tar.gz: 390843351f21b51a9f2f17f1159214035349ecf8a689722d8dd429b803775715b322d6914fc251bb1808ad03c09c569f55beb0c85b634de8fefa41069b6317f1
6
+ metadata.gz: 953c47cc46554a8e953f0d125c5878d1d5b03344673f0e706d4c11718a410157dce3652cc3e0cbf414bd88989c13ae3c55f5d09b6fbc885ceb6447672a703583
7
+ data.tar.gz: ccaae3351ea83e10bb2b25c46966713a9cfad1a98909b0409ec286a9e64644293794675fb4c0ae5a9adac891a79546ac6929f996eb4a5f61c57a0f0b4d2c9cf7
data/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.27.0] - 2026-10-10
11
+
12
+ - HR and admins can fix leave they recorded (type, dates, half day) at any time, past dates included, without cancelling it. A reason is required; it is kept as the decision note and in the audit log (`leave.corrected`), and the balance and loss-of-pay split are worked out again.
13
+
10
14
  ## [0.26.0] - 2026-10-10
11
15
 
12
16
  Two migrations: `hr_lite_ca_reviews`, and a data migration creating the CA role and giving Super Admin the new `payroll.verify` permission. Schedule `CaReviewReminderJob` weekly and `CaReviewOverdueJob` on 31 March.
@@ -37,6 +37,23 @@ module HrLite
37
37
  render :new, status: :unprocessable_entity
38
38
  end
39
39
 
40
+ # Leave HR recorded is fixed in place, any time, with a reason.
41
+ def edit
42
+ @request = find_recorded
43
+ end
44
+
45
+ def update
46
+ @request = find_recorded
47
+ reason = params[:correction_reason].to_s.strip
48
+ @request.errors.add(:base, "A reason is required to fix this leave") if reason.blank?
49
+ attrs = params.require(:leave_request).permit(:leave_type_id, :start_date, :end_date, :half_day_part)
50
+ if reason.present? && @request.correct!(actor: hr_current_user, attrs: attrs, reason: reason)
51
+ return redirect_to(admin_leave_request_path(@request), notice: "Leave fixed.")
52
+ end
53
+
54
+ render :edit, status: :unprocessable_entity
55
+ end
56
+
40
57
  def approve
41
58
  request = find_decidable
42
59
  if request.approve!(actor: hr_current_user, note: params[:decision_note].presence)
@@ -91,6 +108,8 @@ module HrLite
91
108
 
92
109
  def find_decidable = decidable.find(params[:id])
93
110
 
111
+ def find_recorded = decidable.approved.where.not(created_by_id: nil).where("created_by_id <> user_id").find(params[:id])
112
+
94
113
  def recordable = hr_scope(EmployeeProfile.includes(:user), "leave.approve").where.not(user_id: hr_current_user.id)
95
114
  end
96
115
  end
@@ -123,6 +123,24 @@ module HrLite
123
123
  true
124
124
  end
125
125
 
126
+ # HR fixes leave it recorded — any time, even past dates — without a
127
+ # cancel. Re-run as a fresh recording so the create checks and the
128
+ # balance / loss-of-pay split are worked out exactly as the first time.
129
+ def correct!(actor:, attrs:, reason:)
130
+ fixed = false
131
+ transaction do
132
+ assign_attributes(attrs.merge(status: "pending", paid_days: nil, half_day: false))
133
+ raise ActiveRecord::Rollback unless valid?(:create) && save(validate: false)
134
+
135
+ audit!("corrected", actor, reason)
136
+ fixed = approve_outright!(actor: actor, note: "Corrected: #{reason}") || raise(ActiveRecord::Rollback)
137
+ end
138
+ errors.add(:base, "Not enough #{leave_type.name} balance") unless fixed || errors.any?
139
+ fixed
140
+ end
141
+
142
+ def recorded_by_hr? = created_by_id.present? && created_by_id != user_id
143
+
126
144
  def date_range_label
127
145
  if start_date == end_date
128
146
  "#{start_date.strftime('%d %b')}#{half_day ? " (#{half_day_part.present? ? "#{half_day_part} half" : 'half day'})" : ''}"
@@ -230,8 +248,6 @@ module HrLite
230
248
  )
231
249
  end
232
250
 
233
- def recorded_by_hr? = created_by_id.present? && created_by_id != user_id
234
-
235
251
  # The balance covers whole half-days only, never less than nothing.
236
252
  def covered_by(available) = [ (BigDecimal(available.to_s) * 2).floor / BigDecimal(2), 0 ].max
237
253
 
@@ -0,0 +1,30 @@
1
+ <% content_for(:page_title) { "Fix leave" } %>
2
+ <a class="hrl-backlink" href="<%= hr_lite.admin_leave_request_path(@request) %>"><span aria-hidden="true">‹</span> Leave</a>
3
+ <div class="hrl-page__head">
4
+ <h1 class="hrl-page__title">Fix leave — <%= hr_display_name(@request.user) %></h1>
5
+ <p class="hrl-page__sub">Change the type, dates or day. The balance and loss of pay are worked out again, and they get an email.</p>
6
+ </div>
7
+
8
+ <section class="hrl-card">
9
+ <%= form_with model: @request, url: hr_lite.admin_leave_request_path(@request), method: :patch, local: true do |f| %>
10
+ <%= render "hr_lite/shared/form_errors", record: @request %>
11
+ <div class="hrl-field">
12
+ <%= f.label :leave_type_id, "Type" %>
13
+ <%= f.collection_select :leave_type_id, HrLite::LeaveType.active, :id, :name %>
14
+ </div>
15
+ <div class="hrl-field"><%= f.label :start_date, "From" %><%= f.date_field :start_date %></div>
16
+ <div class="hrl-field"><%= f.label :end_date, "To" %><%= f.date_field :end_date %></div>
17
+ <div class="hrl-field">
18
+ <%= f.label :half_day_part, "Day" %>
19
+ <%= f.select :half_day_part, HrLite::DAY_PARTS %>
20
+ </div>
21
+ <div class="hrl-field">
22
+ <%= label_tag :correction_reason, "Reason for the fix (required)" %>
23
+ <%= text_area_tag :correction_reason, params[:correction_reason], required: true, class: "hrl-input" %>
24
+ </div>
25
+ <div class="hrl-form-actions">
26
+ <%= f.submit "Save fix", class: "hrl-btn hrl-btn--primary" %>
27
+ <a class="hrl-btn" href="<%= hr_lite.admin_leave_request_path(@request) %>">Back</a>
28
+ </div>
29
+ <% end %>
30
+ </section>
@@ -24,6 +24,16 @@
24
24
  </dl>
25
25
  </section>
26
26
 
27
+ <% if @request.approved? && @request.recorded_by_hr? %>
28
+ <section class="hrl-card">
29
+ <h2 class="hrl-card__title">Fix</h2>
30
+ <p class="hrl-small hrl-muted">Recorded by HR. Change it any time — no need to cancel.</p>
31
+ <div class="hrl-form-actions">
32
+ <a class="hrl-btn" href="<%= hr_lite.edit_admin_leave_request_path(@request) %>">Fix this leave</a>
33
+ </div>
34
+ </section>
35
+ <% end %>
36
+
27
37
  <%# An approved leave that has not started yet can still be called off — the
28
38
  balance is recomputed live, so cancelling gives the days straight back. %>
29
39
  <% if @request.cancellable_by?(hr_current_user) && !@request.pending? %>
data/config/routes.rb CHANGED
@@ -60,7 +60,7 @@ HrLite::Engine.routes.draw do
60
60
  resources :attendances, only: %i[index show update], param: :user_id do
61
61
  collection { get :week }
62
62
  end
63
- resources :leave_requests, only: %i[index show new create] do
63
+ resources :leave_requests, only: %i[index show new create edit update] do
64
64
  member { post :approve; post :reject; post :cancel }
65
65
  end
66
66
  resources :leave_balances, only: :index do
@@ -1,3 +1,3 @@
1
1
  module HrLite
2
- VERSION = "0.26.0"
2
+ VERSION = "0.27.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hr_lite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.0
4
+ version: 0.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kshitiz sinha
@@ -262,6 +262,7 @@ files:
262
262
  - app/views/hr_lite/admin/hr_requests/index.html.erb
263
263
  - app/views/hr_lite/admin/hr_requests/show.html.erb
264
264
  - app/views/hr_lite/admin/leave_balances/index.html.erb
265
+ - app/views/hr_lite/admin/leave_requests/edit.html.erb
265
266
  - app/views/hr_lite/admin/leave_requests/index.html.erb
266
267
  - app/views/hr_lite/admin/leave_requests/new.html.erb
267
268
  - app/views/hr_lite/admin/leave_requests/show.html.erb