hr_lite 0.2.1 → 0.4.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +96 -0
  3. data/README.md +2 -1
  4. data/app/assets/stylesheets/hr_lite/hr_lite.css +35 -4
  5. data/app/controllers/hr_lite/admin/comp_off_requests_controller.rb +38 -0
  6. data/app/controllers/hr_lite/admin/employees_controller.rb +1 -1
  7. data/app/controllers/hr_lite/admin/leave_balances_controller.rb +1 -1
  8. data/app/controllers/hr_lite/admin/leave_types_controller.rb +1 -1
  9. data/app/controllers/hr_lite/admin/regularization_requests_controller.rb +38 -0
  10. data/app/controllers/hr_lite/comp_off_requests_controller.rb +46 -0
  11. data/app/controllers/hr_lite/leave_balances_controller.rb +1 -1
  12. data/app/controllers/hr_lite/leave_requests_controller.rb +1 -1
  13. data/app/controllers/hr_lite/org_controller.rb +51 -0
  14. data/app/controllers/hr_lite/regularization_requests_controller.rb +36 -0
  15. data/app/controllers/hr_lite/team_controller.rb +11 -0
  16. data/app/helpers/hr_lite/application_helper.rb +62 -3
  17. data/app/jobs/hr_lite/leave_year_rollover_job.rb +18 -6
  18. data/app/models/hr_lite/comp_off_request.rb +177 -0
  19. data/app/models/hr_lite/employee_profile.rb +55 -0
  20. data/app/models/hr_lite/leave_balance.rb +43 -10
  21. data/app/models/hr_lite/leave_request.rb +23 -5
  22. data/app/models/hr_lite/leave_type.rb +17 -0
  23. data/app/models/hr_lite/regularization_request.rb +181 -0
  24. data/app/services/hr_lite/team_day.rb +84 -0
  25. data/app/views/hr_lite/admin/comp_off_requests/index.html.erb +37 -0
  26. data/app/views/hr_lite/admin/comp_off_requests/show.html.erb +47 -0
  27. data/app/views/hr_lite/admin/employees/_form.html.erb +7 -0
  28. data/app/views/hr_lite/admin/employees/show.html.erb +1 -0
  29. data/app/views/hr_lite/admin/leave_balances/index.html.erb +1 -1
  30. data/app/views/hr_lite/admin/leave_requests/index.html.erb +2 -0
  31. data/app/views/hr_lite/admin/leave_types/_form.html.erb +4 -0
  32. data/app/views/hr_lite/admin/regularization_requests/index.html.erb +37 -0
  33. data/app/views/hr_lite/admin/regularization_requests/show.html.erb +50 -0
  34. data/app/views/hr_lite/admin/shared/_approvals_tabs.html.erb +11 -0
  35. data/app/views/hr_lite/attendance/show.html.erb +3 -0
  36. data/app/views/hr_lite/comp_off_requests/index.html.erb +42 -0
  37. data/app/views/hr_lite/comp_off_requests/new.html.erb +28 -0
  38. data/app/views/hr_lite/employee_profiles/show.html.erb +3 -0
  39. data/app/views/hr_lite/leave_balances/index.html.erb +1 -1
  40. data/app/views/hr_lite/leave_requests/_balance_chips.html.erb +2 -2
  41. data/app/views/hr_lite/leave_requests/index.html.erb +1 -0
  42. data/app/views/hr_lite/org/_node.html.erb +14 -0
  43. data/app/views/hr_lite/org/show.html.erb +38 -0
  44. data/app/views/hr_lite/regularization_requests/index.html.erb +41 -0
  45. data/app/views/hr_lite/regularization_requests/new.html.erb +30 -0
  46. data/app/views/hr_lite/team/show.html.erb +48 -0
  47. data/app/views/layouts/hr_lite/application.html.erb +1 -1
  48. data/config/routes.rb +14 -0
  49. data/db/migrate/20260719104315_add_comp_off_to_hr_lite_leave_types.rb +6 -0
  50. data/db/migrate/20260719104316_create_hr_lite_comp_off_requests.rb +24 -0
  51. data/db/migrate/20260719104317_create_hr_lite_regularization_requests.rb +20 -0
  52. data/db/migrate/20260719162154_add_manager_to_hr_lite_employee_profiles.rb +8 -0
  53. data/lib/hr_lite/configuration.rb +14 -0
  54. data/lib/hr_lite/leave_year.rb +33 -0
  55. data/lib/hr_lite/notifications.rb +14 -2
  56. data/lib/hr_lite/seeds.rb +16 -1
  57. data/lib/hr_lite/version.rb +1 -1
  58. data/lib/hr_lite.rb +8 -0
  59. metadata +27 -1
