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

Что вы создаёте и почему это важно
Приложение от учёта времени до выставления счетов решает распространённую проблему: часы распыляются по календарям, чатам и заметкам. А когда приходит день выставления счёта, кому‑то приходится восстанавливать месяц вручную. Там и появляются ошибки: пропущенные платные часы, неверные ставки, дублирующиеся строки или несоответствие итогов.
Это приложение для тех, кто выставляет счета по часу и хочет повторимый процесс: фрилансеры с несколькими клиентами, агентства, где несколько человек ведут учёт по одному проекту, и внутренние команды, которые перекладывают затраты на клиентов или отделы.
Цель практическая: фиксировать записи времени по проекту, сворачивать их в запись счёта и генерировать брендированный PDF, понятный клиенту. Когда этот поток надёжен, выставление счетов перестаёт быть ежемесячной паникой.
Под «просто в первую очередь» обычно понимают:
- Один способ записи времени (дата, проект, часы, заметка)
- Одно правило ставки (по проекту или по человеку)
- Один счёт на клиента за период
- Один макет PDF с вашим логотипом и реквизитами
- Понятные статусы (Draft, Sent, Paid)
Небольшой сценарий: студия из двух человек ведёт учёт по «Client A - Website Updates». Каждый вносит записи в течение недели. В пятницу вы создаёте счёт по проекту и диапазону дат, приложение превращает записи в позиции счёта, и PDF готов к отправке без повторного ввода.
Если вы используете no-code платформу вроде AppMaster, сначала добейтесь корректности данных и процесса, прежде чем добавлять допы: квитанции, мультивалютность, скидки или согласования. Их проще добавить, когда базовый поток быстрый, точный и устойчивый.
Основные функции (и что оставить на потом)
Небольшая первая версия позволяет быстрее отправлять «готовые к отправке» счёта. Сфокусируйтесь на трёх вещах: захват времени, преобразование времени в понятные строки счёта и генерация читаемого PDF.
Начните с нескольких сущностей (названия можно сменить позже, но структура важна): Client, Project, Time Entry, Invoice и Invoice Line.
Держите workflow простым с одним полем статуса у Invoice. Draft, Sent и Paid подойдут большинству команд долгое время.
Обязательные действия должны соответствовать тому, что происходит каждую неделю:
- Записать время (ручной ввод обычно быстрее всего строится и проще для исправления)
- Утвердить время (хотя бы как статус «Approved»)
- Создать счёт из утверждённого времени
- Экспортировать PDF
«Брендированный» не значит вычурный. Это значит последовательный и заслуживающий доверия: логотип, реквизиты, номер и даты счёта, понятные итоги и инструкции по оплате.
Что не нужно добавлять сразу: налоги, скидки, мультивалютность и вложения. Они полезны, но вводят крайние случаи (округления, юрисдикционные правила, курсы обмена, хранение файлов), которые замедлят первый релиз.
Модель данных: сущности и важные поля
Приложение «время → счёт» живёт или умирает благодаря модели данных. Держите её маленькой и предсказуемой, чтобы итоги всегда совпадали с тем, что вы обещали клиенту.
Минимальный набор таблиц обычно выглядит так:
- Client: имя, электронная почта для выставления счётов, адрес, валюта по умолчанию, условия оплаты (например, Net 14)
- Project: client_id, название проекта, ставка по умолчанию (необязательно), флаг активного проекта
- Time entry: project_id, person (имя или user_id), дата, длительность (часы), описание, rate_at_time, billable (yes/no), invoiced_invoice_id (пусто до выставления)
- Invoice: client_id, project_id (необязательно), номер счёта, дата выставления, дата оплаты, статус, subtotal, tax, total
Со ставками часто возникают проблемы. Выберите один подход и придерживайтесь его: ставка по проекту, ставка по человеку или фикс за задачу/услугу.
Даже если вы храните ставку по умолчанию в проекте или у человека, копируйте фактическую ставку в каждую запись времени как rate_at_time при создании (или утверждении) записи. Это предотвращает сюрпризы при последующем изменении ставок. Счета должны отражать то, что было реально в момент работы.
Для записей времени часто можно пропустить отдельный статус и опираться на пустоту invoiced_invoice_id. Для счётов держите статусы жёсткими: Draft, Ready, Sent, Paid (и добавьте Void, если нужна чистая отмена).
В AppMaster Data Designer хорошо мапится в PostgreSQL и помогает держать связи понятными без дублирования полей.
Захват записей времени по проекту (простой UX)
Захват времени — оттуда приложение либо становится незаметным в работе, либо начинает игнорироваться. Первую версию сделайте скучной и быстрой: один экран, одно главное действие и минимум выборов.
Выберите один метод захвата. Ручной ввод обычно выигрывает в начале, потому что подходит всем и легко проверяется. Таймер можно добавить позже, когда вы поймёте, как люди реально ведут день. Если добавляете таймер, оставьте возможность ручного редактирования для пропущенных остановок.
Сделайте поля, которые защищают качество биллинга, обязательными:
- Проект (или клиент + проект)
- Дата
- Длительность (часы и минуты)
- Короткое описание (чтобы клиент узнал работу)
- Исполнитель (если время ведёт несколько людей)
Решите правила округления заранее — они влияют на доверие и итоги. Общепринятый подход — шаг 6 минут (0.1 часа). Ясно укажите, округляете ли вы каждую запись или дневной итог. Округление каждой записи проще объяснить и проверить.
Если в биллинге участвует несколько людей, добавьте лёгкий шаг утверждения. Практичное правило: после утверждения записи обычно блокируются для правок. Если нужно изменить, требуйте роль менеджера для повторного открытия и записывайте, кто и зачем менял.
Преобразование времени в строки счёта (правила свёртки)
Свёртка — это момент, когда сырые логи превращаются в строки, понятные клиенту. Держите правила простыми и повторимыми, чтобы можно было доверять каждому созданному счёту.
Начните с одного действия: выберите клиента и диапазон дат, затем подтяните только незабилованные записи, соответствующие фильтру. Этот фильтр — защитный барьер от двойного счёта. Если запись не имеет клиента или проекта, считайте её «не готовой к выставлению» и не включайте в свёртку, пока не исправите.
Как группировать записи в позиции счёта
Группировка определяет число строк и удобство проверки для клиента. Выберите дефолт и добавьте один опциональный переключатель для гибкости.
Распространённые опции группировки:
- По проекту
- По человеку (полезно при разных ставках)
- По дню или неделе
- По задаче/категории (Design vs Development)
Вне зависимости от выбора каждая позиция должна показывать: понятный ярлык, суммарные часы, ставку и сумму позиции. Если ставки могут меняться, используйте сохранённый rate_at_time в каждой записи (или таблицу ставок с датой вступления в силу), а не одну «текущую ставку».
Пометить как выставленное (не закрывая себе путь назад)
Когда вы добавляете записи в счёт, сохраняйте ID счета в каждой записи времени. Это создаёт аудиторский след и предотвращает повторное включение той же записи.
Исправления случаются. Если вы убираете строку из счёта, не удаляйте историю. Отвяжите затронутые записи времени (очистите invoice ID), пересчитайте итоги и сохраните короткую заметку вроде «Removed 2.0h, wrong project».
В AppMaster это хорошо ложится в один бизнес-процесс: запрос незабилованных записей, группировка, создание строк счёта, затем обновление каждой записи ссылкой на счёт.
Записи счёта: итоги, нумерация и статусы
Запись Invoice — это контейнер, который вы можете отправлять, отслеживать и потом аудировать. Она должна оставаться стабильной, даже если кто‑то изменит название проекта или дефолтную ставку.
Практичная шапка счёта включает:
- Номер счёта (уникальный, удобочитаемый)
- Дату выставления и дату оплаты
- Реквизиты плательщика (имя клиента, адрес для выставления счётов, налоговый идентификатор при необходимости)
- Примечания (инструкции по оплате, короткое спасибо)
- Валюта (и опционально сохранённый курс, если выставляете международно)
Держите итоги предсказуемыми. Subtotal — сумма строк. Затем применяйте скидку (фиксированную или в процентах), рассчитывайте налог (обычно с учётом скидки) и сохраняйте итоговую сумму. Сохраните точную налоговую ставку и значения скидки, чтобы при необходимости воспроизвести счёт.
Нумерация не обязана быть сложной. Выберите шаблон и придерживайтесь его: последовательная (000123), по году (2026-00123) или префикс клиента + номер (ACME-014). Последовательность важнее идеала.
Статусы должны фокусироваться на коммуникации и внутреннем контроле:
- Draft (редактируемый, не отправлен)
- Ready (итоги заблокированы)
- Sent (отправлен клиенту)
- Paid (платёж подтверждён)
- Overdue (просрочен)
- Void (аннулирован, сохраняется для истории)
Генерация брендированного PDF, который понятен клиенту
Хороший PDF отвечает на два вопроса: что выставлено и как платить. Генерируйте PDF из записи Invoice (а не из сырых записей времени), чтобы документ всегда соответствовал номеру, итогам и статусу.
Большинство клиентов ожидают одни и те же блоки:
- Шапка с вашим названием, номером счёта и датой
- Данные клиента (компания, контакт, адрес для выставления счётов, налоговый ID при необходимости)
- Позиции (описание, количество или часы, ставка, сумма позиции)
- Итоги (subtotal, налог, скидка, общая сумма)
- Условия оплаты (дата оплаты, доступные способы, примечание о просрочке, если используется)
Брендинг важен, но читаемость важнее. Используйте один акцентный цвет, чистый шрифт и сделайте итоги легко сканируемыми.
Проблемы в макете проявляются на реальных данных. Тестируйте на длинных описаниях и более чем на 30 позициях. Убедитесь, что заголовки колонок повторяются на новых страницах, а блок итогов не разрывается.
Если вы генерируете PDF в AppMaster, храните файл (или ссылку на хранилище) в записи Invoice с временной меткой и версией. Тогда легко заново отправить именно тот документ, который видел клиент.
Пошаговый план сборки (no-code рабочий процесс)
Определите, что будет «источником правды». Записи времени — сырые факты. Счета — снимок, который вы можете отправить и потом аудировать.
1) Сначала модель данных
Создайте таблицы и связи, затем добавьте несколько полей качества, когда базис устойчив:
- Clients
- Projects
- Time Entries
- Invoices
- Invoice Lines
2) Постройте два простых экрана
Держите интерфейс минимальным:
- Форма записи времени: проект, дата, длительность, заметки, сохранить
- Просмотр счёта для ревью: клиент, период, позиции, итоги, статус
Веб‑интерфейса обычно достаточно для администрирования и проверок. Мобильные экраны добавляйте позже для учёта на ходу.
3) Автоматизируйте логику свёртки
Постройте поток: выбрать клиента + период, получить незабилованные записи, сгруппировать их, создать строки счёта. Отмечайте записи как выставленные только после того, как счёт утверждён или переведён в Ready.
4) Генерация и сохранение PDF
Добавьте действие «Generate PDF», которое подставляет шапку счёта, данные клиента и позиции в шаблон и сохраняет результат в записи Invoice.
Пример: от еженедельных логов до счёта, готового к отправке клиенту
Агентство из трёх человек работает с клиентом Northstar Co и выставляет счета по двум проектам за две недели: Website Refresh и Monthly Support. Команда: Alex (дизайн), Priya (разработка) и Sam (PM). Все логируют время ежедневно, выбирая клиента, проект, дату и короткую заметку.
Каждый день записи сохраняются как Draft. В пятницу Sam открывает экран ревью, фильтрованный по «Эта неделя, Northstar Co». Он исправляет две заметки («Homepage hero» вместо «Hero»), подтверждает billable vs non-billable и блокирует неделю.
Вот пример записей за неделю:
| Date | Person | Project | Hours | Note |
|---|---|---|---|---|
| Mon | Priya | Website Refresh | 2.5 | Header layout fixes |
| Tue | Alex | Website Refresh | 3.0 | New homepage mock |
| Tue | Sam | Monthly Support | 1.0 | Client call |
| Wed | Priya | Website Refresh | 4.0 | Contact form logic |
| Thu | Alex | Monthly Support | 1.5 | Banner update |
| Thu | Priya | Monthly Support | 2.0 | Email template tweak |
| Fri | Sam | Website Refresh | 1.0 | QA and handoff |
Когда Sam нажимает «Create invoice», приложение сворачивает записи в позиции по простым правилам: группирует по проекту и ставке, суммирует часы и переносит краткое описание. В результате счёт имеет 3 строки:
| Line | Description | Qty | Rate | Amount |
|---|---|---|---|---|
| 1 | Website Refresh (Design) | 3.0 hrs | $120 | $360 |
| 2 | Website Refresh (Development/PM) | 7.5 hrs | $140 | $1,050 |
| 3 | Monthly Support | 4.5 hrs | $110 | $495 |
Система присваивает номер счёта (например, NS-2026-014), считает subtotal и tax, и ставит статус Ready. Ещё один клик — и генерируется брендированный PDF (логотип, адрес клиента, детали строк, итоги и примечания по оплате). После отправки статус меняется на Sent, а исходные записи времени помечаются как invoiced, чтобы их нельзя было выставить дважды.
Частые ошибки и как их избежать
Большинство проблем — не в арифметике, а в рабочем процессе.
Не блокировать выставленные записи. Если люди могут редактировать или заново выбирать те же записи для нового счёта, рано или поздно получится двойная оплата. Исправьте это ссылкой на счёт в каждой записи времени и скрывайте оплаченные записи из вида «готовые к выставлению».
Переписывание истории при изменении ставок. Если вы считаете только по «текущей» ставке проекта или пользователя, изменение ставки изменит старые счета. Копируйте фактическую ставку в rate_at_time каждой записи.
Правки утверждённого времени без следа. Добавьте поля «Approved by», «Approved at» и короткую заметку об изменениях после утверждения.
PDF, разрушающиеся на реальных данных. Длинные описания, много строк и большие числа стрессуют шаблон.
Быстрые исправления, которые предотвращают проблемы с макетом:
- Ограничьте длину описания и переносите переполнение в раздел заметок
- Разрешите перенос строк и тестируйте на 30+ строках
- Держите шапку компактной, чтобы таблице было место
- Используйте единый формат чисел (валюта, знаки после запятой)
Неясный поток статусов. Без правил счета отправляют дважды или не отправляют вовсе.
Простой и безопасный поток: Draft -> Ready -> Sent -> Paid. Разрешайте свёртку только в Draft и генерацию PDF только когда итоги заблокированы.
Короткий чек‑лист и практические следующие шаги
Перед отправкой счёта сделайте быстрый ревью. Это предотвращает основные ошибки: неверные итоги, недостающие данные и PDF, которые выглядят нормально на экране, но ломаются при печати.
Чек‑лист перед отправкой:
- Данные клиента заполнены (юридическое имя, адрес для выставления, правильный контакт)
- Период счёта корректен (даты начала и конца соответствуют работе)
- Итоги согласованы (subtotal, налог, общая сумма соответствуют записям, ставкам и правилам округления)
- Ничего не пропущено и не продублировано (ничего не осталось незабилованным, ничего не включено дважды)
- Операционные поля в порядке (уникальный номер счёта, правильный статус, PDF сохранён в счёте)
Затем просмотрите PDF с «глазами печати»: проверьте расположение логотипа, длинные адреса, переносы в таблице и разрывы страниц. Тестируйте короткий счёт (1–2 строки) и длинный (20+ строк).
Следующие шаги, когда основы устоят:
- Отправляйте счёта по email с единым шаблоном
- Подключите Stripe и автоматически помечайте счёта как Paid
- Добавьте права доступа, чтобы только нужные роли могли менять ставки, утверждать время или менять статусы
Если хотите быстро строить и итеративно менять без переписывания, AppMaster (appmaster.io) — практичный вариант для создания no-code приложения выставления счетов с реальной базой данных, бизнес‑логикой и генерацией PDF, с возможностью регенерации чистого исходного кода по мере изменения требований.
Если вы улучшите за неделю только одну вещь — сделайте так, чтобы «незабилованное время» было невозможно пропустить. Это сэкономит часы и защитит доход.
Вопросы и ответы
Начните с того, что у каждой записи времени есть проект, дата, продолжительность и короткое описание. Затем создайте счёт, выбрав клиента и период, подтяните только незанесённые в счёт записи, сгруппируйте их в позиции счёта и сгенерируйте PDF из снимка счёта.
Используйте пять сущностей: Client, Project, Time Entry, Invoice и Invoice Line. Поля держите минимальными, но обязательно включите rate_at_time в каждую запись времени и ссылку invoiced_invoice_id, чтобы история выставления счётов оставалась последовательной и исключалась двойная оплата.
Храните ставку, использованную во время работы, в каждой записи времени (например, rate_at_time). Значения по умолчанию могут храниться в проекте или у пользователя, но расчёт счёта всегда должен основываться на сохранённой ставке, чтобы старые счета не менялись при обновлении тарифов.
Выберите одно правило округления и придерживайтесь его, затем сделайте это прозрачным. Распространённый подход — округление каждой записи до 6-минутных интервалов (0.1 часа), потому что это легко проверять и итоговые суммы остаются предсказуемыми.
Используйте одно поле статуса на счёте и держите набор коротким: Draft, Ready, Sent, Paid (добавляйте Void только при необходимости отмен). Установите чёткие правила, например «сводка только в Draft» и «блокировка итогов в Ready», чтобы люди случайно не меняли то, что уже отправлено.
Ограничьте создание счёта только записями, где invoiced_invoice_id пусто, и устанавливайте это поле сразу при прикреплении записей к счёту. Также скрывайте оплаченные записи из представления «готовые к выставлению», чтобы одно и то же время нельзя было выбрать дважды.
Генерируйте PDF из записи счёта, а не из сырых записей времени, чтобы документ всегда соответствовал номеру счёта, итогам и статусу. Включите понятную шапку, данные клиента, позиции, итоги и инструкции по оплате. Тестируйте шаблон на длинных описаниях и на 30+ позициях, чтобы поймать проблемы с макетом.
Не удаляйте историю. Отсоедините затронутые записи времени от счёта (очистите ссылку на счёт), перестройте позиции и итоги и сохраните короткую запись об исправлении, чтобы позже можно было объяснить изменения, не теряя аудита.
Начинайте с ручного ввода: он быстро строится и легко корректируется. Таймер добавляет дополнительные кейсы (пропущенные остановки, правки, проблемы с устройствами), поэтому его лучше добавить после того, как основной процесс надёжен.
Сначала сделайте основной поток: захват времени, утверждение/блокировка, создание счёта из незанесённого времени и генерация PDF. Отложите налоги, мультивалютность, скидки и вложения, потому что они создают дополнительные крайние случаи и замедляют релиз.


