hr_lite 0.21.3 → 0.22.1
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 +75 -0
- data/README.md +54 -2
- data/app/assets/javascripts/hr_lite/confirm.js +18 -3
- data/app/assets/javascripts/hr_lite/geo_punch.js +65 -10
- data/app/assets/javascripts/hr_lite/nav.js +17 -0
- data/app/assets/javascripts/hr_lite/select_filter.js +46 -0
- data/app/assets/stylesheets/hr_lite/hr_lite.css +219 -79
- data/app/controllers/hr_lite/admin/assets_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/attendances_controller.rb +31 -0
- data/app/controllers/hr_lite/approvals_controller.rb +1 -12
- data/app/controllers/hr_lite/attendance_controller.rb +7 -0
- data/app/controllers/hr_lite/holidays_controller.rb +1 -0
- data/app/controllers/hr_lite/home_controller.rb +40 -3
- data/app/controllers/hr_lite/hr_requests_controller.rb +1 -1
- data/app/controllers/hr_lite/leave_requests_controller.rb +13 -2
- data/app/controllers/hr_lite/regularization_requests_controller.rb +10 -2
- data/app/controllers/hr_lite/tax_declarations_controller.rb +4 -0
- data/app/helpers/hr_lite/application_helper.rb +43 -30
- data/app/jobs/hr_lite/attendance_close_job.rb +6 -1
- data/app/models/hr_lite/approval.rb +5 -0
- data/app/models/hr_lite/attendance_record.rb +26 -0
- data/app/models/hr_lite/employee_profile.rb +1 -0
- data/app/models/hr_lite/hr_request.rb +2 -1
- data/app/models/hr_lite/office_location.rb +12 -0
- data/app/models/hr_lite/regularization_request.rb +10 -4
- data/app/services/hr_lite/attendance_puncher.rb +8 -3
- data/app/views/hr_lite/admin/assets/index.html.erb +3 -2
- data/app/views/hr_lite/admin/assets/new.html.erb +6 -2
- data/app/views/hr_lite/admin/attendances/index.html.erb +37 -6
- data/app/views/hr_lite/admin/attendances/show.html.erb +11 -7
- data/app/views/hr_lite/admin/attendances/week.html.erb +42 -0
- data/app/views/hr_lite/admin/checklists/index.html.erb +1 -1
- data/app/views/hr_lite/admin/comp_off_requests/index.html.erb +2 -2
- data/app/views/hr_lite/admin/comp_off_requests/show.html.erb +2 -2
- data/app/views/hr_lite/admin/documents/index.html.erb +1 -1
- data/app/views/hr_lite/admin/employees/_form.html.erb +15 -7
- data/app/views/hr_lite/admin/employees/show.html.erb +5 -5
- data/app/views/hr_lite/admin/expenses/index.html.erb +2 -2
- data/app/views/hr_lite/admin/leave_balances/index.html.erb +3 -3
- data/app/views/hr_lite/admin/leave_requests/index.html.erb +2 -2
- data/app/views/hr_lite/admin/leave_requests/show.html.erb +4 -6
- data/app/views/hr_lite/admin/loans/new.html.erb +2 -1
- data/app/views/hr_lite/admin/overview/index.html.erb +3 -3
- data/app/views/hr_lite/admin/regularization_requests/index.html.erb +1 -1
- data/app/views/hr_lite/admin/shared/_approvals_tabs.html.erb +6 -5
- data/app/views/hr_lite/appraisals/show.html.erb +1 -1
- data/app/views/hr_lite/approvals/index.html.erb +1 -1
- data/app/views/hr_lite/attendance/_month_grid.html.erb +21 -26
- data/app/views/hr_lite/attendance/_punch_card.html.erb +32 -10
- data/app/views/hr_lite/attendance/show.html.erb +36 -7
- data/app/views/hr_lite/benefits/index.html.erb +1 -1
- data/app/views/hr_lite/calendar/show.html.erb +29 -22
- data/app/views/hr_lite/comp_off_requests/index.html.erb +3 -3
- data/app/views/hr_lite/comp_off_requests/new.html.erb +3 -2
- data/app/views/hr_lite/documents/index.html.erb +32 -30
- data/app/views/hr_lite/employee_profiles/show.html.erb +2 -2
- data/app/views/hr_lite/expenses/index.html.erb +17 -35
- data/app/views/hr_lite/expenses/new.html.erb +11 -6
- data/app/views/hr_lite/holidays/_next_holiday.html.erb +11 -8
- data/app/views/hr_lite/holidays/index.html.erb +6 -6
- data/app/views/hr_lite/home/index.html.erb +29 -19
- data/app/views/hr_lite/hr_requests/index.html.erb +7 -24
- data/app/views/hr_lite/hr_requests/new.html.erb +7 -5
- data/app/views/hr_lite/hr_requests/show.html.erb +4 -0
- data/app/views/hr_lite/kudos/index.html.erb +4 -3
- data/app/views/hr_lite/leave_balances/index.html.erb +14 -5
- data/app/views/hr_lite/leave_requests/_balance_chips.html.erb +5 -3
- data/app/views/hr_lite/leave_requests/_out_list.html.erb +16 -0
- data/app/views/hr_lite/leave_requests/index.html.erb +8 -21
- data/app/views/hr_lite/leave_requests/new.html.erb +22 -9
- data/app/views/hr_lite/leave_requests/show.html.erb +3 -5
- data/app/views/hr_lite/loans/index.html.erb +18 -20
- data/app/views/hr_lite/policies/index.html.erb +1 -1
- data/app/views/hr_lite/regularization_requests/index.html.erb +2 -2
- data/app/views/hr_lite/regularization_requests/new.html.erb +11 -8
- data/app/views/hr_lite/resignations/show.html.erb +1 -1
- data/app/views/hr_lite/salary_slips/_slip_detail.html.erb +9 -3
- data/app/views/hr_lite/salary_slips/index.html.erb +48 -44
- data/app/views/hr_lite/shared/_bell.html.erb +1 -1
- data/app/views/hr_lite/shared/_form_errors.html.erb +1 -1
- data/app/views/hr_lite/tax_declarations/show.html.erb +24 -19
- data/app/views/hr_lite/team/show.html.erb +2 -2
- data/app/views/layouts/hr_lite/application.html.erb +24 -8
- data/config/routes.rb +3 -1
- data/lib/hr_lite/configuration.rb +16 -2
- data/lib/hr_lite/notifications.rb +1 -0
- data/lib/hr_lite/version.rb +1 -1
- metadata +4 -1
|
@@ -11,30 +11,17 @@
|
|
|
11
11
|
</div>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
|
-
<%= render "hr_lite/leave_requests/balance_chips" %>
|
|
14
|
+
<%= render "hr_lite/leave_requests/balance_chips", compact: true %>
|
|
15
15
|
|
|
16
16
|
<section class="hrl-card">
|
|
17
17
|
<% if @requests.any? %>
|
|
18
|
-
|
|
19
|
-
<
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<td data-label="Dates"><%= request.date_range_label %></td>
|
|
26
|
-
<td data-label="Days" class="hrl-num"><%= request.days_count.to_f %></td>
|
|
27
|
-
<td data-label="Status">
|
|
28
|
-
<span class="hrl-badge <%= { "approved" => "hrl-badge--ok", "rejected" => "hrl-badge--bad", "cancelled" => "hrl-badge--muted" }[request.status] %>"><%= request.status.humanize %></span>
|
|
29
|
-
</td>
|
|
30
|
-
<td data-label="">
|
|
31
|
-
<a class="hrl-small" href="<%= hr_lite.leave_request_path(request) %>">View</a>
|
|
32
|
-
</td>
|
|
33
|
-
</tr>
|
|
34
|
-
<% end %>
|
|
35
|
-
</tbody>
|
|
36
|
-
</table>
|
|
37
|
-
</div>
|
|
18
|
+
<% @requests.each do |request| %>
|
|
19
|
+
<a class="hrl-listrow" href="<%= hr_lite.leave_request_path(request) %>">
|
|
20
|
+
<span><span class="hrl-badge hrl-badge--type" style="--hrl-type: <%= request.leave_type.color %>"><%= request.leave_type.code %></span> <%= request.leave_type.name %></span>
|
|
21
|
+
<%= hrl_request_status_badge(request.status) %>
|
|
22
|
+
<span class="hrl-small hrl-muted"><%= request.date_range_label %> · <%= pluralize(hrl_days(request.days_count), "day") %></span>
|
|
23
|
+
</a>
|
|
24
|
+
<% end %>
|
|
38
25
|
<%= hrl_pagination %>
|
|
39
26
|
<% else %>
|
|
40
27
|
<p class="hrl-card--empty">No leave requests yet.</p>
|
|
@@ -1,29 +1,37 @@
|
|
|
1
1
|
<% content_for(:page_title) { "Apply for leave" } %>
|
|
2
|
+
<% content_for(:back, "Leaves") %>
|
|
2
3
|
<div class="hrl-page__head">
|
|
3
4
|
<h1 class="hrl-page__title">Apply for leave</h1>
|
|
4
5
|
</div>
|
|
5
6
|
|
|
6
|
-
<%= render "hr_lite/leave_requests/balance_chips" %>
|
|
7
|
-
<p class="hrl-small hrl-muted">Days beyond your balance are unpaid (loss of pay), cut from that month's salary.</p>
|
|
8
|
-
|
|
9
7
|
<section class="hrl-card">
|
|
10
8
|
<%= form_with model: @request, url: hr_lite.leave_requests_path, local: true do |f| %>
|
|
11
9
|
<%= render "hr_lite/shared/form_errors", record: @request %>
|
|
12
10
|
<div class="hrl-field">
|
|
13
|
-
<%= f.label :leave_type_id, "Type" %>
|
|
14
|
-
|
|
11
|
+
<%= f.label :leave_type_id, "Type", id: "hrl-leave-type", for: nil %>
|
|
12
|
+
<% left = @balances.index_by(&:leave_type_id) %>
|
|
13
|
+
<div class="hrl-chiprow" role="radiogroup" aria-labelledby="hrl-leave-type">
|
|
14
|
+
<% HrLite::LeaveType.active.each_with_index do |type, i| %>
|
|
15
|
+
<label><%= f.radio_button :leave_type_id, type.id, required: i.zero? %><span><%= type.name.sub(/ leave\z/i, "") %><%= " · #{hrl_days(left[type.id].available)} left" if left[type.id] %><%= " · Unpaid" unless type.paid %></span></label>
|
|
16
|
+
<% end %>
|
|
17
|
+
</div>
|
|
18
|
+
<p class="hrl-hint">Days beyond your balance are unpaid (loss of pay), cut from that month's salary.</p>
|
|
15
19
|
</div>
|
|
16
20
|
<div class="hrl-field">
|
|
17
21
|
<%= f.label :start_date, "From" %>
|
|
18
|
-
<%= f.date_field :start_date %>
|
|
22
|
+
<%= f.date_field :start_date, required: true %>
|
|
19
23
|
</div>
|
|
20
24
|
<div class="hrl-field">
|
|
21
|
-
<%= f.label :end_date, "To" %>
|
|
25
|
+
<%= f.label :end_date, "To (leave blank for one day)" %>
|
|
22
26
|
<%= f.date_field :end_date %>
|
|
23
27
|
</div>
|
|
24
28
|
<div class="hrl-field">
|
|
25
|
-
<%= f.label :half_day_part, "Day" %>
|
|
26
|
-
|
|
29
|
+
<%= f.label :half_day_part, "Day", id: "hrl-day-part", for: nil %>
|
|
30
|
+
<div class="hrl-chiprow" role="radiogroup" aria-labelledby="hrl-day-part">
|
|
31
|
+
<% HrLite::DAY_PARTS.each do |label, value| %>
|
|
32
|
+
<label><%= f.radio_button :half_day_part, value %><span><%= label %></span></label>
|
|
33
|
+
<% end %>
|
|
34
|
+
</div>
|
|
27
35
|
</div>
|
|
28
36
|
<div class="hrl-field">
|
|
29
37
|
<%= f.label :reason, "Reason (optional)" %>
|
|
@@ -35,3 +43,8 @@
|
|
|
35
43
|
</div>
|
|
36
44
|
<% end %>
|
|
37
45
|
</section>
|
|
46
|
+
|
|
47
|
+
<section class="hrl-card">
|
|
48
|
+
<h2 class="hrl-card__title">Out in the next 2 weeks</h2>
|
|
49
|
+
<%= render "hr_lite/leave_requests/out_list", leaves: @out_soon, empty: "Nobody is on leave in the next 2 weeks." %>
|
|
50
|
+
</section>
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
<% content_for(:page_title) { "Leave request" } %>
|
|
2
|
+
<% content_for(:back, "Leaves") %>
|
|
2
3
|
<div class="hrl-page__head">
|
|
3
4
|
<h1 class="hrl-page__title">Leave request</h1>
|
|
4
|
-
<div class="hrl-page__actions">
|
|
5
|
-
<a class="hrl-btn" href="<%= hr_lite.leave_requests_path %>">Back</a>
|
|
6
|
-
</div>
|
|
7
5
|
</div>
|
|
8
6
|
|
|
9
7
|
<section class="hrl-card">
|
|
10
8
|
<dl class="hrl-deflist">
|
|
11
9
|
<dt>Type</dt><dd><%= @request.leave_type.name %></dd>
|
|
12
10
|
<dt>Dates</dt><dd><%= @request.date_range_label %></dd>
|
|
13
|
-
<dt>Days</dt><dd><%= @request.days_count
|
|
14
|
-
<dt>Status</dt><dd
|
|
11
|
+
<dt>Days</dt><dd><%= hrl_days(@request.days_count) %></dd>
|
|
12
|
+
<dt>Status</dt><dd><%= hrl_request_status_badge(@request.status) %></dd>
|
|
15
13
|
<% if @request.reason.present? %><dt>Reason</dt><dd><%= @request.reason %></dd><% end %>
|
|
16
14
|
<% if @request.decision_note.present? %><dt>Decision note</dt><dd><%= @request.decision_note %></dd><% end %>
|
|
17
15
|
<% if @request.decided_at %><dt>Decided</dt><dd><%= @request.decided_at.strftime("%d %b %Y") %> by <%= hr_display_name(@request.decided_by) %></dd><% end %>
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
<div class="hrl-page__head"><h1 class="hrl-page__title">Loans & advances</h1></div>
|
|
3
3
|
|
|
4
4
|
<% if @loans.empty? %>
|
|
5
|
-
<section class="hrl-card"
|
|
5
|
+
<section class="hrl-card">
|
|
6
|
+
<p class="hrl-muted">You have no loans or salary advances.</p>
|
|
7
|
+
<a class="hrl-card__link" href="<%= hr_lite.new_hr_request_path(category: "payroll_query") %>">Ask HR about an advance</a>
|
|
8
|
+
</section>
|
|
6
9
|
<% else %>
|
|
7
10
|
<section class="hrl-card">
|
|
8
11
|
<p>Outstanding across everything: <strong><%= hrl_money(@outstanding) %></strong></p>
|
|
@@ -15,32 +18,27 @@
|
|
|
15
18
|
<span class="hrl-badge <%= "hrl-badge--muted" unless loan.active? %>"><%= loan.status.humanize %></span>
|
|
16
19
|
</h2>
|
|
17
20
|
<% if loan.reason.present? %><p class="hrl-muted"><%= loan.reason %></p><% end %>
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
</td>
|
|
29
|
-
</tr>
|
|
30
|
-
</tbody>
|
|
31
|
-
</table>
|
|
32
|
-
</div>
|
|
21
|
+
<dl class="hrl-deflist">
|
|
22
|
+
<dt>Monthly instalment</dt><dd><%= hrl_money(loan.monthly_instalment) %></dd>
|
|
23
|
+
<dt>Repaid so far</dt><dd><%= hrl_money(loan.repaid) %></dd>
|
|
24
|
+
<dt>Outstanding</dt><dd><strong><%= hrl_money(loan.outstanding) %></strong></dd>
|
|
25
|
+
<dt>Next deduction</dt>
|
|
26
|
+
<dd>
|
|
27
|
+
<% amount = loan.instalment_for(@next_month) %>
|
|
28
|
+
<%= amount.positive? ? "#{hrl_money(amount)} in #{@next_month.strftime('%b %Y')}" : "—" %>
|
|
29
|
+
</dd>
|
|
30
|
+
</dl>
|
|
33
31
|
|
|
34
32
|
<% if loan.loan_repayments.any? %>
|
|
35
33
|
<h3 class="hrl-card__title">Already deducted</h3>
|
|
36
34
|
<div class="hrl-table-wrap">
|
|
37
|
-
<table class="hrl-table
|
|
38
|
-
<thead><tr><th>Month</th><th>Amount</th></tr></thead>
|
|
35
|
+
<table class="hrl-table">
|
|
36
|
+
<thead><tr><th>Month</th><th class="hrl-num">Amount</th></tr></thead>
|
|
39
37
|
<tbody>
|
|
40
38
|
<% loan.loan_repayments.sort_by(&:period_month).reverse.each do |r| %>
|
|
41
39
|
<tr>
|
|
42
|
-
<td
|
|
43
|
-
<td
|
|
40
|
+
<td><%= r.period_month.strftime("%b %Y") %></td>
|
|
41
|
+
<td class="hrl-num"><%= hrl_money(r.amount) %></td>
|
|
44
42
|
</tr>
|
|
45
43
|
<% end %>
|
|
46
44
|
</tbody>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<% @policies.each do |policy| %>
|
|
13
13
|
<tr>
|
|
14
14
|
<td data-label="Policy">
|
|
15
|
-
<a href="<%= hr_lite.policy_path(policy) %>"><%= policy.title %></a>
|
|
15
|
+
<a class="hrl-btn" href="<%= hr_lite.policy_path(policy) %>"><%= policy.title %></a>
|
|
16
16
|
<span class="hrl-badge hrl-badge--muted">v<%= policy.version %></span>
|
|
17
17
|
</td>
|
|
18
18
|
<td data-label="In force"><%= policy.effective_from.strftime("%d %b %Y") %></td>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<% content_for(:page_title) { "Regularization" } %>
|
|
2
|
+
<% content_for(:back, "Attendance") %>
|
|
2
3
|
<div class="hrl-page__head">
|
|
3
4
|
<h1 class="hrl-page__title">My regularization tickets</h1>
|
|
4
5
|
<div class="hrl-page__actions">
|
|
5
|
-
<a class="hrl-btn" href="<%= hr_lite.attendance_path %>">My attendance</a>
|
|
6
6
|
<a class="hrl-btn hrl-btn--primary" href="<%= hr_lite.new_regularization_request_path %>">Raise a ticket</a>
|
|
7
7
|
</div>
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
10
|
<section class="hrl-card">
|
|
11
|
-
<p class="hrl-small hrl-muted"
|
|
11
|
+
<p class="hrl-small hrl-muted">
|
|
12
12
|
Forgot to check in or out? Raise a ticket with the actual times — once an
|
|
13
13
|
admin approves, your attendance for that day is fixed automatically.
|
|
14
14
|
</p>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<% content_for(:page_title) { "Raise a regularization ticket" } %>
|
|
2
|
+
<% content_for(:back, "Attendance") %>
|
|
2
3
|
<div class="hrl-page__head">
|
|
3
4
|
<h1 class="hrl-page__title">Raise a regularization ticket</h1>
|
|
4
5
|
</div>
|
|
@@ -7,23 +8,25 @@
|
|
|
7
8
|
<%= form_with model: @request, url: hr_lite.regularization_requests_path, scope: :regularization_request, local: true do |f| %>
|
|
8
9
|
<%= render "hr_lite/shared/form_errors", record: @request %>
|
|
9
10
|
<% if (rule = HrLite.config.self_regularization) %>
|
|
10
|
-
<p class="hrl-small hrl-muted">A missed punch on a working day from today back to <%= rule[:within_days] %> days ago is fixed as soon as you submit, up to <%= rule[:per_week] %> times a week. Anything else goes to HR as a ticket.</p>
|
|
11
|
+
<p class="hrl-small hrl-muted">A missed punch or short day on a working day from today back to <%= rule[:within_days] %> days ago is fixed as soon as you submit, up to <%= rule[:per_week] %> times a week. Anything else goes to HR as a ticket.</p>
|
|
11
12
|
<% end %>
|
|
12
13
|
<div class="hrl-field">
|
|
13
14
|
<%= f.label :date, "Which day needs fixing?" %>
|
|
14
|
-
<%= f.date_field :date, value: @request.date&.strftime("%Y-%m-%d"), max: Date.current %>
|
|
15
|
+
<%= f.date_field :date, value: @request.date&.strftime("%Y-%m-%d"), max: Date.current, required: true %>
|
|
15
16
|
</div>
|
|
16
17
|
<div class="hrl-field">
|
|
17
|
-
<%= f.label :check_in_at, "Actual check-in
|
|
18
|
-
<%= f.
|
|
18
|
+
<%= f.label :check_in_at, "Actual check-in" %>
|
|
19
|
+
<%= f.time_field :check_in_at, value: @request.check_in_at&.strftime("%H:%M") %>
|
|
20
|
+
<p class="hrl-hint">Leave blank if only check-out is missing.</p>
|
|
19
21
|
</div>
|
|
20
22
|
<div class="hrl-field">
|
|
21
|
-
<%= f.label :check_out_at, "Actual check-out
|
|
22
|
-
<%= f.
|
|
23
|
+
<%= f.label :check_out_at, "Actual check-out" %>
|
|
24
|
+
<%= f.time_field :check_out_at, value: @request.check_out_at&.strftime("%H:%M") %>
|
|
25
|
+
<p class="hrl-hint">Leave blank if only check-in is missing. Short day? Leave both times blank and give the reason.</p>
|
|
23
26
|
</div>
|
|
24
27
|
<div class="hrl-field">
|
|
25
|
-
<%= f.label :reason, "Why
|
|
26
|
-
<%= f.text_area :reason %>
|
|
28
|
+
<%= f.label :reason, "Why does this day need fixing? (required)" %>
|
|
29
|
+
<%= f.text_area :reason, required: true %>
|
|
27
30
|
</div>
|
|
28
31
|
<div class="hrl-form-actions">
|
|
29
32
|
<%= f.submit "Raise ticket", class: "hrl-btn hrl-btn--primary" %>
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<%= render "hr_lite/shared/form_errors", record: @new_resignation %>
|
|
29
29
|
<div class="hrl-field">
|
|
30
30
|
<%= f.label :proposed_last_day, "Proposed last working day" %>
|
|
31
|
-
<%= f.date_field :proposed_last_day %>
|
|
31
|
+
<%= f.date_field :proposed_last_day, required: true %>
|
|
32
32
|
</div>
|
|
33
33
|
<div class="hrl-field">
|
|
34
34
|
<%= f.label :reason, "Reason (optional)" %>
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
<%# locals: slip, profile — shared by employee show, admin show %>
|
|
2
|
+
<div class="hrl-kpis hrl-kpis--money">
|
|
3
|
+
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= hrl_money(slip.net_pay) %></div><div class="hrl-kpi__label">Net pay</div></div>
|
|
4
|
+
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= hrl_money(slip.gross_earnings) %></div><div class="hrl-kpi__label">Gross</div></div>
|
|
5
|
+
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= hrl_money(slip.total_deductions) %></div><div class="hrl-kpi__label">Deductions</div></div>
|
|
6
|
+
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= hrl_days(slip.payable_days) %> / <%= hrl_days(slip.effective_lop_days) %></div><div class="hrl-kpi__label">Payable / LOP days</div></div>
|
|
7
|
+
</div>
|
|
2
8
|
<div class="hrl-grid hrl-grid--2">
|
|
3
9
|
<section class="hrl-card">
|
|
4
10
|
<h2 class="hrl-card__title">Earnings</h2>
|
|
@@ -36,12 +42,12 @@
|
|
|
36
42
|
|
|
37
43
|
<section class="hrl-card">
|
|
38
44
|
<dl class="hrl-deflist">
|
|
39
|
-
<dt>Net pay</dt><dd><strong><%= hrl_money(slip.net_pay) %></strong
|
|
45
|
+
<dt>Net pay</dt><dd><strong><%= hrl_money(slip.net_pay) %></strong><br><span class="hrl-small hrl-muted"><%= hrl_amount_in_words(slip.net_pay) %></span></dd>
|
|
40
46
|
<%# Out-of-window days are named rather than silently dropped: without them
|
|
41
47
|
a mid-month joiner's row does not add up to the month. %>
|
|
42
48
|
<dt>Days</dt>
|
|
43
|
-
<dd><%= slip.payable_days %> payable / <%= slip.effective_lop_days %> LOP<% if slip.out_of_window_days.to_f.positive? %>
|
|
44
|
-
/ <%= slip.out_of_window_days %> outside employment<% end %> of <%= slip.days_in_month %></dd>
|
|
49
|
+
<dd><%= hrl_days(slip.payable_days) %> payable / <%= hrl_days(slip.effective_lop_days) %> LOP<% if slip.out_of_window_days.to_f.positive? %>
|
|
50
|
+
/ <%= hrl_days(slip.out_of_window_days) %> outside employment<% end %> of <%= slip.days_in_month %></dd>
|
|
45
51
|
<% if profile %>
|
|
46
52
|
<dt>Employee code</dt><dd><%= profile.employee_code %></dd>
|
|
47
53
|
<% if profile.masked_uan %><dt>PF UAN</dt><dd><%= profile.masked_uan %></dd><% end %>
|
|
@@ -4,31 +4,60 @@
|
|
|
4
4
|
</div>
|
|
5
5
|
|
|
6
6
|
<section class="hrl-card">
|
|
7
|
-
<h2 class="hrl-card__title">
|
|
8
|
-
<% if
|
|
9
|
-
<p class="hrl-small hrl-muted">Current salary from <%= @structure.effective_from.strftime("%d %b %Y") %></p>
|
|
7
|
+
<h2 class="hrl-card__title">Slips</h2>
|
|
8
|
+
<% if @slips.any? %>
|
|
10
9
|
<div class="hrl-table-wrap">
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<thead><tr><th>Component</th><th class="hrl-num">Monthly</th><th class="hrl-num">Yearly</th></tr></thead>
|
|
10
|
+
<table class="hrl-table hrl-table--stack">
|
|
11
|
+
<thead><tr><th>Period</th><th class="hrl-num">Net pay</th><th></th></tr></thead>
|
|
14
12
|
<tbody>
|
|
15
|
-
<%
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
<td data-label="Yearly" class="hrl-num"><%= content_tag(weight, hrl_rupees(breakup[:yearly].fetch(label, amount * 12))) %></td>
|
|
25
|
-
</tr>
|
|
26
|
-
<% end %>
|
|
13
|
+
<% @slips.each do |slip| %>
|
|
14
|
+
<tr>
|
|
15
|
+
<td data-label="Period"><%= slip.period_month.strftime("%B %Y") %></td>
|
|
16
|
+
<td data-label="Net pay" class="hrl-num"><strong><%= hrl_money(slip.net_pay) %></strong></td>
|
|
17
|
+
<td data-label="">
|
|
18
|
+
<a class="hrl-btn" href="<%= hr_lite.salary_slip_path(slip) %>">View</a>
|
|
19
|
+
<a class="hrl-btn" href="<%= hr_lite.salary_slip_path(slip, format: :pdf) %>">PDF</a>
|
|
20
|
+
</td>
|
|
21
|
+
</tr>
|
|
27
22
|
<% end %>
|
|
28
23
|
</tbody>
|
|
29
24
|
</table>
|
|
30
25
|
</div>
|
|
31
|
-
|
|
26
|
+
<%= hrl_pagination %>
|
|
27
|
+
<% else %>
|
|
28
|
+
<p class="hrl-card--empty">No published salary slips yet.<% if (day = HrLite.config.slip_release_day) %> Each month's slip opens on the <%= day.ordinalize %> of the next month.<% end %></p>
|
|
29
|
+
<% end %>
|
|
30
|
+
</section>
|
|
31
|
+
|
|
32
|
+
<section class="hrl-card">
|
|
33
|
+
<h2 class="hrl-card__title">My salary</h2>
|
|
34
|
+
<% if (breakup = @structure&.breakup) %>
|
|
35
|
+
<p class="hrl-small hrl-muted">Current salary from <%= @structure.effective_from.strftime("%d %b %Y") %></p>
|
|
36
|
+
<details>
|
|
37
|
+
<summary class="hrl-btn">Show salary structure</summary>
|
|
38
|
+
<div class="hrl-table-wrap hrl-mt">
|
|
39
|
+
<%# Three narrow columns fit a 320px phone; stacking repeated the headings on every line. %>
|
|
40
|
+
<table class="hrl-table hrl-table--tight hrl-small">
|
|
41
|
+
<thead><tr><th>Component</th><th class="hrl-num">Monthly</th><th class="hrl-num">Yearly</th></tr></thead>
|
|
42
|
+
<tbody>
|
|
43
|
+
<% { "Earnings" => breakup[:earnings].merge("Gross" => breakup[:monthly_gross]),
|
|
44
|
+
"Deductions" => breakup[:deductions].merge("In-hand before tax" => breakup[:in_hand]),
|
|
45
|
+
"Employer contributions" => breakup[:employer].merge("CTC" => breakup[:monthly_ctc]) }.each do |section, lines| %>
|
|
46
|
+
<tr><th colspan="3"><%= section %></th></tr>
|
|
47
|
+
<% lines.each do |label, amount| %>
|
|
48
|
+
<% weight = label == lines.keys.last ? :strong : :span %>
|
|
49
|
+
<tr>
|
|
50
|
+
<td data-label="Component"><%= content_tag(weight, label) %></td>
|
|
51
|
+
<td data-label="Monthly" class="hrl-num"><%= content_tag(weight, hrl_rupees(amount)) %></td>
|
|
52
|
+
<td data-label="Yearly" class="hrl-num"><%= content_tag(weight, hrl_rupees(breakup[:yearly].fetch(label, amount * 12))) %></td>
|
|
53
|
+
</tr>
|
|
54
|
+
<% end %>
|
|
55
|
+
<% end %>
|
|
56
|
+
</tbody>
|
|
57
|
+
</table>
|
|
58
|
+
</div>
|
|
59
|
+
<p class="hrl-small hrl-muted">Income tax (TDS) depends on your declarations and is shown on each slip.</p>
|
|
60
|
+
</details>
|
|
32
61
|
<% end %>
|
|
33
62
|
<% @upcoming.each do |structure| %>
|
|
34
63
|
<% upcoming = structure.breakup(on: structure.effective_from) %>
|
|
@@ -49,28 +78,3 @@
|
|
|
49
78
|
<% end %>
|
|
50
79
|
<% end %>
|
|
51
80
|
</section>
|
|
52
|
-
|
|
53
|
-
<section class="hrl-card">
|
|
54
|
-
<% if @slips.any? %>
|
|
55
|
-
<div class="hrl-table-wrap">
|
|
56
|
-
<table class="hrl-table hrl-table--stack">
|
|
57
|
-
<thead><tr><th>Period</th><th>Net pay</th><th></th></tr></thead>
|
|
58
|
-
<tbody>
|
|
59
|
-
<% @slips.each do |slip| %>
|
|
60
|
-
<tr>
|
|
61
|
-
<td data-label="Period"><%= slip.period_month.strftime("%B %Y") %></td>
|
|
62
|
-
<td data-label="Net pay" class="hrl-num"><strong><%= hrl_money(slip.net_pay) %></strong></td>
|
|
63
|
-
<td data-label="">
|
|
64
|
-
<a class="hrl-btn" href="<%= hr_lite.salary_slip_path(slip) %>">View</a>
|
|
65
|
-
<a class="hrl-btn" href="<%= hr_lite.salary_slip_path(slip, format: :pdf) %>">PDF</a>
|
|
66
|
-
</td>
|
|
67
|
-
</tr>
|
|
68
|
-
<% end %>
|
|
69
|
-
</tbody>
|
|
70
|
-
</table>
|
|
71
|
-
</div>
|
|
72
|
-
<%= hrl_pagination %>
|
|
73
|
-
<% else %>
|
|
74
|
-
<p class="hrl-card--empty">No published salary slips yet.<% if (day = HrLite.config.slip_release_day) %> Each month's slip opens on the <%= day.ordinalize %> of the next month.<% end %></p>
|
|
75
|
-
<% end %>
|
|
76
|
-
</section>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<% if (bell = HrLite.config.notifications&.call(hr_current_user)) %>
|
|
2
|
-
<a class="hrl-bell" href="<%= bell[:url] %>">Notifications<% if bell[:unread].to_i.positive? %> <span class="hrl-bell__count"><%= bell[:unread]
|
|
2
|
+
<a class="hrl-bell" href="<%= bell[:url] %>">Notifications<% if bell[:unread].to_i.positive? %> <span class="hrl-bell__count"><%= bell[:unread] %><span class="hrl-sr-only"> unread</span></span><% end %></a>
|
|
3
3
|
<% end %>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<% if record.errors.any? %>
|
|
2
|
-
<div class="hrl-errors">
|
|
2
|
+
<div class="hrl-errors" role="alert" tabindex="-1" id="hrl-errors" autofocus>
|
|
3
3
|
<strong><%= pluralize(record.errors.count, "problem") %> prevented saving:</strong>
|
|
4
4
|
<ul>
|
|
5
5
|
<% record.errors.full_messages.each do |message| %>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<% content_for(:page_title) { "Tax declaration" } %>
|
|
2
|
+
<% submittable = @declaration.persisted? && (@declaration.draft? || @declaration.rejected?) %>
|
|
2
3
|
<div class="hrl-page__head">
|
|
3
4
|
<h1 class="hrl-page__title">Tax declaration — <%= @declaration.label %></h1>
|
|
4
5
|
</div>
|
|
@@ -24,24 +25,29 @@
|
|
|
24
25
|
|
|
25
26
|
<section class="hrl-card">
|
|
26
27
|
<div class="hrl-field">
|
|
27
|
-
<%= f.label :regime, "Tax regime" %>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
<%= f.label :regime, "Tax regime", id: "hrl-tax-regime", for: nil %>
|
|
29
|
+
<div role="radiogroup" aria-labelledby="hrl-tax-regime">
|
|
30
|
+
<% [ [ "new", "New regime", "Lower rates, no deductions." ],
|
|
31
|
+
[ "old", "Old regime", "The deductions below reduce your tax." ] ].each do |value, name, hint| %>
|
|
32
|
+
<div class="hrl-field--check">
|
|
33
|
+
<%= f.radio_button :regime, value %>
|
|
34
|
+
<%= f.label :regime, value: value do %><span><%= name %><span class="hrl-hint"><%= hint %></span></span><% end %>
|
|
35
|
+
</div>
|
|
36
|
+
<% end %>
|
|
37
|
+
</div>
|
|
33
38
|
</div>
|
|
34
39
|
</section>
|
|
35
40
|
|
|
36
|
-
<
|
|
37
|
-
<
|
|
41
|
+
<details class="hrl-card" <%= "open" if @declaration.regime != "new" || @declaration.errors.any? %>>
|
|
42
|
+
<summary class="hrl-btn">Deductions (old regime only)</summary>
|
|
38
43
|
<%= f.fields_for :tax_declaration_items do |item| %>
|
|
39
44
|
<div class="hrl-field">
|
|
40
45
|
<%= item.hidden_field :section %>
|
|
41
46
|
<%= item.label :declared_amount, item.object.section_label %>
|
|
42
47
|
<%= item.text_field :declared_amount,
|
|
43
48
|
value: item.object.declared_amount&.to_s("F"), inputmode: "decimal" %>
|
|
44
|
-
<%= item.
|
|
49
|
+
<%= item.label :label, "What it is (optional)", class: "hrl-mt hrl-muted" %>
|
|
50
|
+
<%= item.text_field :label %>
|
|
45
51
|
<% if item.object.persisted? && item.object.verified_amount %>
|
|
46
52
|
<span class="hrl-small hrl-muted">
|
|
47
53
|
HR verified <%= hrl_money(item.object.verified_amount) %>
|
|
@@ -50,19 +56,18 @@
|
|
|
50
56
|
</div>
|
|
51
57
|
<% end %>
|
|
52
58
|
<p>Total claimed: <strong><%= hrl_money(@declaration.declared_total) %></strong></p>
|
|
53
|
-
|
|
54
|
-
<%= f.submit "Save draft", class: "hrl-btn hrl-btn--primary" %>
|
|
55
|
-
</div>
|
|
56
|
-
</section>
|
|
57
|
-
<% end %>
|
|
59
|
+
</details>
|
|
58
60
|
|
|
59
|
-
<% if
|
|
60
|
-
<section class="hrl-card">
|
|
61
|
+
<% if submittable %>
|
|
61
62
|
<p class="hrl-muted hrl-small">
|
|
62
63
|
Submitting locks it for HR to check. They can send it back if the proof
|
|
63
64
|
does not match.
|
|
64
65
|
</p>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
<% end %>
|
|
67
|
+
<div class="hrl-form-actions">
|
|
68
|
+
<%= f.submit "Save draft", class: submittable ? "hrl-btn" : "hrl-btn hrl-btn--primary" %>
|
|
69
|
+
<% if submittable %>
|
|
70
|
+
<button type="submit" name="submit_to_hr" value="1" class="hrl-btn hrl-btn--primary">Submit to HR</button>
|
|
71
|
+
<% end %>
|
|
72
|
+
</div>
|
|
68
73
|
<% end %>
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
<span class="hrl-small hrl-muted"> · <%= row.profile.designation %></span><% end %></span>
|
|
34
34
|
</td>
|
|
35
35
|
<td data-label="Status"><%= hrl_team_status(row) %></td>
|
|
36
|
-
<td data-label="Hours" class="hrl-num"><%= hrl_duration(row.day_seconds) %></td>
|
|
36
|
+
<td data-label="Hours <%= @date == Date.current ? "today" : "that day" %>" class="hrl-num"><%= hrl_duration(row.day_seconds) %></td>
|
|
37
37
|
<td data-label="Hours this month" class="hrl-num"><%= hrl_duration(row.month_seconds) %></td>
|
|
38
38
|
</tr>
|
|
39
39
|
<% end %>
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
<p class="hrl-card--empty">Nobody to show for this date.</p>
|
|
45
45
|
<% end %>
|
|
46
46
|
<p class="hrl-small hrl-muted hrl-mt">Forgot a punch yourself?
|
|
47
|
-
<a href="<%= hr_lite.new_regularization_request_path %>">Raise a regularization ticket</a
|
|
47
|
+
<a class="hrl-card__link" href="<%= hr_lite.new_regularization_request_path %>">Raise a regularization ticket</a></p>
|
|
48
48
|
</section>
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
<% end %>
|
|
14
14
|
</head>
|
|
15
15
|
<body class="hrl-body">
|
|
16
|
+
<a class="hrl-skip" href="#hrl-main">Skip to content</a>
|
|
16
17
|
<div class="hrl-shell">
|
|
17
18
|
<%# Keka-style left rail on desktop; slides away on phones (tabbar takes over). %>
|
|
18
19
|
<aside class="hrl-side" aria-label="HR navigation">
|
|
@@ -25,9 +26,11 @@
|
|
|
25
26
|
</a>
|
|
26
27
|
|
|
27
28
|
<nav class="hrl-side__nav">
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
<% hrl_nav_items(HrLite::ApplicationHelper::NAV_ITEMS).chunk { |item| item[:group] }.each do |group, items| %>
|
|
30
|
+
<span class="hrl-side__group"><%= group %></span>
|
|
31
|
+
<% items.each do |item| %>
|
|
32
|
+
<%= hrl_nav_link(item) %>
|
|
33
|
+
<% end %>
|
|
31
34
|
<% end %>
|
|
32
35
|
|
|
33
36
|
<% if hr_admin? || hr_leadership? || hr_can?("expense.approve", scope: :team) %>
|
|
@@ -73,10 +76,15 @@
|
|
|
73
76
|
<% end %>
|
|
74
77
|
</a>
|
|
75
78
|
<%= render "hr_lite/shared/bell" %>
|
|
76
|
-
|
|
79
|
+
<% profile = hr_lite.employee_profile_path if hr_lite_route?(:employee_profile_path) %>
|
|
80
|
+
<%= tag.a hr_display_name(hr_current_user), href: profile, class: "hrl-appbar__user" %>
|
|
77
81
|
</header>
|
|
78
82
|
|
|
79
|
-
<main class="hrl-main">
|
|
83
|
+
<main class="hrl-main" id="hrl-main" tabindex="-1">
|
|
84
|
+
<%# A sub-screen names its parent tab: content_for(:back, "Leaves"). %>
|
|
85
|
+
<% if (tab = HrLite::ApplicationHelper::NAV_ITEMS.find { |i| i[:label] == content_for(:back) }) %>
|
|
86
|
+
<a class="hrl-backlink" href="<%= hr_lite.public_send(tab[:path]) %>"><span aria-hidden="true">‹</span> <%= tab[:label] %></a>
|
|
87
|
+
<% end %>
|
|
80
88
|
<% if flash[:notice].present? %><div class="hrl-flash hrl-flash--ok" role="status"><%= flash[:notice] %></div><% end %>
|
|
81
89
|
<% if flash[:alert].present? %><div class="hrl-flash hrl-flash--warn" role="alert"><%= flash[:alert] %></div><% end %>
|
|
82
90
|
<%= yield %>
|
|
@@ -95,10 +103,17 @@
|
|
|
95
103
|
<%= hrl_nav_link(item) %>
|
|
96
104
|
<% end %>
|
|
97
105
|
<details class="hrl-tabbar__more">
|
|
98
|
-
|
|
106
|
+
<% lit = rest.any? { |i| hrl_nav_active?(i) } || request.path.include?("/admin/") %>
|
|
107
|
+
<%= tag.summary "More", class: [ "hrl-nav__link", ("hrl-nav__link--active" if lit) ], aria: { current: ("true" if lit) } %>
|
|
99
108
|
<div class="hrl-sheet">
|
|
100
|
-
<%
|
|
101
|
-
<%=
|
|
109
|
+
<% if HrLite.config.back_link %>
|
|
110
|
+
<a class="hrl-nav__link hrl-side__back" href="<%= HrLite.config.back_link[:url] %>"><%= HrLite.config.back_link[:label] %></a>
|
|
111
|
+
<% end %>
|
|
112
|
+
<% rest.chunk { |item| item[:group] }.each do |group, items| %>
|
|
113
|
+
<span class="hrl-side__group"><%= group %></span>
|
|
114
|
+
<% items.each do |item| %>
|
|
115
|
+
<%= hrl_nav_link(item) %>
|
|
116
|
+
<% end %>
|
|
102
117
|
<% end %>
|
|
103
118
|
<% if hr_admin? || hr_leadership? || hr_can?("expense.approve", scope: :team) %>
|
|
104
119
|
<span class="hrl-side__group">Manage</span>
|
|
@@ -126,6 +141,7 @@
|
|
|
126
141
|
<%= javascript_include_tag "hr_lite/confirm", defer: true %>
|
|
127
142
|
<%= javascript_include_tag "hr_lite/mention", defer: true %>
|
|
128
143
|
<%= javascript_include_tag "hr_lite/nav", defer: true %>
|
|
144
|
+
<%= javascript_include_tag "hr_lite/select_filter", defer: true %>
|
|
129
145
|
<%= yield :scripts %>
|
|
130
146
|
</body>
|
|
131
147
|
</html>
|
data/config/routes.rb
CHANGED
|
@@ -54,7 +54,9 @@ HrLite::Engine.routes.draw do
|
|
|
54
54
|
namespace :admin do
|
|
55
55
|
resources :policies, only: %i[index new create]
|
|
56
56
|
get "overview", to: "overview#index"
|
|
57
|
-
resources :attendances, only: %i[index show update], param: :user_id
|
|
57
|
+
resources :attendances, only: %i[index show update], param: :user_id do
|
|
58
|
+
collection { get :week }
|
|
59
|
+
end
|
|
58
60
|
resources :leave_requests, only: %i[index show new create] do
|
|
59
61
|
member { post :approve; post :reject; post :cancel }
|
|
60
62
|
end
|