@@ -0,0 +1,20 @@
1
+ class CreateHrLiteRegularizationRequests < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :hr_lite_regularization_requests do |t|
4
+ t.bigint :user_id, null: false
5
+ t.date :date, null: false
6
+ t.datetime :check_in_at
7
+ t.datetime :check_out_at
8
+ t.text :reason, null: false
9
+ t.string :status, null: false, default: "pending"
10
+ t.bigint :decided_by_id
11
+ t.datetime :decided_at
12
+ t.text :decision_note
13
+
14
+ t.timestamps
15
+ end
16
+ add_index :hr_lite_regularization_requests, [ :user_id, :status ]
17
+ add_index :hr_lite_regularization_requests, [ :user_id, :date ]
18
+ add_index :hr_lite_regularization_requests, [ :status, :date ]
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ class AddManagerToHrLiteEmployeeProfiles < ActiveRecord::Migration[8.0]
2
+ def change
3
+ # Reporting line: the user this employee reports to (L1). The chain
4
+ # upward gives L2, L3, ... and powers the everyone-visible org chart.
5
+ add_column :hr_lite_employee_profiles, :manager_id, :bigint
6
+ add_index :hr_lite_employee_profiles, :manager_id
7
+ end
8
+ end
@@ -11,6 +11,19 @@ module HrLite
11
11
  :mailer_from, :public_url_base, :notification_matrix, :back_link,
12
12
  :onboard_user, :offboard_user, :invite_url_for
13
13
 
14
+ attr_reader :leave_year_start_month
15
+
16
+ # Misconfiguration must fail at boot, not as production 500s on every
17
+ # balance screen. Accepts "7" (ENV-friendly) and validates 1..12.
18
+ # Changing this on an install with EXISTING balance rows reinterprets
19
+ # them — set it once at install time (see docs/CONFIGURATION.md).
20
+ def leave_year_start_month=(value)
21
+ month = Integer(value)
22
+ raise ArgumentError, "leave_year_start_month must be 1..12, got #{value.inspect}" unless (1..12).cover?(month)
23
+
24
+ @leave_year_start_month = month
25
+ end
26
+
14
27
  # 0.1.0 pre-release name for public_url_base; kept as an alias so early
15
28
  # adopters' initializers don't break.
16
29
  alias_method :mail_link_base, :public_url_base
@@ -41,6 +54,7 @@ module HrLite
41
54
  @public_url_base = nil # e.g. "https://hr.example.com" — enables email links + HrLite.public_url
42
55
  @notification_matrix = nil # resolved lazily to Notifications::DEFAULT_MATRIX
43
56
  @back_link = nil # optional {label:, url:} for the shell nav
57
+ @leave_year_start_month = 1 # 1 = calendar year; 7 = July–June leave year
44
58
 
45
59
  # Leadership onboarding/offboarding. onboard_user must return a saved
46
60
  # user record (default: create on user_class with whatever of
