kuali_toolbox 0.18
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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.gitignore +14 -0
- data/.travis.yml +10 -0
- data/Account_Provisioning_CSV_Template.xlsx +0 -0
- data/Gemfile +20 -0
- data/LICENSE.txt +663 -0
- data/README.md +57 -0
- data/Rakefile +26 -0
- data/bin/transform_CSV_to_HR_XML +332 -0
- data/bin/validate_HR_XML +32 -0
- data/kuali_toolbox.gemspec +48 -0
- data/lib/kuali_toolbox/etl/grm.rb +394 -0
- data/lib/kuali_toolbox/etl.rb +410 -0
- data/lib/kuali_toolbox/version.rb +20 -0
- data/lib/kuali_toolbox.rb +23 -0
- data/spec/kuali_toolbox/etl/grm_spec.rb +620 -0
- data/spec/kuali_toolbox/etl_spec.rb +521 -0
- data/spec/kuali_toolbox_spec.rb +27 -0
- data/spec/spec_helper.rb +42 -0
- data.tar.gz.sig +0 -0
- metadata +190 -0
- metadata.gz.sig +0 -0
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# kuali_toolbox
|
2
|
+
|
3
|
+
[](https://travis-ci.org/KualiCo/kuali_toolbox)
|
4
|
+
[](https://codeclimate.com/github/KualiCo/kuali_toolbox)
|
5
|
+
[](http://badge.fury.io/rb/kuali_toolbox)
|
6
|
+
|
7
|
+
Client library and command-line tools to help interact with KualiCo's cloud APIs.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
To simply install the gem and provide access to the command line tools:
|
12
|
+
|
13
|
+
$ gem install kuali_toolbox
|
14
|
+
|
15
|
+
However, if you would like to reuse the our ruby modules in your own ruby program,
|
16
|
+
add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'kuali_toolbox'
|
20
|
+
```
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle install
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
### transform_CSV_to_HR_XML
|
29
|
+
|
30
|
+
```
|
31
|
+
Usage: transform_CSV_to_HR_XML [options] csv_file
|
32
|
+
-o, --output [xml_file_output] The file in which the the XML data will be writen (defaults to <csv_file>.xml)
|
33
|
+
-s [separator_character], The character that separates each column of the CSV file.
|
34
|
+
--separator
|
35
|
+
-q, --quote [quote_character] The character used to quote fields.
|
36
|
+
-e, --email [email_recipients] Email recipient list that will receive job report status.
|
37
|
+
-u, --username [username] The username used to authenticate to the HR REST API.
|
38
|
+
-p, --password [password] The password used to authenticate to the HR REST API.
|
39
|
+
-l, --url [url] The full URL of the HR REST API; e.g. https://localhost/kc-dev/hr-import/hrimport/import
|
40
|
+
-h, --help Display this screen
|
41
|
+
```
|
42
|
+
> Note: Please be sure to use the [Account_Provisioning_CSV_Template.xlsx](https://github.com/KualiCo/kuali_toolbox/raw/master/Account_Provisioning_CSV_Template.xlsx) template with this tool.
|
43
|
+
|
44
|
+
### validate_HR_XML
|
45
|
+
|
46
|
+
```
|
47
|
+
Usage: validate_HR_XML xml_file
|
48
|
+
-h, --help Display this screen
|
49
|
+
```
|
50
|
+
|
51
|
+
## Contributing
|
52
|
+
|
53
|
+
1. Fork it: https://github.com/KualiCo/kuali_toolbox/fork
|
54
|
+
2. Create your feature branch: `git checkout -b my-new-feature`
|
55
|
+
3. Commit your changes: `git commit -am 'Add some feature'`
|
56
|
+
4. Push to the branch: `git push origin my-new-feature`
|
57
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# KualiCo's client library and command-line tool to help interact with KualiCo's cloud APIs.
|
2
|
+
# Copyright (C) 2014-2015 KualiCo, Inc.
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require "bundler/gem_tasks"
|
18
|
+
require "rspec/core/rake_task"
|
19
|
+
|
20
|
+
task :default => [:spec]
|
21
|
+
task :test => [:spec]
|
22
|
+
|
23
|
+
desc "Run the specs."
|
24
|
+
RSpec::Core::RakeTask.new do |t|
|
25
|
+
t.pattern = "spec/**/*_spec.rb"
|
26
|
+
end
|
@@ -0,0 +1,332 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
|
6
|
+
require 'builder'
|
7
|
+
require 'csv'
|
8
|
+
require 'optparse'
|
9
|
+
require 'rest_client'
|
10
|
+
require 'time'
|
11
|
+
require 'kuali_toolbox/etl/grm'
|
12
|
+
|
13
|
+
ETL = KualiCo::ETL
|
14
|
+
GRM = KualiCo::ETL::GRM
|
15
|
+
TextParseError = KualiCo::ETL::TextParseError
|
16
|
+
|
17
|
+
def self.parse_command_line_options(
|
18
|
+
executable, args, opt={ csv_options: { headers: :first_row,
|
19
|
+
header_converters: :symbol,
|
20
|
+
skip_blanks: true,
|
21
|
+
col_sep: ",", # comma by default
|
22
|
+
quote_char: '"', # double quote by default
|
23
|
+
}
|
24
|
+
} )
|
25
|
+
optparse = OptionParser.new do |opts|
|
26
|
+
opts.banner = "Usage: #{executable} [options] csv_file"
|
27
|
+
opts.on( '-o [xml_file_output]' ,'--output [xml_file_output]', 'The file in which the the XML data will be writen (defaults to <csv_file>.xml)') do |f|
|
28
|
+
opt[:xml_filename] = f
|
29
|
+
end
|
30
|
+
opts.on( '-s [separator_character]' ,'--separator [separator_character]', 'The character that separates each column of the CSV file.' ) do |s|
|
31
|
+
opt[:col_sep] = s
|
32
|
+
end
|
33
|
+
opts.on( '-q [quote_character]' ,'--quote [quote_character]', 'The character used to quote fields.' ) do |q|
|
34
|
+
opt[:quote_char] = q
|
35
|
+
end
|
36
|
+
opts.on( '-e [email_recipients]', '--email [email_recipients]', 'Email recipient list that will receive job report status.' ) do |e|
|
37
|
+
opt[:email_recipients] = e
|
38
|
+
end
|
39
|
+
opts.on( '-u [username]', '--username [username]', 'The username used to authenticate to the HR REST API.' ) do |u|
|
40
|
+
opt[:username] = u
|
41
|
+
end
|
42
|
+
opts.on( '-p [password]', '--password [password]', 'The password used to authenticate to the HR REST API.' ) do |p|
|
43
|
+
opt[:password] = p
|
44
|
+
end
|
45
|
+
opts.on( '-l [url]', '--url [url]', 'The full URL of the HR REST API; e.g. https://localhost/kc-dev/hr-import/hrimport/import' ) do |l|
|
46
|
+
opt[:url] = l
|
47
|
+
end
|
48
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
49
|
+
puts opts
|
50
|
+
exit 1
|
51
|
+
end
|
52
|
+
|
53
|
+
opt[:csv_filename] = args[0] unless opt[:csv_filename]
|
54
|
+
if opt[:csv_filename].nil? || opt[:csv_filename].empty?
|
55
|
+
puts opts
|
56
|
+
exit 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
optparse.parse!
|
60
|
+
|
61
|
+
# construct a sensible default ouptput filename
|
62
|
+
unless opt[:xml_filename]
|
63
|
+
file_extension = File.extname opt[:csv_filename]
|
64
|
+
dir_name = File.dirname opt[:csv_filename]
|
65
|
+
base_name = File.basename opt[:csv_filename], file_extension
|
66
|
+
opt[:xml_filename] = "#{dir_name}/#{base_name}.xml"
|
67
|
+
end
|
68
|
+
|
69
|
+
unless opt[:email_recipients]
|
70
|
+
opt[:email_recipients] = "no-reply@kuali.co"
|
71
|
+
end
|
72
|
+
|
73
|
+
if opt[:url]
|
74
|
+
unless opt[:username] && opt[:password]
|
75
|
+
raise ArgumentError, "Username and password are required when POSTing to a URL!"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
return opt
|
80
|
+
end
|
81
|
+
|
82
|
+
opt = parse_command_line_options (File.basename $0), ARGF.argv
|
83
|
+
|
84
|
+
text_parse_errors = []
|
85
|
+
|
86
|
+
CSV.open(opt[:csv_filename], opt[:csv_options]) do |csv|
|
87
|
+
record_count = csv.readlines.count
|
88
|
+
csv.rewind # go back to first row
|
89
|
+
|
90
|
+
File.open(opt[:xml_filename], 'w') do |xml_file|
|
91
|
+
xml = Builder::XmlMarkup.new target: xml_file, indent: 2
|
92
|
+
xml.instruct! :xml, encoding: "UTF-8"
|
93
|
+
xml.hrmanifest "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
94
|
+
"xsi:schemaLocation" => "https://github.com/KualiCo/ce-tech-docs/tree/master/v1_0 https://raw.github.com/KualiCo/ce-tech-docs/master/v1_0/hrmanifest.xsd",
|
95
|
+
xmlns: "https://github.com/KualiCo/ce-tech-docs/tree/master/v1_0",
|
96
|
+
schemaVersion: "1.0",
|
97
|
+
statusEmailRecipient: opt[:email_recipients],
|
98
|
+
reportDate: Time.now.iso8601,
|
99
|
+
recordCount: record_count do |hrmanifest|
|
100
|
+
hrmanifest.records do |record|
|
101
|
+
csv.find_all do |row| # begin processing csv rows
|
102
|
+
begin
|
103
|
+
xml.record principalId: GRM.parse_principal_id( row[:prncpl_id] ),
|
104
|
+
principalName: GRM.parse_principal_name( row[:prncpl_nm] ) do |record|
|
105
|
+
record.affiliations do |affiliations|
|
106
|
+
aff = {}
|
107
|
+
afltn_typ_cd = ETL.parse_string row[:afltn_typ_cd], name: 'AFLTN_TYP_CD', length: 40, required: true
|
108
|
+
campus = ETL.parse_string row[:campus_cd], name: 'CAMPUS_CD', length: 2
|
109
|
+
aff[:affiliationType] = afltn_typ_cd unless afltn_typ_cd.empty?
|
110
|
+
aff[:campus] = campus unless campus.empty?
|
111
|
+
aff[:default] = true
|
112
|
+
aff[:active] = true
|
113
|
+
|
114
|
+
affiliations.affiliation aff do |affiliation|
|
115
|
+
emp = {}
|
116
|
+
emp_stat_cd = GRM.parse_emp_stat_cd row[:emp_stat_cd]
|
117
|
+
emp_typ_cd = GRM.parse_emp_typ_cd row[:emp_typ_cd]
|
118
|
+
base_slry_amt = ETL.parse_float row[:base_slry_amt], length: 15, name: 'BASE_SLRY_AMT'
|
119
|
+
prmry_dept_cd = ETL.parse_string row[:prmry_dept_cd], length: 40, name: 'PRMRY_DEPT_CD'
|
120
|
+
emp_id = ETL.parse_string row[:emp_id], length: 40, name: 'EMP_ID'
|
121
|
+
emp[:employeeStatus] = emp_stat_cd unless emp_stat_cd.empty?
|
122
|
+
emp[:employeeType] = emp_typ_cd unless emp_typ_cd.empty?
|
123
|
+
emp[:baseSalaryAmount] = base_slry_amt unless base_slry_amt.nil?
|
124
|
+
emp[:primaryDepartment] = prmry_dept_cd unless prmry_dept_cd.empty?
|
125
|
+
emp[:employeeId] = emp_id unless emp_id.empty?
|
126
|
+
emp[:primaryEmployment] = true
|
127
|
+
|
128
|
+
affiliation.employment emp
|
129
|
+
end
|
130
|
+
end # affiliations
|
131
|
+
|
132
|
+
address = {}
|
133
|
+
addr_typ_cd = GRM.parse_address_type_code( row[:addr_typ_cd] )
|
134
|
+
addr_line_1 = ETL.parse_string( row[:addr_line_1], name: 'ADDR_LINE_1', length: 45 )
|
135
|
+
addr_line_2 = ETL.parse_string( row[:addr_line_2], name: 'ADDR_LINE_2', length: 45 )
|
136
|
+
addr_line_3 = ETL.parse_string( row[:addr_line_3], name: 'ADDR_LINE_3', length: 45 )
|
137
|
+
city = ETL.parse_string( row[:city], name: 'CITY', length: 30 )
|
138
|
+
state_pvc_cd = ETL.parse_string( row[:state_pvc_cd], name: 'STATE_PVC_CD', length: 2 )
|
139
|
+
postal_cd = ETL.parse_string( row[:postal_cd], name: 'POSTAL_CD', length: 20 )
|
140
|
+
postal_cntry_cd = ETL.parse_string( row[:postal_cntry_cd], name: 'POSTAL_CNTRY_CD', length: 2 )
|
141
|
+
address[:addressTypeCode] = addr_typ_cd unless addr_typ_cd.empty?
|
142
|
+
address[:addressLine1] = addr_line_1 unless addr_line_1.empty?
|
143
|
+
address[:addressLine2] = addr_line_2 unless addr_line_2.empty?
|
144
|
+
address[:addressLine3] = addr_line_3 unless addr_line_3.empty?
|
145
|
+
address[:city] = city unless city.empty?
|
146
|
+
address[:stateOrProvince] = state_pvc_cd unless state_pvc_cd.empty?
|
147
|
+
address[:postalCode] = postal_cd unless postal_cd.empty?
|
148
|
+
address[:country] = postal_cntry_cd unless postal_cntry_cd.empty?
|
149
|
+
unless address.empty?
|
150
|
+
record.addresses do |addresses|
|
151
|
+
addresses.address address
|
152
|
+
end # addresses
|
153
|
+
end
|
154
|
+
|
155
|
+
record.names do |names|
|
156
|
+
nm = {}
|
157
|
+
nm_typ_cd = GRM.parse_name_code row[:nm_typ_cd]
|
158
|
+
prefix_nm = GRM.parse_prefix row[:prefix_nm]
|
159
|
+
first_nm = ETL.parse_string row[:first_nm], length: 40, name: 'FIRST_NM'
|
160
|
+
middle_nm = ETL.parse_string row[:middle_nm], length: 40, name: 'MIDDLE_NM'
|
161
|
+
last_nm = ETL.parse_string row[:last_nm], length: 80, name: 'LAST_NM'
|
162
|
+
suffix_nm = GRM.parse_suffix row[:suffix_nm]
|
163
|
+
title_nm = ETL.parse_string row[:title_nm], length: 20, name: 'TITLE_NM'
|
164
|
+
nm[:nameCode] = nm_typ_cd unless nm_typ_cd.empty?
|
165
|
+
nm[:prefix] = prefix_nm unless prefix_nm.empty?
|
166
|
+
nm[:firstName] = first_nm unless first_nm.empty?
|
167
|
+
nm[:middleName] = middle_nm unless middle_nm.empty?
|
168
|
+
nm[:lastName] = last_nm unless last_nm.empty?
|
169
|
+
nm[:suffix] = suffix_nm unless suffix_nm.empty?
|
170
|
+
nm[:title] = title_nm unless title_nm.empty?
|
171
|
+
nm[:default] = true
|
172
|
+
nm[:active] = true
|
173
|
+
|
174
|
+
names.name nm
|
175
|
+
end # names
|
176
|
+
|
177
|
+
ph = {}
|
178
|
+
phone_typ_cd = GRM.parse_phone_type row[:phone_typ_cd]
|
179
|
+
phone_nbr = GRM.parse_phone_number row[:phone_nbr]
|
180
|
+
phone_extn_nbr = ETL.parse_string row[:phone_extn_nbr], length: 8, name: 'PHONE_EXTN_NBR'
|
181
|
+
phone_cntry_cd = ETL.parse_string row[:phone_cntry_cd], length: 2, name: 'PHONE_CNTRY_CD'
|
182
|
+
ph[:phoneType] = phone_typ_cd unless phone_typ_cd.empty?
|
183
|
+
ph[:phoneNumber] = phone_nbr unless phone_nbr.empty?
|
184
|
+
ph[:extension] = phone_extn_nbr unless phone_extn_nbr.empty?
|
185
|
+
ph[:country] = phone_cntry_cd unless phone_cntry_cd.empty?
|
186
|
+
ph[:default] = true
|
187
|
+
ph[:active] = true
|
188
|
+
|
189
|
+
unless phone_typ_cd.empty? || phone_nbr.empty?
|
190
|
+
record.phones do |phones|
|
191
|
+
phones.phone ph
|
192
|
+
end # phones
|
193
|
+
end
|
194
|
+
|
195
|
+
em = {}
|
196
|
+
email_typ_cd = GRM.parse_email_type( row[:email_typ_cd] )
|
197
|
+
email_addr = GRM.parse_email_address( row[:email_addr] )
|
198
|
+
em[:emailType] = email_typ_cd unless email_typ_cd.empty?
|
199
|
+
em[:emailAddress] = email_addr unless email_addr.empty?
|
200
|
+
em[:default] = true
|
201
|
+
em[:active] = true
|
202
|
+
|
203
|
+
unless email_typ_cd.empty? || email_addr.empty?
|
204
|
+
record.emails do |emails|
|
205
|
+
emails.email em unless email_addr.empty?
|
206
|
+
end # emails
|
207
|
+
end
|
208
|
+
|
209
|
+
ea = {}
|
210
|
+
visa_type = ETL.parse_string( row[:visa_type], length: 30, name: 'VISA_TYPE' )
|
211
|
+
county = ETL.parse_string( row[:county], length: 30, name: 'COUNTY' )
|
212
|
+
age_by_fiscal_year = ETL.parse_integer( row[:age_by_fiscal_year], length: 3, name: 'AGE_BY_FISCAL_YEAR' )
|
213
|
+
race = ETL.parse_string( row[:race], length: 30, name: 'RACE' )
|
214
|
+
education_level = ETL.parse_string( row[:education_level], length: 30, name: 'EDUCATION_LEVEL' )
|
215
|
+
degree = GRM.parse_degree( row[:degree], name: 'DEGREE' )
|
216
|
+
major = ETL.parse_string( row[:major], length: 30, name: 'MAJOR' )
|
217
|
+
is_handicapped = ETL.parse_boolean( row[:is_handicapped], name: 'IS_HANDICAPPED' )
|
218
|
+
handicap_type = ETL.parse_string( row[:handicap_type], length: 30, name: 'HANDICAP_TYPE' )
|
219
|
+
is_veteran = ETL.parse_boolean( row[:is_veteran], name: 'IS_VETERAN' )
|
220
|
+
veteran_type = ETL.parse_string( row[:veteran_type], length: 30, name: 'VETERAN_TYPE' )
|
221
|
+
has_visa = ETL.parse_boolean( row[:has_visa], name: 'HAS_VISA' )
|
222
|
+
visa_code = ETL.parse_string( row[:visa_code], length: 20, name: 'VISA_CODE' )
|
223
|
+
visa_renewal_date = ETL.parse_string( row[:visa_renewal_date], length: 19, name: 'VISA_RENEWAL_DATE' )
|
224
|
+
office_location = ETL.parse_string( row[:office_location], length: 30, name: 'OFFICE_LOCATION' )
|
225
|
+
secondry_office_location = ETL.parse_string( row[:secondry_office_location], length: 30, name: 'SECONDRY_OFFICE_LOCATION' )
|
226
|
+
school = ETL.parse_string( row[:school], length: 50, name: 'SCHOOL' )
|
227
|
+
year_graduated = GRM.parse_year( row[:year_graduated], name: 'YEAR_GRADUATED' )
|
228
|
+
directory_department = ETL.parse_string( row[:directory_department], length: 30, name: 'DIRECTORY_DEPARTMENT' )
|
229
|
+
directory_title = ETL.parse_string( row[:directory_title], length: 50, name: 'DIRECTORY_TITLE' )
|
230
|
+
primary_title = ETL.parse_string( row[:primary_title], length: 51, name: 'PRIMARY_TITLE' )
|
231
|
+
vacation_accural = ETL.parse_boolean( row[:vacation_accural], name: 'VACATION_ACCURAL' )
|
232
|
+
is_on_sabbatical = ETL.parse_boolean( row[:is_on_sabbatical], name: 'IS_ON_SABBATICAL' )
|
233
|
+
id_provided = ETL.parse_string( row[:id_provided], length: 30, name: 'ID_PROVIDED' )
|
234
|
+
id_verified = ETL.parse_string( row[:id_verified], length: 30, name: 'ID_VERIFIED' )
|
235
|
+
citizenship_type_code = GRM.parse_citizenship_type( row[:citizenship_type_code] )
|
236
|
+
multi_campus_principal_id = ETL.parse_string( row[:multi_campus_principal_id], length: 40, name: 'MULTI_CAMPUS_PRINCIPAL_ID' )
|
237
|
+
multi_campus_principal_name = ETL.parse_string( row[:multi_campus_principal_name], length: 100, name: 'MULTI_CAMPUS_PRINCIPAL_NAME' )
|
238
|
+
salary_anniversary_date = ETL.parse_string( row[:salary_anniversary_date], length: 10, name: 'SALARY_ANNIVERSARY_DATE' )
|
239
|
+
ea[:visaType] = visa_type unless visa_type.empty?
|
240
|
+
ea[:county] = county unless county.empty?
|
241
|
+
ea[:ageByFiscalYear] = age_by_fiscal_year unless age_by_fiscal_year.nil?
|
242
|
+
ea[:race] = race unless race.empty?
|
243
|
+
ea[:educationLevel] = education_level unless education_level.empty?
|
244
|
+
ea[:degree] = degree unless degree.empty?
|
245
|
+
ea[:major] = major unless major.empty?
|
246
|
+
ea[:handicapped] = is_handicapped unless is_handicapped.nil?
|
247
|
+
ea[:handicapType] = handicap_type unless handicap_type.empty?
|
248
|
+
ea[:veteran] = is_veteran unless is_veteran.nil?
|
249
|
+
ea[:veteranType] = veteran_type unless veteran_type.empty?
|
250
|
+
ea[:visa] = has_visa unless has_visa.nil?
|
251
|
+
ea[:visaCode] = visa_code unless visa_code.empty?
|
252
|
+
ea[:visaRenewalDate] = visa_renewal_date unless visa_renewal_date.empty?
|
253
|
+
ea[:officeLocation] = office_location unless office_location.empty?
|
254
|
+
ea[:secondaryOfficeLocation] = secondry_office_location unless secondry_office_location.empty?
|
255
|
+
ea[:school] = school unless school.empty?
|
256
|
+
ea[:yearGraduated] = year_graduated unless year_graduated.empty?
|
257
|
+
ea[:directoryDepartment] = directory_department unless directory_department.empty?
|
258
|
+
ea[:directoryTitle] = directory_title unless directory_title.empty?
|
259
|
+
ea[:primaryTitle] = primary_title unless primary_title.empty?
|
260
|
+
ea[:vacationAccrual] = vacation_accural unless vacation_accural.nil?
|
261
|
+
ea[:onSabbatical] = is_on_sabbatical unless is_on_sabbatical.nil?
|
262
|
+
ea[:idProvided] = id_provided unless id_provided.empty?
|
263
|
+
ea[:idVerified] = id_verified unless id_verified.empty?
|
264
|
+
ea[:citizenshipType] = citizenship_type_code unless citizenship_type_code.empty?
|
265
|
+
ea[:multiCampusPrincipalId] = multi_campus_principal_id unless multi_campus_principal_id.empty?
|
266
|
+
ea[:multiCampusPrincipalName] = multi_campus_principal_name unless multi_campus_principal_name.empty?
|
267
|
+
ea[:salaryAnniversaryDate] = salary_anniversary_date unless salary_anniversary_date.empty?
|
268
|
+
|
269
|
+
record.kcExtendedAttributes ea
|
270
|
+
|
271
|
+
ap = {}
|
272
|
+
unit_number = ETL.parse_string( row[:unit_number], length: 8, name: 'UNIT_NUMBER' )
|
273
|
+
appointment_type_code = ETL.parse_string( row[:appointment_type_code], length: 3, name: 'APPOINTMENT_TYPE_CODE' )
|
274
|
+
job_code = ETL.parse_string( row[:job_code], length: 6, name: 'JOB_CODE' )
|
275
|
+
salary = ETL.parse_float( row[:salary], length: 15, name: 'SALARY' )
|
276
|
+
appointment_start_date = ETL.parse_string( row[:appointment_start_date], name: 'APPOINTMENT_START_DATE' )
|
277
|
+
appointment_end_date = ETL.parse_string( row[:appointment_end_date], name: 'APPOINTMENT_END_DATE' )
|
278
|
+
job_title = ETL.parse_string( row[:job_title], length: 50, name: 'JOB_TITLE' )
|
279
|
+
prefered_job_title = ETL.parse_string( row[:prefered_job_title], length: 51, name: 'PREFERED_JOB_TITLE' )
|
280
|
+
ap[:unitNumber] = unit_number unless unit_number.empty?
|
281
|
+
ap[:appointmentType] = appointment_type_code unless appointment_type_code.empty?
|
282
|
+
ap[:jobCode] = job_code unless job_code.empty?
|
283
|
+
ap[:salary] = salary unless salary.nil?
|
284
|
+
ap[:startDate] = appointment_start_date unless appointment_start_date.empty?
|
285
|
+
ap[:endDate] = appointment_end_date unless appointment_end_date.empty?
|
286
|
+
ap[:jobTitle] = job_title unless job_title.empty?
|
287
|
+
ap[:preferedJobTitle] = prefered_job_title unless prefered_job_title.empty?
|
288
|
+
|
289
|
+
unless unit_number.empty? || job_code.empty?
|
290
|
+
record.appointments do |appointments|
|
291
|
+
appointments.appointment ap
|
292
|
+
end # appointments
|
293
|
+
end
|
294
|
+
end # record
|
295
|
+
|
296
|
+
rescue TextParseError => e
|
297
|
+
puts e.message
|
298
|
+
text_parse_errors.push e
|
299
|
+
end
|
300
|
+
end # row
|
301
|
+
end # record
|
302
|
+
end # hrmanifest
|
303
|
+
end # xml_file
|
304
|
+
end # csv
|
305
|
+
|
306
|
+
def number_of_errors(parse_errors_array)
|
307
|
+
num_errors = 0
|
308
|
+
unless parse_errors_array.empty?
|
309
|
+
parse_errors_array.each do |err|
|
310
|
+
num_errors += 1 if err.message.start_with? "ERROR"
|
311
|
+
end
|
312
|
+
end
|
313
|
+
return num_errors
|
314
|
+
end
|
315
|
+
|
316
|
+
num_errors = number_of_errors text_parse_errors
|
317
|
+
if num_errors > 0
|
318
|
+
puts "\n#{num_errors} errors found and must be corrected.\n\n"
|
319
|
+
File.unlink opt[:xml_filename]
|
320
|
+
exit 1
|
321
|
+
end
|
322
|
+
|
323
|
+
puts "\nXML file written to #{opt[:xml_filename]}\n\n"
|
324
|
+
|
325
|
+
exit 1 unless GRM.validate_hr_xml opt[:xml_filename]
|
326
|
+
|
327
|
+
# POST the XML file to the server if opt[:url]
|
328
|
+
if opt[:url]
|
329
|
+
resource = RestClient::Resource.new( opt[:url], opt[:username], opt[:password] )
|
330
|
+
resource.post file: File.new(opt[:xml_filename], 'rt'), content_type: 'multipart/form-data', multipart: true
|
331
|
+
puts "\n"
|
332
|
+
end
|
data/bin/validate_HR_XML
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require 'kuali_toolbox/etl/grm'
|
8
|
+
|
9
|
+
GRM = KualiCo::ETL::GRM
|
10
|
+
|
11
|
+
def self.parse_command_line_options( executable, args, opt={} )
|
12
|
+
optparse = OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: #{executable} xml_file"
|
14
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
15
|
+
puts opts
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
|
19
|
+
opt[:xml_filename] = args[0] unless opt[:xml_filename]
|
20
|
+
if opt[:xml_filename].nil? || opt[:xml_filename].empty?
|
21
|
+
puts opts
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
optparse.parse!
|
26
|
+
|
27
|
+
return opt
|
28
|
+
end
|
29
|
+
|
30
|
+
opt = parse_command_line_options (File.basename $0), ARGF.argv
|
31
|
+
|
32
|
+
exit 1 unless GRM.validate_hr_xml opt[:xml_filename]
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# KualiCo's client library and command-line tool to help interact with KualiCo's cloud APIs.
|
2
|
+
# Copyright (C) 2014-2015 KualiCo, Inc.
|
3
|
+
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU Affero General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU Affero General Public License for more details.
|
13
|
+
|
14
|
+
# You should have received a copy of the GNU Affero General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
# coding: utf-8
|
18
|
+
lib = File.expand_path('../lib', __FILE__)
|
19
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
20
|
+
require 'kuali_toolbox/version'
|
21
|
+
|
22
|
+
Gem::Specification.new do |spec|
|
23
|
+
spec.name = "kuali_toolbox"
|
24
|
+
spec.version = KualiCo::VERSION
|
25
|
+
spec.authors = ["Lance Speelmon"]
|
26
|
+
spec.email = ["lspeelmon@kuali.co"]
|
27
|
+
spec.summary = %q{Client library and command-line tools to help interact with KualiCo's cloud APIs.}
|
28
|
+
# spec.description = %q{TODO: Write a longer description. Optional.}
|
29
|
+
spec.homepage = "http://kualico.github.io/kuali_toolbox/"
|
30
|
+
spec.metadata = { "issue_tracker" => "https://github.com/KualiCo/kuali_toolbox/issues" }
|
31
|
+
spec.license = "AGPL-3.0"
|
32
|
+
|
33
|
+
spec.files = `git ls-files -z`.split("\x0")
|
34
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
35
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
36
|
+
spec.require_paths = ["lib"]
|
37
|
+
|
38
|
+
spec.add_runtime_dependency 'builder', '~> 3.2.2'
|
39
|
+
spec.add_runtime_dependency 'nokogiri', '~> 1.6.3.1'
|
40
|
+
spec.add_runtime_dependency 'rest-client', '~> 1.7.2'
|
41
|
+
|
42
|
+
spec.required_ruby_version = '>= 1.9'
|
43
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
44
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
45
|
+
spec.add_development_dependency "rspec", "~> 3.0.0"
|
46
|
+
# spec.add_development_dependency "simplecov"
|
47
|
+
spec.add_development_dependency "codeclimate-test-reporter"
|
48
|
+
end
|