eco-helpers 0.6.17 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +19 -0
  3. data/.yardopts +2 -2
  4. data/Gemfile +6 -0
  5. data/Rakefile +27 -0
  6. data/eco-helpers.gemspec +9 -6
  7. data/lib/eco/api.rb +2 -1
  8. data/lib/eco/api/common/people.rb +1 -1
  9. data/lib/eco/api/common/people/base_parser.rb +31 -1
  10. data/lib/eco/api/common/people/default_parsers.rb +5 -1
  11. data/lib/eco/api/common/people/default_parsers/csv_parser.rb +37 -0
  12. data/lib/eco/api/common/people/default_parsers/numeric_parser.rb +0 -1
  13. data/lib/eco/api/common/people/entries.rb +14 -18
  14. data/lib/eco/api/common/people/entry_factory.rb +97 -9
  15. data/lib/eco/api/common/people/person_entry.rb +147 -206
  16. data/lib/eco/api/common/people/person_entry_attribute_mapper.rb +212 -0
  17. data/lib/eco/api/common/people/person_factory.rb +10 -12
  18. data/lib/eco/api/common/people/person_parser.rb +97 -37
  19. data/lib/eco/api/common/session/base_session.rb +1 -2
  20. data/lib/eco/api/common/session/file_manager.rb +1 -1
  21. data/lib/eco/api/organization.rb +2 -1
  22. data/lib/eco/api/organization/people.rb +54 -22
  23. data/lib/eco/api/organization/person_schemas.rb +54 -0
  24. data/lib/eco/api/organization/policy_groups.rb +5 -9
  25. data/lib/eco/api/organization/{presets.rb → presets_factory.rb} +1 -1
  26. data/lib/eco/api/policies.rb +10 -0
  27. data/lib/eco/api/policies/base_policy.rb +14 -0
  28. data/lib/eco/api/policies/policy.rb +20 -0
  29. data/lib/eco/api/policies/used_policies.rb +37 -0
  30. data/lib/eco/api/session.rb +36 -34
  31. data/lib/eco/api/session/batch.rb +94 -44
  32. data/lib/eco/api/session/batch_job.rb +108 -48
  33. data/lib/eco/api/session/batch_jobs.rb +4 -5
  34. data/lib/eco/api/session/batch_status.rb +70 -11
  35. data/lib/eco/api/session/config.rb +22 -5
  36. data/lib/eco/api/session/config/files.rb +10 -1
  37. data/lib/eco/api/session/config/people.rb +18 -5
  38. data/lib/eco/api/session/config/policies.rb +29 -0
  39. data/lib/eco/api/session/config/use_cases.rb +3 -7
  40. data/lib/eco/api/session/job_groups.rb +9 -10
  41. data/lib/eco/api/usecases.rb +2 -1
  42. data/lib/eco/api/usecases/base_case.rb +7 -2
  43. data/lib/eco/api/usecases/default_cases/change_email_case.rb +4 -2
  44. data/lib/eco/api/usecases/default_cases/create_case.rb +2 -1
  45. data/lib/eco/api/usecases/default_cases/create_details_case.rb +3 -1
  46. data/lib/eco/api/usecases/default_cases/create_details_with_supervisor_case.rb +4 -2
  47. data/lib/eco/api/usecases/default_cases/hris_case.rb +20 -13
  48. data/lib/eco/api/usecases/default_cases/new_email_case.rb +3 -1
  49. data/lib/eco/api/usecases/default_cases/new_id_case.rb +4 -2
  50. data/lib/eco/api/usecases/default_cases/recover_db_case.rb +9 -5
  51. data/lib/eco/api/usecases/default_cases/remove_account_case.rb +4 -2
  52. data/lib/eco/api/usecases/default_cases/set_supervisor_case.rb +4 -2
  53. data/lib/eco/api/usecases/default_cases/to_csv_case.rb +2 -2
  54. data/lib/eco/api/usecases/default_cases/to_csv_detailed_case.rb +2 -2
  55. data/lib/eco/api/usecases/default_cases/update_case.rb +16 -2
  56. data/lib/eco/api/usecases/default_cases/update_details_case.rb +3 -1
  57. data/lib/eco/api/usecases/default_cases/upsert_case.rb +25 -3
  58. data/lib/eco/api/usecases/use_case.rb +23 -140
  59. data/lib/eco/api/usecases/use_case_chain.rb +95 -0
  60. data/lib/eco/api/usecases/use_case_io.rb +117 -0
  61. data/lib/eco/api/usecases/use_group.rb +25 -5
  62. data/lib/eco/common/base_cli_backup.rb +1 -0
  63. data/lib/eco/language/models.rb +1 -1
  64. data/lib/eco/language/models/collection.rb +42 -31
  65. data/lib/eco/language/models/parser_serializer.rb +68 -0
  66. data/lib/eco/version.rb +1 -1
  67. metadata +93 -38
  68. data/lib/eco/api/common/people/types.rb +0 -47
  69. data/lib/eco/api/usecases/case_data.rb +0 -13
  70. data/lib/eco/language/models/attribute_parser.rb +0 -38
  71. data/lib/eco/lexic/dictionary.rb +0 -33
  72. data/lib/eco/lexic/dictionary/dictionary.txt +0 -355484
  73. data/lib/eco/lexic/dictionary/tags.json +0 -38
