API формы бронирования индивидуального тура


СОДЕРЖАНИЕ
  1. Описание
  2.   Теория туров
  3.   Ресурсы
  4.   Билеты
  5. API
  6.   API просчета тура
  7.   API сохранения тура
  8.   API бронирования тура и получения документов

Описание

Форма бронирования является тонким клиентом к SaaS web-сервису tourservice.net. Формат взаимодействия клиента с сервером приложений - Ajax, формат данных - JSON. В большинстве случаев нет разницы - использовать POST или GET. Имейте ввиду, что при передаче GET-параметров есть ограничения браузера и сервера приложений на длину URL (5000 символов для сервера приложений).

Теория туров
Тур, потребляемый туристом, состоит из разнородной информации:

В свою очередь, тур является частным случаем использования турпакета. Турпакет - это комплекс информации о возможных реальных турах, созданный туроператором в рамках подготовки к сезону продаж туров. Турпакет в свою очередь состоит из:

Ресурсы
Каждый продукт, потребленный туристами во время потребления тура, имеет свой ресурс и этот ресурс конечен (ограниченное количество мест в трансфере или самолете, ограниченное количество номеров нужного типа в отеле, ограниченное количество гидов-экскурсоводов и тп). Обладатель ресурса (им может быть как сам туроператор, так и реальный владелец - отельер, авиа- или авто-перевозчик) стремится использовать ресурс максимально, без простоя. Из этого стремления проистекает требование к программному обеспечению в планировании отсутствия простоев ресурса - отсутствие незанятых дней в "сетке" номеров отеля в сезон, отсутствие незанятых одиночных мест в трансфере или запрет нескольких полупустых автобусов (уплотнение). Следует отметить, что, в свою очередь, других участников процесса продажи, не являющихся обладателями ресурса, а лишь продающих его как посредники, это стремление не касается и они при отсутствии контроля со стороны обладателя могут тратить эти ресурсы как заблагорассудится, допуская простои.

Таким образом, если процесс продаж грамотно построен и приносит максимальный доход из-за отсутствия простоев, можно разделить степень ответственности, возлагаемой на разных участников процесса в формировании объема потребления ресурсов и одновременно с этим степень управляемости этими ресурсами. Чем ниже степень ответственности, тем ниже степень управляемости. На деле это выливается в недоступность точной информации о наличии ресурсов для тех участников, которые не являются обладателями ресурсов. Это не является необходимым требованием, но проистекает из ситуации, когда все управление ресурсами сконцентрировано в одних руках (обладателя).

Часто возникает ситуация, когда непосредственный владелец не в силах по разным причинам управлять степенью заполняемости ресурсов и готов за определенную плату делегировать эту задачу на следующего в цепочке участника процесса продаж (чаще всего им будет туроператор). Это несет в себе прибыль и одновременно нагрузку для туроператора и меняет его отношение к делегированным ресурсам. В конкретных действиях это выглядит так: туроператор с владельцем ресурса договариваются об объеме делегируемых ресурсов, туроператор оплачивает этот объем владельцу по сниженной цене (разница между этой ценой и рыночной является оплатой владельца за делегирование нагрузки) и с этой минуты туроператор начинает себя вести как владелец этого ресурса - пытается исключить простои и концентрирует доступ к управлению ресурсом в своих руках.

Таким образом, для одного и того же участника ресурс может быть как чужим, так и своим, причем даже в рамках одного типа ресурсов - например, определенный набор номеров в одном отеле на определенный срок может быть ему делегирован, а все остальные - нет. Называться при этом делегированный набор ресурсов будет жестким блоком, остальные ресурсы - мягким блоком. Название проистекает из неопределенности доступности ресурса - в случае мягкого блока туроператор не знает - свободен ресурс или нет, пока не обратится к владельцу, в случае же жесткого блока - он сам является распределителем ресурса и может выдать мгновенный точный ответ о наличии или отсутствии ресурса. Полноценное онлайн-бронирование подразумевает продажу ресурсов с исключительно жестким блоком мест, так задержка подтверждения брони отсутствует и отложенный отказ не предполагается. Это условие не всегда возможно выполнить, так как обладание жесткими блоками означает связывание больших денежных ресурсов (заблаговременная оплата всего блока до начала продаж).

