# frozen_string_literal: true module Submissions module Filter ALLOWED_PARAMS = %w[ author status folder completed_at_from completed_at_to created_at_from created_at_to ].freeze DATE_PARAMS = %w[ completed_at_from completed_at_to created_at_from created_at_to ].freeze module_function def call(submissions, current_user, params) filters = normalize_filter_params(params, current_user) submissions = filter_by_author(submissions, filters, current_user) submissions = filter_by_folder(submissions, filters, current_user) submissions = filter_by_status(submissions, filters) submissions = filter_by_created_at(submissions, filters) filter_by_completed_at(submissions, filters) end def filter_by_author(submissions, filters, current_user) return submissions if filters[:author].blank? user = current_user.account.users.find_by(email: filters[:author]) submissions.where(created_by_user_id: user&.id || -1) end # rubocop:disable Metrics/MethodLength def filter_by_status(submissions, filters) case filters[:status] when 'pending' submissions.pending when 'completed' submissions.completed when 'declined' submissions.declined when 'expired' submissions.expired when 'sent' submissions.joins(:submitters) .where(submitters: { opened_at: nil, completed_at: nil, declined_at: nil }) .where.not(submitters: { sent_at: nil }) .group(:id) when 'opened' submissions.joins(:submitters) .where(submitters: { completed_at: nil, declined_at: nil }) .where.not(submitters: { opened_at: nil }) .group(:id) when 'partially_completed' submissions.joins(:submitters) .group(:id) .having(Arel::Nodes::NamedFunction.new( 'COUNT', [Arel::Nodes::NamedFunction.new('NULLIF', [Submitter.arel_table[:completed_at].eq(nil), Arel::Nodes.build_quoted(false)])] ).gt(0)) .having(Arel::Nodes::NamedFunction.new( 'COUNT', [Arel::Nodes::NamedFunction.new('NULLIF', [Submitter.arel_table[:completed_at].not_eq(nil), Arel::Nodes.build_quoted(false)])] ).gt(0)) else submissions end end # rubocop:enable Metrics/MethodLength def filter_by_created_at(submissions, filters) submissions = submissions.where(created_at: filters[:created_at_from]..) if filters[:created_at_from].present? if filters[:created_at_to].present? submissions = submissions.where(created_at: ..filters[:created_at_to].end_of_day) end submissions end def filter_by_folder(submissions, filters, current_user) return submissions if filters[:folder].blank? folders = TemplateFolders.filter_by_full_name(current_user.account.template_folders, filters[:folder]) folders += folders.preload(:subfolders).flat_map(&:subfolders) submissions.joins(:template).where(templates: { folder_id: folders.map(&:id) }) end def filter_by_completed_at(submissions, filters) return submissions unless filters[:completed_at_from].present? || filters[:completed_at_to].present? completed_arel = Submitter.arel_table[:completed_at].maximum submissions = submissions.completed.joins(:submitters).group(:id) if filters[:completed_at_from].present? submissions = submissions.having(completed_arel.gteq(filters[:completed_at_from])) end return submissions if filters[:completed_at_to].blank? submissions.having(completed_arel.lteq(filters[:completed_at_to].end_of_day)) end def normalize_filter_params(params, current_user) tz = ActiveSupport::TimeZone[current_user.account.timezone] || Time.zone ALLOWED_PARAMS.each_with_object({}) do |key, acc| next if params[key].blank? value = DATE_PARAMS.include?(key) ? tz.parse(params[key]) : params[key] acc[key.to_sym] = value end end end end