hr_lite 0.1.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 +7 -0
- data/CHANGELOG.md +33 -0
- data/MIT-LICENSE +20 -0
- data/README.md +166 -0
- data/Rakefile +3 -0
- data/app/assets/javascripts/hr_lite/geo_punch.js +61 -0
- data/app/assets/javascripts/hr_lite/mention.js +100 -0
- data/app/assets/stylesheets/hr_lite/application.css +15 -0
- data/app/assets/stylesheets/hr_lite/hr_lite.css +239 -0
- data/app/controllers/hr_lite/admin/appraisals_controller.rb +74 -0
- data/app/controllers/hr_lite/admin/attendances_controller.rb +79 -0
- data/app/controllers/hr_lite/admin/audit_logs_controller.rb +9 -0
- data/app/controllers/hr_lite/admin/base_controller.rb +16 -0
- data/app/controllers/hr_lite/admin/designation_changes_controller.rb +33 -0
- data/app/controllers/hr_lite/admin/employees_controller.rb +53 -0
- data/app/controllers/hr_lite/admin/holidays_controller.rb +70 -0
- data/app/controllers/hr_lite/admin/leadership_controller.rb +18 -0
- data/app/controllers/hr_lite/admin/leave_balances_controller.rb +41 -0
- data/app/controllers/hr_lite/admin/leave_requests_controller.rb +41 -0
- data/app/controllers/hr_lite/admin/leave_types_controller.rb +54 -0
- data/app/controllers/hr_lite/admin/office_locations_controller.rb +46 -0
- data/app/controllers/hr_lite/admin/overview_controller.rb +12 -0
- data/app/controllers/hr_lite/admin/payroll_runs_controller.rb +93 -0
- data/app/controllers/hr_lite/admin/salary_slips_controller.rb +44 -0
- data/app/controllers/hr_lite/admin/salary_structures_controller.rb +49 -0
- data/app/controllers/hr_lite/admin/settings_controller.rb +18 -0
- data/app/controllers/hr_lite/application_controller.rb +76 -0
- data/app/controllers/hr_lite/appraisals_controller.rb +18 -0
- data/app/controllers/hr_lite/attendance_controller.rb +37 -0
- data/app/controllers/hr_lite/calendar_controller.rb +20 -0
- data/app/controllers/hr_lite/career_controller.rb +9 -0
- data/app/controllers/hr_lite/employee_profiles_controller.rb +9 -0
- data/app/controllers/hr_lite/holidays_controller.rb +9 -0
- data/app/controllers/hr_lite/home_controller.rb +7 -0
- data/app/controllers/hr_lite/kudos_controller.rb +36 -0
- data/app/controllers/hr_lite/leave_balances_controller.rb +11 -0
- data/app/controllers/hr_lite/leave_requests_controller.rb +56 -0
- data/app/controllers/hr_lite/salary_slips_controller.rb +39 -0
- data/app/controllers/hr_lite/users_controller.rb +9 -0
- data/app/helpers/hr_lite/application_helper.rb +105 -0
- data/app/jobs/hr_lite/application_job.rb +4 -0
- data/app/jobs/hr_lite/daily_digest_job.rb +33 -0
- data/app/jobs/hr_lite/leave_year_rollover_job.rb +29 -0
- data/app/mailers/hr_lite/application_mailer.rb +5 -0
- data/app/mailers/hr_lite/event_mailer.rb +33 -0
- data/app/models/concerns/hr_lite/audited.rb +70 -0
- data/app/models/concerns/hr_lite/encrypted_money.rb +32 -0
- data/app/models/hr_lite/application_record.rb +5 -0
- data/app/models/hr_lite/appraisal.rb +89 -0
- data/app/models/hr_lite/attendance_record.rb +41 -0
- data/app/models/hr_lite/audit_log.rb +17 -0
- data/app/models/hr_lite/designation_change.rb +52 -0
- data/app/models/hr_lite/employee_profile.rb +72 -0
- data/app/models/hr_lite/holiday.rb +18 -0
- data/app/models/hr_lite/kudo.rb +54 -0
- data/app/models/hr_lite/kudo_mention.rb +8 -0
- data/app/models/hr_lite/leave_balance.rb +42 -0
- data/app/models/hr_lite/leave_request.rb +207 -0
- data/app/models/hr_lite/leave_type.rb +22 -0
- data/app/models/hr_lite/office_location.rb +21 -0
- data/app/models/hr_lite/payroll_run.rb +112 -0
- data/app/models/hr_lite/salary_slip.rb +78 -0
- data/app/models/hr_lite/salary_structure.rb +49 -0
- data/app/models/hr_lite/setting.rb +14 -0
- data/app/services/hr_lite/attendance_puncher.rb +103 -0
- data/app/services/hr_lite/attendance_summary.rb +98 -0
- data/app/services/hr_lite/calculators/esi.rb +25 -0
- data/app/services/hr_lite/calculators/pf.rb +32 -0
- data/app/services/hr_lite/calculators/professional_tax.rb +20 -0
- data/app/services/hr_lite/calculators/proration.rb +30 -0
- data/app/services/hr_lite/calculators/tds.rb +74 -0
- data/app/services/hr_lite/day_status.rb +49 -0
- data/app/services/hr_lite/leave_day_counter.rb +24 -0
- data/app/services/hr_lite/overview_query.rb +39 -0
- data/app/services/hr_lite/payroll_run_processor.rb +46 -0
- data/app/services/hr_lite/pdf_renderer.rb +23 -0
- data/app/services/hr_lite/slip_builder.rb +106 -0
- data/app/services/hr_lite/working_calendar.rb +41 -0
- data/app/views/hr_lite/admin/appraisals/_form.html.erb +29 -0
- data/app/views/hr_lite/admin/appraisals/edit.html.erb +6 -0
- data/app/views/hr_lite/admin/appraisals/new.html.erb +6 -0
- data/app/views/hr_lite/admin/attendances/index.html.erb +49 -0
- data/app/views/hr_lite/admin/attendances/show.html.erb +55 -0
- data/app/views/hr_lite/admin/audit_logs/index.html.erb +39 -0
- data/app/views/hr_lite/admin/designation_changes/new.html.erb +19 -0
- data/app/views/hr_lite/admin/employees/_form.html.erb +40 -0
- data/app/views/hr_lite/admin/employees/edit.html.erb +3 -0
- data/app/views/hr_lite/admin/employees/index.html.erb +40 -0
- data/app/views/hr_lite/admin/employees/new.html.erb +3 -0
- data/app/views/hr_lite/admin/employees/show.html.erb +75 -0
- data/app/views/hr_lite/admin/holidays/index.html.erb +59 -0
- data/app/views/hr_lite/admin/leave_balances/index.html.erb +58 -0
- data/app/views/hr_lite/admin/leave_requests/index.html.erb +35 -0
- data/app/views/hr_lite/admin/leave_requests/show.html.erb +39 -0
- data/app/views/hr_lite/admin/leave_types/_form.html.erb +27 -0
- data/app/views/hr_lite/admin/leave_types/edit.html.erb +10 -0
- data/app/views/hr_lite/admin/leave_types/index.html.erb +39 -0
- data/app/views/hr_lite/admin/leave_types/new.html.erb +3 -0
- data/app/views/hr_lite/admin/office_locations/_form.html.erb +18 -0
- data/app/views/hr_lite/admin/office_locations/edit.html.erb +10 -0
- data/app/views/hr_lite/admin/office_locations/index.html.erb +30 -0
- data/app/views/hr_lite/admin/office_locations/new.html.erb +3 -0
- data/app/views/hr_lite/admin/overview/index.html.erb +72 -0
- data/app/views/hr_lite/admin/payroll_runs/index.html.erb +33 -0
- data/app/views/hr_lite/admin/payroll_runs/new.html.erb +20 -0
- data/app/views/hr_lite/admin/payroll_runs/show.html.erb +76 -0
- data/app/views/hr_lite/admin/salary_slips/show.html.erb +42 -0
- data/app/views/hr_lite/admin/salary_structures/_form.html.erb +25 -0
- data/app/views/hr_lite/admin/salary_structures/edit.html.erb +6 -0
- data/app/views/hr_lite/admin/salary_structures/new.html.erb +6 -0
- data/app/views/hr_lite/admin/settings/edit.html.erb +18 -0
- data/app/views/hr_lite/appraisals/index.html.erb +22 -0
- data/app/views/hr_lite/appraisals/show.html.erb +32 -0
- data/app/views/hr_lite/attendance/_month_grid.html.erb +41 -0
- data/app/views/hr_lite/attendance/_punch_card.html.erb +41 -0
- data/app/views/hr_lite/attendance/show.html.erb +22 -0
- data/app/views/hr_lite/calendar/show.html.erb +45 -0
- data/app/views/hr_lite/career/show.html.erb +49 -0
- data/app/views/hr_lite/employee_profiles/show.html.erb +22 -0
- data/app/views/hr_lite/event_mailer/event.html.erb +10 -0
- data/app/views/hr_lite/event_mailer/event.text.erb +10 -0
- data/app/views/hr_lite/event_mailer/leadership.html.erb +27 -0
- data/app/views/hr_lite/event_mailer/leadership.text.erb +16 -0
- data/app/views/hr_lite/holidays/_next_holiday.html.erb +12 -0
- data/app/views/hr_lite/holidays/index.html.erb +30 -0
- data/app/views/hr_lite/home/index.html.erb +25 -0
- data/app/views/hr_lite/kudos/_kudo.html.erb +17 -0
- data/app/views/hr_lite/kudos/index.html.erb +39 -0
- data/app/views/hr_lite/leave_balances/index.html.erb +19 -0
- data/app/views/hr_lite/leave_requests/_balance_chips.html.erb +17 -0
- data/app/views/hr_lite/leave_requests/index.html.erb +37 -0
- data/app/views/hr_lite/leave_requests/new.html.erb +36 -0
- data/app/views/hr_lite/leave_requests/show.html.erb +25 -0
- data/app/views/hr_lite/salary_slips/_slip_detail.html.erb +48 -0
- data/app/views/hr_lite/salary_slips/index.html.erb +29 -0
- data/app/views/hr_lite/salary_slips/pdf.html.erb +72 -0
- data/app/views/hr_lite/salary_slips/show.html.erb +12 -0
- data/app/views/hr_lite/shared/_form_errors.html.erb +10 -0
- data/app/views/hr_lite/shared/_pagination.html.erb +11 -0
- data/app/views/layouts/hr_lite/application.html.erb +56 -0
- data/app/views/layouts/hr_lite/mailer.html.erb +30 -0
- data/app/views/layouts/hr_lite/mailer.text.erb +6 -0
- data/app/views/layouts/hr_lite/pdf.html.erb +26 -0
- data/config/routes.rb +57 -0
- data/db/migrate/20260718190726_create_hr_lite_kudos.rb +14 -0
- data/db/migrate/20260718190727_create_hr_lite_kudo_mentions.rb +12 -0
- data/db/migrate/20260718190728_create_hr_lite_audit_logs.rb +15 -0
- data/db/migrate/20260718192342_create_hr_lite_office_locations.rb +13 -0
- data/db/migrate/20260718192343_create_hr_lite_attendance_records.rb +27 -0
- data/db/migrate/20260718193045_create_hr_lite_holidays.rb +14 -0
- data/db/migrate/20260718193046_create_hr_lite_leave_types.rb +20 -0
- data/db/migrate/20260718193047_create_hr_lite_leave_balances.rb +17 -0
- data/db/migrate/20260718193048_create_hr_lite_leave_requests.rb +23 -0
- data/db/migrate/20260718193049_create_hr_lite_settings.rb +10 -0
- data/db/migrate/20260718194534_create_hr_lite_employee_profiles.rb +27 -0
- data/db/migrate/20260718194535_create_hr_lite_salary_structures.rb +23 -0
- data/db/migrate/20260718194536_create_hr_lite_payroll_runs.rb +20 -0
- data/db/migrate/20260718194537_create_hr_lite_salary_slips.rb +28 -0
- data/db/migrate/20260718195953_create_hr_lite_appraisals.rb +22 -0
- data/db/migrate/20260718195954_create_hr_lite_designation_changes.rb +17 -0
- data/lib/generators/hr_lite/install/install_generator.rb +29 -0
- data/lib/generators/hr_lite/install/templates/AFTER_INSTALL +35 -0
- data/lib/generators/hr_lite/install/templates/initializer.rb +45 -0
- data/lib/hr_lite/configuration.rb +60 -0
- data/lib/hr_lite/current.rb +7 -0
- data/lib/hr_lite/engine.rb +39 -0
- data/lib/hr_lite/geo.rb +22 -0
- data/lib/hr_lite/mention_parser.rb +18 -0
- data/lib/hr_lite/money.rb +33 -0
- data/lib/hr_lite/notifications.rb +99 -0
- data/lib/hr_lite/seeds.rb +42 -0
- data/lib/hr_lite/statutory_rate_card.rb +60 -0
- data/lib/hr_lite/version.rb +3 -0
- data/lib/hr_lite.rb +104 -0
- data/lib/tasks/hr_lite_tasks.rake +8 -0
- metadata +250 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Team attendance" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Team attendance</h1>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div class="hrl-row" style="margin-bottom:.8rem;">
|
|
7
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_attendances_path(date: @date - 1) %>">←</a>
|
|
8
|
+
<strong><%= @date.strftime("%A, %d %B %Y") %></strong>
|
|
9
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_attendances_path(date: @date + 1) %>">→</a>
|
|
10
|
+
<% unless @date == Date.current %>
|
|
11
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_attendances_path %>">Today</a>
|
|
12
|
+
<% end %>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<div class="hrl-kpis">
|
|
16
|
+
<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>
|
|
17
|
+
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= @employees.size - @records.size %></div><div class="hrl-kpi__label">No punch</div></div>
|
|
18
|
+
<div class="hrl-kpi"><div class="hrl-kpi__value"><%= @flagged_count %></div><div class="hrl-kpi__label">Flagged</div></div>
|
|
19
|
+
<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>
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<div class="hrl-table-wrap">
|
|
23
|
+
<table class="hrl-table hrl-table--stack">
|
|
24
|
+
<thead><tr><th>Employee</th><th>In</th><th>Out</th><th>Status</th><th></th></tr></thead>
|
|
25
|
+
<tbody>
|
|
26
|
+
<% @employees.each do |employee| %>
|
|
27
|
+
<% record = @records[employee.id] %>
|
|
28
|
+
<tr>
|
|
29
|
+
<td data-label="Employee"><%= hr_display_name(employee) %></td>
|
|
30
|
+
<td data-label="In"><%= record&.check_in_at&.strftime("%H:%M") || "—" %></td>
|
|
31
|
+
<td data-label="Out"><%= record&.check_out_at&.strftime("%H:%M") || "—" %></td>
|
|
32
|
+
<td data-label="Status">
|
|
33
|
+
<% if record&.flagged? %>
|
|
34
|
+
<span class="hrl-badge hrl-badge--bad" title="<%= record.flag_note %>">Flagged</span>
|
|
35
|
+
<% elsif record&.check_in_at %>
|
|
36
|
+
<span class="hrl-badge hrl-badge--ok"><%= record.status.humanize %></span>
|
|
37
|
+
<% else %>
|
|
38
|
+
<span class="hrl-badge hrl-badge--muted">No punch</span>
|
|
39
|
+
<% end %>
|
|
40
|
+
<% if record&.regularized? %><span class="hrl-badge">Fixed</span><% end %>
|
|
41
|
+
</td>
|
|
42
|
+
<td data-label="">
|
|
43
|
+
<a class="hrl-small" href="<%= hr_lite.admin_attendance_path(employee.id, date: @date, month: @date.strftime("%Y-%m")) %>">Fix / month</a>
|
|
44
|
+
</td>
|
|
45
|
+
</tr>
|
|
46
|
+
<% end %>
|
|
47
|
+
</tbody>
|
|
48
|
+
</table>
|
|
49
|
+
</div>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Attendance — #{hr_display_name(@employee)}" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title"><%= hr_display_name(@employee) %></h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_attendances_path %>">Team view</a>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<section class="hrl-card">
|
|
10
|
+
<div class="hrl-row" style="margin-bottom:.6rem;">
|
|
11
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_attendance_path(@employee.id, month: (@month - 1.month).strftime("%Y-%m")) %>">←</a>
|
|
12
|
+
<strong><%= @month.strftime("%B %Y") %></strong>
|
|
13
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_attendance_path(@employee.id, month: (@month + 1.month).strftime("%Y-%m")) %>">→</a>
|
|
14
|
+
<span class="hrl-right hrl-small hrl-muted">
|
|
15
|
+
Present <%= @counts[:present] %> · Half <%= @counts[:half_day] %> · Absent <%= @counts[:absent] %>
|
|
16
|
+
</span>
|
|
17
|
+
</div>
|
|
18
|
+
<%= render "hr_lite/attendance/month_grid", month: @month, day_status: @day_status,
|
|
19
|
+
link_builder: ->(date) { hr_lite.admin_attendance_path(@employee.id, date: date, month: @month.strftime("%Y-%m")) } %>
|
|
20
|
+
<p class="hrl-small hrl-muted hrl-mt">Tap a date to fix its punches.</p>
|
|
21
|
+
</section>
|
|
22
|
+
|
|
23
|
+
<% if @edit_date %>
|
|
24
|
+
<section class="hrl-card" id="regularize">
|
|
25
|
+
<h2 class="hrl-card__title">Fix <%= @edit_date.strftime("%A, %d %B") %></h2>
|
|
26
|
+
<% if @edit_record.flagged? %>
|
|
27
|
+
<p class="hrl-small"><span class="hrl-badge hrl-badge--bad">Flagged</span> <%= @edit_record.flag_note %></p>
|
|
28
|
+
<% end %>
|
|
29
|
+
<%= form_with url: hr_lite.admin_attendance_path(@employee.id, date: @edit_date), method: :patch,
|
|
30
|
+
scope: :attendance_record, local: true do |f| %>
|
|
31
|
+
<div class="hrl-field">
|
|
32
|
+
<%= f.label :check_in_at, "Check-in" %>
|
|
33
|
+
<%= f.datetime_local_field :check_in_at, value: @edit_record.check_in_at&.strftime("%Y-%m-%dT%H:%M") %>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="hrl-field">
|
|
36
|
+
<%= f.label :check_out_at, "Check-out" %>
|
|
37
|
+
<%= f.datetime_local_field :check_out_at, value: @edit_record.check_out_at&.strftime("%Y-%m-%dT%H:%M") %>
|
|
38
|
+
<p class="hrl-hint">Clear both times to remove the punch entirely.</p>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="hrl-field">
|
|
41
|
+
<%= f.label :status %>
|
|
42
|
+
<%= f.select :status, HrLite::AttendanceRecord::STATUSES.map { |s| [ s.humanize, s ] },
|
|
43
|
+
selected: @edit_record.status %>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="hrl-field">
|
|
46
|
+
<%= f.label :regularization_note, "Why is this being fixed? (required)" %>
|
|
47
|
+
<%= f.text_area :regularization_note %>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="hrl-form-actions">
|
|
50
|
+
<%= f.submit "Save fix", class: "hrl-btn hrl-btn--primary" %>
|
|
51
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_attendance_path(@employee.id, month: @month.strftime("%Y-%m")) %>">Cancel</a>
|
|
52
|
+
</div>
|
|
53
|
+
<% end %>
|
|
54
|
+
</section>
|
|
55
|
+
<% end %>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<div class="hrl-page__head">
|
|
2
|
+
<h1 class="hrl-page__title">Audit trail</h1>
|
|
3
|
+
<p class="hrl-page__sub">Every policy, settings and payroll change — append-only.</p>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<% if @audit_logs.any? %>
|
|
7
|
+
<div class="hrl-table-wrap">
|
|
8
|
+
<table class="hrl-table hrl-table--stack">
|
|
9
|
+
<thead>
|
|
10
|
+
<tr><th>When</th><th>Who</th><th>Action</th><th>Subject</th><th>Changes</th></tr>
|
|
11
|
+
</thead>
|
|
12
|
+
<tbody>
|
|
13
|
+
<% @audit_logs.each do |log| %>
|
|
14
|
+
<tr>
|
|
15
|
+
<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="Subject"><%= log.subject_type.demodulize.underscore.humanize %> #<%= log.subject_id %></td>
|
|
19
|
+
<td data-label="Changes">
|
|
20
|
+
<% log.audited_changes.each do |attr, change| %>
|
|
21
|
+
<div class="hrl-small">
|
|
22
|
+
<span class="hrl-muted"><%= attr.humanize %>:</span>
|
|
23
|
+
<% if change.is_a?(Array) %>
|
|
24
|
+
<%= change[0].inspect %> → <%= change[1].inspect %>
|
|
25
|
+
<% else %>
|
|
26
|
+
<%= change %>
|
|
27
|
+
<% end %>
|
|
28
|
+
</div>
|
|
29
|
+
<% end %>
|
|
30
|
+
</td>
|
|
31
|
+
</tr>
|
|
32
|
+
<% end %>
|
|
33
|
+
</tbody>
|
|
34
|
+
</table>
|
|
35
|
+
</div>
|
|
36
|
+
<%= hrl_pagination %>
|
|
37
|
+
<% else %>
|
|
38
|
+
<p class="hrl-card hrl-card--empty">No changes recorded yet.</p>
|
|
39
|
+
<% end %>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Role change" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Role change — <%= hr_display_name(@profile.user) %></h1>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<section class="hrl-card">
|
|
7
|
+
<p class="hrl-small hrl-muted">Current: <strong><%= @profile.designation.presence || "not set" %></strong>. The employee is notified and the change is recorded on their career timeline.</p>
|
|
8
|
+
<%= form_with model: @change, url: hr_lite.admin_employee_designation_changes_path(@profile),
|
|
9
|
+
scope: :designation_change, local: true do |f| %>
|
|
10
|
+
<%= render "hr_lite/shared/form_errors", record: @change %>
|
|
11
|
+
<div class="hrl-field"><%= f.label :to_designation, "New designation" %><%= f.text_field :to_designation %></div>
|
|
12
|
+
<div class="hrl-field"><%= f.label :effective_date %><%= f.date_field :effective_date %></div>
|
|
13
|
+
<div class="hrl-field"><%= f.label :note, "Note (optional)" %><%= f.text_area :note %></div>
|
|
14
|
+
<div class="hrl-form-actions">
|
|
15
|
+
<%= f.submit "Record change", class: "hrl-btn hrl-btn--primary" %>
|
|
16
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_employee_path(@profile) %>">Cancel</a>
|
|
17
|
+
</div>
|
|
18
|
+
<% end %>
|
|
19
|
+
</section>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<section class="hrl-card">
|
|
2
|
+
<%= form_with model: profile, url: url, method: method, scope: :employee_profile, local: true do |f| %>
|
|
3
|
+
<%= render "hr_lite/shared/form_errors", record: profile %>
|
|
4
|
+
<%= f.hidden_field :user_id %>
|
|
5
|
+
<% if profile.new_record? && profile.user_id.blank? %>
|
|
6
|
+
<div class="hrl-field">
|
|
7
|
+
<%= f.label :user_id, "Staff member" %>
|
|
8
|
+
<%= f.select :user_id, HrLite.employees.map { |u| [ HrLite.display_name(u), u.id ] } %>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
11
|
+
<div class="hrl-field"><%= f.label :employee_code %><%= f.text_field :employee_code %></div>
|
|
12
|
+
<div class="hrl-field"><%= f.label :designation %><%= f.text_field :designation %></div>
|
|
13
|
+
<div class="hrl-field"><%= f.label :department %><%= f.text_field :department %></div>
|
|
14
|
+
<div class="hrl-field"><%= f.label :work_location %><%= f.text_field :work_location %></div>
|
|
15
|
+
<div class="hrl-field"><%= f.label :date_of_birth %><%= f.date_field :date_of_birth %></div>
|
|
16
|
+
<div class="hrl-field"><%= f.label :date_of_joining %><%= f.date_field :date_of_joining %></div>
|
|
17
|
+
<div class="hrl-field">
|
|
18
|
+
<%= f.label :date_of_exit, "Date of exit (leave blank while employed)" %>
|
|
19
|
+
<%= f.date_field :date_of_exit %>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="hrl-field"><%= f.label :pan_number, "PAN" %><%= f.text_field :pan_number %></div>
|
|
22
|
+
<div class="hrl-field"><%= f.label :pf_uan, "PF UAN" %><%= f.text_field :pf_uan %></div>
|
|
23
|
+
<div class="hrl-field"><%= f.label :esi_number, "ESI number" %><%= f.text_field :esi_number %></div>
|
|
24
|
+
<div class="hrl-field"><%= f.label :bank_name %><%= f.text_field :bank_name %></div>
|
|
25
|
+
<div class="hrl-field"><%= f.label :bank_account_number %><%= f.text_field :bank_account_number %></div>
|
|
26
|
+
<div class="hrl-field"><%= f.label :bank_ifsc, "IFSC" %><%= f.text_field :bank_ifsc %></div>
|
|
27
|
+
<div class="hrl-field">
|
|
28
|
+
<%= f.label :tax_regime %>
|
|
29
|
+
<%= f.select :tax_regime, HrLite::EmployeeProfile::TAX_REGIMES.map { |r| [ "#{r.humanize} regime", r ] } %>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="hrl-field">
|
|
32
|
+
<%= f.label :declared_annual_deductions, "Declared annual deductions (old regime only)" %>
|
|
33
|
+
<%= f.number_field :declared_annual_deductions, step: 0.01, value: profile.declared_annual_deductions&.to_s("F") %>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="hrl-form-actions">
|
|
36
|
+
<%= f.submit "Save profile", class: "hrl-btn hrl-btn--primary" %>
|
|
37
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_employees_path %>">Cancel</a>
|
|
38
|
+
</div>
|
|
39
|
+
<% end %>
|
|
40
|
+
</section>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Employees" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Employees</h1>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<section class="hrl-card">
|
|
7
|
+
<% if @profiles.any? %>
|
|
8
|
+
<div class="hrl-table-wrap">
|
|
9
|
+
<table class="hrl-table hrl-table--stack">
|
|
10
|
+
<thead><tr><th>Code</th><th>Name</th><th>Designation</th><th>Joined</th><th></th></tr></thead>
|
|
11
|
+
<tbody>
|
|
12
|
+
<% @profiles.each do |profile| %>
|
|
13
|
+
<tr>
|
|
14
|
+
<td data-label="Code"><%= profile.employee_code %></td>
|
|
15
|
+
<td data-label="Name"><%= hr_display_name(profile.user) %>
|
|
16
|
+
<% if profile.date_of_exit %><span class="hrl-badge hrl-badge--muted">Exited</span><% end %></td>
|
|
17
|
+
<td data-label="Designation"><%= profile.designation %></td>
|
|
18
|
+
<td data-label="Joined"><%= profile.date_of_joining.strftime("%d %b %Y") %></td>
|
|
19
|
+
<td data-label=""><a class="hrl-btn" href="<%= hr_lite.admin_employee_path(profile) %>">Open</a></td>
|
|
20
|
+
</tr>
|
|
21
|
+
<% end %>
|
|
22
|
+
</tbody>
|
|
23
|
+
</table>
|
|
24
|
+
</div>
|
|
25
|
+
<%= hrl_pagination %>
|
|
26
|
+
<% else %>
|
|
27
|
+
<p class="hrl-card--empty">No employee profiles yet.</p>
|
|
28
|
+
<% end %>
|
|
29
|
+
</section>
|
|
30
|
+
|
|
31
|
+
<% if @users_without_profile.any? %>
|
|
32
|
+
<section class="hrl-card">
|
|
33
|
+
<h2 class="hrl-card__title">Staff without an HR profile</h2>
|
|
34
|
+
<div class="hrl-row">
|
|
35
|
+
<% @users_without_profile.each do |user| %>
|
|
36
|
+
<a class="hrl-btn" href="<%= hr_lite.new_admin_employee_path(user_id: user.id) %>">+ <%= hr_display_name(user) %></a>
|
|
37
|
+
<% end %>
|
|
38
|
+
</div>
|
|
39
|
+
</section>
|
|
40
|
+
<% end %>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
<% content_for(:page_title) { @profile.employee_code } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title"><%= hr_display_name(@profile.user) %> <span class="hrl-muted">(<%= @profile.employee_code %>)</span></h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<a class="hrl-btn" href="<%= hr_lite.edit_admin_employee_path(@profile) %>">Edit</a>
|
|
6
|
+
<a class="hrl-btn" href="<%= hr_lite.new_admin_employee_appraisal_path(@profile) %>">New appraisal</a>
|
|
7
|
+
<a class="hrl-btn" href="<%= hr_lite.new_admin_employee_designation_change_path(@profile) %>">Role change</a>
|
|
8
|
+
<a class="hrl-btn hrl-btn--primary" href="<%= hr_lite.new_admin_employee_salary_structure_path(@profile) %>">New structure</a>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="hrl-grid hrl-grid--2">
|
|
13
|
+
<section class="hrl-card">
|
|
14
|
+
<h2 class="hrl-card__title">Profile</h2>
|
|
15
|
+
<dl class="hrl-deflist">
|
|
16
|
+
<dt>Designation</dt><dd><%= @profile.designation.presence || "—" %></dd>
|
|
17
|
+
<dt>Department</dt><dd><%= @profile.department.presence || "—" %></dd>
|
|
18
|
+
<dt>Joined</dt><dd><%= @profile.date_of_joining.strftime("%d %b %Y") %></dd>
|
|
19
|
+
<% if @profile.date_of_exit %><dt>Exited</dt><dd><%= @profile.date_of_exit.strftime("%d %b %Y") %></dd><% end %>
|
|
20
|
+
<dt>Tax regime</dt><dd><%= @profile.tax_regime.humanize %></dd>
|
|
21
|
+
<dt>PAN</dt><dd><%= @profile.masked_pan || "—" %></dd>
|
|
22
|
+
<dt>UAN</dt><dd><%= @profile.masked_uan || "—" %></dd>
|
|
23
|
+
<dt>ESI</dt><dd><%= @profile.esi_number.present? ? "on file" : "—" %></dd>
|
|
24
|
+
<dt>Bank</dt><dd><%= [ @profile.bank_name, @profile.masked_account ].compact.join(" ").presence || "—" %></dd>
|
|
25
|
+
</dl>
|
|
26
|
+
</section>
|
|
27
|
+
|
|
28
|
+
<section class="hrl-card">
|
|
29
|
+
<h2 class="hrl-card__title">Salary structures</h2>
|
|
30
|
+
<% if @structures.any? %>
|
|
31
|
+
<div class="hrl-table-wrap">
|
|
32
|
+
<table class="hrl-table">
|
|
33
|
+
<thead><tr><th>Effective</th><th class="hrl-num">Basic</th><th class="hrl-num">Gross</th><th></th></tr></thead>
|
|
34
|
+
<tbody>
|
|
35
|
+
<% @structures.each do |structure| %>
|
|
36
|
+
<tr>
|
|
37
|
+
<td><%= structure.effective_from.strftime("%b %Y") %></td>
|
|
38
|
+
<td class="hrl-num"><%= hrl_money(structure.basic) %></td>
|
|
39
|
+
<td class="hrl-num"><%= hrl_money(structure.monthly_gross) %></td>
|
|
40
|
+
<td><a class="hrl-small" href="<%= hr_lite.edit_admin_employee_salary_structure_path(@profile, structure) %>">Edit</a></td>
|
|
41
|
+
</tr>
|
|
42
|
+
<% end %>
|
|
43
|
+
</tbody>
|
|
44
|
+
</table>
|
|
45
|
+
</div>
|
|
46
|
+
<% else %>
|
|
47
|
+
<p class="hrl-muted hrl-small">No structure yet — payroll will skip this employee.</p>
|
|
48
|
+
<% end %>
|
|
49
|
+
</section>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<section class="hrl-card">
|
|
53
|
+
<h2 class="hrl-card__title">Appraisals</h2>
|
|
54
|
+
<% appraisals = HrLite::Appraisal.where(user_id: @profile.user_id).recent_first %>
|
|
55
|
+
<% if appraisals.any? %>
|
|
56
|
+
<% appraisals.each do |appraisal| %>
|
|
57
|
+
<div class="hrl-feed__item">
|
|
58
|
+
<div class="hrl-feed__body">
|
|
59
|
+
<strong><%= appraisal.period_label %></strong>
|
|
60
|
+
<span class="hrl-badge <%= appraisal.shared? ? 'hrl-badge--ok' : 'hrl-badge--muted' %>"><%= appraisal.status.humanize %></span>
|
|
61
|
+
<% if appraisal.rating %><span class="hrl-badge"><%= appraisal.rating %>/5</span><% end %>
|
|
62
|
+
<% if appraisal.outcome != "none" %><span class="hrl-badge hrl-badge--warn"><%= appraisal.outcome.humanize %></span><% end %>
|
|
63
|
+
</div>
|
|
64
|
+
<% if appraisal.draft? %>
|
|
65
|
+
<a class="hrl-btn" href="<%= hr_lite.edit_admin_employee_appraisal_path(@profile, appraisal) %>">Edit</a>
|
|
66
|
+
<%= button_to "Share", hr_lite.share_admin_employee_appraisal_path(@profile, appraisal), method: :post,
|
|
67
|
+
class: "hrl-btn hrl-btn--primary",
|
|
68
|
+
form: { data: { turbo_confirm: "Share this appraisal with the employee? It becomes permanent." } } %>
|
|
69
|
+
<% end %>
|
|
70
|
+
</div>
|
|
71
|
+
<% end %>
|
|
72
|
+
<% else %>
|
|
73
|
+
<p class="hrl-muted hrl-small">No appraisals yet.</p>
|
|
74
|
+
<% end %>
|
|
75
|
+
</section>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Manage holidays" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Holidays <%= @year %></h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_holidays_path(year: @year - 1) %>"><%= @year - 1 %></a>
|
|
6
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_holidays_path(year: @year + 1) %>"><%= @year + 1 %></a>
|
|
7
|
+
</div>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<section class="hrl-card">
|
|
11
|
+
<% if @holidays.any? %>
|
|
12
|
+
<div class="hrl-table-wrap">
|
|
13
|
+
<table class="hrl-table hrl-table--stack">
|
|
14
|
+
<thead><tr><th>Date</th><th>Holiday</th><th>Optional</th><th></th></tr></thead>
|
|
15
|
+
<tbody>
|
|
16
|
+
<% @holidays.each do |holiday| %>
|
|
17
|
+
<tr>
|
|
18
|
+
<td data-label="Date"><%= holiday.date.strftime("%a, %d %b %Y") %></td>
|
|
19
|
+
<td data-label="Holiday"><%= holiday.name %></td>
|
|
20
|
+
<td data-label="Optional"><%= holiday.optional ? "Yes" : "No" %></td>
|
|
21
|
+
<td data-label="">
|
|
22
|
+
<%= button_to "Remove", hr_lite.admin_holiday_path(holiday), method: :delete,
|
|
23
|
+
class: "hrl-btn hrl-btn--danger hrl-small",
|
|
24
|
+
form: { data: { turbo_confirm: "Remove #{holiday.name}?" } } %>
|
|
25
|
+
</td>
|
|
26
|
+
</tr>
|
|
27
|
+
<% end %>
|
|
28
|
+
</tbody>
|
|
29
|
+
</table>
|
|
30
|
+
</div>
|
|
31
|
+
<% else %>
|
|
32
|
+
<p class="hrl-card--empty">No holidays for <%= @year %> yet.</p>
|
|
33
|
+
<% end %>
|
|
34
|
+
</section>
|
|
35
|
+
|
|
36
|
+
<div class="hrl-grid hrl-grid--2">
|
|
37
|
+
<section class="hrl-card">
|
|
38
|
+
<h2 class="hrl-card__title">Add one</h2>
|
|
39
|
+
<%= form_with model: @holiday, url: hr_lite.admin_holidays_path, local: true do |f| %>
|
|
40
|
+
<div class="hrl-field"><%= f.label :date %><%= f.date_field :date %></div>
|
|
41
|
+
<div class="hrl-field"><%= f.label :name %><%= f.text_field :name %></div>
|
|
42
|
+
<div class="hrl-field hrl-field--check"><%= f.check_box :optional %><%= f.label :optional, "Optional / restricted" %></div>
|
|
43
|
+
<div class="hrl-form-actions"><%= f.submit "Add holiday", class: "hrl-btn hrl-btn--primary" %></div>
|
|
44
|
+
<% end %>
|
|
45
|
+
</section>
|
|
46
|
+
|
|
47
|
+
<section class="hrl-card">
|
|
48
|
+
<h2 class="hrl-card__title">Bulk paste</h2>
|
|
49
|
+
<p class="hrl-small hrl-muted">One per line: <code>YYYY-MM-DD, Name</code> (append <code>, optional</code> for restricted holidays). Duplicates are skipped.</p>
|
|
50
|
+
<%= form_with url: hr_lite.bulk_create_admin_holidays_path, method: :post, local: true do %>
|
|
51
|
+
<div class="hrl-field">
|
|
52
|
+
<textarea name="lines" class="hrl-input" rows="6" placeholder="2026-11-09, Diwali 2026-03-04, Holi"></textarea>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="hrl-form-actions">
|
|
55
|
+
<button type="submit" class="hrl-btn hrl-btn--primary">Add all</button>
|
|
56
|
+
</div>
|
|
57
|
+
<% end %>
|
|
58
|
+
</section>
|
|
59
|
+
</div>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Team balances" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Team leave balances <%= @year %></h1>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<section class="hrl-card">
|
|
7
|
+
<div class="hrl-table-wrap">
|
|
8
|
+
<table class="hrl-table">
|
|
9
|
+
<thead>
|
|
10
|
+
<tr><th>Employee</th><% @types.each do |type| %><th class="hrl-num"><%= type.code %></th><% end %></tr>
|
|
11
|
+
</thead>
|
|
12
|
+
<tbody>
|
|
13
|
+
<% @employees.each do |employee| %>
|
|
14
|
+
<tr>
|
|
15
|
+
<td><%= hr_display_name(employee) %></td>
|
|
16
|
+
<% @types.each do |type| %>
|
|
17
|
+
<% balance = HrLite::LeaveBalance.for(employee, type, @year) %>
|
|
18
|
+
<td class="hrl-num"><%= balance.available.to_f %></td>
|
|
19
|
+
<% end %>
|
|
20
|
+
</tr>
|
|
21
|
+
<% end %>
|
|
22
|
+
</tbody>
|
|
23
|
+
</table>
|
|
24
|
+
</div>
|
|
25
|
+
</section>
|
|
26
|
+
|
|
27
|
+
<section class="hrl-card">
|
|
28
|
+
<h2 class="hrl-card__title">Adjust a balance</h2>
|
|
29
|
+
<p class="hrl-small hrl-muted">Positive credits (comp-off), negative debits. Fully audited.</p>
|
|
30
|
+
<%= form_with url: hr_lite.adjust_admin_leave_balances_path, method: :post, local: true do %>
|
|
31
|
+
<div class="hrl-field">
|
|
32
|
+
<label for="adj_user">Employee</label>
|
|
33
|
+
<select name="user_id" id="adj_user" class="hrl-input">
|
|
34
|
+
<% @employees.each do |employee| %>
|
|
35
|
+
<option value="<%= employee.id %>"><%= hr_display_name(employee) %></option>
|
|
36
|
+
<% end %>
|
|
37
|
+
</select>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="hrl-field">
|
|
40
|
+
<label for="adj_type">Leave type</label>
|
|
41
|
+
<select name="leave_type_id" id="adj_type" class="hrl-input">
|
|
42
|
+
<% @types.each do |type| %><option value="<%= type.id %>"><%= type.name %></option><% end %>
|
|
43
|
+
</select>
|
|
44
|
+
</div>
|
|
45
|
+
<input type="hidden" name="year" value="<%= @year %>">
|
|
46
|
+
<div class="hrl-field">
|
|
47
|
+
<label for="adj_delta">Days (+/-)</label>
|
|
48
|
+
<input type="number" step="0.5" name="delta" id="adj_delta" class="hrl-input" required>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="hrl-field">
|
|
51
|
+
<label for="adj_note">Note (required)</label>
|
|
52
|
+
<input type="text" name="note" id="adj_note" class="hrl-input" required>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="hrl-form-actions">
|
|
55
|
+
<button class="hrl-btn hrl-btn--primary" type="submit">Apply adjustment</button>
|
|
56
|
+
</div>
|
|
57
|
+
<% end %>
|
|
58
|
+
</section>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Leave approvals" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Leave approvals</h1>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div class="hrl-row" style="margin-bottom:.8rem;">
|
|
7
|
+
<% HrLite::LeaveRequest::STATUSES.each do |status| %>
|
|
8
|
+
<a class="hrl-btn <%= 'hrl-btn--primary' if @status == status %>"
|
|
9
|
+
href="<%= hr_lite.admin_leave_requests_path(status: status) %>"><%= status.humanize %></a>
|
|
10
|
+
<% end %>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<section class="hrl-card">
|
|
14
|
+
<% if @requests.any? %>
|
|
15
|
+
<div class="hrl-table-wrap">
|
|
16
|
+
<table class="hrl-table hrl-table--stack">
|
|
17
|
+
<thead><tr><th>Employee</th><th>Type</th><th>Dates</th><th>Days</th><th></th></tr></thead>
|
|
18
|
+
<tbody>
|
|
19
|
+
<% @requests.each do |request| %>
|
|
20
|
+
<tr>
|
|
21
|
+
<td data-label="Employee"><%= hr_display_name(request.user) %></td>
|
|
22
|
+
<td data-label="Type"><%= request.leave_type.name %></td>
|
|
23
|
+
<td data-label="Dates"><%= request.date_range_label %></td>
|
|
24
|
+
<td data-label="Days" class="hrl-num"><%= request.days_count.to_f %></td>
|
|
25
|
+
<td data-label=""><a class="hrl-btn" href="<%= hr_lite.admin_leave_request_path(request) %>">Open</a></td>
|
|
26
|
+
</tr>
|
|
27
|
+
<% end %>
|
|
28
|
+
</tbody>
|
|
29
|
+
</table>
|
|
30
|
+
</div>
|
|
31
|
+
<%= hrl_pagination %>
|
|
32
|
+
<% else %>
|
|
33
|
+
<p class="hrl-card--empty">No <%= @status %> requests.</p>
|
|
34
|
+
<% end %>
|
|
35
|
+
</section>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Leave decision" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title"><%= hr_display_name(@request.user) %></h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_leave_requests_path %>">Back</a>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<section class="hrl-card">
|
|
10
|
+
<dl class="hrl-deflist">
|
|
11
|
+
<dt>Type</dt><dd><%= @request.leave_type.name %> (<%= @request.paid? ? "paid" : "unpaid" %>)</dd>
|
|
12
|
+
<dt>Dates</dt><dd><%= @request.date_range_label %></dd>
|
|
13
|
+
<dt>Working days</dt><dd><%= @request.days_count.to_f %></dd>
|
|
14
|
+
<dt>Status</dt><dd><span class="hrl-badge"><%= @request.status.humanize %></span></dd>
|
|
15
|
+
<% if @request.reason.present? %><dt>Reason</dt><dd><%= @request.reason %></dd><% end %>
|
|
16
|
+
<% unless @request.leave_type.unlimited? %>
|
|
17
|
+
<dt>Balance</dt>
|
|
18
|
+
<dd><%= @balance.available.to_f %> of <%= @balance.entitled.to_f %> available</dd>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% if @request.decision_note.present? %><dt>Decision note</dt><dd><%= @request.decision_note %></dd><% end %>
|
|
21
|
+
</dl>
|
|
22
|
+
</section>
|
|
23
|
+
|
|
24
|
+
<% if @request.pending? %>
|
|
25
|
+
<section class="hrl-card">
|
|
26
|
+
<h2 class="hrl-card__title">Decide</h2>
|
|
27
|
+
<%= form_with url: hr_lite.approve_admin_leave_request_path(@request), method: :post, local: true do %>
|
|
28
|
+
<div class="hrl-field">
|
|
29
|
+
<label for="decision_note">Note (required to reject)</label>
|
|
30
|
+
<textarea name="decision_note" id="decision_note" class="hrl-input"></textarea>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="hrl-form-actions">
|
|
33
|
+
<button class="hrl-btn hrl-btn--primary" type="submit">Approve</button>
|
|
34
|
+
<button class="hrl-btn hrl-btn--danger" type="submit"
|
|
35
|
+
formaction="<%= hr_lite.reject_admin_leave_request_path(@request) %>">Reject</button>
|
|
36
|
+
</div>
|
|
37
|
+
<% end %>
|
|
38
|
+
</section>
|
|
39
|
+
<% end %>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<section class="hrl-card">
|
|
2
|
+
<%= form_with model: leave_type, url: url, method: method, local: true do |f| %>
|
|
3
|
+
<%= render "hr_lite/shared/form_errors", record: leave_type %>
|
|
4
|
+
<div class="hrl-field"><%= f.label :name %><%= f.text_field :name %></div>
|
|
5
|
+
<div class="hrl-field"><%= f.label :code %><%= f.text_field :code %></div>
|
|
6
|
+
<div class="hrl-field"><%= f.label :color %><%= f.color_field :color %></div>
|
|
7
|
+
<div class="hrl-field">
|
|
8
|
+
<%= f.label :annual_quota, "Annual quota (blank = unlimited)" %>
|
|
9
|
+
<%= f.number_field :annual_quota, step: 0.5 %>
|
|
10
|
+
</div>
|
|
11
|
+
<div class="hrl-field">
|
|
12
|
+
<%= f.label :accrual %>
|
|
13
|
+
<%= f.select :accrual, HrLite::LeaveType::ACCRUALS.map { |a| [ a.humanize, a ] } %>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="hrl-field">
|
|
16
|
+
<%= f.label :carry_forward_cap, "Carry-forward cap" %>
|
|
17
|
+
<%= f.number_field :carry_forward_cap, step: 0.5 %>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="hrl-field"><%= f.label :position %><%= f.number_field :position %></div>
|
|
20
|
+
<div class="hrl-field hrl-field--check"><%= f.check_box :paid %><%= f.label :paid %></div>
|
|
21
|
+
<div class="hrl-field hrl-field--check"><%= f.check_box :active %><%= f.label :active %></div>
|
|
22
|
+
<div class="hrl-form-actions">
|
|
23
|
+
<%= f.submit "Save", class: "hrl-btn hrl-btn--primary" %>
|
|
24
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_leave_types_path %>">Cancel</a>
|
|
25
|
+
</div>
|
|
26
|
+
<% end %>
|
|
27
|
+
</section>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Edit leave type" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Edit <%= @leave_type.name %></h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<%= button_to "Delete", hr_lite.admin_leave_type_path(@leave_type), method: :delete,
|
|
6
|
+
class: "hrl-btn hrl-btn--danger",
|
|
7
|
+
form: { data: { turbo_confirm: "Delete this leave type?" } } %>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
<%= render "form", leave_type: @leave_type, url: hr_lite.admin_leave_type_path(@leave_type), method: :patch %>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<% content_for(:page_title) { "Leave types" } %>
|
|
2
|
+
<div class="hrl-page__head">
|
|
3
|
+
<h1 class="hrl-page__title">Leave types & policy</h1>
|
|
4
|
+
<div class="hrl-page__actions">
|
|
5
|
+
<a class="hrl-btn hrl-btn--primary" href="<%= hr_lite.new_admin_leave_type_path %>">Add type</a>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<section class="hrl-card">
|
|
10
|
+
<div class="hrl-table-wrap">
|
|
11
|
+
<table class="hrl-table hrl-table--stack">
|
|
12
|
+
<thead><tr><th>Type</th><th>Quota</th><th>Accrual</th><th>Carry cap</th><th>Paid</th><th></th></tr></thead>
|
|
13
|
+
<tbody>
|
|
14
|
+
<% @leave_types.each do |type| %>
|
|
15
|
+
<tr>
|
|
16
|
+
<td data-label="Type">
|
|
17
|
+
<span class="hrl-badge" style="background: <%= type.color %>1f; color: <%= type.color %>;"><%= type.code %></span>
|
|
18
|
+
<%= type.name %>
|
|
19
|
+
<% unless type.active %><span class="hrl-badge hrl-badge--muted">Inactive</span><% end %>
|
|
20
|
+
</td>
|
|
21
|
+
<td data-label="Quota" class="hrl-num"><%= type.unlimited? ? "Unlimited" : type.annual_quota.to_f %></td>
|
|
22
|
+
<td data-label="Accrual"><%= type.accrual.humanize %></td>
|
|
23
|
+
<td data-label="Carry cap" class="hrl-num"><%= type.carry_forward_cap.to_f %></td>
|
|
24
|
+
<td data-label="Paid"><%= type.paid ? "Yes" : "No" %></td>
|
|
25
|
+
<td data-label="">
|
|
26
|
+
<a class="hrl-small" href="<%= hr_lite.edit_admin_leave_type_path(type) %>">Edit</a>
|
|
27
|
+
</td>
|
|
28
|
+
</tr>
|
|
29
|
+
<% end %>
|
|
30
|
+
</tbody>
|
|
31
|
+
</table>
|
|
32
|
+
</div>
|
|
33
|
+
</section>
|
|
34
|
+
|
|
35
|
+
<div class="hrl-row">
|
|
36
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_office_locations_path %>">Office locations</a>
|
|
37
|
+
<a class="hrl-btn" href="<%= hr_lite.admin_holidays_path %>">Holidays</a>
|
|
38
|
+
<a class="hrl-btn" href="<%= hr_lite.edit_admin_setting_path %>">Weekend policy</a>
|
|
39
|
+
</div>
|