Полная карта интеграции с вендорским API (АСБ / ihmanagement): методы, поток каждого поля, схемы БД, эндпоинты и логика проверок.
GET /properties/{id}?in&out. quota_known = есть ли записи Quote у номера; available = qty>0 на все ночи. child_age/child_start_age в ответе.POST /properties/{id}/price: options (calcsum live) + availability{progid} (Quote по concod). ineligibility гасит по возрасту/сроку.BookingService.create: validate_booking → programms → guard servcods → find_quota_shortage (live quotes) → setletter → parse (humanize) → save Order.| метод | HTTP | endpoint | аргументы | передача | ключевые поля ответа |
|---|---|---|---|---|---|
calcsum | POST | calcsum | js_data | form data={"js_data": json} | заказ с заполненным price (итог + по клиентам) |
setletter | POST | setletter | js_data | form data={"js_data": json} | ref (строкой), mes, price, paysysurl, paysysid |
letters | GET | letters | letcod | query {letcod} | объект заказа (list→data[0] или None) |
cancel_letter | DELETE | letters | letcod | query {js_data: {"letcod":N}} ⚠ | {mes, ref} (ref 1=успех) |
url_let_docs | GET | url_let_docs | letcod | query {letcod} | ⚠ голая JSON-строка URL (или {ref}) |
objects | GET | objects | — | — | объекты (objid, objnam, objstars, hourin/out, child_age, geoobject…) |
objtyps | GET | objtyps | — | — | objtypid → objtypnam |
services | GET | services | — | — | servcod → servnam |
catprops | GET | catprops | — | — | catpropid → catpropnam |
categs | GET | categs | objid | query {objid} | catcod, catnam, catbednum, catdopnum, catpropids, catgalery |
programms | GET | programms | objid | query {objid} | progid, pricelistid, prognam, concod, servcods, minlength/maxlength, datein/dateout, discountprc |
prices | GET | prices | objid, pricelistid, length=400 | query | catcod, pricelistid, datein-интервалы, price |
quotes | GET | quotes | objid, length=400, catcod? | query (catcod — если задан) | catcod, resdate, concod, quoteval |
check_price_by_object | GET | check_price_by_object | objid | query {objid} | метка изменения цен (инкрементальный синк) |
int(float(ref)).setletter — build_setletter_jsdata(){
// верхний уровень
"letcod": 0, // константа при регистрации
"datein": "YYYY-MM-DD HH:MM:00", // date_in + hour_in (объекта)
"dateout": "YYYY-MM-DD HH:MM:00", // date_out + hour_out ИЛИ hour_in
"pricelistid": <progid 1-го гостя>, // программа заказа
"queryfl": 0, // 0 = бронь с проверкой квоты
"price": 0,
"rooms": [ {
"catcod": <int>, "catplacefl": 0,
"clients": [ {
"clientid": 0,
"pricelistid": <progid гостя>, // путёвка каждого гостя
"clinam1": фамилия, "clinam2": имя, "clinam3": отчество,
"datebirthday": "YYYY-MM-DD",
"sexcod": 1|2, // 1-М, 2-Ж
"agecod": 1|2, // 1-взрослый, 2-ребёнок (по флагу child)
"dopplacefl": 0|1, // 1 если idx >= capacity (доп. место)
"countintcod": 643, // COUNTRY_RF (Россия)
"enablefl": true, "price": 0,
"heal": [{"servcod": servcods[0]}], // лечение (если есть)
"mealType": [{"servcod": servcods[1]}] // питание (если есть)
} ]
} ],
"payer": { "lastname","firstname","middlename","email","cellphone" } // cellphone ← phone
}
ref→letcod (int(float), ≤0 → BookingError), mes→letregnr, price→int, paysysurl, paysysid. servcods берутся из programms по progid, порядок [лечение, питание].Каждая таблица витрины (локальная БД) и откуда берётся каждое поле в АСБ. Прочерк «—» = поле не из АСБ (вычисляется/локальное).
| колонка | тип | источник АСБ |
|---|---|---|
id | str PK | objid |
name | str | objnam |
type | str | objtypid → objtyps.objtypnam |
city / region / country | str | geoobject.* (canon_place, derive_country) |
stars | int | objstars |
description | text | objnot |
phone | str | objphone |
hour_in / hour_out | str | hourin / hourout |
child_start_age | int? | child_start_age |
child_age | int? | child_age |
lat / lon | float? | geoobject.Latitude/Longitude |
price_from | int? | — (min по Price, синк отдельно) |
city_id | FK | — (resolve_city_id) |
rating, reviews, rating_criteria, memo, how_to_get, prices_info, children_note, capacity (строка «450 мест»), canonical_path, связки treatment_profiles/amenities/media.| колонка | тип | источник АСБ |
|---|---|---|
id | str PK | {objid}:{catcod} |
catcod | int | catcod |
name | str | catnam |
capacity | int? | catbednum (осн. койки) |
dop_capacity | int | catdopnum (доп. места) |
bed | str | — (1-й feature «кроват/диван») |
features | json | catpropids → catprops.catpropnam |
photos | json | catgalery (ind из href) |
description | text | catnot |
price_from | int? | — (из Price, синк отдельно) |
area.| колонка | тип | источник АСБ |
|---|---|---|
id | str PK | {objid}:{progid} |
progid | int | progid |
pricelist_id | int | pricelistid |
name | str | prognam |
concod | str | concod (договор) |
description | text | prognot |
min_nights / max_nights | int? | minlength / maxlength |
date_in / date_out | str | datein / dateout |
discount | json | discountprc (только >0) |
included | json | servcods → services.servnam |
is_union | bool | — (regex «профсоюзн» в prognam) |
min_nights_adult, min_nights_child, note, url_segment.| колонка | тип | источник АСБ |
|---|---|---|
room_id | str | {objid}:{catcod} |
date | date | resdate |
concod | str | concod (договор) |
qty | int | Σ quoteval по ключу |
(room_id, date, concod). До фикса агрегировалось без concod — отсюда была «Quota is empty».| колонка | источник |
|---|---|
room_id | {objid}:{catcod} |
pricelist_id | pricelistid |
date | по-дневно из datein-интервала |
price | price (заглушка 77777 исключается) |
| колонка | источник |
|---|---|
token | uuid4().hex |
letcod / letregnr / price / paysys_url | ответ setletter (parse) |
objid / catcod / date_in / date_out | запрос (body) |
payer / guests | запрос (снапшот json) |
docs_url | url_let_docs (при оплате) |
status / paid_at | «booked»→«paid» |
| поле | полный путь данных |
|---|---|
| Ёмкость (осн.) | catbednum→Room.capacity→RoomItem.capacity→RoomCard.fits / validate_booking |
| Доп. места | catdopnum→Room.dop_capacity→RoomItem.dop_capacity→fits (только детям) |
| Договор (квота) | concod (programms + quotes)→Program.concod · Quote.concod→availability{progid}→RoomGuestPrograms.avail |
| Квота (места) | quoteval→Quote.qty (по date,concod)→available / quota_known · availability→soldOut · программа гаснет |
| Возраст ребёнка | child_age / child_start_age→Property.child_age→PropertyDetail.child_age→BookingFlow.childAge → guestAgeError |
| Время заезда/выезда | hourin / hourout→Property.hour_in/out→(в create)→js_data datein/dateout |
| Программа (путёвка) | progid · servcods→Program.progid · included→program_prices · options→RoomGuestPrograms picked → js_data pricelistid+heal/mealType |
| Цена | calcsum (live)→PriceResponse.total/options→RoomGuestPrograms итог · BookingFlow price |
| метод + путь | тело запроса | ответ | ошибки |
|---|---|---|---|
POST /bookings | BookingCreate: objid, dateIn, dateOut, rooms[], payer | BookingCreated: token, price, letregnr, payUrl | 422 {code,message}; 404 not_found |
GET /bookings/{token} | — | BookingStatus: status, price, letregnr, payUrl, docsUrl | 404 order_not_found |
POST /bookings/{token}/pay | — | BookingStatus (status→paid) | 404 stub_disabled / not_found |
POST /properties/{id}/price | PriceRequest: catcod, datein, dateout, guests[] | PriceResponse: total, guests, options, availability | 404 room_not_found |
GET /properties/{id}?in&out | — | PropertyDetail + RoomItem.available/quota_known | 404 property_not_found |
| схема | поля |
|---|---|
| GuestIn | lastname, firstname, middlename="", birthday, sex(1|2), child=false, age?, progid |
| RoomIn | catcod, guests[GuestIn] (min 1) |
| PayerIn | lastname, firstname, middlename="", phone, email |
| BookingCreate | objid, dateIn→date_in, dateOut→date_out, rooms[RoomIn], payer |
| PriceRequest | catcod, datein, dateout, guests[{child, age, progid?}] |
| PriceResponse | total, guests[{progid, price}], options{gi:{progid:price}}, availability{progid:bool} |
| RoomItem | … capacity, dop_capacity, program_prices{progid:price}, available, quota_known |
/api/booking/create|status|pay → /api/v1/bookings*; /api/booking/price достаёт objid из тела → /api/v1/properties/{objid}/price. Наличие/цена в списке: fetchRoomAvailabilityClient → GET /properties/{id} (rooms[].available/quota_known); fetchRoomsPriceClient → /properties/{id}/rooms-price.| # | шаг | что делает / ошибка |
|---|---|---|
| 1 | Lookup Property | нет → ValueError property_not_found (404) |
| 2 | cap/dop/name по Room | catcod не найден → ValueError room_not_found |
| 3 | validate_booking | ёмкость + возраст (ниже) → BookingError 422 |
| 4 | programms (live) | servcods_by_progid + concod по каждой программе |
| 5 | guard servcods | progid без servcods → «Выбранная путёвка недоступна…» |
| 6 | quotes (live) + find_quota_shortage | нет мест по (catcod,ночи,concod) → «…нет свободных мест» |
| 7 | build js_data | rooms[].clients[] (см. Методы АСБ) |
| 8 | setletter (live) | регистрация; ref<0 = ошибка |
| 9 | parse + humanize | ref≤0 → BookingError (человеческий текст, raw в лог) |
| 10 | save Order | token, status=booked, commit |
cap = capacity or 0 ; dop = dop_capacity or 0 ; adults = гости без child если cap > 0: len(adults) > cap → «В номер «{name}» помещается не более {cap} взросл. (доп. места — только для детей)…» len(guests) > cap + dop → «В номер «{name}» помещается до {cap+dop} гостей ({cap} осн. + {dop} доп.).» если cap == 0 → ёмкость НЕ проверяется (вместимость АСБ не задана)
age = полных лет от birthday до date_in (_age_on) age < 0 → «Дата рождения не может быть позже даты заезда» child & age != заявленный(g.age) → «Возраст ребёнка на заезд — {age}, а указан {claimed}…» child & age > child_age → «…уже не ребёнок (до {child_age} лет). Оформите взрослым» взрослый & age <= child_age → «…детский возраст (до {child_age}). Оформите ребёнком» child_age берётся из Property (из АСБ). Фронт ещё и ограничивает пикер (birthdayBounds).
avail[(catcod, date, concod)] = Σ quoteval nights = [date_in .. date_out-1] для каждой пары (catcod, concod) заказа с числом гостей count: если для любой ночи avail[(catcod, ночь, concod)] < count → нехватка → «На выбранные даты в номере «{room}» по программе «{prog}» нет свободных мест» availability в /price: то же, но per-progid; нет данных по concod → true («по запросу»)
| подстрока в mes | показываем пользователю |
|---|---|
quota is empty | На выбранные даты нет свободных мест… |
not available for | Программа недоступна к бронированию на выбранные даты… |
maximum/minimum number of days | Не подходит / слишком короткий срок — измените даты |
not enough money | Бронь временно недоступна по техническим причинам… |
wrong parametr · check-in/out time · js_data | Техническая ошибка, мы уже разбираемся |
| прочее (fallback) | Не удалось оформить на выбранных условиях… |
booking.rejected, пользователю — только человеческий. Полного справочника кодов у АСБ нет.| компонент | поля | назначение |
|---|---|---|
| BookingBlock | filters.rooms[], RoomItem, avail(available/quota_known), roomPrices | строит roomGroups; клиентские fetch наличия+цены; накладывает avail на фонд |
| RoomsList / RoomCard | capacity, dop_capacity, available, quota_known, program_prices, price_from | soldOut/unverified; fits (ёмкость); собирает booking_draft → /booking |
| RoomGuestPrograms | program_prices, options, availability{progid}, min/max_nights, date_in/out, name | цена (calcsum); гасит по наличию (concod), возрасту (ADULT_AGE=35, ageRange из названия), сроку |
| BookingFlow | draft, forms, property.childAge, catNames, progNames | ageOn/guestAgeError (возраст на заезд); allValid; submit → /api/booking/create; поллинг статуса |
| BirthdayPicker | minDate, maxDate | ограничивает выбор даты рождения под возраст гостя |
| booking/page.tsx | prop.child_age, child_start_age, rooms, programs | фетчит /properties/{id}; прокидывает childAge, catNames, progNames |
sessionStorage.booking_draft; введённые ФИО — в booking_form; токены заказов — в localStorage.my_bookings. Payload create: rooms[].guests[] с lastname/firstname/middlename/birthday/sex/child/age/progid + payer.