peoplegroup-connectors 0.4.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/peoplegroup/connectors/bamboo.rb +5 -10
- data/lib/peoplegroup/connectors/gitlab.rb +3 -10
- data/lib/peoplegroup/connectors/hris.rb +5 -4
- data/lib/peoplegroup/connectors/slack.rb +1 -1
- data/lib/peoplegroup/connectors/version.rb +1 -1
- data/lib/peoplegroup/connectors/workday/client.rb +157 -0
- data/lib/peoplegroup/connectors/workday/report.rb +96 -0
- data/lib/peoplegroup/connectors/workday/xml/get_organizations.rb +85 -0
- data/lib/peoplegroup/connectors/workday/xml/helpers.rb +75 -0
- data/lib/peoplegroup/connectors/workday/xml/request_one_time_payment.rb +105 -0
- data/lib/peoplegroup/connectors/workday/xml.rb +12 -0
- data/lib/peoplegroup/connectors/workday.rb +10 -192
- data/lib/peoplegroup/connectors.rb +5 -4
- metadata +27 -179
- data/lib/peoplegroup/connectors/models/objectified_hash.rb +0 -105
- data/lib/peoplegroup/connectors/xml/get_organizations.rb +0 -84
- data/lib/peoplegroup/connectors/xml/helpers.rb +0 -72
- data/lib/peoplegroup/connectors/xml/request_one_time_payment.rb +0 -103
- data/lib/peoplegroup/connectors/xml.rb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d996feff7137d07264509fcfe7f8bc3dcbd71eefd5d50fe87f09529c23eabba
|
4
|
+
data.tar.gz: bf3a847a3ecb13956246090be029241ba8965d3b69765a00afdf2cf6c8ba6172
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e53ab3a7d2ac8609dbcfe770fb2a797c23053412dcacb52770c0a5ef177b1540543a5566e7ab7b75c83508b20e996b8b606a963ee56ac5700b64aaf1f3c8946
|
7
|
+
data.tar.gz: a1acda40d3c83d4428d146ea6e670aa2fd6cc0be663c87b2717cb806589cd9397a440e3aa98f5203516869eb8c01dbe0e0a8050d9f7af6d60f3037e10b6dad71
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'bamboozled'
|
4
|
-
require_rel 'models/objectified_hash'
|
5
4
|
|
6
5
|
module PeopleGroup
|
7
6
|
module Connectors
|
@@ -127,7 +126,7 @@ module PeopleGroup
|
|
127
126
|
alias_method :update_team_member, :update_employee
|
128
127
|
|
129
128
|
def locations
|
130
|
-
meta_fields.detect { |res| res['name'] == 'Location' }
|
129
|
+
meta_fields.detect { |res| res['name'] == 'Location' }['options'].each_with_object([]) { |option, array| array << option['name'] if option['archived'] == 'no' } || []
|
131
130
|
end
|
132
131
|
|
133
132
|
def employees
|
@@ -172,7 +171,7 @@ module PeopleGroup
|
|
172
171
|
def update_job_details(employee_number, data)
|
173
172
|
id = bamboo_id!(employee_number)
|
174
173
|
current_data = job_details(employee_number) # it should only be one row as we just created this user
|
175
|
-
row_id = current_data.first
|
174
|
+
row_id = current_data.first['id']
|
176
175
|
retry_on_error { @client.employee.update_table_row(id, 'jobInfo', row_id, data) }
|
177
176
|
end
|
178
177
|
|
@@ -231,11 +230,11 @@ module PeopleGroup
|
|
231
230
|
end
|
232
231
|
|
233
232
|
def resumes_folder_id(employee_number)
|
234
|
-
@resumes_folder_id ||= files(employee_number)
|
233
|
+
@resumes_folder_id ||= files(employee_number)['categories'].find { |folder| folder['name'] == 'Resumes and Applications' }['id']
|
235
234
|
end
|
236
235
|
|
237
236
|
def contract_folder_id(employee_number)
|
238
|
-
@contract_folder_id ||= files(employee_number)
|
237
|
+
@contract_folder_id ||= files(employee_number)['categories'].find { |folder| folder['name'] == 'Contracts & Changes' }['id']
|
239
238
|
end
|
240
239
|
|
241
240
|
def add_file(employee_number, file_name, file, folder_id)
|
@@ -344,16 +343,12 @@ module PeopleGroup
|
|
344
343
|
def format_team_member(team_member)
|
345
344
|
return nil if team_member.nil?
|
346
345
|
|
347
|
-
|
346
|
+
{
|
348
347
|
**team_member.except(*MALFORMED_FIELDS),
|
349
348
|
'customExportNameLocationtoTeamPage' => team_member['customExportName/LocationtoTeamPage?'] || 'No',
|
350
349
|
'customJobTitleSpecialtyMultiSelect' => team_member['customJobTitleSpecialty(Multi-Select)'],
|
351
350
|
'customI9Processed' => team_member['customI-9Processed']
|
352
351
|
}
|
353
|
-
|
354
|
-
formatted = PeopleGroup::Connectors::Models::ObjectifiedHash.new(formatted) unless @use_report
|
355
|
-
|
356
|
-
formatted
|
357
352
|
end
|
358
353
|
end
|
359
354
|
end
|
@@ -14,24 +14,17 @@ module PeopleGroup
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def find_gitlabber(field, query)
|
17
|
-
|
18
|
-
|
19
|
-
possible_members = get_group_members('gitlab-com', query: query)
|
20
|
-
if field === :email
|
21
|
-
possible_members.first
|
22
|
-
else
|
23
|
-
possible_members.find { |team_member| team_member.public_send(field) === query }
|
24
|
-
end
|
17
|
+
find_gitlabber_on(field, query, 'gitlab-com')
|
25
18
|
end
|
26
19
|
|
27
20
|
def find_gitlabber_on(field, query, group)
|
28
21
|
return if !query || query.empty?
|
29
22
|
|
30
23
|
possible_members = get_group_members(group, query: query)
|
31
|
-
if field
|
24
|
+
if field == :email
|
32
25
|
possible_members.first
|
33
26
|
else
|
34
|
-
possible_members.find { |team_member| team_member.public_send(field)
|
27
|
+
possible_members.find { |team_member| team_member.public_send(field) == query }
|
35
28
|
end
|
36
29
|
end
|
37
30
|
|
@@ -7,12 +7,12 @@ module PeopleGroup
|
|
7
7
|
EmployeeNotFoundError = Class.new(StandardError)
|
8
8
|
|
9
9
|
def initialize
|
10
|
-
@workday = Workday.new
|
10
|
+
@workday = Workday::Client.new
|
11
11
|
@bamboo = Bamboo.new
|
12
12
|
end
|
13
13
|
|
14
14
|
def employees
|
15
|
-
@employees ||=
|
15
|
+
@employees ||= Workday.workers
|
16
16
|
end
|
17
17
|
alias_method :team_members, :employees
|
18
18
|
|
@@ -85,7 +85,7 @@ module PeopleGroup
|
|
85
85
|
|
86
86
|
team_members.find do |team_member|
|
87
87
|
emails = [team_member['workEmail'], team_member['bestEmail'], team_member['homeEmail']]
|
88
|
-
emails.compact.any? { |match| email.casecmp(match)
|
88
|
+
emails.compact.any? { |match| email.casecmp(match).zero? }
|
89
89
|
end
|
90
90
|
end
|
91
91
|
alias_method :slack_email_lookup_with_fallback, :search_team_member_by_email
|
@@ -214,7 +214,8 @@ module PeopleGroup
|
|
214
214
|
end
|
215
215
|
|
216
216
|
def job_details(employee_number)
|
217
|
-
|
217
|
+
warn '[DEPRECATED] PeopleGroup::Connectors::Hris#job_details, use a custom workday report instead.'
|
218
|
+
Workday::Report.call(url: ENV.fetch('WORKDAY_MANAGER_REPORT', nil))
|
218
219
|
end
|
219
220
|
|
220
221
|
def resumes_folder_id(employee_number)
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'savon'
|
4
|
+
require_relative 'xml'
|
5
|
+
|
6
|
+
module PeopleGroup
|
7
|
+
module Connectors
|
8
|
+
module Workday
|
9
|
+
# Workday client
|
10
|
+
class Client
|
11
|
+
include XML::GetOrganizations
|
12
|
+
include XML::RequestOneTimePayment
|
13
|
+
|
14
|
+
XML_NAMESPACES = {
|
15
|
+
'xmlns' => nil,
|
16
|
+
'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/',
|
17
|
+
'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
18
|
+
'xmlns:wsse' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
# The client instance
|
22
|
+
attr_reader :instance
|
23
|
+
|
24
|
+
# Client Options
|
25
|
+
attr_reader :options
|
26
|
+
|
27
|
+
# service uri
|
28
|
+
attr_reader :uri
|
29
|
+
|
30
|
+
# Current Workday API Version
|
31
|
+
API_VERSION = 'v37.0'
|
32
|
+
|
33
|
+
EmployeeNotFoundError = Class.new(StandardError)
|
34
|
+
ClientError = Class.new(StandardError)
|
35
|
+
|
36
|
+
def initialize(options = {})
|
37
|
+
@options = {
|
38
|
+
url: ENV.fetch('WORKDAY_SERVICE_URL', nil),
|
39
|
+
username: ENV.fetch('WORKDAY_ISU_USERNAME', nil),
|
40
|
+
password: ENV.fetch('WORKDAY_ISU_PASSWORD', nil),
|
41
|
+
debug: ENV.fetch('WORKDAY_SOAP_DEBUG_LOGS', false)
|
42
|
+
}.merge!(options)
|
43
|
+
|
44
|
+
@uri = URI.parse(@options[:url])
|
45
|
+
@uri.query = nil
|
46
|
+
|
47
|
+
@instance = client(services)
|
48
|
+
rescue URI::InvalidURIError
|
49
|
+
raise ClientError, "Invalid service URI: #{uri}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def retry_on_error(&block)
|
53
|
+
Utils.retry_on_error(errors: [Net::ReadTimeout], delay: 3, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def call(operation_name, options = {}, &block)
|
57
|
+
response = @instance.call(operation_name, { **options, **attributes }, &block)
|
58
|
+
{ **response.body, code: response.http.code }
|
59
|
+
rescue Savon::UnknownOperationError => e
|
60
|
+
raise ClientError.new(e), cause: nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def auto_paginated_call(operation_name, options = {}, &block)
|
64
|
+
data = nil
|
65
|
+
page = 1
|
66
|
+
|
67
|
+
loop do
|
68
|
+
response = @instance.call(operation_name, { **options, **attributes }, &block)
|
69
|
+
# The response hash contains only one key named after the operation performed
|
70
|
+
# eg. get_workers_response
|
71
|
+
_operation_response_name, operation_result = response.to_hash.first
|
72
|
+
|
73
|
+
page = operation_result.dig(:response_results, :page).to_i
|
74
|
+
total_pages = operation_result.dig(:response_results, :total_pages).to_i
|
75
|
+
|
76
|
+
# The operation data hash contains only one key named after the Workday object(s) retrieved
|
77
|
+
# eg. worker
|
78
|
+
_object_label, partial_data = operation_result[:response_data].first
|
79
|
+
|
80
|
+
page == 1 ? data = partial_data : data.concat(partial_data)
|
81
|
+
|
82
|
+
break if page == total_pages
|
83
|
+
|
84
|
+
page += 1
|
85
|
+
end
|
86
|
+
|
87
|
+
data
|
88
|
+
end
|
89
|
+
|
90
|
+
# Check if workday debug is enabled for the instance.
|
91
|
+
def debug_enabled?
|
92
|
+
@options[:debug] ? true : false
|
93
|
+
end
|
94
|
+
|
95
|
+
# Default Workday specific body paramaters
|
96
|
+
# xmlns:wd - The URN of the XMLNS file
|
97
|
+
# wd:version - The API Version of workday
|
98
|
+
def attributes
|
99
|
+
{ attributes: { 'xmlns:wd' => 'urn:com.workday/bsvc', 'wd:version' => API_VERSION } }
|
100
|
+
end
|
101
|
+
|
102
|
+
# The respective XML Service WSDL URL
|
103
|
+
# https://wd2-impl-services1.workday.com/ccx/service/systemreport2/gitlab/Public_Web_Services
|
104
|
+
# @return [String] The combined url to access the service at
|
105
|
+
def wsdl_url
|
106
|
+
@wsdl_url ||= "#{@uri}/#{API_VERSION}?wsdl"
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def username
|
112
|
+
@options[:username]
|
113
|
+
end
|
114
|
+
|
115
|
+
def password
|
116
|
+
@options[:password]
|
117
|
+
end
|
118
|
+
|
119
|
+
# The current tenant
|
120
|
+
def tenant
|
121
|
+
@tenant ||= @uri.path.split('/')[-2]
|
122
|
+
end
|
123
|
+
|
124
|
+
# Authentication for Soap web service
|
125
|
+
def wsse_auth
|
126
|
+
@wsse_auth ||= ["#{username}@#{tenant}", password]
|
127
|
+
end
|
128
|
+
|
129
|
+
# Enabled services from the service URL
|
130
|
+
# @return [String] Service or services joined with '+'. Example: 'Staffing' or 'Staffing+Compensation'
|
131
|
+
def services
|
132
|
+
@services ||= @uri.path.split('/')[-1] # .split('+')
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the client based on the service.
|
136
|
+
# @param Service [String] The service to use, ie: Staffing, Compensation
|
137
|
+
# @param options [Hash] default options for the client.
|
138
|
+
#
|
139
|
+
# @return [Savon::Client] The client connected to the specified service.
|
140
|
+
def client(_service, options = {})
|
141
|
+
client_opts = {
|
142
|
+
log: debug_enabled?,
|
143
|
+
wsse_auth: wsse_auth,
|
144
|
+
pretty_print_xml: debug_enabled?,
|
145
|
+
convert_request_keys_to: :camelcase,
|
146
|
+
env_namespace: :env,
|
147
|
+
namespace_identifier: :wd,
|
148
|
+
wsdl: wsdl_url,
|
149
|
+
namespaces: XML_NAMESPACES
|
150
|
+
}.merge!(options)
|
151
|
+
|
152
|
+
Savon.client(**client_opts)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PeopleGroup
|
4
|
+
module Connectors
|
5
|
+
module Workday
|
6
|
+
class ReportError < StandardError
|
7
|
+
def initialize(message = '', request = nil)
|
8
|
+
@request = request
|
9
|
+
@message = message
|
10
|
+
super(message)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Report
|
15
|
+
class Report
|
16
|
+
# The authorization header used for the report.
|
17
|
+
attr_reader :auth_header
|
18
|
+
|
19
|
+
# The parsed URI of the report URL
|
20
|
+
attr_reader :uri
|
21
|
+
|
22
|
+
# Create a new report instance
|
23
|
+
# @param url [String] The report URL without any parameters.
|
24
|
+
# @raises [ReportError]
|
25
|
+
def initialize(url:, password: nil)
|
26
|
+
@uri = URI.parse(url)
|
27
|
+
|
28
|
+
# Ensure URI is properly read
|
29
|
+
raise ReportError, "Error with report URL: #{url}. Is this a valid URL?" unless @uri.scheme && @uri.host && @uri.path
|
30
|
+
|
31
|
+
@uri.query = nil # clear any query params
|
32
|
+
|
33
|
+
# Use provided password or search in env.
|
34
|
+
pass = password || ENV.fetch('WORKDAY_ISU_PASSWORD', nil)
|
35
|
+
|
36
|
+
raise ReportError, "No username provided for report: #{url}" if username.nil?
|
37
|
+
raise ReportError, "No password provided for report: #{url}" if pass.nil?
|
38
|
+
|
39
|
+
# Encode credentials
|
40
|
+
auth = Base64.strict_encode64("#{username}:#{pass}")
|
41
|
+
|
42
|
+
# Base64 Encode
|
43
|
+
@auth_header = { Authorization: "Basic #{auth}" }
|
44
|
+
rescue URI::InvalidURIError
|
45
|
+
raise ReportError, "Invalid URI detected for report: '#{url}'."
|
46
|
+
end
|
47
|
+
|
48
|
+
# @param url [String] The report URL without any parameters
|
49
|
+
# @param prompts [Hash] Report input prompts/parameters.
|
50
|
+
# @return [Array|Hash] the JSON report response.
|
51
|
+
# @see run for more info.
|
52
|
+
def self.call(url:, password: nil, prompts: {})
|
53
|
+
new(url: url, password: password)&.run(prompts)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Run the report with the given prompts
|
57
|
+
# @param [Hash] prompts The report key value pair of parameters or 'prompts' (as referred to in Workday).
|
58
|
+
# @return [Array|Hash] the JSON report response.
|
59
|
+
# @raise [StandardError] if the report returns with any status other than 200.
|
60
|
+
def run(prompts = {})
|
61
|
+
url = report_url(prompts)
|
62
|
+
RestClient.get(url, @auth_header) do |response, _req, _result|
|
63
|
+
# Raise a report error if we ran into any issues accessing the report
|
64
|
+
raise ReportError, inspect, response unless response&.code == 200
|
65
|
+
|
66
|
+
# parse the response body into JSON
|
67
|
+
json = JSON.parse(response.body)
|
68
|
+
|
69
|
+
# if return content of 'Report_Entry' or the whole set if key does not exist.
|
70
|
+
json['Report_Entry'] || json
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Extract username from URI path (needed for auth)
|
75
|
+
def username
|
76
|
+
@username ||= @uri.path.split('/')[-2]
|
77
|
+
end
|
78
|
+
|
79
|
+
# Combine the url and extra input parameters in an encoded format.
|
80
|
+
# @param [Hash] prompts The report prompts/parameters.
|
81
|
+
# @return [String] The @url (report url) combined with report type `?type='json'` and any extra parameters.
|
82
|
+
def report_url(prompts = {})
|
83
|
+
uri = @uri.clone # copy the URI object
|
84
|
+
params = prompts.merge!({ type: :json }) # ensure report format is always JSON
|
85
|
+
uri.query = URI.encode_www_form(params)
|
86
|
+
uri.to_s
|
87
|
+
end
|
88
|
+
|
89
|
+
# Inspect the Workday Report instance
|
90
|
+
def inspect
|
91
|
+
"#<#{self.class.name}:#{object_id} @uri='#{@uri}' @auth_header=#{@auth_header ? 'HIDDEN' : auth_header} @username=#{username}>"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
module PeopleGroup
|
6
|
+
module Connectors
|
7
|
+
module Workday
|
8
|
+
module XML
|
9
|
+
# GetOrganization operation.
|
10
|
+
# @see https://community.workday.com/sites/default/files/file-hosting/productionapi/Staffing/v37.2/Get_Organizations.html
|
11
|
+
module GetOrganizations
|
12
|
+
# The Operation for this Module
|
13
|
+
OPERATION = :get_organizations
|
14
|
+
|
15
|
+
# List all of the active departments.
|
16
|
+
def departments
|
17
|
+
get('Cost_Center')
|
18
|
+
end
|
19
|
+
|
20
|
+
# List all of the active regions.
|
21
|
+
def regions
|
22
|
+
get('Region')
|
23
|
+
end
|
24
|
+
|
25
|
+
# List all of the active entities.
|
26
|
+
def locations
|
27
|
+
@locations ||= get('Company').map { |location| location[:reference_id] }
|
28
|
+
end
|
29
|
+
|
30
|
+
# List all of the active pay groups.
|
31
|
+
def pay_groups
|
32
|
+
get('Pay_Group')
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Call the specified endpoint.
|
38
|
+
# @param type [String] The type of organization to request.
|
39
|
+
# @return [Array<PeopleGroup::Connectors::Models::ObjectifiedHash>] An array of the requested organzation types resources.
|
40
|
+
def get(type, additional = {})
|
41
|
+
options = {
|
42
|
+
**org_request_criteria_by_type(type),
|
43
|
+
**Helpers.default_response_group,
|
44
|
+
**Helpers.pagination_parameters,
|
45
|
+
**additional
|
46
|
+
}
|
47
|
+
|
48
|
+
request = Helpers.construct_options(OPERATION, options)
|
49
|
+
auto_paginated_call(OPERATION, request).map do |data|
|
50
|
+
data[:organization_data]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Get the Request_Criteria via type
|
55
|
+
# @param type [String] Company, Cost Center, Pay Group, Region
|
56
|
+
#
|
57
|
+
# @return [Request_Criteria] The Organiztion_Request_Criteria for the specified type.
|
58
|
+
def org_request_criteria_by_type(type)
|
59
|
+
org_criteria = organization_request_criteria(type: type)
|
60
|
+
Helpers.request_criteria(org_criteria)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Get the Organization_Request_Criteria as a hash.
|
64
|
+
# @param type [String] The type of Organization to perform the search on.
|
65
|
+
# @param include_inactive [boolean] Whether to include inactive organizations, defaults to false.
|
66
|
+
# @param field_and_param_data [Hash] A Hash containing the key value pair of Field and Parameter Criteria Data.
|
67
|
+
def organization_request_criteria(type:, include_inactive: false, field_and_param_data: nil)
|
68
|
+
hash = {
|
69
|
+
'Organization_Type_Reference' => {
|
70
|
+
'ID' => type,
|
71
|
+
:attributes! => { 'ID' => { 'wd:type' => 'Organization_Type_ID' } }
|
72
|
+
},
|
73
|
+
'Include_Inactive' => include_inactive
|
74
|
+
}
|
75
|
+
|
76
|
+
# Only add parameter criteria if present.
|
77
|
+
hash['Field_And_Parameter_Criteria_Data'] = field_and_param_data unless field_and_param_data.nil?
|
78
|
+
|
79
|
+
hash
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PeopleGroup
|
4
|
+
module Connectors
|
5
|
+
module Workday
|
6
|
+
module XML
|
7
|
+
# Common wrapper components for Workday XML queries
|
8
|
+
module Helpers
|
9
|
+
MAX_RESULTS_PER_PAGE = 999
|
10
|
+
|
11
|
+
def self.request_references(refs = {})
|
12
|
+
{
|
13
|
+
'Request_References' => refs
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.response_filter(filters = {})
|
18
|
+
{
|
19
|
+
'Response_Filter' => filters
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
# Default Request Criteria XML Wrapper
|
24
|
+
# @param criteria [Hash] A list of key value pair XML attributes.
|
25
|
+
#
|
26
|
+
# @return [Hash] - The <wd:Request_Criteria> XML Component containing a set of options.
|
27
|
+
def self.request_criteria(criteria = {})
|
28
|
+
{
|
29
|
+
'Request_Criteria' => criteria
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.response_group(group = {})
|
34
|
+
{ 'Response_Group' => group }
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.default_response_group(additional = {})
|
38
|
+
groups = { 'Include_Hierarchy_Data' => false, **additional }
|
39
|
+
response_group groups
|
40
|
+
end
|
41
|
+
|
42
|
+
# Contructs a hash that we can pass into the #call Savon client method.
|
43
|
+
def self.construct_options(operation, message)
|
44
|
+
operation = operation.to_s.split('_').collect(&:capitalize).join('_') unless operation.is_a?(String)
|
45
|
+
{
|
46
|
+
message_tag: "#{operation}_Request",
|
47
|
+
message: message
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.pagination_parameters(page = 1, results_per_page = MAX_RESULTS_PER_PAGE)
|
52
|
+
response_filter(
|
53
|
+
{
|
54
|
+
'Page' => page,
|
55
|
+
'Count' => results_per_page
|
56
|
+
}
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
# The <wd:Employee_Reference> object wrapper.
|
61
|
+
# @param id [Integer] The employee number of the team member.
|
62
|
+
# @return [Hash] The <wd:Employee_Reference> XML wrapper component.
|
63
|
+
def self.team_member_reference(id)
|
64
|
+
{
|
65
|
+
'Employee_Reference' => {
|
66
|
+
'ID' => id,
|
67
|
+
attributes!: { 'ID' => { 'wd:type' => 'Employee_ID' } }
|
68
|
+
}
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'helpers'
|
4
|
+
|
5
|
+
module PeopleGroup
|
6
|
+
module Connectors
|
7
|
+
module Workday
|
8
|
+
module XML
|
9
|
+
# RequestOneTimePayment module
|
10
|
+
# Uses the [PeopleGroup::Connectors::Workday::Client] to add a bonus to the speified team member.
|
11
|
+
# @see https://community.workday.com/sites/default/files/file-hosting/productionapi/Compensation/v37.0/Request_One-Time_Payment.html
|
12
|
+
module RequestOneTimePayment
|
13
|
+
# The Operation for this Module
|
14
|
+
OPERATION = :request_one_time_payment
|
15
|
+
OPERATION_AS_PARAM = 'Request_One-Time_Payment'
|
16
|
+
|
17
|
+
# The amount in USD to give for bonuses, must be a decimal.
|
18
|
+
DISCRETIONARY_BONUS = 1000.0
|
19
|
+
|
20
|
+
# Adds a bonus to the team members
|
21
|
+
# @param employee_number [Integer] The Employee Number of the team member receiving the bonus.
|
22
|
+
# @param comment [String] The comment to leave on the business process.
|
23
|
+
def add_bonus(employee_number, comment)
|
24
|
+
options = {
|
25
|
+
**business_process_params(comment),
|
26
|
+
**one_time_payment_data(employee_number, comment)
|
27
|
+
}
|
28
|
+
|
29
|
+
request = Helpers.construct_options(OPERATION_AS_PARAM, options)
|
30
|
+
call(OPERATION, request)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# https://community.workday.com/sites/default/files/file-hosting/productionapi/Compensation/v37.0/Request_One-Time_Payment.html#Business_Process_ParametersType
|
36
|
+
# @param comment [String] The comment associated with the bonus.
|
37
|
+
# @param run_now: [Boolean] Defaults to true to process this transaction immediatley.
|
38
|
+
# @param auto_complete: [Boolean] Defaults to true to apply this bonus without needing approval.
|
39
|
+
#
|
40
|
+
# @return [Hash] The <wd:Business_Process_Parameters> for this request.
|
41
|
+
def business_process_params(comment, run_now: true, auto_complete: true)
|
42
|
+
{
|
43
|
+
'Business_Process_Parameters' => {
|
44
|
+
'Auto_Complete' => auto_complete,
|
45
|
+
'Run_Now' => run_now,
|
46
|
+
|
47
|
+
# Comment Data
|
48
|
+
# https://community.workday.com/sites/default/files/file-hosting/productionapi/Compensation/v37.0/Request_One-Time_Payment.html#Business_Process_Comment_DataType
|
49
|
+
'Comment_Data' => {
|
50
|
+
'Comment' => comment
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
# The Effective Date parameter for when to apply the payment, defaults to today.
|
57
|
+
# @param date [Date] The day to apply the payment.
|
58
|
+
# @return [Hash] The <wd:Effective_Date> parameter set to the specified date.
|
59
|
+
def effective_date(date = Date.today)
|
60
|
+
{
|
61
|
+
'Effective_Date' => date.to_s
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
# The payment specific data for what should be applied.
|
66
|
+
# @param comment [String] The comment for the discretionary bonus.
|
67
|
+
# @param amount [Double] The amount to include in the bonus with decimal accuracy.
|
68
|
+
def one_time_payment_sub_data(comment, amount = DISCRETIONARY_BONUS)
|
69
|
+
{
|
70
|
+
'One-Time_Payment_Sub_Data' => {
|
71
|
+
**payment_plan_reference,
|
72
|
+
'Amount' => amount,
|
73
|
+
'Comment' => comment
|
74
|
+
}
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
# The type of one time payment we want to group this under.
|
79
|
+
def payment_plan_reference
|
80
|
+
{
|
81
|
+
'One_Time_Payment_Plan_Reference' => {
|
82
|
+
'ID' => 'Discretionary Bonus',
|
83
|
+
attributes!: { 'ID' => { 'wd:type' => 'One-Time_Payment_Plan_ID' } }
|
84
|
+
}
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
# https://community.workday.com/sites/default/files/file-hosting/productionapi/Compensation/v37.0/Request_One-Time_Payment.html#Request_One-Time_Payment_DataType
|
89
|
+
# @param employee_number [Integer] The team member's employee number.
|
90
|
+
# @param comment [String] A comment describing why the payment is being requested.
|
91
|
+
# @return [Hash] The <wd:One-Time_Payment_Data> component.
|
92
|
+
def one_time_payment_data(employee_number, comment)
|
93
|
+
{
|
94
|
+
'One-Time_Payment_Data' => {
|
95
|
+
**Helpers.team_member_reference(employee_number),
|
96
|
+
**effective_date,
|
97
|
+
**one_time_payment_sub_data(comment)
|
98
|
+
}
|
99
|
+
}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|