[taxi][core] citymobil taxi is added

This commit is contained in:
Arsentiy Milchakov 2020-10-14 12:30:51 +03:00 committed by Aleksey Belousov
parent b59e35582a
commit 341403bbe2
13 changed files with 731 additions and 47 deletions

View file

@ -0,0 +1,78 @@
{
"disabled": {
"countries": [],
"mwms": []
},
"enabled": {
"countries": [
{
"cities": [
"Balakovo",
"Berdsk",
"Chelyabinsk",
"Dmitrov",
"Dolgoprudny",
"Dzerzhinsk",
"Elektrostal",
"Engels",
"Engels",
"Kazan",
"Khimki",
"Klin",
"Kolomna",
"Krasnodar",
"Krasnogorsk",
"Krasnoyarsk",
"Moscow",
"Mytishchi",
"Nizhny Novgorod",
"Noginsk",
"Novosibirsk",
"Odintsovo",
"Omsk",
"Pavlovsky Posad",
"Perm",
"Reutov",
"Rostov",
"Saint Petersburg",
"Samara",
"Saratov",
"Sergiyev Posad",
"Serpukhov",
"Sochi",
"Solnechnogorsk",
"Tolyatti",
"Tyumen",
"Ufa",
"Ulyanovsk",
"Vidnoye",
"Volgograd",
"Voronezh",
"Voskresensk",
"Yaroslavl",
"Yekaterinburg",
"\u041e\u0440\u0435\u0445\u043e\u0432\u043e-\u0417\u0443\u0435\u0432\u043e",
"Lobnya",
"Domodedovo",
"Zelenograd",
"Korolyov",
"Lyubertsy",
"Pushkino",
"Skhodnya",
"Balashikha",
"Shchyolkovo",
"Ivanteyevka",
"Podolsk",
"Zhukovsky",
"Ramenskoye",
"Krasnoobsk",
"Akademgorodok",
"Bataysk",
"Kopeysk"
],
"id": "Russian Federation"
}
],
"mwms": []
}
}

View file