@@ -3,135 +3,163 @@ module Eco
3
3
  module Common
4
4
  module People
5
5
  class PersonEntry
6
- @@cached_warnings = {}
7
-
8
- def initialize(data, parser:, mapper:, dependencies: {}, logger: ::Logger.new(IO::NULL))
9
- raise "Constructor needs a PersonParser. Given: #{parser}" if !parser.is_a?(Eco::API::Common::People::PersonParser)
10
- raise "Expecting Mapper object. Given: #{mapper}" if mapper && !mapper.is_a?(Eco::Data::Mapper)
11
-
12
- @source = data
13
- @parser = parser
14
- @mapper = mapper
15
- @deps = dependencies
16
- @logger = logger
6
+ # This class is meant to provide a common interface to access entries of source data that come in different formats.
7
+ # @note
8
+ # - if `data` is a `Person` object, its behaviour is `serialise`.
9
+ # - if `data` is **not** a `Person` object, it does a `parse`.
10
+ # - currently **in rework**, so there may be subtle differences that make it temporarily unstable (yet it is reliable).
11
+ # @param data [Hash, Person] `Person` object to be serialized or hashed entry (`CSV::Row` is accepted).
12
+ # @param person_parser [Common::People::PersonParser] parser/serializer of person attributes (it contains a set of attribute parsers).
13
+ # @param attr_map [Eco::Data::Mapper] mapper to translate attribute names from _external_ to _internal_ names and _vice versa_.
14
+ # @param dependencies [Hash] hash where _keys_ are internal attribute names. It is mostly used to deliver final dependencies to attribute parsers/serializers.
15
+ # @param logger [Common::Session::Logger, ::Logger] object to manage logs.
16
+ def initialize(data, person_parser:, attr_map:, dependencies: {}, logger: ::Logger.new(IO::NULL))
17
+ raise "Constructor needs a PersonParser. Given: #{parser}" if !person_parser.is_a?(Eco::API::Common::People::PersonParser)
18
+ raise "Expecting Mapper object. Given: #{attr_map}" if attr_map && !attr_map.is_a?(Eco::Data::Mapper)
19
+
20
+ @source = data
21
+ @person_parser = person_parser
22
+ @deps = dependencies
23
+ @logger = logger
24
+ @attr_map = attr_map
25
+ @emap = PersonEntryAttributeMapper.new(@source, person_parser: @person_parser, attr_map: @attr_map, logger: @logger)
17
26
 
18
27
  if parsing?
19
- # PARSING
20
- @raw_entry = data
21
- init_attr_trackers
22
- @aliased_entry = mapped_entry(@raw_entry)
23
- @int_row = internal_entry(@aliased_entry)
24
-
25
- # internally named attrs scoped by mapper and parser against the current row
26
- @int_attrs = @int_row.keys
27
- else
28
- # SERIALIZING
29
- @person = data
30
- @int_row = internal_entry(@person)
31
- @aliased_entry = mapped_entry(@int_row)
32
- @int_attrs = @parser.all_attrs
28
+ @external_entry = data
29
+ @serialized_entry = mapped_entry(@external_entry)
30
+ @internal_entry = internal_entry(@serialized_entry)
31
+ else # SERIALIZING
32
+ @person = data
33
+ @internal_entry = internal_entry(@person)
34
+ @serialized_entry = mapped_entry(@internal_entry)
35
+ #@external_entry = external_entry
33
36
  end
