forked from organicmaps/organicmaps
[taxi][core] citymobil taxi is added
This commit is contained in:
parent
b59e35582a
commit
341403bbe2
13 changed files with 731 additions and 47 deletions
78
data/taxi_places/citymobil.json
Normal file
78
data/taxi_places/citymobil.json
Normal 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": []
|
||||
}
|
||||
}
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
198
partners_api/citymobil_api.cpp
Normal file
198
partners_api/citymobil_api.cpp
Normal 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
|
91
partners_api/citymobil_api.hpp
Normal file
91
partners_api/citymobil_api.hpp
Normal 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
|
|
@ -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
|
||||
|
|
71
partners_api/partners_api_tests/citymobil_tests.cpp
Normal file
71
partners_api/partners_api_tests/citymobil_tests.cpp
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
"""
|
||||
|
|
Loading…
Add table
Reference in a new issue