hr_lite 0.5.2 → 0.6.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 +112 -1
- data/README.md +67 -31
- data/app/controllers/hr_lite/admin/attendances_controller.rb +21 -6
- data/app/controllers/hr_lite/admin/base_controller.rb +16 -6
- data/app/controllers/hr_lite/admin/comp_off_requests_controller.rb +16 -4
- data/app/controllers/hr_lite/admin/leadership_controller.rb +11 -8
- data/app/controllers/hr_lite/admin/leave_balances_controller.rb +4 -5
- data/app/controllers/hr_lite/admin/leave_requests_controller.rb +21 -5
- data/app/controllers/hr_lite/admin/payroll_runs_controller.rb +11 -2
- data/app/controllers/hr_lite/admin/regularization_requests_controller.rb +16 -4
- data/app/controllers/hr_lite/admin/role_assignments_controller.rb +63 -0
- data/app/controllers/hr_lite/admin/roles_controller.rb +73 -0
- data/app/controllers/hr_lite/admin/salary_slips_controller.rb +5 -6
- data/app/controllers/hr_lite/admin/superadmin_controller.rb +15 -11
- data/app/controllers/hr_lite/application_controller.rb +39 -1
- data/app/helpers/hr_lite/application_helper.rb +5 -2
- data/app/models/hr_lite/audit_log.rb +26 -1
- data/app/models/hr_lite/comp_off_request.rb +3 -1
- data/app/models/hr_lite/leave_request.rb +27 -4
- data/app/models/hr_lite/payroll_run.rb +30 -4
- data/app/models/hr_lite/regularization_request.rb +3 -4
- data/app/models/hr_lite/role.rb +66 -0
- data/app/models/hr_lite/role_assignment.rb +18 -0
- data/app/models/hr_lite/role_grant.rb +15 -0
- data/app/models/hr_lite/salary_slip.rb +1 -2
- data/app/services/hr_lite/access.rb +111 -0
- data/app/services/hr_lite/payroll_run_processor.rb +4 -1
- data/app/views/hr_lite/admin/roles/_form.html.erb +47 -0
- data/app/views/hr_lite/admin/roles/edit.html.erb +53 -0
- data/app/views/hr_lite/admin/roles/index.html.erb +49 -0
- data/app/views/hr_lite/admin/roles/new.html.erb +3 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20260817182124_add_status_constraints_and_appraisal_fk_to_hr_lite.rb +63 -0
- data/db/migrate/20260817183347_create_hr_lite_roles_and_grants.rb +49 -0
- data/db/migrate/20260817183629_seed_hr_lite_roles_from_email_tiers.rb +82 -0
- data/lib/generators/hr_lite/install/templates/initializer.rb +13 -7
- data/lib/hr_lite/configuration.rb +11 -7
- data/lib/hr_lite/current.rb +4 -0
- data/lib/hr_lite/financial_year.rb +26 -0
- data/lib/hr_lite/permissions.rb +79 -0
- data/lib/hr_lite/role_seeds.rb +81 -0
- data/lib/hr_lite/statutory_rate_card.rb +45 -5
- data/lib/hr_lite/version.rb +1 -1
- data/lib/hr_lite.rb +81 -11
- data/lib/tasks/hr_lite_tasks.rake +10 -2
- metadata +17 -1
data/lib/hr_lite.rb
CHANGED
|
@@ -3,6 +3,9 @@ require "hr_lite/engine"
|
|
|
3
3
|
require "hr_lite/configuration"
|
|
4
4
|
require "hr_lite/current"
|
|
5
5
|
require "hr_lite/leave_year"
|
|
6
|
+
require "hr_lite/financial_year"
|
|
7
|
+
require "hr_lite/permissions"
|
|
8
|
+
require "hr_lite/role_seeds"
|
|
6
9
|
require "hr_lite/mention_parser"
|
|
7
10
|
require "hr_lite/notifications"
|
|
8
11
|
require "hr_lite/seeds"
|
|
@@ -30,34 +33,101 @@ module HrLite
|
|
|
30
33
|
config.user_class.constantize
|
|
31
34
|
end
|
|
32
35
|
|
|
36
|
+
# --- authorization -----------------------------------------------------
|
|
37
|
+
|
|
38
|
+
# The question every gate now asks. `scope:` is what the CALLER needs;
|
|
39
|
+
# a holder with a wider scope satisfies it.
|
|
40
|
+
def can?(user, key, scope: :self)
|
|
41
|
+
Access.for(user).can?(key, scope: scope)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Whether `user` may exercise `key` over `subject`'s rows. This is the
|
|
45
|
+
# question that did not exist before roles, and its absence is why any
|
|
46
|
+
# admin could approve anybody's leave.
|
|
47
|
+
def reaches?(user, key, subject)
|
|
48
|
+
Access.for(user).reaches?(key, subject)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def access_for(user) = Access.for(user)
|
|
52
|
+
|
|
53
|
+
# --- legacy tier predicates --------------------------------------------
|
|
54
|
+
#
|
|
55
|
+
# Kept because views, hosts and the notification fan-out all call them.
|
|
56
|
+
# They are now READ OFF ROLES rather than off a mutable email column; the
|
|
57
|
+
# configured lambdas survive only as an explicit opt-in for a host that
|
|
58
|
+
# has not migrated yet (see Configuration#legacy_tier_checks).
|
|
59
|
+
|
|
33
60
|
def admin?(user)
|
|
34
|
-
user.
|
|
61
|
+
return false if user.blank?
|
|
62
|
+
return !!config.admin_check.call(user) if config.legacy_tier_checks
|
|
63
|
+
|
|
64
|
+
can?(user, "leave.approve", scope: :all) || can?(user, "attendance.manage", scope: :all)
|
|
35
65
|
end
|
|
36
66
|
|
|
37
67
|
def leadership?(user)
|
|
38
|
-
user.
|
|
68
|
+
return false if user.blank?
|
|
69
|
+
return !!config.leadership_check.call(user) if config.legacy_tier_checks
|
|
70
|
+
|
|
71
|
+
can?(user, "profile.manage", scope: :all)
|
|
39
72
|
end
|
|
40
73
|
|
|
41
74
|
def superadmin?(user)
|
|
42
|
-
user.
|
|
75
|
+
return false if user.blank?
|
|
76
|
+
return !!config.superadmin_check.call(user) if config.legacy_tier_checks
|
|
77
|
+
|
|
78
|
+
can?(user, "payroll.manage", scope: :all)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# An access list, cleaned. "a@x.com,,b@x.com".split(",") — one stray
|
|
82
|
+
# comma in an ENV var — used to put "" in the list, and a user whose
|
|
83
|
+
# email was blank then MATCHED it and was handed the tier.
|
|
84
|
+
def normalize_email_list(emails)
|
|
85
|
+
Array(emails).map { |e| e.to_s.downcase.strip }.reject(&:empty?)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Whether a user's own email is on a configured access list. A blank
|
|
89
|
+
# email is never on any list, however the list is spelled.
|
|
90
|
+
def email_listed?(user, emails)
|
|
91
|
+
address = user.respond_to?(:email) ? user.email.to_s.downcase.strip : ""
|
|
92
|
+
return false if address.empty?
|
|
93
|
+
|
|
94
|
+
normalize_email_list(emails).include?(address)
|
|
43
95
|
end
|
|
44
96
|
|
|
45
97
|
# Leadership members resolvable to actual user records (for bell
|
|
46
|
-
# notifications).
|
|
47
|
-
# still reachable by email — see Notifications.
|
|
98
|
+
# notifications). On a legacy host, emails configured but absent from the
|
|
99
|
+
# user table are still reachable by email — see Notifications.
|
|
48
100
|
def leadership_users
|
|
49
|
-
|
|
101
|
+
unless config.legacy_tier_checks
|
|
102
|
+
return users_holding("profile.manage", scope: :all)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
emails = normalize_email_list(config.leadership_emails)
|
|
50
106
|
return user_klass.none if emails.empty?
|
|
51
107
|
|
|
52
108
|
user_klass.where("LOWER(#{user_klass.table_name}.email) IN (?)", emails)
|
|
53
109
|
end
|
|
54
110
|
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
|
|
58
|
-
|
|
111
|
+
# Everyone whose roles grant `key` at `scope` or wider. One query over
|
|
112
|
+
# the grant tables rather than instantiating every user and asking.
|
|
113
|
+
def users_holding(key, scope: :all)
|
|
114
|
+
wide = Permissions::SCOPE_RANK.select { |_, rank| rank >= Permissions::SCOPE_RANK.fetch(scope) }
|
|
115
|
+
ids = RoleAssignment.joins(role: :role_grants)
|
|
116
|
+
.where(hr_lite_role_grants: {
|
|
117
|
+
permission_key: Permissions.validate!(key), scope: wide.keys.map(&:to_s)
|
|
118
|
+
})
|
|
119
|
+
.distinct.pluck(:user_id)
|
|
120
|
+
user_klass.where(id: ids)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Every domain event that bells the admins calls this. On roles it is one
|
|
124
|
+
# query over the grant tables; on a legacy host it still has to run the
|
|
125
|
+
# host's lambda per row, which is why it starts from employees_scope
|
|
126
|
+
# (narrowed to real staff) rather than every row that exists.
|
|
59
127
|
def admin_users
|
|
60
|
-
employees.select { |u| admin?(u) }
|
|
128
|
+
return employees.select { |u| admin?(u) } if config.legacy_tier_checks
|
|
129
|
+
|
|
130
|
+
users_holding("leave.approve", scope: :all).sort_by { |u| display_name(u).downcase }
|
|
61
131
|
end
|
|
62
132
|
|
|
63
133
|
# Everyone HR tracks (host-overridable to exclude bots/test accounts),
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
namespace :hr_lite do
|
|
2
|
-
desc "Idempotently seed HR reference data (leave types, national holidays)"
|
|
2
|
+
desc "Idempotently seed HR reference data (leave types, national holidays, roles)"
|
|
3
3
|
task seed: :environment do
|
|
4
4
|
require "hr_lite/seeds"
|
|
5
|
-
|
|
5
|
+
require "hr_lite/role_seeds"
|
|
6
|
+
created = HrLite::Seeds.run! + HrLite::RoleSeeds.call
|
|
6
7
|
puts created.any? ? "hr_lite:seed created: #{created.join(', ')}" : "hr_lite:seed — nothing to do"
|
|
7
8
|
end
|
|
9
|
+
|
|
10
|
+
desc "Idempotently seed the built-in roles only (never overwrites a tuned role)"
|
|
11
|
+
task roles: :environment do
|
|
12
|
+
require "hr_lite/role_seeds"
|
|
13
|
+
created = HrLite::RoleSeeds.call
|
|
14
|
+
puts created.any? ? "hr_lite:roles created: #{created.join(', ')}" : "hr_lite:roles — nothing to do"
|
|
15
|
+
end
|
|
8
16
|
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.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kshitiz sinha
|
|
@@ -72,6 +72,8 @@ files:
|
|
|
72
72
|
- app/controllers/hr_lite/admin/payroll_runs_controller.rb
|
|
73
73
|
- app/controllers/hr_lite/admin/regularization_requests_controller.rb
|
|
74
74
|
- app/controllers/hr_lite/admin/resignations_controller.rb
|
|
75
|
+
- app/controllers/hr_lite/admin/role_assignments_controller.rb
|
|
76
|
+
- app/controllers/hr_lite/admin/roles_controller.rb
|
|
75
77
|
- app/controllers/hr_lite/admin/salary_slips_controller.rb
|
|
76
78
|
- app/controllers/hr_lite/admin/salary_structures_controller.rb
|
|
77
79
|
- app/controllers/hr_lite/admin/settings_controller.rb
|
|
@@ -120,9 +122,13 @@ files:
|
|
|
120
122
|
- app/models/hr_lite/payroll_run.rb
|
|
121
123
|
- app/models/hr_lite/regularization_request.rb
|
|
122
124
|
- app/models/hr_lite/resignation.rb
|
|
125
|
+
- app/models/hr_lite/role.rb
|
|
126
|
+
- app/models/hr_lite/role_assignment.rb
|
|
127
|
+
- app/models/hr_lite/role_grant.rb
|
|
123
128
|
- app/models/hr_lite/salary_slip.rb
|
|
124
129
|
- app/models/hr_lite/salary_structure.rb
|
|
125
130
|
- app/models/hr_lite/setting.rb
|
|
131
|
+
- app/services/hr_lite/access.rb
|
|
126
132
|
- app/services/hr_lite/attendance_puncher.rb
|
|
127
133
|
- app/services/hr_lite/attendance_summary.rb
|
|
128
134
|
- app/services/hr_lite/calculators/esi.rb
|
|
@@ -170,6 +176,10 @@ files:
|
|
|
170
176
|
- app/views/hr_lite/admin/payroll_runs/show.html.erb
|
|
171
177
|
- app/views/hr_lite/admin/regularization_requests/index.html.erb
|
|
172
178
|
- app/views/hr_lite/admin/regularization_requests/show.html.erb
|
|
179
|
+
- app/views/hr_lite/admin/roles/_form.html.erb
|
|
180
|
+
- app/views/hr_lite/admin/roles/edit.html.erb
|
|
181
|
+
- app/views/hr_lite/admin/roles/index.html.erb
|
|
182
|
+
- app/views/hr_lite/admin/roles/new.html.erb
|
|
173
183
|
- app/views/hr_lite/admin/salary_slips/show.html.erb
|
|
174
184
|
- app/views/hr_lite/admin/salary_structures/_form.html.erb
|
|
175
185
|
- app/views/hr_lite/admin/salary_structures/edit.html.erb
|
|
@@ -242,6 +252,9 @@ files:
|
|
|
242
252
|
- db/migrate/20260807184103_add_live_uniqueness_indexes_to_hr_lite.rb
|
|
243
253
|
- db/migrate/20260807184426_add_fy_opening_to_hr_lite_employee_profiles.rb
|
|
244
254
|
- db/migrate/20260807184939_add_out_of_window_days_to_hr_lite_salary_slips.rb
|
|
255
|
+
- db/migrate/20260817182124_add_status_constraints_and_appraisal_fk_to_hr_lite.rb
|
|
256
|
+
- db/migrate/20260817183347_create_hr_lite_roles_and_grants.rb
|
|
257
|
+
- db/migrate/20260817183629_seed_hr_lite_roles_from_email_tiers.rb
|
|
245
258
|
- lib/generators/hr_lite/install/install_generator.rb
|
|
246
259
|
- lib/generators/hr_lite/install/templates/AFTER_INSTALL
|
|
247
260
|
- lib/generators/hr_lite/install/templates/initializer.rb
|
|
@@ -250,11 +263,14 @@ files:
|
|
|
250
263
|
- lib/hr_lite/configuration.rb
|
|
251
264
|
- lib/hr_lite/current.rb
|
|
252
265
|
- lib/hr_lite/engine.rb
|
|
266
|
+
- lib/hr_lite/financial_year.rb
|
|
253
267
|
- lib/hr_lite/geo.rb
|
|
254
268
|
- lib/hr_lite/leave_year.rb
|
|
255
269
|
- lib/hr_lite/mention_parser.rb
|
|
256
270
|
- lib/hr_lite/money.rb
|
|
257
271
|
- lib/hr_lite/notifications.rb
|
|
272
|
+
- lib/hr_lite/permissions.rb
|
|
273
|
+
- lib/hr_lite/role_seeds.rb
|
|
258
274
|
- lib/hr_lite/seeds.rb
|
|
259
275
|
- lib/hr_lite/statutory_rate_card.rb
|
|
260
276
|
- lib/hr_lite/version.rb
|