hr_lite 0.4.0 → 0.5.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 +16 -0
- data/app/controllers/hr_lite/admin/appraisals_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/designation_changes_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/employees_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/payroll_runs_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/salary_slips_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/salary_structures_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/settings_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/superadmin_controller.rb +16 -0
- data/app/controllers/hr_lite/application_controller.rb +5 -1
- data/app/helpers/hr_lite/application_helper.rb +5 -1
- data/app/models/hr_lite/employee_profile.rb +21 -0
- data/app/models/hr_lite/setting.rb +2 -0
- data/app/views/hr_lite/admin/employees/_form.html.erb +10 -1
- data/app/views/hr_lite/admin/employees/index.html.erb +3 -0
- data/app/views/hr_lite/admin/employees/show.html.erb +9 -3
- data/app/views/hr_lite/admin/settings/edit.html.erb +7 -0
- data/app/views/layouts/hr_lite/application.html.erb +5 -0
- data/db/migrate/20260720094454_add_employee_code_prefix_to_hr_lite_settings.rb +7 -0
- data/lib/hr_lite/configuration.rb +8 -0
- data/lib/hr_lite/version.rb +1 -1
- data/lib/hr_lite.rb +4 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 00cc5c346c88ddc803a5336a1c14a07dd4609fc887213f99e9b11654f26fa109
|
|
4
|
+
data.tar.gz: 8306411151a38ea5b1fe0fe9c7b4bd3572e16917a1defc1e15d4e823ab7f9c1b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6f9be2057c4023881d956fc8feadb18d2917bb38cd92746b7a448a60fedea0fc94d335b22d36a627a8ce888e36a7520ca6118ad77e6f5956b96fdec695f813dc
|
|
7
|
+
data.tar.gz: 95c8048ecd82dc4b92d9e4e5b79240bed1385e297206383280c76e010d141f666e57eb150eac9defdbe556978226d7b4a5fff21ff8132103e04e09862a36f3ad
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2026-07-20
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Superadmin (money) tier** — `config.superadmin_emails`: only these
|
|
15
|
+
people reach salary structures, payroll runs, slips administration,
|
|
16
|
+
appraisals and promotions, or see salary/appraisal data on the
|
|
17
|
+
employee page and the Payroll nav item. Ordinary leadership keeps
|
|
18
|
+
governing people and policy. Empty list (default) = leadership keeps
|
|
19
|
+
the money tier, exactly as before.
|
|
20
|
+
- **System-assigned employee codes**: prefix (Settings, default "EMP")
|
|
21
|
+
+ zero-padded sequence — EMP001, EMP002, … Forms no longer accept a
|
|
22
|
+
code; changing the prefix starts a fresh sequence; explicitly-set
|
|
23
|
+
codes (imports/seeds) are never overwritten.
|
|
24
|
+
- "New employee" button on the Employees screen.
|
|
25
|
+
|
|
10
26
|
## [0.4.0] - 2026-07-19
|
|
11
27
|
|
|
12
28
|
### Added
|
|
@@ -93,7 +93,7 @@ module HrLite
|
|
|
93
93
|
|
|
94
94
|
def profile_params
|
|
95
95
|
params.require(:employee_profile).permit(
|
|
96
|
-
:user_id, :manager_id, :
|
|
96
|
+
:user_id, :manager_id, :designation, :date_of_birth, :date_of_joining,
|
|
97
97
|
:date_of_exit, :department, :work_location, :pan_number, :pf_uan, :esi_number,
|
|
98
98
|
:bank_account_number, :bank_ifsc, :bank_name, :tax_regime, :declared_annual_deductions
|
|
99
99
|
)
|
|
@@ -7,7 +7,7 @@ module HrLite
|
|
|
7
7
|
|
|
8
8
|
def update
|
|
9
9
|
@setting = Setting.instance
|
|
10
|
-
if @setting.update(params.require(:setting).permit(:weekend_policy))
|
|
10
|
+
if @setting.update(params.require(:setting).permit(:weekend_policy, :employee_code_prefix))
|
|
11
11
|
redirect_to edit_admin_setting_path, notice: "Settings saved."
|
|
12
12
|
else
|
|
13
13
|
render :edit, status: :unprocessable_entity
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module HrLite
|
|
2
|
+
module Admin
|
|
3
|
+
# Money tier: salary structures, payroll, slips, appraisals and
|
|
4
|
+
# promotions. Only config.superadmin_emails — ordinary leadership can
|
|
5
|
+
# govern policy and people but never sees another person's pay.
|
|
6
|
+
class SuperadminController < LeadershipController
|
|
7
|
+
before_action :require_hr_superadmin!
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def require_hr_superadmin!
|
|
12
|
+
hr_access_denied unless hr_superadmin?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -10,7 +10,7 @@ module HrLite
|
|
|
10
10
|
before_action :hr_set_current_actor
|
|
11
11
|
around_action :hr_use_time_zone
|
|
12
12
|
|
|
13
|
-
helper_method :hr_current_user, :hr_admin?, :hr_leadership?, :hr_display_name
|
|
13
|
+
helper_method :hr_current_user, :hr_admin?, :hr_leadership?, :hr_superadmin?, :hr_display_name
|
|
14
14
|
|
|
15
15
|
private
|
|
16
16
|
|
|
@@ -26,6 +26,10 @@ module HrLite
|
|
|
26
26
|
HrLite.admin?(hr_current_user)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
def hr_superadmin?
|
|
30
|
+
HrLite.superadmin?(hr_current_user)
|
|
31
|
+
end
|
|
32
|
+
|
|
29
33
|
def hr_leadership?
|
|
30
34
|
HrLite.leadership?(hr_current_user)
|
|
31
35
|
end
|
|
@@ -20,11 +20,15 @@ module HrLite
|
|
|
20
20
|
|
|
21
21
|
LEADERSHIP_NAV_ITEMS = [
|
|
22
22
|
{ label: "Employees", path: :admin_employees_path, match: [ "/admin/employees" ] },
|
|
23
|
-
{ label: "Payroll", path: :admin_payroll_runs_path, match: [ "/admin/payroll_runs", "/admin/salary_slips" ] },
|
|
24
23
|
{ label: "Settings", path: :admin_leave_types_path, match: [ "/admin/leave_types", "/admin/office_locations", "/admin/holidays", "/admin/setting" ] },
|
|
25
24
|
{ label: "Audit", path: :admin_audit_logs_path, match: [ "/admin/audit_logs" ] }
|
|
26
25
|
].freeze
|
|
27
26
|
|
|
27
|
+
# Money tier — only config.superadmin_emails see these.
|
|
28
|
+
SUPERADMIN_NAV_ITEMS = [
|
|
29
|
+
{ label: "Payroll", path: :admin_payroll_runs_path, match: [ "/admin/payroll_runs", "/admin/salary_slips" ] }
|
|
30
|
+
].freeze
|
|
31
|
+
|
|
28
32
|
# Only items whose routes exist yet (the nav grows with each phase).
|
|
29
33
|
def hrl_nav_items(items)
|
|
30
34
|
items.select { |item| hr_lite_route?(item[:path]) }
|
|
@@ -21,6 +21,8 @@ module HrLite
|
|
|
21
21
|
# config.onboard_user; never persisted, never audited).
|
|
22
22
|
attr_accessor :new_user_name, :new_user_email, :new_user_password
|
|
23
23
|
|
|
24
|
+
before_validation :assign_employee_code, on: :create
|
|
25
|
+
|
|
24
26
|
validates :employee_code, presence: true, uniqueness: true
|
|
25
27
|
validates :user_id, uniqueness: true
|
|
26
28
|
validates :date_of_joining, presence: true
|
|
@@ -89,6 +91,25 @@ module HrLite
|
|
|
89
91
|
|
|
90
92
|
private
|
|
91
93
|
|
|
94
|
+
# Codes are system-assigned: Settings prefix + zero-padded next number
|
|
95
|
+
# (EMP001, EMP002, ...). Scans the highest existing suffix for the
|
|
96
|
+
# CURRENT prefix so changing the prefix restarts a fresh sequence
|
|
97
|
+
# without colliding with history.
|
|
98
|
+
def assign_employee_code
|
|
99
|
+
return if employee_code.present?
|
|
100
|
+
|
|
101
|
+
prefix = Setting.instance.employee_code_prefix
|
|
102
|
+
last = self.class.where("employee_code LIKE ?", "#{sanitize_sql_like(prefix)}%")
|
|
103
|
+
.pluck(:employee_code)
|
|
104
|
+
.filter_map { |code| code.delete_prefix(prefix)[/\A\d+\z/]&.to_i }
|
|
105
|
+
.max || 0
|
|
106
|
+
self.employee_code = format("%s%03d", prefix, last + 1)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def sanitize_sql_like(value)
|
|
110
|
+
self.class.sanitize_sql_like(value)
|
|
111
|
+
end
|
|
112
|
+
|
|
92
113
|
# A newly-assigned manager must be a real, still-employed staff member.
|
|
93
114
|
def manager_is_active_staff
|
|
94
115
|
return if manager_id.nil?
|
|
@@ -6,6 +6,8 @@ module HrLite
|
|
|
6
6
|
WEEKEND_POLICIES = %w[sun_only sat_sun second_fourth_sat_sun].freeze
|
|
7
7
|
|
|
8
8
|
validates :weekend_policy, inclusion: { in: WEEKEND_POLICIES }
|
|
9
|
+
validates :employee_code_prefix, presence: true,
|
|
10
|
+
format: { with: /\A[A-Za-z]{1,10}\z/, message: "letters only, max 10" }
|
|
9
11
|
|
|
10
12
|
def self.instance
|
|
11
13
|
first_or_create!
|
|
@@ -28,7 +28,16 @@
|
|
|
28
28
|
</div>
|
|
29
29
|
</fieldset>
|
|
30
30
|
<% end %>
|
|
31
|
-
|
|
31
|
+
<% if profile.persisted? %>
|
|
32
|
+
<div class="hrl-field">
|
|
33
|
+
<%= f.label :employee_code %>
|
|
34
|
+
<input class="hrl-input" type="text" value="<%= profile.employee_code %>" disabled>
|
|
35
|
+
<p class="hrl-hint">System-assigned; the prefix lives under Settings.</p>
|
|
36
|
+
</div>
|
|
37
|
+
<% else %>
|
|
38
|
+
<p class="hrl-hint">The employee code is assigned automatically
|
|
39
|
+
(<%= HrLite::Setting.instance.employee_code_prefix %> + next number).</p>
|
|
40
|
+
<% end %>
|
|
32
41
|
<div class="hrl-field"><%= f.label :designation %><%= f.text_field :designation %></div>
|
|
33
42
|
<div class="hrl-field">
|
|
34
43
|
<%= f.label :manager_id, "Reports to (their L1)" %>
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<% content_for(:page_title) { "Employees" } %>
|
|
2
2
|
<div class="hrl-page__head">
|
|
3
3
|
<h1 class="hrl-page__title">Employees</h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<a class="hrl-btn hrl-btn--primary" href="<%= hr_lite.new_admin_employee_path %>">New employee</a>
|
|
6
|
+
</div>
|
|
4
7
|
</div>
|
|
5
8
|
|
|
6
9
|
<section class="hrl-card">
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
<h1 class="hrl-page__title"><%= hr_display_name(@profile.user) %> <span class="hrl-muted">(<%= @profile.employee_code %>)</span></h1>
|
|
4
4
|
<div class="hrl-page__actions">
|
|
5
5
|
<a class="hrl-btn" href="<%= hr_lite.edit_admin_employee_path(@profile) %>">Edit</a>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
<% if hr_superadmin? %>
|
|
7
|
+
<a class="hrl-btn" href="<%= hr_lite.new_admin_employee_appraisal_path(@profile) %>">New appraisal</a>
|
|
8
|
+
<a class="hrl-btn" href="<%= hr_lite.new_admin_employee_designation_change_path(@profile) %>">Role change</a>
|
|
9
|
+
<a class="hrl-btn hrl-btn--primary" href="<%= hr_lite.new_admin_employee_salary_structure_path(@profile) %>">New structure</a>
|
|
10
|
+
<% end %>
|
|
9
11
|
</div>
|
|
10
12
|
</div>
|
|
11
13
|
|
|
@@ -68,6 +70,7 @@
|
|
|
68
70
|
</dl>
|
|
69
71
|
</section>
|
|
70
72
|
|
|
73
|
+
<% if hr_superadmin? %>
|
|
71
74
|
<section class="hrl-card">
|
|
72
75
|
<h2 class="hrl-card__title">Salary structures</h2>
|
|
73
76
|
<% if @structures.any? %>
|
|
@@ -90,8 +93,10 @@
|
|
|
90
93
|
<p class="hrl-muted hrl-small">No structure yet — payroll will skip this employee.</p>
|
|
91
94
|
<% end %>
|
|
92
95
|
</section>
|
|
96
|
+
<% end %>
|
|
93
97
|
</div>
|
|
94
98
|
|
|
99
|
+
<% if hr_superadmin? %>
|
|
95
100
|
<section class="hrl-card">
|
|
96
101
|
<h2 class="hrl-card__title">Appraisals</h2>
|
|
97
102
|
<% appraisals = HrLite::Appraisal.where(user_id: @profile.user_id).recent_first %>
|
|
@@ -116,3 +121,4 @@
|
|
|
116
121
|
<p class="hrl-muted hrl-small">No appraisals yet.</p>
|
|
117
122
|
<% end %>
|
|
118
123
|
</section>
|
|
124
|
+
<% end %>
|
|
@@ -11,6 +11,13 @@
|
|
|
11
11
|
<%= f.select :weekend_policy, HrLite::Setting::WEEKEND_POLICIES.map { |p| [ p.humanize, p ] } %>
|
|
12
12
|
<p class="hrl-hint">Drives working-day math everywhere: leave counting, attendance, payroll.</p>
|
|
13
13
|
</div>
|
|
14
|
+
<div class="hrl-field">
|
|
15
|
+
<%= f.label :employee_code_prefix, "Employee code prefix" %>
|
|
16
|
+
<%= f.text_field :employee_code_prefix %>
|
|
17
|
+
<p class="hrl-hint">Codes are assigned automatically as
|
|
18
|
+
<%= @setting.employee_code_prefix %>001, <%= @setting.employee_code_prefix %>002, …
|
|
19
|
+
— you only choose the prefix.</p>
|
|
20
|
+
</div>
|
|
14
21
|
<div class="hrl-form-actions">
|
|
15
22
|
<%= f.submit "Save", class: "hrl-btn hrl-btn--primary" %>
|
|
16
23
|
</div>
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
<% hrl_nav_items(HrLite::ApplicationHelper::LEADERSHIP_NAV_ITEMS).each do |item| %>
|
|
43
43
|
<%= hrl_nav_link(item) %>
|
|
44
44
|
<% end %>
|
|
45
|
+
<% if hr_superadmin? %>
|
|
46
|
+
<% hrl_nav_items(HrLite::ApplicationHelper::SUPERADMIN_NAV_ITEMS).each do |item| %>
|
|
47
|
+
<%= hrl_nav_link(item) %>
|
|
48
|
+
<% end %>
|
|
49
|
+
<% end %>
|
|
45
50
|
<% end %>
|
|
46
51
|
</nav>
|
|
47
52
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
class AddEmployeeCodePrefixToHrLiteSettings < ActiveRecord::Migration[8.0]
|
|
2
|
+
def change
|
|
3
|
+
# Employee codes are system-assigned: prefix + zero-padded sequence
|
|
4
|
+
# (EMP001, EMP002, ...). Leadership edits the prefix under Settings.
|
|
5
|
+
add_column :hr_lite_settings, :employee_code_prefix, :string, null: false, default: "EMP"
|
|
6
|
+
end
|
|
7
|
+
end
|
|
@@ -8,6 +8,7 @@ module HrLite
|
|
|
8
8
|
:employees_scope, :mentionable_users, :notify, :render_pdf, :company,
|
|
9
9
|
:time_zone, :currency_symbol, :on_designation_change,
|
|
10
10
|
:leadership_emails, :leadership_check, :extra_stylesheets,
|
|
11
|
+
:superadmin_emails, :superadmin_check,
|
|
11
12
|
:mailer_from, :public_url_base, :notification_matrix, :back_link,
|
|
12
13
|
:onboard_user, :offboard_user, :invite_url_for
|
|
13
14
|
|
|
@@ -49,6 +50,13 @@ module HrLite
|
|
|
49
50
|
emails = HrLite.config.leadership_emails.map { |e| e.to_s.downcase.strip }
|
|
50
51
|
emails.include?(user.email.to_s.downcase)
|
|
51
52
|
end
|
|
53
|
+
# Money tier: salary structures, payroll, slips, appraisals. Empty
|
|
54
|
+
# list means "same as leadership" (pre-0.5.0 behaviour).
|
|
55
|
+
@superadmin_emails = []
|
|
56
|
+
@superadmin_check = ->(user) do
|
|
57
|
+
emails = HrLite.config.superadmin_emails.map { |e| e.to_s.downcase.strip }.reject(&:empty?)
|
|
58
|
+
emails.empty? ? HrLite.leadership?(user) : emails.include?(user.email.to_s.downcase)
|
|
59
|
+
end
|
|
52
60
|
@extra_stylesheets = [] # host stylesheets linked AFTER hr_lite.css (CSS-var overrides)
|
|
53
61
|
@mailer_from = "hr@example.com"
|
|
54
62
|
@public_url_base = nil # e.g. "https://hr.example.com" — enables email links + HrLite.public_url
|
data/lib/hr_lite/version.rb
CHANGED
data/lib/hr_lite.rb
CHANGED
|
@@ -38,6 +38,10 @@ module HrLite
|
|
|
38
38
|
user.present? && !!config.leadership_check.call(user)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
def superadmin?(user)
|
|
42
|
+
user.present? && !!config.superadmin_check.call(user)
|
|
43
|
+
end
|
|
44
|
+
|
|
41
45
|
# Leadership members resolvable to actual user records (for bell
|
|
42
46
|
# notifications). Emails configured but absent from the user table are
|
|
43
47
|
# still reachable by email — see Notifications.
|
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.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kshitiz sinha
|
|
@@ -74,6 +74,7 @@ files:
|
|
|
74
74
|
- app/controllers/hr_lite/admin/salary_slips_controller.rb
|
|
75
75
|
- app/controllers/hr_lite/admin/salary_structures_controller.rb
|
|
76
76
|
- app/controllers/hr_lite/admin/settings_controller.rb
|
|
77
|
+
- app/controllers/hr_lite/admin/superadmin_controller.rb
|
|
77
78
|
- app/controllers/hr_lite/application_controller.rb
|
|
78
79
|
- app/controllers/hr_lite/appraisals_controller.rb
|
|
79
80
|
- app/controllers/hr_lite/attendance_controller.rb
|
|
@@ -236,6 +237,7 @@ files:
|
|
|
236
237
|
- db/migrate/20260719104316_create_hr_lite_comp_off_requests.rb
|
|
237
238
|
- db/migrate/20260719104317_create_hr_lite_regularization_requests.rb
|
|
238
239
|
- db/migrate/20260719162154_add_manager_to_hr_lite_employee_profiles.rb
|
|
240
|
+
- db/migrate/20260720094454_add_employee_code_prefix_to_hr_lite_settings.rb
|
|
239
241
|
- lib/generators/hr_lite/install/install_generator.rb
|
|
240
242
|
- lib/generators/hr_lite/install/templates/AFTER_INSTALL
|
|
241
243
|
- lib/generators/hr_lite/install/templates/initializer.rb
|