hr_lite 0.12.0 → 0.13.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 +35 -1
- data/app/assets/stylesheets/hr_lite/hr_lite.css +6 -0
- data/app/controllers/hr_lite/admin/reports_controller.rb +151 -0
- data/app/controllers/hr_lite/benefits_controller.rb +17 -0
- data/app/controllers/hr_lite/expenses_controller.rb +50 -0
- data/app/controllers/hr_lite/hr_requests_controller.rb +43 -0
- data/app/controllers/hr_lite/policies_controller.rb +26 -0
- data/app/helpers/hr_lite/application_helper.rb +6 -1
- data/app/views/hr_lite/admin/reports/index.html.erb +40 -0
- data/app/views/hr_lite/admin/reports/show.html.erb +32 -0
- data/app/views/hr_lite/benefits/index.html.erb +33 -0
- data/app/views/hr_lite/expenses/index.html.erb +68 -0
- data/app/views/hr_lite/expenses/new.html.erb +38 -0
- data/app/views/hr_lite/hr_requests/index.html.erb +39 -0
- data/app/views/hr_lite/hr_requests/new.html.erb +28 -0
- data/app/views/hr_lite/hr_requests/show.html.erb +25 -0
- data/app/views/hr_lite/policies/index.html.erb +34 -0
- data/app/views/hr_lite/policies/show.html.erb +23 -0
- data/config/routes.rb +11 -0
- data/lib/hr_lite/version.rb +1 -1
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8202157b6f35309884c9df17895d711553e114a57925c8c2e381e51a7be863ba
|
|
4
|
+
data.tar.gz: 3cb55e413c6bcc70bd3aa39a5c212690a21c9cf747b17bfdf5894ef6d73945de
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0ddf504c20a84c58a712fd4efe695e9b90b27eea8acc8883bfb37d33df398778169c35eb2c11f37830e91c9ceec63560df57c631246b2b22381b52df5ce30144
|
|
7
|
+
data.tar.gz: 4a724d4a55068129237e010aca71ce94c392656bb56953a6f1ec5329ddf5d33b6ffd91f76c82229a152f85d134a60ca29308634133f0a3a72779cff3cc6dafdb
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.13.0] - 2026-08-18
|
|
11
|
+
|
|
12
|
+
The screens. No migration.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **Employee self-service for everything built since 0.11.0**: claim an
|
|
17
|
+
expense (with what is left of each cap shown before you type an amount),
|
|
18
|
+
see what you are covered for, read and acknowledge a policy, ask HR a
|
|
19
|
+
question and read the answer.
|
|
20
|
+
- **A reports hub** — headcount, joiners and leavers, leave balances,
|
|
21
|
+
attendance and expenses — each with a CSV download, and each **scoped by
|
|
22
|
+
the same permission that guards the screen its data comes from**. A report
|
|
23
|
+
is not a side door into rows somebody cannot otherwise reach: a manager's
|
|
24
|
+
headcount is their own team. The hub lists only the reports the reader can
|
|
25
|
+
actually open, since a list of links that turn you away is worse than a
|
|
26
|
+
short list.
|
|
27
|
+
- CSV downloads are audited, the same way the payout register is.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **The reports hub locked Finance out of the expense report.** It inherited
|
|
32
|
+
the operations gate, and Finance approves expenses but runs none of the
|
|
33
|
+
operations screens. Found by writing the spec for it.
|
|
34
|
+
|
|
35
|
+
### Changed
|
|
36
|
+
|
|
37
|
+
- `.hrl-prose` for long-form policy text, capped at 68 characters a line — a
|
|
38
|
+
policy read across the full width of a laptop is a policy nobody finishes.
|
|
39
|
+
- The demo sandbox seeds an expense claim, a benefit enrolment, a policy
|
|
40
|
+
awaiting acknowledgement and an open HR request, so the new screens have
|
|
41
|
+
something on them at first boot.
|
|
42
|
+
|
|
10
43
|
## [0.12.0] - 2026-08-18
|
|
11
44
|
|
|
12
45
|
The four things an employee had to leave the system to do. **Adds one
|
|
@@ -729,7 +762,8 @@ Initial release.
|
|
|
729
762
|
bus with per-event channel matrix (bell, email, leadership email/bell),
|
|
730
763
|
daily leadership digest and an append-only audit trail.
|
|
731
764
|
|
|
732
|
-
[Unreleased]: https://github.com/kshtzkr/hr_lite/compare/v0.
|
|
765
|
+
[Unreleased]: https://github.com/kshtzkr/hr_lite/compare/v0.13.0...HEAD
|
|
766
|
+
[0.13.0]: https://github.com/kshtzkr/hr_lite/compare/v0.12.0...v0.13.0
|
|
733
767
|
[0.12.0]: https://github.com/kshtzkr/hr_lite/compare/v0.11.0...v0.12.0
|
|
734
768
|
[0.11.0]: https://github.com/kshtzkr/hr_lite/compare/v0.10.0...v0.11.0
|
|
735
769
|
[0.10.0]: https://github.com/kshtzkr/hr_lite/compare/v0.9.0...v0.10.0
|
|
@@ -318,3 +318,9 @@
|
|
|
318
318
|
.hrl-mt { margin-top: .85rem; }
|
|
319
319
|
.hrl-right { margin-left: auto; }
|
|
320
320
|
.hrl-row { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
|
|
321
|
+
|
|
322
|
+
/* Long-form policy text. Constrained measure — a policy read across the
|
|
323
|
+
full width of a laptop is a policy nobody finishes. */
|
|
324
|
+
.hrl-prose { max-width: 68ch; }
|
|
325
|
+
.hrl-prose p { margin: 0 0 .8rem; line-height: 1.6; }
|
|
326
|
+
.hrl-prose p:last-child { margin-bottom: 0; }
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
module HrLite
|
|
2
|
+
module Admin
|
|
3
|
+
# The numbers somebody asks for at the end of a month, and the CSV they
|
|
4
|
+
# ask for straight afterwards.
|
|
5
|
+
#
|
|
6
|
+
# Every report is scoped by the SAME permission that guards the screens
|
|
7
|
+
# its data comes from — a report is not a side door into rows somebody
|
|
8
|
+
# cannot otherwise reach.
|
|
9
|
+
class ReportsController < BaseController
|
|
10
|
+
# Finance can approve expenses but runs none of the operations screens,
|
|
11
|
+
# so the operations gate would have shut them out of their own expense
|
|
12
|
+
# report. The hub is reachable by anybody who can see AT LEAST ONE
|
|
13
|
+
# report; each report then checks its own permission.
|
|
14
|
+
skip_before_action :require_operations_access!
|
|
15
|
+
before_action :require_any_report!
|
|
16
|
+
|
|
17
|
+
REPORTS = {
|
|
18
|
+
"headcount" => "Headcount by department",
|
|
19
|
+
"joiners_and_leavers" => "Joiners and leavers",
|
|
20
|
+
"leave_balances" => "Leave balances",
|
|
21
|
+
"attendance" => "Attendance summary",
|
|
22
|
+
"expenses" => "Expense claims"
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
def index
|
|
26
|
+
# Only the reports this person could actually open — a list of links
|
|
27
|
+
# that turn you away is worse than a shorter list.
|
|
28
|
+
@reports = REPORTS.select { |name, _| permitted?(name) }
|
|
29
|
+
@month = parse_month_param(params[:month])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def show
|
|
33
|
+
@month = parse_month_param(params[:month])
|
|
34
|
+
@name = params[:id]
|
|
35
|
+
return hr_access_denied unless REPORTS.key?(@name)
|
|
36
|
+
return hr_access_denied unless permitted?(@name)
|
|
37
|
+
|
|
38
|
+
@rows = rows_for(@name)
|
|
39
|
+
respond_to do |format|
|
|
40
|
+
format.html
|
|
41
|
+
format.csv do
|
|
42
|
+
AuditLog.record!(action: "report.exported", subject: hr_current_user,
|
|
43
|
+
actor: hr_current_user,
|
|
44
|
+
changes: { "report" => @name, "rows" => @rows.size,
|
|
45
|
+
"month" => @month.strftime("%Y-%m") })
|
|
46
|
+
send_data to_csv(@rows), filename: "#{@name}-#{@month.strftime('%Y-%m')}.csv",
|
|
47
|
+
type: "text/csv"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def require_any_report!
|
|
55
|
+
hr_access_denied if REPORTS.keys.none? { |name| permitted?(name) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# A report reaches exactly as far as the screen it summarises.
|
|
59
|
+
def permitted?(name)
|
|
60
|
+
case name
|
|
61
|
+
when "expenses" then hr_can?("expense.approve", scope: :all)
|
|
62
|
+
when "leave_balances" then hr_can?("leave.view", scope: :team)
|
|
63
|
+
when "attendance" then hr_can?("attendance.view", scope: :team)
|
|
64
|
+
else hr_can?("profile.view", scope: :team)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def visible_users
|
|
69
|
+
ids = hr_access.visible_user_ids("profile.view")
|
|
70
|
+
employees = HrLite.employees
|
|
71
|
+
ids.nil? ? employees : employees.select { |user| ids.include?(user.id) }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def rows_for(name)
|
|
75
|
+
case name
|
|
76
|
+
when "headcount" then headcount_rows
|
|
77
|
+
when "joiners_and_leavers" then joiners_and_leavers_rows
|
|
78
|
+
when "leave_balances" then leave_balance_rows
|
|
79
|
+
when "attendance" then attendance_rows
|
|
80
|
+
when "expenses" then expense_rows
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def headcount_rows
|
|
85
|
+
profiles = EmployeeProfile.where(user_id: visible_users.map(&:id))
|
|
86
|
+
.active_for(@month)
|
|
87
|
+
profiles.group_by { |p| p.department.presence || "Unassigned" }
|
|
88
|
+
.sort_by(&:first)
|
|
89
|
+
.map { |department, rows| { "Department" => department, "People" => rows.size } }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def joiners_and_leavers_rows
|
|
93
|
+
window = @month..@month.end_of_month
|
|
94
|
+
EmployeeProfile.where(user_id: visible_users.map(&:id))
|
|
95
|
+
.where("date_of_joining BETWEEN ? AND ? OR date_of_exit BETWEEN ? AND ?",
|
|
96
|
+
window.first, window.last, window.first, window.last)
|
|
97
|
+
.includes(:user)
|
|
98
|
+
.map do |profile|
|
|
99
|
+
{ "Employee" => HrLite.display_name(profile.user),
|
|
100
|
+
"Department" => profile.department,
|
|
101
|
+
"Joined" => profile.date_of_joining&.to_s,
|
|
102
|
+
"Left" => profile.date_of_exit&.to_s }
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def leave_balance_rows
|
|
107
|
+
year = LeaveYear.key_for(@month)
|
|
108
|
+
types = LeaveType.active.where(paid: true).where.not(annual_quota: nil)
|
|
109
|
+
visible_users.flat_map do |user|
|
|
110
|
+
types.map do |type|
|
|
111
|
+
balance = LeaveBalance.for(user, type, year)
|
|
112
|
+
{ "Employee" => HrLite.display_name(user), "Type" => type.code,
|
|
113
|
+
"Entitled" => balance.entitled.to_f, "Used" => balance.used.to_f,
|
|
114
|
+
"Available" => balance.available.to_f }
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def attendance_rows
|
|
120
|
+
visible_users.map do |user|
|
|
121
|
+
summary = AttendanceSummary.for(user: user, month: @month)
|
|
122
|
+
{ "Employee" => HrLite.display_name(user),
|
|
123
|
+
"Payable days" => summary[:payable_days].to_f,
|
|
124
|
+
"LOP" => summary[:lop_days].to_f,
|
|
125
|
+
"Days in month" => summary[:days_in_month] }
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def expense_rows
|
|
130
|
+
Expense.where(spent_on: @month..@month.end_of_month)
|
|
131
|
+
.includes(:user, :category).recent_first.map do |expense|
|
|
132
|
+
{ "Employee" => HrLite.display_name(expense.user),
|
|
133
|
+
"Category" => expense.category.name,
|
|
134
|
+
"Spent on" => expense.spent_on.to_s,
|
|
135
|
+
"Amount" => expense.amount.to_s("F"),
|
|
136
|
+
"Status" => expense.status }
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def to_csv(rows)
|
|
141
|
+
require "csv"
|
|
142
|
+
return "" if rows.empty?
|
|
143
|
+
|
|
144
|
+
CSV.generate do |csv|
|
|
145
|
+
csv << rows.first.keys
|
|
146
|
+
rows.each { |row| csv << row.values }
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module HrLite
|
|
2
|
+
# What the signed-in person is actually covered for — previously something
|
|
3
|
+
# you had to email somebody to find out.
|
|
4
|
+
class BenefitsController < ApplicationController
|
|
5
|
+
before_action :require_viewing!
|
|
6
|
+
|
|
7
|
+
def index
|
|
8
|
+
@enrolments = BenefitEnrolment.live_on(Date.current)
|
|
9
|
+
.where(user_id: hr_current_user.id)
|
|
10
|
+
.includes(:benefit)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def require_viewing! = hr_require_permission!("benefit.view")
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module HrLite
|
|
2
|
+
# An employee's own claims. Scoped to the signed-in person the same way
|
|
3
|
+
# every other self-service screen is: a foreign id 404s through the
|
|
4
|
+
# relation rather than 403ing.
|
|
5
|
+
class ExpensesController < ApplicationController
|
|
6
|
+
before_action :require_claiming!
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
@expenses = paginate(own.includes(:category).recent_first)
|
|
10
|
+
@categories = ExpenseCategory.active.alphabetical
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def new
|
|
14
|
+
@expense = Expense.new(spent_on: Date.current)
|
|
15
|
+
@categories = ExpenseCategory.active.alphabetical
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create
|
|
19
|
+
@expense = Expense.new(expense_params.merge(user_id: hr_current_user.id))
|
|
20
|
+
if @expense.save
|
|
21
|
+
@expense.submit!(actor: hr_current_user)
|
|
22
|
+
redirect_to expenses_path, notice: "Claim submitted."
|
|
23
|
+
else
|
|
24
|
+
@categories = ExpenseCategory.active.alphabetical
|
|
25
|
+
render :new, status: :unprocessable_entity
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def cancel
|
|
30
|
+
expense = own.find(params[:id])
|
|
31
|
+
if expense.draft? || expense.submitted?
|
|
32
|
+
expense.update!(status: "cancelled")
|
|
33
|
+
expense.approval_route.cancel_all!
|
|
34
|
+
redirect_to expenses_path, notice: "Claim withdrawn."
|
|
35
|
+
else
|
|
36
|
+
redirect_to expenses_path, alert: "Only a claim still waiting can be withdrawn."
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def require_claiming! = hr_require_permission!("expense.claim")
|
|
43
|
+
|
|
44
|
+
def own = Expense.where(user_id: hr_current_user.id)
|
|
45
|
+
|
|
46
|
+
def expense_params
|
|
47
|
+
params.require(:expense).permit(:category_id, :amount, :spent_on, :description, :receipt)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module HrLite
|
|
2
|
+
# The employee's side of the help desk.
|
|
3
|
+
class HrRequestsController < ApplicationController
|
|
4
|
+
before_action :require_raising!
|
|
5
|
+
|
|
6
|
+
def index
|
|
7
|
+
@requests = paginate(own.recent_first)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def show
|
|
11
|
+
@request = own.find(params[:id])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def new
|
|
15
|
+
@request = HrRequest.new
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create
|
|
19
|
+
@request = HrRequest.new(request_params.merge(user_id: hr_current_user.id))
|
|
20
|
+
if @request.save
|
|
21
|
+
redirect_to hr_requests_path, notice: "Sent to HR."
|
|
22
|
+
else
|
|
23
|
+
render :new, status: :unprocessable_entity
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def cancel
|
|
28
|
+
request = own.find(params[:id])
|
|
29
|
+
request.cancel!(actor: hr_current_user)
|
|
30
|
+
redirect_to hr_requests_path, notice: "Request withdrawn."
|
|
31
|
+
rescue ActiveRecord::RecordInvalid
|
|
32
|
+
redirect_to hr_requests_path, alert: "That request has already been answered."
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def require_raising! = hr_require_permission!("hr_request.raise")
|
|
38
|
+
|
|
39
|
+
def own = HrRequest.where(user_id: hr_current_user.id)
|
|
40
|
+
|
|
41
|
+
def request_params = params.require(:hr_request).permit(:category, :subject, :body)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module HrLite
|
|
2
|
+
# What people are held to, and the button that says they have read it.
|
|
3
|
+
class PoliciesController < ApplicationController
|
|
4
|
+
before_action :require_reading!
|
|
5
|
+
|
|
6
|
+
def index
|
|
7
|
+
@policies = Policy.current.sort_by(&:title)
|
|
8
|
+
@acknowledged = PolicyAcknowledgement.where(user_id: hr_current_user.id)
|
|
9
|
+
.pluck(:policy_id).to_set
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def show
|
|
13
|
+
@policy = Policy.published.find(params[:id])
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def acknowledge
|
|
17
|
+
policy = Policy.published.find(params[:id])
|
|
18
|
+
policy.acknowledge!(hr_current_user)
|
|
19
|
+
redirect_to policies_path, notice: "Thank you — recorded against #{policy.title} v#{policy.version}."
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def require_reading! = hr_require_permission!("policy.view", scope: :all)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -12,6 +12,10 @@ module HrLite
|
|
|
12
12
|
# Employee tier all the same — holding an approval IS the authorisation,
|
|
13
13
|
# so a manager and a stand-in covering for one reach the same screen.
|
|
14
14
|
{ label: "Approvals", path: :approvals_path, match: [ "/approvals" ] },
|
|
15
|
+
{ label: "Expenses", path: :expenses_path, match: [ "/expenses" ] },
|
|
16
|
+
{ label: "Benefits", path: :benefits_path, match: [ "/benefits" ] },
|
|
17
|
+
{ label: "Policies", path: :policies_path, match: [ "/policies" ] },
|
|
18
|
+
{ label: "Ask HR", path: :hr_requests_path, match: [ "/hr_requests" ] },
|
|
15
19
|
{ label: "Org", path: :org_path, match: [ "/org" ] },
|
|
16
20
|
{ label: "Kudos", path: :kudos_path, match: [ "/kudos" ] },
|
|
17
21
|
{ label: "Slips", path: :salary_slips_path, match: [ "/salary_slips" ] },
|
|
@@ -21,7 +25,8 @@ module HrLite
|
|
|
21
25
|
ADMIN_NAV_ITEMS = [
|
|
22
26
|
{ label: "Overview", path: :admin_overview_path, match: [ "/admin/overview" ] },
|
|
23
27
|
{ label: "Team attendance", path: :admin_attendances_path, match: [ "/admin/attendances" ] },
|
|
24
|
-
{ label: "Approvals", path: :admin_leave_requests_path, match: [ "/admin/leave_requests", "/admin/leave_balances", "/admin/comp_off_requests", "/admin/regularization_requests" ] }
|
|
28
|
+
{ label: "Approvals", path: :admin_leave_requests_path, match: [ "/admin/leave_requests", "/admin/leave_balances", "/admin/comp_off_requests", "/admin/regularization_requests" ] },
|
|
29
|
+
{ label: "Reports", path: :admin_reports_path, match: [ "/admin/reports" ] }
|
|
25
30
|
].freeze
|
|
26
31
|
|
|
27
32
|
LEADERSHIP_NAV_ITEMS = [
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Reports" } %>
|
|
2
|
+
<div class="hrl-page__head"><h1 class="hrl-page__title">Reports</h1></div>
|
|
3
|
+
|
|
4
|
+
<section class="hrl-card">
|
|
5
|
+
<p class="hrl-muted hrl-small">
|
|
6
|
+
Each report reaches exactly as far as the screen it summarises — a manager
|
|
7
|
+
sees their own team, HR sees everybody.
|
|
8
|
+
</p>
|
|
9
|
+
<%= form_with url: hr_lite.admin_reports_path, method: :get, local: true do %>
|
|
10
|
+
<div class="hrl-field">
|
|
11
|
+
<%= label_tag :month, "Month" %>
|
|
12
|
+
<%= text_field_tag :month, @month.strftime("%Y-%m"), placeholder: "YYYY-MM" %>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="hrl-form-actions">
|
|
15
|
+
<%= submit_tag "Change month", class: "hrl-btn" %>
|
|
16
|
+
</div>
|
|
17
|
+
<% end %>
|
|
18
|
+
</section>
|
|
19
|
+
|
|
20
|
+
<section class="hrl-card">
|
|
21
|
+
<div class="hrl-table-wrap">
|
|
22
|
+
<table class="hrl-table hrl-table--stack">
|
|
23
|
+
<thead><tr><th>Report</th><th></th></tr></thead>
|
|
24
|
+
<tbody>
|
|
25
|
+
<% @reports.each do |name, label| %>
|
|
26
|
+
<tr>
|
|
27
|
+
<td data-label="Report"><%= label %></td>
|
|
28
|
+
<td data-label="">
|
|
29
|
+
<a class="hrl-small"
|
|
30
|
+
href="<%= hr_lite.admin_report_path(name, month: @month.strftime("%Y-%m")) %>">Open</a>
|
|
31
|
+
|
|
32
|
+
<a class="hrl-small"
|
|
33
|
+
href="<%= hr_lite.admin_report_path(name, month: @month.strftime("%Y-%m"), format: :csv) %>">CSV</a>
|
|
34
|
+
</td>
|
|
35
|
+
</tr>
|
|
36
|
+
<% end %>
|
|
37
|
+
</tbody>
|
|
38
|
+
</table>
|
|
39
|
+
</div>
|
|
40
|
+
</section>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<% content_for(:page_title) { @reports_title = HrLite::Admin::ReportsController::REPORTS[@name] } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title"><%= HrLite::Admin::ReportsController::REPORTS[@name] %></h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<a class="hrl-btn"
|
|
6
|
+
href="<%= hr_lite.admin_report_path(@name, month: @month.strftime("%Y-%m"), format: :csv) %>">Download CSV</a>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<section class="hrl-card">
|
|
11
|
+
<p class="hrl-small hrl-muted"><%= @month.strftime("%B %Y") %></p>
|
|
12
|
+
<% if @rows.empty? %>
|
|
13
|
+
<p class="hrl-muted">Nothing to report for this month.</p>
|
|
14
|
+
<% else %>
|
|
15
|
+
<div class="hrl-table-wrap">
|
|
16
|
+
<table class="hrl-table hrl-table--stack">
|
|
17
|
+
<thead>
|
|
18
|
+
<tr><% @rows.first.keys.each do |header| %><th><%= header %></th><% end %></tr>
|
|
19
|
+
</thead>
|
|
20
|
+
<tbody>
|
|
21
|
+
<% @rows.each do |row| %>
|
|
22
|
+
<tr>
|
|
23
|
+
<% row.each do |header, value| %>
|
|
24
|
+
<td data-label="<%= header %>"><%= value %></td>
|
|
25
|
+
<% end %>
|
|
26
|
+
</tr>
|
|
27
|
+
<% end %>
|
|
28
|
+
</tbody>
|
|
29
|
+
</table>
|
|
30
|
+
</div>
|
|
31
|
+
<% end %>
|
|
32
|
+
</section>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Benefits" } %>
|
|
2
|
+
<div class="hrl-page__head"><h1 class="hrl-page__title">Your benefits</h1></div>
|
|
3
|
+
|
|
4
|
+
<section class="hrl-card">
|
|
5
|
+
<% if @enrolments.empty? %>
|
|
6
|
+
<p class="hrl-muted">You are not enrolled in any benefit yet.</p>
|
|
7
|
+
<% else %>
|
|
8
|
+
<div class="hrl-table-wrap">
|
|
9
|
+
<table class="hrl-table hrl-table--stack">
|
|
10
|
+
<thead><tr><th>Benefit</th><th>Cover</th><th>Since</th><th>Dependants</th></tr></thead>
|
|
11
|
+
<tbody>
|
|
12
|
+
<% @enrolments.each do |enrolment| %>
|
|
13
|
+
<% benefit = enrolment.benefit %>
|
|
14
|
+
<tr>
|
|
15
|
+
<td data-label="Benefit">
|
|
16
|
+
<strong><%= benefit.name %></strong>
|
|
17
|
+
<div class="hrl-small hrl-muted">
|
|
18
|
+
<%= benefit.kind.humanize %><%= " · #{benefit.provider}" if benefit.provider.present? %>
|
|
19
|
+
<%= " · policy #{benefit.policy_number}" if benefit.policy_number.present? %>
|
|
20
|
+
</div>
|
|
21
|
+
</td>
|
|
22
|
+
<td data-label="Cover" class="hrl-num">
|
|
23
|
+
<%= benefit.coverage ? hrl_money(benefit.coverage) : "—" %>
|
|
24
|
+
</td>
|
|
25
|
+
<td data-label="Since"><%= enrolment.enrolled_on.strftime("%d %b %Y") %></td>
|
|
26
|
+
<td data-label="Dependants" class="hrl-num"><%= enrolment.dependants %></td>
|
|
27
|
+
</tr>
|
|
28
|
+
<% end %>
|
|
29
|
+
</tbody>
|
|
30
|
+
</table>
|
|
31
|
+
</div>
|
|
32
|
+
<% end %>
|
|
33
|
+
</section>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Expenses" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Expenses</h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<a class="hrl-btn hrl-btn--primary" href="<%= hr_lite.new_expense_path %>">New claim</a>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<% if @categories.any? %>
|
|
10
|
+
<section class="hrl-card">
|
|
11
|
+
<h2 class="hrl-card__title">What is left this month</h2>
|
|
12
|
+
<ul>
|
|
13
|
+
<% @categories.each do |category| %>
|
|
14
|
+
<% remaining = category.remaining_for(hr_current_user) %>
|
|
15
|
+
<li class="hrl-small">
|
|
16
|
+
<strong><%= category.name %></strong> —
|
|
17
|
+
<%= remaining.nil? ? "no cap" : "#{hrl_money(remaining)} left" %>
|
|
18
|
+
<% if category.receipt_required %>
|
|
19
|
+
<span class="hrl-badge hrl-badge--muted">Receipt needed</span>
|
|
20
|
+
<% end %>
|
|
21
|
+
</li>
|
|
22
|
+
<% end %>
|
|
23
|
+
</ul>
|
|
24
|
+
</section>
|
|
25
|
+
<% end %>
|
|
26
|
+
|
|
27
|
+
<section class="hrl-card">
|
|
28
|
+
<% if @expenses.empty? %>
|
|
29
|
+
<p class="hrl-muted">No claims yet.</p>
|
|
30
|
+
<% else %>
|
|
31
|
+
<div class="hrl-table-wrap">
|
|
32
|
+
<table class="hrl-table hrl-table--stack">
|
|
33
|
+
<thead><tr><th>Spent</th><th>Category</th><th>Amount</th><th>Status</th><th></th></tr></thead>
|
|
34
|
+
<tbody>
|
|
35
|
+
<% @expenses.each do |expense| %>
|
|
36
|
+
<tr>
|
|
37
|
+
<td data-label="Spent"><%= expense.spent_on.strftime("%d %b %Y") %></td>
|
|
38
|
+
<td data-label="Category">
|
|
39
|
+
<%= expense.category.name %>
|
|
40
|
+
<div class="hrl-small hrl-muted"><%= expense.description %></div>
|
|
41
|
+
</td>
|
|
42
|
+
<td data-label="Amount" class="hrl-num"><%= hrl_money(expense.amount) %></td>
|
|
43
|
+
<td data-label="Status">
|
|
44
|
+
<%= hrl_request_status_badge(expense.status) %>
|
|
45
|
+
<% if expense.reimbursed_in %>
|
|
46
|
+
<div class="hrl-small hrl-muted">
|
|
47
|
+
with <%= expense.reimbursed_in.strftime("%B %Y") %> payroll
|
|
48
|
+
</div>
|
|
49
|
+
<% end %>
|
|
50
|
+
<% if expense.decision_note.present? %>
|
|
51
|
+
<div class="hrl-small hrl-muted"><%= expense.decision_note %></div>
|
|
52
|
+
<% end %>
|
|
53
|
+
</td>
|
|
54
|
+
<td data-label="">
|
|
55
|
+
<% if expense.draft? || expense.submitted? %>
|
|
56
|
+
<%= button_to "Withdraw", hr_lite.cancel_expense_path(expense),
|
|
57
|
+
class: "hrl-btn",
|
|
58
|
+
form: { data: { turbo_confirm: "Withdraw this claim?" } } %>
|
|
59
|
+
<% end %>
|
|
60
|
+
</td>
|
|
61
|
+
</tr>
|
|
62
|
+
<% end %>
|
|
63
|
+
</tbody>
|
|
64
|
+
</table>
|
|
65
|
+
</div>
|
|
66
|
+
<%= hrl_pagination %>
|
|
67
|
+
<% end %>
|
|
68
|
+
</section>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<% content_for(:page_title) { "New claim" } %>
|
|
2
|
+
<div class="hrl-page__head"><h1 class="hrl-page__title">New claim</h1></div>
|
|
3
|
+
|
|
4
|
+
<section class="hrl-card">
|
|
5
|
+
<%= form_with model: @expense, url: hr_lite.expenses_path, method: :post, local: true do |f| %>
|
|
6
|
+
<%= render "hr_lite/shared/form_errors", record: @expense %>
|
|
7
|
+
|
|
8
|
+
<div class="hrl-field">
|
|
9
|
+
<%= f.label :category_id, "What kind of expense" %>
|
|
10
|
+
<%= f.select :category_id, @categories.map { |c| [ c.name, c.id ] },
|
|
11
|
+
{ include_blank: "Choose one" } %>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="hrl-field">
|
|
14
|
+
<%= f.label :amount, "Amount (₹)" %>
|
|
15
|
+
<%= f.text_field :amount, inputmode: "decimal" %>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="hrl-field">
|
|
18
|
+
<%= f.label :spent_on, "When you spent it" %>
|
|
19
|
+
<%= f.date_field :spent_on, max: Date.current.to_s %>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="hrl-field">
|
|
22
|
+
<%= f.label :description, "What it was for" %>
|
|
23
|
+
<%= f.text_field :description %>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="hrl-field">
|
|
26
|
+
<%= f.label :receipt, "Receipt (PDF or photo)" %>
|
|
27
|
+
<%= f.file_field :receipt, accept: "application/pdf,image/*" %>
|
|
28
|
+
<span class="hrl-small hrl-muted">
|
|
29
|
+
Some categories need one — the form will say so if yours does.
|
|
30
|
+
</span>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="hrl-form-actions">
|
|
34
|
+
<%= f.submit "Submit claim", class: "hrl-btn hrl-btn--primary" %>
|
|
35
|
+
<a class="hrl-btn" href="<%= hr_lite.expenses_path %>">Cancel</a>
|
|
36
|
+
</div>
|
|
37
|
+
<% end %>
|
|
38
|
+
</section>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Ask HR" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Ask HR</h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<a class="hrl-btn hrl-btn--primary" href="<%= hr_lite.new_hr_request_path %>">New request</a>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<section class="hrl-card">
|
|
10
|
+
<% if @requests.empty? %>
|
|
11
|
+
<p class="hrl-muted">Nothing raised yet.</p>
|
|
12
|
+
<% else %>
|
|
13
|
+
<div class="hrl-table-wrap">
|
|
14
|
+
<table class="hrl-table hrl-table--stack">
|
|
15
|
+
<thead><tr><th>Request</th><th>Raised</th><th>Status</th><th></th></tr></thead>
|
|
16
|
+
<tbody>
|
|
17
|
+
<% @requests.each do |request| %>
|
|
18
|
+
<tr>
|
|
19
|
+
<td data-label="Request">
|
|
20
|
+
<a href="<%= hr_lite.hr_request_path(request) %>"><%= request.subject %></a>
|
|
21
|
+
<div class="hrl-small hrl-muted"><%= request.category_label %></div>
|
|
22
|
+
</td>
|
|
23
|
+
<td data-label="Raised"><%= request.created_at.to_date.strftime("%d %b %Y") %></td>
|
|
24
|
+
<td data-label="Status"><%= hrl_request_status_badge(request.status) %></td>
|
|
25
|
+
<td data-label="">
|
|
26
|
+
<% if request.open? || request.in_progress? %>
|
|
27
|
+
<%= button_to "Withdraw", hr_lite.cancel_hr_request_path(request),
|
|
28
|
+
class: "hrl-btn",
|
|
29
|
+
form: { data: { turbo_confirm: "Withdraw this request?" } } %>
|
|
30
|
+
<% end %>
|
|
31
|
+
</td>
|
|
32
|
+
</tr>
|
|
33
|
+
<% end %>
|
|
34
|
+
</tbody>
|
|
35
|
+
</table>
|
|
36
|
+
</div>
|
|
37
|
+
<%= hrl_pagination %>
|
|
38
|
+
<% end %>
|
|
39
|
+
</section>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<% content_for(:page_title) { "New request" } %>
|
|
2
|
+
<div class="hrl-page__head"><h1 class="hrl-page__title">Ask HR</h1></div>
|
|
3
|
+
|
|
4
|
+
<section class="hrl-card">
|
|
5
|
+
<%= form_with model: @request, url: hr_lite.hr_requests_path, method: :post, local: true do |f| %>
|
|
6
|
+
<%= render "hr_lite/shared/form_errors", record: @request %>
|
|
7
|
+
|
|
8
|
+
<div class="hrl-field">
|
|
9
|
+
<%= f.label :category, "What is this about" %>
|
|
10
|
+
<%= f.select :category,
|
|
11
|
+
HrLite::HrRequest::CATEGORIES.map { |c| [ c.humanize, c ] },
|
|
12
|
+
{ include_blank: "Choose one" } %>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="hrl-field">
|
|
15
|
+
<%= f.label :subject, "In one line" %>
|
|
16
|
+
<%= f.text_field :subject %>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="hrl-field">
|
|
19
|
+
<%= f.label :body, "Anything else HR should know" %>
|
|
20
|
+
<%= f.text_area :body, rows: 5 %>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div class="hrl-form-actions">
|
|
24
|
+
<%= f.submit "Send to HR", class: "hrl-btn hrl-btn--primary" %>
|
|
25
|
+
<a class="hrl-btn" href="<%= hr_lite.hr_requests_path %>">Cancel</a>
|
|
26
|
+
</div>
|
|
27
|
+
<% end %>
|
|
28
|
+
</section>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<% content_for(:page_title) { @request.subject } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title"><%= @request.subject %></h1>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<section class="hrl-card">
|
|
7
|
+
<p class="hrl-small hrl-muted">
|
|
8
|
+
<%= @request.category_label %> · raised
|
|
9
|
+
<%= @request.created_at.to_date.strftime("%d %b %Y") %> ·
|
|
10
|
+
<%= hrl_request_status_badge(@request.status) %>
|
|
11
|
+
</p>
|
|
12
|
+
<% if @request.body.present? %>
|
|
13
|
+
<div class="hrl-prose"><%= simple_format(@request.body) %></div>
|
|
14
|
+
<% end %>
|
|
15
|
+
</section>
|
|
16
|
+
|
|
17
|
+
<% if @request.resolution.present? %>
|
|
18
|
+
<section class="hrl-card">
|
|
19
|
+
<h2 class="hrl-card__title">HR's answer</h2>
|
|
20
|
+
<div class="hrl-prose"><%= simple_format(@request.resolution) %></div>
|
|
21
|
+
<p class="hrl-small hrl-muted">
|
|
22
|
+
<%= @request.resolved_at&.to_date&.strftime("%d %b %Y") %>
|
|
23
|
+
</p>
|
|
24
|
+
</section>
|
|
25
|
+
<% end %>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Policies" } %>
|
|
2
|
+
<div class="hrl-page__head"><h1 class="hrl-page__title">Policies</h1></div>
|
|
3
|
+
|
|
4
|
+
<section class="hrl-card">
|
|
5
|
+
<% if @policies.empty? %>
|
|
6
|
+
<p class="hrl-muted">No policies are published yet.</p>
|
|
7
|
+
<% else %>
|
|
8
|
+
<div class="hrl-table-wrap">
|
|
9
|
+
<table class="hrl-table hrl-table--stack">
|
|
10
|
+
<thead><tr><th>Policy</th><th>In force</th><th></th></tr></thead>
|
|
11
|
+
<tbody>
|
|
12
|
+
<% @policies.each do |policy| %>
|
|
13
|
+
<tr>
|
|
14
|
+
<td data-label="Policy">
|
|
15
|
+
<a href="<%= hr_lite.policy_path(policy) %>"><%= policy.title %></a>
|
|
16
|
+
<span class="hrl-badge hrl-badge--muted">v<%= policy.version %></span>
|
|
17
|
+
</td>
|
|
18
|
+
<td data-label="In force"><%= policy.effective_from.strftime("%d %b %Y") %></td>
|
|
19
|
+
<td data-label="">
|
|
20
|
+
<% if policy.acknowledgement_required %>
|
|
21
|
+
<% if @acknowledged.include?(policy.id) %>
|
|
22
|
+
<span class="hrl-badge hrl-badge--ok">Read</span>
|
|
23
|
+
<% else %>
|
|
24
|
+
<span class="hrl-badge hrl-badge--warn">Needs your acknowledgement</span>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% end %>
|
|
27
|
+
</td>
|
|
28
|
+
</tr>
|
|
29
|
+
<% end %>
|
|
30
|
+
</tbody>
|
|
31
|
+
</table>
|
|
32
|
+
</div>
|
|
33
|
+
<% end %>
|
|
34
|
+
</section>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<% content_for(:page_title) { @policy.title } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title"><%= @policy.title %></h1>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<section class="hrl-card">
|
|
7
|
+
<p class="hrl-small hrl-muted">
|
|
8
|
+
Version <%= @policy.version %>, in force from
|
|
9
|
+
<%= @policy.effective_from.strftime("%d %b %Y") %>.
|
|
10
|
+
</p>
|
|
11
|
+
<div class="hrl-prose"><%= simple_format(@policy.body) %></div>
|
|
12
|
+
</section>
|
|
13
|
+
|
|
14
|
+
<% if @policy.acknowledgement_required %>
|
|
15
|
+
<section class="hrl-card">
|
|
16
|
+
<% if @policy.acknowledged_by?(hr_current_user) %>
|
|
17
|
+
<p class="hrl-muted">You acknowledged this version.</p>
|
|
18
|
+
<% else %>
|
|
19
|
+
<%= button_to "I have read this", hr_lite.acknowledge_policy_path(@policy),
|
|
20
|
+
class: "hrl-btn hrl-btn--primary" %>
|
|
21
|
+
<% end %>
|
|
22
|
+
</section>
|
|
23
|
+
<% end %>
|
data/config/routes.rb
CHANGED
|
@@ -20,6 +20,16 @@ HrLite::Engine.routes.draw do
|
|
|
20
20
|
member { post :cancel }
|
|
21
21
|
end
|
|
22
22
|
resources :approvals, only: :index
|
|
23
|
+
resources :expenses, only: %i[index new create] do
|
|
24
|
+
member { post :cancel }
|
|
25
|
+
end
|
|
26
|
+
resources :hr_requests, only: %i[index show new create] do
|
|
27
|
+
member { post :cancel }
|
|
28
|
+
end
|
|
29
|
+
resources :policies, only: %i[index show] do
|
|
30
|
+
member { post :acknowledge }
|
|
31
|
+
end
|
|
32
|
+
resources :benefits, only: :index
|
|
23
33
|
get "team", to: "team#show"
|
|
24
34
|
get "org", to: "org#show"
|
|
25
35
|
resources :holidays, only: :index
|
|
@@ -51,6 +61,7 @@ HrLite::Engine.routes.draw do
|
|
|
51
61
|
resources :assignments, only: %i[create destroy], controller: "role_assignments"
|
|
52
62
|
end
|
|
53
63
|
resources :statutory_rate_cards, only: %i[index new create edit update]
|
|
64
|
+
resources :reports, only: %i[index show]
|
|
54
65
|
resources :leave_types, except: :show
|
|
55
66
|
resources :office_locations, except: :show
|
|
56
67
|
resources :holidays, only: %i[index create update destroy] do
|
data/lib/hr_lite/version.rb
CHANGED
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.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kshitiz sinha
|
|
@@ -71,6 +71,7 @@ files:
|
|
|
71
71
|
- app/controllers/hr_lite/admin/overview_controller.rb
|
|
72
72
|
- app/controllers/hr_lite/admin/payroll_runs_controller.rb
|
|
73
73
|
- app/controllers/hr_lite/admin/regularization_requests_controller.rb
|
|
74
|
+
- app/controllers/hr_lite/admin/reports_controller.rb
|
|
74
75
|
- app/controllers/hr_lite/admin/resignations_controller.rb
|
|
75
76
|
- app/controllers/hr_lite/admin/role_assignments_controller.rb
|
|
76
77
|
- app/controllers/hr_lite/admin/roles_controller.rb
|
|
@@ -83,16 +84,20 @@ files:
|
|
|
83
84
|
- app/controllers/hr_lite/appraisals_controller.rb
|
|
84
85
|
- app/controllers/hr_lite/approvals_controller.rb
|
|
85
86
|
- app/controllers/hr_lite/attendance_controller.rb
|
|
87
|
+
- app/controllers/hr_lite/benefits_controller.rb
|
|
86
88
|
- app/controllers/hr_lite/calendar_controller.rb
|
|
87
89
|
- app/controllers/hr_lite/career_controller.rb
|
|
88
90
|
- app/controllers/hr_lite/comp_off_requests_controller.rb
|
|
89
91
|
- app/controllers/hr_lite/employee_profiles_controller.rb
|
|
92
|
+
- app/controllers/hr_lite/expenses_controller.rb
|
|
90
93
|
- app/controllers/hr_lite/holidays_controller.rb
|
|
91
94
|
- app/controllers/hr_lite/home_controller.rb
|
|
95
|
+
- app/controllers/hr_lite/hr_requests_controller.rb
|
|
92
96
|
- app/controllers/hr_lite/kudos_controller.rb
|
|
93
97
|
- app/controllers/hr_lite/leave_balances_controller.rb
|
|
94
98
|
- app/controllers/hr_lite/leave_requests_controller.rb
|
|
95
99
|
- app/controllers/hr_lite/org_controller.rb
|
|
100
|
+
- app/controllers/hr_lite/policies_controller.rb
|
|
96
101
|
- app/controllers/hr_lite/regularization_requests_controller.rb
|
|
97
102
|
- app/controllers/hr_lite/resignations_controller.rb
|
|
98
103
|
- app/controllers/hr_lite/salary_slips_controller.rb
|
|
@@ -202,6 +207,8 @@ files:
|
|
|
202
207
|
- app/views/hr_lite/admin/payroll_runs/show.html.erb
|
|
203
208
|
- app/views/hr_lite/admin/regularization_requests/index.html.erb
|
|
204
209
|
- app/views/hr_lite/admin/regularization_requests/show.html.erb
|
|
210
|
+
- app/views/hr_lite/admin/reports/index.html.erb
|
|
211
|
+
- app/views/hr_lite/admin/reports/show.html.erb
|
|
205
212
|
- app/views/hr_lite/admin/roles/_form.html.erb
|
|
206
213
|
- app/views/hr_lite/admin/roles/edit.html.erb
|
|
207
214
|
- app/views/hr_lite/admin/roles/index.html.erb
|
|
@@ -222,6 +229,7 @@ files:
|
|
|
222
229
|
- app/views/hr_lite/attendance/_month_grid.html.erb
|
|
223
230
|
- app/views/hr_lite/attendance/_punch_card.html.erb
|
|
224
231
|
- app/views/hr_lite/attendance/show.html.erb
|
|
232
|
+
- app/views/hr_lite/benefits/index.html.erb
|
|
225
233
|
- app/views/hr_lite/calendar/show.html.erb
|
|
226
234
|
- app/views/hr_lite/career/show.html.erb
|
|
227
235
|
- app/views/hr_lite/comp_off_requests/index.html.erb
|
|
@@ -231,9 +239,14 @@ files:
|
|
|
231
239
|
- app/views/hr_lite/event_mailer/event.text.erb
|
|
232
240
|
- app/views/hr_lite/event_mailer/leadership.html.erb
|
|
233
241
|
- app/views/hr_lite/event_mailer/leadership.text.erb
|
|
242
|
+
- app/views/hr_lite/expenses/index.html.erb
|
|
243
|
+
- app/views/hr_lite/expenses/new.html.erb
|
|
234
244
|
- app/views/hr_lite/holidays/_next_holiday.html.erb
|
|
235
245
|
- app/views/hr_lite/holidays/index.html.erb
|
|
236
246
|
- app/views/hr_lite/home/index.html.erb
|
|
247
|
+
- app/views/hr_lite/hr_requests/index.html.erb
|
|
248
|
+
- app/views/hr_lite/hr_requests/new.html.erb
|
|
249
|
+
- app/views/hr_lite/hr_requests/show.html.erb
|
|
237
250
|
- app/views/hr_lite/kudos/_kudo.html.erb
|
|
238
251
|
- app/views/hr_lite/kudos/index.html.erb
|
|
239
252
|
- app/views/hr_lite/leave_balances/index.html.erb
|
|
@@ -243,6 +256,8 @@ files:
|
|
|
243
256
|
- app/views/hr_lite/leave_requests/show.html.erb
|
|
244
257
|
- app/views/hr_lite/org/_node.html.erb
|
|
245
258
|
- app/views/hr_lite/org/show.html.erb
|
|
259
|
+
- app/views/hr_lite/policies/index.html.erb
|
|
260
|
+
- app/views/hr_lite/policies/show.html.erb
|
|
246
261
|
- app/views/hr_lite/regularization_requests/index.html.erb
|
|
247
262
|
- app/views/hr_lite/regularization_requests/new.html.erb
|
|
248
263
|
- app/views/hr_lite/resignations/show.html.erb
|