Перейти к содержимому

Признание выручки

Эта страница объясняет, как именно система считает выручку за период и почему эта цифра может отличаться от суммы денег, которые реально легли на счёт за этот же период. Понимание этой разницы критично для любого, кто читает финансовые отчёты: владельца, бухгалтера, управляющего.

Система использует метод начисления по ночам проживания (accrual по ночам) — международный стандарт USALI для гостиничного бизнеса. Выручка бронирования распределяется пропорционально ночам, когда гость реально проживал в номере, а не по дате создания брони и не по дате оплаты.

Это значит:

  • Бронь на 10 ночей с 25 января по 4 февраля → в январе признаётся выручка за 7 ночей, в феврале — за 3.
  • Момент, когда деньги легли на счёт, на эту цифру не влияет.
  • В выручку попадают только заехавшие гости — брони в статусе CHECKED_IN и CHECKED_OUT. Подтверждённая, но ещё не заехавшая бронь (CONFIRMED) — это воронка продаж, а не выручка: пока гость не заселился, в номере никто не ночевал, и приписывать эту сумму к выручке месяца нельзя.
  • Отменённые брони (CANCELLED, REJECTED) и неявки (NO_SHOW) в выручку не входят.

Три способа считать выручку — и почему мы выбрали именно этот

Заголовок раздела «Три способа считать выручку — и почему мы выбрали именно этот»

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

Выручка признаётся в момент, когда бронь была создана. Проблема: это не выручка, это объём продаж. Забронированное в январе проживание в мае может быть отменено, и тогда «январская выручка» окажется фикцией.

Выручка признаётся в момент, когда деньги пришли на счёт. Плюс: совпадает с банковской выпиской. Проблема: если гость внёс предоплату в декабре, а жил в марте, декабрь будет искусственно богатым, а март — бедным. Расходы на обслуживание гостя (уборка, коммуналка, зарплаты) всё равно пойдут в марте. В результате декабрь выглядит прибыльным без причины, март — убыточным без причины.

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

Это и есть стандарт USALIUniform System of Accounts for the Lodging Industry, по которому отчитываются все международные гостиничные сети. Мы используем его, потому что это единственный метод, при котором P&L-отчёт даёт правду о том, заработала гостиница или потеряла за конкретный месяц.

Бронь на 100 000 ₸, 10 ночей с 15 января по 25 января. Гость оплатил всё сразу при заезде 15 января. За январь расходы на эту бронь: 75 000 ₸ (зарплаты, коммуналка, продукты).

МетодЯнварь: выручкаЯнварь: GOP
По дате брони (as-booked)зависит от даты созданияслучайная цифра
По дате оплаты (cash)100 000+25 000
По ночам (наш)100 000+25 000

Пока оплата и проживание в одном месяце — все методы сходятся.

А теперь тот же гость, но предоплатил в декабре:

МетодДекабрь выручкаДекабрь GOPЯнварь выручкаЯнварь GOP
По дате брони100 000 (при бронировании в декабре)+100 0000−75 000
По дате оплаты (cash)100 000+100 0000−75 000
По ночам (наш)00100 000+25 000

Видно, что первые два метода создают ложно-прибыльный декабрь и ложно-убыточный январь. Метод по ночам даёт правду: декабрь ничего не заработал, январь принёс 25 000 ₸ прибыли.

Отчёт / экранМетодПочему именно так
Дашборд, карточка «Выручка»Accrual по ночамПоказывает реальную выручку периода
График RevenueStats (месячная разбивка)Accrual по ночамДля корректной помесячной картины
P&L отчёт (/reports/pnl)Accrual по ночамUSALI-стандарт; доступ по праву financial_kpi.view
GOP, GOPPAR, NOIAccrual по ночамТолько так имеет смысл
Night AuditCash (по оплатам смены)Ночной аудит отвечает на вопрос «что произошло за смену», а не «какая выручка признана»
Касса и платежи (/reports/payment-ledger)Cash (по платежам)Главный отчёт для сверки с банком — показывает реально поступившие деньги
Балансы броней (/reports/aging)Остатки по бронямКто сколько должен (и где переплаты)

Для каждой брони, чьи ночи пересекаются с запрашиваемым периодом:

perNightRoom = (totalAmount − extrasSum) / totalNights
perNightExtras = extrasSum / totalNights
perNightAdjustment = adjustmentsSum / totalNights
overlapNights = количество ночей пересечения брони с периодом
roomsRevenue += perNightRoom × overlapNights
extrasRevenue += perNightExtras × overlapNights
adjustmentsRevenue += perNightAdjustment × overlapNights

