Как устроен финансовый движок

Справочник для оператора и владельца · обновлено 16 августа 2026

Движок собирает управленческий P&L двух юрлиц — Thera Interactive DMCC и ИП Качмар С.А. — из первичных документов на Google Drive. Всё, что он делает, подчинено одному правилу: ни одна цифра не появляется из ниоткуда и не исчезает молча. Если данных не хватает, движок останавливается и спрашивает, а не досчитывает за вас.

Зачем и как устроено

Система состоит из трёх слоёв. Разделение не формальное: у каждого своя цена ошибки и своя скорость.

СлойЧто делаетЦена
Зеркала Читает документ, разбирает его, сверяет контрольные суммы, показывает ИИ и замораживает результат в неизменяемый CSV дорого: ИИ на каждый документ, минуты работы
Слой 2 Из зеркал строит два реестра — инвойсов и транзакций, — применяет статьи, курсы, матчинг, определяет период признания дёшево: секунды, без ИИ и без сети
P&L Плоская таблица (одна строка = одно событие) и HTML-отчёт мгновенно
Зеркало неизменяемо. Заморожённый документ не пересобирается никогда — ни при правке правил, ни при новом прогоне. Это гарантия того, что вчерашние цифры сегодня не поедут. Пересобрать можно только явной командой, и только пока месяц не закрыт.

Порядок работы

  1. Оператор кладёт документы в папку своего месяца на Drive и называет их по стандарту. Движок в первичку не пишет никогда — у него доступ только на чтение.
  2. Запуск сборки из консоли: выбрать месяц, нажать «Собрать». Читаются только папки этого месяца.
  3. Движок задаёт вопросы обо всём, что вызывает сомнение: не тот формат имени, файл в чужой папке, не сошлась контрольная сумма, нет обязательного источника.
  4. Оператор отвечает прямо в консоли или исправляет причину на Drive.
  5. Месяц закрывается, когда вопросов не осталось. После закрытия он не пересобирается.

Консоль оператора

Адрес: panel.thera-ltd.com/console.html. Четыре блока:

Кнопка «сверить имена с Drive». Сверяет имена файлов с первоисточником и снимает вопросы о тех, что уже переименованы. Ничего не пересобирает и не считает — только читает листинг папок, поэтому применима и к закрытым месяцам, где пересборка запрещена. Если выбраны месяцы, сверяет только их. Что она сообщит:

Чего сверка не видит. Она идёт по индексу разобранных документов, поэтому файл, который в индекс не попал (не разобран, нет зеркала), ей не виден — за июль таких три. Полный обход папок делает сборка. Если нужна гарантированно полная картина по именам, надо запустить месяц, а не сверку.
Вход раздельный. Панель и движок — два разных приложения Cloudflare Access. Если консоль показывает красную плашку, откройте api.thera-ltd.com/health, подтвердите вход по коду на почту и обновите страницу.

Как признаётся

База — транзакции, а не инвойсы

Решение владельца от 29 июля 2026. Полный комплект инвойсов собрать невозможно: матчинг давал 26 уверенных пар из 128 открытых счетов. Деньги в банке видны все, покрытие статьями стопроцентное — поэтому источником признания стало движение денег. Инвойс уточняет период, но сам по себе расход не создаёт.

Дата начисления

  1. Есть привязанный инвойс с периодом услуг → берётся период услуг.
  2. Период услуг не указан → дата инвойса.
  3. Инвойса нет → дата транзакции.

По сумме оборота около 89% признаётся по начислению, остальное по дате платежа. Основание всегда записано в строке — видно, откуда взялась дата.

Длящиеся услуги. Годовое обслуживание или подписка признаются одной суммой в первом месяце периода услуг. Это упрощение: Kozyk на 39 690 AED за год целиком лёг в июнь. Помесячное распределение пока не делается.

Каждое событие ровно один раз

Главный инвариант. Если выручка признана отчётом площадки, приход денег в P&L не идёт. Если ФОТ признан построчно из ведомости, перевод в кошелёк — трансфер, а не расход. Движок проверяет это на каждом прогоне и печатает результат.

Файлы и папки

Правило одно: документ лежит в папке своего периода и назван по нему — ГГГГ-ММ Источник.расширение. Например 2026-07 Steam.pdf, 2026-06 Al Ansari.xlsx.

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

Почему не доверяем имени: 2026-01 MultiPass.pdf однажды содержал декабрьскую выписку, 2026-02 Google Ads.pdf оказался счётом от Wix, а имя SIF-выгрузки Al Ansari вообще давало период «1301-09».

Узкий прогон

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

Куда движок не смотрит никогда

Полнота данных

Отсутствие выписки за месяц — это не «в этом месяце не было расходов», это дыра. Разница принципиальна, и на ней построены все проверки.

Обязательные источники

ИсточникКонтрольное тождество
Islamic bankвходящий остаток + обороты = исходящий
MultiPassостатки по каждому IBAN отдельно
Сбербанкитого оборотов + исходящий остаток
4Devпредоплата до и после
Deelвыплаты + комиссии = Total Due
Al Ansari (SIF)оклад + переменная = Total по каждому человеку
Steamgross − VAT − возвраты = Net Sales; удержание = 30% × US Share
XsollaTotal payout отчёта
Robokassaостаток + оплаты − комиссии − перечисления = остаток
VK Playдоход − возвраты − НДС агентом − вознаграждение = к перечислению

Границы активности

Источники появляются и исчезают: Steam начал продавать в сентябре 2025, договор ВК с ИП действует с октября 2025, 4Dev заработал в феврале 2026. Спрашивать их отчёты за более ранние месяцы бессмысленно, поэтому в реестре указано, с какого месяца источник существует.