@@ -0,0 +1,33 @@
1
+ module HrLite
2
+ # The leave year is the 12-month window balances live in. It starts on
3
+ # config.leave_year_start_month (1 = calendar year, 7 = July–June, the
4
+ # Indian travel-industry pattern). A year is identified by the calendar
5
+ # year its FIRST month falls in: with July starts, key 2026 spans
6
+ # 1 Jul 2026 – 30 Jun 2027.
7
+ module LeaveYear
8
+ module_function
9
+
10
+ def start_month
11
+ HrLite.config.leave_year_start_month
12
+ end
13
+
14
+ # The key (integer label) of the leave year containing `date`.
15
+ def key_for(date)
16
+ date.month >= start_month ? date.year : date.year - 1
17
+ end
18
+
19
+ def current_key
20
+ key_for(Date.current)
21
+ end
22
+
23
+ def range(key)
24
+ start = Date.new(key, start_month, 1)
25
+ start..(start >> 12) - 1
26
+ end
27
+
28
+ # "2026" for calendar years, "2026–27" otherwise.
29
+ def label(key)
30
+ start_month == 1 ? key.to_s : format("%d–%02d", key, (key + 1) % 100)
31
+ end
32
+ end
33
+ end
@@ -29,12 +29,24 @@ module HrLite
29
29
  "resignation.accepted" => { bell: true, email: true, leadership_email: true, leadership_bell: false },
30
30
  "resignation.withdrawn" => { bell: true, email: false, leadership_email: true, leadership_bell: false },
31
31
  "employee.onboarded" => { bell: true, email: true, leadership_email: true, leadership_bell: false },
32
- "payroll.draft_ready" => { bell: false, email: false, leadership_email: true, leadership_bell: true }
32
+ "payroll.draft_ready" => { bell: false, email: false, leadership_email: true, leadership_bell: true },
33
+ "leave.team_notice" => { bell: true, email: true, leadership_email: false, leadership_bell: false },
34
+ "comp_off.requested" => { bell: true, email: false, leadership_email: true, leadership_bell: true },
35
+ "comp_off.approved" => { bell: true, email: true, leadership_email: true, leadership_bell: false },
36
+ "comp_off.rejected" => { bell: true, email: true, leadership_email: false, leadership_bell: false },
37
+ "comp_off.cancelled" => { bell: true, email: false, leadership_email: true, leadership_bell: false },
38
+ "regularization.requested" => { bell: true, email: false, leadership_email: true, leadership_bell: false },
39
+ "regularization.approved" => { bell: true, email: true, leadership_email: true, leadership_bell: false },
40
+ "regularization.rejected" => { bell: true, email: true, leadership_email: false, leadership_bell: false },
41
+ "regularization.cancelled" => { bell: true, email: false, leadership_email: true, leadership_bell: false }
33
42
  }.freeze
34
43
 
35
44
  class << self
45
+ # DEFAULT under the host override: a host matrix pinned on an older
46
+ # gem version keeps working when new events ship (rows it doesn't
47
+ # know about fall back to the defaults instead of vanishing).
36
48
  def matrix
37
- HrLite.config.notification_matrix || DEFAULT_MATRIX
49
+ DEFAULT_MATRIX.merge(HrLite.config.notification_matrix || {})
38
50
  end
39
51
 
40
52
  def publish(event, title:, body: nil, path: nil, bell_to: [], email_to: [], lines: [], diff: nil, link_url: nil)
data/lib/hr_lite/seeds.rb CHANGED
@@ -7,13 +7,28 @@ module HrLite
7
7
  { code: "SL", name: "Sick leave", color: "#f59e0b", paid: true, annual_quota: 6, accrual: "yearly_upfront", carry_forward_cap: 0, position: 2 },
8
8
  { code: "EL", name: "Earned leave", color: "#10b981", paid: true, annual_quota: 15, accrual: "monthly", carry_forward_cap: 30, position: 3 },
9
9
  { code: "LWP", name: "Leave without pay", color: "#6b7280", paid: false, annual_quota: nil, accrual: "yearly_upfront", carry_forward_cap: 0, position: 4 },
