hr_lite 0.60.0 → 0.62.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/README.md +18 -0
  4. data/app/assets/javascripts/hr_lite/select_all.js +21 -0
  5. data/app/assets/stylesheets/hr_lite/hr_lite.css +26 -0
  6. data/app/controllers/hr_lite/admin/hiring_campaigns_controller.rb +96 -0
  7. data/app/controllers/hr_lite/admin/hiring_candidates_controller.rb +50 -0
  8. data/app/controllers/hr_lite/admin/hiring_interviews_controller.rb +77 -0
  9. data/app/controllers/hr_lite/admin/hiring_sends_controller.rb +62 -0
  10. data/app/controllers/hr_lite/admin/hiring_templates_controller.rb +71 -0
  11. data/app/controllers/hr_lite/hiring_replies_controller.rb +32 -0
  12. data/app/helpers/hr_lite/application_helper.rb +38 -0
  13. data/app/jobs/hr_lite/hiring_send_job.rb +42 -0
  14. data/app/models/hr_lite/hiring_campaign.rb +23 -0
  15. data/app/models/hr_lite/hiring_candidate.rb +56 -0
  16. data/app/models/hr_lite/hiring_interview.rb +13 -0
  17. data/app/models/hr_lite/hiring_message.rb +14 -0
  18. data/app/models/hr_lite/hiring_reply.rb +144 -0
  19. data/app/models/hr_lite/hiring_template.rb +11 -0
  20. data/app/services/hr_lite/hiring_import.rb +106 -0
  21. data/app/services/hr_lite/hiring_merge.rb +54 -0
  22. data/app/views/hr_lite/admin/hiring_campaigns/_form.html.erb +19 -0
  23. data/app/views/hr_lite/admin/hiring_campaigns/edit.html.erb +3 -0
  24. data/app/views/hr_lite/admin/hiring_campaigns/import.html.erb +18 -0
  25. data/app/views/hr_lite/admin/hiring_campaigns/index.html.erb +21 -0
  26. data/app/views/hr_lite/admin/hiring_campaigns/new.html.erb +3 -0
  27. data/app/views/hr_lite/admin/hiring_campaigns/preview.html.erb +62 -0
  28. data/app/views/hr_lite/admin/hiring_campaigns/show.html.erb +106 -0
  29. data/app/views/hr_lite/admin/hiring_candidates/show.html.erb +186 -0
  30. data/app/views/hr_lite/admin/hiring_sends/new.html.erb +34 -0
  31. data/app/views/hr_lite/admin/hiring_templates/_form.html.erb +20 -0
  32. data/app/views/hr_lite/admin/hiring_templates/edit.html.erb +43 -0
  33. data/app/views/hr_lite/admin/hiring_templates/index.html.erb +15 -0
  34. data/app/views/hr_lite/admin/hiring_templates/new.html.erb +3 -0
  35. data/app/views/hr_lite/hiring_replies/show.html.erb +105 -0
  36. data/app/views/layouts/hr_lite/application.html.erb +1 -0
  37. data/app/views/layouts/hr_lite/public.html.erb +21 -0
  38. data/config/routes.rb +14 -0
  39. data/db/migrate/20261021100000_create_hr_lite_hiring_campaigns.rb +15 -0
  40. data/db/migrate/20261021100100_create_hr_lite_hiring_candidates.rb +22 -0
  41. data/db/migrate/20261021100200_create_hr_lite_hiring_templates.rb +10 -0
  42. data/db/migrate/20261021100300_create_hr_lite_hiring_messages.rb +19 -0
  43. data/db/migrate/20261021100400_create_hr_lite_hiring_interviews.rb +16 -0
  44. data/db/migrate/20261021100500_seed_hr_lite_hiring.rb +43 -0
  45. data/db/migrate/20261022090000_create_hr_lite_hiring_replies.rb +26 -0
  46. data/db/migrate/20261022090100_add_allow_sunday_to_hr_lite_hiring_campaigns.rb +6 -0
  47. data/lib/hr_lite/configuration.rb +14 -1
  48. data/lib/hr_lite/permissions.rb +2 -1
  49. data/lib/hr_lite/role_seeds.rb +2 -2
  50. data/lib/hr_lite/version.rb +1 -1
  51. data/lib/hr_lite.rb +6 -0
  52. metadata +40 -1