34
-
35
- @core_attrs = @parser.target_attrs_core(@int_attrs)
36
- @details_attrs = @parser.target_attrs_details(@int_attrs)
37
- @account_attrs = @parser.target_attrs_account(@int_attrs)
38
37
  end
39
38
 
39
+ # To know if currently the object is in parse or serialize mode.
40
+ # @return [Boolean] returns `true` if we are **parsing**, `false` otherwise.
40
41
  def parsing?
41
- !is_person?(@source)
42
+ !@source.is_a?(Ecoportal::API::Internal::Person)
42
43
  end
43
44
 
45
+ # To know if currently the object is in parse or serialize mode.
46
+ # @return [Boolean] returns `true` if we are **serializing**, `false` otherwise.
44
47
  def serializing?
45
48
  !parsing?
46
49
  end
47
50
 
48
- # SHORTCUTS
49
-
51
+ # @return [String, nil] the _internal id_ of this person if defined.
50
52
  def id
51
- @int_row["id"]
53
+ @internal_entry["id"]
52
54
  end
53
55
 
56
+ # @return [String, nil] the _external id_ of this person if defined.
54
57
  def external_id
55
- @int_row["external_id"]
58
+ @internal_entry["external_id"]
56
59
  end
57
60
 
61
+ # @return [String, nil] the _name_ of this person if defined.
58
62
  def name
59
- @int_row["name"]
63
+ @internal_entry["name"]
60
64
  end
61
65
 
66
+ # @return [String, nil] the _email_ of this person if defined.
62
67
  def email
63
- @int_row["email"]
68
+ @internal_entry["email"]
64
69
  end
65
70
 
71
+ # @return [String, nil] the _supervisor id_ of this person if defined.
66
72
  def supervisor_id
67
- @int_row["supervisor_id"]
73
+ @internal_entry["supervisor_id"]
68
74
  end
69
75
 
70
76
  def supervisor_id=(value)
71
- @int_row["supervisor_id"] = value
77
+ @internal_entry["supervisor_id"] = value
72
78
  end
73
79
 
80
+ # Provides a reference of this person.
81
+ # @return [String] string summary of this person identity.
74
82
  def to_s(options)
75
83
  options = into_a(options)
76
84
  case
77
85
  when options.include?(:identify)
78
86
  "'#{name}' ('#{external_id}': '#{email}')"
79
87
  else
80
- @int_row.each.map do |k, v|
88
+ @internal_entry.each.map do |k, v|
81
89
  "'#{k}': '#{v.to_json}'"
82
90
  end.join(" | ")
83
91
  end
84
92
  end
85
93
 
86
- # SETTERS
94
+ # Setter to fill in all the `core` properties of the `Person` that are present in the `Entry`.
95
+ # @note it only sets those core properties defined in the entry.
96
+ # Meaning that if an core property is not present in the entry, this will not be set on the target person.
97
+ # @param person [Person] the person we want to set the core values to.
98
+ # @param exclude [String, Array<String>] core attributes that should not be set/changed to the person.
87
99
  def set_core(person, exclude: nil)
88
- scoped_attrs = @core_attrs - into_a(exclude)
89
- @int_row.slice(*scoped_attrs).each do |attr, value|
100
+ scoped_attrs = @emap.core_attrs - into_a(exclude)
101
+ @internal_entry.slice(*scoped_attrs).each do |attr, value|
90
102
  set_to_core(person, attr, value)
91
103
  end
92
104
  end
93
105
 
106
+ # Setter to fill in all the schema `details` fields of the `Person` that are present in the `Entry`.
107
+ # @note it only sets those details properties defined in the entry.
108
+ # Meaning that if an details property is not present in the entry, this will not be set on the target person.
109
+ # @param person [Person] the person we want to set the schema fields' values to.
110
+ # @param exclude [String, Array<String>] schema field attributes that should not be set/changed to the person.
94
111
  def set_details(person, exclude: nil)