@ -107,7 +107,6 @@
"\u0422\u0430\u0440\u043a\u043e-\u0421\u0430\u043b\u0435",
"\u0420\u044b\u0431\u043d\u043e\u0435",
"\u0420\u0443\u0437\u0430\u0435\u0432\u043a\u0430",
"\u041e\u0440\u0435\u0445\u043e\u0432\u043e-\u0417\u0443\u0435\u0432\u043e",
"Nyandoma",
"Novopavlovsk",
"\u041c\u0438\u0440\u043d\u044b\u0439",
@ -230,7 +229,6 @@
"Grozny",
"\u0413\u0443\u0431\u043a\u0438\u043d\u0441\u043a\u0438\u0439",
"Gusev",
"Dmitrov",
"Dobryanka",
"Drezna",
"Dyurtyuli",
@ -307,7 +305,6 @@
"Svetlogorsk",
"Svobodny",
"\u0421\u0435\u043c\u0438\u0431\u0440\u0430\u0442\u043e\u0432\u043e",
"Sergiyev Posad",
"Sibay",
"Slavgorod",
"Slavyansk-na-Kubani",
@ -333,7 +330,6 @@
"Sharypovo",
"Shatura",
"Shuya",
"Elektrostal",
"Yugo-Kamskiy",
"Yuzhno-Sakhalinsk",
"Yartsevo",
@ -347,7 +343,6 @@
"Balashov",
"Bashmakovo",
"Belokurikha",
"Berdsk",
"Birsk",
"Bratsk",
"Bryukhovetskaya",
@ -355,7 +350,6 @@
"Buynaksk",
"Velikiye Luki",
"Vorkuta",
"Voskresensk",
"Vsevolozhsk",
"Vyatskiye Polyany",
"Gelendzhik",
@ -410,7 +404,6 @@
"Ozyorsk",
"Orlovskiy",
"Pavlovo",
"Pavlovsky Posad",
"Pereslavl-Zalessky",
"\u041f\u043e\u0439\u043a\u043e\u0432\u0441\u043a\u0438\u0439",
"Priozersk",
@ -422,7 +415,6 @@
"Sarov",
"Sverdlovskiy",
"Serdobsk",
"Solnechnogorsk",
"Stavropol",
"Stary Oskol",
"Surgut",
@ -463,7 +455,6 @@
"Atkarsk",
"Baksan",
"Balabanovo",
"Balakovo",
"Belaya Glina",
"Belgorod",
"Belebei",
@ -511,11 +502,9 @@
"Karachayevsk",
"Kimry",
"Kineshma",
"Klin",
"Kovrov",
"Kovylkino",
"Kozelsk",
"Kolomna",
"Korenovsk",
"Kotlas",
"Krasnoufimsk",
@ -541,7 +530,6 @@
"Nizhnekamsk",
"Nikolayevsk-on-Amur",
"Novopokrovskaya",
"Noginsk",
"Norilsk",
"Noyabrsk",
"Nyurba",
@ -560,7 +548,6 @@
"Rezh",
"Rovenki",
"Roslavl",
"Rostov",
"Rubtsovsk",
"Sasovo",
"Severodvinsk",
@ -718,21 +705,16 @@
"Veliky Novgorod",
"Vladivostok",
"Vladimir",
"Volgograd",
"Vologda",
"Voronezh",
"Votkinsk",
"Gatchina",
"Dzerzhinsk",
"Dimitrovgrad",
"Donskoj",
"Yekaterinburg",
"Zlatoust",
"Ivanovo",
"Izhevsk",
"Irkutsk",
"Yoshkar-Ola",
"Kazan",
"Kaliningrad",
"Kaluga",
"Kemerovo",
@ -740,8 +722,6 @@
"Kirov",
"Kondrovo",
"Kostroma",
"Krasnodar",
"Krasnoyarsk",
"Kungur",
"Kyzyl",
"Lipetsk",
@ -750,73 +730,49 @@
"Magnitogorsk",
"Miass",
"Minusinsk",
"Moscow",
"Murmansk",
"Naberezhnye Chelny",
"Nizhny Novgorod",
"Nizhny Tagil",
"Novoaltaysk",
"Novokuznetsk",
"Novokuybyshevsk",
"Novomoskovsk",
"Novorossiysk",
"Novosibirsk",
"Novocherkassk",
"Obninsk",
"Oktyabrskiy",
"Omsk",
"Orenburg",
"Orsk",
"Penza",
"Pervouralsk",
"Perm",
"Petrozavodsk",
"Pskov",
"Rostov-on-Don",
"Ryazan",
"Salavat",
"Samara",
"Saint Petersburg",
"Saransk",
"Saratov",
"Sayanogorsk",
"Serpukhov",
"Smolensk",
"Solikamsk",
"Sochi",
"Sterlitamak",
"Syzran",
"Syktyvkar",
"Taganrog",
"Tambov",
"Tver",
"Tolyatti",
"Tomsk",
"Tyumen",
"Ulan-Ude",
"Ulyanovsk",
"Ufa",
"Khabarovsk",
"Chaikovsky",
"Chapaevsk",
"Cheboksary",
"Chelyabinsk",
"Cherepovets",
"Chernogorsk",
"Chita",
"Chusovoy",
"Shakhty",
"Engels",
"Yaroslavl",
"Mytishchi",
"Reutov",
"Kotelniki",
"Dzerzhinsky",
"Vidnoye",
"Odintsovo",
"Krasnogorsk",
"Dolgoprudny",
"Khimki",
"Sestroretsk",
"Murino",
"Shushary",

View file