@@ -0,0 +1,10 @@
1
+ class CreateHrLiteHiringTemplates < ActiveRecord::Migration[8.1]
2
+ def change
3
+ create_table :hr_lite_hiring_templates do |t|
4
+ t.string :name, null: false
5
+ t.string :subject, null: false
6
+ t.text :body, null: false
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ class CreateHrLiteHiringMessages < ActiveRecord::Migration[8.1]
2
+ def change
3
+ create_table :hr_lite_hiring_messages do |t|
4
+ t.references :candidate, null: false, foreign_key: { to_table: :hr_lite_hiring_candidates }
5
+ t.references :template, null: false, foreign_key: { to_table: :hr_lite_hiring_templates }
6
+ t.string :batch, null: false
7
+ t.string :status, null: false, default: "queued"
8
+ t.string :gmail_message_id
9
+ t.string :gmail_thread_id
10
+ t.string :error
11
+ t.datetime :sent_at
12
+ t.bigint :sent_by_id
13
+ t.timestamps
14
+ end
15
+ # One send of a template per candidate: double clicks and job redelivery cannot repeat it.
16
+ add_index :hr_lite_hiring_messages, %i[candidate_id template_id], unique: true
17
+ add_index :hr_lite_hiring_messages, :batch
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ class CreateHrLiteHiringInterviews < ActiveRecord::Migration[8.1]
2
+ def change
3
+ create_table :hr_lite_hiring_interviews do |t|
4
+ t.references :candidate, null: false, foreign_key: { to_table: :hr_lite_hiring_candidates }
5
+ t.integer :round, null: false
6
+ t.datetime :starts_at, null: false
7
+ t.datetime :ends_at, null: false
8
+ t.string :status, null: false, default: "scheduled"
9
+ t.string :event_id
10
+ t.string :meet_link
11
+ t.string :error
12
+ t.timestamps
13
+ end
14
+ add_index :hr_lite_hiring_interviews, %i[candidate_id round]
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ class SeedHrLiteHiring < ActiveRecord::Migration[8.1]
2
+ # hiring.manage is new in 0.61.0. RoleSeeds only creates missing roles, so
3
+ # the existing HR, Leadership and Super Admin roles get it here. Also seeds
4
+ # the first outreach email so HR starts from the approved wording.
5
+ BODY = <<~TEXT.freeze
6
+ Hi @first_name,
7
+
8
+ I hope you're doing well.
9
+
10
+ I've gone through your profile and CV, and I believe your experience could be a good fit for the @position position at escapes.asia
11
+
12
+ Before proceeding with the interview process, we'd like to confirm your interest and comfort with the following details:
13
+
14
+ Position: @position
15
+ Programme: @programme
16
+ Monthly Stipend: @stipend
17
+ Full-Time CTC: @ctc, subject to performance and successful completion of the programme
18
+ Work Location: @location
19
+ Work Schedule: @schedule
20
+
21
+ The programme includes structured training during the first three months, followed by performance reviews and continued hands-on experience. Progression to a full-time role is merit-based and depends on performance throughout the programme.
22
+
23
+ Please reply to confirm your interest and availability. Once we receive your confirmation, we'll share the interview schedule and further details.
24
+
25
+ Looking forward to hearing from you.
26
+
27
+ Best,
28
+ @sender_name
29
+ TEXT
30
+
31
+ def up
32
+ HrLite::Role.where(name: [ "HR", "Leadership", "Super Admin" ]).find_each do |role|
33
+ HrLite::RoleGrant.find_or_initialize_by(role: role, permission_key: "hiring.manage").update!(scope: "all")
34
+ end
35
+ execute <<~SQL
36
+ INSERT INTO hr_lite_hiring_templates (name, subject, body, created_at, updated_at)
37
+ VALUES (#{connection.quote("Interest check")}, #{connection.quote("@position at escapes.asia: please confirm your interest")},
38
+ #{connection.quote(BODY)}, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
39
+ SQL
40
+ end
41
+
42
+ def down; end
43
+ end
@@ -0,0 +1,26 @@
1
+ class CreateHrLiteHiringReplies < ActiveRecord::Migration[8.1]
2
+ # One reply link per candidate per interview round: their answers, the day
3
+ # and 2-hour slot they picked, an optional alternate phone, and (from round
4
+ # 2) their documents through Active Storage, stored encrypted. Round 3 adds
5
+ # the joining KYC: Aadhaar, PAN (or "PAN pending") and salary slips.
6
+ def change
7
+ create_table :hr_lite_hiring_replies do |t|
8
+ t.references :candidate, null: false, foreign_key: { to_table: :hr_lite_hiring_candidates }
9
+ t.integer :round, null: false
10
+ t.string :token, null: false
11
+ t.json :answers, null: false, default: {}
12
+ t.text :alternate_phone
13
+ t.text :aadhaar_number
14
+ t.text :pan_number
15
+ t.boolean :pan_pending, null: false, default: false
16
+ t.boolean :no_salary_slips, null: false, default: false
17
+ t.date :preferred_date
18
+ t.string :preferred_slot
19
+ t.datetime :responded_at
20
+ t.timestamps
21
+ end
22
+ add_index :hr_lite_hiring_replies, :token, unique: true
23
+ add_index :hr_lite_hiring_replies, %i[candidate_id round], unique: true
24
+ add_index :hr_lite_hiring_replies, %i[preferred_date preferred_slot]
25
+ end
26
+ end
@@ -0,0 +1,6 @@
1
+ class AddAllowSundayToHrLiteHiringCampaigns < ActiveRecord::Migration[8.1]
2
+ # Sunday is off; HR can open it for one campaign's interview slots.
3
+ def change
4
+ add_column :hr_lite_hiring_campaigns, :allow_sunday, :boolean, null: false, default: false
5
+ end
6
+ end
@@ -35,7 +35,13 @@ module HrLite
35
35
  # ->(user, query) { [{ id:, label: }] } — leads to link to a client meeting
36
36
  :crm_search,
37
37
  # ->(id) { { label:, url: } or nil } — one lead, to validate and link it
38
- :crm_find
38
+ :crm_find,
39
+ # An object with sender, send_email, create_event, update_event and
40
+ # cancel_event (see README, Hiring). nil = hiring cannot send or schedule.
41
+ :hiring,
42
+ # ->(path, filename) { rows as arrays, headers first } — reads an
43
+ # uploaded candidate sheet. Default: .csv only.
44
+ :read_sheet
39
45
 
40
46
  attr_reader :leave_year_start_month, :slip_release_day, :self_regularization, :work_hours
41
47
 
@@ -124,6 +130,13 @@ module HrLite
124
130
  @require_punch_location = false
125
131
  @attendance_slots = false
126
132
  @office_geofence = false
133
+ @hiring = nil
134
+ @read_sheet = ->(path, filename) {
135
+ raise ArgumentError, "Upload the sheet as a .csv file." unless filename.to_s.downcase.end_with?(".csv")
136
+
137
+ require "csv"
138
+ CSV.read(path, encoding: "bom|utf-8")
139
+ }
127
140
  @work_hours = nil # e.g. { day: 8, probation_day: 9, week: 40 } — short days close as half days
128
141
 
129
142
  # Leadership onboarding/offboarding. onboard_user must return a saved
@@ -65,7 +65,8 @@ module HrLite
65
65
  "settings.manage" => [ "Administration", "Change company settings, offices and policy" ],
66
66
  "audit.view" => [ "Administration", "Read the audit trail" ],
67
67
  "audit.view_money" => [ "Administration", "Read audit rows about pay, appraisals and promotions" ],
68
- "role.manage" => [ "Administration", "Create roles and grant permissions" ]
68
+ "role.manage" => [ "Administration", "Create roles and grant permissions" ],
69
+ "hiring.manage" => [ "Hiring", "Import candidates, email them from the hiring mailbox, schedule interviews and decide" ]
69
70
  }.freeze
