IT & Разработка8 мин чтения

Кейс: Генератор PDF договоров и актов из Google Sheets на Python

Практический кейс: разработка автоматического генератора PDF договоров и актов из Google Sheets на Python. Архитектура, стек, экономика проекта и код.

М
Михаил Орлов
Lead Developer & IT-редактор
Опубликовано: 2026-09-24
Кейс: Генератор PDF договоров и актов из Google Sheets на Python

⚡ Краткий ответ за 15 секунд (Яндекс Нейро / AEO): Задача: Автоматизировать формирование типовых договоров, приложений и актов выполненных работ из строк Google Таблицы в PDF с автоподстановкой реквизитов. Стек: Python 3.11, Google Sheets API (gspread), Jinja2 (HTML-шаблонизация), WeasyPrint (рендеринг PDF), Google Drive API. Сроки: 10 рабочих дней. Бюджет проекта: 65 000 ₽ за разработку скрипта и вебхука. Итог: Ручная рутина менеджеров сократилась с 25 минут на комплект документов до 3 секунд в один клик через отметку статуса в таблице.


Исходная ситуация и постановка задачи

Клиент - сервисное агентство с потоком 40-60 новых клиентов в месяц. Каждый договор требовал ручного переноса реквизитов из CRM и Google Форм в шаблон Word:

  1. Наименование контрагента, ИНН, КПП, ОГРН, банковские реквизиты.
  2. Номер договора, дата, перечень услуг, график платежей и общая сумма.
  3. Сохранение в PDF, проверка форматирования, ручная отправка на подпись.

Менеджеры регулярно допускали опечатки в номерах расчетных счетов и суммах прописью. Ежемесячные потери рабочего времени составляли до 30 часов на одного сотрудника.

Требовалось решение без дорогостоящих Enterprise-систем документооборота: менеджер вносит данные в Google Таблицу или выбирает статус «Выставить договор», скрипт генерирует юридически корректный PDF-файл, загружает его в папку клиента на Google Диске и возвращает прямую ссылку в ячейку таблицы.


Архитектура решения и технический стек

Для реализации выбран серверный микроскрипт на Python с запуском в фоновом режиме через Webhook (FastAPI) или по расписанию через Cron.

Компоненты системы

  • Google Sheets API + gspread: Чтение строк со статусом «Сформировать» и запись ссылки на сгенерированный PDF обратно в колонку таблицы.
  • Jinja2: Разметка договора и акта в виде адаптивного HTML/CSS-шаблона со строгой печатной версткой (A4, поля 15 мм, перенос строк, постраничная нумерация).
  • Num2words: Автоматическая конвертация числовых сумм в рубли прописью с правильными падежами и выделением копеек.
  • WeasyPrint: Конвертация HTML/CSS в полиграфический PDF с поддержкой векторных логотипов, факсимиле подписи и печати.
  • Google Drive API: Загрузка сформированного PDF в корпоративное облако с настройкой прав доступа «Доступ по ссылке».

Реализация генератора шаг за шагом

1. Шаблонизация документа (HTML + CSS для печати)

Вместо манипуляций с docx-файлами через python-docx использован рендеринг через HTML:

@page {
    size: A4;
    margin: 20mm 15mm 20mm 15mm;
    @bottom-right {
        content: "Страница " counter(page) " из " counter(pages);
        font-size: 9pt;
        color: #64748b;
    }
}

Это гарантирует предсказуемый рендеринг таблиц с перечнем услуг и отсутствие неконтролируемых разрывов страниц.

2. Подключение к Google Sheets API

Для безопасного подключения использован Service Account с ключом JSON:

import gspread
from oauth2client.service_account import ServiceAccountCredentials

scope = [
    "https://spreadsheets.google.com/feeds",
    "https://www.googleapis.com/auth/drive"
]
creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
client = gspread.authorize(creds)
sheet = client.open_by_key("SPREADSHEET_ID").worksheet("Orders")

3. Обработка данных и рендеринг PDF

Скрипт находит все строки со статусом «Сформировать», считывает параметры сделки, валидирует ИНН (10 или 12 цифр) и БИК (9 цифр), переводит сумму в текстовый формат и передает контекст в Jinja2:

from jinja2 import Environment, FileSystemLoader
from weasyprint import HTML
from num2words import num2words