95
- person.add_details(@parser.schema) if !person.details || !person.details.schema_id
96
- scoped_attrs = @details_attrs - into_a(exclude)
97
- @int_row.slice(*scoped_attrs).each do |attr, value|
112
+ person.add_details(@person_parser.schema) if !person.details || !person.details.schema_id
113
+ scoped_attrs = @emap.details_attrs - into_a(exclude)
114
+ @internal_entry.slice(*scoped_attrs).each do |attr, value|
98
115
  set_to_details(person, attr, value)
99
116
  end
100
117
  end
101
118
 
119
+ # Setter to fill in the `account` properties of the `Person` that are present in the `Entry`.
120
+ # @note it only sets those account properties defined in the entry.
121
+ # Meaning that if an account property is not present in the entry, this will not be set on the target person.
122
+ # @param person [Person] the person we want to set the account values to.
123
+ # @param exclude [String, Array<String>] account properties that should not be set/changed to the person.
102
124
  def set_account(person, exclude: nil)
103
125
  person.account = {} if !person.account
104
126
  person.account.permissions_preset = nil unless person.account.permissions_preset = "custom"
105
- scoped_attrs = @account_attrs - into_a(exclude)
106
- @int_row.slice(*scoped_attrs).each do |attr, value|
127
+ scoped_attrs = @emap.account_attrs - into_a(exclude)
128
+ @internal_entry.slice(*scoped_attrs).each do |attr, value|
107
129
  set_to_account(person, attr, value)
108
130
  end
109
131
  end
110
132
 
111
- # GETTERS
112
- def entry(klass: nil)
113
- return klass.new(to_hash) if klass
114
- to_hash
133
+ # Entry represented in a `Hash` with **external** attribute names and values thereof.
134
+ # @note normally used to obtain a **serialized entry**.
135
+ # @return [Hash] with **external** names and values.
136
+ def to_hash
137
+ external_entry
115
138
  end
116
139
 
117
- def to_hash
118
- @aliased_entry.each.map do |int_attr, v|
119
- [to_external(int_attr), v || ""] if to_external(int_attr)
120
- end.compact.to_h
140
+ # Entry represented in a `Hash` with **external** attribute names and values thereof.
141
+ # @note normally used to obtain a **serialized entry**.
142
+ # @return [Hash] with **external** names and values.
143
+ def external_entry
144
+ @emap.all_attrs.each_with_object({}) do |attr, hash|
145
+ unless hash.key?(ext_attr = @emap.to_external(attr))
146
+ hash[ext_attr] = @serialized_entry[attr]
147
+ end
148
+ end
121
149
  end
122
150
 
123
151
  private
124
152
 
125
- def set_to_core (person, attr, value)
153
+ def set_to_core(person, attr, value)
126
154
  value = value&.downcase if attr == "email"
127
155
  person.send("#{attr}=", value&.strip)
128
156
  end
129
157
 
130
- def set_to_account (person, attr, value)
158
+ def set_to_account(person, attr, value)
131
159
  return if !person.account
132
160
  multiple = ["policy_group_ids", "filter_tags"].include?(attr)
133
161
  if multiple
134
- value = @parser.parse(:multiple, value)
162
+ value = @person_parser.parse(:multiple, value)
135
163
  value = value.map { |v| v&.upcase } if attr == "filter_tags"
136
164
  # preserve previous order
137
165
  current = into_a(person.account.send(attr))
@@ -141,85 +169,62 @@ module Eco
141
169
  person.account.send("#{attr}=", value)
142
170
  end
143
171
 
144
- def set_to_details (person, attr, value)
172
+ def set_to_details(person, attr, value)
145
173
  return if !person.details
146
- field = person.details.get_field(attr)
147
- fatal("Field '#{attr}' does not exist in details of schema: '#{person.details.schema_id}'") if !field
148
- value = @parser.parse(:multiple, value) if field.multiple
174
+ unless field = person.details.get_field(attr)
175
+ fatal("Field '#{attr}' does not exist in details of schema: '#{person.details.schema_id}'")
176
+ end
177
+ value = nil if value.to_s.empty?
178
+ value = @person_parser.parse(:multiple, value) if field.multiple
149
179
 