Билеты
Билеты в бронировании являются метками, связывающими конкретный тур с конкретным ресурсом. Билеты используются для любого продукта - будь то отель, трансфер, авиаперелет, питание или экскурсия. Билеты могут потреблять ресурс или нет. Но нужно, чтобы хотя бы один билет в туре потреблял этот ресурс. Пример: Вместе с молодой мамой в самолете летит годовалый младенец у нее на руках. Он не потребляет отдельное кресло, но для него нужен билет, иначе с ним не пропустят в салон. Другой пример: в случае продажи номера отеля тратится всего один ресурс - номер отеля. В то же время в нем живет несколько человек, и их имена вписаны в ваучер, можно сказать - они все потребляют один номер, но у каждого свой билет (дискретность привязки туриста к ресурсу). Привязка туриста к номеру обязательна еще и в других случаях - если проданы два номера в рамках одного тура, то для некоторых стран незамужние мужчина и женщина до определенного возраста не могут быть поселены в один из этих номеров - именная билетная привязка к ресурсу обязательна.

В случае мягкого блока нет точной привязки тура к физическому ресурсу, потому что мягкий ресурс абстрактен, его реальный номерной фонд неизвестен. Например, в случае мягкого блока отеля точный набор доступных номеров не имеет смысла заранее хранить в базе продавца, важно лишь знать о возможных типах номеров, чтобы выставлять точную цену. Конкретный же свободный ресурс (номер комнаты) сообщит владелец ресурса в момент подтверждения брони. Поэтому мягкий блок позволяет не хранить конкретные номера комнат отеля в базе продавца мягкого блока, поскольку нет смысла отслеживать степень их занятости. Все равно неизвестно, проданы ли эти ресурсы кому-то еще или не могут быть отданы вам, чтобы избежать незанятых "дырок" по времени, простоев без дохода.

Билеты могут иметь статусы, которые отражают состояние брони ресурса в туре. Если бронируется мягкий блок, саму попытку бронирования надо отметить созданием билетов, но задать им неподтвержденный статус (ожидание подтверждения брони). Они имеют минимальную ценность в этом состоянии. После этого они могут быть либо уничтожены (бронь не подтверждена, ресурс недоступен), либо переведены в статус подтвержденных - здесь они приобретают вес. В этом случае турист может отказаться от них без обязательной оплаты (если это допустимо правилами хозяина ресурса) или понести штрафы. Турагент в случае штрафов является поручителем туриста и если он не удосужился заранее взять деньги с туриста, будет расплачиваться своими средствами за штрафы при отмене брони. При реальной оплате ресурса билеты переводятся в статус оплаченных и имеют наивысший приоритет. Поясняющий пример: забронированные билеты в трансфере без оплаты могут быть отменены за несколько дней до отъезда, если их покупателем является турист, а не агент (который, напомним, является поручителем туриста).


API

Сервер приложений требует избирательной аутентификации со стороны клиентского интерфейса кукисами, предполагает со стороны клиента агрессивную среду. Работа интерфейса бронирования с сервером приложений может быть разбита на несколько основных этапов:
  1. Подбор пакетов, их продуктов и ресурсов и просчет цены тура. Этап REST-совместим (не хранит состояние между запросами). Не требует аутентификации (если иное не настроено конкретным туроператором).
  2. Оформление заявки на тур и ее сохранение. Этап REST-несовместим - выполняется изменение серверной части и хранение результатов между запросами. Требует аутентификации.
  3. Бронирование заявки и распечатка документов. Этап REST-несовместим. Требует аутентификации.
  4. Оплата заявки. Этап REST-несовместим.

API просчета тура
1. Сначала получаем список доступных турпакетов (и их базовых параметров), выставленных на просчет тура:

POST http://hostname.tourservice.net/Voucher/partner/packets/0/get/param/
POST-параметры:
area=packet
is_ajax=1
params=a_locations
params=a_currency
params=a_sale2agents
params=a_start_town
params=a_stoptime
params=a_selected_location
params=a_hide4agents
selectid=58
Пояснения: здесь идет перечень запрашиваемых параметров турпакетов, привязанных к конкретной форме онлайн-бронирования (Индивидуальный тур), на данном хосте имеющей ID=58. У каждого туроператора она может иметь свой ID.
Возвращаемые данные:
{
"variants":[{
	"a_currency":"KZT",
	"a_locations":"[\"Киргизия\",\"база Каракол\",\"Бишкек\",\"Каракол\"]",
	"a_sale2agents":1,
	"a_start_town":"Алматы",
	"a_hide4agents":1,
	"pid":11
},{
	"a_currency":"KZT",
	"a_locations":"[\"Казахстан\",\"Акши\",\"Коктума\"]",
	"a_sale2agents":0,
	"a_start_town":"Алматы",
	"pid":31
}],
"packets":{
	11: { name="ГОРНОЛЫЖНЫЙ СЕЗОН В КИРГИЗИИ", desc="горнолыжные базы, выезды по выходным. Включен трансфер, подъем на гору, проживание."},
	31: { name="Алаколь 2014", desc=""}}
}
Описание ключей:
variants
a_currency Валюта турпакета
a_locations STRING для повторного парсинга JSON с перечнем локаций турпакета. Первый элемент - страна, остальные элементы - курорты (города) в ней, в которых находятся ресурсы турпакета.
a_sale2agents 1 - можно отображать кнопку продажи тура, 0 - нет, только для ознакомления (в начале сезона есть период, когда продажи еще не стартовали и доступны лишь предварительные цены, либо в силу каких-то обстоятельств возможна продажа лишь при бронировании по телефону)
a_hide4agents 1 - игнорировать пакет (только для внутреннего пользования), 0 или отсутствует ключ - пакет доступен для работы
a_start_town Город выезда (начала тура)
pid ID пакета
packets
name Название пакета
desc Необязательное описание пакета