10
- { code: "CO", name: "Comp off", color: "#8b5cf6", paid: true, annual_quota: 0, accrual: "yearly_upfront", carry_forward_cap: 0, position: 5 }
10
+ { code: "CO", name: "Comp off", color: "#8b5cf6", paid: true, annual_quota: 0, accrual: "yearly_upfront", carry_forward_cap: 0, position: 5, comp_off: true }
11
11
  ].freeze
12
12
 
13
13
  def self.run!
14
14
  seed_leave_types! + seed_holidays!
15
15
  end
16
16
 
17
+ # Deliberately NOT auto-run from run!: an operator unticking every
18
+ # comp-off flag to disable the feature must stay disabled across
19
+ # deploys ("re-runs never overwrite operator edits"). Pre-0.3.0
20
+ # installs call this once from their own upgrade seed, or just tick
21
+ # the box under Settings -> Leave types.
22
+ def self.seed_comp_off_flag!
23
+ return [] if LeaveType.exists?(comp_off: true)
24
+
25
+ type = LeaveType.find_by(code: "CO")
26
+ return [] if type.nil?
27
+
28
+ type.update!(comp_off: true)
29
+ [ "comp_off flag on CO" ]
30
+ end
31
+
17
32
  def self.seed_leave_types!
18
33
  DEFAULT_LEAVE_TYPES.filter_map do |attrs|
19
34
  next if LeaveType.exists?(code: attrs[:code])
@@ -1,3 +1,3 @@
1
1
  module HrLite
2
- VERSION = "0.2.1"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/hr_lite.rb CHANGED
@@ -2,6 +2,7 @@ require "hr_lite/version"
2
2
  require "hr_lite/engine"
3
3
  require "hr_lite/configuration"
4
4
  require "hr_lite/current"
5
+ require "hr_lite/leave_year"
5
6
  require "hr_lite/mention_parser"
6
7
  require "hr_lite/notifications"
7
8
  require "hr_lite/seeds"
@@ -57,6 +58,13 @@ module HrLite
57
58
  config.employees_scope.call.sort_by { |u| display_name(u).downcase }
58
59
  end
59
60
 
61
+ # employees minus anyone whose profile says they have exited — user
62
+ # accounts outlive employment (slip access), broadcasts must not.
63
+ def active_employees(on: Date.current)
64
+ exits = HrLite::EmployeeProfile.where.not(date_of_exit: nil).pluck(:user_id, :date_of_exit).to_h
65
+ employees.select { |u| exits[u.id].nil? || exits[u.id] >= on }
66
+ end
67
+
60
68
  def display_name(user)
61
69
  return "" if user.nil?
62
70
 
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.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kshitiz sinha
@@ -58,6 +58,7 @@ files:
58
58
  - app/controllers/hr_lite/admin/attendances_controller.rb
59
59
  - app/controllers/hr_lite/admin/audit_logs_controller.rb
60
60
  - app/controllers/hr_lite/admin/base_controller.rb
61
+ - app/controllers/hr_lite/admin/comp_off_requests_controller.rb
61
62
  - app/controllers/hr_lite/admin/designation_changes_controller.rb
62
63
  - app/controllers/hr_lite/admin/employees_controller.rb
63
64
  - app/controllers/hr_lite/admin/holidays_controller.rb
@@ -68,6 +69,7 @@ files:
68
69
  - app/controllers/hr_lite/admin/office_locations_controller.rb
69
70
  - app/controllers/hr_lite/admin/overview_controller.rb
70
71
  - app/controllers/hr_lite/admin/payroll_runs_controller.rb
72
+ - app/controllers/hr_lite/admin/regularization_requests_controller.rb
71
73
  - app/controllers/hr_lite/admin/resignations_controller.rb
72
74
  - app/controllers/hr_lite/admin/salary_slips_controller.rb
73
75
  - app/controllers/hr_lite/admin/salary_structures_controller.rb
@@ -77,14 +79,18 @@ files:
77
79
  - app/controllers/hr_lite/attendance_controller.rb