150
- if @parser.defined?(field.type.to_sym)
151
- value = @parser.parse(field.type.to_sym, value, deps: {"attr" => attr})
180
+ if @person_parser.defined?(field.type.to_sym)
181
+ value = @person_parser.parse(field.type.to_sym, value, deps: {"attr" => attr})
152
182
  end
153
183
 
154
184
  person.details[attr] = value
155
185
  end
156
186
 
157
- def get_from_core (person, attr)
187
+ def get_from_core (person, attr)
158
188
  person.send(attr)
159
189
  end
160
190
 
161
191
  def get_from_account (person, attr)
162
- return "-" if !person.account
192
+ return nil if !person.account
163
193
  multiple = ["policy_group_ids", "filter_tags"].include?(attr)
164
194
  value = person.account.send(attr)
165
- @parser.serialize(:multiple, value) if multiple
195
+ @person_parser.serialize(:multiple, value) if multiple
166
196
  end
167
197
 
168
- def get_from_details (person, attr)
169
- return "-" if !person.details || !person&.details&.schema_id
170
- field = person.details.get_field(attr)
171
- fatal("Field '#{attr}' does not exist in details of schema: '#{person.details.schema_id}'") if !field
198
+ def get_from_details(person, attr)
199
+ return nil if !person.details || !person&.details&.schema_id
200
+ unless field = person.details.get_field(attr)
201
+ fatal("Field '#{attr}' does not exist in details of schema: '#{person.details.schema_id}'")
202
+ end
172
203
  value = person.details[attr]
173
- value = @parser.serialize(:date, value) if field.type == "date"
174
- value = @parser.serialize(:multiple, value) if field.multiple
204
+ value = @person_parser.serialize(:date, value) if field.type == "date"
205
+ value = @person_parser.serialize(:multiple, value) if field.multiple
175
206
  value
176
207
  end
177
208
 
178
- # INIT
179
-
180
- # when parsing:
181
- def init_attr_trackers
182
- # internal <-> external attributes
183
- int_aliased = @parser.all_attrs.select { |attr| to_external(attr) }
184
- ext_alias = int_aliased.map { |attr| to_external(attr) }
185
-
186
- # virtual attrs (non native internal attr that require aliasing):
187
- ext_vi_aliased = attributes(@raw_entry).select do |attr|
188
- !ext_alias.include?(attr) && @mapper.external?(attr)
189
- end
190
-
191
- int_vi_aliased = ext_vi_aliased.map { |attr| @mapper.to_internal(attr) }
192
- @aliased_attrs = int_aliased + int_vi_aliased
193
-
194
- int_unlinked = @parser.undefined_attrs.select { |attr| !to_external(attr) }
195
- # those with parser or alias:
196
- int_linked = @parser.all_attrs - int_unlinked
197
-
198
- ext_aliased = ext_alias + ext_vi_aliased
199
- # those that are direct external to internal:
200
- ext_direct = attributes(@raw_entry) - ext_aliased
201
- # to avoid collisions between internal names:
202
- @direct_attrs = ext_direct - int_linked
203
- end
204
-
205
209
  # MAPPED ENTRY (when and where applicable)
206
- # return entry with internal names and external values
210
+ # To obtain an entry with internal names but external values.
211
+ # @param data [Hash] external or raw entry (when parsing) or internal or parsed entry (when serializing).
212
+ # @return [Hash] entry with **internal names** and **external values**.
207
213
  def mapped_entry(data)
208
214
  return aliased_entry(data) if parsing?
209
215
  serialized_entry(data)
210
216
  end
211
217
 
212
- # parse: here we aliase attribute names
213
- def aliased_entry(raw_data)
214
- aliased_hash = @aliased_attrs.map do |attr|
215
- [attr, raw_data[to_external(attr)]]
216
- end.to_h
217
-
218
- direct_hash = @direct_attrs.map do |attr|
219
- [attr, raw_data[attr]]
218
+ # Parsing helper that aliases attribute names (from internal to external names)
219
+ # @note **Parse**: here we aliase internal attribute names into external ones.
220
+ # @param ext_entry [Hash] entry in raw, with **external** names and values.
221
+ # @return [Hash] entry with **internal names** and **external values**.
222
+ def aliased_entry(ext_entry)
223
+ aliased_hash = @emap.aliased_attrs.map do |attr|
224
+ [attr, ext_entry[@emap.to_external(attr)]]
220
225
  end.to_h
