hr_lite 0.5.0 → 0.5.3

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +218 -1
  3. data/README.md +312 -99
  4. data/app/assets/javascripts/hr_lite/confirm.js +31 -0
  5. data/app/assets/stylesheets/hr_lite/hr_lite.css +28 -0
  6. data/app/controllers/hr_lite/admin/attendances_controller.rb +19 -5
  7. data/app/controllers/hr_lite/admin/audit_logs_controller.rb +4 -1
  8. data/app/controllers/hr_lite/admin/employees_controller.rb +36 -12
  9. data/app/controllers/hr_lite/admin/leave_balances_controller.rb +19 -13
  10. data/app/controllers/hr_lite/admin/leave_requests_controller.rb +16 -0
  11. data/app/controllers/hr_lite/admin/payroll_runs_controller.rb +11 -2
  12. data/app/controllers/hr_lite/admin/resignations_controller.rb +17 -5
  13. data/app/controllers/hr_lite/admin/salary_slips_controller.rb +22 -8
  14. data/app/controllers/hr_lite/admin/superadmin_controller.rb +5 -0
  15. data/app/controllers/hr_lite/org_controller.rb +6 -1
  16. data/app/controllers/hr_lite/resignations_controller.rb +6 -1
  17. data/app/helpers/hr_lite/application_helper.rb +2 -12
  18. data/app/jobs/hr_lite/application_job.rb +5 -0
  19. data/app/jobs/hr_lite/daily_digest_job.rb +1 -1
  20. data/app/jobs/hr_lite/leave_year_rollover_job.rb +1 -1
  21. data/app/jobs/hr_lite/payroll_auto_draft_job.rb +5 -2
  22. data/app/models/concerns/hr_lite/audited.rb +11 -4
  23. data/app/models/hr_lite/appraisal.rb +9 -1
  24. data/app/models/hr_lite/audit_log.rb +36 -0
  25. data/app/models/hr_lite/comp_off_request.rb +8 -16
  26. data/app/models/hr_lite/designation_change.rb +18 -1
  27. data/app/models/hr_lite/employee_profile.rb +5 -1
  28. data/app/models/hr_lite/leave_balance.rb +51 -5
  29. data/app/models/hr_lite/leave_request.rb +36 -5
  30. data/app/models/hr_lite/leave_type.rb +13 -3
  31. data/app/models/hr_lite/payroll_run.rb +68 -13
  32. data/app/models/hr_lite/regularization_request.rb +11 -4
  33. data/app/models/hr_lite/resignation.rb +27 -0
  34. data/app/models/hr_lite/salary_slip.rb +8 -5
  35. data/app/services/hr_lite/attendance_puncher.rb +8 -1
  36. data/app/services/hr_lite/calculators/esi.rb +7 -4
  37. data/app/services/hr_lite/calculators/professional_tax.rb +5 -1
  38. data/app/services/hr_lite/calculators/tds.rb +8 -1
  39. data/app/services/hr_lite/leave_day_counter.rb +9 -4
  40. data/app/services/hr_lite/overview_query.rb +12 -1
  41. data/app/services/hr_lite/payroll_run_processor.rb +9 -1
  42. data/app/services/hr_lite/slip_builder.rb +54 -8
  43. data/app/views/hr_lite/admin/attendances/index.html.erb +4 -1
  44. data/app/views/hr_lite/admin/comp_off_requests/show.html.erb +19 -5
  45. data/app/views/hr_lite/admin/employees/_form.html.erb +20 -2
  46. data/app/views/hr_lite/admin/employees/show.html.erb +25 -15
  47. data/app/views/hr_lite/admin/leave_requests/show.html.erb +37 -5
  48. data/app/views/hr_lite/admin/overview/index.html.erb +21 -0
  49. data/app/views/hr_lite/admin/payroll_runs/show.html.erb +3 -1
  50. data/app/views/hr_lite/admin/regularization_requests/show.html.erb +18 -4
  51. data/app/views/hr_lite/attendance/_punch_card.html.erb +22 -2
  52. data/app/views/hr_lite/career/show.html.erb +7 -1
  53. data/app/views/hr_lite/salary_slips/_slip_detail.html.erb +5 -1
  54. data/app/views/hr_lite/salary_slips/pdf.html.erb +5 -5
  55. data/app/views/layouts/hr_lite/application.html.erb +42 -4
  56. data/config/routes.rb +1 -1
  57. data/db/migrate/20260807184103_add_live_uniqueness_indexes_to_hr_lite.rb +28 -0
  58. data/db/migrate/20260807184426_add_fy_opening_to_hr_lite_employee_profiles.rb +14 -0
  59. data/db/migrate/20260807184939_add_out_of_window_days_to_hr_lite_salary_slips.rb +12 -0
  60. data/db/migrate/20260817182124_add_status_constraints_and_appraisal_fk_to_hr_lite.rb +63 -0
  61. data/lib/hr_lite/amount_in_words.rb +15 -2
  62. data/lib/hr_lite/configuration.rb +3 -6
  63. data/lib/hr_lite/financial_year.rb +26 -0
  64. data/lib/hr_lite/money.rb +18 -0
  65. data/lib/hr_lite/notifications.rb +23 -8
  66. data/lib/hr_lite/statutory_rate_card.rb +51 -6
  67. data/lib/hr_lite/version.rb +1 -1
  68. data/lib/hr_lite.rb +23 -2
  69. metadata +7 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00cc5c346c88ddc803a5336a1c14a07dd4609fc887213f99e9b11654f26fa109
