module Eco module API class MicroCases # Finds each **entry** of `entries` in `people` and runs a block. # @note # - it also links to `person.entry` the input data entry. # @param entries [Eco::API::Common::People::Entries] the input entries with the data. # @param people [Eco::API::Organization::People] target existing _People_ of the current update. # @param options [Hash] the options. # @param append_created [Boolean] whether or not a new person will be added to the `people` object. # @yield [entry, person] gives each entry, and the paired person thereof (new or existing). # @yieldparam entry [PersonEntry] the input entry with the data we should set on person. # @yieldparam person [Ecoportal::API::V1::Person] the found person that matches `entry`, or a new person otherwise. # @return [Eco::API::Organization::People] all the people, including new and existing ones. def with_each(entries, people, options, append_created: true) @_skip_all_multiple_results = false people_copy = people.newFrom(people.to_a) entries.each_with_object([]) do |entry, scoped| begin person = people_copy.find(entry, strict: micro.strict_search?(options)) person ||= session.new_person.tap do |pers| people << pers if append_created end rescue Eco::API::Organization::People::MultipleSearchResults => e unless @_skip_all_multiple_results msg = "\n * When searching this Entry: #{entry.to_s(:identify)}" person = _with_each_prompt_to_select_user(e.append_message(msg), entry: entry) end end next unless person person.entry = entry yield(entry, person) if block_given? scoped << person end.then do |all_people| people.newFrom all_people.uniq end end private def _with_each_prompt_to_select_user(error, entry: nil, increase_count: true) # rubocop:disable Metrics/AbcSize unless error.is_a?(Eco::API::Organization::People::MultipleSearchResults) raise "Expecting Eco::API::Organization::People::MultipleSearchResults. Given: #{error.class}" end @_with_each_prompts = 0 unless instance_variable_defined?(:@_with_each_prompts) @_with_each_prompts += 1 if increase_count lines = [] lines << "\n(#{@_with_each_prompts}) #{error}\n" lines << " #index - Select the correct person by its number index among the list above." lines << " (I) - Just Skip/Ignore this one. I will deal with that input entry in another launch." lines << " (A) - Ignore all the rest of input entries with this problem." lines << " (C) - Create a new person." lines << " (B) - Just break this script. I need to change the input file :/" prompt_user("Type one option (#number/I/A/C/B):", explanation: lines.join("\n"), default: "I") do |res| res = res.upcase if res.start_with?("I") log(:info) { "Ignoring entry... #{entry&.to_s(:identify)}" } nil elsif res.start_with?("A") log(:info) { "All input entries with this same issue will be ignored for this launch" } @_skip_all_multiple_results = true nil elsif res.start_with?("C") log(:info) { "Creating new person...#{"for entry #{entry.to_s(:identify)}" if entry}" } session.new_person elsif res.start_with?("B") raise error elsif res && !res.empty? && (pos = res.to_i rescue nil) && (pos < error.candidates.length) # rubocop:disable Style/RescueModifier error.candidate(pos).tap do |person| log(:info) { "Thanks!! You selected #{person.identify}" } sleep(1.5) end else if pos.is_a?(Numeric) && (pos >= error.candidates.length) print "#{pos} is not a number in the range. " else print "#{res} is not an option. " end puts "Please select one of the offered options..." sleep(1) _with_each_prompt_to_select_user(error, increase_count: false, entry: entry) end end end end end end