@ -40,6 +40,8 @@ set(
booking_ordering_params.cpp
booking_ordering_params.hpp
booking_params_base.hpp
citymobil_api.cpp
citymobil_api.hpp
freenow_api.cpp
freenow_api.hpp
guides_on_map_api.cpp

View file

@ -0,0 +1,198 @@
#include "partners_api/citymobil_api.hpp"
#include "platform/http_client.hpp"
#include "platform/platform.hpp"
#include "geometry/latlon.hpp"
#include "coding/url.hpp"
#include "coding/writer.hpp"
#include "base/logging.hpp"
#include "base/thread.hpp"
#include "std/target_os.hpp"
#include <iomanip>
#include <limits>
#include <sstream>
#include "3party/jansson/myjansson.hpp"
#include "private.h"
namespace
{
bool RunHttpRequest(std::string const & url, std::string && body, std::string & result)
{
platform::HttpClient request(url);
request.SetRawHeader("Accept", "application/json");
request.SetRawHeader("Authorization", CITYMOBIL_TOKEN);
request.SetBodyData(std::move(body), "application/json");
if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200)
{
result = request.ServerResponse();
return true;
}
return false;
}
template<typename T>
std::string SerializeToJson(T const & data)
{
std::string jsonStr;
using Sink = MemWriter<std::string>;
Sink sink(jsonStr);
coding::SerializerJson<Sink> serializer(sink);
serializer(data);
return jsonStr;
}
} // namespace
namespace taxi
{
namespace citymobil
{
std::string const kBaseUrl = "https://t.city-mobil.ru/taxiserv/api/corporation/v2";
// static
bool RawApi::GetSupportedTariffs(SupportedTariffsBody const & body, std::string & result,
std::string const & baseUrl /* = kBaseUrl */)
{
return RunHttpRequest(url::Join(baseUrl, "get_supported_tariffs"), SerializeToJson(body), result);
}
// static
bool RawApi::CalculatePrice(CalculatePriceBody const & body, std::string & result,
std::string const & baseUrl /* = kBaseUrl */)
{
return RunHttpRequest(url::Join(baseUrl, "calculate_price"), SerializeToJson(body), result);
}
/// Requests list of available products from Citymobil.
void Api::GetAvailableProducts(ms::LatLon const & from, ms::LatLon const & to,
ProductsCallback const & successFn,
ErrorProviderCallback const & errorFn)
{
ASSERT(successFn, ());
ASSERT(errorFn, ());
// TODO(a): Add ErrorCode::FarDistance and provide this error code.
if (!IsDistanceSupported(from, to))
{
errorFn(ErrorCode::NoProducts);
return;
}
auto const baseUrl = m_baseUrl;
GetPlatform().RunTask(Platform::Thread::Network, [from, to, baseUrl, successFn, errorFn]()
{
std::string tariffsResult;
RawApi::SupportedTariffsBody supportedTariffs(from);
if (!RawApi::GetSupportedTariffs(supportedTariffs, tariffsResult, baseUrl))
{
errorFn(ErrorCode::RemoteError);
return;
}
RawApi::TariffGroups tariffGroups = MakeTariffGroupsFromJson(tariffsResult);
std::string calculatePriceResult;
RawApi::CalculatePriceBody calculatePrice(from, to, tariffGroups);
if (!RawApi::CalculatePrice(calculatePrice, calculatePriceResult, baseUrl))
{
errorFn(ErrorCode::RemoteError);
return;
}
std::vector<Product> products;
try
{
products = MakeProductsFromJson(calculatePriceResult);
}
catch (base::Json::Exception const & e)
{
LOG(LERROR, (e.Msg()));
products.clear();
}
if (products.empty())
errorFn(ErrorCode::NoProducts);
else
successFn(products);
});
}
/// Returns link which allows you to launch the Citymobil app.
RideRequestLinks Api::GetRideRequestLinks(std::string const & productId, ms::LatLon const & from,
ms::LatLon const & to) const
{
std::ostringstream deepLink;
deepLink << std::fixed << std::setprecision(6) << "https://trk.mail.ru/c/q4akt6?from="
<< from.m_lat << "," << from.m_lon << "&to=" << to.m_lat << "," << to.m_lon
<< "&tariff=" << productId;
return {deepLink.str(), deepLink.str()};
}
RawApi::TariffGroups MakeTariffGroupsFromJson(std::string const & src)
{
RawApi::TariffGroups result;
base::Json root(src.c_str());
auto const tariffGroups = json_object_get(root.get(), "tariff_groups");
auto const tariffGroupsSize = json_array_size(tariffGroups);
result.resize(tariffGroupsSize);
for (size_t i = 0; i < tariffGroupsSize; ++i)
{
auto const item = json_array_get(tariffGroups, i);
FromJSONObject(item, "tariff_group_id", result[i]);
}
return result;
}
std::vector<taxi::Product> MakeProductsFromJson(std::string const & src)
{
std::vector<taxi::Product> products;
base::Json root(src.c_str());
uint32_t serviceStatus;
FromJSONObject(root.get(), "service_status", serviceStatus);
// Temporary unavailable.
if (serviceStatus == 0)
return {};
uint32_t eta = 0;
FromJSONObject(root.get(), "eta", eta);
auto const productsArray = json_object_get(root.get(), "prices");
auto const productsSize = json_array_size(productsArray);
for (size_t i = 0; i < productsSize; ++i)
{
taxi::Product product;
uint32_t id = 0;
uint32_t price = 0;
auto const item = json_array_get(productsArray, i);
FromJSONObject(item, "id_tariff_group", id);
FromJSONObject(item, "total_price", price);
auto const tariffInfo = json_object_get(item, "tariff_info");
FromJSONObject(tariffInfo, "name", product.m_name);
product.m_productId = strings::to_string(id);
product.m_price = strings::to_string(price);
product.m_time = strings::to_string(eta);
product.m_currency = "RUB";
products.push_back(std::move(product));
}
return products;
}
} // namespace citymobil
} // namespace taxi

