hr_lite 0.57.1 → 0.58.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 +9 -0
- data/README.md +1 -0
- data/app/controllers/hr_lite/home_controller.rb +3 -1
- data/app/jobs/hr_lite/team_notices_job.rb +26 -0
- data/app/models/hr_lite/employee_profile.rb +13 -0
- data/app/views/hr_lite/home/index.html.erb +16 -0
- data/app/views/hr_lite/leave_requests/_out_list.html.erb +1 -1
- data/lib/hr_lite/notifications.rb +3 -0
- data/lib/hr_lite/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c02612fcf572f2b42eab074882c2c07b975e9e272b6b94eb58b3a40edb00cdc
|
|
4
|
+
data.tar.gz: a537c7010fc7e5c5bbfc5e85eaa62d4afb4bc5b04eae953500d64ed5f4d1530e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 54ca6bb8b70ce33601c8d163caf80556bdec2c653b0360f4d3ff418b0180a14fe2487292ef83499d989c5b064b919857bb083197789fef628bf42f736544a6c5
|
|
7
|
+
data.tar.gz: cf2c5930379f973d7a08870b87e3b3c7c28117e4f09921f5465702117c931195203df20292d4532e4b40ce4708479be770627acf7fa5e0a524791c5c81e1db5a
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.58.0] - 2026-10-21
|
|
11
|
+
|
|
12
|
+
Leave and birthdays for the whole team, Keka-style. No migrations. Hosts schedule `HrLite::TeamNoticesJob` daily at 10am.
|
|
13
|
+
|
|
14
|
+
- **Pending leave shows on Home.** "On leave this week" lists pending requests too, tagged "Pending approval". Approval is management's decision, not a reason to hide the leave.
|
|
15
|
+
- **10am "On leave today" email** to every current employee: name and dates, never the leave type. No one out, no email.
|
|
16
|
+
- **10am "Birthdays today" email**, same rules. A 29 Feb birthday falls on 28 Feb outside leap years.
|
|
17
|
+
- **Birthdays this week** card on Home, Monday to Sunday, today marked.
|
|
18
|
+
|
|
10
19
|
## [0.57.1] - 2026-10-19
|
|
11
20
|
|
|
12
21
|
Forms in the host's iOS and Android staff apps (D24). No migrations.
|
data/README.md
CHANGED
|
@@ -384,6 +384,7 @@ whatever you run). Each is idempotent and sends nothing on a quiet day.
|
|
|
384
384
|
| Job | Schedule | Purpose |
|
|
385
385
|
|---|---|---|
|
|
386
386
|
| `HrLite::DailyDigestJob` | each morning | Leadership digest: who is out today, pending approvals, flagged punches, missing checkouts |
|
|
387
|
+
| `HrLite::TeamNoticesJob` | daily, 10am | Emails every current employee who is on leave today and whose birthday it is; each email is skipped when its list is empty |
|
|
387
388
|
| `HrLite::PayrollAutoDraftJob` | monthly, on the 1st | Draft and compute the previous month's payroll from attendance, then notify the approvers (`payroll.approve`) and payroll operators |
|
|
388
389
|
| `HrLite::CaReviewReminderJob` | weekly (it acts only in March) | Tell CA reviewers how many slips and declarations are still unverified before 31 March |
|
|
389
390
|
| `HrLite::CaReviewOverdueJob` | 31 March, evening | Tell payroll and HR what the CA has not verified, and any flags left open |
|
|
@@ -3,9 +3,11 @@ module HrLite
|
|
|
3
3
|
def index
|
|
4
4
|
@latest_kudos = Kudo.recent.includes(:giver, kudo_mentions: :user).limit(3)
|
|
5
5
|
@awards = Award.current
|
|
6
|
-
|
|
6
|
+
# Pending shows too: approval is management's call, not a reason to hide the leave.
|
|
7
|
+
@out_week = LeaveRequest.where(status: %w[pending approved]).overlapping_range(Date.current, Date.current.end_of_week)
|
|
7
8
|
.includes(:user).where(user_id: HrLite.active_employees.map(&:id))
|
|
8
9
|
.sort_by { |leave| hr_display_name(leave.user).downcase }
|
|
10
|
+
@birthdays = EmployeeProfile.birthdays_in(Date.current.all_week)
|
|
9
11
|
@attention = attention_days
|
|
10
12
|
@waiting = Approval.pending_for(hr_current_user).count
|
|
11
13
|
@mine_pending = [ LeaveRequest.includes(:leave_type), RegularizationRequest, CompOffRequest, WfhRequest ]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module HrLite
|
|
2
|
+
# 10am email to every current employee: who is on leave today, whose
|
|
3
|
+
# birthday it is. Each goes only when its list has someone on it.
|
|
4
|
+
class TeamNoticesJob < ApplicationJob
|
|
5
|
+
queue_as :default
|
|
6
|
+
|
|
7
|
+
def perform(date: Date.current)
|
|
8
|
+
staff = HrLite.active_employees(on: date)
|
|
9
|
+
out = LeaveRequest.where(status: %w[pending approved], user_id: staff.map(&:id))
|
|
10
|
+
.overlapping_range(date, date).includes(:user)
|
|
11
|
+
announce("leave.out_today", "On leave today", staff, date,
|
|
12
|
+
out.map { |l| "#{HrLite.display_name(l.user)} — #{l.date_range_label}#{' (pending approval)' if l.pending?}" })
|
|
13
|
+
announce("birthday.today", "Birthdays today", staff, date,
|
|
14
|
+
EmployeeProfile.birthdays_in(date..date).map { |p, _| "Happy birthday, #{HrLite.display_name(p.user)}" })
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def announce(event, title, staff, date, lines)
|
|
20
|
+
return if lines.empty?
|
|
21
|
+
|
|
22
|
+
Notifications.publish(event, title: "#{title} — #{date.strftime('%a %-d %b')}", lines: lines.sort,
|
|
23
|
+
email_to: staff, path: "/")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -101,6 +101,19 @@ module HrLite
|
|
|
101
101
|
date_of_joining <= date && (date_of_exit.nil? || date_of_exit >= date)
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
+
# 29 Feb birthdays fall on 28 Feb outside leap years.
|
|
105
|
+
def birthday_in(year)
|
|
106
|
+
day = Date.valid_date?(year, date_of_birth.month, date_of_birth.day) ? date_of_birth.day : 28
|
|
107
|
+
Date.new(year, date_of_birth.month, day)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# [profile, day] for current staff whose birthday falls in `range`, earliest first.
|
|
111
|
+
def self.birthdays_in(range)
|
|
112
|
+
where(user_id: HrLite.active_employees(on: range.first).map(&:id)).where.not(date_of_birth: nil).includes(:user)
|
|
113
|
+
.filter_map { |p| (day = range.find { |d| p.birthday_in(d.year) == d }) && [ p, day ] }
|
|
114
|
+
.sort_by { |p, day| [ day, HrLite.display_name(p.user).downcase ] }
|
|
115
|
+
end
|
|
116
|
+
|
|
104
117
|
def employment_range_in(month)
|
|
105
118
|
from = [ date_of_joining, month.beginning_of_month ].max
|
|
106
119
|
to = [ date_of_exit || month.end_of_month, month.end_of_month ].min
|
|
@@ -40,6 +40,22 @@
|
|
|
40
40
|
<%= render "hr_lite/leave_requests/out_list", leaves: @out_week, empty: "Nobody is on leave this week." %>
|
|
41
41
|
</section>
|
|
42
42
|
|
|
43
|
+
<section class="hrl-card">
|
|
44
|
+
<h2 class="hrl-card__title">Birthdays this week</h2>
|
|
45
|
+
<% if @birthdays.any? %>
|
|
46
|
+
<div class="hrl-feed">
|
|
47
|
+
<% @birthdays.each do |profile, day| %>
|
|
48
|
+
<div class="hrl-feed__item">
|
|
49
|
+
<div class="hrl-feed__body"><strong><%= hr_display_name(profile.user) %></strong>
|
|
50
|
+
<div class="hrl-feed__meta"><%= day == Date.current ? "Today" : day.strftime("%a %-d %b") %></div></div>
|
|
51
|
+
</div>
|
|
52
|
+
<% end %>
|
|
53
|
+
</div>
|
|
54
|
+
<% else %>
|
|
55
|
+
<p class="hrl-muted hrl-small">No birthdays this week.</p>
|
|
56
|
+
<% end %>
|
|
57
|
+
</section>
|
|
58
|
+
|
|
43
59
|
<% if @awards.any? %>
|
|
44
60
|
<section class="hrl-card">
|
|
45
61
|
<h2 class="hrl-card__title">Employee of the month, quarter and year</h2>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<% leaves.first(10).each do |leave| %>
|
|
5
5
|
<div class="hrl-feed__item">
|
|
6
6
|
<div class="hrl-feed__body"><%= tag.strong hr_display_name(leave.user), title: "On leave: #{leave.date_range_label}" %>
|
|
7
|
-
<div class="hrl-feed__meta"><%= leave.date_range_label %></div></div>
|
|
7
|
+
<div class="hrl-feed__meta"><%= leave.date_range_label %><%= " · Pending approval" if leave.pending? %></div></div>
|
|
8
8
|
</div>
|
|
9
9
|
<% end %>
|
|
10
10
|
</div>
|
|
@@ -56,6 +56,9 @@ module HrLite
|
|
|
56
56
|
"policy.published" => { bell: true, email: true, leadership_email: false, leadership_bell: false },
|
|
57
57
|
"holiday.published" => { bell: true, email: true, leadership_email: false, leadership_bell: false },
|
|
58
58
|
"digest.daily" => { bell: false, email: false, leadership_email: true, leadership_bell: false },
|
|
59
|
+
# 10am team emails (TeamNoticesJob) to every current employee; skipped when the list is empty.
|
|
60
|
+
"leave.out_today" => { bell: false, email: true, leadership_email: false, leadership_bell: false },
|
|
61
|
+
"birthday.today" => { bell: false, email: true, leadership_email: false, leadership_bell: false },
|
|
59
62
|
"resignation.submitted" => { bell: true, email: false, leadership_email: true, leadership_bell: true },
|
|
60
63
|
"resignation.accepted" => { bell: true, email: true, leadership_email: true, leadership_bell: false },
|
|
61
64
|
"resignation.withdrawn" => { bell: true, email: false, leadership_email: true, leadership_bell: false },
|
data/lib/hr_lite/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hr_lite
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.58.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kshitiz sinha
|
|
@@ -173,6 +173,7 @@ files:
|
|
|
173
173
|
- app/jobs/hr_lite/payroll_auto_draft_job.rb
|
|
174
174
|
- app/jobs/hr_lite/payroll_compute_job.rb
|
|
175
175
|
- app/jobs/hr_lite/slips_ready_job.rb
|
|
176
|
+
- app/jobs/hr_lite/team_notices_job.rb
|
|
176
177
|
- app/jobs/hr_lite/work_mode_expire_job.rb
|
|
177
178
|
- app/mailers/hr_lite/application_mailer.rb
|
|
178
179
|
- app/mailers/hr_lite/event_mailer.rb
|