hr_lite 0.53.0 → 0.55.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 +73 -0
- data/README.md +5 -2
- data/app/assets/javascripts/hr_lite/confirm.js +9 -5
- data/app/assets/javascripts/hr_lite/countdown.js +9 -2
- data/app/assets/javascripts/hr_lite/emoji_pick.js +4 -4
- data/app/assets/javascripts/hr_lite/search.js +1 -1
- data/app/assets/stylesheets/hr_lite/hr_lite.css +24 -14
- data/app/controllers/hr_lite/admin/attendances_controller.rb +12 -3
- data/app/controllers/hr_lite/admin/audit_logs_controller.rb +1 -0
- data/app/controllers/hr_lite/admin/comp_off_requests_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/documents_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/employees_controller.rb +11 -4
- data/app/controllers/hr_lite/admin/expenses_controller.rb +17 -1
- data/app/controllers/hr_lite/admin/hr_requests_controller.rb +4 -0
- data/app/controllers/hr_lite/admin/leave_requests_controller.rb +5 -2
- data/app/controllers/hr_lite/admin/payroll_runs_controller.rb +9 -5
- data/app/controllers/hr_lite/admin/regularization_requests_controller.rb +1 -1
- data/app/controllers/hr_lite/admin/reports_controller.rb +3 -2
- data/app/controllers/hr_lite/admin/salary_structures_controller.rb +2 -0
- data/app/controllers/hr_lite/admin/statutory_rate_cards_controller.rb +2 -1
- data/app/controllers/hr_lite/admin/tax_declarations_controller.rb +15 -4
- data/app/controllers/hr_lite/admin/work_locations_controller.rb +1 -1
- data/app/controllers/hr_lite/approvals_controller.rb +1 -0
- data/app/controllers/hr_lite/home_controller.rb +2 -11
- data/app/controllers/hr_lite/loans_controller.rb +1 -1
- data/app/controllers/hr_lite/regularization_requests_controller.rb +4 -4
- data/app/controllers/hr_lite/tax_declarations_controller.rb +9 -5
- data/app/helpers/hr_lite/application_helper.rb +34 -9
- data/app/jobs/hr_lite/attendance_close_job.rb +1 -1
- data/app/jobs/hr_lite/payroll_compute_job.rb +12 -0
- data/app/models/concerns/hr_lite/audited.rb +3 -1
- data/app/models/concerns/hr_lite/encrypted_money.rb +8 -5
- data/app/models/hr_lite/attendance_record.rb +21 -4
- data/app/models/hr_lite/comp_off_request.rb +2 -0
- data/app/models/hr_lite/document.rb +1 -1
- data/app/models/hr_lite/expense.rb +3 -0
- data/app/models/hr_lite/hr_request.rb +2 -0
- data/app/models/hr_lite/kudo.rb +2 -2
- data/app/models/hr_lite/leave_request.rb +25 -6
- data/app/models/hr_lite/payroll_line_item.rb +8 -0
- data/app/models/hr_lite/payroll_run.rb +15 -6
- data/app/models/hr_lite/regularization_request.rb +2 -2
- data/app/models/hr_lite/resignation.rb +5 -1
- data/app/models/hr_lite/role.rb +5 -0
- data/app/models/hr_lite/salary_slip.rb +2 -1
- data/app/models/hr_lite/statutory_rate_card_record.rb +6 -0
- data/app/models/hr_lite/tax_declaration.rb +5 -0
- data/app/services/hr_lite/attendance_puncher.rb +4 -0
- data/app/services/hr_lite/overview_query.rb +0 -12
- data/app/services/hr_lite/work_status.rb +5 -2
- data/app/views/hr_lite/admin/assets/index.html.erb +9 -2
- data/app/views/hr_lite/admin/attendances/index.html.erb +4 -4
- data/app/views/hr_lite/admin/attendances/show.html.erb +4 -2
- data/app/views/hr_lite/admin/attendances/summary.html.erb +5 -2
- data/app/views/hr_lite/admin/audit_logs/index.html.erb +6 -4
- data/app/views/hr_lite/admin/benefits/index.html.erb +10 -4
- data/app/views/hr_lite/admin/ca_reviews/index.html.erb +3 -3
- data/app/views/hr_lite/admin/checklists/index.html.erb +3 -3
- data/app/views/hr_lite/admin/comp_off_requests/index.html.erb +1 -2
- data/app/views/hr_lite/admin/comp_off_requests/show.html.erb +6 -6
- data/app/views/hr_lite/admin/designation_changes/new.html.erb +4 -3
- data/app/views/hr_lite/admin/documents/index.html.erb +9 -4
- data/app/views/hr_lite/admin/documents/show.html.erb +1 -0
- data/app/views/hr_lite/admin/employees/_form.html.erb +12 -5
- data/app/views/hr_lite/admin/employees/show.html.erb +40 -33
- data/app/views/hr_lite/admin/expense_categories/index.html.erb +1 -1
- data/app/views/hr_lite/admin/expenses/index.html.erb +7 -4
- data/app/views/hr_lite/admin/holidays/index.html.erb +7 -5
- data/app/views/hr_lite/admin/hr_requests/index.html.erb +3 -3
- data/app/views/hr_lite/admin/hr_requests/show.html.erb +5 -4
- data/app/views/hr_lite/admin/leave_balances/index.html.erb +6 -4
- data/app/views/hr_lite/admin/leave_requests/index.html.erb +1 -2
- data/app/views/hr_lite/admin/leave_requests/show.html.erb +6 -4
- data/app/views/hr_lite/admin/leave_types/edit.html.erb +4 -4
- data/app/views/hr_lite/admin/leave_types/index.html.erb +5 -5
- data/app/views/hr_lite/admin/loans/index.html.erb +1 -1
- data/app/views/hr_lite/admin/loans/new.html.erb +1 -1
- data/app/views/hr_lite/admin/loans/show.html.erb +8 -12
- data/app/views/hr_lite/admin/office_locations/edit.html.erb +4 -4
- data/app/views/hr_lite/admin/office_locations/index.html.erb +1 -1
- data/app/views/hr_lite/admin/overview/index.html.erb +10 -31
- data/app/views/hr_lite/admin/payroll_line_items/new.html.erb +2 -1
- data/app/views/hr_lite/admin/payroll_runs/index.html.erb +3 -3
- data/app/views/hr_lite/admin/payroll_runs/show.html.erb +15 -10
- data/app/views/hr_lite/admin/performance_plans/_form.html.erb +2 -1
- data/app/views/hr_lite/admin/policies/index.html.erb +2 -2
- data/app/views/hr_lite/admin/policies/new.html.erb +4 -3
- data/app/views/hr_lite/admin/regularization_requests/index.html.erb +3 -4
- data/app/views/hr_lite/admin/regularization_requests/show.html.erb +5 -6
- data/app/views/hr_lite/admin/reports/index.html.erb +3 -6
- data/app/views/hr_lite/admin/reports/show.html.erb +16 -2
- data/app/views/hr_lite/admin/roles/_form.html.erb +8 -6
- data/app/views/hr_lite/admin/roles/edit.html.erb +4 -2
- data/app/views/hr_lite/admin/roles/index.html.erb +1 -1
- data/app/views/hr_lite/admin/salary_slips/show.html.erb +3 -2
- data/app/views/hr_lite/admin/salary_structures/_form.html.erb +1 -0
- data/app/views/hr_lite/admin/settings/edit.html.erb +5 -1
- data/app/views/hr_lite/admin/statutory_rate_cards/_form.html.erb +14 -10
- data/app/views/hr_lite/admin/statutory_rate_cards/index.html.erb +3 -1
- data/app/views/hr_lite/admin/tax_declarations/index.html.erb +1 -1
- data/app/views/hr_lite/admin/tax_declarations/show.html.erb +8 -4
- data/app/views/hr_lite/admin/wfh_requests/index.html.erb +17 -16
- data/app/views/hr_lite/admin/wfh_requests/show.html.erb +3 -5
- data/app/views/hr_lite/admin/work_locations/index.html.erb +1 -1
- data/app/views/hr_lite/admin/work_modes/index.html.erb +1 -1
- data/app/views/hr_lite/approvals/index.html.erb +5 -4
- data/app/views/hr_lite/attendance/_custom_status.html.erb +7 -9
- data/app/views/hr_lite/attendance/_month_grid.html.erb +9 -9
- data/app/views/hr_lite/attendance/_penalties.html.erb +2 -2
- data/app/views/hr_lite/attendance/_punch_card.html.erb +10 -4
- data/app/views/hr_lite/attendance/_slot.html.erb +9 -6
- data/app/views/hr_lite/attendance/_trail.html.erb +1 -1
- data/app/views/hr_lite/attendance/_work_mode.html.erb +1 -1
- data/app/views/hr_lite/attendance/show.html.erb +7 -5
- data/app/views/hr_lite/calendar/show.html.erb +2 -2
- data/app/views/hr_lite/comp_off_requests/index.html.erb +1 -1
- data/app/views/hr_lite/comp_off_requests/new.html.erb +1 -1
- data/app/views/hr_lite/documents/_upload_form.html.erb +1 -1
- data/app/views/hr_lite/employee_profiles/show.html.erb +4 -2
- data/app/views/hr_lite/home/index.html.erb +6 -5
- data/app/views/hr_lite/id_cards/show.html.erb +5 -1
- data/app/views/hr_lite/leave_requests/_balance_chips.html.erb +3 -2
- data/app/views/hr_lite/leave_requests/new.html.erb +17 -8
- data/app/views/hr_lite/leave_requests/show.html.erb +2 -0
- data/app/views/hr_lite/loans/index.html.erb +1 -1
- data/app/views/hr_lite/org/show.html.erb +1 -1
- data/app/views/hr_lite/regularization_requests/index.html.erb +7 -7
- data/app/views/hr_lite/regularization_requests/new.html.erb +7 -5
- data/app/views/hr_lite/resignations/show.html.erb +2 -1
- data/app/views/hr_lite/salary_slips/_slip_detail.html.erb +7 -7
- data/app/views/hr_lite/salary_slips/pdf.html.erb +2 -1
- data/app/views/hr_lite/tax/_computation.html.erb +1 -1
- data/app/views/hr_lite/tax_declarations/show.html.erb +4 -4
- data/app/views/hr_lite/team/show.html.erb +8 -7
- data/app/views/hr_lite/timelines/show.html.erb +1 -0
- data/app/views/hr_lite/wfh_requests/index.html.erb +3 -3
- data/app/views/hr_lite/work_time/_bars.html.erb +5 -4
- data/app/views/hr_lite/work_time/_donut.html.erb +1 -1
- data/app/views/hr_lite/work_time/_report.html.erb +14 -8
- data/app/views/layouts/hr_lite/application.html.erb +1 -0
- data/app/views/layouts/hr_lite/mailer.html.erb +10 -2
- data/app/views/layouts/hr_lite/mailer.text.erb +4 -1
- data/config/routes.rb +1 -1
- data/lib/hr_lite/amount_in_words.rb +7 -5
- data/lib/hr_lite/notifications.rb +5 -2
- data/lib/hr_lite/statutory_seeds.rb +1 -1
- data/lib/hr_lite/version.rb +1 -1
- metadata +2 -1
|
@@ -135,7 +135,7 @@ module HrLite
|
|
|
135
135
|
transition!("cancelled", actor, nil)
|
|
136
136
|
Notifications.publish(
|
|
137
137
|
"regularization.cancelled",
|
|
138
|
-
title: "#{HrLite.display_name(user)} cancelled a
|
|
138
|
+
title: "#{HrLite.display_name(user)} cancelled a day fix request (#{date.strftime('%d %b')})",
|
|
139
139
|
path: "/admin/regularization_requests",
|
|
140
140
|
bell_to: HrLite.admin_users
|
|
141
141
|
)
|
|
@@ -220,7 +220,7 @@ module HrLite
|
|
|
220
220
|
def notify_requested
|
|
221
221
|
Notifications.publish(
|
|
222
222
|
"regularization.requested",
|
|
223
|
-
title: "#{HrLite.display_name(user)}
|
|
223
|
+
title: "#{HrLite.display_name(user)} asked to fix #{date.strftime('%d %b')} " \
|
|
224
224
|
"(#{times_label})",
|
|
225
225
|
body: reason.presence,
|
|
226
226
|
path: "/admin/regularization_requests/#{id}",
|
|
@@ -20,6 +20,7 @@ module HrLite
|
|
|
20
20
|
STATUSES.each { |s| define_method("#{s}?") { status == s } }
|
|
21
21
|
|
|
22
22
|
after_create :notify_submitted
|
|
23
|
+
after_create { audit!("submitted", user) }
|
|
23
24
|
|
|
24
25
|
def accept!(actor:, last_day: nil, note: nil)
|
|
25
26
|
raise ActiveRecord::RecordInvalid.new(self), "not pending" unless pending?
|
|
@@ -34,6 +35,7 @@ module HrLite
|
|
|
34
35
|
# nothing was stamped, because the screen used to claim it was.
|
|
35
36
|
@exit_date_recorded = profile.present?
|
|
36
37
|
profile&.update!(date_of_exit: final_day)
|
|
38
|
+
audit!("accepted", actor)
|
|
37
39
|
end
|
|
38
40
|
|
|
39
41
|
# Notice periods are the normal case, so access is revoked here only
|
|
@@ -55,7 +57,7 @@ module HrLite
|
|
|
55
57
|
def withdraw!(actor:)
|
|
56
58
|
raise ActiveRecord::RecordInvalid.new(self), "not pending" unless pending? && actor.id == user_id
|
|
57
59
|
|
|
58
|
-
update!(status: "withdrawn", decided_at: Time.current)
|
|
60
|
+
transaction { update!(status: "withdrawn", decided_at: Time.current) && audit!("withdrawn", actor) }
|
|
59
61
|
Notifications.publish(
|
|
60
62
|
"resignation.withdrawn",
|
|
61
63
|
title: "#{HrLite.display_name(user)} withdrew their resignation",
|
|
@@ -72,6 +74,8 @@ module HrLite
|
|
|
72
74
|
|
|
73
75
|
private
|
|
74
76
|
|
|
77
|
+
def audit!(action, actor) = AuditLog.record!(action: "resignation.#{action}", subject: self, actor: actor, changes: { "last_day" => proposed_last_day.to_s })
|
|
78
|
+
|
|
75
79
|
# Best-effort, like every other call of this hook: a host that cannot
|
|
76
80
|
# revoke must not roll back an accepted resignation.
|
|
77
81
|
def revoke_access!
|
data/app/models/hr_lite/role.rb
CHANGED
|
@@ -36,12 +36,17 @@ module HrLite
|
|
|
36
36
|
# permission being taken away, not one left alone.
|
|
37
37
|
def replace_grants!(grants)
|
|
38
38
|
transaction do
|
|
39
|
+
before = grant_map
|
|
39
40
|
role_grants.destroy_all
|
|
40
41
|
grants.each do |key, scope|
|
|
41
42
|
next if scope.blank? || scope.to_s == "none"
|
|
42
43
|
|
|
43
44
|
role_grants.create!(permission_key: Permissions.validate!(key), scope: scope.to_s)
|
|
44
45
|
end
|
|
46
|
+
role_grants.reload
|
|
47
|
+
after = grant_map
|
|
48
|
+
changed = (before.keys | after.keys).reject { |key| before[key] == after[key] }
|
|
49
|
+
AuditLog.record!(action: "role.grants_changed", subject: self, changes: changed.to_h { |key| [ key, [ before[key], after[key] ] ] }) if changed.any?
|
|
45
50
|
end
|
|
46
51
|
reload
|
|
47
52
|
end
|
|
@@ -61,8 +61,9 @@ module HrLite
|
|
|
61
61
|
row ? Money.d(row["amount"]) : BigDecimal(0)
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
# Bump the version when the PDF template changes, or the old layout serves until the cache expires.
|
|
64
65
|
def pdf_cache_key
|
|
65
|
-
[ "
|
|
66
|
+
[ "hr_lite_slip_v3", id, updated_at.to_i, payroll_run.status,
|
|
66
67
|
user_profile&.updated_at.to_i ].join("/")
|
|
67
68
|
end
|
|
68
69
|
|
|
@@ -7,6 +7,9 @@ module HrLite
|
|
|
7
7
|
|
|
8
8
|
self.table_name = "hr_lite_statutory_rate_cards"
|
|
9
9
|
|
|
10
|
+
# Shipped cards count as verified so payroll can auto-approve, but no person checked them.
|
|
11
|
+
SHIPPED_SIGN_OFF = "Shipped defaults, not checked by a person".freeze
|
|
12
|
+
|
|
10
13
|
validates :effective_from, presence: true, uniqueness: true
|
|
11
14
|
validate :effective_from_opens_a_financial_year
|
|
12
15
|
validate :carries_every_figure_payroll_reads
|
|
@@ -22,6 +25,9 @@ module HrLite
|
|
|
22
25
|
|
|
23
26
|
def verified? = verified_by.present? && verified_on.present?
|
|
24
27
|
|
|
28
|
+
# Cards seeded before this read "hr_lite 0.52.0 (official source …)": a version is not a sign-off.
|
|
29
|
+
def verified_by = super&.start_with?("hr_lite ") ? SHIPPED_SIGN_OFF : super
|
|
30
|
+
|
|
25
31
|
# The shape SlipBuilder and the calculators expect: symbol keys and
|
|
26
32
|
# BigDecimal everywhere, because JSON gives back strings and floats and
|
|
27
33
|
# a float has no business in a PF calculation.
|
|
@@ -86,6 +86,11 @@ module HrLite
|
|
|
86
86
|
|
|
87
87
|
def verify!(actor:, note: nil)
|
|
88
88
|
raise ActiveRecord::RecordInvalid.new(self), "not submitted" unless submitted?
|
|
89
|
+
# A blank verified amount would count as ₹0 allowed once verified.
|
|
90
|
+
if tax_declaration_items.any? { |item| item.verified_amount.nil? }
|
|
91
|
+
errors.add(:base, "Every line needs a verified amount — enter 0 where the proof supports nothing")
|
|
92
|
+
raise ActiveRecord::RecordInvalid, self
|
|
93
|
+
end
|
|
89
94
|
|
|
90
95
|
update!(status: "verified", verified_by_id: actor.id, verified_at: Time.current,
|
|
91
96
|
note: note.presence)
|
|
@@ -247,6 +247,10 @@ module HrLite
|
|
|
247
247
|
# Late ladder against slot + buffer; after 11:00 also +1h on the next two
|
|
248
248
|
# working days; after 11:30 the day is a half day. The buffer shifts all three.
|
|
249
249
|
def apply_slot_rules(record)
|
|
250
|
+
# No slot to be late for on a weekly off, a holiday, or leave that starts the day (full or first half).
|
|
251
|
+
return unless WorkingCalendar.for_user(@user.id, record.date..record.date).working_day?(record.date)
|
|
252
|
+
return if LeaveRequest.active_on(record.date).where(user_id: @user.id, half_day_part: [ nil, "", "first" ]).exists?
|
|
253
|
+
|
|
250
254
|
local = record.check_in_at.in_time_zone(HrLite.config.time_zone)
|
|
251
255
|
arrived = local.hour * 60 + local.min - EmployeeProfile.where(user_id: @user.id).pick(:buffer_minutes).to_i
|
|
252
256
|
late = AttendanceSlot.penalty_minutes(arrived - AttendanceSlot.start_minute_for(@user.id, record.date))
|
|
@@ -17,17 +17,6 @@ module HrLite
|
|
|
17
17
|
reach(LeaveRequest.active_on(@date).includes(:leave_type, :user).order(:start_date))
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
# Comp-off and regularization are approvals too. Counting leave alone made
|
|
21
|
-
# the board announce "All present and accounted for" while both queues
|
|
22
|
-
# still had work in them.
|
|
23
|
-
def pending_comp_offs
|
|
24
|
-
reach(CompOffRequest.pending.includes(:user).recent_first)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def pending_regularizations
|
|
28
|
-
reach(RegularizationRequest.pending.includes(:user).recent_first)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
20
|
def flagged_today
|
|
32
21
|
reach(AttendanceRecord.for_date(@date).flagged.includes(:user))
|
|
33
22
|
end
|
|
@@ -41,7 +30,6 @@ module HrLite
|
|
|
41
30
|
|
|
42
31
|
def kpis
|
|
43
32
|
{
|
|
44
|
-
pending: pending_requests.count + pending_comp_offs.count + pending_regularizations.count,
|
|
45
33
|
on_leave: on_leave_today.count,
|
|
46
34
|
flagged: flagged_today.count,
|
|
47
35
|
missing_checkout: missing_checkout_yesterday.count
|
|
@@ -16,8 +16,11 @@ module HrLite
|
|
|
16
16
|
def self.for(user_id, at: Time.current) = for_users([ user_id ], at: at)[user_id]
|
|
17
17
|
|
|
18
18
|
# When an open Busy or Meeting ends, or nil when the person is reachable.
|
|
19
|
-
def self.do_not_disturb_until(user_id, at: Time.current)
|
|
20
|
-
|
|
19
|
+
def self.do_not_disturb_until(user_id, at: Time.current) = do_not_disturb_for([ user_id ], at: at)[user_id]
|
|
20
|
+
|
|
21
|
+
# The same for many people in one query: { user_id => ends_at }, reachable people absent.
|
|
22
|
+
def self.do_not_disturb_for(user_ids, at: Time.current)
|
|
23
|
+
WorkModeEvent.open.overlay.where(user_id: user_ids, mode: %w[busy meeting]).where("ends_at > ?", at).group(:user_id).maximum(:ends_at)
|
|
21
24
|
end
|
|
22
25
|
|
|
23
26
|
def self.for_users(user_ids, at: Time.current)
|
|
@@ -22,6 +22,9 @@
|
|
|
22
22
|
<% end %>
|
|
23
23
|
|
|
24
24
|
<section class="hrl-card">
|
|
25
|
+
<% if @assets.empty? %>
|
|
26
|
+
<p class="hrl-muted">No assets recorded yet. Add the first one above.</p>
|
|
27
|
+
<% else %>
|
|
25
28
|
<div class="hrl-table-wrap">
|
|
26
29
|
<table class="hrl-table hrl-table--stack">
|
|
27
30
|
<thead><tr><th>Asset</th><th>Status</th><th>With</th><th></th></tr></thead>
|
|
@@ -39,13 +42,16 @@
|
|
|
39
42
|
<td data-label="">
|
|
40
43
|
<% if asset.assigned? %>
|
|
41
44
|
<%= form_with url: hr_lite.take_back_admin_asset_path(asset), method: :post do %>
|
|
42
|
-
<%=
|
|
45
|
+
<%= label_tag "asset-condition-#{asset.id}", "Condition on return", class: "hrl-sr-only" %>
|
|
46
|
+
<%= text_field_tag :condition_note, nil, id: "asset-condition-#{asset.id}", placeholder: "Condition on return", class: "hrl-input" %>
|
|
43
47
|
<%= submit_tag "Take back", class: "hrl-btn" %>
|
|
44
48
|
<% end %>
|
|
45
49
|
<% elsif asset.available? %>
|
|
46
50
|
<%= form_with url: hr_lite.assign_admin_asset_path(asset), method: :post do %>
|
|
51
|
+
<%= label_tag "asset-holder-#{asset.id}", "Hand over to", class: "hrl-sr-only" %>
|
|
47
52
|
<%= select_tag :user_id,
|
|
48
|
-
options_for_select(HrLite.employees.map { |u| [ hr_display_name(u), u.id ] }),
|
|
53
|
+
options_for_select(HrLite.employees.map { |u| [ hr_display_name(u), u.id ] }), id: "asset-holder-#{asset.id}",
|
|
54
|
+
include_blank: "Choose…", required: true, class: "hrl-input",
|
|
49
55
|
data: { hrl_filter: "Type a name to filter" } %>
|
|
50
56
|
<%= submit_tag "Hand over", class: "hrl-btn" %>
|
|
51
57
|
<% end %>
|
|
@@ -56,5 +62,6 @@
|
|
|
56
62
|
</tbody>
|
|
57
63
|
</table>
|
|
58
64
|
</div>
|
|
65
|
+
<% end %>
|
|
59
66
|
<%= hrl_pagination %>
|
|
60
67
|
</section>
|
|
@@ -15,10 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
<div class="hrl-kpis">
|
|
17
17
|
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= @records.values.count { |r| r.check_in_at } %></div><div class="hrl-kpi__label">Checked in</div></div>
|
|
18
|
-
<%#
|
|
19
|
-
|
|
20
|
-
quietly stopped adding up to the headcount. %>
|
|
21
|
-
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= @employees.size - @records.values.count { |r| r.check_in_at } %></div><div class="hrl-kpi__label">No punch</div></div>
|
|
18
|
+
<%# Expected in and not checked in: people on leave, a holiday or a weekly off are not counted. %>
|
|
19
|
+
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= @employees.count { |u| @days[u.id]&.kind == :absent } %></div><div class="hrl-kpi__label">No punch</div></div>
|
|
22
20
|
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= @flagged_count %></div><div class="hrl-kpi__label">Flagged</div></div>
|
|
23
21
|
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= @records.values.count { |r| r.check_in_at && r.check_out_at.nil? } %></div><div class="hrl-kpi__label">Still in</div></div>
|
|
24
22
|
</div>
|
|
@@ -71,6 +69,8 @@
|
|
|
71
69
|
<span class="hrl-badge hrl-badge--bad">Flagged</span> <span class="hrl-small"><%= record.flag_note %></span>
|
|
72
70
|
<% elsif record&.check_in_at %>
|
|
73
71
|
<span class="hrl-badge hrl-badge--ok"><%= record.status.humanize %><%= " (#{record.half_day_part} half)" if record.half_day_part %></span>
|
|
72
|
+
<% elsif @days[employee.id] %>
|
|
73
|
+
<%= hrl_team_status(@days[employee.id]) %>
|
|
74
74
|
<% else %>
|
|
75
75
|
<span class="hrl-badge hrl-badge--muted">No punch</span>
|
|
76
76
|
<% end %>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<% content_for(:page_title) { "Attendance — #{hr_display_name(@employee)}" } %>
|
|
2
2
|
<% content_for(:tabrow) { render "hr_lite/shared/person_tabs", user: @employee } %>
|
|
3
|
+
<% content_for(:back, "Team") %>
|
|
3
4
|
<div class="hrl-page__head">
|
|
4
5
|
<h1 class="hrl-page__title"><%= hr_display_name(@employee) %></h1>
|
|
5
6
|
<div class="hrl-page__actions">
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
<% if @punches.any? %>
|
|
34
35
|
<section class="hrl-card">
|
|
35
36
|
<h2 class="hrl-card__title">Where they punched</h2>
|
|
37
|
+
<% all_punches = HrLite::AttendancePunch.where(user_id: @employee.id, date: @punches.map(&:date)).order(:at, :id).group_by(&:date) # one query, not one a day %>
|
|
36
38
|
<% @punches.each do |record| %>
|
|
37
39
|
<div class="hrl-feed__item hrl-small">
|
|
38
40
|
<div class="hrl-feed__body">
|
|
@@ -47,7 +49,7 @@
|
|
|
47
49
|
<% end %>
|
|
48
50
|
</div>
|
|
49
51
|
<% end %>
|
|
50
|
-
<% if record.check_in_place %><%= render "hr_lite/attendance/trail", record: record %><% end %>
|
|
52
|
+
<% if record.check_in_place %><%= render "hr_lite/attendance/trail", record: record, punches: all_punches.fetch(record.date, []) %><% end %>
|
|
51
53
|
<% if (gap = record.punch_gap_m) %>
|
|
52
54
|
<div class="<%= gap > HrLite::AttendanceRecord::PUNCH_GAP_ALERT_M ? "hrl-badge hrl-badge--warn" : "hrl-muted" %>"><%= (gap / 1000.0).round(1) %> km apart</div>
|
|
53
55
|
<% end %>
|
|
@@ -80,7 +82,7 @@
|
|
|
80
82
|
</div>
|
|
81
83
|
<div class="hrl-field">
|
|
82
84
|
<%= f.label :regularization_note, "Why is this being fixed? (required)" %>
|
|
83
|
-
<%= f.text_area :regularization_note %>
|
|
85
|
+
<%= f.text_area :regularization_note, required: true %>
|
|
84
86
|
</div>
|
|
85
87
|
<div class="hrl-form-actions">
|
|
86
88
|
<%= f.submit "Save fix", class: "hrl-btn hrl-btn--primary" %>
|
|
@@ -25,14 +25,17 @@
|
|
|
25
25
|
<% end %>
|
|
26
26
|
</section>
|
|
27
27
|
|
|
28
|
+
<% fixes_pending = HrLite::RegularizationRequest.pending.where(user_id: @employee.id, date: @period.from..@period.to).pluck(:date) %>
|
|
28
29
|
<section class="hrl-card">
|
|
29
30
|
<h2 class="hrl-card__title">Days</h2>
|
|
30
31
|
<% (@period.from..@period.to).each do |date| %>
|
|
31
|
-
<% day = @days.for(date); rec = day.record; punches = @punches[date].to_a
|
|
32
|
+
<% day = @days.for(date); rec = day.record; punches = @punches[date].to_a
|
|
33
|
+
not_in_yet = date == Date.current && day.kind == :absent # the day is not over %>
|
|
32
34
|
<div class="hrl-feed__item hrl-row">
|
|
33
35
|
<div class="hrl-feed__body hrl-small">
|
|
34
36
|
<strong><%= date.strftime("%a %-d %b") %></strong>
|
|
35
|
-
<span class="hrl-badge <%= tones[day.kind] %>"><%= HrLite::ApplicationHelper::DAY_STATES[day.kind][1] %></span>
|
|
37
|
+
<span class="hrl-badge <%= not_in_yet ? "hrl-badge--muted" : tones[day.kind] %>"><%= not_in_yet ? "Not in yet" : HrLite::ApplicationHelper::DAY_STATES[day.kind][1] %></span>
|
|
38
|
+
<% if fixes_pending.include?(date) %><span class="hrl-badge hrl-badge--warn">Fix pending</span><% end %>
|
|
36
39
|
<% if @profile&.hours_allowance_minutes && (length = HrLite::EmployeeProfile.day_minutes_for(@employee.id, on: date)) < HrLite::Setting.instance.day_minutes %>
|
|
37
40
|
<span class="hrl-badge hrl-badge--muted">Day <%= hrl_duration(length * 60) %></span>
|
|
38
41
|
<% end %>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Audit trail" } %>
|
|
1
2
|
<div class="hrl-page__head">
|
|
2
3
|
<h1 class="hrl-page__title">Audit trail</h1>
|
|
3
|
-
<p class="hrl-page__sub">Every policy, settings and payroll change — append-only
|
|
4
|
+
<p class="hrl-page__sub">Every policy, settings and payroll change — append-only.
|
|
5
|
+
<% if params[:views] %><a href="<%= hr_lite.admin_audit_logs_path %>">Hide page views</a><% else %><a href="<%= hr_lite.admin_audit_logs_path(views: 1) %>">Show page views too</a><% end %></p>
|
|
4
6
|
</div>
|
|
5
7
|
|
|
6
8
|
<% if @audit_logs.any? %>
|
|
@@ -13,15 +15,15 @@
|
|
|
13
15
|
<% @audit_logs.each do |log| %>
|
|
14
16
|
<tr>
|
|
15
17
|
<td data-label="When"><%= log.created_at.strftime("%d %b %Y, %H:%M") %></td>
|
|
16
|
-
<td data-label="Who"><%= hr_display_name(log.actor) %></td>
|
|
17
|
-
<td data-label="Action"><span class="hrl-badge hrl-badge--muted"><%= log.action %></span></td>
|
|
18
|
+
<td data-label="Who"><%= log.actor ? hr_display_name(log.actor) : "System" %></td>
|
|
19
|
+
<td data-label="Action"><span class="hrl-badge hrl-badge--muted"><%= log.action.tr("._", " ").humanize %></span></td>
|
|
18
20
|
<td data-label="Subject"><%= log.subject_type.demodulize.underscore.humanize %> #<%= log.subject_id %></td>
|
|
19
21
|
<td data-label="Changes">
|
|
20
22
|
<% log.audited_changes.each do |attr, change| %>
|
|
21
23
|
<div class="hrl-small">
|
|
22
24
|
<span class="hrl-muted"><%= attr.humanize %>:</span>
|
|
23
25
|
<% if change.is_a?(Array) %>
|
|
24
|
-
<%= change[0].
|
|
26
|
+
<%= change[0].to_s.presence || "blank" %> → <%= change[1].to_s.presence || "blank" %>
|
|
25
27
|
<% else %>
|
|
26
28
|
<%= change %>
|
|
27
29
|
<% end %>
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
<%= form_with url: hr_lite.enrol_admin_benefit_path(benefit), method: :post, local: true do %>
|
|
21
21
|
<div class="hrl-field">
|
|
22
22
|
<%= label_tag "enrol_user_#{benefit.id}", "Employee" %>
|
|
23
|
-
<%= select_tag :user_id, options_for_select(people), id: "enrol_user_#{benefit.id}"
|
|
23
|
+
<%= select_tag :user_id, options_for_select(people), id: "enrol_user_#{benefit.id}", include_blank: "Choose…", required: true,
|
|
24
|
+
data: { hrl_filter: "Type a name to filter" } %>
|
|
24
25
|
</div>
|
|
25
26
|
<div class="hrl-field">
|
|
26
27
|
<%= label_tag "enrol_on_#{benefit.id}", "Covered from" %>
|
|
@@ -49,10 +50,15 @@
|
|
|
49
50
|
<td data-label="Since"><%= enrolment.enrolled_on.strftime("%d %b %Y") %></td>
|
|
50
51
|
<td data-label="Dependants" class="hrl-num"><%= enrolment.dependants %></td>
|
|
51
52
|
<td data-label="">
|
|
52
|
-
|
|
53
|
+
<% if enrolment.ended_on %>
|
|
54
|
+
<p class="hrl-small">Cover ends <%= enrolment.ended_on.strftime("%d %b %Y") %></p>
|
|
55
|
+
<% end %>
|
|
56
|
+
<%= form_with url: hr_lite.unenrol_admin_benefit_path(enrolment.benefit), method: :post, class: "hrl-row",
|
|
57
|
+
data: { turbo_confirm: "End #{enrolment.benefit.name} for #{hr_display_name(enrolment.user)} on the date picked?" } do %>
|
|
53
58
|
<%= hidden_field_tag :user_id, enrolment.user_id %>
|
|
54
|
-
<%=
|
|
55
|
-
<%=
|
|
59
|
+
<%= label_tag "ended-on-#{enrolment.id}", "Last day of cover", class: "hrl-small" %>
|
|
60
|
+
<%= date_field_tag :ended_on, enrolment.ended_on || Date.current, id: "ended-on-#{enrolment.id}", class: "hrl-input" %>
|
|
61
|
+
<%= submit_tag enrolment.ended_on ? "Change end" : "End cover", class: "hrl-btn" %>
|
|
56
62
|
<% end %>
|
|
57
63
|
</td>
|
|
58
64
|
</tr>
|
|
@@ -22,12 +22,12 @@
|
|
|
22
22
|
</div>
|
|
23
23
|
|
|
24
24
|
<div class="hrl-row hrl-row--mb" role="tablist">
|
|
25
|
-
<a class="hrl-btn <%= "
|
|
26
|
-
<a class="hrl-btn <%= "
|
|
25
|
+
<a class="hrl-btn" <%= "aria-current=true" if @tab == "slips" %> href="<%= hr_lite.admin_ca_reviews_path(keep.(tab: "slips", status: @status)) %>">Salary slips</a>
|
|
26
|
+
<a class="hrl-btn" <%= "aria-current=true" if @tab == "declarations" %> href="<%= hr_lite.admin_ca_reviews_path(keep.(tab: "declarations", status: @status)) %>">Tax declarations</a>
|
|
27
27
|
</div>
|
|
28
28
|
<div class="hrl-row hrl-row--mb">
|
|
29
29
|
<% [ [ nil, "All" ], [ "unreviewed", "To review" ], [ "flagged", "Flagged" ], [ "verified", "Verified" ], [ "resolved", "Resolved" ] ].each do |value, label| %>
|
|
30
|
-
<a class="hrl-btn <%= "
|
|
30
|
+
<a class="hrl-btn" <%= "aria-current=true" if @status == value %> href="<%= hr_lite.admin_ca_reviews_path(keep.(status: value)) %>"><%= label %></a>
|
|
31
31
|
<% end %>
|
|
32
32
|
</div>
|
|
33
33
|
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
<section class="hrl-card">
|
|
5
5
|
<div class="hrl-row">
|
|
6
6
|
<% HrLite::ChecklistTemplate::KINDS.each do |kind| %>
|
|
7
|
-
|
|
8
|
-
href="<%= hr_lite.admin_checklists_path(kind: kind) %>"><%= kind.humanize %></a>
|
|
7
|
+
<%= link_to kind.humanize, hr_lite.admin_checklists_path(kind: kind), class: "hrl-btn", aria: { current: ("true" if kind == @kind) } %>
|
|
9
8
|
<% end %>
|
|
10
9
|
</div>
|
|
11
10
|
</section>
|
|
@@ -37,7 +36,8 @@
|
|
|
37
36
|
<td data-label="Due"><%= item.due_on&.strftime("%d %b %Y") || "—" %></td>
|
|
38
37
|
<td data-label="">
|
|
39
38
|
<%= form_with url: hr_lite.complete_admin_checklist_path(item), method: :post do %>
|
|
40
|
-
<%=
|
|
39
|
+
<%= label_tag "checklist-note-#{item.id}", "Note (optional)", class: "hrl-sr-only" %>
|
|
40
|
+
<%= text_field_tag :note, nil, id: "checklist-note-#{item.id}", placeholder: "Note (optional)", class: "hrl-input" %>
|
|
41
41
|
<%= submit_tag "Done", class: "hrl-btn hrl-btn--primary" %>
|
|
42
42
|
<% end %>
|
|
43
43
|
</td>
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
<div class="hrl-row hrl-row--mb">
|
|
7
7
|
<span class="hrl-small hrl-muted">Status</span>
|
|
8
8
|
<% HrLite::CompOffRequest::STATUSES.each do |status| %>
|
|
9
|
-
|
|
10
|
-
href="<%= hr_lite.admin_comp_off_requests_path(status: status) %>"><%= status.humanize %></a>
|
|
9
|
+
<%= link_to status.humanize, hr_lite.admin_comp_off_requests_path(status: status), class: "hrl-btn", aria: { current: ("true" if @status == status) } %>
|
|
11
10
|
<% end %>
|
|
12
11
|
</div>
|
|
13
12
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
<% content_for(:page_title) { "Comp-off — #{hr_display_name(@request.user)}" } %>
|
|
2
|
+
<a class="hrl-backlink" href="<%= hr_lite.admin_comp_off_requests_path %>"><span aria-hidden="true">‹</span> Approvals</a>
|
|
2
3
|
<div class="hrl-page__head">
|
|
3
4
|
<h1 class="hrl-page__title">Comp-off — <%= hr_display_name(@request.user) %></h1>
|
|
4
|
-
<div class="hrl-page__actions">
|
|
5
|
-
<a class="hrl-btn" href="<%= hr_lite.admin_comp_off_requests_path %>">All requests</a>
|
|
6
|
-
</div>
|
|
7
5
|
</div>
|
|
8
6
|
|
|
9
7
|
<section class="hrl-card">
|
|
@@ -34,7 +32,8 @@
|
|
|
34
32
|
`formaction:` can never pass verification on the second endpoint. %>
|
|
35
33
|
<section class="hrl-card">
|
|
36
34
|
<h2 class="hrl-card__title">Approve</h2>
|
|
37
|
-
<%= form_with url: hr_lite.approve_admin_comp_off_request_path(@request), method: :post, local: true
|
|
35
|
+
<%= form_with url: hr_lite.approve_admin_comp_off_request_path(@request), method: :post, local: true,
|
|
36
|
+
html: { data: { turbo_confirm: "Credit #{hrl_days(@request.credit_days)} day of comp-off to #{hr_display_name(@request.user)}?" } } do |f| %>
|
|
38
37
|
<div class="hrl-field">
|
|
39
38
|
<%= f.label :decision_note, "Note (optional)", for: "approve_note" %>
|
|
40
39
|
<%= f.text_area :decision_note, id: "approve_note" %>
|
|
@@ -48,10 +47,11 @@
|
|
|
48
47
|
|
|
49
48
|
<section class="hrl-card">
|
|
50
49
|
<h2 class="hrl-card__title">Reject</h2>
|
|
51
|
-
<%= form_with url: hr_lite.reject_admin_comp_off_request_path(@request), method: :post, local: true
|
|
50
|
+
<%= form_with url: hr_lite.reject_admin_comp_off_request_path(@request), method: :post, local: true,
|
|
51
|
+
html: { data: { turbo_confirm: "Reject #{hr_display_name(@request.user)}'s comp-off for #{@request.date_worked.strftime('%d %b %Y')}?" } } do |f| %>
|
|
52
52
|
<div class="hrl-field">
|
|
53
53
|
<%= f.label :decision_note, "Reason (required)", for: "reject_note" %>
|
|
54
|
-
<%= f.text_area :decision_note, id: "reject_note" %>
|
|
54
|
+
<%= f.text_area :decision_note, id: "reject_note", required: true %>
|
|
55
55
|
</div>
|
|
56
56
|
<div class="hrl-form-actions">
|
|
57
57
|
<%= f.button "Reject", type: :submit, class: "hrl-btn hrl-btn--danger" %>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
<% content_for(:page_title) { "
|
|
1
|
+
<% content_for(:page_title) { "Designation change" } %>
|
|
2
2
|
<div class="hrl-page__head">
|
|
3
|
-
<h1 class="hrl-page__title">
|
|
3
|
+
<h1 class="hrl-page__title">Designation change — <%= hr_display_name(@profile.user) %></h1>
|
|
4
4
|
</div>
|
|
5
5
|
|
|
6
6
|
<section class="hrl-card">
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
<div class="hrl-field"><%= f.label :effective_date %><%= f.date_field :effective_date %></div>
|
|
13
13
|
<div class="hrl-field"><%= f.label :note, "Note (optional)" %><%= f.text_area :note %></div>
|
|
14
14
|
<div class="hrl-form-actions">
|
|
15
|
-
<%= f.submit "Record change", class: "hrl-btn hrl-btn--primary"
|
|
15
|
+
<%= f.submit "Record change", class: "hrl-btn hrl-btn--primary",
|
|
16
|
+
data: { turbo_confirm: "Record this designation change? #{hr_display_name(@profile.user)} is told at once." } %>
|
|
16
17
|
<a class="hrl-btn" href="<%= hr_lite.admin_employee_path(@profile) %>">Cancel</a>
|
|
17
18
|
</div>
|
|
18
19
|
<% end %>
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
visibility allows.
|
|
9
9
|
</p>
|
|
10
10
|
<div class="hrl-row">
|
|
11
|
-
<a class="hrl-btn <%= "
|
|
11
|
+
<a class="hrl-btn" <%= "aria-current=true" if @category.nil? %>
|
|
12
12
|
href="<%= hr_lite.admin_documents_path %>">All</a>
|
|
13
13
|
<% @categories.each do |category| %>
|
|
14
|
-
<a class="hrl-btn <%= "
|
|
14
|
+
<a class="hrl-btn" <%= "aria-current=true" if @category == category %>
|
|
15
15
|
href="<%= hr_lite.admin_documents_path(category: category) %>"><%= category.humanize %></a>
|
|
16
16
|
<% end %>
|
|
17
17
|
</div>
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
</td>
|
|
36
36
|
<td data-label="File">
|
|
37
37
|
<% if doc.readable_by?(hr_current_user) && doc.file.attached? %>
|
|
38
|
-
<a class="hrl-
|
|
38
|
+
<a class="hrl-btn" href="<%= hr_lite.download_document_path(doc) %>">Open</a>
|
|
39
39
|
<% else %>
|
|
40
40
|
<span class="hrl-small hrl-muted">Not yours to open</span>
|
|
41
41
|
<% end %>
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
<%= button_to "Verify", hr_lite.verify_admin_document_path(doc),
|
|
45
45
|
method: :post, class: "hrl-btn hrl-btn--primary" %>
|
|
46
46
|
<%= form_with url: hr_lite.reject_admin_document_path(doc), method: :post, local: true do %>
|
|
47
|
-
<%=
|
|
47
|
+
<%= label_tag "reject-doc-#{doc.id}", "What is wrong with it", class: "hrl-sr-only" %>
|
|
48
|
+
<%= text_field_tag :note, nil, id: "reject-doc-#{doc.id}", placeholder: "What is wrong with it", class: "hrl-input", required: true %>
|
|
48
49
|
<%= submit_tag "Reject", class: "hrl-btn" %>
|
|
49
50
|
<% end %>
|
|
50
51
|
</td>
|
|
@@ -58,6 +59,9 @@
|
|
|
58
59
|
|
|
59
60
|
<section class="hrl-card">
|
|
60
61
|
<h2 class="hrl-card__title">Everything on file</h2>
|
|
62
|
+
<% if @documents.empty? %>
|
|
63
|
+
<p class="hrl-muted">No documents on file yet. People upload them from Me › Documents; you can upload for someone from their page.</p>
|
|
64
|
+
<% else %>
|
|
61
65
|
<div class="hrl-table-wrap">
|
|
62
66
|
<table class="hrl-table hrl-table--stack">
|
|
63
67
|
<thead><tr><th>Person</th><th>Document</th><th>Expires</th><th>Checked</th></tr></thead>
|
|
@@ -85,5 +89,6 @@
|
|
|
85
89
|
</tbody>
|
|
86
90
|
</table>
|
|
87
91
|
</div>
|
|
92
|
+
<% end %>
|
|
88
93
|
<%= hrl_pagination %>
|
|
89
94
|
</section>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<% content_for(:page_title) { hr_display_name(@employee) } %>
|
|
2
2
|
<% content_for(:tabrow) { render "hr_lite/shared/person_tabs", user: @employee } %>
|
|
3
|
+
<% content_for(:back, "Documents to verify") %>
|
|
3
4
|
<div class="hrl-page__head">
|
|
4
5
|
<h1 class="hrl-page__title"><%= hr_display_name(@employee) %> — documents</h1>
|
|
5
6
|
</div>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<section class="hrl-card">
|
|
2
2
|
<%= form_with model: profile, url: url, method: method, scope: :employee_profile, local: true do |f| %>
|
|
3
3
|
<%= render "hr_lite/shared/form_errors", record: profile %>
|
|
4
|
+
<h2 class="hrl-card__title">Identity</h2>
|
|
4
5
|
<% if profile.new_record? && profile.user_id.blank? %>
|
|
5
6
|
<div class="hrl-field">
|
|
6
7
|
<%= f.label :user_id, "Existing staff member" %>
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
</div>
|
|
23
24
|
<div class="hrl-field">
|
|
24
25
|
<%= f.label :new_user_password, "Starting password (optional)" %>
|
|
25
|
-
<%= f.
|
|
26
|
+
<%= f.password_field :new_user_password, autocomplete: "new-password" %>
|
|
26
27
|
<p class="hrl-hint">Leave blank (recommended): they get an email invite and set their own
|
|
27
28
|
password. Fill it only if you want to hand a password over yourself.</p>
|
|
28
29
|
</div>
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
<p class="hrl-hint">The employee code is assigned automatically
|
|
41
42
|
(<%= HrLite::Setting.instance.employee_code_prefix %> + next number).</p>
|
|
42
43
|
<% end %>
|
|
44
|
+
<h2 class="hrl-card__title hrl-mt">Work</h2>
|
|
43
45
|
<div class="hrl-field"><%= f.label :designation %><%= f.text_field :designation %></div>
|
|
44
46
|
<div class="hrl-field">
|
|
45
47
|
<%= f.label :manager_id, "Reports to (their L1)" %>
|
|
@@ -64,7 +66,7 @@
|
|
|
64
66
|
<%= f.select :office_location_id, offices, { include_blank: "None — only all-office holidays" }, data: { hrl_filter: ("Type an office" if offices.size > 5) } %></div>
|
|
65
67
|
<% end %>
|
|
66
68
|
<div class="hrl-field"><%= f.label :date_of_birth %><%= f.date_field :date_of_birth %></div>
|
|
67
|
-
<div class="hrl-field"><%= f.label :date_of_joining %><%= f.date_field :date_of_joining %></div>
|
|
69
|
+
<div class="hrl-field"><%= f.label :date_of_joining %><%= f.date_field :date_of_joining, required: true %></div>
|
|
68
70
|
<div class="hrl-field">
|
|
69
71
|
<%= f.label :blood_group, id: "hrl-blood-group", for: nil %>
|
|
70
72
|
<div class="hrl-chiprow" role="radiogroup" aria-labelledby="hrl-blood-group">
|
|
@@ -79,6 +81,7 @@
|
|
|
79
81
|
<%= f.label :probation_until, "On probation until (blank = not on probation)" %>
|
|
80
82
|
<%= f.date_field :probation_until %>
|
|
81
83
|
</div>
|
|
84
|
+
<h2 class="hrl-card__title hrl-mt">Attendance rules</h2>
|
|
82
85
|
<% if HrLite.config.attendance_slots %>
|
|
83
86
|
<div class="hrl-field">
|
|
84
87
|
<%= f.label :buffer_minutes, "Late buffer (delays late penalties; colleagues see the reason category)" %>
|
|
@@ -99,12 +102,16 @@
|
|
|
99
102
|
<%= f.label :date_of_exit, "Date of exit (leave blank while employed)" %>
|
|
100
103
|
<%= f.date_field :date_of_exit %>
|
|
101
104
|
</div>
|
|
102
|
-
<
|
|
103
|
-
<div class="hrl-field"><%= f.label :
|
|
105
|
+
<h2 class="hrl-card__title hrl-mt">Pay & statutory</h2>
|
|
106
|
+
<div class="hrl-field"><%= f.label :pan_number, "PAN" %><%= f.text_field :pan_number %>
|
|
107
|
+
<p class="hrl-hint">10 characters in capitals, like ABCDE1234F.</p></div>
|
|
108
|
+
<div class="hrl-field"><%= f.label :pf_uan, "PF UAN" %><%= f.text_field :pf_uan %>
|
|
109
|
+
<p class="hrl-hint">12 digits.</p></div>
|
|
104
110
|
<div class="hrl-field"><%= f.label :esi_number, "ESI number" %><%= f.text_field :esi_number %></div>
|
|
105
111
|
<div class="hrl-field"><%= f.label :bank_name %><%= f.text_field :bank_name %></div>
|
|
106
112
|
<div class="hrl-field"><%= f.label :bank_account_number %><%= f.text_field :bank_account_number %></div>
|
|
107
|
-
<div class="hrl-field"><%= f.label :bank_ifsc, "IFSC" %><%= f.text_field :bank_ifsc
|
|
113
|
+
<div class="hrl-field"><%= f.label :bank_ifsc, "IFSC" %><%= f.text_field :bank_ifsc %>
|
|
114
|
+
<p class="hrl-hint">11 characters in capitals, fifth is a zero, like HDFC0001234.</p></div>
|
|
108
115
|
<div class="hrl-field">
|
|
109
116
|
<%= f.label :tax_regime %>
|
|
110
117
|
<%= f.select :tax_regime, HrLite::EmployeeProfile::TAX_REGIMES.map { |r| [ "#{r.humanize} regime", r ] } %>
|