View file

@ -0,0 +1,91 @@
#pragma once
#include "partners_api/taxi_base.hpp"
#include "coding/serdes_json.hpp"
#include <string>
#include <vector>
namespace ms
{
class LatLon;
}
namespace taxi
{
namespace citymobil
{
extern std::string const kBaseUrl;
/// Citymobil api wrapper based on synchronous http requests.
class RawApi
{
public:
using TariffGroups = std::vector<uint8_t>;
struct Position
{
DECLARE_VISITOR(visitor(m_lat, "latitude"), visitor(m_lon, "longitude"));
double m_lat = 0.0;
double m_lon = 0.0;
};
class CalculatePriceBody
{
public:
CalculatePriceBody(ms::LatLon const & from, ms::LatLon const & to, TariffGroups const & tariffs)
: m_pickup{from.m_lat, from.m_lon}
, m_dropoff{to.m_lat, to.m_lon}
, m_tariffGroups(tariffs)
{
}
DECLARE_VISITOR(visitor(m_pickup, "pickup"), visitor(m_dropoff, "dropoff"),
visitor(m_tariffGroups, "tariff_group"), visitor(m_waypoints, "waypoints"));
private:
Position m_pickup;
Position m_dropoff;
TariffGroups m_tariffGroups;
// Required api parameter but it is not used in our app.
std::vector<Position> m_waypoints;
};
class SupportedTariffsBody
{
public:
SupportedTariffsBody(ms::LatLon const & pos) : m_pickup{pos.m_lat, pos.m_lon} {}
DECLARE_VISITOR(visitor(m_pickup, "pickup"));
private:
Position m_pickup;
};
static bool GetSupportedTariffs(SupportedTariffsBody const & body, std::string & result,
std::string const & url = kBaseUrl);
static bool CalculatePrice(CalculatePriceBody const & body, std::string & result,
std::string const & url = kBaseUrl);
};
/// Class which used for making products from http requests results.
class Api : public ApiBase
{
public:
explicit Api(std::string const & baseUrl = kBaseUrl) : ApiBase(baseUrl) {}
// ApiBase overrides:
/// Requests list of available products from Citymobil.
void GetAvailableProducts(ms::LatLon const & from, ms::LatLon const & to,
ProductsCallback const & successFn,
ErrorProviderCallback const & errorFn) override;
/// Returns link which allows you to launch the Citymobil app.
RideRequestLinks GetRideRequestLinks(std::string const & productId, ms::LatLon const & from,
ms::LatLon const & to) const override;
};
RawApi::TariffGroups MakeTariffGroupsFromJson(std::string const & src);
std::vector<taxi::Product> MakeProductsFromJson(std::string const & src);
} // namespace citymobil
} // namespace taxi

View file