2. Также (параллельно) делаем запрос параметров индивидуального просчета турпакетов, выставленных на просчет тура:
POST http://hostname.tourservice.net/Voucher/partner/packets/0/get/param/
POST-параметры:
area=options
is_ajax=1
params=t_program
params=t_min_days
params=t_max_days
params=t_bind_tours
params=t_hotel_late_entry
params=t_allow_change_late_entry
type=itour
Пояснения: здесь идет перечень запрашиваемых параметров индивидуального просчета для всех имеющихся турпакетов.
Возвращаемые данные:
{
"variants":[{
	"293":{
		"pid":11
		"t_program":"[\"Транспорт туда\",1,0,0],[\"Транспорт обратно\",2,0,0],[\"Подъем до горнолыжной базы\",3,0,0],[\"Размещение\",4,1,1]",
		"t_max_days":12
		"t_min_days":3
	}
},{
	"352":{
		"t_program":"[\"Размещение\",0,1,1,0,0],[\"Питание\",0,0,0,0,0]",
		"pid":31
	}
}],
"packets":{
	11: { name="ГОРНОЛЫЖНЫЙ СЕЗОН В КИРГИЗИИ", desc="горнолыжные базы, выезды по выходным. Включен трансфер, подъем на гору, проживание."},
	31: { name="Алаколь 2014", desc=""}}
}
Описание ключей:
variants
t_program STRING для повторного парсинга JSON с перечнем продуктов в туре. Первый элемент каждого подмассива - название продукта, второй - ID типа продолжительности, третий - позволить выбирать цены (номера в отеле) авторизованным пользователям (не агенту), четвертый - позволить выбирать цены (номера в отеле) агентам или туристам, пятый - показывать себестоимость агентам (редко).
Типы продолжительности продукта в туре:
  1. Весь тур (трансфер в турах выходного дня, в других - отель)
  2. Первый день тура (обычно трансфер или авиа). Продукт этого типа определяет начало тура (используется ниже).
  3. Последний день тура (обычно трансфер или авиа). Продукт этого типа определяет конец тура (используется ниже).
  4. Весь тур без первого и последнего дня.
  5. Весь тур без первого дня (обычно отель, питание).
  6. Весь тур без последнего дня (обычно отель, питание).
  7. Первые 2 (два) дня тура (обычно трансфер в ночь). Продукт этого типа определяет начало тура (используется ниже).
  8. Последние 2 (два) дня тура (обычно трансфер в ночь). Продукт этого типа определяет конец тура (используется ниже).
  9. Даты указываются покупателем.
t_min_days Число минимального количества дней в туре. Необязательное. Если есть, не позволять в календаре выбирать дату конца тура меньше, чем за указанное количество дней от начала тура.
t_min_days Число максимального количества дней в туре. Необязательное. Если есть, не позволять в календаре выбирать дату конца тура больше, чем за указанное количество дней от начала тура. Если указано и равно 0, подставлять автоматически дату конца тура тем же днем, что и дату начала тура (туры выходного дня).
pid ID пакета
packets
name Название пакета
desc Необязательное описание пакета


