class PeopleGroup::Connectors::Bamboo

Constants

EmployeeNotFoundError

Attributes

client[RW]

Public Class Methods

new(use_report: false) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 12
def initialize(use_report: false)
  @use_report = use_report
  @client = Bamboozled.client(subdomain: 'gitlab', api_key: ENV['BAMBOO_API_KEY'])
end

Public Instance Methods

accrued_days(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 270
def accrued_days(employee_id)
  employee_accruals_type = time_off_type('Employee Accruals')
  total_accruals = time_off_estimate(employee_id).find { |type| type['timeOffType'] == employee_accruals_type['id'] }

  total_accruals['balance'].to_f
end
active_and_current_employees() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 220
def active_and_current_employees
  today = Date.current
  employees.select do |employee|
    employee['status'] == 'Active' && Date.parse(employee['hireDate']) <= today
  end
end
active_and_current_team_members()
active_employees() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 215
def active_employees
  employees.select { |employee| employee['status'] == 'Active' }
end
Also aliased as: active_team_members
active_team_members()
Alias for: active_employees
add_additional_data(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 340
def add_additional_data(employee_id, data)
  retry_on_error { @client.employee.add_table_row(employee_id, 'customAdditionalInformation1', data) }
end
add_bonus(team_member_id, comment) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 352
def add_bonus(team_member_id, comment)
  data = {
    customBonusdate: Date.today.to_s,
    customBonusamount: { value: 1_000, currency: 'USD' },
    customBonustype: 'Discretionary Bonus',
    customBonuscomments: comment
    # customNominatedBy: 'TODO'
  }
  retry_on_error { @client.employee.add_table_row(team_member_id, 'customBonus', data) }
end
add_compensation_details(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 246
def add_compensation_details(employee_id, data)
  retry_on_error { @client.employee.add_table_row(employee_id, 'compensation', data) }
end
add_currency_conversion(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 324
def add_currency_conversion(employee_id, data)
  retry_on_error { @client.employee.add_table_row(employee_id, 'customCurrencyConversion', data) }
end
add_employment_status(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 320
def add_employment_status(employee_id, data)
  retry_on_error { @client.employee.add_table_row(employee_id, 'employmentStatus', data) }
end
add_family_member(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 336
def add_family_member(employee_id, data)
  retry_on_error { @client.employee.add_table_row(employee_id, 'customFamilyMember', data) }
end
add_file(employee_id, file_name, file, folder_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 310
def add_file(employee_id, file_name, file, folder_id)
  options = {
    category: folder_id,
    fileName: file_name,
    share: 'yes',
    file: file
  }
  retry_on_error { @client.employee.add_file(employee_id, options) }
end
add_job_details(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 236
def add_job_details(employee_id, data)
  retry_on_error { @client.employee.add_table_row(employee_id, 'jobInfo', data) }
end
add_on_target_earnings(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 328
def add_on_target_earnings(employee_id, data)
  retry_on_error { @client.employee.add_table_row(employee_id, 'customOnTargetEarnings', data) }
end
add_rating_details(team_member_id, performance, potential) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 363
def add_rating_details(team_member_id, performance, potential)
  data = {
    customEffectiveDate4: Date.today.to_s,
    customPerformanceFactor: performance,
    customPotentialFactor: potential
  }
  retry_on_error { @client.employee.add_table_row(team_member_id, 'customPerformanceandPotentialTable', data) }
end
add_signing_bonus(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 332
def add_signing_bonus(employee_id, data)
  retry_on_error { @client.employee.add_table_row(employee_id, 'customBonus', data) }
end
add_stock_options(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 228
def add_stock_options(employee_id, data)
  retry_on_error { @client.employee.add_table_row(employee_id, 'customEquity', data) }
end
add_time_off_policy(employee_id, time_off_policy_id, accrual_start_date) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 286
def add_time_off_policy(employee_id, time_off_policy_id, accrual_start_date)
  policies = [{ timeOffPolicyId: time_off_policy_id, accrualStartDate: accrual_start_date }]

  retry_on_error { @client.employee.add_time_off_policies(employee_id, policies) }
end
additional_data(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 344
def additional_data(employee_id)
  retry_on_error { @client.employee.table_data(employee_id, 'employmentStatus') }
end
all_reports_for(id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 143
def all_reports_for(id)
  direct_reports_to_check = direct_reports_for(id)
  reports_to_return = []
  while direct_reports_to_check.present?
    current_node = direct_reports_to_check.shift
    reports_to_return << current_node
    direct_reports_to_check.concat(direct_reports_for(current_node['id']))
  end
  reports_to_return
end
contract_folder_id(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 306
def contract_folder_id(employee_id)
  @contract_folder_id ||= files(employee_id).dig('categories').find { |folder| folder['name'] == 'Contracts & Changes' }.dig('id')
end
create_employee(employee_details_hash) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 176
def create_employee(employee_details_hash)
  retry_on_error { @client.employee.add(employee_details_hash) }
end
currency_conversion(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 348
def currency_conversion(employee_id)
  retry_on_error { @client.employee.table_data(employee_id, 'customCurrencyConversion') }
end
departments() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 184
def departments
  meta_fields.detect { |res| res['name'] == 'Department' }.dig('options').each_with_object([]) { |option, array| array << option['name'] if option['archived'] == 'no' } || []
end
direct_reports_for(id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 154
def direct_reports_for(id)
  active_and_current_team_members.select { |team_member| team_member['supervisorEId'] == id.to_s }
end
divisions() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 188
def divisions
  meta_fields.detect { |res| res['name'] == 'Division' }.dig('options').each_with_object([]) { |option, array| array << option['name'] if option['archived'] == 'no' } || []
end
employee_time_off_policies(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 281
def employee_time_off_policies(employee_id)
  retry_on_error { @client.employee.time_off_policies(employee_id) }
end
employees() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 205
def employees
  retry_on_error do
    if @use_report
      @employees ||= @client.report.find(@use_report, 'JSON', true).reject { |employee| employee['lastName'] == 'Test-Gitlab' }
    else
      @employees ||= @client.report.custom(fields, 'JSON').reject { |employee| employee['lastName'] == 'Test-Gitlab' }
    end
  end
end
employment_statuses(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 250
def employment_statuses(employee_id)
  retry_on_error { @client.employee.table_data(employee_id, 'employmentStatus') }
end
fetch_manager(team_member) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 103
def fetch_manager(team_member)
  active_team_members.find { |tm| tm['id'] == team_member['supervisorEId'] }
end
fetch_manager!(team_member) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 107
def fetch_manager!(team_member)
  manager = fetch_manager(team_member)
  raise EmployeeNotFoundError, "Manager not found for employee #{team_member['id']}" if manager.nil?

  manager
end
fetch_manager_for_id(team_member_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 114
def fetch_manager_for_id(team_member_id)
  team_member = get_employee_details(team_member_id)
  active_team_members.find { |tm| tm['id'] == team_member['supervisorEId'] }
end
fetch_manager_for_id!(team_member_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 119
def fetch_manager_for_id!(team_member_id)
  manager = fetch_manager_for_id(team_member_id)
  raise EmployeeNotFoundError, "No manager found with id #{team_member_id}" if manager.nil?

  manager
end
fetch_second_level_manager(team_member) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 126
def fetch_second_level_manager(team_member)
  fetch_manager(fetch_manager(team_member))
end
fetch_second_level_manager!(team_member) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 130
def fetch_second_level_manager!(team_member)
  manager = fetch_second_level_manager(team_member)
  raise EmployeeNotFoundError, "No second level manager found for employee #{team_member['id']}" if manager.nil?

  manager
end
fields() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 196
def fields
  return @fields if @fields

  meta_field_aliases = retry_on_error { @client.meta.fields }.map { |f| f['alias'] }
  @fields = (Bamboozled::API::FieldCollection.all_names + meta_field_aliases).compact.uniq
  @fields.delete('flsaCode') # temp fix for problems with BambooHR
  @fields
end
get_employee(id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 29
def get_employee(id)
  retry_on_error do
    @client.employee.find(id, %w[firstName lastName jobTitle supervisor hireDate country location department division workEmail customCostCenter])
  end
end
get_employee!(id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 35
def get_employee!(id)
  employee = get_employee(id)
  raise EmployeeNotFoundError, "No employee found with id #{id}" if employee.nil?

  employee
end
get_employee_details(id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 17
def get_employee_details(id)
  employees.find { |emp| emp['id'] == id.to_s }
end
Also aliased as: get_team_member_details
get_employee_details!(id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 22
def get_employee_details!(id)
  employee_details = get_employee_details(id)
  raise EmployeeNotFoundError, "No employee found with id #{id}" if employee_details.nil?

  employee_details
end
get_team_member_details(id)
has_direct_reports?(id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 158
def has_direct_reports?(id)
  active_and_current_team_members.any? { |team_member| team_member['supervisorEId'] == id.to_s }
end
job_details(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 298
def job_details(employee_id)
  retry_on_error { @client.employee.table_data(employee_id, 'jobInfo') }
end
locations() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 192
def locations
  meta_fields.detect { |res| res['name'] == 'Location' }.dig('options').each_with_object([]) { |option, array| array << option['name'] if option['archived'] == 'no' } || []
end
people_managers_in_functions(departments: [], divisions: []) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 137
def people_managers_in_functions(departments: [], divisions: [])
  active_and_current_team_members.select do |team_member|
    (departments.include?(team_member['department']) || divisions.include?(team_member['division'])) && has_direct_reports?(team_member['id'])
  end
end
remove_time_off_policy(employee_id, time_off_policy_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 292
def remove_time_off_policy(employee_id, time_off_policy_id)
  # A nil accrual start date removes a policy assignment
  # Reference: https://documentation.bamboohr.com/reference#time-off-assign-time-off-policies-for-an-employee
  add_time_off_policy(employee_id, time_off_policy_id, nil)
end
reports_in_departments(departments, exclude_email) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 162
def reports_in_departments(departments, exclude_email)
  active_and_current_team_members.select do |team_member|
    # exclude_email is for example to filter out the PBP itself in case their department is also the department they manage
    departments.include?(team_member['department']) && team_member['workEmail'] != exclude_email
  end
end
reports_in_divisions(divisions, exclude_email) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 169
def reports_in_divisions(divisions, exclude_email)
  active_and_current_team_members.select do |team_member|
    # exclude_email is for example to filter out the PBP itself in case their department is also the department they manage
    divisions.include?(team_member['division']) && team_member['workEmail'] != exclude_email
  end
end
resumes_folder_id(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 302
def resumes_folder_id(employee_id)
  @resumes_folder_id ||= files(employee_id).dig('categories').find { |folder| folder['name'] == 'Resumes and Applications' }.dig('id')
end
search_employee(name) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 42
def search_employee(name)
  return if name.empty?

  employees.find do |emp|
    [
      emp['displayName']&.downcase,
      "#{emp['firstName']&.downcase} #{emp['lastName']&.downcase}",
      "#{emp['preferredName']&.downcase} #{emp['lastName']&.downcase}",
      "#{emp['firstName']&.downcase} #{emp['customPreferredLastName']&.downcase}",
      "#{emp['preferredName']&.downcase} #{emp['customPreferredLastName']&.downcase}",
      emp['fullName5']&.downcase # this is firstName middleName lastName
    ].include?(name.downcase)
  end
end
Also aliased as: search_team_member
search_employee!(name) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 58
def search_employee!(name)
  employee = search_employee(name)
  raise EmployeeNotFoundError, "No employee found with name #{name}" if employee.nil?

  employee
end
Also aliased as: search_team_member!
search_employee_by_field(field:, value:) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 66
def search_employee_by_field(field:, value:)
  employees.find { |employee| employee[field] == value.to_s }
end
Also aliased as: search_team_member_by_field
search_employee_by_field!(field:, value:) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 71
def search_employee_by_field!(field:, value:)
  employee = search_employee_by_field(field: field, value: value)
  raise EmployeeNotFoundError, "No employee found with #{field}: #{value}" if employee.nil?

  employee
end
Also aliased as: search_team_member_by_field!
search_team_member(name)
Alias for: search_employee
search_team_member!(name)
Alias for: search_employee!
search_team_member_by_field(field:, value:)
search_team_member_by_field!(field:, value:)
slack_email_lookup_with_fallback(email) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 79
def slack_email_lookup_with_fallback(email)
  file_path = File.join(__dir__, '../../../data/email_mapper.yml')
  email_mapper = YAML.load_file(file_path)
  email_hit = email_mapper.find { |mapping| mapping['slack_email'] == email.delete_suffix('@gitlab.com') }
  email = "#{email_hit['bamboo_email']}@gitlab.com" if email_hit

  employees.find { |employee| employee['workEmail'] == email }
end
slack_email_lookup_with_fallback!(email) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 88
def slack_email_lookup_with_fallback!(email)
  employee = slack_email_lookup_with_fallback(email)
  raise EmployeeNotFoundError, "No employee found with Slack email #{email}" if employee.nil?

  employee
end
stock_options_data(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 232
def stock_options_data(employee_id)
  retry_on_error { @client.employee.table_data(employee_id, 'customEquity') }
end
team_member_time_off_policies(employee_id)
team_members_by_department(department) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 95
def team_members_by_department(department)
  active_and_current_team_members.select { |team_member| team_member['department'] == department }
end
team_members_by_division(division) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 99
def team_members_by_division(division)
  active_and_current_team_members.select { |team_member| team_member['division'] == division }
end
time_off_adjustment(employee_id, options) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 266
def time_off_adjustment(employee_id, options)
  retry_on_error { @client.employee.time_off_balance_adjustment(employee_id, options) }
end
time_off_estimate(employee_id, end_date = Date.today) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 262
def time_off_estimate(employee_id, end_date = Date.today)
  retry_on_error { @client.employee.time_off_estimate(employee_id, end_date) }
end
time_off_policies() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 277
def time_off_policies
  @time_off_policies ||= retry_on_error { @client.meta.time_off_policies }
end
time_off_type(name) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 258
def time_off_type(name)
  time_off_types['timeOffTypes'].find { |type| type['name'] == name }
end
time_off_types() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 254
def time_off_types
  @time_off_types ||= retry_on_error { @client.meta.time_off_types }
end
update_employee(employee_id, employee_details_hash) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 180
def update_employee(employee_id, employee_details_hash)
  retry_on_error { @client.employee.update(employee_id, employee_details_hash) }
end
update_job_details(employee_id, data) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 240
def update_job_details(employee_id, data)
  current_data = job_details(employee_id) # it should only be one row as we just created this user
  row_id = current_data.first.dig('id')
  retry_on_error { @client.employee.update_table_row(employee_id, 'jobInfo', row_id, data) }
end

Private Instance Methods

files(employee_id) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 378
def files(employee_id)
  @files ||= retry_on_error { @client.employee.files(employee_id) }
end
meta_fields() click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 374
def meta_fields
  @meta_fields ||= retry_on_error { @client.meta.lists }
end
retry_on_error(&block) click to toggle source
# File lib/peoplegroup/connectors/bamboo.rb, line 382
def retry_on_error(&block)
  Utils.retry_on_error(errors: [Net::ReadTimeout, Bamboozled::GatewayError], delay: 3, &block)
end