Module: HrLite
- Defined in:
- lib/hr_lite.rb,
lib/hr_lite/geo.rb,
lib/hr_lite/money.rb,
lib/hr_lite/seeds.rb,
lib/hr_lite/engine.rb,
lib/hr_lite/current.rb,
lib/hr_lite/version.rb,
lib/hr_lite/leave_year.rb,
lib/hr_lite/role_seeds.rb,
app/models/hr_lite/kudo.rb,
app/models/hr_lite/loan.rb,
app/models/hr_lite/role.rb,
lib/hr_lite/permissions.rb,
app/models/hr_lite/asset.rb,
app/models/hr_lite/policy.rb,
lib/hr_lite/configuration.rb,
lib/hr_lite/notifications.rb,
app/models/hr_lite/benefit.rb,
app/models/hr_lite/expense.rb,
app/models/hr_lite/holiday.rb,
app/models/hr_lite/setting.rb,
lib/hr_lite/financial_year.rb,
lib/hr_lite/mention_parser.rb,
app/models/hr_lite/approval.rb,
app/models/hr_lite/document.rb,
app/services/hr_lite/access.rb,
lib/hr_lite/amount_in_words.rb,
lib/hr_lite/statutory_seeds.rb,
app/models/hr_lite/appraisal.rb,
app/models/hr_lite/audit_log.rb,
app/models/hr_lite/hr_request.rb,
app/models/hr_lite/leave_type.rb,
app/models/hr_lite/role_grant.rb,
app/services/hr_lite/team_day.rb,
app/models/hr_lite/payroll_run.rb,
app/models/hr_lite/resignation.rb,
app/models/hr_lite/salary_slip.rb,
app/models/hr_lite/kudo_mention.rb,
app/services/hr_lite/day_status.rb,
lib/hr_lite/statutory_rate_card.rb,
app/jobs/hr_lite/application_job.rb,
app/mailers/hr_lite/event_mailer.rb,
app/models/hr_lite/approval_flow.rb,
app/models/hr_lite/approval_step.rb,
app/models/hr_lite/leave_balance.rb,
app/models/hr_lite/leave_request.rb,
app/jobs/hr_lite/daily_digest_job.rb,
app/models/hr_lite/checklist_item.rb,
app/models/hr_lite/loan_repayment.rb,
app/services/hr_lite/pdf_renderer.rb,
app/services/hr_lite/slip_builder.rb,
app/models/hr_lite/office_location.rb,
app/models/hr_lite/role_assignment.rb,
app/models/hr_lite/tax_declaration.rb,
app/models/concerns/hr_lite/audited.rb,
app/models/hr_lite/asset_assignment.rb,
app/models/hr_lite/comp_off_request.rb,
app/models/hr_lite/employee_profile.rb,
app/models/hr_lite/expense_category.rb,
app/models/hr_lite/salary_component.rb,
app/models/hr_lite/salary_structure.rb,
app/services/hr_lite/approval_route.rb,
app/services/hr_lite/calculators/pf.rb,
app/services/hr_lite/overview_query.rb,
app/jobs/hr_lite/document_expiry_job.rb,
app/models/hr_lite/attendance_record.rb,
app/models/hr_lite/benefit_enrolment.rb,
app/models/hr_lite/payroll_line_item.rb,
app/services/hr_lite/calculators/esi.rb,
app/services/hr_lite/calculators/tds.rb,
app/models/hr_lite/application_record.rb,
app/models/hr_lite/checklist_template.rb,
app/models/hr_lite/designation_change.rb,
app/services/hr_lite/working_calendar.rb,
app/controllers/hr_lite/org_controller.rb,
app/helpers/hr_lite/application_helper.rb,
app/mailers/hr_lite/application_mailer.rb,
app/models/concerns/hr_lite/approvable.rb,
app/models/hr_lite/approval_delegation.rb,
app/services/hr_lite/leave_day_counter.rb,
app/controllers/hr_lite/home_controller.rb,
app/controllers/hr_lite/team_controller.rb,
app/jobs/hr_lite/payroll_auto_draft_job.rb,
app/models/hr_lite/tax_declaration_item.rb,
app/services/hr_lite/attendance_puncher.rb,
app/services/hr_lite/attendance_summary.rb,
app/controllers/hr_lite/kudos_controller.rb,
app/controllers/hr_lite/loans_controller.rb,
app/controllers/hr_lite/users_controller.rb,
app/jobs/hr_lite/approval_escalation_job.rb,
app/jobs/hr_lite/leave_year_rollover_job.rb,
app/models/hr_lite/professional_tax_slab.rb,
app/controllers/hr_lite/career_controller.rb,
app/models/hr_lite/policy_acknowledgement.rb,
app/models/hr_lite/regularization_request.rb,
app/services/hr_lite/calculators/proration.rb,
app/services/hr_lite/payroll_run_processor.rb,
app/controllers/hr_lite/benefits_controller.rb,
app/controllers/hr_lite/calendar_controller.rb,
app/controllers/hr_lite/expenses_controller.rb,
app/controllers/hr_lite/holidays_controller.rb,
app/controllers/hr_lite/policies_controller.rb,
app/models/concerns/hr_lite/encrypted_money.rb,
app/controllers/hr_lite/approvals_controller.rb,
app/controllers/hr_lite/documents_controller.rb,
app/controllers/hr_lite/admin/base_controller.rb,
app/controllers/hr_lite/appraisals_controller.rb,
app/controllers/hr_lite/attendance_controller.rb,
app/models/hr_lite/statutory_rate_card_record.rb,
app/controllers/hr_lite/admin/loans_controller.rb,
app/controllers/hr_lite/admin/roles_controller.rb,
app/controllers/hr_lite/application_controller.rb,
app/controllers/hr_lite/hr_requests_controller.rb,
app/controllers/hr_lite/admin/assets_controller.rb,
app/controllers/hr_lite/resignations_controller.rb,
app/controllers/hr_lite/salary_slips_controller.rb,
app/controllers/hr_lite/admin/reports_controller.rb,
lib/generators/hr_lite/install/install_generator.rb,
app/controllers/hr_lite/admin/expenses_controller.rb,
app/controllers/hr_lite/admin/holidays_controller.rb,
app/controllers/hr_lite/admin/overview_controller.rb,
app/controllers/hr_lite/admin/settings_controller.rb,
app/controllers/hr_lite/leave_balances_controller.rb,
app/controllers/hr_lite/leave_requests_controller.rb,
app/services/hr_lite/calculators/professional_tax.rb,
app/controllers/hr_lite/admin/documents_controller.rb,
app/controllers/hr_lite/admin/employees_controller.rb,
app/controllers/hr_lite/admin/appraisals_controller.rb,
app/controllers/hr_lite/admin/audit_logs_controller.rb,
app/controllers/hr_lite/admin/checklists_controller.rb,
app/controllers/hr_lite/admin/leadership_controller.rb,
app/controllers/hr_lite/admin/superadmin_controller.rb,
app/controllers/hr_lite/tax_declarations_controller.rb,
app/controllers/hr_lite/admin/attendances_controller.rb,
app/controllers/hr_lite/admin/hr_requests_controller.rb,
app/controllers/hr_lite/admin/leave_types_controller.rb,
app/controllers/hr_lite/comp_off_requests_controller.rb,
app/controllers/hr_lite/employee_profiles_controller.rb,
app/controllers/hr_lite/admin/payroll_runs_controller.rb,
app/controllers/hr_lite/admin/resignations_controller.rb,
app/controllers/hr_lite/admin/salary_slips_controller.rb,
app/controllers/hr_lite/admin/leave_balances_controller.rb,
app/controllers/hr_lite/admin/leave_requests_controller.rb,
app/controllers/hr_lite/admin/office_locations_controller.rb,
app/controllers/hr_lite/admin/role_assignments_controller.rb,
app/controllers/hr_lite/admin/tax_declarations_controller.rb,
app/controllers/hr_lite/admin/comp_off_requests_controller.rb,
app/controllers/hr_lite/admin/salary_structures_controller.rb,
app/controllers/hr_lite/regularization_requests_controller.rb,
app/controllers/hr_lite/admin/designation_changes_controller.rb,
app/controllers/hr_lite/admin/statutory_rate_cards_controller.rb,
app/controllers/hr_lite/admin/regularization_requests_controller.rb
Defined Under Namespace
Modules: Admin, AmountInWords, ApplicationHelper, Approvable, AttendanceSummary, Audited, Calculators, EncryptedMoney, FinancialYear, Generators, Geo, LeaveDayCounter, LeaveYear, MentionParser, Money, Notifications, PdfRenderer, Permissions, RoleSeeds, Seeds, StatutoryRateCard, StatutorySeeds Classes: Access, ApplicationController, ApplicationJob, ApplicationMailer, ApplicationRecord, Appraisal, AppraisalsController, Approval, ApprovalDelegation, ApprovalEscalationJob, ApprovalFlow, ApprovalRoute, ApprovalStep, ApprovalsController, Asset, AssetAssignment, AttendanceController, AttendancePuncher, AttendanceRecord, AuditLog, Benefit, BenefitEnrolment, BenefitsController, CalendarController, CareerController, ChecklistItem, ChecklistTemplate, CompOffRequest, CompOffRequestsController, Configuration, Current, DailyDigestJob, DayStatus, DesignationChange, Document, DocumentExpiryJob, DocumentsController, EmployeeProfile, EmployeeProfilesController, Engine, EventMailer, Expense, ExpenseCategory, ExpensesController, Holiday, HolidaysController, HomeController, HrRequest, HrRequestsController, Kudo, KudoMention, KudosController, LeaveBalance, LeaveBalancesController, LeaveRequest, LeaveRequestsController, LeaveType, LeaveYearRolloverJob, Loan, LoanRepayment, LoansController, OfficeLocation, OrgController, OverviewQuery, PayrollAutoDraftJob, PayrollLineItem, PayrollRun, PayrollRunProcessor, PoliciesController, Policy, PolicyAcknowledgement, ProfessionalTaxSlab, RegularizationRequest, RegularizationRequestsController, Resignation, ResignationsController, Role, RoleAssignment, RoleGrant, SalaryComponent, SalarySlip, SalarySlipsController, SalaryStructure, Setting, SlipBuilder, StatutoryRateCardRecord, TaxDeclaration, TaxDeclarationItem, TaxDeclarationsController, TeamController, TeamDay, UsersController, WorkingCalendar
Constant Summary collapse
- VERSION =
"0.15.0"
Class Method Summary collapse
- .access_for(user) ⇒ Object
-
.active_employees(on: Date.current) ⇒ Object
employees minus anyone whose profile says they have exited — user accounts outlive employment (slip access), broadcasts must not.
-
.admin?(user) ⇒ Boolean
--- tier predicates ----------------------------------------------------.
-
.admin_users ⇒ Object
Every domain event that bells the admins calls this.
-
.can?(user, key, scope: :self) ⇒ Boolean
The question every gate now asks.
- .config ⇒ Object
-
.config=(configuration) ⇒ Object
Test-only escape hatch: swap the whole configuration object.
- .configure {|config| ... } ⇒ Object
-
.default_mentionable_users(query) ⇒ Object
Default @mention source: name/email prefix match on the host user table.
- .display_name(user) ⇒ Object
-
.employees ⇒ Object
Everyone HR tracks (host-overridable to exclude bots/test accounts), sorted by display name for team screens.
- .leadership?(user) ⇒ Boolean
-
.leadership_users ⇒ Object
Leadership members resolvable to actual user records (for bell notifications).
-
.normalize_email_list(emails) ⇒ Object
An access list, cleaned — read now only by the 0.6.0 upgrade migration.
-
.notify(user:, kind:, title:, body: nil, path: nil) ⇒ Object
Host bell hook.
-
.public_url(path = "/") ⇒ Object
Absolute public URL for an engine-relative path, from config.public_url_base.
-
.public_url?(candidate) ⇒ Boolean
True when the given absolute URL points at the configured public HR host — the allowlist check for hosts that follow stored notification links (an open-redirect guard stays intact on their side).
-
.reaches?(user, key, subject) ⇒ Boolean
Whether
usermay exercisekeyoversubject's rows. - .superadmin?(user) ⇒ Boolean
- .user_klass ⇒ Object
-
.users_holding(key, scope: :all) ⇒ Object
Everyone whose roles grant
keyatscopeor wider.
Class Method Details
.access_for(user) ⇒ Object
52 |
# File 'lib/hr_lite.rb', line 52 def access_for(user) = Access.for(user) |
.active_employees(on: Date.current) ⇒ Object
employees minus anyone whose profile says they have exited — user accounts outlive employment (slip access), broadcasts must not.
119 120 121 122 |
# File 'lib/hr_lite.rb', line 119 def active_employees(on: Date.current) exits = HrLite::EmployeeProfile.where.not(date_of_exit: nil).pluck(:user_id, :date_of_exit).to_h employees.select { |u| exits[u.id].nil? || exits[u.id] >= on } end |
.admin?(user) ⇒ Boolean
--- tier predicates ----------------------------------------------------
Shorthands over the permissions, kept because views, hosts and the notification fan-out all read better asking "is this person leadership" than "do they hold profile.manage at all scope". They are ROLES all the way down; the pre-0.6.0 lambdas no longer decide anything.
61 62 63 64 65 |
# File 'lib/hr_lite.rb', line 61 def admin?(user) return false if user.blank? can?(user, "leave.approve", scope: :all) || can?(user, "attendance.manage", scope: :all) end |
.admin_users ⇒ Object
Every domain event that bells the admins calls this. One query over the grant tables — it used to instantiate every employee and ask each one.
107 108 109 |
# File 'lib/hr_lite.rb', line 107 def admin_users users_holding("leave.approve", scope: :all).sort_by { |u| display_name(u).downcase } end |
.can?(user, key, scope: :self) ⇒ Boolean
The question every gate now asks. scope: is what the CALLER needs;
a holder with a wider scope satisfies it.
41 42 43 |
# File 'lib/hr_lite.rb', line 41 def can?(user, key, scope: :self) Access.for(user).can?(key, scope: scope) end |
.config ⇒ Object
20 21 22 |
# File 'lib/hr_lite.rb', line 20 def config @config ||= Configuration.new end |
.config=(configuration) ⇒ Object
Test-only escape hatch: swap the whole configuration object.
29 30 31 |
# File 'lib/hr_lite.rb', line 29 def config=(configuration) @config = configuration end |
.configure {|config| ... } ⇒ Object
24 25 26 |
# File 'lib/hr_lite.rb', line 24 def configure yield config end |
.default_mentionable_users(query) ⇒ Object
Default @mention source: name/email prefix match on the host user table. Uses LOWER(...) LIKE so it works on sqlite and postgres alike; hosts with pg_trgm or scopes of their own override config.mentionable_users.
95 96 97 98 99 100 101 102 103 |
# File 'lib/hr_lite/configuration.rb', line 95 def default_mentionable_users(query) q = "%#{ActiveRecord::Base.sanitize_sql_like(query.to_s.downcase)}%" klass = user_klass columns = %w[name email].select { |c| klass.column_names.include?(c) } return klass.none if columns.empty? where_sql = columns.map { |c| "LOWER(#{klass.table_name}.#{c}) LIKE :q" }.join(" OR ") klass.where(where_sql, q: q).order(:id).limit(8) end |
.display_name(user) ⇒ Object
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/hr_lite.rb', line 124 def display_name(user) return "" if user.nil? [ config.display_name_method, :display_name, :name, :email ].each do |m| next unless m && user.respond_to?(m) value = user.public_send(m).presence return value if value end "User ##{user.id}" end |
.employees ⇒ Object
Everyone HR tracks (host-overridable to exclude bots/test accounts), sorted by display name for team screens.
113 114 115 |
# File 'lib/hr_lite.rb', line 113 def employees config.employees_scope.call.sort_by { |u| display_name(u).downcase } end |
.leadership?(user) ⇒ Boolean
67 68 69 70 71 |
# File 'lib/hr_lite.rb', line 67 def leadership?(user) return false if user.blank? can?(user, "profile.manage", scope: :all) end |
.leadership_users ⇒ Object
Leadership members resolvable to actual user records (for bell notifications).
89 90 91 |
# File 'lib/hr_lite.rb', line 89 def leadership_users users_holding("profile.manage", scope: :all) end |
.normalize_email_list(emails) ⇒ Object
An access list, cleaned — read now only by the 0.6.0 upgrade migration. One stray comma in an ENV var ("a@x.com,,b@x.com") used to put "" in the list, and a user whose email was blank then MATCHED it and was handed the tier. Kept honest here so the migration cannot repeat that.
83 84 85 |
# File 'lib/hr_lite.rb', line 83 def normalize_email_list(emails) Array(emails).map { |e| e.to_s.downcase.strip }.reject(&:empty?) end |
.notify(user:, kind:, title:, body: nil, path: nil) ⇒ Object
Host bell hook. Never raises — a notification must not break the domain action that triggered it.
162 163 164 165 166 167 |
# File 'lib/hr_lite.rb', line 162 def notify(user:, kind:, title:, body: nil, path: nil) config.notify.call(user: user, kind: kind, title: title, body: body, path: path) rescue => e Rails.logger.error("[hr_lite] notify failed: #{e.class}: #{e.}") nil end |
.public_url(path = "/") ⇒ Object
Absolute public URL for an engine-relative path, from config.public_url_base. Nil when no base is configured — callers (and emails) then simply carry no link. Hosts use this to build bell deep-links and profile links without re-deriving the HR host.
139 140 141 142 143 144 |
# File 'lib/hr_lite.rb', line 139 def public_url(path = "/") base = config.public_url_base.to_s.chomp("/") return nil if base.empty? "#{base}#{path}" end |
.public_url?(candidate) ⇒ Boolean
True when the given absolute URL points at the configured public HR host — the allowlist check for hosts that follow stored notification links (an open-redirect guard stays intact on their side).
149 150 151 152 153 154 155 156 157 158 |
# File 'lib/hr_lite.rb', line 149 def public_url?(candidate) base = public_url return false if base.nil? candidate_uri = URI.parse(candidate.to_s) base_uri = URI.parse(base) %w[http https].include?(candidate_uri.scheme) && candidate_uri.host == base_uri.host rescue URI::InvalidURIError false end |
.reaches?(user, key, subject) ⇒ Boolean
Whether user may exercise key over subject's rows. This is the
question that did not exist before roles, and its absence is why any
admin could approve anybody's leave.
48 49 50 |
# File 'lib/hr_lite.rb', line 48 def reaches?(user, key, subject) Access.for(user).reaches?(key, subject) end |
.superadmin?(user) ⇒ Boolean
73 74 75 76 77 |
# File 'lib/hr_lite.rb', line 73 def superadmin?(user) return false if user.blank? can?(user, "payroll.manage", scope: :all) end |
.user_klass ⇒ Object
33 34 35 |
# File 'lib/hr_lite.rb', line 33 def user_klass config.user_class.constantize end |
.users_holding(key, scope: :all) ⇒ Object
Everyone whose roles grant key at scope or wider. One query over
the grant tables rather than instantiating every user and asking.
95 96 97 98 99 100 101 102 103 |
# File 'lib/hr_lite.rb', line 95 def users_holding(key, scope: :all) wide = Permissions::SCOPE_RANK.select { |_, rank| rank >= Permissions::SCOPE_RANK.fetch(scope) } ids = RoleAssignment.joins(role: :role_grants) .where(hr_lite_role_grants: { permission_key: Permissions.validate!(key), scope: wide.keys.map(&:to_s) }) .distinct.pluck(:user_id) user_klass.where(id: ids) end |