3. После разбора данных формируем список доступных пакетов и даем пользователю выбор, либо определяем тур автоматически
4. Получив в п.3 PID (активный Packet ID), делаем запрос перечня точек доставки (отелей) в рамках этого тура для построения списка:
POST http://hostname.tourservice.net/Voucher/partner/dictionaries/get/hotels
POST-параметры: country=Казахстан
distinct=1
is_ajax=1
output=array
sortby=name
town=Акши
town=Коктума
what=name
what=town
what=country
what=class
what=policies
Пояснения: здесь идет указание страны (необязательно), перечень городов (Акши и Коктума), которые получены ранее для каждого турпакета и перечень полей из справочника, которые нужно получить. Ключ output=array говорит о том, что данные должны быть минимизированы по объему и каждая найденная строка должна быть массивом найденных значений, а не хешем с ключами и найденными значениями. Ключ sortby=name заставляет возвращать список отсортированным по именам отелей (например, можно по их классу и тп).
Возвращаемые данные:
{
"variants":[
	["Alateniz HV","Акши","Казахстан","5","genfrom:1;per_baseclient:1"],
	["Алаколь","Акши","Казахстан","2",""],
	["Аласу","Акши","Казахстан","2","genfrom:1;nosale"],
	["Асуан","Коктума","Казахстан","2",""],
	["Варадеро","Акши","Казахстан","2","genfrom:1"],
	["Варадеро","Акши","Казахстан","2",""],
	["Грин Хаус","Акши","Казахстан","2",""],
	["Зодиак","Коктума","Казахстан","2","genfrom:1"],
	["Коктума","Коктума","Казахстан","2",""],
	["Пеликан","Акши","Казахстан","2","genfrom:1"],
	["Черный Камень","Акши","Казахстан","2","genfrom:1"]
],
"dictname":"hotels"
}
Здесь возвращен массив подмассивов перечня отелей для запрошенных курортов. Порядок и количество полей соответствует порядку и количеству запрошенных полей справочника в массиве what в запросе. Внимание: если в поле policy присутствует слово "nosale", нельзя предлагать продукт отеля к продаже, если он присуствует в перечне продуктов (это только точка доставки, как вокзал или таможня).