@ -7,6 +7,7 @@ set(
ads_engine_tests.cpp
booking_tests.cpp
bookmark_catalog_ads_tests.cpp
citymobil_tests.cpp
download_on_map_container_delegate.hpp
facebook_tests.cpp
freenow_tests.cpp

View file

@ -0,0 +1,71 @@
#include "testing/testing.hpp"
#include "partners_api/citymobil_api.hpp"
#include "geometry/latlon.hpp"
#include "platform/platform.hpp"
#include <string>
namespace
{
using Runner = Platform::ThreadRunner;
UNIT_TEST(Citymobil_GetSupportedTariffs)
{
std::string result;
taxi::citymobil::RawApi::SupportedTariffsBody supportedTariffs({55.796918, 37.537859});
taxi::citymobil::RawApi::GetSupportedTariffs(supportedTariffs, result);
TEST(!result.empty(), ());
}
UNIT_TEST(Citymobil_CalculatePrice)
{
std::string result;
taxi::citymobil::RawApi::CalculatePriceBody calculatePrice({55.796918, 37.537859},
{55.758213, 37.616093},
{1, 2, 3, 4, 5});
taxi::citymobil::RawApi::CalculatePrice(calculatePrice, result);
TEST(!result.empty(), ());
}
UNIT_CLASS_TEST(Runner, Citymobil_GetAvailableProducts)
{
taxi::citymobil::Api api("http://localhost:34568/partners");
ms::LatLon const from(55.796918, 37.537859);
ms::LatLon const to(55.758213, 37.616093);
std::vector<taxi::Product> resultProducts;
api.GetAvailableProducts(from, to,
[&resultProducts](std::vector<taxi::Product> const & products) {
resultProducts = products;
testing::Notify();
},
[](taxi::ErrorCode const code) {
TEST(false, (code));
});
testing::Wait();
TEST(!resultProducts.empty(), ());
taxi::ErrorCode errorCode = taxi::ErrorCode::RemoteError;
ms::LatLon const farPos(56.838197, 35.908507);
api.GetAvailableProducts(from, farPos,
[](std::vector<taxi::Product> const & products) {
TEST(false, ());
},
[&errorCode](taxi::ErrorCode const code) {
errorCode = code;
testing::Notify();
});
testing::Wait();
TEST_EQUAL(errorCode, taxi::ErrorCode::NoProducts, ());
}
} // namespace

View file

@ -1,11 +1,13 @@
#include "testing/testing.hpp"
#include "partners_api/citymobil_api.hpp"
#include "partners_api/freenow_api.hpp"
#include "partners_api/maxim_api.hpp"
#include "partners_api/rutaxi_api.hpp"
#include "partners_api/taxi_engine.hpp"
#include "partners_api/uber_api.hpp"
#include "partners_api/yandex_api.hpp"
#include "partners_api/yango_api.hpp"
#include "platform/platform_tests_support/async_gui_thread.hpp"
@ -110,6 +112,18 @@ public:
storage::CountryId GetMwmId(m2::PointD const & point) override { return {}; }
};
class RussiaMoscowDelegate : public taxi::Delegate
{
public:
storage::CountriesVec GetCountryIds(m2::PointD const & point) override
{
return {"Russian Federation"};
}
std::string GetCityName(m2::PointD const & point) override { return "Moscow"; }
storage::CountryId GetMwmId(m2::PointD const & point) override { return {}; }
};
std::vector<taxi::Product> GetUberSynchronous(ms::LatLon const & from, ms::LatLon const & to,
std::string const & url)
{
@ -191,6 +205,25 @@ std::vector<taxi::Product> GetFreenowSynchronous(ms::LatLon const & from, ms::La
return taxi::freenow::MakeProductsFromJson(freenowAnswer);
}
std::vector<taxi::Product> GetCitymobilSynchronous(ms::LatLon const & from, ms::LatLon const & to,
std::string const & url)
{
std::string tariffsResult;
taxi::citymobil::RawApi::SupportedTariffsBody supportedTariffs(from);
TEST(taxi::citymobil::RawApi::GetSupportedTariffs(supportedTariffs, tariffsResult, url), ());
return {};
taxi::citymobil::RawApi::TariffGroups tariffGroups =
taxi::citymobil::MakeTariffGroupsFromJson(tariffsResult);
std::string calculatePriceResult;
taxi::citymobil::RawApi::CalculatePriceBody calculatePrice(from, to, tariffGroups);
TEST(taxi::citymobil::RawApi::CalculatePrice(calculatePrice, calculatePriceResult, url), ());
return taxi::citymobil::MakeProductsFromJson(calculatePriceResult);
}
taxi::ProvidersContainer GetProvidersSynchronous(taxi::Engine const & engine,
ms::LatLon const & from, ms::LatLon const & to,
taxi::Delegate & delegate, std::string const & url)
@ -217,6 +250,12 @@ taxi::ProvidersContainer GetProvidersSynchronous(taxi::Engine const & engine,
case taxi::Provider::Type::Freenow:
providers.emplace_back(taxi::Provider::Type::Freenow, GetFreenowSynchronous(from, to, url));
break;
case taxi::Provider::Type::Yango:
providers.emplace_back(taxi::Provider::Type::Yango, GetYandexSynchronous(from, to, url));
break;
case taxi::Provider::Type::Citymobil:
providers.emplace_back(taxi::Provider::Type::Citymobil, GetCitymobilSynchronous(from, to, url));
break;
case taxi::Provider::Type::Count:
LOG(LERROR, ());
break;
@ -471,7 +510,8 @@ UNIT_CLASS_TEST(AsyncGuiThread, TaxiEngine_Smoke)
{taxi::Provider::Type::Yandex, kTesturl},
{taxi::Provider::Type::Maxim, kTesturl},
{taxi::Provider::Type::Rutaxi, kTesturl},
{taxi::Provider::Type::Freenow, kTesturl}});
{taxi::Provider::Type::Freenow, kTesturl},
{taxi::Provider::Type::Citymobil, kTesturl}});
engine.SetDelegate(std::make_unique<BelarusMinskDelegate>());
BelarusMinskDelegate delegate;
@ -544,7 +584,7 @@ UNIT_TEST(TaxiEngine_GetProvidersAtPos)
engine.SetDelegate(std::make_unique<RussiaSochiDelegate>());
providers = engine.GetProvidersAtPos(latlon);
TEST_EQUAL(providers.size(), 1, ());
TEST_EQUAL(providers[0], taxi::Provider::Type::Yandex, ());
TEST_EQUAL(providers[0], taxi::Provider::Type::Citymobil, ());
engine.SetDelegate(std::make_unique<RussiaKonetsDelegate>());
providers = engine.GetProvidersAtPos(latlon);
@ -554,5 +594,10 @@ UNIT_TEST(TaxiEngine_GetProvidersAtPos)
providers = engine.GetProvidersAtPos(latlon);
TEST_EQUAL(providers.size(), 1, ());
TEST_EQUAL(providers[0], taxi::Provider::Type::Freenow, ());
engine.SetDelegate(std::make_unique<RussiaMoscowDelegate>());
providers = engine.GetProvidersAtPos(latlon);
TEST_EQUAL(providers.size(), 1, ());
TEST_EQUAL(providers[0], taxi::Provider::Type::Citymobil, ());
}
} // namespace

