Введение
Есть одна мебельная фабрика. Исторически у этой фабрики IT хозяйство было не очень развито и со временем накопилось множество внутренних сервисов для расчета материалов, нагрузки на станки, учета временных затрат работников, доставки и прочего. Исходя из этих расчетов составляется себестоимость продукции. Далее накладывается маржа, и идет расчет доставки и сборки, в зависимости от условий. Фабрика захотела объединить все сервисы в один, основанный на веб, чтобы все расчёты и результаты можно было видеть в одном месте. Было выбрано делать новую веб систему на фреймворке Symfony (PHP).
По задумке данные из разных Excel файлов и локальной базы данных должны стекаться туда, группироваться по проектам и красиво отображаться. Изначально не планировалось изменять какие-либо данные, только просматривать. Также заказчик не хотел полностью отказываться от Excel файлов и переносить формулы в новую систему. Да, это странно со стороны разработчика, но объяснимо со стороны бизнеса: формул очень много, и они очень старые и запутанные. Но они отлично работают и всех устраивают. Их анализ, перенос в новую систему, отладка, и обучение работников пользоваться новой системой не входило в планы и бюджет проекта.
Проблема
На этапе разработки, когда первые Excel файлы были загружены и красиво отображались таблицы с материалами и суммы, клиенту захотелось немного "поиграть" цифрами внутри системы. Вместо одного стола, "поставить" два и посмотреть как изменятся суммы материалов. Естественно, возник вопрос, что мы не можем пересчитать формулы в нашей системе, так как мы их не переносили. Вариант увеличивать итог пропорционально количеству не мог быть использован, так как это не было пропорциональное увеличение. Упрощенный пример: для изготовления стола нужна заготовка столешницы из которой можно сделать пять столов. Но если надо сделать шесть столов, то заготовок нужно уже две. Так же и доставка: если в грузовик влезает сто столов, то чтобы привести сто один стол нужно уже два грузовика. Excel всё это учитывал, а еще скидки для конкретных клиентов, разный расчет стоимости сборки и прочее, прочее.
Первая попытка — PhpSpreadsheet
Кажется встала невыполнимая задача - пересчитывать формулы, которых нет. Но как говорил мой первый наставник и шеф: "Мы можем сделать всё, для программиста нет ничего невозможного". Для импорта Excel файла я использовал библиотеку https://github.com/phpoffice/phpspreadsheet с помощью нее можно прочитать лист внутри файла и получить значение (как саму формулу так и ее результат) из любой ячейки.
Пример кода, как прочитать результат формулы из ячейки
use PhpOffice\PhpSpreadsheet\IOFactory; $spreadsheet = IOFactory::load('/path/file.xlsx'); $sheet = $spreadsheet->getSheetByName('Totals'); $value = $sheet->getCell('F18')->getCalculatedValue();
У этой библиотеки есть также функция задать значение в ячейку. То есть теоретически можно создать форму на сайте, например с полями "количество товара". При отправке формы, получить данные и поменять в файле количество товара но новое, рассчитать новые значения сумм после этого.
Скрытый текст
use PhpOffice\PhpSpreadsheet\IOFactory; $newQuantity = 5; $spreadsheet = IOFactory::load('/path/file.xlsx'); $sheet = $spreadsheet->getSheetByName('Products'); $sheet->setCellValue('D:5', $newQuantity);
Но на практике это не сработало - формулы не могли рассчитаться так как было много листов и перекрестных ссылок. PhpOffice\PhpSpreadsheet это не полноценный движок Excel а лишь библиотека для работы с готовым файлом. А значит, можно попробовать использовать полноценный движок. Что если установить на сервер headless LibreOffice и делать перерасчет формул там? Стал пробовать.
Вторая попытка — использовать настоящий движок Excel
Установил LibreOffice на сервер
sudo apt update sudo apt install -y libreoffice libreoffice-calc fonts-dejavu fontconfig
И все получилось!
Перерасчет формул в headless LibreOffice
use PhpOffice\PhpSpreadsheet\IOFactory; $newQuantity = 5; $spreadsheet = IOFactory::load('/path/file.xlsx'); $sheet = $spreadsheet->getSheetByName('Products'); $sheet->setCellValue('D5', $newQuantity); $writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); $writer->setPreCalculateFormulas(false); $writer->save('/path/file.xlsx'); $cmd = sprintf( 'HOME=/tmp libreoffice --headless --nologo --nofirststartwizard --calc --convert-to xlsx --outdir %s %s', escapeshellarg(dirname($absolutePath)), escapeshellarg($absolutePath) ); exec($cmd, $output, $code); if ($code !== 0) { throw new RuntimeException('LibreOffice recalculation failed'); } $updatedSpreadsheet = IOFactory::load('/path/file.xlsx'); $updatedSheet = $updatedSpreadsheet->getSheetByName('Totals'); $updatedValue = $updatedSheet->getCell('F18')->getCalculatedValue();
В итоге Excel так и остался внутри системы — но уже не как файл, из которого берём данные, а как движок бизнес-логики.
Вывод
Да, решение получилось немного необычным: веб-приложение на Symfony меняет входные данные в Excel, затем headless LibreOffice пересчитывает формулы, и система забирает обратно готовые результаты. На практике это занимает около 15 секунд. Но для пользователя, который делает расчёт проекта мебели, это вполне приемлемо. Ему важнее менять параметры и видеть результат.
Можно ли было переписать все формулы на PHP? Конечно. Но это заняло бы месяцы работы, большой бюджет и риск сломать давно работающую логику.
Наверное такой подход можно использовать в MVP где надо много менять формулы, и это должен делать не программист, а например менеджер или сам клиент.
Иногда подходящее решение - не переписать всё заново, а грамотно встроить существующий инструмент в новую систему. И в этот раз Excel оказался не пережитком прошлого, а вполне рабочим микросервисом для расчётов. Вместо того, чтобы бороться с существующим инструментом, проще признать: Excel уже является системой расчётов. И его можно использовать программно.
Комментарии (6)