Граница — это факт о том, что источника не было, а не способ спрятать пропуск. «Отчёт был, но мы его не скачали» ею не закрывается.

Проверки и закрытие

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

  1. Контрольное тождество источника — сходится ли документ сам с собой.
  2. Гейт периода — выписка обязана покрывать ровно свой месяц, с первого по последнее число. Заезд на соседний месяц означает задвоение операций, недобор — потерю.
  3. ИИ-сверка зеркала с оригиналом. Обязательна на боевом контуре: прогон без неё однажды молча снял сомнения по трём документам, один из которых терял выплату на 400 евро.
  4. Имя и раскладка — соответствие стандарту.

Закрытие месяца

Месяц можно закрыть, только если по нему нет открытых вопросов, все документы заморожены, все обязательные источники на месте и имена по стандарту. Иначе кнопка недоступна, а попытка закрыть через API отклоняется с перечнем причин.

Закрытие хранится в реестре на Drive и переживает любые пересборки. Закрытый месяц пропускается при сборке — правка парсера или справочника не может переписать историю.

Площадки

Steam

Выручка признаётся отчётом Valve, а не приходом денег: Valve платит примерно через 25 дней после закрытия месяца, и признание по платежу увело бы июньскую выручку в июль. В банк приходит только net payment — без отчёта не видно ни комиссии 30%, ни удержанного налога, ни потребительских налогов.

VK Play

Признание по отчёту площадки. «Доход Разработчика» равен валовым платежам, а возвраты и вознаграждение ВК вычитаются позже — поэтому цепочка у ВК устроена иначе, чем у Steam. Старые платежи на Thera (апрель–октябрь 2025, через ROCK RIM MEDIA) отчётов не имеют и не будут иметь: соглашение тогда было на другое юрлицо. Они признаются по деньгам со сдвигом на месяц назад — ВК платит в следующем месяце за предыдущий.

Robokassa

Выручка берётся только из акта (пункт 9 — оплаты игроков). CSV заявок на вывод его не заменяет и выручки не содержит. НДС не возникает — освобождение по Сколково.

Xsolla

Единственный источник с допуском: расхождение payout до 0,01% не блокирует заморозку, но обязательно порождает вопрос оператору. Причина — накопленное округление: при 1171 транзакции разница в 2,42 евро набегает из сотых долей цента на строку.

Валовые платежи игроков

В строке «Выручка» стоит то, что стало нашим. Потребительские налоги, которые Valve как merchant of record собирает с игрока и сам платит государству, в выручку не входят — по IFRS 15 это суммы, собираемые в пользу третьих лиц. За период это около миллиона долларов.

Чтобы можно было сравнивать себя с рыночными оценками (они считают выручку от цены на витрине, а она VAT-inclusive), в таблице есть справочный блок 00: валовые платежи игроков, потребительские налоги, возвраты. В итоги P&L он не входит. Из доллара, заплаченного игроком в Steam, до компании доходит около 56 центов.

ФОТ

Три канала выплат: кошельки (Deel, 4Dev), зарплатный счёт WPS через Al Ansari, прямые банковские переводы.

Перевод в кошелёк — это трансфер, а не расход. Расход признаётся построчно из ведомости, пофамильно. Иначе ФОТ задвоился бы. Инвойсы канала wallet намеренно не признаются — движок проверяет, что их ноль.

Разбивка по людям обязательна: она даёт разрез по отделам. Около 278 тысяч долларов пока идут строкой «без привязки к отделу» — это агрегированные зарплатные реестры, где получатели не детализированы.

Курсы валют

Месячные средние, источник — ЦБ РФ. Подтягиваются автоматически: если за месяц курса нет, движок берёт его сам и дописывает в справочник.

Раньше курсы вносились руками из freecurrencyrates, но тот отдаёт битый сертификат и программно недоступен. Сверка ЦБ с внесёнными вручную значениями за пять месяцев показала расхождение в сотые доли процента — это тот же рынок, разброс лишь от разного набора дней усреднения.

Месяц без курса не даёт ошибки — он просто выпадает из P&L: суммы в рублях и дирхамах остаются без пересчёта. Именно так июль однажды потерял 396 строк. Поэтому курсы подтягиваются до начала расчётов.

Справочники

Мастер — книга «FE — Engine rules» в папке 03_engine_rules на Drive. Одиннадцать вкладок: статьи, правила, счета, контрагенты, люди, курсы, источники, ведомость WPS, решения разбора, два файла переопределений.

Список обязан быть полным. Того, чего нет в книге, в облаке не существует. Однажды в нём не было ведомости WPS и решений разбора — и ФОТ перестал признаваться пофамильно, а результат периода уехал на 93 тысячи долларов. Без единой ошибки в логе.

Правки оператора живут в книге и переживают пересборки. Локальные копии — рабочие, не источник истины.

Облако и доступ

ДвижокCloud Run, проект finance-engine-alfa, регион europe-west1
APIapi.thera-ltd.com — Cloudflare Worker, проксирует в Cloud Run
Консольpanel.thera-ltd.com/console.html
Отчётpanel.thera-ltd.com/reports/pnl-to-date.html — постоянная ссылка, обновляется после каждого прогона
ТаблицыGoogle Sheets в папке 04_output: плоская таблица, реестры инвойсов и транзакций

Доступ — Cloudflare Access, семь адресов. Сервис дополнительно проверяет подпись Cloudflare сам и без неё отвечает отказом. Ключи хранятся в Secret Manager, в образ не попадают.

Прогон живёт в фоновом потоке: запуск возвращает идентификатор сразу, ход виден через консоль. Одновременно идёт только один прогон — два писали бы в один индекс.

Ловушки, на которых уже обжигались

Здесь собрано то, что выглядело правильным и оказалось неверным. Каждый пункт стоил времени или денег.

Открытые вопросы