Где:

  • totalAmount — итоговая сумма брони (включая доп. услуги из extraCharges)
  • extrasSum — сумма полей total из массива extraCharges
  • adjustmentsSum — сумма BookingPriceAdjustment.calculatedAmount для всех активных корректировок брони (SURCHARGE даёт положительный вклад, DISCOUNT — отрицательный)
  • totalNights — количество ночей брони целиком (checkOut − checkIn)
  • overlapNights — пересечение дат брони с запрашиваемым периодом

Если бронь полностью вне периода → выручка 0. Если totalNights = 0 (некорректная бронь) → выручка 0.

В accrual-выручку (дашборд и P&L) попадают только заехавшие гости — брони в статусе CHECKED_IN и CHECKED_OUT. Подтверждённые, но ещё не заехавшие брони (CONFIRMED) исключаются: это будущая выручка (воронка), а не выручка периода. Отменённые (CANCELLED, REJECTED) и неявки (NO_SHOW) также не учитываются.

Скидка/доплата — это пост-факт изменение цены брони (SURCHARGE — доплата, DISCOUNT — скидка), которая применяется оператором уже после создания брони (например: «доплата за дополнительного гостя», «VIP-скидка 10%», «компенсация за поломку кондиционера»).

Скидки/доплаты распределяются по тем же ночам проживания, что и сама бронь — это нужно чтобы реальная цена сделки (totalAmount + сумма скидок/доплат) корректно отражалась в accrual-выручке за период проживания.

Пример: бронь на 10 ночей с 25 января по 4 февраля, базовая цена 100 000 ₸, оператор 13 февраля добавил скидку −20 000 ₸ за лояльность. Скидка распределится по 2 000 ₸ на каждую ночь:

МетодЯнварь выручкаФевраль выручка
По дате createdAt скидки/доплаты70 000 (100к × 7/10)30 000 − 20 000 = 10 000
По ночам проживания (наш)70 000 − 14 000 = 56 00030 000 − 6 000 = 24 000

Метод по ночам — единственный корректный для accrual: скидка относится к услуге (10 ночам проживания), а не к моменту, когда оператор её внёс в систему.

Выручка сверх проживания разбивается на два потока:

  1. Доп. услуги в бронированиях (поле booking.extraCharges — завтрак, трансфер, доп. кровать и прочее из каталога, приложенное к брони) — распределяются пропорционально ночам проживания, так же как и основная выручка. Входят в P&L и в «Выручку» дашборда.

  2. Допродажи (standalone ServiceSale — разовые продажи на ресепшене сверх брони: бар, прачечная, сувениры) — признаются по дате оплаты (paidAt). У каждой такой продажи нет понятия «ночей проживания», и дата услуги совпадает с датой оплаты в подавляющем большинстве случаев. В P&L и «Выручку» дашборда не входят — для них отдельный отчёт «Допродажи».

Это небольшое расхождение с чистым USALI (где и service sales могли бы признаваться по дате оказания услуги), но на практике оно значимо только для случая, когда гость оплачивает накопленные услуги при выезде — тогда вся сумма попадает в день выезда, а не распределяется по дням проживания. Для гостиницы это редко меняет картину.

В P&L-отчёте accrual-выручка дополнительно разносится по операционным департаментам по стандарту USALI: Rooms (проживание), F&B, и прочие операционные департаменты. Привязка идёт через категорию услуги (SaleCategory.department):

  • Проживание (комната + скидки/доплаты − возвраты) → всегда департамент Rooms.
  • Доп. услуги в бронированиях и допродажи → в свой департамент по категории услуги; если категория не задана — попадают в UNCLASSIFIED (не распределено).

По каждому департаменту P&L показывает не только выручку, но и прибыль департамента (departmentProfits = выручка департамента − его операционные расходы). Это позволяет увидеть, какой департамент зарабатывает, а какой — съедает маржу. Сама модель расчёта по ночам при этом не меняется: департаментная разбивка — это «надстройка» над той же accrual-выручкой.

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

Последствие: если гость жил в январе, а возврат ему оформили в марте, то:

  • Январь показывает полную выручку (100 000 ₸)
  • Март вычитает возврат из своей выручки
  • Сумма помесячных чисел за январь-март не равна сумме выручки за квартал, если возврат был частичным и затронул оба месяца. Для квартального периода возврат будет учтён один раз.

Если для вас это проблема (например, нужна чистая квартальная выручка без таких артефактов) — запрашивайте P&L за квартал целиком, а не складывайте три месячных отчёта вручную.

Самый частый источник путаницы. Управляющий смотрит на дашборд за апрель и видит «Выручка: 593 270 ₸». Потом открывает банковскую выписку и кассу и понимает, что за размещение (за ночи гостей) за этот месяц фактически не пришло ни тенге — только 20 270 ₸ за услуги на ресепшене. Возникает закономерный вопрос: что это за 593 270 ₸ и где они?