5. Также (параллельно) делаем запрос перечня продуктов в туре:
POST http://develop.tourservice.net/Voucher/partner/packets/31/get/param/
POST-параметры:
area=products
is_ajax=1
params=offertype
params=p_name
params=p_resourcedictid
params=p_cancellable_right
params=p_dictid
params=p_pricedictid
params=p_provider
params=p_skip_nonexistent
params=p_block_nonexistent
params=p_cost_mode
params=p_maxinfantage
Пояснения: здесь идет перечень запрашиваемых параметров продуктов из выбранного турпакета (31).
Возвращаемые данные:
{
"variants":[
	{
		"92":
		{
			"pid":"31",
			"p_cost_mode":"night",
			"p_dictid":"9",
			"p_resourcedictid":"0",
			"p_name":"Размещение",
			"offertype":"location",
			"p_pricedictid":"13",
			"p_cancellable_right":"ManageTickets"
		},
		"90":
		{
			"pid":"31",
			"p_cost_mode":"client",
			"p_dictid":"97",
			"p_resourcedictid":"50",
			"p_name":"Транспорт туда",
			"offertype":"transfer_to",
			"p_pricedictid":"121"
		},
		"91":
		{
			"pid":"31",
			"p_cost_mode":"client",
			"p_dictid":"97",
			"p_resourcedictid":"50",
			"p_name":"Транспорт обратно",
			"offertype":"transfer_from",
			"p_pricedictid":"121"
		}
	}
],"packets":{
	31: { name="Алаколь 2014", desc=""}}
}
Описание ключей: Каждый продукт имеет свой ID, в возвращенной структуре данных этот ID является ключом в первом и единственном хеше-элементе массива variants. Значение этого ключа - перечень запрошенных параметров продукта.
variants
p_cost_mode Тип цены. Именно на форме бронирования используется лишь при отображении сетки номеров в отеле. На стороне сервера приложений используется как определяющий параметр для подсчета цены тура.
Типы цен:
  • day - Цена указана за день (умножается на количество дней, которые занимает продукт в туре). Типичный пример - питание.
  • night - Цена указана за ночь (умножается на количество ночей, которые занимает продукт в туре). Типичный пример - отель.
  • client - Цена указана за клиента в группе (умножается на кол-во туристов. Типичный пример - транспорт.
  • tour - Цена берется один раз за тур, без разницы от количества дней, ночей или туристов. Типичный пример - гид-экскурсовод.
  • client*day - Цена умножается на количество дней и количество туристов. Типичный пример - страховой полис.
  • client*night - Цена умножается на количество ночей и количество туристов. Типичный пример - отель, где цена номера указана за человека.
p_dictid Номер информационного справочника для этого продукта. Содержит базовую информацию об услуге (продукте) в туре. На форме бронирования не используется. На стороне сервера приложений используется для заполнения полей заявки нужными данными.
p_resourcedictid Номер справочника ресурсов для этого продукта. Содержит перечень ресурсов для каждого продукта. Широко используется на форме бронирования - от построения перечня дат выезда-приезда до построения списка автобусов в трансфере и сетки номеров в отеле. Ресурсы являются определяющими для возможности совершения тура и набора характеристик тура. Не все продукты обладают ресурсными справочниками (в этом случае их номер будет равен 0 или ключ будет отсутствовать вообще), в этом случае продукты считаются не требующими учета ресурсов (например, питание в отеле или экскурсии).
p_pricedictid Номер справочника цен для этого продукта. На форме бронирования не употребляется. На стороне сервера приложений является главным источником ценообразования.
p_name Название продукта. Уникально для каждого турпакета и может не совпадать с предполагаемым названием услуги с тем же типом. Например, в турах выходного дня продукт трансфера может называться "Автобус в обе стороны", в другом туре - "Трансфер туда".
offertype Определяющий политику работы с продуктом тип услуги. Перечень доступных типов услуг и их пользовательское название:
  • flight - Авиаперелет туда.
  • flight_from - Авиаперелет обратно.
  • transfer_to - Транспорт туда
  • transfer_from - Транспорт обратно
  • location - Размещение
  • insurance - Страхование
  • excursion - Экскурсии
  • extra_service - Дополнительные услуги. Обычно используются для питания, подъема на гору и проч.
p_cancellable_right Право отмены выбора продукта. Если оно есть, туристу/агенту должно быть запрещено действие отказа от продукта в составе этого тура.
pid ID пакета
packets
name Название пакета
desc Необязательное описание пакета


6. Затем получаем список ресурсов для продуктов, чей тип продолжительности в туре равен 1,2,6 или 7 (определяют даты поездки):
GET http://hostname.tourservice.net/Voucher/partner/dictionaries/get/50?is_ajax=1&output=array&pid=34&what=orgname&what=provider&what=date_from&distinct=1
GET-параметры:
is_ajax=1
output=array
pid=90
what=orgname
what=provider
what=date_from
distinct=1
Пояснения: Этих запросов будет, скорее всего, два (для продукта, определяющего начало тура и для продукта, определяющего конец тура. Если есть только продукт, определяющий начало тура, скорее всего это используется для туров выходного дня и тогда должно быть ограничение длительности максимум 0 дней (см выше). Здесь ключ pid означает ID продукта (не турпакета), из перечня продуктов в туре. Запрашиваемые поля orgname и provider - синонимы и употребляются в справочниках на разных уровнях, обычно один из них пуст (null).
Возвращаемые данные:
{
"variants":[
	["Азимут Трэвел",null,"2014-06-05"],
	["Азимут Трэвел",null,"2014-06-12"],
	["Азимут Трэвел",null,"2014-06-15"],
	["Азимут Трэвел",null,"2014-06-19"],
	["Азимут Трэвел",null,"2014-06-22"],
	["Азимут Трэвел",null,"2014-06-24"],
	["Азимут Трэвел",null,"2014-06-26"],
	["Азимут Трэвел",null,"2014-06-30"],
	["Азимут Трэвел",null,"2014-07-02"],
	...
],"dictname":"int_transfer_res"
}
На основании полученных данных строится выпадающий список дат тура. В зависимости от совпадения по одному из полей orgname и provider (которое заполнено), идет дополнительная фильтрация дат возвращения, полученных из второго запроса (запроса ресурсов продукта, определяющего конец тура): нужно отфильтровывать те записи, чьи поля содержат иную информацию. Делать это нужно для того, чтобы туристы туда и обратно доставлялись одним поставщиком услуг. Иное допускается только при применении специальных ключей и здесь не описано. Игнорирование этого пункта чревато накладками в отдельных ситуациях.
Внимание: если ни один из продуктов, определяющих дату начала и конца тура, не имеет справочника ресурсов - нужно выдавать календарь дат с полем заполнения, а не выпадающий список дат. При этом подразумевается, что воспользоваться туром можно на любой период. Такое возможно в период сезона для туроператоров, продающих только отели.

7. После этого строится интерфейс календаря, турист определяется с датами, количеством людей в группе, их возрастом, и с точкой доставки/отелем.
8. Турист начинает рассаживать группу (тратить ресурсы) автобусов на даты, отелей на даты. Он последовательно выбирает все требующие внимания продукты (если указан справочник ресурса или указана возможность выбора цены для этого типа посетителя. Должна быть запускающая выбор функция в виде кнопки или иного элемента. После запуска выбора идет запрос наличия ресурсов на нужные даты и их отображение. Если выбранный продукт имеет тип продолжительности, определяющий, что он находится в начале тура, тогда для запроса ресурса этого продукта используется выбранная дата начала тура, соответственно выбирается ресурс для продукта в конце тура:
POST http://hostname.tourservice.net/Voucher/partner/dictionaries/get/50
POST-параметры:
date_from=2014-06-05
date_to=2014-06-05
is_ajax=1
pid=34
what=rowid
what=available
what=floatable
what=reserved
what=saled
what=number
what=placescheme
what=block_start
what=block_end
Пояснения: Объем возвращаемых данных обычно невелик, количество строк в ключе variants равен количеству ресурсов, в данном случае количеству автобусов на эту дату, поэтому дополнительная экономия в виде вывода в массиве неактуальна. Здесь запрашиваются подробные параметры ресурса для построения графической схемы для рассадки группы.
Возвращаемые данные:
{
"variants":[
	{
		"placescheme":"",
		"number":"1",
		"block_start":"1",
		"floatable":"0",
		"rowid":"1939",
		"saled":"2",
		"dictid":"50",
		"block_end":"4",
		"reserved":"0",
		"available":"48"
	},{
		"placescheme":"mersedes",
		"number":"2",
		"block_start":"1",
		"floatable":"0",
		"rowid":"2131",
		"saled":"4",
		"dictid":"50",
		"block_end":"4",
		"reserved":"16",
		"available":"51"
	}
],
"dictname":"int_transfer_res"
}
Описание ключей:
variants
available Количество мест жесткого блока ресурса (в данном случае - количество мест в автобусе).
floatable Количество мест жесткого блока ресурса (в случае автобусов не используется и равно 0).
placescheme Класс отображения, содержащий CSS-параметры прорисовки ресурса, также используется в javascript-коде для выдачи нужной последовательности мест. Нужен для точности отображения мест в реальном автобусе (двухэтажный, короткий и тп). Это поле также позволяет иметь разные схемы рассадки для автобусов с одинаковым количеством мест. CSS-схема доступна в файле http://hostname.tourservice.net/styles/voucher.css по совпадающему имени селектора.
number Номер ресурса (автобуса) для различения между собой в этот день. Часто на автобусах крепят соответствующие номера.
reserved Количество ранее забронированных мест в этом автобусе/ресурсе.
saled Количество ранее забронированных и оплаченных мест в этом автобусе/ресурсе.
block_start Стартовый номер блока мест, запрещенного агентом к продаже (места гидов, запасных водителей и тп)
block_end Конечный номер блока мест, запрещенного агентом к продаже (места гидов, запасных водителей и тп)
rowid ID ресурса. Требуется для запоминания выбранного ресурса.


Вычисление реального количества мест производится следующим образом: от суммы полей available и floatable отнимается сумма полей reserved и saled. Если оставшееся количество мест меньше, чем число людей в группе туристов, группа не может быть размещена в этом ресурсе. Не допускается частичное размещение группы по нескольким ресурсам. В таком случае турист выбирает следующий ресурс и размещает группу в нем. Туроператор обязан следить за наполняемостью ресурсов через отчеты и своевременно добавлять ресурсы на те даты, где осталось мало мест, чтобы избежать отказов бронирования.
Кроме css-стиля для отображения ресурса используется также javascript-код, возвращающий массив мест для того или иного ресурса (принимается во внимание количество мест ресурса (available и его необязательное название схемы placescheme). На данный момент этот код присутствует лишь в составе страницы оригинального модуля онлайн-бронирования и позже по запросу может быть реализован отдельным запросом.

9. Получение перечня занятых мест в выбранном ресурсе:
GET http://hostname.tourservice.net/Voucher/partner/packets/31/get/helper/?is_ajax=1&function=TicketsPlaces&rowid=1939&dictid=50
GET-параметры:
is_ajax=1
function=TicketsPlaces
rowid=1939
dictid=50
Пояснения: Запрашивается на выполнение функция TicketsPlaces, возвращающая список билетов на выбранный ресурс (1939). Для гостя и агента не будет возвращен список фио туристов, номеров заявок и статус их оплаты - только занятые и свободные места.
Возвращаемые данные:
{
	"variants":[
		{"ticket":"7"},
		{"ticket":"8"},
		{"ticket":"5"},
		{"ticket":"6"},
		{"ticket":"9"},
		{"ticket":"12"},
		{"ticket":"11"},
		...
	]
}
Перечень занятых мест нужно графически отобразить на схеме ресурса/автобуса и предотвратить повторный их выбор туристом, так как при попытке забронировать заявку с местами, которые уже заняты в других заявках, заявка на тур будет испорчена.

10. После рассадки группы по местам ресурса (в этом документе не освещена задача выбора отельных ресурсов, как неактуальная на данный момент и ресурсоемкая), остается две задачи - просчет цены и оформление заявки. Для подачи запроса на просчет нужно сформировать cookie, содержащий кодированную через функцию javascript escape() структуру данных JSON-формата и сделать Ajax-вызов функции сервера приложений. Это формат продиктован особенностями построения оригинальной клиентской части. Пример cookie:


query=%7B%2234%22:%7B%22selected%22:1,%22rowid%22:%221938%22,%22tickets%22:%5B24,23%5D,%22provider%22:%22%D0%90%D0%B7%D0%B8%D0%BC%D1%83%D1%82%20%D0%A2%D1%80%D1%8D%D0%B2%D0%B5%D0%BB%22%7D,%2235%22:%7B%22selected%22:1,%22rowid%22:%222008%22,%22tickets%22:%5B22,21%5D,%22provider%22:%22%D0%90%D0%B7%D0%B8%D0%BC%D1%83%D1%82%20%D0%A2%D1%80%D1%8D%D0%B2%D0%B5%D0%BB%22%7D,%2236%22:%7B%22selected%22:0,%22roomname%22:0,%22roomid%22:0,%22tickets%22:%5B%5D,%22bindrid%22:0%7D,%22query%22:%7B%22country%22:%22%D0%9A%D0%B0%D0%B7%D0%B0%D1%85%D1%81%D1%82%D0%B0%D0%BD%22,%22town%22:%22%D0%90%D0%BA%D1%88%D0%B8%22,%22hotel%22:%22%D0%90%D0%BB%D0%B0%D1%81%D1%83%22,%22date_from%22:%222014-06-05%22,%22date_to%22:%222014-06-19%22,%22packetid%22:%2214%22,%22adults%22:%222%22,%22pensioners%22:%220%22,%22childs%22:%220%22,%22childs_ages%22:%22%22,%22infants%22:%220%22,%22start_town%22:%22%D0%90%D0%BB%D0%BC%D0%B0%D1%82%D1%8B%22%7D%7D; path=/
Декодированный пример:
{
	"query":{
		"country":"Казахстан",
		"town":"Акши",
		"hotel":"Аласу",
		"date_from":"2014-06-05",
		"date_to":"2014-06-19",
		"packetid":"31",
		"adults":"1",
		"pensioners":"1",
		"childs":"2",
		"childs_ages":"5,8",
		"infants":"0",
		"start_town":"Алматы"
	},
	"90":{
		"selected":1,
		"rowid":"1939",
		"tickets":[24,23,24],
		"provider":"Азимут Трэвел"
	},
	"91":{
		"selected":1,
		"rowid":"2008",
		"tickets":[22,21,20],
		"provider":"Азимут Трэвел"
	},
	"92":{
		"selected":0,
		"roomname":0,
		"roomid":0,
		"tickets":[],
		"bindrid":0
	}
}
Описание ключей и их значений:
query
country Выбранная страна
town Выбранный город (курорт). Должен выбираться интерфейсом бронирования автоматически при выборе точки доставки/отеля (см. запрос перечня точек доставки (отелей))
hotel Отель (точка доставки), выбранный туристом.
date_from Дата в формате ISO (YYYY-MM-DD), выбранная в качестве начала тура. Если у продукта, определяющего начало тура, есть справочник ресурсов, обязан быть ресурс на эту дату.
date_to Дата в формате ISO (YYYY-MM-DD), выбранная в качестве конца тура. Если у продукта, определяющего конец тура, есть справочник ресурсов, обязан быть ресурс на эту дату.
packetid ID турпакета.
adults Количество взрослых (включая пенсионеров!)
pensioners Количество пенсионеров из числа взрослых.
childs Число детей
childs_ages Перечень возрастов детей через запятую. Число возрастов должно соответствовать числу детей, иначе созданная позже заявка не забронируется. Если с туристом взрослого возраста будут младенцы, не требующие места, они указываются в ключе infants.
infants Число младенцев, не требующих места (обычно дети до двух лет, но это может быть переопределено настройками хоста или конкретного продукта (механизм может быть описан в этом документе позже)).
start_town Стартовый город, выбранный туристом.
90 (ID продукта)
selected Булевый ключ, определяющий - выбрал турист этот продукт к использованию или нет. Не может быть равно нулю, если продукт обязателен.
rowid ID выбранного к употреблению ресурса в этом продукте
tickets Массив номеров мест, выбранный туристом. Количество элементов должно быть равно количеству взрослых плюс количество детей (но не младенцев)
provider Владелец ресурса, полученный со списком ресурсов - для этого ресурса.

Из этого примера можно понять, что тур будет использовать пенсионер с двумя детьми - 5 и 8 лет.

После формирования кукиса нужно сделать запрос просчета цены пакета и вывести ее туристу для ознакомления.
POST http://hostname.tourservice.net/Voucher/partner/packets/31/get/helper/
POST-параметры:
do=CalcCookie
function=run_package
is_ajax=1
package=ts_sale
Пояснения: в адресе указывается ID турпакета. Возвращаемый ответ:
{
	"price":14000
}
Приведенная сумма указана в валюте турпакета. После того, как турист увидел сумму и согласен продолжать, можно перейти на этап оформления заявки на тур.

API сохранения тура

Для сохранения заявки на тур на стороне сервера приложений нужно сделать авторизованный запрос для получения данных, требуемых к сохранению в качестве параметров заявки (подавляющая их часть уже сформирована на стороне сервера). Авторизация агента состоит в получении кукиса после отправки POST-формы авторизации и прикреплении этого кукиса в дальнейшем ко всем запросам к серверу приложений.

1. Авторизуемся агентом, отправляем запрос (обязателен POST):
POST http://host.tourservice.net/Voucher/partner/auth
POST-параметры:
agentlogin=LOGIN
agentpass=PASSWORD
submit=OK
Значение LOGIN и PASSWORD вы получите у туроператора после регистрации личного кабинета на их сайте. В ответе сервера будет содержаться авторизационный cookie с именем tsagent.

2. Делаем запрос на получение блока данных для создания формы заявки (обязателен POST):
POST http://hostname.tourservice.net/Voucher/partner/packets/31/buy/individual/
POST-параметры:
is_ajax=1
Сюда же должен быть прикреплен cookie из предыдущего запроса (на просчет цены тура). Он является основным источником информации для формирования ответа. Итого в этом запросе должно быть два cookie - tsagent и query. Ответ не будет приведен здесь в силу объемности и неактуальности листинга. Для обработки формы и сохранения заявки нужна POST-форма с большим количеством скрытых и заполненных полей ввода и всего одно поле для ввода со стороны туриста (имя туриста).
Конструкция возвращаемой структуры JSON включает в себя следующие основные блоки: 3. Заполненную форму нужно послать POST-ом на адрес:
http://hostname.tourservice.net/Voucher/partner/queries/2/save
Запрос должен содержать в себе авторизационный cookie tsagent. Цифра 2 в этом адресе индивидуальна для каждого туроператора. Также возможен вариант со скрытием этой промежуточной формы на стороне агента и запрос ФИО туриста сразу же на первой форме бронирования тура. Ответ на запрос будет содержать в себе HTML-код, в котором нас интересует один из тегов. Пример содержимого:

<html><head><title>Перенаправление...</title><META HTTP-EQUIV="refresh" CONTENT="0; URL=/Voucher/partner/queries/16996/view?operation=op_query_created,16996"></head><body style="text-align:center;"><h3>Вы будете перенаправлены на запрошенный адрес</h3><hr>Если перенаправление не сработало, нажмите: <a href="/Voucher/partner/queries/16996/view?operation=op_query_created,16996">/Voucher/partner/queries/16996/view?operation=op_query_created,16996</a></body></html>
Содержимое ключа URL в теге META указывает на адрес просмотра заявки, содержащий в себе ID созданной заявки. Если в процессе сохранения заявки будут найдены ошибки, содержимое ответа будет другим (содержать текст ошибки).

API бронирования тура и получения документов

1. Для бронирования ресурсов в заявке нужно выполнить всего один авторизованный GET-запрос, при условии, что заявка уже была создана на стороне сервера в предыдущей главе:

GET http://hostname.tourservice.net/Voucher/partner/queries/16996/reserving
Здесь используется ID заявки, полученный методом парсинга из предыдущего пункта. Запрос должен содержать в себе авторизационный cookie tsagent. Если произошла ошибка бронирования, ее текст будет в ответе на запрос, иначе это будет html-блок перенаправления на страницу, аналогичный блоку ответа при сохранении заявки. Временная задержка между выбором мест туристом и бронированием заявки должна быть минимальной, чтобы избежать возможной порчи заявки в ситуации, когда кто-то успел забронировать эти места раньше. При бронировании в заявке будут создаваться билеты, связывающие этот тур с ресурсом и тратящие его.

2. Распечатываем документ "Посадочный талон" для туриста. Нужно выполнить последовательно два авторизованных GET-запроса, из ответа первого получив ссылку на второй (аналогично получению ID заявки из ответа при ее сохранении):
GET http://hostname.tourservice.net/Voucher/partner/queries/16996/createdoc/9
Здесь 16996 - это ID заявки, полученный ранее, 9 - это номер шаблона документа посадочного талона, индивидуальный для каждого туроператора. Ответ содержит в себе ссылку на распечатываемый документ:

<html><head><title>Перенаправление...</title><META HTTP-EQUIV="refresh" CONTENT="0; URL=/Voucher/partner/queries/16996/printdoc/9?did=7463"></head><body style="text-align:center;"><h3>Вы будете перенаправлены на запрошенный адрес</h3><hr>Если перенаправление не сработало, нажмите: <a href="/Voucher/partner/queries/16996/printdoc/9?did=7463">/Voucher/partner/queries/16996/printdoc/9?did=7463</a></body></html>
Здесь искомый URL следующий: http://hostname.tourservice.net/Voucher/partner/queries/16996/printdoc/9?did=7463. Авторизованное (с участием cookie tsagent) получение его содержимого и трансляция в браузер туриста даст возможность туристу получить распечатанный билет.
<< Оглавление | Наверх…