У клиента было двадцать таблиц Excel и почта. На каждое коммерческое предложение уходило по два часа: открыть файл, вспомнить, какие цены были актуальны, пересчитать, сверстать в письмо, отправить. Мы с ним прогнали два круга — сначала шаблоны, потом скрипт. Итог: PDF генерируется за тридцать секунд, клиент меняет цены без меня.

Откуда растёт задача

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

Мы сели и разобрали задачу. Клиенту нужно было решение, которое:

  • принимает конфигурацию заказа — размеры, профиль, комплектация;
  • считает стоимость по актуальным ценам;
  • формирует PDF, который можно отправить клиенту.

Первый подход: статичные HTML-шаблоны

Я предложил начать с простого: HTML-шаблон с подстановкой данных через плейсхолдеры. Идея в том, чтобы хранить прайс отдельно, а при генерации предложения читать его и заполнять шаблон. Реализовали на handlebars — шаблонизатор, который принимает объект данных и возвращает готовый HTML.

Проект завёлся за два дня. Шаблон выглядел прилично, подстановка работала. Но на тестовых данных в сто позиций скрипт упал — количество строк в прайсе не влезало в разметку, числа округлялись криво, а при изменении формулы расчёта приходилось править и шаблон, и скрипт одновременно.

Клиент заметил ошибки и откатился на Excel. Мне пришлось пересмотреть подход.

Второй подход: скрипт с разделением данных и логики

Я разделил систему на три независимых слоя:

  • Конфигурация — JSON-файл с ценами, формулами, контактами. Меняется без кода.
  • Логика расчёта — Node.js-скрипт, который читает конфигурацию, принимает параметры заказа и формирует структурированный объект.
  • Шаблон вывода — HTML+Pug, который принимает объект из скрипта и рендерит PDF.

Результат: клиент работает только с конфигурацией. Если изменилась цена на профиль — правит один JSON-файл. Если изменилась формула расчёта — правлю только логику. Шаблон остаётся нетронутым.

Как это работает сейчас

Менеджер запускает скрипт, вводит параметры заказа — площадь, тип профиля, этаж,нужные работы. Скрипт читает актуальные цены, рассчитывает итоговую сумму, генерирует HTML и конвертирует в PDF. Весь процесс: около тридцати секунд.

Клиент получил ссылку на готовый PDF через час после первой встречи. Отработал три дня на реальных заказах — замечаний по качеству не было.

Когда шаблон достаточно, а когда нужен скрипт

Шаблон без скрипта подходит для статичных документов — когда прайс не меняется или меняется редко, а формат КП постоянен. Если номенклатура большая, цены обновляются часто и хочется автоматизировать рутину — скрипт экономит время уже на втором-третьем использовании.

Скрипт не заменит CRM или систему управления заказами. Для полного цикла — от заявки до счёта и отгрузки — нужна специализированная система. Но для задачи «быстро и красиво отправить коммерческое предложение» Node.js-скрипт — это быстро, дёшево и гибко.

Главное — не переусложнить. Мы начали с простого скрипта без базы данных и веб-интерфейса. Добавили их позже, когда бизнес клиента вырос и стало понятно, что ручной ввод данных — это узкое место.