4
- data.tar.gz: 8306411151a38ea5b1fe0fe9c7b4bd3572e16917a1defc1e15d4e823ab7f9c1b
3
+ metadata.gz: bdcc58ee5fdba440b0f70b9f22b85d85d20ef02f16c92481d4aad89a2395489f
4
+ data.tar.gz: f705fe091062bbe92246fd19fb1615c9fd9e0f2c6ed34ece293d155cc81879b1
5
5
  SHA512:
6
- metadata.gz: 6f9be2057c4023881d956fc8feadb18d2917bb38cd92746b7a448a60fedea0fc94d335b22d36a627a8ce888e36a7520ca6118ad77e6f5956b96fdec695f813dc
7
- data.tar.gz: 95c8048ecd82dc4b92d9e4e5b79240bed1385e297206383280c76e010d141f666e57eb150eac9defdbe556978226d7b4a5fff21ff8132103e04e09862a36f3ad
6
+ metadata.gz: c674e21d22c69a6b2ff5e51cbbb329f166140054212d81a2582c5d0b421350a732c94ae2b8074e4da15f4b510f9a0fa5bfceda84c633b57def295c2066276370
7
+ data.tar.gz: 514bf9fa94450d2ccdd4a7443125ec355dd4d68e99c264eac62fe3b5b3be2034a17a64c94571ef51580b97a8ebd59ba85e0a05a55474e3ec80dd9a4ebf798a7d
data/CHANGELOG.md CHANGED
@@ -7,6 +7,213 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.3] - 2026-08-17
11
+
12
+ Correctness and traceability pass, ahead of the permissions work in 0.6.0.
13
+ **Adds one migration** — check constraints on every status column, plus an
14
+ index and foreign key on `hr_lite_designation_changes.appraisal_id`. It
15
+ refuses to run, naming the table and the offending values, if a live row
16
+ already holds a status no model declares.
17
+
18
+ ### Fixed
19
+
20
+ - **Payroll ran silently on an out-of-date statutory card.** The lookup fell
21
+ back to the newest card on or before the run month with no signal, so a run
22
+ in a financial year the gem ships no card for computed PF, ESI, PT and TDS
23
+ on the previous year's figures and said nothing. It still falls back —
24
+ payroll cannot stop dead every 1 April — but `PayrollRunProcessor` now puts
25
+ a warning naming both financial years at the TOP of the run's warnings, on
26
+ every compute. Adding a year remains one new entry in
27
+ `StatutoryRateCard::CARDS`; rates are never inferred forward.
28
+ - **A blank email could be granted the leadership tier.** `leadership_check`
29
+ did not drop empty entries the way `superadmin_check` did, so one stray
30
+ comma in `HR_LEADERSHIP_EMAILS` ("a@x.com,,b@x.com") put `""` on the list
31
+ and any user whose email was blank or nil matched it. Both checks now share
32
+ `HrLite.email_listed?`, which refuses a blank address against any list.
33
+ - Comp-off approval no longer reaches for a plural that cannot occur — a
34
+ credit is 0.5 or 1 day and never more.
35
+
36
+ ### Added
37
+
38
+ - **The money path leaves a trail.** Payroll compute, finalize, unlock and
39
+ publish, every leave approval, rejection and cancellation, and the payout
40
+ register download now write `AuditLog` rows. Previously a run could be
41
+ computed, finalized, unlocked, edited and republished and the audit screen
42
+ showed none of it.
43
+ - These rows are written inside the same transaction as the change they
44
+ describe and RAISE on failure, unlike the `Audited` concern, which stays
45
+ best-effort for ordinary policy edits. A payroll transition nobody can
46
+ account for afterwards does not happen at all.
47
+ - Amounts are deliberately excluded — `audit_logs` is not encrypted. Rows
48
+ record who moved a run, how far, and over how many people. Leave rows
49
+ carry the approver's note and never the employee's own reason.
50
+ - `HrLite::PayrollRun` and `HrLite::SalarySlip` join `MONEY_TIER_TYPES`, so
51
+ payroll rows stay out of the leadership audit screen.
52
+ - `HrLite::AuditLog.record!` — the five-line `create!` that five call sites
53
+ had each written out.
54
+ - `HrLite::FinancialYear` — the Indian FY (1 April) worked out in one place
55
+ instead of three.
56
+
57
+ ### Changed
58
+
59
+ - Statuses are enforced by the database. `update_column`, `update_all`,
60
+ `insert_all` and console fixes can no longer write a value that no screen
61
+ renders and no transition accepts.
62
+ - The suite enforces its own coverage: 100% line, 90% branch, 90% per file.
63
+ The README claimed 100% and nothing checked it; switching the floor on found
64
+ eight untested paths, including all three slip-override money guards (LOP
65
+ above the days in the month, negative LOP, negative TDS) and the offboarding
66
+ error path. All are covered now.
67
+ - `docs/PAYROLL.md` no longer lists ESI contribution-period lock-in as
68
+ unmodelled — 0.5.2 implemented it.
69
+
70
+ ## [0.5.2] - 2026-08-08
71
+
72
+ The rest of the audit that produced 0.5.1. **Adds three migrations** — they
73
+ run through the host's normal `db:migrate`; each table holds a handful of
74
+ rows per employee, so the builds are instant.
75
+
76
+ ### Fixed
77
+
78
+ - **Payroll accepted a run for a month that had not ended.** Days that have
79
+ not happened score as `upcoming`, which fed straight into payable days, so
80
+ computing mid-month paid for every remaining day as if it had been worked —
81
+ and finalizing froze that into immutable slips. `parse_month_param` made it
82
+ easy to reach: a mangled month fell back to the current one.
83
+ - **ESI eligibility was re-decided every month.** ESIC contribution periods run
84
+ April–September and October–March and eligibility holds for the whole
85
+ period; a mid-period raise past the ceiling used to end coverage on the spot.
86
+ - **A mid-year install deducted no tax.** TDS projected the year only from
87
+ slips this install produced, so earlier months — a previous employer, or the
88
+ months before payroll was switched on — read as zero income and usually put
89
+ the year under the rebate cap. `EmployeeProfile` gains `fy_opening_gross`
90
+ and `fy_opening_tds`.
91
+ - Regularization now re-checks the approved-leave conflict at approval. Leave
92
+ granted while the ticket waited made the fix a silent no-op, because
93
+ full-day leave outranks any punch — while everyone was told attendance had
94
+ been corrected.
95
+ - Admins can cancel leave. `cancellable_by?` always allowed it for approved
96
+ leave that has not started, but no route reached it, so leave called off
97
+ while someone was away could not be released and the quota stayed spent.
98
+ - One open resignation per person, one pending regularization per person per
99
+ day, and one leave type carrying the comp-off flag are now enforced by
100
+ partial unique indexes, not only by validations that race. Retiring the
101
+ flagged comp-off type releases the flag so a replacement can take it.
102
+ - An employee whose resignation was already accepted can no longer file
103
+ another, which would have overwritten the agreed exit date.
104
+ - `Audited` fires on commit. Firing inside the transaction announced changes
105
+ to leadership that then rolled back — a failed onboarding mailed out a diff
106
+ for a profile that was never saved.
107
+ - Slips record and show days outside the employment window, so a mid-month
108
+ joiner's payslip adds up instead of looking short.
109
+ - The career page dates the current role from the change actually in force,
110
+ not from a promotion recorded for next quarter.
111
+ - The org chart's reporting line stops at the first manager who has left; it
112
+ used to skip them and promote everyone above a level, contradicting the
113
+ tree below.
114
+ - Publishing no longer bells offboarded people at a page their revoked login
115
+ cannot open. They still get the email.
116
+ - Leadership copies of employee-scoped notifications are named and point at a
117
+ page leadership can open. "Your appraisal has been shared" linking to
118
+ `/appraisals/7` was fanned out verbatim; the leadership copy also drops the
119
+ rating, which is money-tier.
120
+
121
+ ### Performance
122
+
123
+ - `LeaveBalance#used` builds one working calendar for the leave year instead
124
+ of one per approved request — measured 11 queries down to 1 for five
125
+ requests, and the admin balances grid multiplies that by employees × leave
126
+ types.
127
+ - `HrLite.admin_users` starts from `employees_scope` rather than loading and
128
+ instantiating every row in the users table on each admin notification.
129
+
130
+ ## [0.5.1] - 2026-08-07
131
+
132
+ Bug-fix release from a full audit of the engine. No migrations, no
133
+ configuration changes required.
134
+
135
+ ### Fixed
136
+
137
+ - **Every admin "Reject" button returned a 422.** The decision screens
138
+ rendered one form pointed at the approve endpoint and retargeted the
139
+ Reject button with `formaction:`. Rails binds the authenticity token to
140
+ the form's own action and method (`per_form_csrf_tokens`, the default
141
+ since `load_defaults 5.0`), so that token was never valid at the reject
142
+ path. Comp-off, leave and regularization rejections could not be made
143
+ from a browser at all. Each screen now renders separate Approve and
144
+ Reject forms.
145
+ - **`PayrollRun#compute!` demoted any run — including a published one — to
146
+ `draft`.** The `raise_unless` guard raised inside the method-level
147
+ rescue, which then rewrote the status. Draft runs are deletable and the
148
+ delete cascades over every salary slip. The guard now sits outside the
149
+ rescue and the previous status is restored; a run stranded in
150
+ `processing` is recoverable.
151
+ - **TDS was wrong on every slip from April to December**: months remaining
152
+ in the financial year read `15 - month` instead of `16 - month`.
153
+ - TDS to-date counted published slips only, so a finalized-but-unpublished
154
+ month projected as zero income; §115BAC marginal relief above the rebate
155
+ cap was missing; a leaver's projection ran past their exit month.
156
+ - Net pay is floored at zero and the run warns when deductions exceed
157
+ earnings. Review-stage LOP and TDS overrides are bounded.
158
+ - **A configured superadmin absent from `leadership_emails` was locked out
159
+ of the money tier entirely.** `SuperadminController` no longer inherits
160
+ the leadership check, and the Payroll nav item hangs off the money tier.
161
+ - Appraisal ratings and review text reached ordinary leadership through
162
+ the audit screen and the `policy.changed` email; money-tier subjects are
163
+ excluded from both.
164
+ - Accepting a resignation stamped an exit date, which hid the only control
165
+ that revokes sign-in. The card stays, and access is revoked immediately
166
+ when the last day has already passed.
167
+ - Onboarding created the login before validating the profile and outside
168
+ any transaction, leaving orphaned role-bearing accounts behind.
169
+ - A backdated `DesignationChange` overwrote the current designation and
170
+ pushed it to the host; only the newest row applies now.
171
+ - Editing a profile whose manager had exited silently cleared the
172
+ reporting line, because the select offered no matching option.
173
+ - Leave: creation and approval use the same as-of date (future-dated
174
+ requests on monthly accrual could be filed but never approved); approval
175
+ locks the balance row rather than the request row; the stored adjustment
176
+ has one locked write path; entitlement stops accruing at the exit date;
177
+ the comp-off flag can be moved to a replacement leave type.
178
+ - Attendance: a check-out with no check-in is refused; clearing both times
179
+ on a day with no punch no longer writes a bogus audit row or emails a
180
+ removal that never happened; the punch card offers yesterday's check-out
181
+ after midnight; `geo_status` is confined to what a browser can report.
182
+ - The overview board counts and lists comp-off and regularization, and the
183
+ team attendance KPIs add up to the headcount again.
184
+ - One bad recipient no longer drops the rest of a notification fan-out.
185
+ - The slip PDF formats money like the web slip; amounts in words handle
186
+ negatives and figures above ₹100 crore; professional-tax slabs gained an
187
+ inclusive `from:` bound.
188
+
189
+ ### Added
190
+
191
+ - A **More** tab on phones, opening a sheet with every nav item and every
192
+ group the viewer is entitled to. Below 768px the left rail is hidden and
193
+ the tab bar holds five items, so the rest of the app — including all
194
+ admin, leadership and payroll screens — was unreachable.
195
+ - Confirmation prompts that actually run. The engine ships no Turbo, so
196
+ its `data-turbo-confirm` attributes were inert and destructive buttons
197
+ fired on the first click. A small script reads the same attribute and
198
+ stands aside when a host does load Turbo.
199
+ - A retry policy on the engine's jobs, which had never inherited
200
+ `ApplicationJob`.
201
+
202
+ ### Documentation
203
+
204
+ - Reworked the README to open-source standard: a shields.io badge row, a table
205
+ of contents, a per-feature usage guide (attendance and geolocation; leave,
206
+ comp-off and regularization; payroll; kudos and @mentions; the notification
207
+ bus), and sections for the recurring jobs, rake tasks and the install
208
+ generator.
209
+ - Documented the leadership and superadmin (money) access tiers, and the
210
+ `HR_LEADERSHIP_EMAILS` convention the generated initializer uses to keep the
211
+ governing list out of a deploy.
212
+ - Filled gaps in `docs/CONFIGURATION.md`: the `superadmin_check`,
213
+ `public_url_base`, `onboard_user`, `offboard_user` and `invite_url_for`
214
+ keys, and the `resignation.*`, `employee.onboarded` and `payroll.draft_ready`
215
+ rows of the notification matrix.
216
+
10
217
  ## [0.5.0] - 2026-07-20