purple_elephant
17.04.2026 09:58А это был Эксель чисто на формулах, без макросов, или vba уже так хорошо поддерживается что - заработало все само?

dimas846 Автор
17.04.2026 09:58У меня файлы были без макросов. Пишут, что LibreOffice имеет свой язык макросов, который частично совместим с vba, то есть простой скрипт может сработать, но рассчивать на полную совместимость нельзя.

WALL_E
17.04.2026 09:58Ничего необычного.
И еще. Если вы на сервере будете держать экземпляр "книги" все время в запущенном состоянии, что отъест немного памяти, то при каждом пересчете не будете тратить время на ее инициализацию. В результате пересчет будет длиться какие-то микросекунды.
IvanSTV
А теперь на тему как вижу этот бизнес-процесс я. Я как бы много-много занимался разработкой всяких макросов и процессов, которые на Экселе сидят, видел массу.
Эксель хорош гибкостью, но тем же и плох, потому что требует квалифицированного пользователя. Если в той же 1С еще надо умудриться все сломать (тем не менее, ломают все, что может сломаться), то в экселе ломается вообще все, к чему притрагивается пользователь, на раз.
Типично: в Эксель-файл пользователь вставляет список накладных из другого файла Эксель, макрос хватает данные из справочников, обрабатывает и влупляет в SAP нужные данные. Удаленный пользователь звонит, жалуется - не работает ни рожна, обрабатывает только одну накладную, и все. Я беру список, вставляю - все обрабатывается. Так и отвечаю. Через полдня - нет, не работает. Я опять проделываю ту же операцию. Все работает, те же самые накладные, которые у нее не работают. Перезаписываю файл, прошу заново открыть. Нет, не работает, только первая накладная. Прошу расшарить экран, залезаю к ней, ту же операцию провожу, все работает. "Покажи, как делала?". Она вместо диапазона из Эксель берет из письма строку с накладными через запятую, вставляет. Результат немного предсказуем. Причем уже успела нажаловаться начальнику, что у нее ничего не работает. С средним качеством владения инструментом в российских офисах, когда даже по видеоинструкции оператор не может сформировать банальную сводную таблицу, я бы строить на Экселе процессы не рекомендовал. Одно дело, когда таблицы курсируют между аналитиками и руководителями (причем последние в основном смотрят), а другое - когда они добираются до исполнителей (а они неизбежно добираются), и там уже свет туши.
Вообще, я бы настоял на переписывании всех формул. Почему? Потому что со временем в любой таблице, которую легко изменять, накапливаются ошибки - алгоритмов, архитектуры, часть процессов вообще теряют актуальность, а многие надо оптимизировать. Если никто не может логику таблиц описать, то такая таблица - жесточайший бизнес-риск, это ОГРОМНОЕ ПОЛЕ для ошибок и злоупотреблений. Коробка, которая выдает неясно на чем основанные результаты. Например, на одной работе обнаружилось, что себестоимость логистики год считалась в 10 раз меньше факта - ошибка распределения затрат, заложенная в формуле расчета. Причем обнаружилось случайно - кто-то просто протянул до конца формулу, и у маркетологов все распродажи ушли в минус. Стали ковыряться, обнаружили, что формулу никто год не протягивал, а строки добавлялись, и вообще вся формула неверна. Так что переписывание таких инструментов нужно в первую очередь бизнесу. Сломать обычно можно не "работающую" логику, а "криво и непонятно работающую логику", а потом заменить ее на понятную, задокументированную и защищенную от дурака логику. Нужно ли это делать на PHP или еще на чем - вопрос уже технический.
dimas846 Автор
Согласен на все 100% Excel как черный ящик это ужасно, с какой стороны не посмотри. Все это, конечно было объяснено заказчику. Но вот в реальной жизни бизнес не готов к большим изменениям. У них все хорошо работает (по их мнению). Вкладываться в переделку они не хотят. Я их прекрасно понимаю, и не мне их учить зарабатывать деньги и делать ИХ бизнес.
С технической стороны это получилось и работает! Клиент доволен. Со стороны этики профессии могут быть вопросы: но даже не могу сформулировать :))) Может, что решение ненадежное? Но нет же. Это обычный файл, открыл, отредактировал, сохранил (программно).
WALL_E
Почему то бытует мнение о повинности экселей во всех грехах как бизнеса так и разработчиков. Зачастую с обоих сторон собираются дилетанты бизнесовой логики. С другой стороны "разрабы", которые владеют средой по остаточному принципу. На выходе получается нечто неустойчивое ко многим отклонениям от единственно правильного сценария использования. Чтобы создать что либо на любом инструменте и получать крепкий результат - нужна высокая квалификация специалистов и затраты временные. А эксели здесь ни при чем. Это непревзойденный инструмент для малой автоматизации.