221
226
 
222
- aliased_hash.merge!(direct_hash)
227
+ ext_entry.slice(*@emap.direct_attrs).merge(aliased_hash)
223
228
  end
224
229
 
225
230
  def hash_attr(attr, value)
@@ -227,106 +232,69 @@ module Eco
227
232
  { attr => value }
228
233
  end
229
234
 
230
- # serializing: run serializers (overrides existing keys)
235
+ # Serializing helper that serializes values (from internal to external values).
236
+ # @note **Serializing**:
237
+ # 1. here we tranform internal into external **values**.
238
+ # 2. when running the serializers, it overrides existing keys.
239
+ # @param unserialized_entry [Hash] entry with **internal** names and values.
240
+ # @return [Hash] entry with **internal names** and **external values**.
231
241
  def serialized_entry(unserialized_entry)
232
- serial_attrs = @parser.defined_attrs.reduce({}) do |serial_hash, attr|
242
+ serial_attrs = @person_parser.defined_attrs.reduce({}) do |serial_hash, attr|
233
243
  deps = @deps[attr] || {}
234
- serial_attr = @parser.serialize(attr, @person, deps: deps)
244
+ serial_attr = @person_parser.serialize(attr, @person, deps: deps)
235
245
  serial_hash.merge(hash_attr(attr, serial_attr))
236
246
  end
237
247
  unserialized_entry.merge(serial_attrs)
238
248
  end
239
249
 
240
- # returns entry with internal names and values
250
+ # To obtain an entry with internal names but external values.
251
+ # @param data [Hash, Ecoportal::API::V1::Person] alised_entry (when parsing) or person (when serializing).
252
+ # @return [Hash] the `internal entry` with the **internal** attributes names and values.
241
253
  def internal_entry(data)
242
254
  return parsed_entry(data) if parsing?
243
255
  unserialized_entry(data)
244
256
  end
245
257
 
246
- # parse: to internal entry (parse values)
258
+ # Parsing helper that just **parses the values** that have a parser/serializer defined.
259
+ # @param aliased_entry [Hash] the entry with the _internal attribute_ names but the _external values_.
260
+ # @return [Hash] the `internal entry` with the **internal** attributes names and values.
247
261
  def parsed_entry(aliased_entry)
248
- parsed = @parser.defined_attrs.map do |attr|
249
- value = @parser.parse(attr, aliased_entry)
262
+ parsed = @person_parser.defined_attrs.map do |attr|
263
+ value = @person_parser.parse(attr, aliased_entry)
250
264
  [attr, value]
251
265
  end.to_h
252
266
  aliased_entry.merge(parsed)
253
267
  end
254
268
 
255
- # serializing: to internal entry (create the internal entry out of a person)
269
+ # Serializing helper that just creates the _internal entry_ out of a `Person` object.
270
+ # @note
271
+ # - when unnesting attributes, the overriding precedence for collisions is
272
+ # - `core` -> _overrides_ -> `account` -> _overrides_ -> `details`
273
+ # - to keep things consistent, the `internal entry` hash has keys in this order:
274
+ # - `core`, `account`, `details`.
275
+ # @param person [Ecoportal::API::V1::Person] the `Person` object to transform into an _internal entry_.
276
+ # @return [Hash] the `internal entry` with the **internal** attributes names and values.
256
277
  def unserialized_entry(person)
257
- core_hash = @parser.target_attrs_core.reduce({}) do |hash, attr|
278
+ core_hash = @person_parser.target_attrs_core.reduce({}) do |hash, attr|
258
279
  value = get_from_core(person, attr)
259
280
  hash.merge(hash_attr(attr, value))
260
281
  end
261
282
 