70
71
 
71
72
  KEYS = REGISTRY.keys.freeze
@@ -42,7 +42,7 @@ module HrLite
42
42
  "expense.claim" => "self", "benefit.view" => "all", "benefit.manage" => "all",
43
43
  "hr_request.raise" => "self", "hr_request.manage" => "all", "policy.view" => "all",
44
44
  "asset.view" => "all", "asset.manage" => "all", "checklist.manage" => "all",
45
- "work_analytics.view" => "all"
45
+ "work_analytics.view" => "all", "hiring.manage" => "all"
46
46
  }
47
47
  },
48
48
  Role::FINANCE => {
@@ -69,7 +69,7 @@ module HrLite
69
69
  "document.view" => "all", "expense.approve" => "all", "benefit.manage" => "all",
70
70
  "hr_request.manage" => "all", "policy.view" => "all", "policy.manage" => "all",
71
71
  "asset.view" => "all", "asset.manage" => "all", "checklist.manage" => "all",
72
- "work_analytics.view" => "all"
72
+ "work_analytics.view" => "all", "hiring.manage" => "all"
73
73
  }
74
74
  },
75
75
  Role::CA => {
@@ -1,3 +1,3 @@
1
1
  module HrLite
2
- VERSION = "0.60.0"
2
+ VERSION = "0.62.0"
3
3
  end
data/lib/hr_lite.rb CHANGED
@@ -17,6 +17,12 @@ require "hr_lite/amount_in_words"
17
17
  require "hr_lite/statutory_rate_card"
18
18
 
19
19
  module HrLite
20
+ # Raised by a host hiring adapter. Failed: Google refused, nothing was sent.
21
+ # Unknown: Google may or may not have acted (a timeout, a 5xx), so the row is
22
+ # marked for a person to check and never retried by itself.
23
+ HiringDeliveryFailed = Class.new(StandardError)
24
+ HiringDeliveryUnknown = Class.new(StandardError)
25
+
20
26
  # Full day / first half / second half — one picker for leave and attendance.
21
27
  DAY_PARTS = [ [ "Full day", "" ], [ "First half", "first" ], [ "Second half", "second" ] ].freeze
22
28
  class << self
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.60.0
4
+ version: 0.62.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - kshitiz sinha
@@ -75,6 +75,7 @@ files:
75
75
  - app/assets/javascripts/hr_lite/photo_crop.js
76
76
  - app/assets/javascripts/hr_lite/print.js
77
77
  - app/assets/javascripts/hr_lite/search.js
78
+ - app/assets/javascripts/hr_lite/select_all.js
78
79
  - app/assets/javascripts/hr_lite/select_filter.js
79
80
  - app/assets/javascripts/hr_lite/share.js
80
81
  - app/assets/javascripts/hr_lite/tax_preview.js
@@ -97,6 +98,11 @@ files:
97
98
  - app/controllers/hr_lite/admin/employees_controller.rb
98
99
  - app/controllers/hr_lite/admin/expense_categories_controller.rb
99
100
  - app/controllers/hr_lite/admin/expenses_controller.rb
101
+ - app/controllers/hr_lite/admin/hiring_campaigns_controller.rb
102
+ - app/controllers/hr_lite/admin/hiring_candidates_controller.rb
103
+ - app/controllers/hr_lite/admin/hiring_interviews_controller.rb
104
+ - app/controllers/hr_lite/admin/hiring_sends_controller.rb
105
+ - app/controllers/hr_lite/admin/hiring_templates_controller.rb
100
106
  - app/controllers/hr_lite/admin/holidays_controller.rb
101
107
  - app/controllers/hr_lite/admin/hr_requests_controller.rb
102
108
  - app/controllers/hr_lite/admin/leadership_controller.rb
@@ -136,6 +142,7 @@ files:
136
142
  - app/controllers/hr_lite/documents_controller.rb
137
143
  - app/controllers/hr_lite/employee_profiles_controller.rb
138
144
  - app/controllers/hr_lite/expenses_controller.rb
145
+ - app/controllers/hr_lite/hiring_replies_controller.rb
139
146
  - app/controllers/hr_lite/holidays_controller.rb
140
147
  - app/controllers/hr_lite/home_controller.rb
141
148
  - app/controllers/hr_lite/hr_requests_controller.rb
@@ -168,6 +175,7 @@ files:
168
175
  - app/jobs/hr_lite/calendar_meeting_sync_job.rb
169
176
  - app/jobs/hr_lite/daily_digest_job.rb
170
177
  - app/jobs/hr_lite/document_expiry_job.rb
178
+ - app/jobs/hr_lite/hiring_send_job.rb
171
179
  - app/jobs/hr_lite/leave_year_rollover_job.rb
172
180
  - app/jobs/hr_lite/payroll_auto_approve_job.rb
173
181
  - app/jobs/hr_lite/payroll_auto_draft_job.rb
@@ -205,6 +213,12 @@ files:
205
213
  - app/models/hr_lite/employee_profile.rb
206
214
  - app/models/hr_lite/expense.rb
207
215
  - app/models/hr_lite/expense_category.rb
216
+ - app/models/hr_lite/hiring_campaign.rb
217
+ - app/models/hr_lite/hiring_candidate.rb
218
+ - app/models/hr_lite/hiring_interview.rb
219
+ - app/models/hr_lite/hiring_message.rb
220
+ - app/models/hr_lite/hiring_reply.rb
221
+ - app/models/hr_lite/hiring_template.rb
208
222
  - app/models/hr_lite/holiday.rb
209
223
  - app/models/hr_lite/hr_request.rb
210
224
  - app/models/hr_lite/kudo.rb
@@ -248,6 +262,8 @@ files:
248
262
  - app/services/hr_lite/calculators/proration.rb
249
263
  - app/services/hr_lite/calculators/tds.rb
250
264
  - app/services/hr_lite/day_status.rb
265
+ - app/services/hr_lite/hiring_import.rb
266
+ - app/services/hr_lite/hiring_merge.rb
251
267
  - app/services/hr_lite/leave_day_counter.rb
252
268
  - app/services/hr_lite/overview_query.rb
253
269
  - app/services/hr_lite/payroll_run_processor.rb
@@ -296,6 +312,19 @@ files:
296
312
  - app/views/hr_lite/admin/expense_categories/index.html.erb
297
313
  - app/views/hr_lite/admin/expense_categories/new.html.erb
298
314
  - app/views/hr_lite/admin/expenses/index.html.erb
315
+ - app/views/hr_lite/admin/hiring_campaigns/_form.html.erb
316
+ - app/views/hr_lite/admin/hiring_campaigns/edit.html.erb
317
+ - app/views/hr_lite/admin/hiring_campaigns/import.html.erb
318
+ - app/views/hr_lite/admin/hiring_campaigns/index.html.erb
319
+ - app/views/hr_lite/admin/hiring_campaigns/new.html.erb
320
+ - app/views/hr_lite/admin/hiring_campaigns/preview.html.erb
321
+ - app/views/hr_lite/admin/hiring_campaigns/show.html.erb
322
+ - app/views/hr_lite/admin/hiring_candidates/show.html.erb
323
+ - app/views/hr_lite/admin/hiring_sends/new.html.erb
324
+ - app/views/hr_lite/admin/hiring_templates/_form.html.erb
325
+ - app/views/hr_lite/admin/hiring_templates/edit.html.erb
326
+ - app/views/hr_lite/admin/hiring_templates/index.html.erb
327
+ - app/views/hr_lite/admin/hiring_templates/new.html.erb
299
328
  - app/views/hr_lite/admin/holidays/index.html.erb
300
329
  - app/views/hr_lite/admin/hr_requests/index.html.erb
301
330
  - app/views/hr_lite/admin/hr_requests/show.html.erb
@@ -381,6 +410,7 @@ files:
381
410
  - app/views/hr_lite/event_mailer/leadership.text.erb
382
411
  - app/views/hr_lite/expenses/index.html.erb
383
412
  - app/views/hr_lite/expenses/new.html.erb
413
+ - app/views/hr_lite/hiring_replies/show.html.erb
384
414
  - app/views/hr_lite/holidays/_next_holiday.html.erb
385
415
  - app/views/hr_lite/holidays/index.html.erb
386
416
  - app/views/hr_lite/home/_today_checkins.html.erb
@@ -431,6 +461,7 @@ files:
431
461
  - app/views/layouts/hr_lite/mailer.html.erb
432
462
  - app/views/layouts/hr_lite/mailer.text.erb
433
463
  - app/views/layouts/hr_lite/pdf.html.erb
464
+ - app/views/layouts/hr_lite/public.html.erb
434
465
  - config/routes.rb
435
466
  - db/migrate/20260718190726_create_hr_lite_kudos.rb
436
467
  - db/migrate/20260718190727_create_hr_lite_kudo_mentions.rb
@@ -508,6 +539,14 @@ files:
508
539
  - db/migrate/20261016100000_add_hours_allowance_repeat_to_hr_lite_employee_profiles.rb
509
540
  - db/migrate/20261017161441_make_hr_lite_benefit_enrolments_unique_while_open.rb
510
541
  - db/migrate/20261017161443_add_attendance_record_id_index_to_hr_lite_work_mode_events.rb
542
+ - db/migrate/20261021100000_create_hr_lite_hiring_campaigns.rb
543
+ - db/migrate/20261021100100_create_hr_lite_hiring_candidates.rb
544
+ - db/migrate/20261021100200_create_hr_lite_hiring_templates.rb
545
+ - db/migrate/20261021100300_create_hr_lite_hiring_messages.rb
546
+ - db/migrate/20261021100400_create_hr_lite_hiring_interviews.rb
547
+ - db/migrate/20261021100500_seed_hr_lite_hiring.rb
548
+ - db/migrate/20261022090000_create_hr_lite_hiring_replies.rb
549
+ - db/migrate/20261022090100_add_allow_sunday_to_hr_lite_hiring_campaigns.rb
511
550
  - lib/generators/hr_lite/install/install_generator.rb
512
551
  - lib/generators/hr_lite/install/templates/AFTER_INSTALL
513
552
  - lib/generators/hr_lite/install/templates/initializer.rb