Обычно обозначается как "<Начальная остановка> - <Конечная остановка> <номер>", иногда используется комментарий по промежуточным остановкам.
Пример - "Старый Оскол АВ — Обоянь АС 2859", "Рязань ЦАВ - Скопин(ч/з Захарово)"
Задается как совокупность маршрута, времени отправления, перевозчика и расписания.
Пример - "Рязань ЦАВ - Кораблино, перевозчbки АО Кораблинское АТП, отправление в 11-30, регулярность - ежедневно"
Пример - "Рязань ЦАВ - Кораблино, перевозчки АО Кораблинское АТП, отправление в 12.01.2023 в 11-30".
Имеет все параметры регулярного рейса, плюс - цена взрослого/детского/багажного, кол-во свободных мест, схема мест и т.д
Приложение будет взаимодействовать с беком по REST API протоколу. Авторизация через токен в заголовках
Пример:
```
GET /
{ "readonly" : false } ```
Общий формат получения списков и пагинации:
http response
HTTP 200 OK
{
"count": 10,
"next": "https://api.example.org/accounts/?page=5",
"previous": "https://api.example.org/accounts/?page=3",
"results": [
…
]
}
Завести отдельное приложение app. Все взаимодействие - через DRF вьюхи.
Вся логика уже реализована, использовать существующие методы, а также сериализаторы (при наличии).
Возможные коды ошибок:
Формат тела ответа - всегда присутствует message и exception_type.
Примеры:
403:
json
{
"message": "Учетные данные не были предоставлены.",
"code": "not_authenticated",
"exception_type": "NotAuthenticated"
}
404:
json
{
"exception_type": "Http404",
"message": "No Report matches the given query."
}
404:
json
{
"message": "Выбранный отчет - комплексный. Получение данных отчета невозможно.",
"code": 400,
"exception_type": "APIException"
}
500:
json
{
"exception_type": "ZeroDivisionError",
"message": "division by zero"
}
Создать эксепшен для приложения от APIException. При возникновении осмысленных ошибок вызывать его.
При первом запуске, приложение запрашивает токен доступа с сервера и отправляет информацию об устройстве.
Далее сохраняет этот токен в локальном хранилище.
Все дальнейшие запросы должно быть только авторизованные (с токеном в заголовках).
Если приложение отвечает кодом 403, необходимо заново запросить токен
http request
POST /app/device/auth/
{
"device_id": "<Уникальный идентификатор устройства>",
"device_os": "<1 - android, 2 - ios>",
"firebase_id": "<При наличии>",
"device_data": {
// Все остальные данные по устройству по формате JSON
}
}
Ответ
json
{
"device_token": ""
// токен для авторизации в остальных запросах
}
Этот токен необходимо в дальнейшем использовать в заголовках Device-Token во всех запросах.
Завести модель Device, сохранять данные по нему, авторизовывать и выдавать токен.
ЭП для получения основных настроек приложения. Запрашивается до показа первого экрана.
http request
GET /app/config/
json
{
"background_image": "https://<картинка на главном экране>"
// Визуальные и прочие настройки приложения
}
Завести синглтон модель AppSettings.
Справочники загружать/обновлять при старте приложения в фоновом режиме
http request
GET /app/type-of-document/
Ответ
json
{
"count": 22,
"next": null,
"previous": null,
"results": [
{
"id": 101,
"available_range_age": {
// Достпуный возвраст для типа документов
"lower": 14,
"upper": null,
"bounds": "[)"
},
"title": "Паспорт гражданина РФ",
"is_active": true,
"use_default": true,
// Использовать по умолчанию
"mask": "^\\d{10}$",
// маска ввода
"mask_description": "10 цифр без разделителей",
// комментарий к маске
"mask_example": "1234567890"
// пример
},
{
"id": 110,
"available_range_age": {
"lower": null,
"upper": null,
"bounds": "()"
},
"title": "Свидетельство о рождении иностранного гражданина",
"is_active": true,
"use_default": false,
"mask": null,
"mask_description": null,
"mask_example": null
}
]
}
http request
GET /app/country/
http response
HTTP 200 OK
{
// ...
"results": [
{
"id": 2,
"title": "Казахстанг",
"use_default": false
}
]
}
http request
GET /app/dispatch/q=Мих
http response
HTTP 200 OK
{
// ...
"results": [
{
"id" : "mikhailov",
"title" : "Михайлов",
}
]
}
В параметре q передается строка, вводимая пользователем.
Список прибытий зависит от ID станции отправления. Без пункта отправления будет выдана ошибка.
http request
GET /app/arrival/q=Вор&from_id=mikhailov
json
{
// ...
"results": [
{
"id": "voronezh",
"title": "Воронеж"
}
]
}
В параметре q передается строка, вводимая пользователем.
http request
GET /app/routes/calendar/?dispatch_id=mikhailov&arrival_id=voronezh
json
{
// ...
"results": [
{
"id": "11.10.2023",
"price": 1267.3
},
{
"id": "12.10.2023",
"price": 1265.3
}
]
}
Для бека - использовать алгоритм из виджета соседних дат.
Расписания бывает 2 видов - только с пунктом отправления (общее расписание АВ) и с пунктом прибытия (расписание по конкретному маршруту)
http request
GET /app/routes/?dispatch_id=mikhailov
json
{
// ...
"results": [
{
"route": "Старый Оскол АВ - Воронеж АВ 2871",
"schedule": "Пн, Вт, Ср, Чт, Вс",
"start_plan": {
"15:15": {
"id": "<ID регулярного рейса"
// Информация по регулярному рейсу
}
}
}
]
}
http request
GET /app/routes/?dispatch_id=mikhailov&arrival_id=voronezh
json
{
"table_trips": [
// Список рейсов
{
"start": "05:20:00",
// Время отправления
"point_a": 7470,
// ID пункта отправления
"trip_id": "3375",
// ID рейсы
"route": "Старый Оскол АВ — Воронеж АВ 1349",
// Название маршрута
"end": "07:20:00",
// Время прибытия
"point_b": 7317,
// ID пункта прибытия
"free_place": null,
// Кол-во свободных мест
"distance": 121,
// Дистанция в км;
"free_places": null,
// Массив свободных мест
"price_full": 371,
// Цена полный
"price_child": 0,
// Цена детский
"price_baggage": 0,
// Цена багажный
"price_insurance": 0,
// Цена страховки
"bus_info": null,
// Информация по автобусу
"number": null,
// Номер маршрута
"travel_time": 120,
// Время в пути (в минутах)
"travel_time_human": " 2 ч. ",
// Время в пути (человеко-читаемое)
"carrier": "Платонов Д.Б.",
// Перевозчик
"schedule": "Ежедневно",
// Расписание
"platform": null,
// Номер платформы
"without_pd": false,
// Возможно продажа без персональных данных
"without_select_places": false,
// Не доступен выбор мест
"status": null,
// Статус рейса
"sale_status": null,
// Статус продажи
"available_for_sale": false,
// Рейс доступен для продажи
"commission": 1
// ID Комиссии
}
],
"aggregate_table": {
// Сводная информация по рейса (самый быстрый, самый дешевый, средняя продолжительность и цена и т.д
"fastest_trip": {
"start": "19:30:00",
"point_a": 7470,
"trip_id": "3390",
"route": "Старый Оскол АВ-Москва АВ \"Саларьево\" 5488",
"concreate": false,
"end": "20:30:00",
"point_b": 7317,
"free_place": null,
"distance": 150,
"free_places": null,
"price_full": 0,
"price_child": 0,
"price_baggage": 0,
"price_insurance": 0,
"bus_info": null,
"number": null,
"travel_time": 60,
"travel_time_human": " 1 ч. ",
"carrier": "Лаврусик В.И",
"schedule": "Вс",
"platform": null,
"without_pd": false,
"without_select_places": false,
"status": null,
"sale_status": null,
"available_for_sale": false,
"station_for_sale": null,
"commission": 1
},
"cheapest_trip": {
"start": "05:55:00",
"point_a": 7470,
"trip_id": "3362",
"route": "Старый Оскол -Воронеж 3979",
"concreate": false,
"end": "07:55:00",
"point_b": 7317,
"free_place": null,
"distance": 121,
"free_places": null,
"price_full": 250,
"price_child": 0,
"price_baggage": 0,
"price_insurance": 0,
"bus_info": null,
"number": null,
"travel_time": 120,
"travel_time_human": " 2 ч. ",
"carrier": "Сафонов Е.Н.",
"schedule": "Пт",
"platform": null,
"without_pd": false,
"without_select_places": false,
"status": null,
"sale_status": null,
"available_for_sale": false,
"station_for_sale": null,
"commission": 1
},
"avg_travel_time": " 1 ч. 56 мин. ",
"avg_distance": 122,
"avg_price": 355.806451612903,
"min_price": 275
}
}
http request
GET /app/trips/?dispatch_id=mikhailov&arrival_id=voronezh&trip_date=16.10.2023
json
{
"trips": [
{
"point_a": 7470,
"start": "2023-10-19T05:35:00+03:00",
"trip_id": "1250357",
"route": "Старый Оскол-Белгород 515",
"concreate": true,
"end": "2023-10-19T07:55:00+03:00",
"point_b": 7292,
"free_place": 8,
"distance": 148,
"free_places": [
2,
3,
4,
6,
7,
8,
9,
10
],
"price_full": 345,
"price_child": 172,
"price_baggage": 34,
"price_insurance": 0,
"bus_info": "Mercedes 0303 (17+0багаж)",
"number": "515",
"travel_time": 140,
"travel_time_human": " 2 ч. 20 мин. ",
"carrier": "Гриднев Е.Е.",
"schedule": "Пн, Вт, Ср, Чт, Пт",
"platform": "2",
"without_pd": true,
"without_select_places": false,
"status": null,
"sale_status": null,
"available_for_sale": false,
"commission": 1
}
],
"fastest_trip": {
"point_a": 7470,
"start": "2023-10-19T15:20:00+03:00",
"trip_id": "1249945",
"route": "Воронеж АВ — Белгород АВ 2199",
"concreate": true,
"end": "2023-10-19T17:15:00+03:00",
"point_b": 7292,
"free_place": 3,
"distance": 280,
"free_places": [
15,
18,
19
],
"price_full": 350,
"price_child": 175,
"price_baggage": 35,
"price_insurance": 0,
"bus_info": "FOXBUS (31)",
"number": "2199",
"travel_time": 115,
"travel_time_human": " 1 ч. 55 мин. ",
"carrier": "Федотова Е.П.",
"schedule": "Ежедневно",
"platform": "0",
"without_pd": true,
"without_select_places": true,
"status": null,
"sale_status": null,
"available_for_sale": false,
"commission": 1
},
"cheapest_trip": {
"point_a": 7470,
"start": "2023-10-19T14:28:00+03:00",
"trip_id": "1249998",
"route": "Воронеж АВ — Белгород АВ 565",
"concreate": true,
"end": "2023-10-19T16:30:00+03:00",
"point_b": 7292,
"free_place": 7,
"distance": 280,
"free_places": [
1,
2,
3,
4,
5,
6,
7
],
"price_full": 278.5,
"price_child": 139,
"price_baggage": 27,
"price_insurance": 0,
"bus_info": "Setra 315HD(2) (57)",
"number": "565",
"travel_time": 122,
"travel_time_human": " 2 ч. 2 мин. ",
"carrier": "Капустин Ю.В.",
"schedule": "Ежедневно",
"platform": "0",
"without_pd": true,
"without_select_places": true,
"status": null,
"sale_status": null,
"available_for_sale": false,
"commission": 1
},
"avg_travel_time": " 2 ч. 15 мин. ",
"avg_distance": 171,
"avg_price": 398.3333333333333,
"min_price": 307
}
```http request POST /app/cart/add-to-cart/
{ // Полный объект рейса "point_a": 7470, "start": "2023-10-26T09:15:00+03:00", "trip_id": "1255954", "route": "Старый Оскол -Воронеж 2325", "concreate": true, "end": "2023-10-26T11:10:00+03:00", "point_b": 7317, "free_place": 19, "distance": 120, "free_places": [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ], "price_full": 200, "price_child": 100, "price_baggage": 60, "price_insurance": 0, "bus_info": "Iveco (20)", "number": "2325", "travel_time": 115, "travel_time_human": " 1 ч. 55 мин. ", "carrier": "Исайкин Д. А.", "schedule": "Чт, Пт", "platform": "3", "without_pd": false, "without_select_places": false, "status": null, "sale_status": null, "available_for_sale": false, "commission": 1 } ```
В ответ - полный объект корзины
```http request DELETE /app/cart/remove-from-cart/
{ "cart_item_id" : 123213 } ```
http request
GET /app/cart/current/
Ответ
json
{
"uuid": "08fa8bef-f9c2-426d-8726-b7c3a5f942ff",
"cart_items": [
{
"id": 47531,
"trip": {
"id": 47544,
"tickets": [
{
"id": 54002,
"external_id": null,
"created_at": "2023-10-17T19:01:04.374829+03:00",
"updated_at": "2023-10-17T19:01:04.374829+03:00",
"title": "Билет по маршруту Короча АС -Москва \" Саларьево\" АВ 5842 на дату 20.10.2023 09:00",
"is_active": true,
"date": null,
"date_reserve": null,
"ticket_number": null,
"place_number": "14",
"is_stand": false,
"is_child": false,
"barcode": null,
"is_return": false,
"commission_value": "0.00",
"status": 1,
"price": "440.00",
"price_base": "0.00",
"price_baggage": "0.00",
"price_baggage_base": "0.00",
"sum_baggage": "0.00",
"sum_baggage_base": "0.00",
"count_baggage": 0,
"external_id_baggage": [],
"sum_all": "0.00",
"sum_insurance": "0.00",
"uuid": "31dd8a00-9460-45a9-9530-5051fd8c943e",
"company": 12,
"passenger": null
}
],
"point_a": "Старый Оскол АВ",
"point_b": "Воронеж Юго-Западная АС",
"external_id": "1250916",
"created_at": "2023-10-17T19:01:04.350885+03:00",
"updated_at": "2023-10-17T19:01:04.350885+03:00",
"title": "Короча АС -Москва \" Саларьево\" АВ 5842 на дату 20.10.2023 09:00",
"is_active": true,
"trip_id": "1250916",
"price_full": "440.00",
"price_full_base": "400.00",
"price_child": "165.00",
"price_child_base": "150.00",
"price_baggage": "33.00",
"price_baggage_base": "30.00",
"price_insurance": "0.00",
"start": "2023-10-20T09:00:00+03:00",
"end": "2023-10-20T10:40:00+03:00",
"route": "Короча АС -Москва \" Саларьево\" АВ 5842",
"platform": null,
"free_place": 10,
"free_place_baggage": "0",
"free_places": [
"14",
"17",
"21",
"22",
"23",
"24",
"27",
"28",
"31",
"32"
],
"travel_time": 100,
"without_select_places": false,
"carrier": "Аведян А. А.",
"commission": 1
},
"count": 0,
"price": "0.00",
"sum_all": "0.00"
}
]
}
Пояснения по полям:
Вычисление суммовых показателей заказа (общая сумма, кол-во пассажирских, детских и багажных) реализовать на клиенте (из информации о поездке).
Отправить только идентификатор позиции корзины
```http request POST /app/cart/add-ticket/
{ "cart_item_id" : 123123 } ```
В случае успеха, в ответ - полный объект корзины
```http request POST /app/cart/remove_ticket/
{ "cart_id" : 123123, "ticket_id" : 123123 } ```
В случае успеха, в ответ - полный объект корзины.
```http request POST /app/order/
{
"buyer_emai" : 123123,
"buyer_phone" : 123123,
"items": {
"
При успешно оформлении - полный объект заказа и ссылка на оплату