diff --git a/.gitignore b/.gitignore index 25c3136a..1c4e3537 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.byebug_history .bundle/ log/*.log pkg/ diff --git a/Gemfile.lock b/Gemfile.lock index f8088729..270bcce0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,7 +2,7 @@ PATH remote: . specs: bookingsync_portal (1.0.1) - bookingsync_application (>= 3, < 4) + bookingsync_application (>= 3) bootstrap-bookingsync-sass (~> 1.0.0) bootstrap-sass (< 3.5) coffee-rails @@ -10,11 +10,13 @@ PATH handlebars_assets jquery-rails jquery-ui-rails (~> 6.0.1) - message_bus + kaminari + message_bus (= 2.0.2) rails + ransack redis responders - sass-rails + sass-rails (~> 5) simple_form sprockets-rails turbolinks @@ -95,6 +97,7 @@ GEM autoprefixer-rails (>= 5.2.1) sassc (>= 2.0.0) builder (3.2.4) + byebug (11.1.1) coderay (1.1.2) coffee-rails (5.0.0) coffee-script (>= 2.2.0) @@ -147,6 +150,18 @@ GEM concurrent-ruby railties (>= 4.1) jwt (2.2.1) + kaminari (1.2.0) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.2.0) + kaminari-activerecord (= 1.2.0) + kaminari-core (= 1.2.0) + kaminari-actionview (1.2.0) + actionview + kaminari-core (= 1.2.0) + kaminari-activerecord (1.2.0) + activerecord + kaminari-core (= 1.2.0) + kaminari-core (1.2.0) loofah (2.4.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) @@ -154,7 +169,7 @@ GEM mini_mime (>= 0.1.1) marcel (0.3.3) mimemagic (~> 0.3.2) - message_bus (2.2.3) + message_bus (2.0.2) rack (>= 1.1.3) method_source (0.9.2) mimemagic (0.3.4) @@ -188,6 +203,8 @@ GEM parallel (1.19.1) parser (2.7.0.2) ast (~> 2.4.0) + polyamorous (2.3.2) + activerecord (>= 5.2.1) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -227,6 +244,11 @@ GEM thor (>= 0.19.0, < 2.0) rainbow (3.0.0) rake (13.0.1) + ransack (2.3.2) + activerecord (>= 5.2.1) + activesupport (>= 5.2.1) + i18n + polyamorous (= 2.3.2) rb-fsevent (0.10.3) rb-inotify (0.10.1) ffi (~> 1.0) @@ -265,16 +287,14 @@ GEM sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - sass-rails (6.0.0) - sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.2.1) + sass-rails (5.1.0) + railties (>= 5.2.0) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) + sassc (2.4.0) ffi (~> 1.9) - sassc-rails (2.1.2) - railties (>= 4.0.0) - sassc (>= 2.0) - sprockets (> 3.0) - sprockets-rails - tilt shoulda (3.6.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (~> 3.0) @@ -322,6 +342,7 @@ PLATFORMS DEPENDENCIES appraisal bookingsync_portal! + byebug factory_girl_rails pry-rails rails-controller-testing diff --git a/app/assets/javascripts/bookingsync_portal/admin/application.js.coffee b/app/assets/javascripts/bookingsync_portal/admin/application.js.coffee index 1baaab08..37a54b44 100644 --- a/app/assets/javascripts/bookingsync_portal/admin/application.js.coffee +++ b/app/assets/javascripts/bookingsync_portal/admin/application.js.coffee @@ -21,6 +21,7 @@ #= require bookingsync/form #= require ./vendor/css-contains #= require ./lib/list-filter +#= require ./lib/list-backend-filter #= require_tree ./templates #= require_tree . diff --git a/app/assets/javascripts/bookingsync_portal/admin/lib/list-backend-filter.js.coffee b/app/assets/javascripts/bookingsync_portal/admin/lib/list-backend-filter.js.coffee new file mode 100644 index 00000000..b64b1b3d --- /dev/null +++ b/app/assets/javascripts/bookingsync_portal/admin/lib/list-backend-filter.js.coffee @@ -0,0 +1,118 @@ +class @ListBackedFilter + constructor: (header, list, @listElement, @listFilterable, @inputId, formTemplate, paginationTemplate) -> + @header = $(header) + @list = $(list) + @form = $(formTemplate) + @insertForm() + @observeFormChanges() + + @paginationTemplate ||= $(HandlebarsTemplates["pagination"]()) + @insertPagination() + @observePageChanges() + + @loadingTemplate = $(HandlebarsTemplates["loading"]()) + + @doneTypingInterval = 1500 # 1.5 seconds wait after each keyup before sending search request + @typingTimer = undefined + + @currentSearchQuery = @form.serialize() + + insertForm: -> + @form.appendTo(@header) + @input = $("#" + @inputId) + + insertPagination: -> + @paginationTemplate.find("[data-type=previous]").addClass("disabled") + @setPage(1) + $(@paginationTemplate).appendTo(@list.parent()) + @refreshPagination() + + refreshPagination: -> + if @firstPage() + @paginationTemplate.find("[data-type=previous]").addClass("disabled") + else + @paginationTemplate.find("[data-type=previous]").removeClass("disabled") + + if @lastPage() + @paginationTemplate.find("[data-type=next]").addClass("disabled") + else + @paginationTemplate.find("[data-type=next]").removeClass("disabled") + + setPage: (page)-> + $(@form).data("current-page", page) + + currentPage: -> + $(@form).data("current-page") + + firstPage: -> + @currentPage() == 1 + + lastPage: -> + $(".bookingsync-rentals-list").find(".panel").length < $("body").data("items-per-page") + if @form.parents(".bookingsync-rentals-list").length > 0 + itemsCount = $("body").data("rentals-records-count") + else + itemsCount = $("body").data("remote-rentals-records-count") + parseInt(itemsCount) < $("body").data("items-per-page") + + observeFormChanges: -> + @input.on 'keyup', (e) => + @startSearching() + + @input.on 'change', => + @startSearching() + + @form.on 'change', (e) => + @startSearching() + + startSearching: => + return if @currentSearchQuery == @form.serialize() + @currentSearchQuery = @form.serialize() + @setPage(1) + @displayWaiting() + clearTimeout(@typingTimer) + @typingTimer = setTimeout(@backendSearch, @doneTypingInterval) # make search request only when user is done typing + + observePageChanges: -> + @paginationTemplate.find("[data-type=previous]").on "click", @goToPreviousPage + @paginationTemplate.find("[data-type=next]").on "click", @goToNextPage + + displayWaiting: -> + @list.html(@loadingTemplate) unless @list.children()[0] == @loadingTemplate[0] + @paginationTemplate.find("[data-type=previous]").addClass("disabled") + @paginationTemplate.find("[data-type=next]").addClass("disabled") + + backendSearch: => + $.get(@getSearchQuery(), @afterSearch) + + afterSearch: => + @refreshPagination() + + getSearchQuery: -> + if @form.parents(".bookingsync-rentals-list").length > 0 + fieldName = "rentals_search" + else + fieldName = "remote_rentals_search" + searchParams = ["#{fieldName}[page]=#{@currentPage()}"] + $(@form.serialize().split("&")).each (_, item) -> + key = item.split("=")[0] + value = item.split("=")[1] + searchParams.push("#{fieldName}[#{key}]=#{value}") + + "#{document.location.href}.js?#{searchParams.join("&")}" + + goToPreviousPage: (e) => + e.preventDefault() + return if @firstPage() + $(@form).data("current-page", @currentPage() - 1) + @displayWaiting() + clearTimeout(@typingTimer) + @backendSearch() + + goToNextPage: (e) => + e.preventDefault() + return if @lastPage() + $(@form).data("current-page", @currentPage() + 1) + @displayWaiting() + clearTimeout(@typingTimer) + @backendSearch() diff --git a/app/assets/javascripts/bookingsync_portal/admin/rentals.js.coffee b/app/assets/javascripts/bookingsync_portal/admin/rentals.js.coffee index a3369a7d..e740a392 100644 --- a/app/assets/javascripts/bookingsync_portal/admin/rentals.js.coffee +++ b/app/assets/javascripts/bookingsync_portal/admin/rentals.js.coffee @@ -1,12 +1,19 @@ $ -> + if $("body").data("paginated-view") + Filter = ListBackedFilter + else + Filter = ListFilter + for rentalsList, index in $(".rentals-list") inputId = "rentals-list-filter-#{index}" - new ListFilter( + filterInput = $(rentalsList).data("filter-input") + filterInput ||= "filter_input" + new Filter( $(rentalsList).children(".rentals-list-header"), $(rentalsList).children(".rentals-list-scroll"), ".panel", ".panel h4", inputId, - HandlebarsTemplates["filter_input"] + HandlebarsTemplates[filterInput] inputId: inputId ) diff --git a/app/assets/javascripts/bookingsync_portal/admin/templates/filter_input.hbs b/app/assets/javascripts/bookingsync_portal/admin/templates/filter_input.hbs index e789f280..d8ffddd4 100644 --- a/app/assets/javascripts/bookingsync_portal/admin/templates/filter_input.hbs +++ b/app/assets/javascripts/bookingsync_portal/admin/templates/filter_input.hbs @@ -1,6 +1,6 @@
- +
diff --git a/app/assets/javascripts/bookingsync_portal/admin/templates/loading.hbs b/app/assets/javascripts/bookingsync_portal/admin/templates/loading.hbs new file mode 100644 index 00000000..b8433532 --- /dev/null +++ b/app/assets/javascripts/bookingsync_portal/admin/templates/loading.hbs @@ -0,0 +1,3 @@ +
+ +
diff --git a/app/assets/javascripts/bookingsync_portal/admin/templates/pagination.hbs b/app/assets/javascripts/bookingsync_portal/admin/templates/pagination.hbs new file mode 100644 index 00000000..db37df56 --- /dev/null +++ b/app/assets/javascripts/bookingsync_portal/admin/templates/pagination.hbs @@ -0,0 +1,6 @@ + diff --git a/app/controllers/bookingsync_portal/admin/rentals_controller.rb b/app/controllers/bookingsync_portal/admin/rentals_controller.rb index 665f8349..5d74bbf0 100644 --- a/app/controllers/bookingsync_portal/admin/rentals_controller.rb +++ b/app/controllers/bookingsync_portal/admin/rentals_controller.rb @@ -1,36 +1,144 @@ module BookingsyncPortal module Admin class RentalsController < Admin::BaseController - before_action :synchronize_rentals, only: :index - before_action :fetch_remote_rentals, only: :index + before_action :resolve_action, only: :index + + helper_method :search_by_rentals? + helper_method :search_by_remote_rentals? def index - @not_connected_rentals = current_account.rentals.visible.ordered.not_connected - @visible_rentals = current_account.rentals.visible - @remote_accounts = current_account.remote_accounts - @remote_rentals_by_account = current_account.remote_rentals.ordered - .includes(:remote_account, :rental).group_by(&:remote_account) + synchronize_rentals + fetch_remote_rentals + + prepare_index_variables + end + + def index_with_search + prepare_index_variables do + apply_search + apply_pagination + end + + respond_to do |format| + format.html do + synchronize_rentals + fetch_remote_rentals + render :index + end + format.js # view can be app specific + end end def show rental end + def ignore_blank_remote_accounts? + search_filter.remote_rentals_query.blank? && search_filter.remote_rentals_page > 1 + end + + def action_variables + @action_variables ||= {} + end + + public :current_account + private + def search_by_rentals? + params[:rentals_search].present? + end + + def search_by_remote_rentals? + params[:remote_rentals_search].present? + end + + def resolve_action + redirect_to admin_v2_rentals_path if use_paginated_view? + end + + def prepare_index_variables + @action_variables = OpenStruct.new + + @action_variables.not_connected_rentals = current_account.rentals.visible.ordered.not_connected + @action_variables.visible_rentals = current_account.rentals.visible + @action_variables.remote_rentals = current_account.remote_rentals.ordered + @action_variables.blank_remote_accounts = generate_blank_remote_accounts + + BookingsyncPortal.before_rentals_index_action_filter.call(self) + yield if block_given? + + @action_variables.remote_rentals_by_account = @action_variables.remote_rentals + .includes(*BookingsyncPortal.remote_rentals_by_account_included_tables) + .reorder(remote_account_id: :desc) + .group_by(&:remote_account) + + @action_variables.remote_rentals_by_account = blank_remote_accounts.merge(@action_variables.remote_rentals_by_account) + @action_variables.remote_accounts = @action_variables.remote_rentals_by_account.keys + + BookingsyncPortal.after_rentals_index_action_filter.call(self) + @action_variables.to_h.each do |variable_name, variable_value| + instance_variable_set("@#{variable_name}", variable_value) + end + end + + def blank_remote_accounts + return {} if ignore_blank_remote_accounts? + BookingsyncPortal.filter_strategies.each do |strategy| + @action_variables.blank_remote_accounts = strategy.constantize.call(account: current_account, records: @action_variables.blank_remote_accounts, search_filter: search_filter) + end + @action_variables.blank_remote_accounts.each_with_object({}) do |remote_account, res| + res[remote_account] = [] + end + end + + def generate_blank_remote_accounts + return RemoteAccount.none if ignore_blank_remote_accounts? + current_account + .remote_accounts + .left_outer_joins(:remote_rentals) + .where(remote_rentals: { id: nil }) + end + + def apply_search + BookingsyncPortal.filter_strategies.each do |strategy| + @action_variables.not_connected_rentals = strategy.constantize.call( + account: current_account, + records: @action_variables.not_connected_rentals, + search_filter: search_filter + ) + @action_variables.remote_rentals = strategy.constantize.call( + account: current_account, + records: @action_variables.remote_rentals, + search_filter: search_filter + ) + end + end + + def apply_pagination + @action_variables.not_connected_rentals = @action_variables.not_connected_rentals.page(search_filter.rentals_page).per(BookingsyncPortal.items_per_page) + @action_variables.remote_rentals = @action_variables.remote_rentals.page(search_filter.remote_rentals_page).per(BookingsyncPortal.items_per_page) + end + def synchronize_rentals BookingsyncPortal.rental_model.constantize.synchronize(scope: current_account) end def fetch_remote_rentals - unless BookingsyncPortal.fetch_remote_rentals(current_account) - @remote_account_not_registered = true - end + @remote_account_not_registered = true unless BookingsyncPortal.fetch_remote_rentals(current_account) end def rental @rental ||= current_account.rentals.visible.find(params[:id]) end + + def search_filter + @search_filter ||= BookingsyncPortal::SearchFilter.new(params) + end + + def use_paginated_view? + BookingsyncPortal.use_paginated_view.call(current_account) + end end end end diff --git a/app/helpers/bookingsync_portal/admin/application_helper.rb b/app/helpers/bookingsync_portal/admin/application_helper.rb index edcfef53..8e0e4809 100644 --- a/app/helpers/bookingsync_portal/admin/application_helper.rb +++ b/app/helpers/bookingsync_portal/admin/application_helper.rb @@ -29,6 +29,18 @@ def rental_details(rental) safe_join(details, ', ') end + + def use_paginated_view? + BookingsyncPortal.use_paginated_view.call(current_account) + end + + def not_connected_rentals_count + @not_connected_rentals.present? ? @not_connected_rentals.count : 0 + end + + def remote_rentals_count + @remote_rentals.present? ? @remote_rentals.count : 0 + end end end end diff --git a/app/services/bookingsync_portal/default_rentals_filter_strategy.rb b/app/services/bookingsync_portal/default_rentals_filter_strategy.rb new file mode 100644 index 00000000..f782fe72 --- /dev/null +++ b/app/services/bookingsync_portal/default_rentals_filter_strategy.rb @@ -0,0 +1,6 @@ +class BookingsyncPortal::DefaultRentalsFilterStrategy + def self.call(records:, search_filter:) + return records if records.table_name != "rentals" + BookingsyncPortal::Searcher.call(query: search_filter.rentals_query, records: records, search_settings: BookingsyncPortal.rentals_search) + end +end diff --git a/app/services/bookingsync_portal/filter_strategies.rb b/app/services/bookingsync_portal/filter_strategies.rb new file mode 100644 index 00000000..66bcda6c --- /dev/null +++ b/app/services/bookingsync_portal/filter_strategies.rb @@ -0,0 +1,4 @@ +module BookingsyncPortal + module FilterStrategies + end +end diff --git a/app/services/bookingsync_portal/filter_strategies/base_strategy.rb b/app/services/bookingsync_portal/filter_strategies/base_strategy.rb new file mode 100644 index 00000000..96a023cf --- /dev/null +++ b/app/services/bookingsync_portal/filter_strategies/base_strategy.rb @@ -0,0 +1,28 @@ +module BookingsyncPortal + module FilterStrategies + class BaseStrategy + + attr_accessor :account, :records, :search_filter + private :account, :records, :search_filter + + def initialize(account: nil, records:, search_filter:) + @account = account + @records = records + @search_filter = search_filter + end + + def self.call(account: nil, records:, search_filter: nil) + return records if models_for_filter.all? {|model_name| model_name.constantize.table_name != records.table_name } + new(account: account, records: records, search_filter: search_filter).call + end + + def self.filtered_models(*args) + @filtered_models = Array.wrap(args) + end + + def self.models_for_filter + @filtered_models ||= [] + end + end + end +end diff --git a/app/services/bookingsync_portal/filter_strategies/blank_remote_accounts.rb b/app/services/bookingsync_portal/filter_strategies/blank_remote_accounts.rb new file mode 100644 index 00000000..1b4faee3 --- /dev/null +++ b/app/services/bookingsync_portal/filter_strategies/blank_remote_accounts.rb @@ -0,0 +1,17 @@ +module BookingsyncPortal + module FilterStrategies + class BlankRemoteAccounts < BaseStrategy + + filtered_models BookingsyncPortal.remote_account_model + + def call + search_settings = {} + BookingsyncPortal.remote_rentals_search.each do |type, fields| + remote_account_fields = fields.select {|field| field.include?("remote_account.") }.map {|f| f.gsub("remote_account.", "") } + search_settings[type] = remote_account_fields if remote_account_fields.present? + end.compact + BookingsyncPortal::Searcher.call(query: search_filter.remote_rentals_query, records: records, search_settings: search_settings) + end + end + end +end diff --git a/app/services/bookingsync_portal/filter_strategies/remote_rentals.rb b/app/services/bookingsync_portal/filter_strategies/remote_rentals.rb new file mode 100644 index 00000000..e291cbc1 --- /dev/null +++ b/app/services/bookingsync_portal/filter_strategies/remote_rentals.rb @@ -0,0 +1,11 @@ +module BookingsyncPortal + module FilterStrategies + class RemoteRentals < BaseStrategy + filtered_models BookingsyncPortal.remote_rental_model + + def call + BookingsyncPortal::Searcher.call(query: search_filter.remote_rentals_query, records: records, search_settings: BookingsyncPortal.remote_rentals_search) + end + end + end +end diff --git a/app/services/bookingsync_portal/filter_strategies/rentals.rb b/app/services/bookingsync_portal/filter_strategies/rentals.rb new file mode 100644 index 00000000..e06820f4 --- /dev/null +++ b/app/services/bookingsync_portal/filter_strategies/rentals.rb @@ -0,0 +1,11 @@ +module BookingsyncPortal + module FilterStrategies + class Rentals < BaseStrategy + filtered_models BookingsyncPortal.rental_model + + def call + BookingsyncPortal::Searcher.call(query: search_filter.rentals_query, records: records, search_settings: BookingsyncPortal.rentals_search) + end + end + end +end diff --git a/app/services/bookingsync_portal/search_filter.rb b/app/services/bookingsync_portal/search_filter.rb new file mode 100644 index 00000000..e6ab84eb --- /dev/null +++ b/app/services/bookingsync_portal/search_filter.rb @@ -0,0 +1,23 @@ +class BookingsyncPortal::SearchFilter + attr_reader :params + def initialize(params) + @params = params + end + + def rentals_query + @rentals_query ||= params.dig(:rentals_search, :query).to_s.strip + end + + def remote_rentals_query + @remote_rentals_query ||= params.dig(:remote_rentals_search, :query).to_s.strip + end + + def rentals_page + @rentals_page ||= [params.dig(:rentals_search, :page).to_i, 1].max + end + + def remote_rentals_page + @remote_rentals_page ||= [params.dig(:remote_rentals_search, :page).to_i, 1].max + end +end + diff --git a/app/services/bookingsync_portal/searcher.rb b/app/services/bookingsync_portal/searcher.rb new file mode 100644 index 00000000..416c2893 --- /dev/null +++ b/app/services/bookingsync_portal/searcher.rb @@ -0,0 +1,26 @@ +class BookingsyncPortal::Searcher + def self.call(query:, search_settings:, records:) + return records if query.blank? + return records if search_settings.blank? + + conditions = { m: "or" } + + search_settings.each do |type, filtered_fields| + filtered_fields.each do |field| + conditions.merge!(build_search_query(type, field.gsub(".", "_"), query)) + end + end + + records.ransack(conditions).result + end + + private + + def self.build_search_query(type, field, query) + if type == :string + { "#{field}_cont" => query } + else + { "#{field}_eq" => query } + end + end +end diff --git a/app/views/bookingsync_portal/admin/rentals/_rentals.html.erb b/app/views/bookingsync_portal/admin/rentals/_rentals.html.erb index 7066e77d..de6ed78d 100644 --- a/app/views/bookingsync_portal/admin/rentals/_rentals.html.erb +++ b/app/views/bookingsync_portal/admin/rentals/_rentals.html.erb @@ -6,6 +6,11 @@ <% not_connected_rentals.each do |rental| %> <%= render rental %> <% end %> +<%- elsif params[:controller] == "bookingsync_portal/admin/connections" && (search_by_rentals? || search_by_remote_rentals?) %> +
+

<%= icon 'search fa-lg' %>

+

<%=t '.no_results' %>

+
<%- else -%>

<%= icon 'thumbs-up fa-lg' %>

diff --git a/app/views/bookingsync_portal/admin/rentals/index_with_search.js.erb b/app/views/bookingsync_portal/admin/rentals/index_with_search.js.erb new file mode 100644 index 00000000..2a189779 --- /dev/null +++ b/app/views/bookingsync_portal/admin/rentals/index_with_search.js.erb @@ -0,0 +1,20 @@ +<%- if search_by_rentals? %> + list = $(".bookingsync-rentals-list.rentals-list .rentals-list-scroll") + data = $("<%=escape_javascript(render file: 'bookingsync_portal/admin/rentals/index') %>") + newList = $(data).find(".bookingsync-rentals-list.rentals-list .rentals-list-scroll").first() + list.html(newList.html()) + + $(".bookingsync-rental").draggableRental() + $(".panel.panel-remote").droppableRemoteRental() +<%- elsif search_by_remote_rentals? %> + list = $(".remote-rentals-list.rentals-list .rentals-list-scroll") + data = $("<%=escape_javascript(render file: 'bookingsync_portal/admin/rentals/index') %>") + newList = $(data).find(".remote-rentals-list.rentals-list .rentals-list-scroll").first() + list.html(newList.html()) + + $(".bookingsync-rental").draggableRental() + $(".panel.panel-remote").droppableRemoteRental() +<%- end %> + +$("body").data("rentals-records-count", "<%= @not_connected_rentals.count %>") +$("body").data("remote-rentals-records-count", "<%= @remote_rentals.count %>") diff --git a/app/views/layouts/bookingsync_portal/admin.html.erb b/app/views/layouts/bookingsync_portal/admin.html.erb index a3afa18b..b89b864f 100644 --- a/app/views/layouts/bookingsync_portal/admin.html.erb +++ b/app/views/layouts/bookingsync_portal/admin.html.erb @@ -9,7 +9,13 @@ <%= stylesheet_link_tag 'admin/application', media: 'all' %> <%= csrf_meta_tags %> - + <%= render partial: '/layouts/bookingsync_portal/menu' %>
<%= render '/layouts/bookingsync_portal/flash' %> diff --git a/bookingsync_portal.gemspec b/bookingsync_portal.gemspec index 9952406b..18f3837c 100644 --- a/bookingsync_portal.gemspec +++ b/bookingsync_portal.gemspec @@ -19,7 +19,7 @@ Gem::Specification.new do |s| s.add_dependency 'rails' s.add_dependency 'sprockets-rails' s.add_dependency 'responders' - s.add_dependency 'bookingsync_application', ['>= 3', '< 4'] + s.add_dependency 'bookingsync_application', '>= 3' s.add_dependency 'redis' # FIXME: Will no longer be needed once UI moved to Ember s.add_dependency 'jquery-rails' @@ -29,12 +29,16 @@ Gem::Specification.new do |s| s.add_dependency 'font-awesome-sass', '4.7.0' s.add_dependency 'handlebars_assets' s.add_dependency 'simple_form' - s.add_dependency 'message_bus' + s.add_dependency 'message_bus', '2.0.2' s.add_dependency 'turbolinks' - s.add_dependency 'sass-rails' + s.add_dependency 'sass-rails', '~> 5' s.add_dependency 'uglifier' s.add_dependency 'coffee-rails' + s.add_dependency 'ransack' + s.add_dependency 'kaminari' + + s.add_development_dependency 'byebug' s.add_development_dependency 'appraisal' s.add_development_dependency 'rspec-rails' s.add_development_dependency 'shoulda' diff --git a/config/locales/en.yml b/config/locales/en.yml index 0269e231..557b0662 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -53,6 +53,7 @@ en: rentals: no_published_rentals_html: 'No published rentals present, please make sure to fill all your rentals details.' all_synchronized: Perfect! All your rentals are synchronized. + no_results: No results rental: bedrooms_html: one: '1 Bedroom' diff --git a/config/routes.rb b/config/routes.rb index e842863d..b125bfaa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,8 @@ BookingsyncPortal::Engine.routes.draw do namespace :admin do resources :rentals, only: [:index, :show] + get "v2/rentals", to: "rentals#index_with_search", as: "v2_rentals" + resources :connections, only: [:create, :destroy] resources :remote_accounts, only: [:new, :create] get 'help', to: 'help#index' diff --git a/gemfiles/rails_5.0.gemfile.lock b/gemfiles/rails_5.0.gemfile.lock index 2f7f3e12..aeb8d80a 100644 --- a/gemfiles/rails_5.0.gemfile.lock +++ b/gemfiles/rails_5.0.gemfile.lock @@ -10,11 +10,13 @@ PATH handlebars_assets jquery-rails jquery-ui-rails (~> 6.0.1) - message_bus + kaminari + message_bus (= 2.0.2) rails + ransack redis responders - sass-rails + sass-rails (~> 5) simple_form sprockets-rails turbolinks @@ -91,6 +93,7 @@ GEM autoprefixer-rails (>= 5.2.1) sassc (>= 2.0.0) builder (3.2.4) + byebug (11.1.1) coderay (1.1.2) coffee-rails (4.2.2) coffee-script (>= 2.2.0) @@ -143,12 +146,24 @@ GEM concurrent-ruby railties (>= 4.1) jwt (2.2.1) + kaminari (1.2.0) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.2.0) + kaminari-activerecord (= 1.2.0) + kaminari-core (= 1.2.0) + kaminari-actionview (1.2.0) + actionview + kaminari-core (= 1.2.0) + kaminari-activerecord (1.2.0) + activerecord + kaminari-core (= 1.2.0) + kaminari-core (1.2.0) loofah (2.4.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - message_bus (2.2.3) + message_bus (2.0.2) rack (>= 1.1.3) method_source (0.9.2) mini_mime (1.0.2) @@ -181,6 +196,8 @@ GEM parallel (1.19.1) parser (2.7.0.2) ast (~> 2.4.0) + polyamorous (2.3.0) + activerecord (>= 5.0) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -219,6 +236,12 @@ GEM thor (>= 0.18.1, < 2.0) rainbow (3.0.0) rake (13.0.1) + ransack (2.3.0) + actionpack (>= 5.0) + activerecord (>= 5.0) + activesupport (>= 5.0) + i18n + polyamorous (= 2.3.0) rb-fsevent (0.10.3) rb-inotify (0.10.1) ffi (~> 1.0) @@ -257,16 +280,12 @@ GEM sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - sass-rails (6.0.0) - sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.2.1) - ffi (~> 1.9) - sassc-rails (2.1.2) - railties (>= 4.0.0) - sassc (>= 2.0) - sprockets (> 3.0) - sprockets-rails - tilt + sass-rails (5.0.7) + railties (>= 4.0.0, < 6) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) shoulda (3.6.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (~> 3.0) @@ -314,6 +333,7 @@ PLATFORMS DEPENDENCIES appraisal bookingsync_portal! + byebug factory_girl_rails pry-rails rails (~> 5.0.0) diff --git a/gemfiles/rails_5.1.gemfile.lock b/gemfiles/rails_5.1.gemfile.lock index b400c733..55d770ef 100644 --- a/gemfiles/rails_5.1.gemfile.lock +++ b/gemfiles/rails_5.1.gemfile.lock @@ -10,11 +10,13 @@ PATH handlebars_assets jquery-rails jquery-ui-rails (~> 6.0.1) - message_bus + kaminari + message_bus (= 2.0.2) rails + ransack redis responders - sass-rails + sass-rails (~> 5) simple_form sprockets-rails turbolinks @@ -91,6 +93,7 @@ GEM autoprefixer-rails (>= 5.2.1) sassc (>= 2.0.0) builder (3.2.4) + byebug (11.1.1) coderay (1.1.2) coffee-rails (4.2.2) coffee-script (>= 2.2.0) @@ -143,12 +146,24 @@ GEM concurrent-ruby railties (>= 4.1) jwt (2.2.1) + kaminari (1.2.0) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.2.0) + kaminari-activerecord (= 1.2.0) + kaminari-core (= 1.2.0) + kaminari-actionview (1.2.0) + actionview + kaminari-core (= 1.2.0) + kaminari-activerecord (1.2.0) + activerecord + kaminari-core (= 1.2.0) + kaminari-core (1.2.0) loofah (2.4.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - message_bus (2.2.3) + message_bus (2.0.2) rack (>= 1.1.3) method_source (0.9.2) mini_mime (1.0.2) @@ -181,6 +196,8 @@ GEM parallel (1.19.1) parser (2.7.0.2) ast (~> 2.4.0) + polyamorous (2.3.0) + activerecord (>= 5.0) pry (0.12.2) coderay (~> 1.1.0) method_source (~> 0.9.0) @@ -219,6 +236,12 @@ GEM thor (>= 0.18.1, < 2.0) rainbow (3.0.0) rake (13.0.1) + ransack (2.3.0) + actionpack (>= 5.0) + activerecord (>= 5.0) + activesupport (>= 5.0) + i18n + polyamorous (= 2.3.0) rb-fsevent (0.10.3) rb-inotify (0.10.1) ffi (~> 1.0) @@ -257,16 +280,12 @@ GEM sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - sass-rails (6.0.0) - sassc-rails (~> 2.1, >= 2.1.1) - sassc (2.2.1) - ffi (~> 1.9) - sassc-rails (2.1.2) - railties (>= 4.0.0) - sassc (>= 2.0) - sprockets (> 3.0) - sprockets-rails - tilt + sass-rails (5.0.7) + railties (>= 4.0.0, < 6) + sass (~> 3.1) + sprockets (>= 2.8, < 4.0) + sprockets-rails (>= 2.0, < 4.0) + tilt (>= 1.1, < 3) shoulda (3.6.0) shoulda-context (~> 1.0, >= 1.0.1) shoulda-matchers (~> 3.0) @@ -314,6 +333,7 @@ PLATFORMS DEPENDENCIES appraisal bookingsync_portal! + byebug factory_girl_rails pry-rails rails (~> 5.1.0) diff --git a/lib/bookingsync_portal.rb b/lib/bookingsync_portal.rb index e5b124f6..55e96a92 100644 --- a/lib/bookingsync_portal.rb +++ b/lib/bookingsync_portal.rb @@ -16,6 +16,8 @@ require 'simple_form' require 'turbolinks' require 'responders' +require 'kaminari' +require 'ransack' module BookingsyncPortal # portal name @@ -57,6 +59,46 @@ module BookingsyncPortal mattr_accessor :rate_model @@rate_model = 'BookingsyncPortal::Rate' + # whether load-all (false) or paginated (true) view should be used for admin#index + mattr_accessor :use_paginated_view + @@use_paginated_view = -> (_account) { false } + + # search by not connected rentals + mattr_accessor :rentals_search + @@rentals_search = { + numeric: %w(synced_id), + string: %w(name) + } + + # search by remote rentals rentals + mattr_accessor :remote_rentals_search + @@remote_rentals_search = { + numeric: %w(uid remote_account.uid), + string: %w(rental.name) + } + + mattr_accessor :filter_strategies + @@filter_strategies = [ + "BookingsyncPortal::FilterStrategies::Rentals", + "BookingsyncPortal::FilterStrategies::RemoteRentals", + "BookingsyncPortal::FilterStrategies::BlankRemoteAccounts" + ] + + # the number of items that will be displayed per page + # works only with enabled use_paginated_view + mattr_accessor :items_per_page + @@items_per_page = 25 + + mattr_accessor :before_rentals_index_action_filter + @@before_rentals_index_action_filter = -> (_controller) { } + + mattr_accessor :after_rentals_index_action_filter + @@after_rentals_index_action_filter = -> (_controller) { } + + # included tables for remote_rentals_by_account + mattr_accessor :remote_rentals_by_account_included_tables + @@remote_rentals_by_account_included_tables = %w(remote_account rental) + # message bus channel scope mattr_accessor :message_bus_channel_scope diff --git a/spec/controllers/admin/rentals_controller_spec.rb b/spec/controllers/admin/rentals_controller_spec.rb index 30cc3d70..78c63ed6 100644 --- a/spec/controllers/admin/rentals_controller_spec.rb +++ b/spec/controllers/admin/rentals_controller_spec.rb @@ -5,10 +5,14 @@ routes { BookingsyncPortal::Engine.routes } let!(:account) { create(:account) } - let!(:remote_account) { create(:remote_account, account: account) } - let(:rental) { create(:rental, account: account) } - let!(:rental_connected) { create(:rental, account: account) } - let!(:connection) { create(:connection, rental: rental_connected) } + let!(:remote_account) { create(:remote_account, account: account, uid: 3001) } + let(:rental) { create(:rental, account: account, synced_id: 1001) } + let!(:remote_rental) { create(:remote_rental, remote_account: remote_account, uid: 2001) } + let!(:rental_connected) { create(:rental, account: account, synced_id: 1002) } + let!(:remote_account_connected) { create(:remote_account, account: account, uid: 3002) } + let!(:remote_rental_connected) { create(:remote_rental, remote_account: remote_account_connected, uid: 2002) } + let!(:connection) { create(:connection, rental: rental_connected, remote_rental: remote_rental_connected) } + let!(:remote_account_empty) { create(:remote_account, account: account, uid: 3003) } before do request.env['HTTPS'] = 'on' @@ -27,4 +31,292 @@ expect { get :index }.to change { Rental.count } end end + + describe 'GET #index_with_search' do + subject(:index_with_search) do + get :index_with_search, params: params, format: request_format + end + + let(:params) do + { + rentals_search: {query: rentals_search_query, page: rentals_search_page}, + remote_rentals_search: {query: remote_rentals_search_query, page: remote_rentals_search_page}, + } + end + let(:rentals_search_query) { "" } + let(:rentals_search_page) { 1 } + let(:remote_rentals_search_query) { "" } + let(:remote_rentals_search_page) { 1 } + let(:request_format) { :html } + + context "when format is js" do + let(:request_format) { :js } + + it "does not call Rental.synchronize for current_account" do + expect(Rental).not_to receive(:synchronize).with(scope: account) + index_with_search + end + end + + context "when format is html" do + let(:request_format) { :html } + + before do + allow(Rental).to receive(:synchronize).with(scope: account) do + # pretending to sync rentals :P + rental + end + end + + it "calls Rental.synchronize for current_account" do + expect(Rental).to receive(:synchronize).with(scope: account) + index_with_search + end + end + + context "when there is rentals_search query" do + context "and it's empty string" do + let(:rentals_search_query) { "" } + + it "does not filter rentals" do + index_with_search + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account_connected => [remote_rental_connected], + remote_account => [remote_rental], + remote_account_empty => [] + }) + expect(assigns(:remote_rentals_by_account).first).to eq([remote_account_empty, []]) + end + + context "and goes to the next page" do + let(:rentals_search_page) { 2 } + + it "appies pagination only for not_connected_rentals" do + index_with_search + expect(assigns(:not_connected_rentals)).to be_blank + + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account_connected => [remote_rental_connected], + remote_account => [remote_rental], + remote_account_empty => [] + }) + expect(assigns(:remote_rentals_by_account).first).to eq([remote_account_empty, []]) + end + end + end + + context "and it's attempt to filter by" do + context "rental.synced_id" do + let(:rentals_search_query) { "#{rental.synced_id}" } + + it "filters not_connected_rentals but does not filter remote_rentals part" do + index_with_search + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account_connected => [remote_rental_connected], + remote_account => [remote_rental], + remote_account_empty => [] + }) + expect(assigns(:remote_rentals_by_account).first).to eq([remote_account_empty, []]) + end + end + + context "rental_connected.synced_id" do + let(:rentals_search_query) { "#{rental_connected.synced_id}" } + + it "filters not_connected_rentals but does not filter remote_rentals part" do + index_with_search + expect(assigns(:not_connected_rentals)).to be_blank + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account_connected => [remote_rental_connected], + remote_account => [remote_rental], + remote_account_empty => [] + }) + expect(assigns(:remote_rentals_by_account).first).to eq([remote_account_empty, []]) + end + end + end + end + + context "when there is remote_rentals_search query" do + context "and it's empty string" do + let(:remote_rentals_search_query) { "" } + + it "does not filter rentals" do + index_with_search + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account_connected => [remote_rental_connected], + remote_account => [remote_rental], + remote_account_empty => [] + }) + expect(assigns(:remote_rentals_by_account).first).to eq([remote_account_empty, []]) + end + + context "and goes to the next page" do + let(:remote_rentals_search_page) { 2 } + + it "appies pagination only for remote_rentals" do + index_with_search + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to be_blank + end + end + end + + context "and it's attempt to filter by" do + context "remote_account.uid" do + let(:remote_rentals_search_query) { "#{remote_account.uid}" } + + it "filters remote_rentals but does not filter not_connected_rentals part" do + index_with_search + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account => [remote_rental] + }) + end + end + + context "remote_account_connected.uid" do + let(:remote_rentals_search_query) { "#{remote_account_connected.uid}" } + + it "filters remote_rentals but does not filter not_connected_rentals part" do + index_with_search + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account_connected => [remote_rental_connected] + }) + end + end + + context "remote_account_empty.uid" do + let(:remote_rentals_search_query) { "#{remote_account_empty.uid}" } + + it "filters remote_rentals but does not filter not_connected_rentals part" do + index_with_search + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account_empty => [] + }) + end + end + + end + end + + context "when there is before_rentals_index_action_filter setting" do + let(:rentals_index_action_extention) do + Proc.new do |controller| + controller.action_variables.not_connected_rentals = Rental.all + controller.action_variables.remote_rentals = RemoteRental.all + controller.action_variables.custom_variable = "BookingSync" + end + end + + before do + BookingsyncPortal.before_rentals_index_action_filter = rentals_index_action_extention + end + + after do + BookingsyncPortal.before_rentals_index_action_filter = Proc.new {} + end + + it "applies extended logic" do + index_with_search + expect(assigns(:not_connected_rentals)).not_to eq(Rental.all) # will be overridden + expect(assigns(:remote_rentals)).not_to eq(RemoteRental.all) # will be overridden + expect(assigns(:custom_variable)).to eq("BookingSync") + end + end + + context "when there is after_rentals_index_action_filter setting" do + let(:rentals_index_action_extention) do + Proc.new do |controller| + controller.action_variables.not_connected_rentals = Rental.all + controller.action_variables.remote_rentals = RemoteRental.all + controller.action_variables.custom_variable = "BookingSync" + end + end + + before do + BookingsyncPortal.after_rentals_index_action_filter = rentals_index_action_extention + end + + after do + BookingsyncPortal.after_rentals_index_action_filter = Proc.new {} + end + + it "applies extended logic" do + index_with_search + expect(assigns(:not_connected_rentals)).to eq(Rental.all) + expect(assigns(:remote_rentals)).to eq(RemoteRental.all) + expect(assigns(:custom_variable)).to eq("BookingSync") + end + end + + context "when there are several remote_rentals belonged to several remote_accounts" do + let!(:remote_account1) { remote_account } + let!(:remote_account2) { remote_account_connected } + let!(:remote_account3) { create(:remote_account, account: account) } + + let!(:remote_rental_11) { remote_rental } + let!(:remote_rental_21) { remote_rental_connected } + let!(:remote_rental_31) { create(:remote_rental, remote_account: remote_account3) } + + let!(:remote_rental_12) { create(:remote_rental, remote_account: remote_account1) } + let!(:remote_rental_22) { create(:remote_rental, remote_account: remote_account2) } + let!(:remote_rental_32) { create(:remote_rental, remote_account: remote_account3) } + + let!(:remote_rental_13) { create(:remote_rental, remote_account: remote_account1) } + let!(:remote_rental_23) { create(:remote_rental, remote_account: remote_account2) } + let!(:remote_rental_33) { create(:remote_rental, remote_account: remote_account3) } + + before do + allow(BookingsyncPortal).to receive(:items_per_page).and_return(4) + end + + context "and there is the first page" do + let(:remote_rentals_search_page) { 1 } + + it "displayes recors in corrent order" do + index_with_search + + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account_empty => [], + remote_account3 => [remote_rental_31, remote_rental_32, remote_rental_33], + remote_account2 => [remote_rental_21], + }) + end + end + + context "and there is the second page" do + let(:remote_rentals_search_page) { 2 } + + it "displayes recors in corrent order" do + index_with_search + + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account2 => [remote_rental_22, remote_rental_23], + remote_account1 => [remote_rental_11, remote_rental_12], + }) + end + end + + context "and there is the third page" do + let(:remote_rentals_search_page) { 3 } + + it "displayes recors in corrent order" do + index_with_search + + expect(assigns(:not_connected_rentals)).to contain_exactly(rental) + expect(assigns(:remote_rentals_by_account)).to eq({ + remote_account1 => [remote_rental_13], + }) + end + end + end + end end diff --git a/spec/dummy/config/routes.rb b/spec/dummy/config/routes.rb index 787824f8..19448cf0 100644 --- a/spec/dummy/config/routes.rb +++ b/spec/dummy/config/routes.rb @@ -1,3 +1,3 @@ Rails.application.routes.draw do - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html + mount BookingsyncPortal::Engine => "/" end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index b11e0137..54c50193 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -8,6 +8,7 @@ require 'shoulda/matchers' require 'factory_girl_rails' require 'rails-controller-testing' +require 'byebug' Rails::Controller::Testing.install diff --git a/spec/request/admin_rentals_spec.rb b/spec/request/admin_rentals_spec.rb new file mode 100644 index 00000000..2076fc0b --- /dev/null +++ b/spec/request/admin_rentals_spec.rb @@ -0,0 +1,44 @@ +require "rails_helper" + +describe "admin/rentals", type: :request do + let!(:account) { create(:account) } + let!(:remote_account) { create(:remote_account, account: account) } + + describe "GET #index" do + subject(:get_rentals) { get "/admin/rentals", headers: { "HTTPS" => "on" } } + + before do + allow_any_instance_of(BookingsyncPortal::Admin::RentalsController).to receive(:current_account).and_return(account) + end + + context "when config's use_paginated_view returns false (default)" do + it "successfully renders page" do + get_rentals + expect(response).to have_http_status :ok + end + end + + context "when config's use_paginated_view returns true" do + around do |example| + BookingsyncPortal.setup do |config| + config.use_paginated_view = ->(account) { account.persisted? } # anything as long as returns true + end + example.run + BookingsyncPortal.setup do |config| + config.use_paginated_view = ->(_account) { false } + end + end + + before do + allow_any_instance_of(BookingsyncPortal::Admin::RentalsController).to receive(:current_account).and_return(account) + end + + it "successfully renders page" do + get_rentals + expect(response).to redirect_to("/admin/v2/rentals") + follow_redirect! + expect(response).to have_http_status :ok + end + end + end +end diff --git a/spec/services/bookingsync_portal/filter_strategies/blank_remote_accounts_spec.rb b/spec/services/bookingsync_portal/filter_strategies/blank_remote_accounts_spec.rb new file mode 100644 index 00000000..cedeb143 --- /dev/null +++ b/spec/services/bookingsync_portal/filter_strategies/blank_remote_accounts_spec.rb @@ -0,0 +1,27 @@ +require 'rails_helper' + +describe BookingsyncPortal::FilterStrategies::BlankRemoteAccounts do + describe ".call" do + subject(:call) { described_class.call(records: records, search_filter: search_filter) } + + let(:search_filter) { BookingsyncPortal::SearchFilter.new({}) } + + context "when records is RemoteAccount based" do + let(:records) { RemoteAccount.all } + + it "delegates logic to searcher" do + expect(BookingsyncPortal::Searcher).to receive(:call) + call + end + end + + context "when records is not RemoteAccount based" do + let(:records) { RemoteRental.all } + + it "does not delegate logic to searcher and return current records" do + expect(BookingsyncPortal::Searcher).not_to receive(:call) + expect(call).to eq(records) + end + end + end +end diff --git a/spec/services/bookingsync_portal/filter_strategies/remote_rentals_spec.rb b/spec/services/bookingsync_portal/filter_strategies/remote_rentals_spec.rb new file mode 100644 index 00000000..141a95d5 --- /dev/null +++ b/spec/services/bookingsync_portal/filter_strategies/remote_rentals_spec.rb @@ -0,0 +1,27 @@ +require 'rails_helper' + +describe BookingsyncPortal::FilterStrategies::RemoteRentals do + describe ".call" do + subject(:call) { described_class.call(records: records, search_filter: search_filter) } + + let(:search_filter) { BookingsyncPortal::SearchFilter.new({}) } + + context "when records is RemoteRental based" do + let(:records) { RemoteRental.all } + + it "delegates logic to searcher" do + expect(BookingsyncPortal::Searcher).to receive(:call) + call + end + end + + context "when records is not RemoteRental based" do + let(:records) { Rental.all } + + it "does not delegate logic to searcher and return current records" do + expect(BookingsyncPortal::Searcher).not_to receive(:call) + expect(call).to eq(records) + end + end + end +end diff --git a/spec/services/bookingsync_portal/filter_strategies/rentals_spec.rb b/spec/services/bookingsync_portal/filter_strategies/rentals_spec.rb new file mode 100644 index 00000000..616424f6 --- /dev/null +++ b/spec/services/bookingsync_portal/filter_strategies/rentals_spec.rb @@ -0,0 +1,27 @@ +require 'rails_helper' + +describe BookingsyncPortal::FilterStrategies::Rentals do + describe ".call" do + subject(:call) { described_class.call(records: records, search_filter: search_filter) } + + let(:search_filter) { BookingsyncPortal::SearchFilter.new({}) } + + context "when records is Rental based" do + let(:records) { Rental.all } + + it "delegates logic to searcher" do + expect(BookingsyncPortal::Searcher).to receive(:call) + call + end + end + + context "when records is not Rental based" do + let(:records) { RemoteRental.all } + + it "does not delegate logic to searcher and return current records" do + expect(BookingsyncPortal::Searcher).not_to receive(:call) + expect(call).to eq(records) + end + end + end +end diff --git a/spec/services/bookingsync_portal/search_filter_spec.rb b/spec/services/bookingsync_portal/search_filter_spec.rb new file mode 100644 index 00000000..6617ab04 --- /dev/null +++ b/spec/services/bookingsync_portal/search_filter_spec.rb @@ -0,0 +1,87 @@ +require 'rails_helper' + +describe BookingsyncPortal::SearchFilter do + let(:search_filter) { described_class.new(params) } + let(:params) do + { + rentals_search: rentals_search, + remote_rentals_search: remote_rentals_search, + } + end + let(:remote_rentals_search) { {} } + let(:rentals_search) { {} } + + describe "#rentals_query" do + subject(:rentals_query) { search_filter.rentals_query } + + let(:rentals_search) { { query: query } } + + context "when query is blank" do + let(:query) { "" } + + it { is_expected.to be_blank } + end + + context "when query exists" do + let(:query) { "bla-bla" } + + it { is_expected.to eq(query) } + end + end + + describe "#remote_rentals_query" do + subject(:remote_rentals_query) { search_filter.remote_rentals_query } + + let(:remote_rentals_search) { { query: query } } + + context "when remote_rentals_page is blank" do + let(:query) { "" } + + it { is_expected.to be_blank } + end + + context "when query exists" do + let(:query) { "bla-bla" } + + it { is_expected.to eq(query) } + end + end + + describe "#rentals_page" do + subject(:rentals_page) { search_filter.rentals_page } + + let(:rentals_search) { { page: page } } + + context "when page is blank" do + let(:page) { "" } + + it { is_expected.to eq(1) } + end + + context "when page exists" do + let(:page) { 20 } + + it { is_expected.to eq(page) } + end + + end + + describe "#remote_rentals_page" do + subject(:remote_rentals_page) { search_filter.remote_rentals_page } + + let(:remote_rentals_search) { { page: page } } + + context "when page is blank" do + let(:page) { "" } + + it { is_expected.to eq(1) } + end + + context "when page exists" do + let(:page) { 20 } + + it { is_expected.to eq(page) } + end + + end +end diff --git a/spec/services/bookingsync_portal/searcher_spec.rb b/spec/services/bookingsync_portal/searcher_spec.rb new file mode 100644 index 00000000..59a17ab7 --- /dev/null +++ b/spec/services/bookingsync_portal/searcher_spec.rb @@ -0,0 +1,47 @@ +require 'rails_helper' + +describe BookingsyncPortal::Searcher do + describe ".call" do + subject(:call) { described_class.call(query: query, search_settings: search_settings, records: records) } + + let(:records) { Rental.all } + let(:search_settings) do + { + numeric: %w(synced_id), + string: %w(synced_data) + } + end + + context "when query is synced_id" do + let(:query) { "1" } + + context "and there is rental with such synced_id" do + let!(:rental) { create(:rental, synced_id: query) } + + it { is_expected.to contain_exactly(rental) } + end + + context "and there is no rental with such synced_id" do + let!(:rental) { create(:rental, synced_id: query.to_i + 1) } + + it { is_expected.to be_blank } + end + end + + context "when query is string" do + let(:query) { "bla-bla" } + + context "and there is rental with such synced_id" do + let!(:rental) { create(:rental, synced_data: { name: query }) } + + it { is_expected.to contain_exactly(rental) } + end + + context "and there is no rental with such synced_id" do + let!(:rental) { create(:rental, synced_data: { name: "zzz" }) } + + it { is_expected.to be_blank } + end + end + end +end