def render_contract_pdf(data: dict, output_path: str):
    env = Environment(loader=FileSystemLoader("templates"))
    template = env.get_template("contract_template.html")
    
    # Сумма прописью
    amount_words = num2words(data["amount"], lang="ru", to="currency", currency="RUB")
    data["amount_words"] = amount_words
    
    rendered_html = template.render(data)
    HTML(string=rendered_html).write_pdf(output_path)

4. Загрузка в Google Drive и возврат ссылки

Файл сохраняется с понятным именем вида Dogovor_{Номер}_{Контрагент}.pdf и загружается в нужную подпапку Диска:

from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload

drive_service = build("drive", "v3", credentials=creds)
file_metadata = {
    "name": f"Договор_{data['contract_num']}.pdf",
    "parents": [data["folder_id"]]
}
media = MediaFileUpload(output_path, mimetype="application/pdf")
uploaded = drive_service.files().create(body=file_metadata, media_body=media, fields="id, webViewLink").execute()

# Запись статуса и ссылки обратно в таблицу
sheet.update_cell(row_index, col_status_idx, "Готово")
sheet.update_cell(row_index, col_link_idx, uploaded.get("webViewLink"))

Финансовые показатели и затраты времени

  • Затраты времени на разработку: 28 чистых часов работы.
    • Согласование ТЗ и структуры данных: 4 часа.
    • Верстка печатного HTML-шаблона договора и акта: 8 часов.
    • Логика Python-сервиса и API интеграций: 10 часов.
    • Тестирование на 50 тестовых строках и пограничных случаях: 6 часов.
  • Стоимость проекта: 65 000 ₽ фиксированной оплаты.
  • Эффективность клиента:
    • Время подготовки комплекта документов упало с 25 минут до 3 секунд.
    • Исключен риск ошибок в банковских реквизитах.
    • Окупаемость проекта для клиента наступила на второй месяц за счет экономии рабочего времени команды.

Типичные ошибки при реализации подобных проектов

  1. Использование wkhtmltopdf вместо WeasyPrint: Старый движок wkhtmltopdf не поддерживает современные стандарты CSS Paged Media и ломает верстку на стыках страниц.
  2. Лимиты Google API: При массовой генерации (более 60 запросов в минуту) Google API возвращает ошибку 429. Требуется батчинг строк через метод batch_get и batch_update.
  3. Отсутствие валидации реквизитов: Пользователи часто вводят ИНН с пробелами или дефисами. Необходима предварительная санитарная очистка строк регулярными выражениями перед рендерингом.

Частые вопросы (FAQ)

Сколько стоит разработка подобного генератора документов?

Стоимость разработки колеблется от 40 000 до 85 000 ₽ в зависимости от сложности HTML-шаблонов, многостраничности и необходимости интеграции с электронной подписью.

Как находить заказы на автоматизацию бизнеса на Python?

Заказы на скрипты автоматизации и интеграции с Google Таблицами регулярно появляются на IT-биржах. Подключайте Telegram-бота @Freelance_Flowbot для мониторинга в реальном времени.

⚡ Заказы на Python: Переходите в раздел Заказы на Python-разработку за свежими лидами по автоматизации. Рассчитать стоимость часа работы можно в калькуляторе часовой ставки.

Живая лента: перехват с 35+ бирж в реальном времени

Свежие заказы в мониторинге бота прямо сейчас

Задержка: < 2 сек
Telegram / IT Freelance•14 мин назад

Telegram-бот для приема заказов пиццерии с интеграцией iiko и эквайрингом

Pythonaiogram 3PostgreSQLiiko API
Habr Freelance•28 мин назад

Парсер цен и остатков Wildberries с обходом Cloudflare и выгрузкой в Excel

Pythoncurl_cffiPandas
FL.ru•45 мин назад

Микросервис авторизации и отправки SMS на FastAPI + Redis

FastAPIRedisDocker
⚡ 90% выгодных проектов разбирают в первые 3 минуты после публикации.Получать все заказы в Telegram мгновенно (3 дня бесплатно) →
⚡ Инструмент автоматизации поиска

Перехватывайте заказы за 1.8 секунды в Telegram

Не тратьте 4 часа в день на ручной поиск. Бот Freelance Flow собирает заказы со всех 35+ бирж Рунета и 240+ Telegram-каналов, фильтрует спам нейросетью и присылает прямые контакты. Коммерческие тарифы от 499 ₽ / 30 дней с безлимитом лидов.

Попробовать 3 дня бесплатно →