78
80
  - app/controllers/hr_lite/calendar_controller.rb
79
81
  - app/controllers/hr_lite/career_controller.rb
82
+ - app/controllers/hr_lite/comp_off_requests_controller.rb
80
83
  - app/controllers/hr_lite/employee_profiles_controller.rb
81
84
  - app/controllers/hr_lite/holidays_controller.rb
82
85
  - app/controllers/hr_lite/home_controller.rb
83
86
  - app/controllers/hr_lite/kudos_controller.rb
84
87
  - app/controllers/hr_lite/leave_balances_controller.rb
85
88
  - app/controllers/hr_lite/leave_requests_controller.rb
89
+ - app/controllers/hr_lite/org_controller.rb
90
+ - app/controllers/hr_lite/regularization_requests_controller.rb
86
91
  - app/controllers/hr_lite/resignations_controller.rb
87
92
  - app/controllers/hr_lite/salary_slips_controller.rb
93
+ - app/controllers/hr_lite/team_controller.rb
88
94
  - app/controllers/hr_lite/users_controller.rb
89
95
  - app/helpers/hr_lite/application_helper.rb
90
96
  - app/jobs/hr_lite/application_job.rb
@@ -99,6 +105,7 @@ files:
99
105
  - app/models/hr_lite/appraisal.rb
100
106
  - app/models/hr_lite/attendance_record.rb
101
107
  - app/models/hr_lite/audit_log.rb
108
+ - app/models/hr_lite/comp_off_request.rb
102
109
  - app/models/hr_lite/designation_change.rb
103
110
  - app/models/hr_lite/employee_profile.rb
104
111
  - app/models/hr_lite/holiday.rb
@@ -109,6 +116,7 @@ files:
109
116
  - app/models/hr_lite/leave_type.rb
110
117
  - app/models/hr_lite/office_location.rb
111
118
  - app/models/hr_lite/payroll_run.rb
119
+ - app/models/hr_lite/regularization_request.rb
112
120
  - app/models/hr_lite/resignation.rb
113
121
  - app/models/hr_lite/salary_slip.rb
114
122
  - app/models/hr_lite/salary_structure.rb
@@ -126,6 +134,7 @@ files:
126
134
  - app/services/hr_lite/payroll_run_processor.rb
127
135
  - app/services/hr_lite/pdf_renderer.rb
128
136
  - app/services/hr_lite/slip_builder.rb
137
+ - app/services/hr_lite/team_day.rb
129
138
  - app/services/hr_lite/working_calendar.rb
130
139
  - app/views/hr_lite/admin/appraisals/_form.html.erb
131
140
  - app/views/hr_lite/admin/appraisals/edit.html.erb
@@ -133,6 +142,8 @@ files:
133
142
  - app/views/hr_lite/admin/attendances/index.html.erb
134
143
  - app/views/hr_lite/admin/attendances/show.html.erb
135
144
  - app/views/hr_lite/admin/audit_logs/index.html.erb
145
+ - app/views/hr_lite/admin/comp_off_requests/index.html.erb
146
+ - app/views/hr_lite/admin/comp_off_requests/show.html.erb
136
147
  - app/views/hr_lite/admin/designation_changes/new.html.erb
137
148
  - app/views/hr_lite/admin/employees/_form.html.erb
138
149
  - app/views/hr_lite/admin/employees/edit.html.erb
@@ -155,11 +166,14 @@ files:
155
166
  - app/views/hr_lite/admin/payroll_runs/index.html.erb
156
167
  - app/views/hr_lite/admin/payroll_runs/new.html.erb
157
168
  - app/views/hr_lite/admin/payroll_runs/show.html.erb
169
+ - app/views/hr_lite/admin/regularization_requests/index.html.erb
170
+ - app/views/hr_lite/admin/regularization_requests/show.html.erb
158
171
  - app/views/hr_lite/admin/salary_slips/show.html.erb
