hr_lite 0.23.1 → 0.26.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 +49 -0
- data/README.md +4 -1
- data/app/assets/javascripts/hr_lite/tax_preview.js +38 -0
- data/app/assets/stylesheets/hr_lite/hr_lite.css +12 -1
- data/app/controllers/hr_lite/admin/ca_reviews_controller.rb +76 -0
- data/app/controllers/hr_lite/admin/payroll_runs_controller.rb +14 -4
- data/app/controllers/hr_lite/admin/salary_slips_controller.rb +4 -0
- data/app/controllers/hr_lite/admin/salary_structures_controller.rb +6 -16
- data/app/controllers/hr_lite/admin/tax_declarations_controller.rb +46 -0
- data/app/controllers/hr_lite/tax_declarations_controller.rb +19 -1
- data/app/controllers/hr_lite/timelines_controller.rb +2 -1
- data/app/helpers/hr_lite/application_helper.rb +7 -0
- data/app/jobs/hr_lite/ca_review_overdue_job.rb +19 -0
- data/app/jobs/hr_lite/ca_review_reminder_job.rb +21 -0
- data/app/jobs/hr_lite/payroll_auto_approve_job.rb +21 -0
- data/app/jobs/hr_lite/payroll_auto_draft_job.rb +1 -1
- data/app/models/hr_lite/audit_log.rb +1 -1
- data/app/models/hr_lite/ca_review.rb +66 -0
- data/app/models/hr_lite/payroll_run.rb +47 -3
- data/app/models/hr_lite/role.rb +3 -0
- data/app/models/hr_lite/salary_structure.rb +22 -8
- data/app/models/hr_lite/statutory_rate_card_record.rb +6 -6
- data/app/models/hr_lite/tax_declaration.rb +24 -0
- data/app/models/hr_lite/tax_declaration_item.rb +56 -4
- data/app/services/hr_lite/calculators/tds.rb +7 -6
- data/app/services/hr_lite/payroll_run_processor.rb +9 -0
- data/app/services/hr_lite/slip_builder.rb +1 -1
- data/app/services/hr_lite/tax_computation.rb +61 -0
- data/app/services/hr_lite/timeline.rb +10 -1
- data/app/views/hr_lite/admin/ca_reviews/index.html.erb +94 -0
- data/app/views/hr_lite/admin/employees/show.html.erb +3 -1
- data/app/views/hr_lite/admin/payroll_runs/show.html.erb +17 -7
- data/app/views/hr_lite/admin/salary_structures/_form.html.erb +15 -7
- data/app/views/hr_lite/admin/statutory_rate_cards/_form.html.erb +1 -1
- data/app/views/hr_lite/admin/tax_declarations/index.html.erb +1 -0
- data/app/views/hr_lite/admin/tax_declarations/overview.html.erb +39 -0
- data/app/views/hr_lite/admin/tax_declarations/person.html.erb +10 -0
- data/app/views/hr_lite/admin/tax_declarations/show.html.erb +19 -2
- data/app/views/hr_lite/leave_requests/_balance_chips.html.erb +6 -4
- data/app/views/hr_lite/tax/_computation.html.erb +56 -0
- data/app/views/hr_lite/tax_declarations/show.html.erb +61 -59
- data/app/views/hr_lite/timelines/show.html.erb +1 -0
- data/config/routes.rb +8 -2
- data/db/migrate/20261010100000_add_ctc_to_hr_lite_salary_structures.rb +9 -0
- data/db/migrate/20261010100100_add_approval_to_hr_lite_payroll_runs.rb +10 -0
- data/db/migrate/20261010100200_grant_hr_lite_payroll_approve.rb +22 -0
- data/db/migrate/20261010100300_seed_hr_lite_fy2026_rate_cards.rb +16 -0
- data/db/migrate/20261010100400_add_tax_fields_to_hr_lite_tax_declaration_items.rb +9 -0
- data/db/migrate/20261010100500_grant_hr_lite_tax_to_hr.rb +12 -0
- data/db/migrate/20261010110000_create_hr_lite_ca_reviews.rb +21 -0
- data/db/migrate/20261010110100_seed_hr_lite_ca_role.rb +14 -0
- data/lib/hr_lite/notifications.rb +5 -0
- data/lib/hr_lite/permissions.rb +2 -0
- data/lib/hr_lite/role_seeds.rb +9 -3
- data/lib/hr_lite/statutory_rate_card.rb +65 -43
- data/lib/hr_lite/statutory_seeds.rb +4 -2
- data/lib/hr_lite/version.rb +1 -1
- data/lib/hr_lite.rb +9 -1
- metadata +20 -1
|
@@ -18,50 +18,72 @@ module HrLite
|
|
|
18
18
|
def self.r(value) = BigDecimal(value.to_s)
|
|
19
19
|
private_class_method :r
|
|
20
20
|
|
|
21
|
+
FY2025_TAX = {
|
|
22
|
+
"new" => {
|
|
23
|
+
standard_deduction: r("75000"), rebate_cap: r("1200000"), cess_rate: r("0.04"),
|
|
24
|
+
# §115BAC carries marginal relief just above the rebate cap; the
|
|
25
|
+
# old regime does not, so this is a per-regime flag.
|
|
26
|
+
marginal_relief: true,
|
|
27
|
+
slabs: [
|
|
28
|
+
[ r("0"), r("400000"), r("0") ],
|
|
29
|
+
[ r("400000"), r("800000"), r("0.05") ],
|
|
30
|
+
[ r("800000"), r("1200000"), r("0.10") ],
|
|
31
|
+
[ r("1200000"), r("1600000"), r("0.15") ],
|
|
32
|
+
[ r("1600000"), r("2000000"), r("0.20") ],
|
|
33
|
+
[ r("2000000"), r("2400000"), r("0.25") ],
|
|
34
|
+
[ r("2400000"), nil, r("0.30") ]
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"old" => {
|
|
38
|
+
standard_deduction: r("50000"), rebate_cap: r("500000"), cess_rate: r("0.04"),
|
|
39
|
+
slabs: [
|
|
40
|
+
[ r("0"), r("250000"), r("0") ],
|
|
41
|
+
[ r("250000"), r("500000"), r("0.05") ],
|
|
42
|
+
[ r("500000"), r("1000000"), r("0.20") ],
|
|
43
|
+
[ r("1000000"), nil, r("0.30") ]
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}.freeze
|
|
47
|
+
private_constant :FY2025_TAX
|
|
48
|
+
|
|
49
|
+
PF_15K = {
|
|
50
|
+
employee_rate: r("0.12"), employer_rate: r("0.12"), eps_rate: r("0.0833"),
|
|
51
|
+
wage_ceiling: r("15000"), eps_wage_ceiling: r("15000"),
|
|
52
|
+
edli_rate: r("0.005"), edli_ceiling: r("15000"), admin_rate: r("0.005")
|
|
53
|
+
}.freeze
|
|
54
|
+
private_constant :PF_15K
|
|
55
|
+
|
|
56
|
+
ESI = { employee_rate: r("0.0075"), employer_rate: r("0.0325"), gross_ceiling: r("21000") }.freeze
|
|
57
|
+
private_constant :ESI
|
|
58
|
+
|
|
59
|
+
PT = {
|
|
60
|
+
# Neither UP nor Uttarakhand levies professional tax today; both
|
|
61
|
+
# ship empty (PT = 0). Karnataka included as a worked template.
|
|
62
|
+
"none" => [],
|
|
63
|
+
"uttar_pradesh" => [],
|
|
64
|
+
"uttarakhand" => [],
|
|
65
|
+
# Inclusive lower bounds. `above: 24999` with a strict `>` taxed a
|
|
66
|
+
# prorated gross of ₹24,999.50, which is below the real threshold.
|
|
67
|
+
"karnataka" => [ { from: r("25000"), monthly: r("200") } ]
|
|
68
|
+
}.freeze
|
|
69
|
+
private_constant :PT
|
|
70
|
+
|
|
71
|
+
# Cards the gem ships already verified, with where the figures come from.
|
|
72
|
+
# StatutorySeeds stamps the source as the verifier, so nobody has to.
|
|
73
|
+
SOURCES = {
|
|
74
|
+
Date.new(2026, 4, 1) => "Finance Act 2026: slabs, standard deduction and §87A rebate unchanged from " \
|
|
75
|
+
"FY 2025-26 (Income-tax Act 2025 in force from 1 April 2026; salary TDS §392). " \
|
|
76
|
+
"PF ₹15,000 and ESI ₹21,000 ceilings unchanged.",
|
|
77
|
+
Date.new(2026, 10, 1) => "EPF/EPS/EDLI wage ceiling ₹25,000 — Ministry of Labour Notification S.O. 5109(E), " \
|
|
78
|
+
"17 Sep 2026; applied from October 2026 payroll. Tax slabs and ESI as FY 2026-27."
|
|
79
|
+
}.freeze
|
|
80
|
+
|
|
21
81
|
CARDS = {
|
|
22
|
-
Date.new(2025, 4, 1) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
esi: { employee_rate: r("0.0075"), employer_rate: r("0.0325"), gross_ceiling: r("21000") },
|
|
29
|
-
pt: {
|
|
30
|
-
# Neither UP nor Uttarakhand levies professional tax today; both
|
|
31
|
-
# ship empty (PT = 0). Karnataka included as a worked template.
|
|
32
|
-
"none" => [],
|
|
33
|
-
"uttar_pradesh" => [],
|
|
34
|
-
"uttarakhand" => [],
|
|
35
|
-
# Inclusive lower bounds. `above: 24999` with a strict `>` taxed a
|
|
36
|
-
# prorated gross of ₹24,999.50, which is below the real threshold.
|
|
37
|
-
"karnataka" => [ { from: r("25000"), monthly: r("200") } ]
|
|
38
|
-
},
|
|
39
|
-
income_tax: {
|
|
40
|
-
"new" => {
|
|
41
|
-
standard_deduction: r("75000"), rebate_cap: r("1200000"), cess_rate: r("0.04"),
|
|
42
|
-
# §115BAC carries marginal relief just above the rebate cap; the
|
|
43
|
-
# old regime does not, so this is a per-regime flag.
|
|
44
|
-
marginal_relief: true,
|
|
45
|
-
slabs: [
|
|
46
|
-
[ r("0"), r("400000"), r("0") ],
|
|
47
|
-
[ r("400000"), r("800000"), r("0.05") ],
|
|
48
|
-
[ r("800000"), r("1200000"), r("0.10") ],
|
|
49
|
-
[ r("1200000"), r("1600000"), r("0.15") ],
|
|
50
|
-
[ r("1600000"), r("2000000"), r("0.20") ],
|
|
51
|
-
[ r("2000000"), r("2400000"), r("0.25") ],
|
|
52
|
-
[ r("2400000"), nil, r("0.30") ]
|
|
53
|
-
]
|
|
54
|
-
},
|
|
55
|
-
"old" => {
|
|
56
|
-
standard_deduction: r("50000"), rebate_cap: r("500000"), cess_rate: r("0.04"),
|
|
57
|
-
slabs: [
|
|
58
|
-
[ r("0"), r("250000"), r("0") ],
|
|
59
|
-
[ r("250000"), r("500000"), r("0.05") ],
|
|
60
|
-
[ r("500000"), r("1000000"), r("0.20") ],
|
|
61
|
-
[ r("1000000"), nil, r("0.30") ]
|
|
62
|
-
]
|
|
63
|
-
}
|
|
64
|
-
}
|
|
82
|
+
Date.new(2025, 4, 1) => { pf: PF_15K, esi: ESI, pt: PT, income_tax: FY2025_TAX },
|
|
83
|
+
Date.new(2026, 4, 1) => { pf: PF_15K, esi: ESI, pt: PT, income_tax: FY2025_TAX },
|
|
84
|
+
Date.new(2026, 10, 1) => {
|
|
85
|
+
pf: PF_15K.merge(wage_ceiling: r("25000"), eps_wage_ceiling: r("25000"), edli_ceiling: r("25000")),
|
|
86
|
+
esi: ESI, pt: PT, income_tax: FY2025_TAX
|
|
65
87
|
}
|
|
66
88
|
}.freeze
|
|
67
89
|
|
|
@@ -20,8 +20,10 @@ module HrLite
|
|
|
20
20
|
pf: stringify(card[:pf]),
|
|
21
21
|
esi: stringify(card[:esi]),
|
|
22
22
|
income_tax: card[:income_tax].transform_values { |regime| stringify_regime(regime) },
|
|
23
|
-
notes:
|
|
24
|
-
"accountant, then record who verified it."
|
|
23
|
+
notes: StatutoryRateCard::SOURCES[effective_from] ||
|
|
24
|
+
"Shipped with hr_lite #{HrLite::VERSION}. Confirm with your accountant, then record who verified it.",
|
|
25
|
+
verified_by: (StatutoryRateCard::SOURCES.key?(effective_from) ? "hr_lite #{HrLite::VERSION} (official source in the notes)" : nil),
|
|
26
|
+
verified_on: (Date.current if StatutoryRateCard::SOURCES.key?(effective_from))
|
|
25
27
|
)
|
|
26
28
|
"rate card FY #{FinancialYear.label(effective_from)}"
|
|
27
29
|
end
|
data/lib/hr_lite/version.rb
CHANGED
data/lib/hr_lite.rb
CHANGED
|
@@ -114,7 +114,15 @@ module HrLite
|
|
|
114
114
|
# Everyone HR tracks (host-overridable to exclude bots/test accounts),
|
|
115
115
|
# sorted by display name for team screens.
|
|
116
116
|
def employees
|
|
117
|
-
|
|
117
|
+
outside = outside_accountant_ids
|
|
118
|
+
config.employees_scope.call.reject { |u| outside.include?(u.id) }.sort_by { |u| display_name(u).downcase }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# CA logins with no HR profile: they review pay, they are not staff, so
|
|
122
|
+
# no attendance, leave, payroll or team list ever counts them.
|
|
123
|
+
def outside_accountant_ids
|
|
124
|
+
ids = HrLite::RoleAssignment.joins(:role).where(hr_lite_roles: { name: HrLite::Role::CA }).pluck(:user_id)
|
|
125
|
+
(ids - HrLite::EmployeeProfile.where(user_id: ids).pluck(:user_id)).to_set
|
|
118
126
|
end
|
|
119
127
|
|
|
120
128
|
# employees minus anyone whose profile says they have exited — user
|
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.26.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kshitiz sinha
|
|
@@ -70,6 +70,7 @@ files:
|
|
|
70
70
|
- app/assets/javascripts/hr_lite/nav.js
|
|
71
71
|
- app/assets/javascripts/hr_lite/print.js
|
|
72
72
|
- app/assets/javascripts/hr_lite/select_filter.js
|
|
73
|
+
- app/assets/javascripts/hr_lite/tax_preview.js
|
|
73
74
|
- app/assets/stylesheets/hr_lite/application.css
|
|
74
75
|
- app/assets/stylesheets/hr_lite/hr_lite.css
|
|
75
76
|
- app/controllers/hr_lite/admin/appraisals_controller.rb
|
|
@@ -79,6 +80,7 @@ files:
|
|
|
79
80
|
- app/controllers/hr_lite/admin/awards_controller.rb
|
|
80
81
|
- app/controllers/hr_lite/admin/base_controller.rb
|
|
81
82
|
- app/controllers/hr_lite/admin/benefits_controller.rb
|
|
83
|
+
- app/controllers/hr_lite/admin/ca_reviews_controller.rb
|
|
82
84
|
- app/controllers/hr_lite/admin/checklists_controller.rb
|
|
83
85
|
- app/controllers/hr_lite/admin/comp_off_requests_controller.rb
|
|
84
86
|
- app/controllers/hr_lite/admin/designation_changes_controller.rb
|
|
@@ -142,9 +144,12 @@ files:
|
|
|
142
144
|
- app/jobs/hr_lite/application_job.rb
|
|
143
145
|
- app/jobs/hr_lite/approval_escalation_job.rb
|
|
144
146
|
- app/jobs/hr_lite/attendance_close_job.rb
|
|
147
|
+
- app/jobs/hr_lite/ca_review_overdue_job.rb
|
|
148
|
+
- app/jobs/hr_lite/ca_review_reminder_job.rb
|
|
145
149
|
- app/jobs/hr_lite/daily_digest_job.rb
|
|
146
150
|
- app/jobs/hr_lite/document_expiry_job.rb
|
|
147
151
|
- app/jobs/hr_lite/leave_year_rollover_job.rb
|
|
152
|
+
- app/jobs/hr_lite/payroll_auto_approve_job.rb
|
|
148
153
|
- app/jobs/hr_lite/payroll_auto_draft_job.rb
|
|
149
154
|
- app/jobs/hr_lite/slips_ready_job.rb
|
|
150
155
|
- app/mailers/hr_lite/application_mailer.rb
|
|
@@ -165,6 +170,7 @@ files:
|
|
|
165
170
|
- app/models/hr_lite/award.rb
|
|
166
171
|
- app/models/hr_lite/benefit.rb
|
|
167
172
|
- app/models/hr_lite/benefit_enrolment.rb
|
|
173
|
+
- app/models/hr_lite/ca_review.rb
|
|
168
174
|
- app/models/hr_lite/checklist_item.rb
|
|
169
175
|
- app/models/hr_lite/checklist_template.rb
|
|
170
176
|
- app/models/hr_lite/comp_off_request.rb
|
|
@@ -216,6 +222,7 @@ files:
|
|
|
216
222
|
- app/services/hr_lite/payroll_run_processor.rb
|
|
217
223
|
- app/services/hr_lite/pdf_renderer.rb
|
|
218
224
|
- app/services/hr_lite/slip_builder.rb
|
|
225
|
+
- app/services/hr_lite/tax_computation.rb
|
|
219
226
|
- app/services/hr_lite/team_day.rb
|
|
220
227
|
- app/services/hr_lite/timeline.rb
|
|
221
228
|
- app/services/hr_lite/working_calendar.rb
|
|
@@ -234,6 +241,7 @@ files:
|
|
|
234
241
|
- app/views/hr_lite/admin/awards/new.html.erb
|
|
235
242
|
- app/views/hr_lite/admin/benefits/index.html.erb
|
|
236
243
|
- app/views/hr_lite/admin/benefits/new.html.erb
|
|
244
|
+
- app/views/hr_lite/admin/ca_reviews/index.html.erb
|
|
237
245
|
- app/views/hr_lite/admin/checklists/index.html.erb
|
|
238
246
|
- app/views/hr_lite/admin/comp_off_requests/index.html.erb
|
|
239
247
|
- app/views/hr_lite/admin/comp_off_requests/show.html.erb
|
|
@@ -299,6 +307,8 @@ files:
|
|
|
299
307
|
- app/views/hr_lite/admin/statutory_rate_cards/index.html.erb
|
|
300
308
|
- app/views/hr_lite/admin/statutory_rate_cards/new.html.erb
|
|
301
309
|
- app/views/hr_lite/admin/tax_declarations/index.html.erb
|
|
310
|
+
- app/views/hr_lite/admin/tax_declarations/overview.html.erb
|
|
311
|
+
- app/views/hr_lite/admin/tax_declarations/person.html.erb
|
|
302
312
|
- app/views/hr_lite/admin/tax_declarations/show.html.erb
|
|
303
313
|
- app/views/hr_lite/appraisals/index.html.erb
|
|
304
314
|
- app/views/hr_lite/appraisals/show.html.erb
|
|
@@ -349,6 +359,7 @@ files:
|
|
|
349
359
|
- app/views/hr_lite/shared/_bell.html.erb
|
|
350
360
|
- app/views/hr_lite/shared/_form_errors.html.erb
|
|
351
361
|
- app/views/hr_lite/shared/_pagination.html.erb
|
|
362
|
+
- app/views/hr_lite/tax/_computation.html.erb
|
|
352
363
|
- app/views/hr_lite/tax_declarations/show.html.erb
|
|
353
364
|
- app/views/hr_lite/team/show.html.erb
|
|
354
365
|
- app/views/hr_lite/timelines/_events.html.erb
|
|
@@ -400,6 +411,14 @@ files:
|
|
|
400
411
|
- db/migrate/20261006120100_add_half_day_part_to_hr_lite_attendance_records.rb
|
|
401
412
|
- db/migrate/20261010090000_create_hr_lite_performance_plans.rb
|
|
402
413
|
- db/migrate/20261010090100_create_hr_lite_awards.rb
|
|
414
|
+
- db/migrate/20261010100000_add_ctc_to_hr_lite_salary_structures.rb
|
|
415
|
+
- db/migrate/20261010100100_add_approval_to_hr_lite_payroll_runs.rb
|
|
416
|
+
- db/migrate/20261010100200_grant_hr_lite_payroll_approve.rb
|
|
417
|
+
- db/migrate/20261010100300_seed_hr_lite_fy2026_rate_cards.rb
|
|
418
|
+
- db/migrate/20261010100400_add_tax_fields_to_hr_lite_tax_declaration_items.rb
|
|
419
|
+
- db/migrate/20261010100500_grant_hr_lite_tax_to_hr.rb
|
|
420
|
+
- db/migrate/20261010110000_create_hr_lite_ca_reviews.rb
|
|
421
|
+
- db/migrate/20261010110100_seed_hr_lite_ca_role.rb
|
|
403
422
|
- lib/generators/hr_lite/install/install_generator.rb
|
|
404
423
|
- lib/generators/hr_lite/install/templates/AFTER_INSTALL
|
|
405
424
|
- lib/generators/hr_lite/install/templates/initializer.rb
|