From 44ef32f033f2dadeefbcd7c40f97630ec983902f Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 13 Sep 2016 10:30:36 +0600 Subject: [PATCH 01/16] SAW: remove flag_free_sale from search endpoint --- lib/concierge/suppliers/saw/payload_builder.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/concierge/suppliers/saw/payload_builder.rb b/lib/concierge/suppliers/saw/payload_builder.rb index 7c207ff84..d35b68f9d 100644 --- a/lib/concierge/suppliers/saw/payload_builder.rb +++ b/lib/concierge/suppliers/saw/payload_builder.rb @@ -85,7 +85,6 @@ def propertysearch_request(country:, property_id: nil) #{build_username_and_password} #{country} -1 - Y #{property_id ? build_property_container(property_id) : nil } } From 1730f1893ffb86c3c9b80b09409f592fe510e388 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 13 Sep 2016 10:45:06 +0600 Subject: [PATCH 02/16] SAW: cleanup not-needed logic --- apps/workers/suppliers/saw.rb | 2 +- lib/concierge/suppliers/saw/importer.rb | 37 ------------------- .../concierge/suppliers/saw/importer_spec.rb | 36 ------------------ 3 files changed, 1 insertion(+), 74 deletions(-) diff --git a/apps/workers/suppliers/saw.rb b/apps/workers/suppliers/saw.rb index 8c39ba18e..8a3b6b22c 100644 --- a/apps/workers/suppliers/saw.rb +++ b/apps/workers/suppliers/saw.rb @@ -21,7 +21,7 @@ def perform return end - result = importer.fetch_available_properties_by_countries(countries) + result = importer.fetch_properties_by_countries(countries) if result.success? properties = result.value diff --git a/lib/concierge/suppliers/saw/importer.rb b/lib/concierge/suppliers/saw/importer.rb index 5c13116f0..5f29af69f 100644 --- a/lib/concierge/suppliers/saw/importer.rb +++ b/lib/concierge/suppliers/saw/importer.rb @@ -56,24 +56,6 @@ def fetch_properties_by_country(country) properties_fetcher.call(country) end - # Retrieves the list of available properties in a given country - # Available means those which doesn't have `on_request` attribute - # - # Returns a +Result+ wrapping +Array+ of +SAW::Entities::BasicProperty+ - # when operation succeeds - # Returns a +Result+ with +Result::Error+ when operation fails - def fetch_available_properties_by_country(country) - result = fetch_properties_by_country(country) - - if result.success? - all_properties = result.value - available_properties = all_properties.reject { |p| p.on_request? } - Result.new(available_properties) - else - result - end - end - # Retrieves the list of properties in given countries # In case if request to one of the countries fails, method stops its # execution and returns a result with a failure. @@ -93,25 +75,6 @@ def fetch_properties_by_countries(countries) Result.new(properties) end - # Retrieves the list of available properties in given countries - # In case if request to one of the countries fails, method stops its - # execution and returns a result with a failure. - # - # Returns a +Result+ wrapping +Array+ of +SAW::Entities::BasicProperty+ - # when operation succeeds - # Returns a +Result+ with +Result::Error+ when operation fails - def fetch_available_properties_by_countries(countries) - properties = countries.map do |country| - result = fetch_available_properties_by_country(country) - - return result unless result.success? - - result.value - end.flatten - - Result.new(properties) - end - # Retrieves property with extended information. # # Returns a +Result+ wrapping +SAW::Entities::DetailedProperty+ object diff --git a/spec/lib/concierge/suppliers/saw/importer_spec.rb b/spec/lib/concierge/suppliers/saw/importer_spec.rb index 044c29fad..578c12155 100644 --- a/spec/lib/concierge/suppliers/saw/importer_spec.rb +++ b/spec/lib/concierge/suppliers/saw/importer_spec.rb @@ -45,42 +45,6 @@ end end - describe "fetch_available_properties_by_country" do - it "returns full set if there wasn't any property with on request flag" do - mock_request(:country, :one) - mock_request(:propertysearch, :success) - - countries_result = subject.fetch_countries - current_country = countries_result.value.first - - properties_result = subject.fetch_available_properties_by_country( - current_country - ) - expect(properties_result.success?).to be true - expect(properties_result.value.size).to eq(5) - expect(properties_result.value).to all( - be_kind_of(SAW::Entities::BasicProperty) - ) - end - - it "filters out properties with on request flag" do - mock_request(:country, :one) - mock_request(:propertysearch, :success_with_on_request) - - countries_result = subject.fetch_countries - current_country = countries_result.value.first - - properties_result = subject.fetch_available_properties_by_country( - current_country - ) - expect(properties_result.success?).to be true - expect(properties_result.value.size).to eq(4) - expect(properties_result.value).to all( - be_kind_of(SAW::Entities::BasicProperty) - ) - end - end - describe "fetch_properties_by_countries" do it "returns a result with an empty array when all requests are empty" do mock_request(:country, :multiple) From a290fba3fac5ee2c22a732ced943949a1de447aa Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 13 Sep 2016 11:45:08 +0600 Subject: [PATCH 03/16] SAW: documentation update --- lib/concierge/suppliers/saw/importer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/concierge/suppliers/saw/importer.rb b/lib/concierge/suppliers/saw/importer.rb index 5f29af69f..c306e2a52 100644 --- a/lib/concierge/suppliers/saw/importer.rb +++ b/lib/concierge/suppliers/saw/importer.rb @@ -95,7 +95,7 @@ def fetch_unit_rates_by_property_ids(ids) bulk_rates_fetcher.call(ids) end - # Retrieves rates for properties + # Retrieves rates for units of all given properties. # # It groups properties by currency because SAW API doesn't support # fetching property rates when multiple currencies are given. From 8e9d96a5ae9eb1863c3b3ab2539f6836b967d32c Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 13 Sep 2016 11:46:38 +0600 Subject: [PATCH 04/16] SAW: update error message when fetching unit rates fails --- apps/workers/suppliers/saw.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/workers/suppliers/saw.rb b/apps/workers/suppliers/saw.rb index 8a3b6b22c..5db25721a 100644 --- a/apps/workers/suppliers/saw.rb +++ b/apps/workers/suppliers/saw.rb @@ -36,7 +36,7 @@ def perform if result.success? all_unit_rates = result.value else - message = "Failed to perform the `#fetch_rates_for_properties` operation" + message = "Failed to perform the `#fetch_all_unit_rates_for_properties` operation" announce_error(message, result) return end From e218f66811b6d31e19a672c4efaac8abb882f526 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 13 Sep 2016 11:47:52 +0600 Subject: [PATCH 05/16] SAW: better variable name for clarity --- apps/workers/suppliers/saw.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/workers/suppliers/saw.rb b/apps/workers/suppliers/saw.rb index 5db25721a..dd839f667 100644 --- a/apps/workers/suppliers/saw.rb +++ b/apps/workers/suppliers/saw.rb @@ -53,7 +53,7 @@ def perform synchronisation.finish! end - def fetch_details_and_build_property(property, rates) + def fetch_details_and_build_property(property, unit_rates) result = importer.fetch_detailed_property(property.internal_id) if result.success? @@ -62,7 +62,7 @@ def fetch_details_and_build_property(property, rates) roomorama_property = ::SAW::Mappers::RoomoramaProperty.build( property, detailed_property, - rates + unit_rates ) Result.new(roomorama_property) From d36b7b91bdcaf8ca6a6504e66fa2ca0232121e1d Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 13 Sep 2016 11:57:32 +0600 Subject: [PATCH 06/16] SAW: more strict spec --- .../suppliers/saw/mappers/roomorama_property_mapper_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/concierge/suppliers/saw/mappers/roomorama_property_mapper_spec.rb b/spec/lib/concierge/suppliers/saw/mappers/roomorama_property_mapper_spec.rb index 576992528..9afca5901 100644 --- a/spec/lib/concierge/suppliers/saw/mappers/roomorama_property_mapper_spec.rb +++ b/spec/lib/concierge/suppliers/saw/mappers/roomorama_property_mapper_spec.rb @@ -208,7 +208,7 @@ rates ) - expect(property.units).not_to eq([]) + expect(property.units.size).to eq(6) expect(property.units).to all(be_kind_of(Roomorama::Unit)) end end From cf62f4e933fb320e855eef26afdd7045f1f87897 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 13 Sep 2016 14:59:58 +0600 Subject: [PATCH 07/16] SAW: return [] instead of Result.error if rates are not available --- lib/concierge/suppliers/saw/commands/base_fetcher.rb | 3 ++- .../saw/commands/bulk_rates_fetcher_spec.rb | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/lib/concierge/suppliers/saw/commands/base_fetcher.rb b/lib/concierge/suppliers/saw/commands/base_fetcher.rb index 092b46d38..cff3e384d 100644 --- a/lib/concierge/suppliers/saw/commands/base_fetcher.rb +++ b/lib/concierge/suppliers/saw/commands/base_fetcher.rb @@ -6,7 +6,8 @@ class BaseFetcher # # Whitelisted SAW API errors: # 1007 - No properties are available for the given search parameters - VALID_RESULT_ERROR_CODES = ['1007'] + # 3031 - Rates are not available for this property + VALID_RESULT_ERROR_CODES = ['1007', '3031'] attr_reader :credentials diff --git a/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb b/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb index 0c1e197e8..f7e83bbf3 100644 --- a/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb +++ b/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb @@ -34,6 +34,18 @@ expect(rates).to all(be_kind_of(SAW::Entities::PropertyRate)) end + it "returns a result with an empty array if all rates are unavailable" do + mock_request(:propertyrates, :rates_not_available) + + result = subject.call(property_ids) + expect(result).to be_success + + rates = result.value + + expect(rates).to be_kind_of(Array) + expect(rates.size).to eq(0) + end + it "returns result with error after error" do mock_request(:propertyrates, :error) From fafd8f4b019ad4a0883212c8fe195973e46801c5 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 13 Sep 2016 15:00:15 +0600 Subject: [PATCH 08/16] SAW: disable context --- apps/workers/suppliers/saw.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/workers/suppliers/saw.rb b/apps/workers/suppliers/saw.rb index dd839f667..b8fd8ed3c 100644 --- a/apps/workers/suppliers/saw.rb +++ b/apps/workers/suppliers/saw.rb @@ -43,8 +43,6 @@ def perform properties.each do |property| synchronisation.start(property.internal_id) do - Concierge.context.disable! - unit_rates = find_rates(property.internal_id, all_unit_rates) fetch_details_and_build_property(property, unit_rates) end From 9e8282b0256ec4588355ae7837b474d00e2c3ca9 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 13 Sep 2016 15:28:42 +0600 Subject: [PATCH 09/16] SAW: adjust quote specs according latest changes --- spec/api/controllers/saw/quote_spec.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/spec/api/controllers/saw/quote_spec.rb b/spec/api/controllers/saw/quote_spec.rb index a06eb0da7..b6cb37812 100644 --- a/spec/api/controllers/saw/quote_spec.rb +++ b/spec/api/controllers/saw/quote_spec.rb @@ -104,9 +104,17 @@ def provoke_failure! result = controller.quote_price(params) - expect(result.success?).to be false + expect(result.success?).to be true expect(result).to be_kind_of(Result) - expect(result.value).to be nil + + quotation = result.value + expect(quotation).to be_kind_of(Quotation) + expect(quotation.property_id).to eq(params[:property_id]) + expect(quotation.unit_id).to eq(params[:unit_id]) + expect(quotation.check_in).to eq(params[:check_in]) + expect(quotation.check_out).to eq(params[:check_out]) + expect(quotation.guests).to eq(params[:guests]) + expect(quotation.available).to be false end end From 172d276b95635054e2e9470024881f708d976b18 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Wed, 14 Sep 2016 15:48:24 +0600 Subject: [PATCH 10/16] Update unit rates fetching strategy --- .../saw/commands/bulk_rates_fetcher.rb | 6 +++--- .../suppliers/saw/commands/price_fetcher.rb | 2 +- .../suppliers/saw/mappers/property_rate.rb | 14 +++++++++++--- .../saw/mappers/property_rate_spec.rb | 19 +++++++++++++++++++ 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher.rb b/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher.rb index 0251d2b85..57c7a64c6 100644 --- a/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher.rb +++ b/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher.rb @@ -46,7 +46,7 @@ def build_rates(rates_hash) Array(rates).map do |rate| safe_hash = Concierge::SafeAccessHash.new(rate) SAW::Mappers::PropertyRate.build(safe_hash) - end + end.compact end def build_payload(ids) @@ -59,11 +59,11 @@ def build_payload(ids) end def check_in - (today + 30 * one_day).strftime("%d/%m/%Y") + (today + 90 * one_day).strftime("%d/%m/%Y") end def check_out - (today + 31 * one_day).strftime("%d/%m/%Y") + (today + 92 * one_day).strftime("%d/%m/%Y") end def one_day diff --git a/lib/concierge/suppliers/saw/commands/price_fetcher.rb b/lib/concierge/suppliers/saw/commands/price_fetcher.rb index 22cfed51a..5bacfeca0 100644 --- a/lib/concierge/suppliers/saw/commands/price_fetcher.rb +++ b/lib/concierge/suppliers/saw/commands/price_fetcher.rb @@ -46,7 +46,7 @@ def call(params) if valid_result?(result_hash) property_rate = build_property_rate(result_hash) - quotation = if property_rate.has_unit?(params[:unit_id]) + quotation = if property_rate && property_rate.has_unit?(params[:unit_id]) SAW::Mappers::Quotation.build(params, property_rate) else SAW::Mappers::Quotation.build_unavailable(params) diff --git a/lib/concierge/suppliers/saw/mappers/property_rate.rb b/lib/concierge/suppliers/saw/mappers/property_rate.rb index 58e1b62e8..f038e0d1b 100644 --- a/lib/concierge/suppliers/saw/mappers/property_rate.rb +++ b/lib/concierge/suppliers/saw/mappers/property_rate.rb @@ -15,6 +15,8 @@ class << self # # Returns [SAW::Entities::PropertyRate] def build(hash) + return nil if empty_unit_rates?(hash) + Entities::PropertyRate.new( id: hash.get("@id"), units: build_units(hash), @@ -28,10 +30,16 @@ def parse_currency(hash) hash.get("currency_code") end + def empty_unit_rates?(hash) + units_hash(hash).nil? + end + + def units_hash(hash) + hash.get("apartments.accommodation_type.property_accommodation") + end + def build_units(hash) - units = hash.get( - "apartments.accommodation_type.property_accommodation" - ) + units = units_hash(hash) Array(units).map do |unit_hash| safe_hash = Concierge::SafeAccessHash.new(unit_hash) diff --git a/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb b/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb index 2c6559bde..f20e2ce71 100644 --- a/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb +++ b/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb @@ -76,5 +76,24 @@ module SAW expect(unit.available).to eq(true) expect(unit.max_guests).to eq(4) end + + describe "when rates are not available" do + let(:attributes) do + { + "name"=>"Adagio Access Avignon", + "check_in"=>"01/09/2016", + "check_out"=>"02/09/2016", + "currency_code"=>"EUR", + "default_currency_code"=>"EUR", + "apartments"=> {} + } + end + + it "returns nil object" do + property_rate = described_class.build(hash) + + expect(property_rate).to be_nil + end + end end end From 2a6089e3f641a600db6decfcff1092ac9f1552bc Mon Sep 17 00:00:00 2001 From: Keang Date: Mon, 19 Sep 2016 17:16:21 +0800 Subject: [PATCH 11/16] Return result instead of nil --- .../suppliers/saw/commands/price_fetcher.rb | 12 +++++----- .../suppliers/saw/mappers/property_rate.rb | 8 +++---- .../suppliers/saw/mappers/quotation.rb | 24 +++++++++++-------- .../saw/commands/bulk_rates_fetcher_spec.rb | 10 ++++++-- .../saw/mappers/property_rate_spec.rb | 7 +++--- 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/lib/concierge/suppliers/saw/commands/price_fetcher.rb b/lib/concierge/suppliers/saw/commands/price_fetcher.rb index 5bacfeca0..f42b09b66 100644 --- a/lib/concierge/suppliers/saw/commands/price_fetcher.rb +++ b/lib/concierge/suppliers/saw/commands/price_fetcher.rb @@ -44,15 +44,15 @@ def call(params) result_hash = response_parser.to_hash(result.value.body) if valid_result?(result_hash) - property_rate = build_property_rate(result_hash) + property_rate_res = build_property_rate(result_hash) - quotation = if property_rate && property_rate.has_unit?(params[:unit_id]) - SAW::Mappers::Quotation.build(params, property_rate) + if property_rate_res.success? + Result.new SAW::Mappers::Quotation.build(params, property_rate_res.value) + elsif property_rate_res.error.code == :empty_unit_rates + Result.new SAW::Mappers::Quotation.build_unavailable(params) else - SAW::Mappers::Quotation.build_unavailable(params) + property_rate_res end - - Result.new(quotation) else error_result(result_hash) end diff --git a/lib/concierge/suppliers/saw/mappers/property_rate.rb b/lib/concierge/suppliers/saw/mappers/property_rate.rb index f038e0d1b..a04c30273 100644 --- a/lib/concierge/suppliers/saw/mappers/property_rate.rb +++ b/lib/concierge/suppliers/saw/mappers/property_rate.rb @@ -13,15 +13,15 @@ class << self # * +hash+ [Concierge::SafeAccessHash] property rate object # attributes # - # Returns [SAW::Entities::PropertyRate] + # Returns [Result] wrapping [SAW::Entities::PropertyRate] def build(hash) - return nil if empty_unit_rates?(hash) + return Result.error(:empty_unit_rates) if empty_unit_rates?(hash) - Entities::PropertyRate.new( + Result.new(Entities::PropertyRate.new( id: hash.get("@id"), units: build_units(hash), currency: parse_currency(hash) - ) + )) end private diff --git a/lib/concierge/suppliers/saw/mappers/quotation.rb b/lib/concierge/suppliers/saw/mappers/quotation.rb index e1e61420e..2d0711c5e 100644 --- a/lib/concierge/suppliers/saw/mappers/quotation.rb +++ b/lib/concierge/suppliers/saw/mappers/quotation.rb @@ -15,16 +15,20 @@ class Quotation def self.build(params, property_rate) requested_unit = property_rate.find_unit(params[:unit_id]) - ::Quotation.new( - property_id: params[:property_id], - unit_id: params[:unit_id], - check_in: params[:check_in].to_s, - check_out: params[:check_out].to_s, - guests: params[:guests], - currency: property_rate.currency, - total: requested_unit.price, - available: requested_unit.available - ) + if requested_unit + ::Quotation.new( + property_id: params[:property_id], + unit_id: params[:unit_id], + check_in: params[:check_in].to_s, + check_out: params[:check_out].to_s, + guests: params[:guests], + currency: property_rate.currency, + total: requested_unit.price, + available: requested_unit.available + ) + else + self.build_unavailable(params) + end end # Builds unavailable quotation. diff --git a/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb b/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb index f7e83bbf3..899a9bc3c 100644 --- a/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb +++ b/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb @@ -19,7 +19,10 @@ rates = result.value expect(rates).to be_kind_of(Array) expect(rates.size).to eq(2) - expect(rates).to all(be_kind_of(SAW::Entities::PropertyRate)) + expect(rates).to all(be_kind_of(Result)) + rates.each do |r| + expect(r).to be_success + end end it "returns rates for single property id" do @@ -31,7 +34,10 @@ rates = result.value expect(rates).to be_kind_of(Array) expect(rates.size).to eq(1) - expect(rates).to all(be_kind_of(SAW::Entities::PropertyRate)) + expect(rates).to all(be_kind_of(Result)) + rates.each do |r| + expect(r).to be_success + end end it "returns a result with an empty array if all rates are unavailable" do diff --git a/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb b/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb index f20e2ce71..898b25b32 100644 --- a/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb +++ b/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb @@ -63,7 +63,7 @@ module SAW let(:hash) { Concierge::SafeAccessHash.new(attributes) } it "builds available property rate object" do - property_rate = described_class.build(hash) + property_rate = described_class.build(hash).value expect(property_rate).to be_kind_of(SAW::Entities::PropertyRate) expect(property_rate.id).to eq("2596") expect(property_rate.currency).to eq("EUR") @@ -89,10 +89,11 @@ module SAW } end - it "returns nil object" do + it "returns Result with error object" do property_rate = described_class.build(hash) - expect(property_rate).to be_nil + expect(property_rate).to be_a Result + expect(property_rate.error.code).to eq :empty_unit_rates end end end From 1be93c56a1f1626a13e4dc8ae01b5b8d5d9746cb Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 20 Sep 2016 12:25:18 +0600 Subject: [PATCH 12/16] SAW: separate logic for quote price and bulk price fetcher --- .../saw/commands/bulk_rates_fetcher.rb | 19 ++-- .../suppliers/saw/commands/price_fetcher.rb | 26 ++--- .../suppliers/saw/entities/property_rate.rb | 45 -------- .../suppliers/saw/entities/unit_rate.rb | 2 +- .../suppliers/saw/entities/units_pricing.rb | 45 ++++++++ lib/concierge/suppliers/saw/importer.rb | 4 +- .../suppliers/saw/mappers/quotation.rb | 100 ++++++++++++------ .../{property_rate.rb => units_pricing.rb} | 43 +++++--- .../saw/commands/bulk_rates_fetcher_spec.rb | 10 +- .../saw/mappers/roomorama_unit_set_spec.rb | 4 +- ...rty_rate_spec.rb => units_pricing_spec.rb} | 50 +++++++-- 11 files changed, 205 insertions(+), 143 deletions(-) delete mode 100644 lib/concierge/suppliers/saw/entities/property_rate.rb create mode 100644 lib/concierge/suppliers/saw/entities/units_pricing.rb rename lib/concierge/suppliers/saw/mappers/{property_rate.rb => units_pricing.rb} (52%) rename spec/lib/concierge/suppliers/saw/mappers/{property_rate_spec.rb => units_pricing_spec.rb} (62%) diff --git a/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher.rb b/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher.rb index 57c7a64c6..e3cd7e57c 100644 --- a/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher.rb +++ b/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher.rb @@ -10,6 +10,12 @@ module Commands # command = SAW::Commands::BulkRatesFetcher.new(credentials) # result = command.call(property_id) class BulkRatesFetcher < BaseFetcher + # How many days in future skip to fetch rates. + STAY_OFFSET = 90 + + # SAW returns rates for more properties if chosen STAY_LENGTH is 2 days + STAY_LENGTH = 2 + # Calls the SAW API method using the HTTP client. # # Arguments @@ -39,14 +45,11 @@ def call(ids) private def build_rates(rates_hash) - rates = rates_hash.get("response.property") + rates_array = Array(rates_hash.get("response.property")) - return [] unless rates + return rates_array unless rates_array.any? - Array(rates).map do |rate| - safe_hash = Concierge::SafeAccessHash.new(rate) - SAW::Mappers::PropertyRate.build(safe_hash) - end.compact + SAW::Mappers::UnitsPricing.build(rates_array, STAY_LENGTH) end def build_payload(ids) @@ -59,11 +62,11 @@ def build_payload(ids) end def check_in - (today + 90 * one_day).strftime("%d/%m/%Y") + (today + STAY_OFFSET * one_day).strftime("%d/%m/%Y") end def check_out - (today + 92 * one_day).strftime("%d/%m/%Y") + (today + (STAY_OFFSET+STAY_LENGTH) * one_day).strftime("%d/%m/%Y") end def one_day diff --git a/lib/concierge/suppliers/saw/commands/price_fetcher.rb b/lib/concierge/suppliers/saw/commands/price_fetcher.rb index f42b09b66..ea343f330 100644 --- a/lib/concierge/suppliers/saw/commands/price_fetcher.rb +++ b/lib/concierge/suppliers/saw/commands/price_fetcher.rb @@ -44,15 +44,11 @@ def call(params) result_hash = response_parser.to_hash(result.value.body) if valid_result?(result_hash) - property_rate_res = build_property_rate(result_hash) + quotation = build_quotation(params, result_hash) - if property_rate_res.success? - Result.new SAW::Mappers::Quotation.build(params, property_rate_res.value) - elsif property_rate_res.error.code == :empty_unit_rates - Result.new SAW::Mappers::Quotation.build_unavailable(params) - else - property_rate_res - end + return Result.error(:empty_unit_rates) unless quotation + + Result.new(quotation) else error_result(result_hash) end @@ -62,13 +58,6 @@ def call(params) end private - def build_property_rate(hash) - rates_hash = hash.get("response.property") - safe_hash = Concierge::SafeAccessHash.new(rates_hash) - - SAW::Mappers::PropertyRate.build(safe_hash) - end - def build_payload(params) payload_builder.build_compute_pricing( property_id: params[:property_id], @@ -78,6 +67,13 @@ def build_payload(params) num_guests: params[:guests] ) end + + def build_quotation(params, result_hash) + rates_hash = result_hash.get("response.property") + safe_hash = Concierge::SafeAccessHash.new(rates_hash) + + SAW::Mappers::Quotation.build(params, safe_hash) + end end end end diff --git a/lib/concierge/suppliers/saw/entities/property_rate.rb b/lib/concierge/suppliers/saw/entities/property_rate.rb deleted file mode 100644 index 0a526c89a..000000000 --- a/lib/concierge/suppliers/saw/entities/property_rate.rb +++ /dev/null @@ -1,45 +0,0 @@ -module SAW - module Entities - # +SAW::Entities::PropertyRate+ - # - # This entity represents an object with available rates for property - # units: entity includes +units+ array which has unit rates and the - # currency used for the current property - # - # Attributes - # - # +id+ - property id - # +units+ - array of SAW::Entities::UnitRate objects - # +current+ - currency code - class PropertyRate - attr_reader :id, :units, :currency - - def initialize(id:, units:, currency:) - @id = id - @units = units - @currency = currency - end - - # Find unit by +id+ - # - # Arguments - # * +id+ - # - # Returns [SAW::Entities::UnitRate] - def find_unit(id) - units.detect { |u| u.id == id } - end - - # Determines whether unit with given +id+ is present in property rate - # object or not. - # - # Arguments - # * +id+ - # - # Returns [Boolean] flag indicating the presence of rates for unit - def has_unit?(id) - !!find_unit(id) - end - end - end -end diff --git a/lib/concierge/suppliers/saw/entities/unit_rate.rb b/lib/concierge/suppliers/saw/entities/unit_rate.rb index aab25c72c..5e92f8e46 100644 --- a/lib/concierge/suppliers/saw/entities/unit_rate.rb +++ b/lib/concierge/suppliers/saw/entities/unit_rate.rb @@ -1,6 +1,6 @@ module SAW module Entities - # +SAW::Entities::PropertyRate+ + # +SAW::Entities::UnitRate+ # # This entity represents an object with available rates for units in # property. diff --git a/lib/concierge/suppliers/saw/entities/units_pricing.rb b/lib/concierge/suppliers/saw/entities/units_pricing.rb new file mode 100644 index 000000000..477c98f7e --- /dev/null +++ b/lib/concierge/suppliers/saw/entities/units_pricing.rb @@ -0,0 +1,45 @@ +module SAW + module Entities + # +SAW::Entities::UnitsPricing+ + # + # This entity represents an object with available rates for property + # units: entity includes +units+ array which has unit rates and the + # currency used for the current property + # + # Attributes + # + # +property_id+ - property id + # +currency+ - currency code + # +units+ - array of +SAW::Entities::UnitRate+ objects + class UnitsPricing + attr_reader :property_id, :units, :currency + + def initialize(property_id:, units:, currency:) + @property_id = property_id + @units = units + @currency = currency + end + + # Find unit rate by +unit_id+ + # + # Arguments + # * +unit_id+ + # + # Returns [SAW::Entities::UnitRate] + def find_unit_rate(unit_id) + units.detect { |u| u.id == unit_id } + end + + # Determines whether unit with given +uni_id+ is present in units pricing + # object or not. + # + # Arguments + # * +unit_id+ + # + # Returns [Boolean] flag indicating the presence of rates for unit + def has_rates_for_unit?(unit_id) + !!find_unit(unit_id) + end + end + end +end diff --git a/lib/concierge/suppliers/saw/importer.rb b/lib/concierge/suppliers/saw/importer.rb index c306e2a52..3decb37d0 100644 --- a/lib/concierge/suppliers/saw/importer.rb +++ b/lib/concierge/suppliers/saw/importer.rb @@ -87,7 +87,7 @@ def fetch_detailed_property(property_id) # Retrieves rates for units by given property ids # - # Returns a +Result+ wrapping an array of +SAW::Entities::PropertyRate+ + # Returns a +Result+ wrapping an array of +SAW::Entities::UnitsPricing+ # objects when operation succeeds # Returns a +Result+ with +Result::Error+ when operation fails def fetch_unit_rates_by_property_ids(ids) @@ -102,7 +102,7 @@ def fetch_unit_rates_by_property_ids(ids) # # Limits to send maximum 20 property ids (API limitation) # - # Returns a +Result+ wrapping an array of +SAW::Entities::PropertyRate+ + # Returns a +Result+ wrapping an array of +SAW::Entities::UnitsPricing+ # objects when operation succeeds # Returns a +Result+ with +Result::Error+ when operation fails def fetch_all_unit_rates_for_properties(properties) diff --git a/lib/concierge/suppliers/saw/mappers/quotation.rb b/lib/concierge/suppliers/saw/mappers/quotation.rb index 2d0711c5e..750241d6e 100644 --- a/lib/concierge/suppliers/saw/mappers/quotation.rb +++ b/lib/concierge/suppliers/saw/mappers/quotation.rb @@ -4,50 +4,80 @@ module Mappers # # This class is responsible for building a +Quotation+ object class Quotation - # Builds a quotation - # - # Arguments: - # - # * +params+ [Hash] property parameters - # * +property_rate+ [SAW::Entities::PropertyRate] property rate - # - # Returns [Quotation] - def self.build(params, property_rate) - requested_unit = property_rate.find_unit(params[:unit_id]) - - if requested_unit + class << self + # Builds a quotation + # + # Arguments: + # + # * +params+ [Hash] quotation request parameters + # * +safe_hash+ [Concierge::SafeAccessHash] result hash with price + # + # Returns [Quotation] + def build(params, safe_hash) + requested_unit = find_requested_unit(safe_hash, params[:unit_id]) + + if requested_unit + ::Quotation.new( + property_id: params[:property_id], + unit_id: params[:unit_id], + check_in: params[:check_in].to_s, + check_out: params[:check_out].to_s, + guests: params[:guests], + currency: parse_currency(safe_hash), + total: parse_price(requested_unit), + available: parse_availability(requested_unit) + ) + else + build_unavailable(params) + end + end + + private + # Builds unavailable quotation. + # Used in cases when rates information for unit is not available. + # + # Arguments: + # + # * +params+ [Hash] parameters + # + # Returns [Quotation] + def build_unavailable(params) ::Quotation.new( property_id: params[:property_id], unit_id: params[:unit_id], check_in: params[:check_in].to_s, check_out: params[:check_out].to_s, guests: params[:guests], - currency: property_rate.currency, - total: requested_unit.price, - available: requested_unit.available + available: false ) - else - self.build_unavailable(params) end - end - # Builds unavailable quotation. - # Used in cases when rates information for unit is not available. - # - # Arguments: - # - # * +params+ [Hash] parameters - # - # Returns [Quotation] - def self.build_unavailable(params) - ::Quotation.new( - property_id: params[:property_id], - unit_id: params[:unit_id], - check_in: params[:check_in].to_s, - check_out: params[:check_out].to_s, - guests: params[:guests], - available: false - ) + def units_hash(hash) + hash.get("apartments.accommodation_type.property_accommodation") + end + + def find_requested_unit(safe_hash, id) + units = units_hash(safe_hash) + requested_unit_hash = Array(units).find { |u| u["@id"] == id } + + return nil unless requested_unit_hash + Concierge::SafeAccessHash.new(requested_unit_hash) + end + + def parse_currency(hash) + hash.get("currency_code") + end + + def parse_price(hash) + price = hash.get("price_detail.net.total_price.price") + BigDecimal.new(price) + end + + def parse_availability(hash) + flag = hash.get("flag_bookable_property_accommodation") + + flag == "Y" + end end end end diff --git a/lib/concierge/suppliers/saw/mappers/property_rate.rb b/lib/concierge/suppliers/saw/mappers/units_pricing.rb similarity index 52% rename from lib/concierge/suppliers/saw/mappers/property_rate.rb rename to lib/concierge/suppliers/saw/mappers/units_pricing.rb index a04c30273..0fe62729d 100644 --- a/lib/concierge/suppliers/saw/mappers/property_rate.rb +++ b/lib/concierge/suppliers/saw/mappers/units_pricing.rb @@ -1,30 +1,37 @@ module SAW module Mappers - # +SAW::Mappers::PropertyRate+ + # +SAW::Mappers::UnitsPricing+ # - # This class is responsible for building a +SAW::Entities::PropertyRate+ + # This class is responsible for building a +SAW::Entities::UnitsPricing+ # object from the hash which was fetched from the SAW API. - class PropertyRate + class UnitsPricing class << self # Builds a property rate object # # Arguments: # - # * +hash+ [Concierge::SafeAccessHash] property rate object - # attributes + # * +rates+ [Array] array with rates hashes + # * +stay_length+ [Integer] number of days for which rates are + # fetched for # - # Returns [Result] wrapping [SAW::Entities::PropertyRate] - def build(hash) - return Result.error(:empty_unit_rates) if empty_unit_rates?(hash) - - Result.new(Entities::PropertyRate.new( - id: hash.get("@id"), - units: build_units(hash), - currency: parse_currency(hash) - )) + # Returns [Array] wrapping [SAW::Entities::UnitsPricing] objects + def build(rates, stay_length) + rates.map do |rate| + safe_hash = Concierge::SafeAccessHash.new(rate) + build_units_pricing(safe_hash, stay_length) + end.compact end private + def build_units_pricing(hash, stay_length) + return nil if empty_unit_rates?(hash) + + Entities::UnitsPricing.new( + property_id: hash.get("@id"), + units: build_units(hash, stay_length), + currency: parse_currency(hash) + ) + end def parse_currency(hash) hash.get("currency_code") @@ -38,15 +45,19 @@ def units_hash(hash) hash.get("apartments.accommodation_type.property_accommodation") end - def build_units(hash) + def build_units(hash, stay_length) units = units_hash(hash) Array(units).map do |unit_hash| safe_hash = Concierge::SafeAccessHash.new(unit_hash) + price_per_period = parse_price(safe_hash) + + # since it's average prices, we don't need high precision + price_per_night = (price_per_period / stay_length).round(2) Entities::UnitRate.new( id: safe_hash.get("@id"), - price: parse_price(safe_hash), + price: price_per_night, available: parse_availability(safe_hash), max_guests: parse_max_guests(safe_hash) ) diff --git a/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb b/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb index 899a9bc3c..87f6f4db1 100644 --- a/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb +++ b/spec/lib/concierge/suppliers/saw/commands/bulk_rates_fetcher_spec.rb @@ -19,10 +19,7 @@ rates = result.value expect(rates).to be_kind_of(Array) expect(rates.size).to eq(2) - expect(rates).to all(be_kind_of(Result)) - rates.each do |r| - expect(r).to be_success - end + expect(rates).to all(be_kind_of(SAW::Entities::UnitsPricing)) end it "returns rates for single property id" do @@ -34,10 +31,7 @@ rates = result.value expect(rates).to be_kind_of(Array) expect(rates.size).to eq(1) - expect(rates).to all(be_kind_of(Result)) - rates.each do |r| - expect(r).to be_success - end + expect(rates).to all(be_kind_of(SAW::Entities::UnitsPricing)) end it "returns a result with an empty array if all rates are unavailable" do diff --git a/spec/lib/concierge/suppliers/saw/mappers/roomorama_unit_set_spec.rb b/spec/lib/concierge/suppliers/saw/mappers/roomorama_unit_set_spec.rb index 0da28d011..aabf7cf67 100644 --- a/spec/lib/concierge/suppliers/saw/mappers/roomorama_unit_set_spec.rb +++ b/spec/lib/concierge/suppliers/saw/mappers/roomorama_unit_set_spec.rb @@ -367,8 +367,8 @@ module SAW context "when custom property rates are given" do let(:unit_rates) do - SAW::Entities::PropertyRate.new( - id: '123', + SAW::Entities::UnitsPricing.new( + property_id: '123', currency: 'USD', units: [ SAW::Entities::UnitRate.new(id: '8368', price: 200.04, available: true, max_guests: 7), diff --git a/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb b/spec/lib/concierge/suppliers/saw/mappers/units_pricing_spec.rb similarity index 62% rename from spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb rename to spec/lib/concierge/suppliers/saw/mappers/units_pricing_spec.rb index 898b25b32..72bf64a97 100644 --- a/spec/lib/concierge/suppliers/saw/mappers/property_rate_spec.rb +++ b/spec/lib/concierge/suppliers/saw/mappers/units_pricing_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' module SAW - RSpec.describe Mappers::PropertyRate do + RSpec.describe Mappers::UnitsPricing do let(:attributes) do { "name"=>"Adagio Access Avignon", @@ -61,15 +61,21 @@ module SAW end let(:hash) { Concierge::SafeAccessHash.new(attributes) } + let(:rates_array) { Array(hash) } + let(:stay_length) { 1 } it "builds available property rate object" do - property_rate = described_class.build(hash).value - expect(property_rate).to be_kind_of(SAW::Entities::PropertyRate) - expect(property_rate.id).to eq("2596") - expect(property_rate.currency).to eq("EUR") - expect(property_rate.units.size).to eq(1) + units_pricings = described_class.build(rates_array, stay_length) + expect(units_pricings).to be_kind_of(Array) + expect(units_pricings.size).to eq(1) + expect(units_pricings).to all(be_kind_of(SAW::Entities::UnitsPricing)) - unit = property_rate.units.first + units_pricing = units_pricings.first + expect(units_pricing.property_id).to eq("2596") + expect(units_pricing.currency).to eq("EUR") + expect(units_pricing.units.size).to eq(1) + + unit = units_pricing.units.first expect(unit.id).to eq("9863") expect(unit.price).to eq(104.00) @@ -89,11 +95,33 @@ module SAW } end - it "returns Result with error object" do - property_rate = described_class.build(hash) + it "returns an empty array" do + units_pricing = described_class.build(rates_array, stay_length) + + expect(units_pricing).to eq([]) + end + end + + describe "when rates are fetched for a few days" do + let(:stay_length) { 3 } + + it "divide total price to stay_length value" do + units_pricings = described_class.build(rates_array, stay_length) + expect(units_pricings).to be_kind_of(Array) + expect(units_pricings.size).to eq(1) + expect(units_pricings).to all(be_kind_of(SAW::Entities::UnitsPricing)) + + units_pricing = units_pricings.first + expect(units_pricing.property_id).to eq("2596") + expect(units_pricing.currency).to eq("EUR") + expect(units_pricing.units.size).to eq(1) + + unit = units_pricing.units.first - expect(property_rate).to be_a Result - expect(property_rate.error.code).to eq :empty_unit_rates + expect(unit.id).to eq("9863") + expect(unit.price).to eq(34.67) + expect(unit.available).to eq(true) + expect(unit.max_guests).to eq(4) end end end From 604a2a9d9cb092373ccb47fd4e8fdb248f0adba2 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 20 Sep 2016 13:54:45 +0600 Subject: [PATCH 13/16] SAW: worker update --- apps/workers/suppliers/saw.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/workers/suppliers/saw.rb b/apps/workers/suppliers/saw.rb index b8fd8ed3c..e5a341c06 100644 --- a/apps/workers/suppliers/saw.rb +++ b/apps/workers/suppliers/saw.rb @@ -11,7 +11,7 @@ def initialize(host) end def perform - result = importer.fetch_countries + result = synchronisation.new_context { importer.fetch_countries } if result.success? countries = result.value @@ -21,7 +21,9 @@ def perform return end - result = importer.fetch_properties_by_countries(countries) + result = synchronisation.new_context do + importer.fetch_properties_by_countries(countries) + end if result.success? properties = result.value @@ -31,7 +33,9 @@ def perform return end - result = importer.fetch_all_unit_rates_for_properties(properties) + result = synchronisation.new_context do + importer.fetch_all_unit_rates_for_properties(properties) + end if result.success? all_unit_rates = result.value @@ -99,7 +103,7 @@ def announce_error(message, result) end def find_rates(property_id, all_unit_rates) - all_unit_rates.find { |rate| rate.id == property_id.to_s } + all_unit_rates.find { |rate| rate.property_id == property_id.to_s } end end end From e101471bcfaf6a8138d19177530ef892eb295c5e Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 20 Sep 2016 13:55:13 +0600 Subject: [PATCH 14/16] SAW: remove not-needed methods --- .../suppliers/saw/entities/units_pricing.rb | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/lib/concierge/suppliers/saw/entities/units_pricing.rb b/lib/concierge/suppliers/saw/entities/units_pricing.rb index 477c98f7e..53baf9df5 100644 --- a/lib/concierge/suppliers/saw/entities/units_pricing.rb +++ b/lib/concierge/suppliers/saw/entities/units_pricing.rb @@ -19,27 +19,6 @@ def initialize(property_id:, units:, currency:) @units = units @currency = currency end - - # Find unit rate by +unit_id+ - # - # Arguments - # * +unit_id+ - # - # Returns [SAW::Entities::UnitRate] - def find_unit_rate(unit_id) - units.detect { |u| u.id == unit_id } - end - - # Determines whether unit with given +uni_id+ is present in units pricing - # object or not. - # - # Arguments - # * +unit_id+ - # - # Returns [Boolean] flag indicating the presence of rates for unit - def has_rates_for_unit?(unit_id) - !!find_unit(unit_id) - end end end end From cc81f1509d09866008bd55fda13e6dda10da5efd Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 20 Sep 2016 13:55:52 +0600 Subject: [PATCH 15/16] SAW: update class documentation --- lib/concierge/suppliers/saw/mappers/roomorama_unit_set.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/concierge/suppliers/saw/mappers/roomorama_unit_set.rb b/lib/concierge/suppliers/saw/mappers/roomorama_unit_set.rb index aae09ca15..257b010a0 100644 --- a/lib/concierge/suppliers/saw/mappers/roomorama_unit_set.rb +++ b/lib/concierge/suppliers/saw/mappers/roomorama_unit_set.rb @@ -13,6 +13,7 @@ class RoomoramaUnitSet # # * +basic_property+ [SAW::Entities::BasicProperty] # * +detailed_property+ [SAW::Entities::DetailedProperty] + # * +rates+ [SAW::Entities::UnitsPricing] # # +detailed_property+ includes two attributes-hashes: # From 78336bb67cac520e2658dd6d3528e640338c8645 Mon Sep 17 00:00:00 2001 From: Sharipov Ruslan Date: Tue, 20 Sep 2016 14:17:08 +0600 Subject: [PATCH 16/16] SAW: nil quotation does not make any sense --- lib/concierge/suppliers/saw/commands/price_fetcher.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/concierge/suppliers/saw/commands/price_fetcher.rb b/lib/concierge/suppliers/saw/commands/price_fetcher.rb index ea343f330..e871cfefa 100644 --- a/lib/concierge/suppliers/saw/commands/price_fetcher.rb +++ b/lib/concierge/suppliers/saw/commands/price_fetcher.rb @@ -46,8 +46,6 @@ def call(params) if valid_result?(result_hash) quotation = build_quotation(params, result_hash) - return Result.error(:empty_unit_rates) unless quotation - Result.new(quotation) else error_result(result_hash)