eco-helpers 2.0.21 → 2.0.26
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 +4 -4
- data/CHANGELOG.md +101 -4
- data/eco-helpers.gemspec +0 -1
- data/lib/eco/api/common.rb +0 -1
- data/lib/eco/api/common/loaders.rb +2 -0
- data/lib/eco/api/common/loaders/base.rb +58 -0
- data/lib/eco/api/common/loaders/case_base.rb +33 -0
- data/lib/eco/api/common/loaders/error_handler.rb +2 -2
- data/lib/eco/api/common/loaders/parser.rb +30 -5
- data/lib/eco/api/common/loaders/policy.rb +1 -1
- data/lib/eco/api/common/loaders/use_case.rb +1 -1
- data/lib/eco/api/common/people/default_parsers.rb +1 -0
- data/lib/eco/api/common/people/default_parsers/csv_parser.rb +93 -1
- data/lib/eco/api/common/people/default_parsers/xls_parser.rb +53 -0
- data/lib/eco/api/common/people/entries.rb +83 -14
- data/lib/eco/api/common/people/entry_factory.rb +36 -21
- data/lib/eco/api/common/people/person_attribute_parser.rb +8 -0
- data/lib/eco/api/common/people/person_factory.rb +4 -2
- data/lib/eco/api/common/people/person_parser.rb +8 -2
- data/lib/eco/api/common/people/supervisor_helpers.rb +1 -1
- data/lib/eco/api/common/version_patches/ecoportal_api/external_person.rb +0 -8
- data/lib/eco/api/common/version_patches/ecoportal_api/internal_person.rb +0 -8
- data/lib/eco/api/microcases/set_core_with_supervisor.rb +4 -2
- data/lib/eco/api/microcases/set_supervisor.rb +29 -8
- data/lib/eco/api/microcases/with_each.rb +7 -3
- data/lib/eco/api/microcases/with_each_starter.rb +3 -2
- data/lib/eco/api/organization/people.rb +7 -1
- data/lib/eco/api/session.rb +18 -7
- data/lib/eco/api/session/batch.rb +1 -1
- data/lib/eco/api/session/batch/job.rb +42 -9
- data/lib/eco/api/usecases.rb +2 -2
- data/lib/eco/api/usecases/base_case.rb +2 -2
- data/lib/eco/api/usecases/base_io.rb +17 -4
- data/lib/eco/api/usecases/default_cases/create_case.rb +10 -1
- data/lib/eco/api/usecases/default_cases/create_details_case.rb +10 -1
- data/lib/eco/api/usecases/default_cases/create_details_with_supervisor_case.rb +10 -1
- data/lib/eco/api/usecases/default_cases/hris_case.rb +25 -1
- data/lib/eco/api/usecases/default_cases/upsert_case.rb +10 -1
- data/lib/eco/cli/config/default/input.rb +63 -10
- data/lib/eco/cli/config/default/options.rb +40 -8
- data/lib/eco/cli/config/default/usecases.rb +16 -0
- data/lib/eco/cli/config/default/workflow.rb +7 -4
- data/lib/eco/cli/config/filters.rb +6 -2
- data/lib/eco/cli/config/filters/input_filters.rb +3 -2
- data/lib/eco/cli/config/filters/people_filters.rb +3 -2
- data/lib/eco/cli/config/help.rb +1 -1
- data/lib/eco/cli/config/options_set.rb +6 -4
- data/lib/eco/cli/config/use_cases.rb +6 -3
- data/lib/eco/cli/scripting/args_helpers.rb +2 -2
- data/lib/eco/csv.rb +2 -0
- data/lib/eco/language/models/collection.rb +5 -2
- data/lib/eco/version.rb +1 -1
- metadata +4 -22
- data/lib/eco/api/common/base_loader.rb +0 -68
@@ -0,0 +1,53 @@
|
|
1
|
+
class Eco::API::Common::People::DefaultParsers::XLSParser < Eco::API::Common::Loaders::Parser
|
2
|
+
attribute :xls
|
3
|
+
|
4
|
+
attr_accessor :already_required
|
5
|
+
attr_reader :file
|
6
|
+
|
7
|
+
def parser(file, deps)
|
8
|
+
@file = file
|
9
|
+
rows.tap {|r| @file = nil}
|
10
|
+
end
|
11
|
+
|
12
|
+
def serializer(array_hash, deps)
|
13
|
+
raise "Not implemented. TODO: using axlsx or rubyXL gems. See: https://spin.atomicobject.com/2017/03/22/parsing-excel-files-ruby/"
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def headers
|
19
|
+
raise "You should implement this method"
|
20
|
+
end
|
21
|
+
|
22
|
+
def sheet_name
|
23
|
+
0
|
24
|
+
end
|
25
|
+
|
26
|
+
def workbook
|
27
|
+
require_reading_libs!
|
28
|
+
Roo::Spreadsheet.open(file)
|
29
|
+
end
|
30
|
+
|
31
|
+
def spreadheet(name_or_index = sheet_name)
|
32
|
+
workbook.sheet(name_or_index)
|
33
|
+
end
|
34
|
+
|
35
|
+
def rows(target = headers)
|
36
|
+
begin
|
37
|
+
spreadheet.parse(header_search: target)
|
38
|
+
rescue Roo::HeaderRowNotFoundError => e
|
39
|
+
missing = JSON.parse(e.message)
|
40
|
+
logger.warn("The input file is missing these headers: #{missing}")
|
41
|
+
present = target - missing
|
42
|
+
rows(present)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def require_reading_libs!
|
47
|
+
return if already_required
|
48
|
+
require 'roo'
|
49
|
+
require 'roo-xls'
|
50
|
+
already_required = true
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -5,6 +5,42 @@ module Eco
|
|
5
5
|
# Class meant to offer a _collection_ of entries, normally used to get parsed input data.
|
6
6
|
# @attr_reader entries [Array<Eco::API::Common::PeopleEntry] a pure `Array` object.
|
7
7
|
class Entries < Eco::Language::Models::Collection
|
8
|
+
# Error class that allows to handle cases where multiple entries were found for the same criterion.
|
9
|
+
# @note its main purpose to prevent the false pairing of duplicates or override information between different people.
|
10
|
+
class MultipleSearchResults < StandardError
|
11
|
+
attr_reader :candidates, :property
|
12
|
+
# @param msg [String] the basic message error.
|
13
|
+
# @param candiates [Array<PersonEntry>] the entries that match the same search criterion.
|
14
|
+
# @param property [String] the property of the entry model that triggered the error (base of the search criterion).
|
15
|
+
def initialize(msg, candidates: [], property: "email")
|
16
|
+
@candidates = candidates
|
17
|
+
@property = property
|
18
|
+
super(msg + " " + candidates_summary)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param with_index [Boolean] to add an index to each candidate description.
|
22
|
+
# @return [Array<String>] the `candidates` identified
|
23
|
+
def identify_candidates(with_index: false)
|
24
|
+
candidates.map.each_with_index do |entry, i|
|
25
|
+
index = with_index ? "#{i}. " : ""
|
26
|
+
"#{index} #{entry.identify}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Person] the `candidate` in the `index` position
|
31
|
+
def candidate(index)
|
32
|
+
candidates[index]
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def candidates_summary
|
38
|
+
lines = ["The following entries have the same '#{property}':"]
|
39
|
+
lines.concat(identify_candidates(with_index: true)).join("\n ")
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
8
44
|
# build the shortcuts of Collection
|
9
45
|
attr_collection :id, :external_id, :email, :name, :supervisor_id
|
10
46
|
|
@@ -54,19 +90,34 @@ module Eco
|
|
54
90
|
# @!group Searchers
|
55
91
|
|
56
92
|
# Search function to find an `entry` based on one of different options
|
93
|
+
# It searches an entry using the parameters given.
|
94
|
+
# @note This is how the search function actually works:
|
95
|
+
# 1. if eP `id` is given, returns the entry (if found), otherwise...
|
96
|
+
# 2. if `external_id` is given, returns the entry (if found), otherwise...
|
97
|
+
# 3. if `strict` is `false` and `email` is given:
|
98
|
+
# - if there is only 1 entry with that email, returns that entry, otherwise...
|
99
|
+
# - if found but, there are many candidate entries, it raises MultipleSearchResults error
|
100
|
+
# - if entry `external_id` matches `email`, returns that entry
|
101
|
+
# @raise MultipleSearchResults if there are multiple entries with the same `email`
|
102
|
+
# and there's no other criteria to find the entry. It only gets to this point if
|
103
|
+
# `external_id` was **not** provided and we are **not** in 'strict' search mode.
|
104
|
+
# However, it could be we were in `strict` mode and `external_id` was not provided.
|
105
|
+
# @param id [String] the `internal id` of the person
|
106
|
+
# @param external_id [String] the `exernal_id` of the person
|
107
|
+
# @param email [String] the `email` of the person
|
108
|
+
# @param strict [Boolean] if should perform a `:soft` or a `:strict` search. `strict` will avoid repeated email addresses.
|
109
|
+
# @return [Entry, nil] the entry we were searching, or `nil` if not found.
|
57
110
|
def entry(id: nil, external_id: nil, email: nil, strict: false)
|
58
111
|
init_caches
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
pers
|
112
|
+
# normalize values
|
113
|
+
ext_id = !external_id.to_s.strip.empty? && external_id.strip
|
114
|
+
email = !email.to_s.strip.empty? && email.downcase.strip
|
115
|
+
|
116
|
+
e = nil
|
117
|
+
e ||= @by_id[id]&.first
|
118
|
+
e ||= @by_external_id[ext_id]&.first
|
119
|
+
e ||= entry_by_email(email) unless strict && ext_id
|
120
|
+
e
|
70
121
|
end
|
71
122
|
|
72
123
|
# Search function to find an `entry` based on one of different options
|
@@ -136,15 +187,33 @@ module Eco
|
|
136
187
|
|
137
188
|
private
|
138
189
|
|
190
|
+
def entry_by_email(email, prevent_multiple_match: false)
|
191
|
+
return nil unless email
|
192
|
+
|
193
|
+
candidates = @by_email[email] || []
|
194
|
+
return candidates.first if candidates.length == 1
|
195
|
+
|
196
|
+
if prevent_multiple_match && !candidates.empty?
|
197
|
+
msg = "Multiple search results match the criteria."
|
198
|
+
raise MultipleSearchResults.new(msg, candidates: candidates, property: "email")
|
199
|
+
end
|
200
|
+
|
201
|
+
@by_external_id[email]&.first
|
202
|
+
end
|
203
|
+
|
139
204
|
def init_caches
|
140
205
|
return if @caches_init
|
141
|
-
@by_id = to_h
|
142
|
-
@by_external_id = to_h('external_id')
|
143
|
-
@by_email = to_h('email')
|
206
|
+
@by_id = no_nil_key(to_h)
|
207
|
+
@by_external_id = no_nil_key(to_h('external_id'))
|
208
|
+
@by_email = no_nil_key(to_h('email'))
|
144
209
|
@array_supers = sort_by_supervisors(@items)
|
145
210
|
@caches_init = true
|
146
211
|
end
|
147
212
|
|
213
|
+
def no_nil_key(hash)
|
214
|
+
hash.tap {|h| h.delete(nil)}
|
215
|
+
end
|
216
|
+
|
148
217
|
end
|
149
218
|
end
|
150
219
|
end
|
@@ -80,54 +80,69 @@ module Eco
|
|
80
80
|
# @param data [Array<Hash>] data to be parsed. It cannot be used alongside with `file:`
|
81
81
|
# @param file [String] absolute or relative path to the input file. It cannot be used alongside with `data:`.
|
82
82
|
# @param format [Symbol] it must be used when you use the option `file:` (i.e. `:xml`, `:csv`), as it specifies the format of the input `file:`.
|
83
|
-
# @param
|
83
|
+
# @param options [Hash] further options.
|
84
|
+
# @option options [String] :encoding optional parameter to read `file:` by expecting certain encoding.
|
85
|
+
# @option options [Boolean] :check_headers signals if the `csv` file headers should be expected.
|
84
86
|
# @return [Eco::API::Common::People::Entries] collection of `Eco::API::Common::People::PersonEntry`.
|
85
|
-
def entries(data: (no_data = true; nil), file: (no_file = true; nil), format: (no_format = true; nil),
|
87
|
+
def entries(data: (no_data = true; nil), file: (no_file = true; nil), format: (no_format = true; nil), **options)
|
86
88
|
fatal("You should at least use data: or file:, but not both") if no_data == no_file
|
87
89
|
fatal("You must specify a valid format: (symbol) when you use file.") if file && no_format
|
88
90
|
fatal("Format should be a Symbol. Given '#{format}'") if format && !format.is_a?(Symbol)
|
89
91
|
fatal("There is no parser/serializer for format ':#{format.to_s}'") unless no_format || @person_parser.defined?(format)
|
90
92
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
kargs.merge!(format: format) unless no_format
|
95
|
-
kargs.merge!(encoding: encoding) if encoding
|
93
|
+
options.merge!(content: data) unless no_data
|
94
|
+
options.merge!(file: file) unless no_file
|
95
|
+
options.merge!(format: format) unless no_format
|
96
96
|
|
97
|
-
Entries.new(to_array_of_hashes(**
|
97
|
+
Entries.new(to_array_of_hashes(**options), klass: PersonEntry, factory: self)
|
98
98
|
end
|
99
99
|
|
100
100
|
def to_array_of_hashes(**kargs)
|
101
101
|
data = []
|
102
102
|
content, file, encoding, format = kargs.values_at(:content, :file, :encoding, :format)
|
103
103
|
|
104
|
-
|
104
|
+
# Support for multiple file
|
105
|
+
if file.is_a?(Array)
|
106
|
+
return file.each_with_object([]) do |f, out|
|
107
|
+
logger.info("Parsing file '#{f}'")
|
108
|
+
curr = to_array_of_hashes(**kargs.merge(file: f))
|
109
|
+
out.concat(curr)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
# Get content only when it's not :xls
|
113
|
+
# note: even if content was provided, file takes precedence
|
114
|
+
content = get_file_content(file, format, encoding) if (format != :xls) && file
|
105
115
|
|
106
116
|
case content
|
107
|
-
when !content
|
108
|
-
logger.error("Could not obtain any data out of these: #{kargs}")
|
109
|
-
exit(1)
|
110
117
|
when Hash
|
111
118
|
logger.error("Input data as 'Hash' not supported. Expecting 'Enumerable' or 'String'")
|
112
119
|
exit(1)
|
113
120
|
when String
|
114
|
-
|
115
|
-
|
116
|
-
entry_hash.tap {|hash| hash["idx"] = j}
|
117
|
-
end
|
118
|
-
to_array_of_hashes(content: data)
|
121
|
+
deps = {check_headers: true} if kargs[:check_headers]
|
122
|
+
to_array_of_hashes(content: person_parser.parse(format, content, deps: deps || {}))
|
119
123
|
when Enumerable
|
120
124
|
sample = content.to_a.first
|
121
125
|
case sample
|
122
126
|
when Hash, Array, ::CSV::Row
|
123
127
|
Eco::CSV::Table.new(content).to_array_of_hashes
|
124
128
|
else
|
125
|
-
logger.error("Input 'Array' of '#{sample.class}' is not supported.")
|
129
|
+
logger.error("Input content 'Array' of '#{sample.class}' is not supported.")
|
126
130
|
end
|
127
131
|
else
|
128
|
-
|
129
|
-
|
132
|
+
if file && format == :xls
|
133
|
+
person_parser.parse(format, file)
|
134
|
+
else
|
135
|
+
logger.error("Could not obtain any data out of these: #{kargs}. Given content: '#{content.class}'")
|
136
|
+
exit(1)
|
137
|
+
end
|
138
|
+
end.tap do |out_array|
|
139
|
+
start_from_two = (format == :csv) || format == :xls
|
140
|
+
out_array.each_with_index do |entry_hash, i|
|
141
|
+
entry_hash["idx"] = start_from_two ? i + 2 : i + 1
|
142
|
+
entry_hash["source_file"] = file
|
143
|
+
end
|
130
144
|
end
|
145
|
+
|
131
146
|
end
|
132
147
|
|
133
148
|
|
@@ -150,7 +165,7 @@ module Eco
|
|
150
165
|
|
151
166
|
run = true
|
152
167
|
if Eco::API::Common::Session::FileManager.file_exists?(file)
|
153
|
-
prompt_user("
|
168
|
+
prompt_user("Do you want to overwrite it? (Y/n):", explanation: "The file '#{file}' already exists.", default: "Y") do |response|
|
154
169
|
run = (response == "") || reponse.upcase.start_with?("Y")
|
155
170
|
end
|
156
171
|
end
|
@@ -6,6 +6,14 @@ module Eco
|
|
6
6
|
# Class to define a parser/serializer.
|
7
7
|
class PersonAttributeParser < Eco::Language::Models::ParserSerializer
|
8
8
|
|
9
|
+
# @note
|
10
|
+
# - This was introduced at a later stage and might not be available for certain org-parsers configs
|
11
|
+
# @return [RequiredAttrs]
|
12
|
+
def required_attrs
|
13
|
+
@required_attrs ||= @dependencies[:required_attrs]
|
14
|
+
#@required_attrs ||= RequiredAttrs.new(attr, :unkown, [attr])
|
15
|
+
end
|
16
|
+
|
9
17
|
# @see Eco::Language::Models::ParserSerializer#def_parser
|
10
18
|
# @note
|
11
19
|
# - additionally, you can declare a callback `active:` to determine if when the
|
@@ -10,7 +10,7 @@ module Eco
|
|
10
10
|
|
11
11
|
attr_reader :schema, :schema_attrs
|
12
12
|
|
13
|
-
def initialize(person:
|
13
|
+
def initialize(person: nil, schema: {}, account: {}, modifier: Common::People::PersonModifier.new)
|
14
14
|
@modifier = Common::People::PersonModifier.new(modifier)
|
15
15
|
@person = person
|
16
16
|
@account = account
|
@@ -77,7 +77,9 @@ module Eco
|
|
77
77
|
when Hash
|
78
78
|
JSON.parse(person.to_json)
|
79
79
|
else
|
80
|
-
{
|
80
|
+
{
|
81
|
+
"subordinates" => 0
|
82
|
+
}
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
@@ -16,7 +16,7 @@ module Eco
|
|
16
16
|
CORE_ATTRS = ["id", "external_id", "email", "name", "supervisor_id", "filter_tags", "freemium"]
|
17
17
|
ACCOUNT_ATTRS = ["policy_group_ids", "default_tag", "send_invites", "landing_page_id", "login_provider_ids"]
|
18
18
|
TYPE = [:select, :text, :date, :number, :phone_number, :boolean, :multiple]
|
19
|
-
FORMAT = [:csv, :xml, :json]
|
19
|
+
FORMAT = [:csv, :xml, :json, :xls]
|
20
20
|
|
21
21
|
attr_reader :schema
|
22
22
|
attr_reader :details_attrs, :all_model_attrs
|
@@ -59,9 +59,15 @@ module Eco
|
|
59
59
|
|
60
60
|
# @!group Scopping attributes (identifying, presence & active)
|
61
61
|
|
62
|
+
# @return [Array<Eco::API::Common::Loaders::Parser::RequiredAttrs>]
|
63
|
+
def required_attrs
|
64
|
+
@parsers.values_at(*all_attrs(include_defined_parsers: true)).compact.map(&:required_attrs).compact
|
65
|
+
end
|
66
|
+
|
62
67
|
# All the internal name attributes, including _core_, _account_ and _details_.
|
63
68
|
def all_attrs(include_defined_parsers: false)
|
64
|
-
all_model_attrs | defined_model_attrs
|
69
|
+
return all_model_attrs | defined_model_attrs if include_defined_parsers
|
70
|
+
all_model_attrs
|
65
71
|
end
|
66
72
|
|
67
73
|
# Scopes `source_attrs` using the _**core** attributes_.
|
@@ -15,7 +15,7 @@ module Eco
|
|
15
15
|
# Reorders as follows:
|
16
16
|
# 1. supervisors, people with no supervisor or where their supervisor not present
|
17
17
|
# 2. subordinates
|
18
|
-
# @return [Array<
|
18
|
+
# @return [Array<PersonEntry>] `values` sorted by supervisors/subordinates
|
19
19
|
def sort_by_supervisors(values, supervisors_first: true)
|
20
20
|
raise "Expected non hash Enumerable. Given: #{values.class}" if values.is_a?(Hash)
|
21
21
|
return [] unless values && values.is_a?(Enumerable)
|
@@ -5,14 +5,6 @@ module Ecoportal
|
|
5
5
|
class Person
|
6
6
|
attr_accessor :entry
|
7
7
|
|
8
|
-
def reset_details!
|
9
|
-
doc["details"] = JSON.parse(original_doc["details"])
|
10
|
-
end
|
11
|
-
|
12
|
-
def consolidate_details!
|
13
|
-
original_doc["details"] = JSON.parse(doc["details"])
|
14
|
-
end
|
15
|
-
|
16
8
|
def identify(section = :person)
|
17
9
|
if entry && section == :entry
|
18
10
|
entry.to_s(:identify)
|
@@ -3,14 +3,6 @@ module Ecoportal
|
|
3
3
|
class Internal
|
4
4
|
class Person
|
5
5
|
|
6
|
-
def reset_account!
|
7
|
-
doc["account"] = JSON.parse(original_doc["account"])
|
8
|
-
end
|
9
|
-
|
10
|
-
def consolidate_account!
|
11
|
-
original_doc["account"] = JSON.parse(doc["account"])
|
12
|
-
end
|
13
|
-
|
14
6
|
def new?(doc = :initial)
|
15
7
|
ref_doc = (doc == :original) ? original_doc : initial_doc
|
16
8
|
!ref_doc["details"] && !ref_doc["account"]
|
@@ -12,9 +12,11 @@ module Eco
|
|
12
12
|
unless options.dig(:exclude, :core) && !person.new?
|
13
13
|
micro.set_core(entry, person, options)
|
14
14
|
if entry.supervisor_id?
|
15
|
-
micro.set_supervisor(entry.supervisor_id,
|
15
|
+
micro.set_supervisor(person, entry.supervisor_id, people, options) do |unknown_id|
|
16
16
|
# delay setting supervisor if does not exit
|
17
|
-
supers_job.add(person)
|
17
|
+
supers_job.add(person) do |person|
|
18
|
+
micro.set_supervisor(person, unknown_id, people, options)
|
19
|
+
end
|
18
20
|
end
|
19
21
|
end
|
20
22
|
end
|
@@ -1,22 +1,27 @@
|
|
1
1
|
module Eco
|
2
2
|
module API
|
3
3
|
class MicroCases
|
4
|
-
#
|
5
|
-
# @note delaying the setting of a `supervisor_id` can save errors when the supervisor still does not exit.
|
6
|
-
# @param sup_id [nil, String] the **supervisor id** we should set on the `person`.
|
4
|
+
# Unique access point to set the `supervisor_id` value on a person.
|
7
5
|
# @param person [Ecoportal::API::V1::Person] the person we want to update, carrying the changes to be done.
|
8
|
-
# @param
|
6
|
+
# @param sup_id [nil, String] the **supervisor id** we should set on the `person`.
|
7
|
+
# @param people [Eco::API::Organization::People] _People_ involved in the current update.
|
9
8
|
# @param options [Hash] the options.
|
10
9
|
# @yield [supervisor_id] callback when the supervisor_id is **unknown** (not `nil` nor any one's in `people`).
|
11
10
|
# @yieldparam supervisor_id [String] the **unknown** `supervisor_id`.
|
12
|
-
def set_supervisor(
|
11
|
+
def set_supervisor(person, sup_id, people, options)
|
13
12
|
unless options.dig(:exclude, :core) || options.dig(:exclude, :supervisor)
|
14
|
-
|
13
|
+
cur_id = person.supervisor_id
|
14
|
+
cur_super = cur_id && with_supervisor(cur_id, people)
|
15
|
+
micro.with_supervisor(sup_id, people) do |new_super|
|
15
16
|
if !sup_id
|
16
17
|
person.supervisor_id = nil
|
17
|
-
|
18
|
-
|
18
|
+
descrease_subordinates(cur_super)
|
19
|
+
elsif new_super && id = new_super.id
|
20
|
+
person.supervisor_id = id
|
21
|
+
descrease_subordinates(cur_super)
|
22
|
+
increase_subordinates(new_super)
|
19
23
|
elsif !block_given?
|
24
|
+
descrease_subordinates(cur_super)
|
20
25
|
person.supervisor_id = sup_id
|
21
26
|
else
|
22
27
|
yield(sup_id) if block_given?
|
@@ -25,6 +30,22 @@ module Eco
|
|
25
30
|
end
|
26
31
|
end
|
27
32
|
|
33
|
+
private
|
34
|
+
|
35
|
+
def descrease_subordinates(person, by = 1)
|
36
|
+
if person.is_a?(Ecoportal::API::V1::Person)
|
37
|
+
person.subordinates -= by
|
38
|
+
#person.subordinates = 0 if person.subordinates < 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def increase_subordinates(person, by = 1)
|
43
|
+
if person.is_a?(Ecoportal::API::V1::Person)
|
44
|
+
#person.subordinates = 0 if person.subordinates < 0
|
45
|
+
person.subordinates += by
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
28
49
|
end
|
29
50
|
end
|
30
51
|
end
|