hr_lite 0.20.2 → 0.21.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 +4 -4
- data/CHANGELOG.md +21 -0
- data/app/controllers/hr_lite/admin/attendances_controller.rb +3 -1
- data/app/controllers/hr_lite/admin/employees_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/leave_requests_controller.rb +1 -1
- data/app/controllers/hr_lite/leave_requests_controller.rb +1 -1
- data/app/models/hr_lite/attendance_record.rb +1 -0
- data/app/models/hr_lite/employee_profile.rb +10 -0
- data/app/models/hr_lite/leave_request.rb +14 -1
- data/app/views/hr_lite/admin/attendances/index.html.erb +1 -1
- data/app/views/hr_lite/admin/attendances/show.html.erb +2 -3
- data/app/views/hr_lite/admin/employees/_form.html.erb +4 -0
- data/app/views/hr_lite/admin/employees/index.html.erb +2 -1
- data/app/views/hr_lite/admin/employees/show.html.erb +2 -1
- data/app/views/hr_lite/admin/leave_requests/new.html.erb +3 -3
- data/app/views/hr_lite/employee_profiles/show.html.erb +2 -1
- data/app/views/hr_lite/leave_requests/new.html.erb +3 -3
- data/db/migrate/20261006090000_add_probation_until_to_hr_lite_employee_profiles.rb +5 -0
- data/db/migrate/20261006120000_add_half_day_part_to_hr_lite_leave_requests.rb +5 -0
- data/db/migrate/20261006120100_add_half_day_part_to_hr_lite_attendance_records.rb +5 -0
- data/lib/hr_lite/configuration.rb +3 -1
- data/lib/hr_lite/version.rb +1 -1
- data/lib/hr_lite.rb +2 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d2f9a101bb4b88ff5c5387f7da5141c2352388216b60b74889a508826f0b1ed
|
|
4
|
+
data.tar.gz: 67e8da86ef1d895d5ff40a35f1d27c3a131787b154ba3c5ed68af8b0fdbf7649
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f3365b0fec9bacdbddb3118a634fb781552b032f59c20b0375de141052b018f7960bb76c7354b8d48edb14236134bdfbc3a2040932387fe8ef406305cf99c74d
|
|
7
|
+
data.tar.gz: 5aac23f5baf4c64b1266580e8785360ce10d2033ee68d2d01d3965329a8c0c18e7daedb58e96ae478444099e4d5a01845fb5a7afc0dcf014eff594ab9996960a
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.21.0] - 2026-10-06
|
|
11
|
+
|
|
12
|
+
Three migrations: `hr_lite_employee_profiles.probation_until` (date),
|
|
13
|
+
`hr_lite_leave_requests.half_day_part` and
|
|
14
|
+
`hr_lite_attendance_records.half_day_part` (string).
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Probation.** `config.probation_months` (e.g. 6) gives every new hire a
|
|
19
|
+
`probation_until` date of joining + N months. HR edits it per employee on
|
|
20
|
+
the profile form: blank removes the tag, a date adds or extends it.
|
|
21
|
+
While on probation an employee can take at most 1 day of leave (any type,
|
|
22
|
+
half days count 0.5) per calendar month; the request is refused at apply.
|
|
23
|
+
A "Probation" badge shows on the employee list, the admin profile and the
|
|
24
|
+
employee's own profile, and drops off by itself after the date.
|
|
25
|
+
Existing employees are not tagged — the host backfills or HR sets them.
|
|
26
|
+
- **Full day / First half / Second half.** The leave forms (employee and
|
|
27
|
+
HR-recorded) and HR's attendance day form use one "Day" picker instead
|
|
28
|
+
of a half-day checkbox / status select. A half still counts 0.5; the
|
|
29
|
+
label reads "05 Jul (first half)", and the team board shows which half.
|
|
30
|
+
|
|
10
31
|
## [0.20.2] - 2026-10-05
|
|
11
32
|
|
|
12
33
|
No migration.
|
|
@@ -37,7 +37,7 @@ module HrLite
|
|
|
37
37
|
alert: "A regularization note is required."
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
attrs = params.require(:attendance_record).permit(:check_in_at, :check_out_at, :status)
|
|
40
|
+
attrs = params.require(:attendance_record).permit(:check_in_at, :check_out_at, :status, :half_day_part)
|
|
41
41
|
if attrs[:check_in_at].blank? && attrs[:check_out_at].blank?
|
|
42
42
|
# Nothing to remove used to still write a `destroy` audit row with
|
|
43
43
|
# subject_id 0 and email the employee that a punch was removed.
|
|
@@ -61,6 +61,8 @@ module HrLite
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
record.assign_attributes(attrs)
|
|
64
|
+
record.half_day_part = attrs[:half_day_part].presence if attrs.key?(:half_day_part)
|
|
65
|
+
record.status = record.half_day_part ? "half_day" : "present" if attrs.key?(:half_day_part)
|
|
64
66
|
record.status = "present" if record.status.blank?
|
|
65
67
|
record.regularized_by_id = hr_current_user.id
|
|
66
68
|
record.regularized_at = Time.current
|
|
@@ -113,7 +113,7 @@ module HrLite
|
|
|
113
113
|
def profile_params
|
|
114
114
|
params.require(:employee_profile).permit(
|
|
115
115
|
:user_id, :manager_id, :designation, :date_of_birth, :date_of_joining,
|
|
116
|
-
:date_of_exit, :department, :work_location, :pan_number, :pf_uan, :esi_number,
|
|
116
|
+
:date_of_exit, :probation_until, :department, :work_location, :pan_number, :pf_uan, :esi_number,
|
|
117
117
|
:bank_account_number, :bank_ifsc, :bank_name, :tax_regime, :declared_annual_deductions,
|
|
118
118
|
:fy_opening_gross, :fy_opening_tds, :blood_group, :emergency_contact
|
|
119
119
|
)
|
|
@@ -25,7 +25,7 @@ module HrLite
|
|
|
25
25
|
|
|
26
26
|
def create
|
|
27
27
|
profile = recordable.find_by(employee_code: params[:employee_code].to_s.strip)
|
|
28
|
-
@request = LeaveRequest.new(params.require(:leave_request).permit(:leave_type_id, :start_date, :end_date, :half_day, :reason)
|
|
28
|
+
@request = LeaveRequest.new(params.require(:leave_request).permit(:leave_type_id, :start_date, :end_date, :half_day, :half_day_part, :reason)
|
|
29
29
|
.merge(user_id: profile&.user_id, created_by_id: hr_current_user.id))
|
|
30
30
|
recorded = profile && LeaveRequest.transaction do
|
|
31
31
|
(@request.save && @request.approve!(actor: hr_current_user, note: "Recorded by HR")) || raise(ActiveRecord::Rollback)
|
|
@@ -52,7 +52,7 @@ module HrLite
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def request_params
|
|
55
|
-
params.require(:leave_request).permit(:leave_type_id, :start_date, :end_date, :half_day, :reason)
|
|
55
|
+
params.require(:leave_request).permit(:leave_type_id, :start_date, :end_date, :half_day, :half_day_part, :reason)
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
end
|
|
@@ -8,6 +8,7 @@ module HrLite
|
|
|
8
8
|
|
|
9
9
|
validates :date, presence: true, uniqueness: { scope: :user_id }
|
|
10
10
|
validates :status, inclusion: { in: STATUSES }
|
|
11
|
+
validates :half_day_part, inclusion: { in: %w[first second] }, allow_blank: true
|
|
11
12
|
validate :check_out_after_check_in
|
|
12
13
|
|
|
13
14
|
scope :for_date, ->(date) { where(date: date) }
|
|
@@ -34,6 +34,10 @@ module HrLite
|
|
|
34
34
|
attr_accessor :new_user_name, :new_user_email, :new_user_password
|
|
35
35
|
|
|
36
36
|
before_validation :assign_employee_code, on: :create
|
|
37
|
+
before_validation(on: :create) do
|
|
38
|
+
months = HrLite.config.probation_months.to_i
|
|
39
|
+
self.probation_until ||= date_of_joining.advance(months: months) - 1 if months.positive? && date_of_joining
|
|
40
|
+
end
|
|
37
41
|
# Without a role a new hire cannot see policies or raise an HR request.
|
|
38
42
|
after_create { (role = Role.find_by(name: Role::EMPLOYEE)) && RoleAssignment.find_or_create_by!(user_id:, role:) }
|
|
39
43
|
|
|
@@ -57,6 +61,12 @@ module HrLite
|
|
|
57
61
|
.where("date_of_exit IS NULL OR date_of_exit >= ?", month.beginning_of_month)
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
# Admin owns probation_until: blank = no probation tag, a date = tagged
|
|
65
|
+
# through that day. New hires default to config.probation_months.
|
|
66
|
+
def on_probation?(on = Date.current)
|
|
67
|
+
probation_until.present? && on <= probation_until
|
|
68
|
+
end
|
|
69
|
+
|
|
60
70
|
def active_on?(date)
|
|
61
71
|
date_of_joining <= date && (date_of_exit.nil? || date_of_exit >= date)
|
|
62
72
|
end
|
|
@@ -12,6 +12,7 @@ module HrLite
|
|
|
12
12
|
|
|
13
13
|
validates :start_date, :end_date, presence: true
|
|
14
14
|
validates :status, inclusion: { in: STATUSES }
|
|
15
|
+
validates :half_day_part, inclusion: { in: %w[first second] }, allow_blank: true
|
|
15
16
|
|
|
16
17
|
with_options on: :create do
|
|
17
18
|
validate :end_after_start
|
|
@@ -21,8 +22,10 @@ module HrLite
|
|
|
21
22
|
validate :no_overlap_with_own_requests
|
|
22
23
|
validate :no_punch_conflict
|
|
23
24
|
validate :sufficient_balance
|
|
25
|
+
validate :within_probation_cap
|
|
24
26
|
end
|
|
25
27
|
|
|
28
|
+
before_validation { self.half_day = true if half_day_part.present? }
|
|
26
29
|
before_validation :cache_days_count, on: :create
|
|
27
30
|
after_create :notify_requested, unless: :recorded_by_hr?
|
|
28
31
|
after_create :notify_team
|
|
@@ -122,7 +125,7 @@ module HrLite
|
|
|
122
125
|
|
|
123
126
|
def date_range_label
|
|
124
127
|
if start_date == end_date
|
|
125
|
-
"#{start_date.strftime('%d %b')}#{half_day ?
|
|
128
|
+
"#{start_date.strftime('%d %b')}#{half_day ? " (#{half_day_part.present? ? "#{half_day_part} half" : 'half day'})" : ''}"
|
|
126
129
|
else
|
|
127
130
|
"#{start_date.strftime('%d %b')} – #{end_date.strftime('%d %b')}"
|
|
128
131
|
end
|
|
@@ -329,6 +332,16 @@ module HrLite
|
|
|
329
332
|
errors.add(:base, "Attendance is marked in this period") if punched.exists?
|
|
330
333
|
end
|
|
331
334
|
|
|
335
|
+
# Probation: at most one day of leave (any type) in a calendar month.
|
|
336
|
+
def within_probation_cap
|
|
337
|
+
return unless start_date && days_count
|
|
338
|
+
return unless EmployeeProfile.find_by(user_id: user_id)&.on_probation?(start_date)
|
|
339
|
+
|
|
340
|
+
taken = self.class.where(user_id: user_id, status: %w[pending approved])
|
|
341
|
+
.where(start_date: start_date.all_month).sum(:days_count)
|
|
342
|
+
errors.add(:base, "During probation only 1 day of leave a month is allowed") if taken + days_count > 1
|
|
343
|
+
end
|
|
344
|
+
|
|
332
345
|
# Only comp-off is refused past its balance: it is earned credit, never
|
|
333
346
|
# borrowed. Any other type's excess becomes loss of pay at approval.
|
|
334
347
|
def sufficient_balance
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
<% if record&.flagged? %>
|
|
37
37
|
<span class="hrl-badge hrl-badge--bad" title="<%= record.flag_note %>">Flagged</span>
|
|
38
38
|
<% elsif record&.check_in_at %>
|
|
39
|
-
<span class="hrl-badge hrl-badge--ok"><%= record.status.humanize %></span>
|
|
39
|
+
<span class="hrl-badge hrl-badge--ok"><%= record.status.humanize %><%= " (#{record.half_day_part} half)" if record.half_day_part %></span>
|
|
40
40
|
<% else %>
|
|
41
41
|
<span class="hrl-badge hrl-badge--muted">No punch</span>
|
|
42
42
|
<% end %>
|
|
@@ -38,9 +38,8 @@
|
|
|
38
38
|
<p class="hrl-hint">Clear both times to remove the punch entirely.</p>
|
|
39
39
|
</div>
|
|
40
40
|
<div class="hrl-field">
|
|
41
|
-
<%= f.label :
|
|
42
|
-
<%= f.select :
|
|
43
|
-
selected: @edit_record.status %>
|
|
41
|
+
<%= f.label :half_day_part, "Day" %>
|
|
42
|
+
<%= f.select :half_day_part, HrLite::DAY_PARTS, selected: @edit_record.half_day_part.to_s %>
|
|
44
43
|
</div>
|
|
45
44
|
<div class="hrl-field">
|
|
46
45
|
<%= f.label :regularization_note, "Why is this being fixed? (required)" %>
|
|
@@ -62,6 +62,10 @@
|
|
|
62
62
|
<%= f.select :blood_group, HrLite::EmployeeProfile::BLOOD_GROUPS, include_blank: "—" %>
|
|
63
63
|
</div>
|
|
64
64
|
<div class="hrl-field"><%= f.label :emergency_contact, "Emergency contact (printed on the ID card)" %><%= f.telephone_field :emergency_contact %></div>
|
|
65
|
+
<div class="hrl-field">
|
|
66
|
+
<%= f.label :probation_until, "On probation until (blank = not on probation)" %>
|
|
67
|
+
<%= f.date_field :probation_until %>
|
|
68
|
+
</div>
|
|
65
69
|
<div class="hrl-field">
|
|
66
70
|
<%= f.label :date_of_exit, "Date of exit (leave blank while employed)" %>
|
|
67
71
|
<%= f.date_field :date_of_exit %>
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
<tr>
|
|
17
17
|
<td data-label="Code"><%= profile.employee_code %></td>
|
|
18
18
|
<td data-label="Name"><%= hr_display_name(profile.user) %>
|
|
19
|
-
<% if profile.date_of_exit %><span class="hrl-badge hrl-badge--muted">Exited</span><% end
|
|
19
|
+
<% if profile.date_of_exit %><span class="hrl-badge hrl-badge--muted">Exited</span><% end %>
|
|
20
|
+
<% if profile.on_probation? %><span class="hrl-badge hrl-badge--warn">Probation</span><% end %></td>
|
|
20
21
|
<td data-label="Designation"><%= profile.designation %></td>
|
|
21
22
|
<td data-label="Joined"><%= profile.date_of_joining.strftime("%d %b %Y") %></td>
|
|
22
23
|
<td data-label=""><a class="hrl-btn" href="<%= hr_lite.admin_employee_path(profile) %>">Open</a></td>
|
|
@@ -71,7 +71,8 @@
|
|
|
71
71
|
<dt>Designation</dt><dd><%= @profile.designation.presence || "—" %></dd>
|
|
72
72
|
<dt>Reports to</dt><dd><%= @profile.manager ? hr_display_name(@profile.manager) : "—" %></dd>
|
|
73
73
|
<dt>Department</dt><dd><%= @profile.department.presence || "—" %></dd>
|
|
74
|
-
<dt>Joined</dt><dd><%= @profile.date_of_joining.strftime("%d %b %Y")
|
|
74
|
+
<dt>Joined</dt><dd><%= @profile.date_of_joining.strftime("%d %b %Y") %>
|
|
75
|
+
<% if @profile.on_probation? %><span class="hrl-badge hrl-badge--warn">Probation</span><% end %></dd>
|
|
75
76
|
<% if @profile.date_of_exit %><dt>Exited</dt><dd><%= @profile.date_of_exit.strftime("%d %b %Y") %></dd><% end %>
|
|
76
77
|
<dt>Tax regime</dt><dd><%= @profile.tax_regime.humanize %></dd>
|
|
77
78
|
<dt>PAN</dt><dd><%= @profile.masked_pan || "—" %></dd>
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
</div>
|
|
30
30
|
<div class="hrl-field"><%= f.label :start_date, "From" %><%= f.date_field :start_date %></div>
|
|
31
31
|
<div class="hrl-field"><%= f.label :end_date, "To" %><%= f.date_field :end_date %></div>
|
|
32
|
-
<div class="hrl-field
|
|
33
|
-
<%= f.
|
|
34
|
-
<%= f.
|
|
32
|
+
<div class="hrl-field">
|
|
33
|
+
<%= f.label :half_day_part, "Day" %>
|
|
34
|
+
<%= f.select :half_day_part, HrLite::DAY_PARTS %>
|
|
35
35
|
</div>
|
|
36
36
|
<div class="hrl-field"><%= f.label :reason, "Note (optional)" %><%= f.text_area :reason %></div>
|
|
37
37
|
<div class="hrl-form-actions">
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
<dd><%= (boss = @profile.active_manager) ? "#{hr_display_name(boss)} (your L1)" : "—" %>
|
|
13
13
|
· <a href="<%= hr_lite.org_path %>">Org chart</a></dd>
|
|
14
14
|
<dt>Department</dt><dd><%= @profile.department.presence || "—" %></dd>
|
|
15
|
-
<dt>Joined</dt><dd><%= @profile.date_of_joining.strftime("%d %B %Y")
|
|
15
|
+
<dt>Joined</dt><dd><%= @profile.date_of_joining.strftime("%d %B %Y") %>
|
|
16
|
+
<% if @profile.on_probation? %><span class="hrl-badge hrl-badge--warn">Probation</span><% end %></dd>
|
|
16
17
|
<dt>Tax regime</dt><dd><%= @profile.tax_regime.humanize %></dd>
|
|
17
18
|
<dt>PAN</dt><dd><%= @profile.masked_pan || "—" %></dd>
|
|
18
19
|
<dt>PF UAN</dt><dd><%= @profile.masked_uan || "—" %></dd>
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
<%= f.label :end_date, "To" %>
|
|
22
22
|
<%= f.date_field :end_date %>
|
|
23
23
|
</div>
|
|
24
|
-
<div class="hrl-field
|
|
25
|
-
<%= f.
|
|
26
|
-
<%= f.
|
|
24
|
+
<div class="hrl-field">
|
|
25
|
+
<%= f.label :half_day_part, "Day" %>
|
|
26
|
+
<%= f.select :half_day_part, HrLite::DAY_PARTS %>
|
|
27
27
|
</div>
|
|
28
28
|
<div class="hrl-field">
|
|
29
29
|
<%= f.label :reason, "Reason (optional)" %>
|
|
@@ -12,7 +12,9 @@ module HrLite
|
|
|
12
12
|
:onboard_user, :offboard_user, :invite_url_for,
|
|
13
13
|
# ->(user) { { url:, unread: } } — shows a notifications link in
|
|
14
14
|
# the HR shell; nil (default) shows nothing.
|
|
15
|
-
:notifications
|
|
15
|
+
:notifications,
|
|
16
|
+
# e.g. 6 — default probation for new hires (admin edits per employee)
|
|
17
|
+
:probation_months
|
|
16
18
|
|
|
17
19
|
attr_reader :leave_year_start_month, :slip_release_day, :self_regularization
|
|
18
20
|
|
data/lib/hr_lite/version.rb
CHANGED
data/lib/hr_lite.rb
CHANGED
|
@@ -17,6 +17,8 @@ require "hr_lite/amount_in_words"
|
|
|
17
17
|
require "hr_lite/statutory_rate_card"
|
|
18
18
|
|
|
19
19
|
module HrLite
|
|
20
|
+
# Full day / first half / second half — one picker for leave and attendance.
|
|
21
|
+
DAY_PARTS = [ [ "Full day", "" ], [ "First half", "first" ], [ "Second half", "second" ] ].freeze
|
|
20
22
|
class << self
|
|
21
23
|
def config
|
|
22
24
|
@config ||= Configuration.new
|
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.
|
|
4
|
+
version: 0.21.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kshitiz sinha
|
|
@@ -376,6 +376,9 @@ files:
|
|
|
376
376
|
- db/migrate/20260927100145_add_id_card_fields_to_hr_lite_employee_profiles.rb
|
|
377
377
|
- db/migrate/20260927101031_add_created_by_id_to_hr_lite_leave_requests.rb
|
|
378
378
|
- db/migrate/20260929081109_add_paid_days_to_hr_lite_leave_requests.rb
|
|
379
|
+
- db/migrate/20261006090000_add_probation_until_to_hr_lite_employee_profiles.rb
|
|
380
|
+
- db/migrate/20261006120000_add_half_day_part_to_hr_lite_leave_requests.rb
|
|
381
|
+
- db/migrate/20261006120100_add_half_day_part_to_hr_lite_attendance_records.rb
|
|
379
382
|
- lib/generators/hr_lite/install/install_generator.rb
|
|
380
383
|
- lib/generators/hr_lite/install/templates/AFTER_INSTALL
|
|
381
384
|
- lib/generators/hr_lite/install/templates/initializer.rb
|