262
- details_hash = @parser.target_attrs_details.reduce({}) do |hash, attr|
283
+ details_hash = @person_parser.target_attrs_details.reduce({}) do |hash, attr|
263
284
  value = get_from_details(person, attr)
264
285
  hash.merge(hash_attr(attr, value))
265
286
  end
266
287
 
267
- account_hash = @parser.target_attrs_account.reduce({}) do |hash, attr|
288
+ account_hash = @person_parser.target_attrs_account.reduce({}) do |hash, attr|
268
289
  value = get_from_account(person, attr)
269
290
  hash.merge(hash_attr(attr, value))
270
291
  end
271
292
 
272
- details_hash.merge(account_hash).merge(core_hash)
273
- #core_hash.merge(account_hash).merge(details_hash)
274
- end
275
-
276
-
277
- def to_internal(value)
278
- return value if !@mapper
279
- attr = value
280
- case value
281
- when Array
282
- return value.map do |v|
283
- to_internal(v)
284
- end.compact
285
- when String
286
- case
287
- when @mapper.external?(value)
288
- attr = @mapper.to_internal(value)
289
- when @mapper.external?(value.strip)
290
- unless cached_warning("external", "spaces", value)
291
- logger.warn("The external person field name '#{value}' contains additional spaces in the reference file")
292
- end
293
- attr = @mapper.to_internal(value.strip)
294
- when @mapper.internal?(value) || @mapper.internal?(value.strip) || @mapper.internal?(value.strip.downcase)
295
- unless cached_warning("external", "reversed", value)
296
- logger.warn("The mapper [external, internal] attribute names may be declared reversedly for EXTERNAL attribute: '#{value}'")
297
- end
298
- end
299
- end
300
-
301
- return nil unless @parser.all_attrs.include?(attr)
302
- end
303
-
304
- def to_external(value)
305
- return value if !@mapper
306
- attr = value
307
- case value
308
- when Array
309
- return value.map do |v|
310
- to_external(v)
311
- end.compact
312
- when String
313
- case
314
- when @mapper.internal?(value)
315
- attr = @mapper.to_external(value)
316
- when @mapper.internal?(value.strip)
317
- unless cached_warning("internal", "spaces", value)
318
- logger.warn("The internal person field name '#{value}' contains additional spaces in the reference file")
319
- end
320
- attr = @mapper.to_external(value.strip)
321
- when @mapper.external?(value) || @mapper.external?(value.strip) || @mapper.external?(value.strip.downcase)
322
- unless cached_warning("internal", "reversed", value)
323
- logger.warn("The mapper [external, internal] attribute names may be declared reversedly for INTERNAL attribute: '#{value}'")
324
- end
325
- end
326
- end
327
-
328
- return nil unless !@raw_entry || attributes(@raw_entry).include?(attr)
329
- attr
293
+ # merge by core overriding account and details
294
+ rh = details_hash.merge(account_hash).merge(core_hash)
295
+ # resort hash keys
296
+ sorted_keys = core_hash.keys | account_hash.keys | details_hash.keys
297
+ sorted_keys.reduce({}) {|h,k| h[k] = rh[k]; h}
330
298
  end
331
299
 
332
300
  # LOGGER
@@ -334,16 +302,6 @@ module Eco
334
302
  @logger || ::Logger.new(IO::NULL)
335
303
  end
336
304
 
337
- def cached_warning(*args)
338
- unless exists = !!@@cached_warnings.dig(*args)
339
- args.reduce(@@cached_warnings) do |cache, level|
340
- cache[level] = {} if !cache.key?(level)
341
- cache[level]
342
- end
343
- end
344
- exists
345
- end
346
-
347
305
  def fatal(msg)
348
306
  logger.fatal(msg)
349
307
  exit
@@ -356,23 +314,6 @@ module Eco
356
314
  value
357
315
  end
358
316
 
359
- def attributes(value)
360
- case value
361
- when CSV::Row
362
- value&.headers
363
- when Hash
364
- value&.keys
365
- when PersonEntry
366
- @parser.target_attrs_core
367
- else
368
- []
369
- end
370
- end
371
-
372
- def is_person?(value)
373
- value.is_a?(Ecoportal::API::Internal::Person)
374
- end
375
-
376
317
  end
377
318
  end
378
319
  end