diff --git a/android/jni/com/mapswithme/maps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp index 23f3b9b04a..1d82cc1975 100644 --- a/android/jni/com/mapswithme/maps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -11,6 +11,7 @@ #include "partners_api/ads_engine.hpp" #include "partners_api/banner.hpp" +#include "partners_api/booking_block_params.hpp" #include "partners_api/mopub_ads.hpp" #include "partners_api/megafon_countries.hpp" @@ -507,12 +508,12 @@ place_page::Info & Framework::GetPlacePageInfo() } void Framework::RequestBookingMinPrice(JNIEnv * env, jobject policy, - string const & hotelId, string const & currencyCode, - booking::GetMinPriceCallback const & callback) + booking::BlockParams const & params, + booking::BlockAvailabilityCallback const & callback) { auto const bookingApi = m_work.GetBookingApi(ToNativeNetworkPolicy(env, policy)); if (bookingApi) - bookingApi->GetMinPrice(hotelId, currencyCode, callback); + bookingApi->GetBlockAvailability(params, callback); } void Framework::RequestBookingInfo(JNIEnv * env, jobject policy, diff --git a/android/jni/com/mapswithme/maps/Framework.hpp b/android/jni/com/mapswithme/maps/Framework.hpp index b7fed20c86..eaeaa50f63 100644 --- a/android/jni/com/mapswithme/maps/Framework.hpp +++ b/android/jni/com/mapswithme/maps/Framework.hpp @@ -16,6 +16,7 @@ #include "local_ads/event.hpp" +#include "partners_api/booking_api.hpp" #include "partners_api/locals_api.hpp" #include "platform/country_defines.hpp" @@ -40,6 +41,11 @@ namespace search struct EverywhereSearchParams; } +namespace booking +{ +struct BlockParams; +} + namespace android { class Framework @@ -175,9 +181,8 @@ namespace android void SetPlacePageInfo(place_page::Info const & info); place_page::Info & GetPlacePageInfo(); - void RequestBookingMinPrice(JNIEnv * env, jobject policy, - std::string const & hotelId, std::string const & currency, - booking::GetMinPriceCallback const & callback); + void RequestBookingMinPrice(JNIEnv * env, jobject policy, booking::BlockParams const & params, + booking::BlockAvailabilityCallback const & callback); void RequestBookingInfo(JNIEnv * env, jobject policy, std::string const & hotelId, std::string const & lang, booking::GetHotelInfoCallback const & callback); diff --git a/android/jni/com/mapswithme/maps/Sponsored.cpp b/android/jni/com/mapswithme/maps/Sponsored.cpp index c2ff6f1e86..9c44b84e0a 100644 --- a/android/jni/com/mapswithme/maps/Sponsored.cpp +++ b/android/jni/com/mapswithme/maps/Sponsored.cpp @@ -1,9 +1,12 @@ -#include "Framework.hpp" +#include "com/mapswithme/maps/Framework.hpp" #include "com/mapswithme/core/jni_helper.hpp" #include "com/mapswithme/platform/Platform.hpp" + #include "map/place_page_info.hpp" + #include "partners_api/booking_api.hpp" +#include "partners_api/booking_block_params.hpp" #include #include @@ -142,16 +145,21 @@ JNIEXPORT void JNICALL Java_com_mapswithme_maps_widget_placepage_Sponsored_nativ g_lastRequestedHotelId = hotelId; std::string const code = jni::ToNativeString(env, currencyCode); - + auto params = booking::BlockParams::MakeDefault(); + params.m_hotelId = hotelId; + params.m_currency = code; g_framework->RequestBookingMinPrice( - env, policy, hotelId, code, - [](std::string const hotelId, std::string const price, std::string const currency) { + env, policy, params, [](std::string const & hotelId, booking::Blocks const & blocks) { if (g_lastRequestedHotelId != hotelId) return; JNIEnv * env = jni::GetEnv(); - env->CallStaticVoidMethod(g_sponsoredClass, g_priceCallback, jni::ToJavaString(env, hotelId), - jni::ToJavaString(env, price), jni::ToJavaString(env, currency)); + auto const price = blocks.m_totalMinPrice == BlockInfo::kIncorrectPrice + ? "" + : std::to_string(blocks.m_totalMinPrice); + env->CallStaticVoidMethod(g_sponsoredClass, g_priceCallback, + jni::ToJavaString(env, hotelId), jni::ToJavaString(env, price), + jni::ToJavaString(env, blocks.m_currency)); }); } diff --git a/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm b/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm index 958f258464..32828608f1 100644 --- a/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm +++ b/iphone/Maps/UI/PlacePage/MWMPlacePageData.mm @@ -16,9 +16,12 @@ #include "platform/preferred_languages.hpp" #include "partners_api/booking_api.hpp" +#include "partners_api/booking_block_params.hpp" #include "3party/opening_hours/opening_hours.hpp" +#include + using namespace place_page; namespace @@ -579,16 +582,19 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS"; std::string const currency = self.currencyFormatter.currencyCode.UTF8String; auto const func = [self, label, currency](std::string const & hotelId, - std::string const & minPrice, - std::string const & priceCurrency) { - if (currency != priceCurrency) + booking::Blocks const & blocks) { + if (currency != blocks.m_currency) return; NSNumberFormatter * decimalFormatter = [[NSNumberFormatter alloc] init]; decimalFormatter.numberStyle = NSNumberFormatterDecimalStyle; + auto const price = blocks.m_totalMinPrice == booking::BlockInfo::kIncorrectPrice + ? "" + : std::to_string(blocks.m_totalMinPrice); + NSNumber * currencyNumber = [decimalFormatter - numberFromString:[@(minPrice.c_str()) + numberFromString:[@(price.c_str()) stringByReplacingOccurrencesOfString:@"." withString:decimalFormatter .decimalSeparator]]; @@ -601,7 +607,10 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS"; }); }; - api->GetMinPrice(self.sponsoredId.UTF8String, currency, func); + auto params = booking::BlockParams::MakeDefault(); + params.m_hotelId = self.sponsoredId.UTF8String; + params.m_currency = currency; + api->GetBlockAvailability(params, func); }); } diff --git a/map/map_tests/booking_filter_test.cpp b/map/map_tests/booking_filter_test.cpp index 1b03251172..9223fa1065 100644 --- a/map/map_tests/booking_filter_test.cpp +++ b/map/map_tests/booking_filter_test.cpp @@ -35,7 +35,7 @@ public: protected: TestMwmEnvironment() { - booking::SetBookingUrlForTesting("http://localhost:34568/booking/min_price"); + booking::SetBookingUrlForTesting("http://localhost:34568/booking"); } ~TestMwmEnvironment() diff --git a/partners_api/CMakeLists.txt b/partners_api/CMakeLists.txt index b8a474c7f3..d7f0e3f53a 100644 --- a/partners_api/CMakeLists.txt +++ b/partners_api/CMakeLists.txt @@ -13,6 +13,8 @@ set( booking_api.hpp booking_availability_params.cpp booking_availability_params.hpp + booking_block_params.cpp + booking_block_params.hpp booking_params_base.hpp facebook_ads.cpp facebook_ads.hpp diff --git a/partners_api/booking_api.cpp b/partners_api/booking_api.cpp index dd4732d364..ad92a1548d 100644 --- a/partners_api/booking_api.cpp +++ b/partners_api/booking_api.cpp @@ -30,7 +30,7 @@ using namespace std::chrono; namespace { string const kBookingApiBaseUrlV1 = "https://distribution-xml.booking.com/json/bookings"; -string const kBookingApiBaseUrlV2 = "https://distribution-xml.booking.com/2.0/json/"; +string const kBookingApiBaseUrlV2 = "https://distribution-xml.booking.com/2.0/json"; string const kExtendedHotelInfoBaseUrl = "https://hotels.maps.me/getDescription"; string const kPhotoOriginalUrl = "http://aff.bstatic.com/images/hotel/max500/"; string const kPhotoSmallUrl = "http://aff.bstatic.com/images/hotel/max300/"; @@ -231,43 +231,123 @@ void FillHotelInfo(string const & src, HotelInfo & info) info.m_reviews = ParseReviews(reviewsArray); } -void FillPriceAndCurrency(string const & src, string const & currency, string & minPrice, - string & priceCurrency) +void FillPriceAndCurrency(json_t * src, string const & currency, BlockInfo & result) { - my::Json root(src.c_str()); - if (!json_is_array(root.get())) - MYTHROW(my::Json::Exception, ("The answer must contain a json array.")); - size_t const rootSize = json_array_size(root.get()); + FromJSONObject(src, "currency", result.m_currency); + FromJSONObject(src, "price", result.m_minPrice); - if (rootSize == 0) - return; - - // Read default hotel price and currency. - auto obj = json_array_get(root.get(), 0); - FromJSONObject(obj, "min_price", minPrice); - FromJSONObject(obj, "currency_code", priceCurrency); - - if (currency.empty() || priceCurrency == currency) + if (currency.empty() || result.m_currency == currency) return; // Try to get price in requested currency. - json_t * arr = json_object_get(obj, "other_currency"); - if (arr == nullptr || !json_is_array(arr)) + json_t * other = json_object_get(src, "other_currency"); + if (!json_is_object(other)) return; - size_t sz = json_array_size(arr); - string code; + string otherCurrency; + FromJSONObject(other, "currency", otherCurrency); + if (otherCurrency == currency) + { + result.m_currency = otherCurrency; + FromJSONObject(other, "price", result.m_minPrice); + return; + } +} + +BlockInfo MakeBlock(json_t * src, string const & currency) +{ + BlockInfo result; + + FromJSONObject(src, "block_id", result.m_blockId); + FromJSONObject(src, "name", result.m_name); + FromJSONObject(src, "room_description", result.m_description); + FromJSONObject(src, "max_occupancy", result.m_maxOccupancy); + FromJSONObject(src, "breakfast_included", result.m_breakfastIncluded); + FromJSONObject(src, "deposit_required", result.m_depositRequired); + + auto minPriceRoot = json_object_get(src, "min_price"); + if (!json_is_object(minPriceRoot)) + MYTHROW(my::Json::Exception, ("The min_price must contain a json object.")); + + FillPriceAndCurrency(minPriceRoot, currency, result); + + auto photosArray = json_object_get(src, "photos"); + size_t sz = json_array_size(photosArray); + string photoUrl; for (size_t i = 0; i < sz; ++i) { - auto el = json_array_get(arr, i); - FromJSONObject(el, "currency_code", code); - if (code == currency) + auto photoItem = json_array_get(photosArray, i); + FromJSONObject(photoItem, "url_original", photoUrl); + result.m_photos.emplace_back(photoUrl); + } + + Deals deals; + bool lastMinuteDeal = false; + FromJSONObjectOptionalField(src, "is_last_minute_deal", lastMinuteDeal); + if (lastMinuteDeal) + { + deals.m_types.emplace_back(Deals::Type::LastMinute); + FromJSONObject(src, "last_minute_deal_percentage", deals.m_discount); + } + bool smartDeal = false; + FromJSONObjectOptionalField(src, "is_smart_deal", smartDeal); + if (smartDeal) + deals.m_types.emplace_back(Deals::Type::Smart); + + string refundableUntil; + auto refundableUntilObject = json_object_get(src, "refundable_until"); + if (json_is_string(refundableUntilObject)) + { + FromJSON(refundableUntilObject, refundableUntil); + + if (!refundableUntil.empty()) { - priceCurrency = code; - FromJSONObject(el, "min_price", minPrice); - break; + istringstream ss(refundableUntil); + tm t = {}; + ss >> base::get_time(&t, "%Y-%m-%d %H:%M:%S"); + if (ss.fail()) + LOG(LWARNING, ("Incorrect refundable_until date =", refundableUntil)); + else + result.m_refundableUntil = system_clock::from_time_t(mktime(&t)); } } + + return result; +} + +void FillBlocks(string const & src, string const & currency, Blocks & blocks) +{ + my::Json root(src.c_str()); + if (!json_is_object(root.get())) + MYTHROW(my::Json::Exception, ("The answer must contain a json object.")); + + auto rootArray = json_object_get(root.get(), "result"); + if (!json_is_array(rootArray)) + MYTHROW(my::Json::Exception, ("The \"result\" field must contain a json array.")); + + size_t const rootSize = json_array_size(rootArray); + ASSERT_LESS(rootSize, 2, ("Several hotels is not supported in this method")); + if (rootSize == 0) + return; + + auto rootItem = json_array_get(rootArray, 0); + if (!json_is_object(rootItem)) + MYTHROW(my::Json::Exception, ("The root item must contain a json object.")); + + auto blocksArray = json_object_get(rootItem, "block"); + if (!json_is_array(blocksArray)) + MYTHROW(my::Json::Exception, ("The \"block\" field must contain a json array.")); + + size_t const blocksSize = json_array_size(blocksArray); + for (size_t i = 0; i < blocksSize; ++i) + { + auto block = json_array_get(blocksArray, i); + + if (!json_is_object(block)) + MYTHROW(my::Json::Exception, ("The block item must contain a json object.")); + + blocks.Add(MakeBlock(block, currency)); + } } void FillHotelIds(string const & src, vector & ids) @@ -345,6 +425,14 @@ bool RawApi::HotelAvailability(AvailabilityParams const & params, string & resul return RunSimpleHttpRequest(true, url, result); } +// static +bool RawApi::BlockAvailability(BlockParams const & params, string & result) +{ + string url = MakeApiUrlV2("blockAvailability", params.Get()); + + return RunSimpleHttpRequest(true, url, result); +} + string Api::GetBookHotelUrl(string const & baseUrl) const { ASSERT(!baseUrl.empty(), ()); @@ -407,31 +495,29 @@ string Api::ApplyAvailabilityParams(string const & url, AvailabilityParams const return ApplyAvailabilityParamsUniversal(url, params); } -void Api::GetMinPrice(string const & hotelId, string const & currency, - GetMinPriceCallback const & fn) const +void Api::GetBlockAvailability(BlockParams const & params, + BlockAvailabilityCallback const & fn) const { - GetPlatform().RunTask(Platform::Thread::Network, [hotelId, currency, fn]() + GetPlatform().RunTask(Platform::Thread::Network, [params, fn]() { - string minPrice; - string priceCurrency; string httpResult; - if (!RawApi::GetHotelAvailability(hotelId, currency, httpResult)) + if (!RawApi::BlockAvailability(params, httpResult)) { - fn(hotelId, minPrice, priceCurrency); + fn(params.m_hotelId, {}); return; } + Blocks blocks; try { - FillPriceAndCurrency(httpResult, currency, minPrice, priceCurrency); + FillBlocks(httpResult, params.m_currency, blocks); } catch (my::Json::Exception const & e) { LOG(LERROR, (e.Msg())); - minPrice.clear(); - priceCurrency.clear(); + blocks = {}; } - fn(hotelId, minPrice, priceCurrency); + fn(params.m_hotelId, blocks); }); } @@ -456,7 +542,7 @@ void Api::GetHotelInfo(string const & hotelId, string const & lang, } catch (my::Json::Exception const & e) { - LOG(LERROR, ("Failed to parse json:", hotelId, result, e.what())); + LOG(LINFO, ("Failed to parse json:", hotelId, result, e.what())); ClearHotelInfo(info); } diff --git a/partners_api/booking_api.hpp b/partners_api/booking_api.hpp index 5c4302c3b6..f35d295003 100644 --- a/partners_api/booking_api.hpp +++ b/partners_api/booking_api.hpp @@ -1,6 +1,7 @@ #pragma once #include "partners_api/booking_availability_params.hpp" +#include "partners_api/booking_block_params.hpp" #include "platform/safe_callback.hpp" @@ -48,6 +49,59 @@ struct HotelInfo uint32_t m_scoreCount = 0; }; +struct Deals +{ + enum Type + { + /// Good price. + Smart, + /// Sale with discount in percent from base price. + LastMinute + }; + + std::vector m_types; + uint8_t m_discount = 0; +}; + +struct BlockInfo +{ + static double constexpr kIncorrectPrice = std::numeric_limits::max(); + std::string m_blockId; + std::string m_name; + std::string m_description; + uint8_t m_maxOccupancy = 0; + double m_minPrice = kIncorrectPrice; + std::string m_currency; + std::vector m_photos; + Deals m_deals; + std::chrono::time_point m_refundableUntil; + bool m_breakfastIncluded = false; + bool m_depositRequired = false; +}; + +struct Blocks +{ + void Add(BlockInfo && block) + { + if (block.m_minPrice < m_totalMinPrice) + { + m_totalMinPrice = block.m_minPrice; + m_currency = block.m_currency; + } + if (block.m_deals.m_discount > m_maxDiscount) + m_maxDiscount = block.m_deals.m_discount; + + m_blocks.emplace_back(block); + } + + double m_totalMinPrice = BlockInfo::kIncorrectPrice; + std::string m_currency; + + uint8_t m_maxDiscount = 0; + + std::vector m_blocks; +}; + class RawApi { public: @@ -56,9 +110,11 @@ public: static bool GetExtendedInfo(std::string const & hotelId, std::string const & lang, std::string & result); // Booking Api v2 methods: static bool HotelAvailability(AvailabilityParams const & params, std::string & result); + static bool BlockAvailability(BlockParams const & params, string & result); }; -using GetMinPriceCallback = platform::SafeCallback; +using BlockAvailabilityCallback = + platform::SafeCallback; using GetHotelInfoCallback = platform::SafeCallback; // NOTE: this callback will be called on the network thread. using GetHotelAvailabilityCallback = std::function hotelIds)>; @@ -79,8 +135,7 @@ public: /// Real-time information methods (used for retrieving rapidly changing information). /// These methods send requests directly to Booking. - void GetMinPrice(std::string const & hotelId, std::string const & currency, - GetMinPriceCallback const & fn) const; + void GetBlockAvailability(BlockParams const & params, BlockAvailabilityCallback const & fn) const; /// NOTE: callback will be called on the network thread. void GetHotelAvailability(AvailabilityParams const & params, diff --git a/partners_api/booking_availability_params.cpp b/partners_api/booking_availability_params.cpp index 341e4d32da..506b764a13 100644 --- a/partners_api/booking_availability_params.cpp +++ b/partners_api/booking_availability_params.cpp @@ -1,5 +1,4 @@ #include "partners_api/booking_availability_params.hpp" -#include "partners_api/utils.hpp" #include "base/string_utils.hpp" @@ -9,11 +8,6 @@ using namespace base; namespace { -std::string FormatTime(booking::AvailabilityParams::Time p) -{ - return partners_api::FormatTime(p, "%Y-%m-%d"); -} - bool IsAcceptedByFilter(booking::AvailabilityParams::UrlFilter const & filter, std::string const & value) { diff --git a/partners_api/booking_availability_params.hpp b/partners_api/booking_availability_params.hpp index 3f3bc26db9..7d29c742aa 100644 --- a/partners_api/booking_availability_params.hpp +++ b/partners_api/booking_availability_params.hpp @@ -37,8 +37,6 @@ struct AvailabilityParams : public ParamsBase int8_t m_ageOfChild = kNoChildren; }; - using Clock = std::chrono::system_clock; - using Time = Clock::time_point; using Hotels = std::vector; using Rooms = std::vector; using Stars = std::vector; diff --git a/partners_api/booking_block_params.cpp b/partners_api/booking_block_params.cpp new file mode 100644 index 0000000000..bcd98b4548 --- /dev/null +++ b/partners_api/booking_block_params.cpp @@ -0,0 +1,60 @@ +#include "partners_api/booking_block_params.hpp" + +#include "base/string_utils.hpp" + +using namespace base; + +namespace booking +{ +// static +BlockParams BlockParams::MakeDefault() +{ + BlockParams result; + // Use tomorrow and day after tomorrow by default. + result.m_checkin = Clock::now() + std::chrono::hours(24); + result.m_checkout = Clock::now() + std::chrono::hours(48); + // Information about sales by default. + result.m_extras = {"deal_smart", "deal_lastm", "photos"}; + + return result; +} + +url::Params BlockParams::Get() const +{ + url::Params params = {{"hotel_ids", m_hotelId}, + {"checkin", FormatTime(m_checkin)}, + {"checkout", FormatTime(m_checkout)}}; + + if (!m_currency.empty()) + params.emplace_back("currency", m_currency); + + if (!m_extras.empty()) + params.emplace_back("extras", strings::JoinStrings(m_extras, ',')); + + if (!m_language.empty()) + params.emplace_back("language", m_language); + + return params; +} + +bool BlockParams::IsEmpty() const +{ + return m_checkin == Time() || m_checkout == Time(); +} + +bool BlockParams::Equals(ParamsBase const & rhs) const +{ + return rhs.Equals(*this); +} + +bool BlockParams::Equals(BlockParams const & rhs) const +{ + return m_checkin == rhs.m_checkin && m_checkout == rhs.m_checkout && + m_currency == rhs.m_currency && m_extras == rhs.m_extras && m_language == rhs.m_language; +} + +void BlockParams::Set(ParamsBase const & src) +{ + src.CopyTo(*this); +} +} // namepace booking \ No newline at end of file diff --git a/partners_api/booking_block_params.hpp b/partners_api/booking_block_params.hpp new file mode 100644 index 0000000000..836cfbfc49 --- /dev/null +++ b/partners_api/booking_block_params.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "partners_api/booking_params_base.hpp" + +#include "base/url_helpers.hpp" + +#include +#include + +namespace booking +{ +struct BlockParams : public ParamsBase +{ + using Extras = std::vector; + + static BlockParams MakeDefault(); + + base::url::Params Get() const; + + // ParamsBase overrides: + bool IsEmpty() const override; + bool Equals(ParamsBase const & rhs) const override; + bool Equals(BlockParams const & lhs) const override; + void Set(ParamsBase const & src) override; + + std::string m_hotelId; + std::string m_currency; + Time m_checkin; + Time m_checkout; + Extras m_extras; + std::string m_language; +}; +} // namespce booking diff --git a/partners_api/booking_params_base.hpp b/partners_api/booking_params_base.hpp index a740197b34..c2c275662b 100644 --- a/partners_api/booking_params_base.hpp +++ b/partners_api/booking_params_base.hpp @@ -1,5 +1,7 @@ #pragma once +#include "partners_api/utils.hpp" + #include "base/macros.hpp" #include @@ -7,9 +9,18 @@ namespace booking { struct AvailabilityParams; +struct BlockParams; struct ParamsBase { + using Clock = std::chrono::system_clock; + using Time = Clock::time_point; + + static std::string FormatTime(Time p) + { + return partners_api::FormatTime(p, "%Y-%m-%d"); + } + virtual ~ParamsBase() = default; virtual bool IsEmpty() const = 0; @@ -21,6 +32,11 @@ struct ParamsBase return false; } + virtual bool Equals(BlockParams const & lhs) const + { + return false; + } + template void CopyTo(T & dest) const { diff --git a/partners_api/partners_api_tests/booking_tests.cpp b/partners_api/partners_api_tests/booking_tests.cpp index fdf741e2b8..5491a9c21a 100644 --- a/partners_api/partners_api_tests/booking_tests.cpp +++ b/partners_api/partners_api_tests/booking_tests.cpp @@ -16,7 +16,7 @@ class AsyncGuiThreadBooking : public AsyncGuiThread public: AsyncGuiThreadBooking() { - SetBookingUrlForTesting("http://localhost:34568/booking/min_price"); + SetBookingUrlForTesting("http://localhost:34568/booking"); } ~AsyncGuiThreadBooking() override @@ -55,66 +55,53 @@ UNIT_TEST(Booking_HotelAvailability) LOG(LINFO, (result)); } -UNIT_CLASS_TEST(AsyncGuiThreadBooking, Booking_GetMinPrice) +UNIT_CLASS_TEST(AsyncGuiThreadBooking, Booking_GetBlockAvailability) { - string const kHotelId = "0"; // Internal hotel id for testing. + auto params = BlockParams::MakeDefault(); + params.m_hotelId = "0"; // Internal hotel id for testing. Api api; { - string price; + double price = std::numeric_limits::max(); string currency; string hotelId; - api.GetMinPrice(kHotelId, "" /* default currency */, - [&hotelId, &price, ¤cy](string const & id, string const & val, string const & curr) { - hotelId = id; - price = val; - currency = curr; - testing::Notify(); - }); + api.GetBlockAvailability(params, [&hotelId, &price, ¤cy](std::string const & id, + Blocks const & blocks) + { + hotelId = id; + price = blocks.m_totalMinPrice; + currency = blocks.m_currency; + testing::Notify(); + }); testing::Wait(); - TEST_EQUAL(hotelId, kHotelId, ()); - TEST(!price.empty(), ()); + TEST_EQUAL(hotelId, params.m_hotelId, ()); + TEST_NOT_EQUAL(price, std::numeric_limits::max(), ()); TEST(!currency.empty(), ()); - TEST_EQUAL(currency, "USD", ()); + TEST_EQUAL(currency, "EUR", ()); } { - string price; + auto params = BlockParams::MakeDefault(); + params.m_hotelId = "0"; // Internal hotel id for testing. + params.m_currency = "RUB"; + double price = std::numeric_limits::max(); string currency; string hotelId; - api.GetMinPrice(kHotelId, "RUB", [&hotelId, &price, ¤cy](string const & id, string const & val, string const & curr) - { - hotelId = id; - price = val; - currency = curr; - testing::Notify(); - }); + api.GetBlockAvailability(params, [&hotelId, &price, ¤cy](std::string const & id, + Blocks const & blocks) + { + hotelId = id; + price = blocks.m_totalMinPrice; + currency = blocks.m_currency; + testing::Notify(); + }); testing::Wait(); - TEST_EQUAL(hotelId, kHotelId, ()); - TEST(!price.empty(), ()); + TEST_EQUAL(hotelId, params.m_hotelId, ()); + TEST_NOT_EQUAL(price, std::numeric_limits::max(), ()); TEST(!currency.empty(), ()); TEST_EQUAL(currency, "RUB", ()); } - - { - string price; - string currency; - string hotelId; - api.GetMinPrice(kHotelId, "ISK", [&hotelId, &price, ¤cy](string const & id, string const & val, string const & curr) - { - hotelId = id; - price = val; - currency = curr; - testing::Notify(); - }); - testing::Wait(); - - TEST_EQUAL(hotelId, kHotelId, ()); - TEST(!price.empty(), ()); - TEST(!currency.empty(), ()); - TEST_EQUAL(currency, "ISK", ()); - } } UNIT_CLASS_TEST(AsyncGuiThread, GetHotelInfo) diff --git a/tools/python/ResponseProvider.py b/tools/python/ResponseProvider.py index 550bd820ac..0b8eb176c8 100644 --- a/tools/python/ResponseProvider.py +++ b/tools/python/ResponseProvider.py @@ -141,10 +141,9 @@ class ResponseProvider: "/id": self.my_id, "/partners/time": self.partners_time, "/partners/price": self.partners_price, - "/booking/min_price": self.partners_minprice, - "/booking/min_price.getHotelAvailability": self.partners_minprice, - "/booking/min_price/hotelAvailability": self.partners_hotel_availability, - "/booking/min_price/deals": self.partners_hotels_with_deals, + "/booking/hotelAvailability": self.partners_hotel_availability, + "/booking/deals": self.partners_hotels_with_deals, + "/booking/blockAvailability": self.partners_block_availability, "/partners/taxi_info": self.partners_yandex_taxi_info, "/partners/get-offers-in-bbox/": self.partners_rent_nearby, "/partners/CalculateByCoords": self.partners_calculate_by_coords, @@ -222,16 +221,15 @@ class ResponseProvider: def partners_price(self): return Payload(jsons.PARTNERS_PRICE) - - def partners_minprice(self): - return Payload(jsons.PARTNERS_MINPRICE) - def partners_hotel_availability(self): return Payload(jsons.HOTEL_AVAILABILITY) def partners_hotels_with_deals(self): return Payload(jsons.HOTELS_WITH_DEALS) + def partners_block_availability(self): + return Payload(jsons.BLOCK_AVAILABILITY) + def partners_yandex_taxi_info(self): return Payload(jsons.PARTNERS_TAXI_INFO) diff --git a/tools/python/jsons.py b/tools/python/jsons.py index 68f512b37c..a8c0913b55 100644 --- a/tools/python/jsons.py +++ b/tools/python/jsons.py @@ -230,29 +230,67 @@ HOTELS_WITH_DEALS = """ } """ -PARTNERS_MINPRICE = """ -[ +BLOCK_AVAILABILITY = """ +{ + "result": [ { - "hotel_id":"0000000", - "currency_code":"USD", - "max_price":"5000.00", - "ranking":1, - "min_price":"250.00", - "available_rooms":37, - "other_currency": [ - { - "currency_code":"RUB", - "max_price":"250000.00", - "min_price":"15000.00" - }, - { - "currency_code":"ISK", - "max_price":"500000.00", - "min_price":"30000.00" + "direct_payment": true, + "checkin": "2018-06-16", + "hotel_id": 61394, + "block": [ + { + "room_description": "Более просторные апартаменты-студио с кухней открытой планировки, телевизором с плоским экраном и бесплатным Wi-Fi.По запросу предоставляется DVD-плеер.", + "taxes": "НДС в размере 7 % , городской налог в размере 5 % ", + "rack_rate": { + "currency": "EUR", + "price": 0, + "other_currency": { + "currency": "RUB", + "price": 0 } - ] + }, + "block_id": "6139409_116589412_2_1_0", + "max_occupancy": 2, + "refundable": false, + "breakfast_included": true, + "is_smart_deal": false, + "incremental_price": [ + { + "other_currency": { + "currency": "RUB", + "price": 8405.46 + }, + "price": 116, + "currency": "EUR" + } + ], + "photos": [ + { + "url_original": "https://q-xx.bstatic.com/images/hotel/max500/437/43793388.jpg", + "photo_id": 43793388, + "url_max300": "https://q-xx.bstatic.com/images/hotel/max300/437/43793388.jpg", + "url_square60": "https://q-xx.bstatic.com/images/hotel/square60/437/43793388.jpg" + } + ], + "deposit_required": false, + "name": "Синьо Студио 1 - Стоимость не возвращается", + "is_last_minute_deal": false, + "min_price": { + "other_currency": { + "currency": "RUB", + "price": 8405.46 + }, + "price": 116, + "currency": "EUR" + }, + "refundable_until": "", + "room_id": 6139409 + } + ], + "checkout": "2018-06-17" } -] + ] +} """ PARTNERS_TAXI_INFO = """ diff --git a/xcode/partners_api/partners_api.xcodeproj/project.pbxproj b/xcode/partners_api/partners_api.xcodeproj/project.pbxproj index ec63df8e1a..733382a15d 100644 --- a/xcode/partners_api/partners_api.xcodeproj/project.pbxproj +++ b/xcode/partners_api/partners_api.xcodeproj/project.pbxproj @@ -42,6 +42,8 @@ 3DA5713420B57358007BDE27 /* booking_params_base.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DA5713320B57358007BDE27 /* booking_params_base.hpp */; }; 3DBC1C541E4B14920016897F /* facebook_ads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DBC1C521E4B14920016897F /* facebook_ads.cpp */; }; 3DBC1C551E4B14920016897F /* facebook_ads.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DBC1C531E4B14920016897F /* facebook_ads.hpp */; }; + 3DCD415320DAB33700143533 /* booking_block_params.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD415120DAB33700143533 /* booking_block_params.cpp */; }; + 3DCD415420DAB33700143533 /* booking_block_params.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DCD415220DAB33700143533 /* booking_block_params.hpp */; }; 3DF01C2D20652463005DDF8C /* taxi_places.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF01C2A20652462005DDF8C /* taxi_places.cpp */; }; 3DF01C2E20652463005DDF8C /* taxi_places.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3DF01C2B20652463005DDF8C /* taxi_places.hpp */; }; 3DF9C219207CAC3000DA0793 /* taxi_places_tests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3DF9C218207CAC3000DA0793 /* taxi_places_tests.cpp */; }; @@ -124,6 +126,8 @@ 3DBC1C501E4B14810016897F /* facebook_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = facebook_tests.cpp; sourceTree = ""; }; 3DBC1C521E4B14920016897F /* facebook_ads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = facebook_ads.cpp; sourceTree = ""; }; 3DBC1C531E4B14920016897F /* facebook_ads.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = facebook_ads.hpp; sourceTree = ""; }; + 3DCD415120DAB33700143533 /* booking_block_params.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = booking_block_params.cpp; sourceTree = ""; }; + 3DCD415220DAB33700143533 /* booking_block_params.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = booking_block_params.hpp; sourceTree = ""; }; 3DF01C2A20652462005DDF8C /* taxi_places.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = taxi_places.cpp; sourceTree = ""; }; 3DF01C2B20652463005DDF8C /* taxi_places.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = taxi_places.hpp; sourceTree = ""; }; 3DF9C218207CAC3000DA0793 /* taxi_places_tests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = taxi_places_tests.cpp; sourceTree = ""; }; @@ -227,6 +231,8 @@ F6B5363B1DA520B20067EEA5 /* partners_api */ = { isa = PBXGroup; children = ( + 3DCD415120DAB33700143533 /* booking_block_params.cpp */, + 3DCD415220DAB33700143533 /* booking_block_params.hpp */, 346E888F1E9D087400D4CE9B /* ads_base.cpp */, 346E88901E9D087400D4CE9B /* ads_base.hpp */, 346E88911E9D087400D4CE9B /* ads_engine.cpp */, @@ -341,6 +347,7 @@ 3DA5713420B57358007BDE27 /* booking_params_base.hpp in Headers */, 346E88971E9D087400D4CE9B /* ads_base.hpp in Headers */, 3D7815761F3A14910068B6AC /* async_gui_thread.hpp in Headers */, + 3DCD415420DAB33700143533 /* booking_block_params.hpp in Headers */, F67E75261DB8F06F00D6741F /* opentable_api.hpp in Headers */, 3D452AF41EE6D20D009EAB9B /* google_ads.hpp in Headers */, F6B536411DA520E40067EEA5 /* booking_api.hpp in Headers */, @@ -466,6 +473,7 @@ 3DFEBF891EF82C1300317D5C /* viator_tests.cpp in Sources */, 3DFEBF851EF82BEA00317D5C /* viator_api.cpp in Sources */, 3D4E997D1FB439260025B48C /* booking_availability_params.cpp in Sources */, + 3DCD415320DAB33700143533 /* booking_block_params.cpp in Sources */, F6B536421DA520E40067EEA5 /* uber_api.cpp in Sources */, F6539537207FBED70057B97C /* taxi_places_loader.cpp in Sources */, 4566605020D91FEE0085E8C1 /* megafon_countries.cpp in Sources */,