Содержание
Менеджер открывает Word, копирует прошлый договор, вручную меняет реквизиты, название компании, сумму, срок. Потом проверяет — не забыл ли где-то старые данные. 30–40 минут на каждый документ, и это при условии что не было ошибок.
Автоматизация сокращает это до 30 секунд и полностью исключает ошибки. Разберём как это сделать.
1. Проблема ручного документооборота
Ручное создание документов — это не просто потеря времени. Это системная проблема которая стоит денег:
- Ошибки в реквизитах — неправильный ИНН, адрес или расчётный счёт могут сделать документ юридически недействительным
- Задержки — клиент ждёт договор часами пока менеджер не дошёл до задачи
- Несогласованность — разные менеджеры используют разные версии шаблонов
- Потеря документов — файлы в разных папках, нет единого архива
2. Подходы к автоматизации
Есть несколько способов автоматизировать создание документов — выбор зависит от задачи:
- python-docx — генерация Word-документов из шаблонов. Идеально если нужно сохранить форматирование Word
- Jinja2 + python-docx — продвинутый вариант с условиями и циклами в шаблоне
- WeasyPrint / ReportLab — генерация PDF из HTML или кода. Для красивых счетов и актов
- Google Docs API — если работаете в Google Workspace
- docxtpl — самый простой способ для Word-шаблонов с переменными
3. Автоматизация Word с python-docx
Самый частый сценарий — есть шаблон договора в Word, нужно подставить данные клиента. Используем библиотеку docxtpl которая расширяет python-docx шаблонизатором Jinja2.
Сначала подготовим шаблон — в Word-документе заменяем переменные данные на метки вида {{ переменная }}:
# Содержимое шаблона договора (contract_template.docx) # В Word-документе заменяем: # "ООО Ромашка" → {{ company_name }} # "7701234567" → {{ inn }} # "85 000 рублей" → {{ amount }} рублей # "30 дней" → {{ term }} дней
# pip install docxtpl from docxtpl import DocxTemplate from datetime import date import os def generate_contract(client_data: dict, output_path: str): """Генерация договора из шаблона""" doc = DocxTemplate('templates/contract_template.docx') # Контекст — данные для подстановки context = { 'contract_number': client_data['id'], 'contract_date': date.today().strftime('%d.%m.%Y'), 'company_name': client_data['company'], 'inn': client_data['inn'], 'kpp': client_data['kpp'], 'address': client_data['address'], 'director': client_data['director'], 'amount': f'{client_data["price"]:,.0f}'.replace(',', ' '), 'amount_words': amount_to_words(client_data['price']), 'term': client_data['term_days'], 'services': client_data['services'], # список услуг } doc.render(context) doc.save(output_path) return output_path # Использование client = { 'id': '2025-127', 'company': 'ООО Ромашка', 'inn': '7701234567', 'kpp': '770101001', 'address': 'г. Москва, ул. Ленина, 1', 'director': 'Иванов И.И.', 'price': 85000, 'term_days': 30, 'services': ['Разработка Telegram-бота', 'Интеграция с CRM'], } path = generate_contract(client, f'contracts/contract_{client["id"]}.docx') print(f'Договор создан: {path}')
4. Расширенные шаблоны с Jinja2
docxtpl поддерживает полный синтаксис Jinja2 прямо в Word-шаблоне. Можно использовать условия и циклы:
# В Word-шаблоне можно писать: # Условие — разные тексты для юрлиц и физлиц # {% if is_company %} # {{ company_name }}, ИНН {{ inn }} # {% else %} # {{ full_name }}, паспорт {{ passport }} # {% endif %} # Цикл — список услуг в таблице # {% for service in services %} # {{ loop.index }}. {{ service.name }} — {{ service.price }} ₽ # {% endfor %} # В Python-коде: context = { 'is_company': True, 'company_name': 'ООО Ромашка', 'services': [ {'name': 'Разработка бота', 'price': 50000}, {'name': 'Интеграция с CRM', 'price': 35000}, ] }
5. Конвертация в PDF
После генерации Word-документа часто нужен PDF. На сервере Linux это делается через LibreOffice:
import subprocess import os def docx_to_pdf(docx_path: str) -> str: """Конвертация DOCX в PDF через LibreOffice""" output_dir = os.path.dirname(docx_path) subprocess.run([ 'libreoffice', '--headless', '--convert-to', 'pdf', '--outdir', output_dir, docx_path ], check=True, capture_output=True) pdf_path = docx_path.replace('.docx', '.pdf') return pdf_path # Генерируем договор и конвертируем в PDF docx_path = generate_contract(client, 'contract.docx') pdf_path = docx_to_pdf(docx_path) print(f'PDF готов: {pdf_path}')
6. Автоматическая отправка документов
Финальный шаг — отправить готовый документ клиенту автоматически:
import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email import encoders def send_contract(client_email: str, contract_pdf: str, contract_num: str): msg = MIMEMultipart() msg['From'] = 'contracts@company.ru' msg['To'] = client_email msg['Subject'] = f'Договор №{contract_num} — Гиперсайт' body = f""" Здравствуйте! Направляем договор №{contract_num} для ознакомления и подписания. Документ во вложении. С уважением, Команда Гиперсайт +7 (922) 290-23-72 """ msg.attach(MIMEText(body, 'plain', 'utf-8')) # Прикладываем PDF with open(contract_pdf, 'rb') as f: part = MIMEBase('application', 'pdf') part.set_payload(f.read()) encoders.encode_base64(part) part.add_header( 'Content-Disposition', f'attachment; filename="Договор_{contract_num}.pdf"' ) msg.attach(part) with smtplib.SMTP_SSL('smtp.yandex.ru', 465) as server: server.login('contracts@company.ru', 'пароль_приложения') server.send_message(msg) print(f'Договор отправлен на {client_email}')
7. Полный workflow за 30 секунд
Собираем всё вместе — от данных в CRM до письма клиенту:
def process_deal(deal_id: int): """Полный workflow: сделка в CRM → договор → PDF → email""" # 1. Получаем данные из amoCRM amo = AmoCRM(AMO_DOMAIN, ACCESS_TOKEN) deal = amo.get_lead(deal_id) contact = amo.get_contact(deal['contact_id']) # 2. Генерируем договор contract_num = f'2025-{deal_id}' docx_path = generate_contract({ 'id': contract_num, 'company': contact['company'], 'inn': get_field(contact, 'ИНН'), 'price': deal['price'], 'term_days': 30, }, f'contracts/contract_{contract_num}.docx') # 3. Конвертируем в PDF pdf_path = docx_to_pdf(docx_path) # 4. Отправляем клиенту send_contract(contact['email'], pdf_path, contract_num) # 5. Обновляем сделку в CRM amo.update_lead(deal_id, { 'custom_fields_values': [{ 'field_code': 'CONTRACT_NUMBER', 'values': [{'value': contract_num}] }] }) print(f'Готово! Договор {contract_num} отправлен клиенту') # Запуск — менеджер нажимает кнопку в CRM или это триггерится автоматически process_deal(12345)
Нужна автоматизация документооборота под ключ?
Настраиваем автогенерацию договоров, актов и счетов с интеграцией CRM. От 25 000 ₽, срок 1–2 недели.
Получить оценку