View file

@ -1,5 +1,6 @@
#include "partners_api/taxi_engine.hpp"
#include "partners_api/citymobil_api.hpp"
#include "partners_api/freenow_api.hpp"
#include "partners_api/maxim_api.hpp"
#include "partners_api/rutaxi_api.hpp"
@ -122,6 +123,7 @@ Engine::Engine(std::vector<ProviderUrl> urls /* = {} */)
AddApi<yandex::Api>(urls, Provider::Type::Yandex);
AddApi<freenow::Api>(urls, Provider::Type::Freenow);
AddApi<yango::Api>(urls, Provider::Type::Yango);
AddApi<citymobil::Api>(urls, Provider::Type::Citymobil);
}
void Engine::SetDelegate(std::unique_ptr<Delegate> delegate)

View file

@ -56,6 +56,7 @@ std::string Loader::GetFileNameByProvider(Provider::Type const type)
case Provider::Type::Yandex: return "taxi_places/yandex.json";
case Provider::Type::Freenow: return "taxi_places/freenow.json";
case Provider::Type::Yango: return "taxi_places/yango.json";
case Provider::Type::Citymobil: return "taxi_places/citymobil.json";
case Provider::Type::Count: LOG(LERROR, ("Incorrect taxi provider")); return "";
}
UNREACHABLE();

View file

@ -19,7 +19,7 @@ struct Product
class Provider
{
public:
enum Type
enum class Type
{
Uber,
Yandex,
@ -27,6 +27,7 @@ public:
Rutaxi,
Freenow,
Yango,
Citymobil,
Count
};
@ -86,6 +87,7 @@ inline std::string DebugPrint(Provider::Type type)
case Provider::Type::Rutaxi: return "Rutaxi";
case Provider::Type::Freenow: return "Freenow";
case Provider::Type::Yango: return "Yango";
case Provider::Type::Citymobil: return "Citymobil";
case Provider::Type::Count: ASSERT(false, ()); return "";
}
UNREACHABLE();