159
172
  - app/views/hr_lite/admin/salary_structures/_form.html.erb
160
173
  - app/views/hr_lite/admin/salary_structures/edit.html.erb
161
174
  - app/views/hr_lite/admin/salary_structures/new.html.erb
162
175
  - app/views/hr_lite/admin/settings/edit.html.erb
176
+ - app/views/hr_lite/admin/shared/_approvals_tabs.html.erb
163
177
  - app/views/hr_lite/appraisals/index.html.erb
164
178
  - app/views/hr_lite/appraisals/show.html.erb
165
179
  - app/views/hr_lite/attendance/_month_grid.html.erb
@@ -167,6 +181,8 @@ files:
167
181
  - app/views/hr_lite/attendance/show.html.erb
168
182
  - app/views/hr_lite/calendar/show.html.erb
169
183
  - app/views/hr_lite/career/show.html.erb
184
+ - app/views/hr_lite/comp_off_requests/index.html.erb
185
+ - app/views/hr_lite/comp_off_requests/new.html.erb
170
186
  - app/views/hr_lite/employee_profiles/show.html.erb
171
187
  - app/views/hr_lite/event_mailer/event.html.erb
172
188
  - app/views/hr_lite/event_mailer/event.text.erb
@@ -182,6 +198,10 @@ files:
182
198
  - app/views/hr_lite/leave_requests/index.html.erb
183
199
  - app/views/hr_lite/leave_requests/new.html.erb
184
200
  - app/views/hr_lite/leave_requests/show.html.erb
201
+ - app/views/hr_lite/org/_node.html.erb
202
+ - app/views/hr_lite/org/show.html.erb
203
+ - app/views/hr_lite/regularization_requests/index.html.erb
204
+ - app/views/hr_lite/regularization_requests/new.html.erb
185
205
  - app/views/hr_lite/resignations/show.html.erb
186
206
  - app/views/hr_lite/salary_slips/_slip_detail.html.erb
187
207
  - app/views/hr_lite/salary_slips/index.html.erb
@@ -189,6 +209,7 @@ files:
189
209
  - app/views/hr_lite/salary_slips/show.html.erb
190
210
  - app/views/hr_lite/shared/_form_errors.html.erb
191
211
  - app/views/hr_lite/shared/_pagination.html.erb
212
+ - app/views/hr_lite/team/show.html.erb
192
213
  - app/views/layouts/hr_lite/application.html.erb
193
214
  - app/views/layouts/hr_lite/mailer.html.erb
194
215
  - app/views/layouts/hr_lite/mailer.text.erb
@@ -211,6 +232,10 @@ files:
211
232
  - db/migrate/20260718195953_create_hr_lite_appraisals.rb
212
233
  - db/migrate/20260718195954_create_hr_lite_designation_changes.rb
213
234
  - db/migrate/20260719065841_create_hr_lite_resignations.rb
235
+ - db/migrate/20260719104315_add_comp_off_to_hr_lite_leave_types.rb
236
+ - db/migrate/20260719104316_create_hr_lite_comp_off_requests.rb
237
+ - db/migrate/20260719104317_create_hr_lite_regularization_requests.rb
238
+ - db/migrate/20260719162154_add_manager_to_hr_lite_employee_profiles.rb
214
239
  - lib/generators/hr_lite/install/install_generator.rb
215
240
  - lib/generators/hr_lite/install/templates/AFTER_INSTALL
216
241
  - lib/generators/hr_lite/install/templates/initializer.rb
@@ -220,6 +245,7 @@ files:
220
245
  - lib/hr_lite/current.rb
221
246
  - lib/hr_lite/engine.rb
222
247
  - lib/hr_lite/geo.rb
248
+ - lib/hr_lite/leave_year.rb
223
249
  - lib/hr_lite/mention_parser.rb
224
250
  - lib/hr_lite/money.rb
225
251
  - lib/hr_lite/notifications.rb