From fbb9222e3ec7b83643088c12d3bafcbe1bf179e8 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Wed, 19 Oct 2016 09:15:00 +0600 Subject: [PATCH 1/4] Kigo: use the same logic for setting minimum_stay both in property and calendar builders --- lib/concierge/suppliers/kigo/calendar.rb | 7 +++ .../suppliers/kigo/mappers/min_stay.rb | 34 +++++++++++ .../suppliers/kigo/mappers/property.rb | 17 ++++-- .../concierge/suppliers/kigo/calendar_spec.rb | 51 ++++++++++++----- spec/workers/suppliers/kigo/calendar_spec.rb | 57 ++++++++++++++----- 5 files changed, 134 insertions(+), 32 deletions(-) create mode 100644 lib/concierge/suppliers/kigo/mappers/min_stay.rb diff --git a/lib/concierge/suppliers/kigo/calendar.rb b/lib/concierge/suppliers/kigo/calendar.rb index 456dd452e..085a65391 100644 --- a/lib/concierge/suppliers/kigo/calendar.rb +++ b/lib/concierge/suppliers/kigo/calendar.rb @@ -35,6 +35,13 @@ def perform(pricing, availabilities: [], reservations: []) set_reservations(reservations) entries.each do |entry| + min_stay_result = Kigo::Mappers::MinStay.new( + property.data.get("minimum_stay"), + entry.minimum_stay + ).value + return min_stay_result unless min_stay_result.success? + + entry.minimum_stay = min_stay_result.value calendar.add(entry) end diff --git a/lib/concierge/suppliers/kigo/mappers/min_stay.rb b/lib/concierge/suppliers/kigo/mappers/min_stay.rb new file mode 100644 index 000000000..961589164 --- /dev/null +++ b/lib/concierge/suppliers/kigo/mappers/min_stay.rb @@ -0,0 +1,34 @@ +module Kigo::Mappers + # It's possible that min_stay value for property and min_stay value for + # calendar entry can be different. + # + # This class solves the problem of determining which min_stay value + # we should use. + # + # This class should be used everywhere where we need to set min_stay values. + class MinStay + attr_reader :prop_min_stay, :cal_min_stay + + def initialize(prop_min_stay, cal_min_stay) + @prop_min_stay = prop_min_stay + @cal_min_stay = cal_min_stay + end + + # Compare and return the most strict min_stay value. + def value + min_stay = [prop_min_stay.to_i, cal_min_stay.to_i].max + + if min_stay.zero? + invalid_min_stay_error + else + Result.new(min_stay) + end + end + + private + def invalid_min_stay_error + desc = "Min stay was not defined both for property and calendar entry" + Result.error(:invalid_min_stay, desc) + end + end +end diff --git a/lib/concierge/suppliers/kigo/mappers/property.rb b/lib/concierge/suppliers/kigo/mappers/property.rb index d6e4117d8..59694a3f4 100644 --- a/lib/concierge/suppliers/kigo/mappers/property.rb +++ b/lib/concierge/suppliers/kigo/mappers/property.rb @@ -43,6 +43,14 @@ def prepare(property_data, pricing_data) set_deposit set_cleaning_service + min_stay_result = Kigo::Mappers::MinStay.new( + property.minimum_stay.to_i, + pricing_mapper.minimum_stay + ).value + return min_stay_result unless min_stay_result.success? + + set_minimum_stay(min_stay_result.value) + Result.new(property) end @@ -165,6 +173,10 @@ def set_cleaning_service property.services_cleaning_rate = get_fee_amount(cleaning_fee) end + def set_minimum_stay(minimum_stay) + property.minimum_stay = minimum_stay + end + # STAYLENGTH unit means deposit has different prices for night, week, month # since Roomorama doesn't support variates of deposit, to be conservative # we are choosing maximum price @@ -194,11 +206,6 @@ def set_price(pricing_mapper) property.nightly_rate = pricing_mapper.nightly_rate property.weekly_rate = pricing_mapper.weekly_rate property.monthly_rate = pricing_mapper.monthly_rate - property.minimum_stay = [ - property.minimum_stay.to_i, - pricing_mapper.minimum_stay - ].max - end def code_for(item) diff --git a/spec/lib/concierge/suppliers/kigo/calendar_spec.rb b/spec/lib/concierge/suppliers/kigo/calendar_spec.rb index 9530d102a..5bf0482b3 100644 --- a/spec/lib/concierge/suppliers/kigo/calendar_spec.rb +++ b/spec/lib/concierge/suppliers/kigo/calendar_spec.rb @@ -40,18 +40,43 @@ expect(entry.checkout_allowed).to eq true end - it 'returns calendar with unavailable dates' do - availabilities.concat([availability, unavailable_availability]) - result = subject.perform(nil, availabilities: availabilities) - - expect(result).to be_success - - calendar = result.value - available_entry = calendar.entries.find { |entry| entry.date.to_s == availability['DATE'] } - unavailable_entry = calendar.entries.find { |entry| entry.date.to_s == unavailable_availability['DATE'] } - - expect(available_entry.available).to eq true - expect(unavailable_entry.available).to eq false + context "when pricing is empty" do + let(:pricing) { nil } + + context "when property has minimum_stay value" do + let(:property) { create_property(data: { minimum_stay: 17 }) } + + it 'uses entry.minimum_stay value from property' do + availabilities.concat([availability, unavailable_availability]) + result = subject.perform(pricing, availabilities: availabilities) + + expect(result).to be_success + + calendar = result.value + available_entry = calendar.entries.find { |entry| entry.date.to_s == availability['DATE'] } + unavailable_entry = calendar.entries.find { |entry| entry.date.to_s == unavailable_availability['DATE'] } + + expect(available_entry.available).to eq true + expect(unavailable_entry.available).to eq false + + calendar.entries.each do |entry| + expect(entry.minimum_stay).to eq(17) + end + end + end + + context "when property hasn't minimum_stay value" do + it 'returns invalid_min_stay error' do + availabilities.concat([availability, unavailable_availability]) + result = subject.perform(pricing, availabilities: availabilities) + + expect(result).not_to be_success + expect(result.error.code).to eq(:invalid_min_stay) + expect(result.error.data).to eq( + "Min stay was not defined both for property and calendar entry" + ) + end + end end end @@ -76,4 +101,4 @@ end end -end \ No newline at end of file +end diff --git a/spec/workers/suppliers/kigo/calendar_spec.rb b/spec/workers/suppliers/kigo/calendar_spec.rb index 980ff7d69..346e77879 100644 --- a/spec/workers/suppliers/kigo/calendar_spec.rb +++ b/spec/workers/suppliers/kigo/calendar_spec.rb @@ -7,7 +7,8 @@ let(:supplier) { create_supplier(name: 'Kigo') } let(:identifier) { '123' } let(:host) { create_host(supplier_id: supplier.id, identifier: '14908') } - let!(:property) { create_property(host_id: host.id, identifier: identifier) } + let(:property_attrs) {{ host_id: host.id, identifier: identifier }} + let!(:property) { create_property(property_attrs) } subject { described_class.new(host, [identifier]) } @@ -69,24 +70,52 @@ expect(stats[:unavailable_records]).to eq 0 end - it 'sets only availabilities' do - empty_prices = { 'PRICING' => nil } - allow_any_instance_of(Kigo::Importer).to receive(:fetch_prices) { Result.new(empty_prices) } - allow_any_instance_of(Kigo::Importer).to receive(:fetch_availabilities) { Result.new(availabilities) } + context "when pricing is empty" do + let(:empty_prices) {{ 'PRICING' => nil }} - subject.perform + context "when property has minimum_stay value" do + let(:property_attrs) {{ host_id: host.id, identifier: identifier, data: { minimum_stay: 13, nightly_rate: 10 }}} - sync_process = SyncProcessRepository.last + it 'sets only availabilities' do + allow_any_instance_of(Kigo::Importer).to receive(:fetch_prices) { Result.new(empty_prices) } + allow_any_instance_of(Kigo::Importer).to receive(:fetch_availabilities) { Result.new(availabilities) } - expect(sync_process.host_id).to eq host.id - expect(sync_process.type).to eq 'availabilities' + subject.perform - stats = sync_process.stats + sync_process = SyncProcessRepository.last - expect(stats[:properties_processed]).to eq 1 - expect(stats[:available_records]).to eq 1 - expect(stats[:unavailable_records]).to eq 7 + expect(sync_process.host_id).to eq host.id + expect(sync_process.type).to eq 'availabilities' + + stats = sync_process.stats + + expect(stats[:properties_processed]).to eq 1 + expect(stats[:available_records]).to eq 1 + expect(stats[:unavailable_records]).to eq 7 + end + end + + context "when property has no minimum_stay value" do + let(:property_attrs) {{ host_id: host.id, identifier: identifier, data: { minimum_stay: nil, nightly_rate: 10 }}} + + it "returns external error" do + allow_any_instance_of(Kigo::Importer).to receive(:fetch_prices) { Result.new(empty_prices) } + allow_any_instance_of(Kigo::Importer).to receive(:fetch_availabilities) { Result.new(availabilities) } + + subject.perform + + sync_process = SyncProcessRepository.last + + expect(sync_process.host_id).to eq host.id + expect(sync_process.type).to eq 'availabilities' + + stats = sync_process.stats + + expect(stats[:properties_processed]).to eq 1 + expect(stats[:available_records]).to eq 0 + expect(stats[:unavailable_records]).to eq 0 + end + end end end - end From c4b12e84f91f93b506ca0c477a86a72a174ff47f Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Wed, 19 Oct 2016 09:19:14 +0600 Subject: [PATCH 2/4] update changelog --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a427309b..e22c44787 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,15 +8,16 @@ how this file is formatted and how the process works. ### Added - Rentals United: add late check-in / early check-out fees to description_append +### Fixed +- Atleisure: set cleaning fee mapping logic according to #405 +- `Kigo::Calendar` now respects to property's `minimum_stay` value if it's more stricter + ## [0.12.11] - 2016-10-21 ### Added - Atleisure, Ciirus, Poplidays, Kigo, Waytostay, RentalsUnited: add error.data reporting to Rollbar - Translations for title, description, t&c, check_in_instructions and description_append on Roomorama::Property -### Fixed -- Atleisure: set cleaning fee mapping logic according to #405 - ## [0.12.10] - 2016-10-19 ### Fixed - Poplidays: metadata sync is safe for `nil` availabilities response From 8dab61ff83638256781b9a89546fa5b8602aa1c2 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Wed, 19 Oct 2016 09:44:25 +0600 Subject: [PATCH 3/4] add specs for new min_stay class --- .../suppliers/kigo/mappers/min_stay_spec.rb | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 spec/lib/concierge/suppliers/kigo/mappers/min_stay_spec.rb diff --git a/spec/lib/concierge/suppliers/kigo/mappers/min_stay_spec.rb b/spec/lib/concierge/suppliers/kigo/mappers/min_stay_spec.rb new file mode 100644 index 000000000..edc464835 --- /dev/null +++ b/spec/lib/concierge/suppliers/kigo/mappers/min_stay_spec.rb @@ -0,0 +1,83 @@ +require 'spec_helper' + +RSpec.describe Kigo::Mappers::MinStay do + describe "#value" do + it "selects property's minimum_stay if it's bigger than calendar's minimum_stay" do + prop_min_stay = 20 + cal_min_stay = 19 + + min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value + expect(min_stay_result).to be_success + expect(min_stay_result.value).to eq(20) + end + + it "selects calendars's minimum_stay if it's bigger than property's minimum_stay" do + prop_min_stay = 16 + cal_min_stay = 17 + + min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value + expect(min_stay_result).to be_success + expect(min_stay_result.value).to eq(17) + end + + it "selects any of minimum_stay values if they equal to each other" do + prop_min_stay = 15 + cal_min_stay = 15 + + min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value + expect(min_stay_result).to be_success + expect(min_stay_result.value).to eq(15) + end + + it "selects property's minimum_stay when calendar's one is nil" do + prop_min_stay = 13 + cal_min_stay = nil + + min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value + expect(min_stay_result).to be_success + expect(min_stay_result.value).to eq(13) + end + + it "selects property's minimum_stay when calendar's one is nil" do + prop_min_stay = nil + cal_min_stay = 11 + + min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value + expect(min_stay_result).to be_success + expect(min_stay_result.value).to eq(11) + end + + it "applies .to_i to property's minimum_stay values" do + prop_min_stay = "20" + cal_min_stay = 19 + + min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value + expect(min_stay_result).to be_success + expect(min_stay_result.value).to eq(20) + end + + it "applies .to_i to calendars's minimum_stay values" do + prop_min_stay = 10 + cal_min_stay = "19" + + min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value + expect(min_stay_result).to be_success + expect(min_stay_result.value).to eq(19) + end + + it "returns error when both minimum_stay values are nil or 0" do + null_values = [nil, 0] + + null_values.each do |prop_min_stay| + null_values.each do |cal_min_stay| + min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value + expect(min_stay_result).not_to be_success + expect(min_stay_result.error.code).to eq(:invalid_min_stay) + expect(min_stay_result.error.data).to eq( + "Min stay was not defined both for property and calendar entry" + ) + end + end + end + end +end From e6dd75b916122c2f3c0b737dcd8b7b7b5f514714 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Wed, 19 Oct 2016 15:26:27 +0600 Subject: [PATCH 4/4] Set default minimum_stay equal 1 to property, keep nil minimum_stays for calendar entries --- lib/concierge/suppliers/kigo/calendar.rb | 7 ++- .../suppliers/kigo/mappers/min_stay.rb | 13 +----- .../suppliers/kigo/mappers/property.rb | 32 ++++++-------- .../concierge/suppliers/kigo/calendar_spec.rb | 19 +++++--- .../suppliers/kigo/mappers/min_stay_spec.rb | 43 +++++++------------ spec/workers/suppliers/kigo/calendar_spec.rb | 6 +-- 6 files changed, 50 insertions(+), 70 deletions(-) diff --git a/lib/concierge/suppliers/kigo/calendar.rb b/lib/concierge/suppliers/kigo/calendar.rb index 085a65391..1516c04b3 100644 --- a/lib/concierge/suppliers/kigo/calendar.rb +++ b/lib/concierge/suppliers/kigo/calendar.rb @@ -35,13 +35,12 @@ def perform(pricing, availabilities: [], reservations: []) set_reservations(reservations) entries.each do |entry| - min_stay_result = Kigo::Mappers::MinStay.new( + min_stay = Kigo::Mappers::MinStay.new( property.data.get("minimum_stay"), entry.minimum_stay - ).value - return min_stay_result unless min_stay_result.success? + ) - entry.minimum_stay = min_stay_result.value + entry.minimum_stay = min_stay.value calendar.add(entry) end diff --git a/lib/concierge/suppliers/kigo/mappers/min_stay.rb b/lib/concierge/suppliers/kigo/mappers/min_stay.rb index 961589164..e9b65979e 100644 --- a/lib/concierge/suppliers/kigo/mappers/min_stay.rb +++ b/lib/concierge/suppliers/kigo/mappers/min_stay.rb @@ -15,20 +15,11 @@ def initialize(prop_min_stay, cal_min_stay) end # Compare and return the most strict min_stay value. + # Return nil if both prop_min_stay and cal_min_stay are zero def value min_stay = [prop_min_stay.to_i, cal_min_stay.to_i].max - if min_stay.zero? - invalid_min_stay_error - else - Result.new(min_stay) - end - end - - private - def invalid_min_stay_error - desc = "Min stay was not defined both for property and calendar entry" - Result.error(:invalid_min_stay, desc) + min_stay.zero? ? nil : min_stay end end end diff --git a/lib/concierge/suppliers/kigo/mappers/property.rb b/lib/concierge/suppliers/kigo/mappers/property.rb index 59694a3f4..11738c347 100644 --- a/lib/concierge/suppliers/kigo/mappers/property.rb +++ b/lib/concierge/suppliers/kigo/mappers/property.rb @@ -38,19 +38,12 @@ def prepare(property_data, pricing_data) return Result.error(:no_prices_provided, "Empty or invalid price") unless pricing_mapper.valid? set_price(pricing_mapper) + set_minimum_stay(pricing_mapper) set_images set_deposit set_cleaning_service - min_stay_result = Kigo::Mappers::MinStay.new( - property.minimum_stay.to_i, - pricing_mapper.minimum_stay - ).value - return min_stay_result unless min_stay_result.success? - - set_minimum_stay(min_stay_result.value) - Result.new(property) end @@ -81,9 +74,6 @@ def set_base_info property.check_out_time = info['PROP_COUT_TIME'] property.check_in_instructions = info['PROP_ARRIVAL_SHEET'] - # min_stay is set here, but maybe overided with a stricter minimum from pricingSetup - property.minimum_stay = stay_length(info['PROP_STAYTIME_MIN']) - # Kigo properties are available by default, but most of them has a periodical rate # which covers almost all days. The days which not in periodical rates # have unavailable availabilities for these days @@ -103,12 +93,6 @@ def set_base_info end end - # Parse the minimum stay from the given interval, - # or use 1 to statisfy Roomorama's property validation - def stay_length(interval) - Kigo::TimeInterval.new(interval).days || 1 - end - def set_description description = strip(info['PROP_DESCRIPTION']) || strip(info['PROP_SHORTDESCRIPTION']) area_description = strip(info['PROP_AREADESCRIPTION']) @@ -173,8 +157,18 @@ def set_cleaning_service property.services_cleaning_rate = get_fee_amount(cleaning_fee) end - def set_minimum_stay(minimum_stay) - property.minimum_stay = minimum_stay + def set_minimum_stay(pricing_mapper) + min_stay = Kigo::Mappers::MinStay.new( + stay_length(info['PROP_STAYTIME_MIN']), + pricing_mapper.minimum_stay + ) + + # Use 1 if min_stay is nil to satisfy Roomorama's property validation + property.minimum_stay = min_stay.value || 1 + end + + def stay_length(interval) + Kigo::TimeInterval.new(interval).days end # STAYLENGTH unit means deposit has different prices for night, week, month diff --git a/spec/lib/concierge/suppliers/kigo/calendar_spec.rb b/spec/lib/concierge/suppliers/kigo/calendar_spec.rb index 5bf0482b3..a8556081b 100644 --- a/spec/lib/concierge/suppliers/kigo/calendar_spec.rb +++ b/spec/lib/concierge/suppliers/kigo/calendar_spec.rb @@ -66,15 +66,22 @@ end context "when property hasn't minimum_stay value" do - it 'returns invalid_min_stay error' do + it 'returns entries with nil min stay' do availabilities.concat([availability, unavailable_availability]) result = subject.perform(pricing, availabilities: availabilities) - expect(result).not_to be_success - expect(result.error.code).to eq(:invalid_min_stay) - expect(result.error.data).to eq( - "Min stay was not defined both for property and calendar entry" - ) + expect(result).to be_success + + calendar = result.value + available_entry = calendar.entries.find { |entry| entry.date.to_s == availability['DATE'] } + unavailable_entry = calendar.entries.find { |entry| entry.date.to_s == unavailable_availability['DATE'] } + + expect(available_entry.available).to eq true + expect(unavailable_entry.available).to eq false + + calendar.entries.each do |entry| + expect(entry.minimum_stay).to be_nil + end end end end diff --git a/spec/lib/concierge/suppliers/kigo/mappers/min_stay_spec.rb b/spec/lib/concierge/suppliers/kigo/mappers/min_stay_spec.rb index edc464835..76d576bbb 100644 --- a/spec/lib/concierge/suppliers/kigo/mappers/min_stay_spec.rb +++ b/spec/lib/concierge/suppliers/kigo/mappers/min_stay_spec.rb @@ -6,63 +6,56 @@ prop_min_stay = 20 cal_min_stay = 19 - min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value - expect(min_stay_result).to be_success - expect(min_stay_result.value).to eq(20) + min_stay = described_class.new(prop_min_stay, cal_min_stay) + expect(min_stay.value).to eq(20) end it "selects calendars's minimum_stay if it's bigger than property's minimum_stay" do prop_min_stay = 16 cal_min_stay = 17 - min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value - expect(min_stay_result).to be_success - expect(min_stay_result.value).to eq(17) + min_stay = described_class.new(prop_min_stay, cal_min_stay) + expect(min_stay.value).to eq(17) end it "selects any of minimum_stay values if they equal to each other" do prop_min_stay = 15 cal_min_stay = 15 - min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value - expect(min_stay_result).to be_success - expect(min_stay_result.value).to eq(15) + min_stay = described_class.new(prop_min_stay, cal_min_stay) + expect(min_stay.value).to eq(15) end it "selects property's minimum_stay when calendar's one is nil" do prop_min_stay = 13 cal_min_stay = nil - min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value - expect(min_stay_result).to be_success - expect(min_stay_result.value).to eq(13) + min_stay = described_class.new(prop_min_stay, cal_min_stay) + expect(min_stay.value).to eq(13) end it "selects property's minimum_stay when calendar's one is nil" do prop_min_stay = nil cal_min_stay = 11 - min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value - expect(min_stay_result).to be_success - expect(min_stay_result.value).to eq(11) + min_stay = described_class.new(prop_min_stay, cal_min_stay) + expect(min_stay.value).to eq(11) end it "applies .to_i to property's minimum_stay values" do prop_min_stay = "20" cal_min_stay = 19 - min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value - expect(min_stay_result).to be_success - expect(min_stay_result.value).to eq(20) + min_stay = described_class.new(prop_min_stay, cal_min_stay) + expect(min_stay.value).to eq(20) end it "applies .to_i to calendars's minimum_stay values" do prop_min_stay = 10 cal_min_stay = "19" - min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value - expect(min_stay_result).to be_success - expect(min_stay_result.value).to eq(19) + min_stay = described_class.new(prop_min_stay, cal_min_stay) + expect(min_stay.value).to eq(19) end it "returns error when both minimum_stay values are nil or 0" do @@ -70,12 +63,8 @@ null_values.each do |prop_min_stay| null_values.each do |cal_min_stay| - min_stay_result = described_class.new(prop_min_stay, cal_min_stay).value - expect(min_stay_result).not_to be_success - expect(min_stay_result.error.code).to eq(:invalid_min_stay) - expect(min_stay_result.error.data).to eq( - "Min stay was not defined both for property and calendar entry" - ) + min_stay = described_class.new(prop_min_stay, cal_min_stay) + expect(min_stay.value).to be_nil end end end diff --git a/spec/workers/suppliers/kigo/calendar_spec.rb b/spec/workers/suppliers/kigo/calendar_spec.rb index 346e77879..14932edf6 100644 --- a/spec/workers/suppliers/kigo/calendar_spec.rb +++ b/spec/workers/suppliers/kigo/calendar_spec.rb @@ -98,7 +98,7 @@ context "when property has no minimum_stay value" do let(:property_attrs) {{ host_id: host.id, identifier: identifier, data: { minimum_stay: nil, nightly_rate: 10 }}} - it "returns external error" do + it "doesn't creates an external error" do allow_any_instance_of(Kigo::Importer).to receive(:fetch_prices) { Result.new(empty_prices) } allow_any_instance_of(Kigo::Importer).to receive(:fetch_availabilities) { Result.new(availabilities) } @@ -112,8 +112,8 @@ stats = sync_process.stats expect(stats[:properties_processed]).to eq 1 - expect(stats[:available_records]).to eq 0 - expect(stats[:unavailable_records]).to eq 0 + expect(stats[:available_records]).to eq 1 + expect(stats[:unavailable_records]).to eq 7 end end end