Это две разные метрики про два разных события, и обе верные — просто про разное.

  • 593 270 ₸ (P&L / дашборд) — это начисленная выручка за апрель по USALI: столько гостиница заработала услугами, оказанными в апреле. Часть гостей оплачивала эти ночи в марте, часть оплатит в мае — но услуги оказаны в апреле, поэтому выручка признана в апреле.
  • 20 270 ₸ (касса) — это сколько реальных денег поступило в апреле. За проживание в этом месяце большая часть уже была оплачена заранее (в марте или раньше), поэтому в кассе апреля только допродажи.

Обе цифры корректны. Они отвечают на разные вопросы:

  • P&L отвечает «сколько гостиница заработала апрелем»
  • Касса отвечает «сколько денег поступило в апреле»

Владелец смотрит на P&L за март и видит «GOP: 2 000 000 ₸». Потом смотрит выписку за март — «пришло 3 500 000 ₸». Разница в другую сторону.

  • GOP 2 000 000 — столько гостиница заработала за услуги, оказанные в марте (прибыль до аренды и налогов).
  • 3 500 000 на счёте — это разные деньги: часть за март, часть предоплат за апрель-май, минус частичные возвраты за февральские брони.

Эти цифры никогда не обязаны совпадать. Совпадают они только в учебном примере, когда все гости заехали, прожили и расплатились в одном и том же месяце, а возвратов не было.

Как посмотреть реальные деньги — пошагово

Заголовок раздела «Как посмотреть реальные деньги — пошагово»
Касса и платежи — KPI, график и транзакции
Касса и платежи — KPI, график и транзакции

Если нужно ответить на вопрос «сколько денег реально пришло за этот период», зайти нужно в Касса и платежи.

  1. В левом меню откройте раздел «Отчёты»«Касса и платежи» (значок кошелька).
  2. Вверху — три KPI-карточки:
    • Поступления — сколько пришло всего за период (и количество транзакций).
    • Возвраты — сколько вернули гостям (если были возвраты).
    • Чистая касса — итог: поступления минус возвраты. Это число для сверки с банком.
  3. Ниже — блок «По источнику»: отдельно брони и отдельно сервис (бар, прачечная, допуслуги на ресепшене). Видно, откуда пришли деньги.
  4. График «Поступления по дням» — столбчатая диаграмма. Зелёные столбцы — поступления, красные — возвраты. Сразу видно пиковые дни.
  5. Таблица «По способам оплаты» — отдельно наличные, Kaspi, банк. перевод и т.д. Эта разбивка обычно нужна бухгалтеру.
  6. Внизу — детальная таблица транзакций: каждая запись со ссылкой на бронирование и гостя.
  7. Справа сверху — кнопки Excel и CSV. Обычно бухгалтеру отправляется Excel за месяц.

Фильтр периода — стандартный: сегодня / вчера / этот месяц / прошлый месяц / квартал / произвольный диапазон. Всё на странице — KPI, график, разбивки и таблица — пересчитывается в связке.

ЗадачаОтчёт
Сколько денег пришло за день/неделю/месяцКасса и платежи
Сверка кассы с банковской выпискойКасса и платежи → Excel
Сколько пришло наличными / Kaspi / переводомКасса и платежи → «По способам оплаты»
Что заработала гостиница в марте (прибыльность)P&L
Какая маржа (GOP, NOI, GOPPAR)P&L
Сравнение этого месяца с прошлым годом по прибылиГод к году
Что произошло за смену на ресепшене (заезды/выезды/оплаты одной даты)Ночной аудит
Кто из гостей должен денег (и где переплаты)Балансы броней
  • Файл хелпера: apps/api/src/common/helpers/revenue.helper.ts
  • Функция: prorateBookingRevenue(bookings, from, to) — для суммы за период
  • Функция: prorateBookingRevenueByBucket(bookings, from, to, granularity) — для помесячной/подневной разбивки
  • Используется в analytics.service.revenue() и reports.service.profitAndLoss()
  • YoY Comparison пока использует упрощённый метод (вся выручка брони приписывается месяцу checkIn). Это близко к accrual, но не точно. В следующей итерации переедет на тот же хелпер.
  • Night Audit останется на cash-basis — это его естественная семантика.
ОтчётМетод учёта скидок/доплат
Дашборд → «Выручка» (analytics.revenue)Pro-rata по ночам, в составе totalRevenue
P&L (reports.profitAndLoss)Отдельная строка revenue.adjustments, входит в revenue.total
Revenue by GroupСвёрнуты в totalRevenue группы (без отдельной строки)
Channel PerformanceСвёрнуты в totalRevenue канала (без отдельной строки)
Cancellation ReportВключены в lostRevenue отменённой брони целиком
Night AuditОтдельная строка revenue.adjustments по createdAt скидки/доплаты