View file

@ -153,6 +153,8 @@ class ResponseProvider:
"/partners/oauth/token": self.freenow_auth_token,
"/partners/service-types": self.freenow_service_types,
"/gallery/v2/map": self.guides_on_map_gallery,
"/partners/get_supported_tariffs": self.citymobil_supported_tariffs,
"/partners/calculate_price": self.citymobil_calculate_price,
}[url]()
except:
return self.test_404()
@ -263,6 +265,12 @@ class ResponseProvider:
def guides_on_map_gallery(self):
return Payload(jsons.GUIDES_ON_MAP_GALLERY)
def citymobil_supported_tariffs(self):
return Payload(jsons.CITYMOBIL_SUPPORTED_TARIFFS)
def citymobil_calculate_price(self):
return Payload(jsons.CITYMOBIL_CALCULATE_PRICE)
def kill(self):
logging.debug("Kill called in ResponseProvider")
self.delegate.kill()

View file

@ -726,3 +726,232 @@ GUIDES_ON_MAP_GALLERY = """
}
}
"""
CITYMOBIL_SUPPORTED_TARIFFS = """
{
"tariff_groups": [
{
"tariff_group_id": 2,
"tariff_options": [],
"tariff_detail": {
"is_waypoints_enabled": false,
"is_by_instruction_enabled": true,
"is_options_enabled": true,
"order_time_type": [
"asap",
"delay"
],
"description": "Таксипортация для ежедневных поездок",
"luxury_level": 1,
"car_models": "Kia Rio, Hyundai Solaris, VW Polo",
"car_image": "https://external-storage.city-mobil.ru/generated/storage_files/Polo.png",
"fastest_car_image": "https://external-storage.city-mobil.ru/generated/storage_files/econom_vw.png"
}
},
{
"tariff_group_id": 4,
"tariff_options": [],
"tariff_detail": {
"is_waypoints_enabled": false,
"is_by_instruction_enabled": true,
"is_options_enabled": true,
"order_time_type": [
"asap",
"delay"
],
"description": "Комфортная таксипортация",
"luxury_level": 3,
"car_models": "Skoda Octavia, Hyundai Elantra, Kia Cerato",
"car_image": "https://external-storage.city-mobil.ru/generated/storage_files/Octavia.png",
"fastest_car_image": "https://external-storage.city-mobil.ru/generated/storage_files/comfort_shkoda.png"
}
},
{
"tariff_group_id": 13,
"tariff_options": [],
"tariff_detail": {
"is_waypoints_enabled": false,
"is_by_instruction_enabled": true,
"is_options_enabled": true,
"order_time_type": [
"asap",
"delay"
],
"description": "Таксипортация с повышенным комфортом",
"luxury_level": 4,
"car_models": "Kia Optima, Toyota Camry, Hyundai Sonata",
"car_image": "https://external-storage.city-mobil.ru/generated/storage_files/Optima.png",
"fastest_car_image": "https://external-storage.city-mobil.ru/generated/storage_files/comfort_plus_kia.png"
}
},
{
"tariff_group_id": 5,
"tariff_options": [],
"tariff_detail": {
"is_waypoints_enabled": false,
"is_by_instruction_enabled": true,
"is_options_enabled": true,
"order_time_type": [
"asap",
"delay"
],
"description": "Для важных встреч",
"luxury_level": 5,
"car_models": "BMW 5, Mercedes E-klasse, Audi A6",
"car_image": "https://external-storage.city-mobil.ru/generated/storage_files/E-Klasse.png",
"fastest_car_image": "https://external-storage.city-mobil.ru/generated/storage_files/buisness_merce.png"
}
},
{
"tariff_group_id": 3,
"tariff_options": [],
"tariff_detail": {
"is_waypoints_enabled": false,
"is_by_instruction_enabled": true,
"is_options_enabled": true,
"order_time_type": [
"asap",
"delay"
],
"description": "",
"luxury_level": 0,
"car_models": "Ford Focus, Kia Rio, Nissan Almera",
"car_image": "",
"fastest_car_image": ""
}
},
{
"tariff_group_id": 7,
"tariff_options": [],
"tariff_detail": {
"is_waypoints_enabled": false,
"is_by_instruction_enabled": true,
"is_options_enabled": true,
"order_time_type": [
"asap",
"delay"
],
"description": "Таксипортация для большой компании",
"luxury_level": -1,
"car_models": "Ford Galaxy, Citroen C4 Picasso, Chevrolet Orlando",
"car_image": "https://external-storage.city-mobil.ru/generated/storage_files/C4.png",
"fastest_car_image": "https://external-storage.city-mobil.ru/generated/storage_files/miniven_citrienC4.png"
}
},
{
"tariff_group_id": 27,
"tariff_options": [
{
"id": 99,
"title": "От двери до двери",
"type": "delivery_tariff_door_to_door",
"is_toggle_selection": true,
"description": "Водитель сам заберет посылку у вас и доставит ее адресату до квартиры"
}
],
"tariff_detail": {
"is_waypoints_enabled": false,
"is_by_instruction_enabled": false,
"is_options_enabled": false,
"order_time_type": [
"asap"
],
"description": "",
"luxury_level": -1,
"car_models": "Когда можно не ехать, но нужно передать документы, ключи или чемодан",
"car_image": "https://external-storage.city-mobil.ru/generated/storage_files/Delivery_day.png",
"fastest_car_image": ""
}
}
]
}
"""
CITYMOBIL_CALCULATE_PRICE = """
{
"distance_text": "8 км",
"duration_text": "15 мин",
"id_calculation": "494d1fc56850ae4411e86fe2d902abe9",
"prices": [
{
"coefficient": 1,
"fixed_price": true,
"has_discount": false,
"id_tariff": 4098,
"id_tariff_group": 2,
"label": "763₽. В пути ~15 мин",
"new_user_discount": false,
"price": 763,
"total_price": 763,
"tariff_info": {
"name": "Эконом",
"price": "763₽. В пути ~15 мин",
"car_models": "Kia Rio, Hyundai Solaris, VW Polo, Renault Logan, Skoda Rapid, Nissan Almera, Chevrolet Aveo, Ford Focus.",
"car_capacity": "Пассажиров: 4, мест багажа: 2",
"link": "https://t.city-mobil.ru/view/tariffs/2/ru?id_tariff=4098",
"details": [
{
"text": "Стоимость поездки",
"value": "763₽"
}
]
}
},
{
"coefficient": 1,
"fixed_price": true,
"has_discount": false,
"id_tariff": 2,
"id_tariff_group": 4,
"label": "816₽. В пути ~15 мин",
"new_user_discount": false,
"price": 816,
"total_price": 816,
"tariff_info": {
"name": "Комфорт",
"price": "816₽. В пути ~15 мин",
"car_models": "Skoda Octavia, Hyundai Elantra, Kia Cerato, Toyota Camry, Nissan Teana, Ford Mondeo, Kia Ceed, Hyundai Sonata",
"car_capacity": "Пассажиров: 4, мест багажа: 2. Кондиционер обязателен.",
"link": "https://t.city-mobil.ru/view/tariffs/2/ru?id_tariff=2",
"details": [
{
"text": "Стоимость поездки",
"value": "816₽"
}
]
}
},
{
"coefficient": 1,
"fixed_price": true,
"has_discount": false,
"id_tariff": 144,
"id_tariff_group": 5,
"label": "1000₽. В пути ~15 мин",
"new_user_discount": false,
"price": 1000,
"total_price": 1000,
"tariff_info": {
"name": "Бизнес",
"price": "1000₽. В пути ~15 мин",
"car_models": "BMW 5, Mercedes E-klasse, Audi A6, Lexus GS, Hyundai Equus",
"car_capacity": "Пассажиров: 4, мест багажа: 2",
"link": "https://t.city-mobil.ru/view/tariffs/2/ru?id_tariff=144",
"details": [
{
"text": "Стоимость поездки",
"value": "1000₽"
}
]
}
}
],
"route": {
"distance": 7250,
"duration": 846,
"points": ""
},
"service_status": 1,
"eta": 600
}
"""