hr_lite 0.54.0 → 0.56.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 +71 -0
- data/app/assets/javascripts/hr_lite/confirm.js +9 -5
- data/app/assets/javascripts/hr_lite/countdown.js +9 -2
- data/app/assets/javascripts/hr_lite/search.js +1 -1
- data/app/assets/stylesheets/hr_lite/hr_lite.css +18 -9
- data/app/controllers/hr_lite/admin/attendances_controller.rb +10 -3
- data/app/controllers/hr_lite/admin/audit_logs_controller.rb +1 -0
- data/app/controllers/hr_lite/admin/employees_controller.rb +11 -4
- data/app/controllers/hr_lite/admin/expenses_controller.rb +6 -2
- data/app/controllers/hr_lite/admin/hr_requests_controller.rb +4 -0
- data/app/controllers/hr_lite/admin/leave_requests_controller.rb +4 -1
- data/app/controllers/hr_lite/admin/payroll_runs_controller.rb +9 -5
- data/app/controllers/hr_lite/admin/reports_controller.rb +3 -2
- data/app/controllers/hr_lite/admin/salary_structures_controller.rb +2 -0
- data/app/controllers/hr_lite/admin/tax_declarations_controller.rb +13 -3
- data/app/controllers/hr_lite/approvals_controller.rb +1 -0
- data/app/controllers/hr_lite/home_controller.rb +2 -2
- data/app/controllers/hr_lite/regularization_requests_controller.rb +4 -4
- data/app/controllers/hr_lite/tax_declarations_controller.rb +9 -5
- data/app/helpers/hr_lite/application_helper.rb +20 -14
- data/app/jobs/hr_lite/attendance_close_job.rb +1 -1
- data/app/jobs/hr_lite/payroll_compute_job.rb +12 -0
- data/app/models/concerns/hr_lite/audited.rb +3 -1
- data/app/models/concerns/hr_lite/encrypted_money.rb +8 -5
- data/app/models/hr_lite/attendance_record.rb +14 -0
- data/app/models/hr_lite/benefit_enrolment.rb +3 -1
- data/app/models/hr_lite/comp_off_request.rb +2 -0
- data/app/models/hr_lite/document.rb +1 -1
- data/app/models/hr_lite/expense.rb +13 -5
- data/app/models/hr_lite/hr_request.rb +2 -0
- data/app/models/hr_lite/kudo.rb +2 -2
- data/app/models/hr_lite/leave_request.rb +25 -6
- data/app/models/hr_lite/payroll_line_item.rb +8 -0
- data/app/models/hr_lite/payroll_run.rb +18 -6
- data/app/models/hr_lite/regularization_request.rb +2 -2
- data/app/models/hr_lite/resignation.rb +5 -1
- data/app/models/hr_lite/role.rb +5 -0
- data/app/models/hr_lite/salary_slip.rb +1 -1
- data/app/models/hr_lite/tax_declaration.rb +5 -0
- data/app/services/hr_lite/attendance_puncher.rb +4 -0
- data/app/services/hr_lite/overview_query.rb +0 -12
- data/app/services/hr_lite/payroll_run_processor.rb +3 -0
- data/app/services/hr_lite/slip_builder.rb +17 -9
- data/app/services/hr_lite/work_status.rb +5 -2
- data/app/views/hr_lite/admin/assets/index.html.erb +9 -2
- data/app/views/hr_lite/admin/attendances/show.html.erb +3 -1
- data/app/views/hr_lite/admin/attendances/summary.html.erb +5 -2
- data/app/views/hr_lite/admin/audit_logs/index.html.erb +6 -4
- data/app/views/hr_lite/admin/ca_reviews/index.html.erb +3 -3
- data/app/views/hr_lite/admin/checklists/index.html.erb +3 -3
- data/app/views/hr_lite/admin/comp_off_requests/index.html.erb +1 -2
- data/app/views/hr_lite/admin/comp_off_requests/show.html.erb +5 -5
- data/app/views/hr_lite/admin/designation_changes/new.html.erb +4 -3
- data/app/views/hr_lite/admin/documents/index.html.erb +8 -3
- data/app/views/hr_lite/admin/documents/show.html.erb +2 -1
- data/app/views/hr_lite/admin/employees/_form.html.erb +12 -5
- data/app/views/hr_lite/admin/employees/show.html.erb +38 -32
- data/app/views/hr_lite/admin/expenses/index.html.erb +4 -3
- data/app/views/hr_lite/admin/holidays/index.html.erb +5 -4
- data/app/views/hr_lite/admin/hr_requests/index.html.erb +1 -1
- data/app/views/hr_lite/admin/hr_requests/show.html.erb +4 -3
- data/app/views/hr_lite/admin/leave_balances/index.html.erb +6 -4
- data/app/views/hr_lite/admin/leave_requests/index.html.erb +1 -2
- data/app/views/hr_lite/admin/leave_requests/show.html.erb +5 -3
- data/app/views/hr_lite/admin/leave_types/edit.html.erb +4 -4
- data/app/views/hr_lite/admin/leave_types/index.html.erb +3 -3
- data/app/views/hr_lite/admin/loans/index.html.erb +2 -2
- data/app/views/hr_lite/admin/loans/show.html.erb +8 -12
- data/app/views/hr_lite/admin/office_locations/edit.html.erb +4 -4
- data/app/views/hr_lite/admin/payroll_runs/index.html.erb +2 -2
- data/app/views/hr_lite/admin/payroll_runs/show.html.erb +10 -7
- data/app/views/hr_lite/admin/policies/index.html.erb +1 -1
- data/app/views/hr_lite/admin/policies/new.html.erb +2 -2
- data/app/views/hr_lite/admin/regularization_requests/index.html.erb +3 -4
- data/app/views/hr_lite/admin/regularization_requests/show.html.erb +4 -5
- data/app/views/hr_lite/admin/reports/index.html.erb +3 -6
- data/app/views/hr_lite/admin/reports/show.html.erb +16 -2
- data/app/views/hr_lite/admin/roles/_form.html.erb +6 -5
- data/app/views/hr_lite/admin/salary_slips/show.html.erb +3 -2
- data/app/views/hr_lite/admin/salary_structures/_form.html.erb +1 -0
- data/app/views/hr_lite/admin/settings/edit.html.erb +5 -1
- data/app/views/hr_lite/admin/statutory_rate_cards/_form.html.erb +3 -3
- data/app/views/hr_lite/admin/statutory_rate_cards/index.html.erb +3 -1
- data/app/views/hr_lite/admin/tax_declarations/index.html.erb +1 -1
- data/app/views/hr_lite/admin/tax_declarations/show.html.erb +2 -0
- data/app/views/hr_lite/admin/wfh_requests/index.html.erb +17 -16
- data/app/views/hr_lite/admin/wfh_requests/show.html.erb +2 -4
- data/app/views/hr_lite/admin/work_locations/index.html.erb +1 -1
- data/app/views/hr_lite/admin/work_modes/index.html.erb +1 -1
- data/app/views/hr_lite/approvals/index.html.erb +1 -1
- data/app/views/hr_lite/attendance/_month_grid.html.erb +9 -9
- data/app/views/hr_lite/attendance/_penalties.html.erb +2 -2
- data/app/views/hr_lite/attendance/_punch_card.html.erb +2 -4
- data/app/views/hr_lite/attendance/_slot.html.erb +9 -6
- data/app/views/hr_lite/attendance/_trail.html.erb +1 -1
- data/app/views/hr_lite/attendance/_work_mode.html.erb +1 -1
- data/app/views/hr_lite/attendance/show.html.erb +4 -4
- data/app/views/hr_lite/calendar/show.html.erb +2 -2
- data/app/views/hr_lite/comp_off_requests/index.html.erb +1 -1
- data/app/views/hr_lite/comp_off_requests/new.html.erb +1 -1
- data/app/views/hr_lite/documents/_upload_form.html.erb +1 -1
- data/app/views/hr_lite/employee_profiles/show.html.erb +4 -2
- data/app/views/hr_lite/home/index.html.erb +2 -2
- data/app/views/hr_lite/id_cards/show.html.erb +5 -1
- data/app/views/hr_lite/leave_requests/_balance_chips.html.erb +2 -2
- data/app/views/hr_lite/leave_requests/new.html.erb +17 -8
- data/app/views/hr_lite/leave_requests/show.html.erb +2 -0
- data/app/views/hr_lite/org/show.html.erb +1 -1
- data/app/views/hr_lite/regularization_requests/index.html.erb +7 -7
- data/app/views/hr_lite/regularization_requests/new.html.erb +7 -5
- data/app/views/hr_lite/salary_slips/_slip_detail.html.erb +2 -2
- data/app/views/hr_lite/salary_slips/pdf.html.erb +1 -1
- data/app/views/hr_lite/tax/_computation.html.erb +1 -1
- data/app/views/hr_lite/tax_declarations/show.html.erb +4 -4
- data/app/views/hr_lite/team/show.html.erb +8 -7
- data/app/views/hr_lite/timelines/show.html.erb +1 -0
- data/app/views/hr_lite/wfh_requests/index.html.erb +3 -3
- data/app/views/hr_lite/work_time/_bars.html.erb +1 -1
- data/app/views/hr_lite/work_time/_donut.html.erb +1 -1
- data/app/views/hr_lite/work_time/_report.html.erb +14 -8
- data/app/views/layouts/hr_lite/application.html.erb +1 -0
- data/db/migrate/20261017161441_make_hr_lite_benefit_enrolments_unique_while_open.rb +8 -0
- data/db/migrate/20261017161443_add_attendance_record_id_index_to_hr_lite_work_mode_events.rb +5 -0
- data/lib/hr_lite/notifications.rb +5 -2
- data/lib/hr_lite/version.rb +1 -1
- metadata +4 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<% content_for(:page_title) { "Timeline — #{hr_display_name(@person)}" } %>
|
|
2
2
|
<% content_for(:tabrow) { render "hr_lite/shared/person_tabs", user: @person } if params[:user_id] %>
|
|
3
|
+
<% content_for(:back, "Org chart") if params[:user_id] %>
|
|
3
4
|
<% year_path = ->(y) { @person.id == hr_current_user.id ? hr_lite.timeline_path(year: y) : hr_lite.person_timeline_path(@person.id, year: y) } %>
|
|
4
5
|
<% name = hr_display_name(@person) %>
|
|
5
6
|
<div class="hrl-page__head">
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
<section class="hrl-card">
|
|
8
8
|
<h2 class="hrl-card__title">Request WFH</h2>
|
|
9
|
-
<p class="hrl-small hrl-muted">Pick dates from today up to <%= HrLite::WfhRequest::MAX_DAYS_AHEAD %> days ahead. HR approves or rejects. While a request is waiting you can still check in away from the office;
|
|
9
|
+
<p class="hrl-small hrl-muted">Pick dates from today up to <%= HrLite::WfhRequest::MAX_DAYS_AHEAD %> days ahead. Your manager or HR approves or rejects. While a request is waiting you can still check in away from the office; they see the reason. A rejected date cannot.</p>
|
|
10
10
|
<%= form_with model: @request, url: hr_lite.wfh_requests_path, scope: :wfh_request, local: true do |f| %>
|
|
11
11
|
<%= render "hr_lite/shared/form_errors", record: @request %>
|
|
12
12
|
<% min, max = @window.first.iso8601, @window.last.iso8601 %>
|
|
13
13
|
<div class="hrl-field"><%= f.label :start_date, "From" %><%= f.date_field :start_date, min: min, max: max, required: true %></div>
|
|
14
14
|
<div class="hrl-field"><%= f.label :end_date, "To (same day for one day)" %><%= f.date_field :end_date, min: min, max: max, required: true %></div>
|
|
15
15
|
<div class="hrl-field"><%= f.label :reason, "Why do you need WFH?" %><%= f.text_area :reason, rows: 3, required: true %></div>
|
|
16
|
-
<div class="hrl-form-actions"><%= f.submit "Send
|
|
16
|
+
<div class="hrl-form-actions"><%= f.submit "Send for approval", class: "hrl-btn hrl-btn--primary" %></div>
|
|
17
17
|
<% end %>
|
|
18
18
|
</section>
|
|
19
19
|
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<% code, word, mod = marks[@day_status[date]] %>
|
|
28
28
|
<div class="<%= class_names("hrl-mgrid__day", "hrl-mgrid__day--#{mod}": mod, "hrl-mgrid__day--today": date == Date.current) %>"
|
|
29
29
|
role="group" aria-label="<%= date.strftime('%-d %b') %><%= ", #{word}" if word %>">
|
|
30
|
-
<span class="hrl-mgrid__num"><%= date.day %></span>
|
|
30
|
+
<span class="hrl-mgrid__num"><%= date.day == 1 ? date.strftime("%-d %b") : date.day %></span>
|
|
31
31
|
<% if code %><span class="hrl-mgrid__tag"><%= code %></span><% end %>
|
|
32
32
|
</div>
|
|
33
33
|
<% end %>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<% buckets = result.by_bucket
|
|
3
3
|
totals = buckets.transform_values { |m| m.except("offline").values.sum }
|
|
4
4
|
max = [ totals.values.max.to_f, 1 ].max
|
|
5
|
-
w = 12; gap =
|
|
5
|
+
w = 12; gap = 8; h = 100 # gap 8 units: bars ~11px apart on screen
|
|
6
6
|
fmt = { day: "%-d", week: "%-d %b", month: "%b" }[period.bucket] %>
|
|
7
7
|
<section class="hrl-card">
|
|
8
8
|
<h2 class="hrl-card__title">By <%= period.bucket %></h2>
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
</tbody>
|
|
30
30
|
</table>
|
|
31
31
|
</div>
|
|
32
|
-
<p class="hrl-small hrl-muted">Shares are of tracked time (<%= hrl_duration(total) %>: working, breaks and out of office). Offline (<%= hrl_duration(result.offline) %>) is not included.</p>
|
|
32
|
+
<p class="hrl-small hrl-muted">Shares are of tracked time (<%= hrl_duration(total) %>: working, breaks and out of office). Offline (<%= hrl_duration(result.offline) %>) is not included. Stretches: how many separate times each mode ran.</p>
|
|
33
33
|
<% else %>
|
|
34
34
|
<p class="hrl-card--empty">Only offline time recorded.</p>
|
|
35
35
|
<% end %>
|
|
@@ -20,12 +20,16 @@
|
|
|
20
20
|
<a class="hrl-btn" href="<%= path.(period: period.kind, date: period.shift(1)) %>" aria-label="Next <%= period.kind %>">›</a>
|
|
21
21
|
<% end %>
|
|
22
22
|
</div>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
<%# One picker on show: the date range stays folded unless it is what was asked for. %>
|
|
24
|
+
<%= tag.details open: params[:period] == "custom" do %>
|
|
25
|
+
<summary class="hrl-card__link">Pick your own dates</summary>
|
|
26
|
+
<%= form_with url: path.({}), method: :get, local: true, class: "hrl-row" do %>
|
|
27
|
+
<input type="hidden" name="period" value="custom">
|
|
28
|
+
<% (local_assigns[:keep] || {}).each do |k, v| %><input type="hidden" name="<%= k %>" value="<%= v %>"><% end %>
|
|
29
|
+
<div class="hrl-field"><label for="wt-from">From</label><%= date_field_tag :from, period.from, max: Date.current, id: "wt-from" %></div>
|
|
30
|
+
<div class="hrl-field"><label for="wt-to">To</label><%= date_field_tag :to, period.to, max: Date.current, id: "wt-to" %></div>
|
|
31
|
+
<div class="hrl-form-actions"><button type="submit" class="hrl-btn">Show range</button></div>
|
|
32
|
+
<% end %>
|
|
29
33
|
<% end %>
|
|
30
34
|
</section>
|
|
31
35
|
|
|
@@ -35,7 +39,8 @@
|
|
|
35
39
|
<% office = result.by_mode["office"]; wfh = result.by_mode["wfh"]; field = result.by_mode["travelling"] + result.by_mode["outside_meeting"] %>
|
|
36
40
|
<div class="hrl-kpis">
|
|
37
41
|
<% [ [ "Attendance (check-in to check-out)", result.attendance ], [ "Working time (breaks included)", result.working + result.breaks ], [ "Of which breaks", result.breaks ],
|
|
38
|
-
[ "In office", office ], [ "Work from home", wfh ], [ "Travel and client meetings", field ],
|
|
42
|
+
[ "In office", office ], [ "Work from home", wfh ], [ "Travel and client meetings", field ],
|
|
43
|
+
[ "Meetings and busy", result.by_mode["meeting"] + result.by_mode["busy"] ], [ "Out of office", result.other ] ].each do |kpi_label, secs| %>
|
|
39
44
|
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= hrl_duration(secs) %></div><div class="hrl-kpi__label"><%= kpi_label %></div></div>
|
|
40
45
|
<% end %>
|
|
41
46
|
</div>
|
|
@@ -62,11 +67,12 @@
|
|
|
62
67
|
<% if records.any? %>
|
|
63
68
|
<section class="hrl-card">
|
|
64
69
|
<h2 class="hrl-card__title">Check-ins</h2>
|
|
70
|
+
<% all_punches = HrLite::AttendancePunch.where(user_id: records.map(&:user_id).uniq, date: records.map(&:date)).order(:at, :id).group_by { |p| [ p.user_id, p.date ] } # one query, not one a day %>
|
|
65
71
|
<% records.each do |r| %>
|
|
66
72
|
<div class="hrl-feed__item hrl-small"><div class="hrl-feed__body">
|
|
67
73
|
<% if names %><strong><%= names[r.user_id] %></strong> · <% end %>
|
|
68
74
|
<%= r.date.strftime("%a %-d %b") %><% if r.work_mode_label %> · <%= r.work_mode_label %><% end %>
|
|
69
|
-
<%= render "hr_lite/attendance/trail", record: r %>
|
|
75
|
+
<%= render "hr_lite/attendance/trail", record: r, punches: all_punches.fetch([ r.user_id, r.date ], []) %>
|
|
70
76
|
</div></div>
|
|
71
77
|
<% end %>
|
|
72
78
|
</section>
|
|
@@ -117,6 +117,7 @@
|
|
|
117
117
|
<%= javascript_include_tag "hr_lite/select_filter", defer: true %>
|
|
118
118
|
<%= javascript_include_tag "hr_lite/search", defer: true %>
|
|
119
119
|
<dialog class="hrl-search" data-hrl-search aria-label="Search">
|
|
120
|
+
<form method="dialog" class="hrl-search__close"><button class="hrl-btn" type="submit">Close</button></form>
|
|
120
121
|
<form action="<%= hr_lite.search_path %>" method="get" role="search">
|
|
121
122
|
<label class="hrl-sr-only" for="hrl-search-q">Search screens and people</label>
|
|
122
123
|
<input id="hrl-search-q" class="hrl-input" type="search" name="q" placeholder="Search screens and people" autocomplete="off">
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
class MakeHrLiteBenefitEnrolmentsUniqueWhileOpen < ActiveRecord::Migration[8.1]
|
|
2
|
+
# One open enrolment per person per plan; ended ones stay as history.
|
|
3
|
+
def change
|
|
4
|
+
remove_index :hr_lite_benefit_enrolments, %i[benefit_id user_id], unique: true, if_exists: true
|
|
5
|
+
add_index :hr_lite_benefit_enrolments, %i[benefit_id user_id], unique: true, where: "ended_on IS NULL",
|
|
6
|
+
name: "index_hr_lite_benefit_enrolments_one_open", if_not_exists: true
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -131,14 +131,17 @@ module HrLite
|
|
|
131
131
|
# Rescued PER RECIPIENT. Wrapping the whole loop meant one bad address
|
|
132
132
|
# or a single enqueue failure silently dropped everyone after it — on
|
|
133
133
|
# a team-wide leave notice, most of the team.
|
|
134
|
-
Array(email_to).compact.uniq
|
|
134
|
+
users = Array(email_to).compact.uniq
|
|
135
|
+
# One query for everyone's Busy/Meeting end, not one per recipient.
|
|
136
|
+
held_until = HrLite.config.office_geofence ? WorkStatus.do_not_disturb_for(users.map(&:id)) : {}
|
|
137
|
+
users.each do |user|
|
|
135
138
|
next if user.email.blank?
|
|
136
139
|
|
|
137
140
|
begin
|
|
138
141
|
mail = EventMailer.event(to: user.email, subject: title, heading: title,
|
|
139
142
|
body: body, lines: lines, path: path, link_url: link_url)
|
|
140
143
|
# Busy or in a meeting: the email waits until that ends.
|
|
141
|
-
held =
|
|
144
|
+
held = held_until[user.id]
|
|
142
145
|
held ? mail.deliver_later(wait_until: held) : mail.deliver_later
|
|
143
146
|
rescue => e
|
|
144
147
|
Rails.logger.error("[hr_lite] event email failed: #{e.class}: #{e.message}")
|
data/lib/hr_lite/version.rb
CHANGED
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.56.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kshitiz sinha
|
|
@@ -171,6 +171,7 @@ files:
|
|
|
171
171
|
- app/jobs/hr_lite/leave_year_rollover_job.rb
|
|
172
172
|
- app/jobs/hr_lite/payroll_auto_approve_job.rb
|
|
173
173
|
- app/jobs/hr_lite/payroll_auto_draft_job.rb
|
|
174
|
+
- app/jobs/hr_lite/payroll_compute_job.rb
|
|
174
175
|
- app/jobs/hr_lite/slips_ready_job.rb
|
|
175
176
|
- app/jobs/hr_lite/work_mode_expire_job.rb
|
|
176
177
|
- app/mailers/hr_lite/application_mailer.rb
|
|
@@ -504,6 +505,8 @@ files:
|
|
|
504
505
|
- db/migrate/20261016090000_add_penalty_leave_type_to_hr_lite_settings.rb
|
|
505
506
|
- db/migrate/20261016091000_create_hr_lite_penalty_removals.rb
|
|
506
507
|
- db/migrate/20261016100000_add_hours_allowance_repeat_to_hr_lite_employee_profiles.rb
|
|
508
|
+
- db/migrate/20261017161441_make_hr_lite_benefit_enrolments_unique_while_open.rb
|
|
509
|
+
- db/migrate/20261017161443_add_attendance_record_id_index_to_hr_lite_work_mode_events.rb
|
|
507
510
|
- lib/generators/hr_lite/install/install_generator.rb
|
|
508
511
|
- lib/generators/hr_lite/install/templates/AFTER_INSTALL
|
|
509
512
|
- lib/generators/hr_lite/install/templates/initializer.rb
|