11
218
 
12
219
  ### Added
@@ -202,5 +409,15 @@ Initial release.
202
409
  bus with per-event channel matrix (bell, email, leadership email/bell),
203
410
  daily leadership digest and an append-only audit trail.
204
411
 
205
- [Unreleased]: https://github.com/kshtzkr/hr_lite/compare/v0.1.0...HEAD
412
+ [Unreleased]: https://github.com/kshtzkr/hr_lite/compare/v0.5.3...HEAD
413
+ [0.5.3]: https://github.com/kshtzkr/hr_lite/compare/v0.5.2...v0.5.3
414
+ [0.5.2]: https://github.com/kshtzkr/hr_lite/compare/v0.5.1...v0.5.2
415
+ [0.5.1]: https://github.com/kshtzkr/hr_lite/compare/v0.5.0...v0.5.1
416
+ [0.5.0]: https://github.com/kshtzkr/hr_lite/compare/v0.4.0...v0.5.0
417
+ [0.4.0]: https://github.com/kshtzkr/hr_lite/compare/v0.3.0...v0.4.0
418
+ [0.3.0]: https://github.com/kshtzkr/hr_lite/compare/v0.2.1...v0.3.0
419
+ [0.2.1]: https://github.com/kshtzkr/hr_lite/compare/v0.2.0...v0.2.1
420
+ [0.2.0]: https://github.com/kshtzkr/hr_lite/compare/v0.1.2...v0.2.0
421
+ [0.1.2]: https://github.com/kshtzkr/hr_lite/compare/v0.1.1...v0.1.2
422
+ [0.1.1]: https://github.com/kshtzkr/hr_lite/compare/v0.1.0...v0.1.1
206
423
  [0.1.0]: https://github.com/kshtzkr/hr_lite/releases/tag/v0.1.0