В организации часто печатают сметы и это множество файлов, но часто бывают ситуации когда последняя страница распечатанного документа содержит только подписи, но не содержит ни одной цифры стоимости, потому что все они остаются на предыдущем листе. Директора в такой ситуации обычно отказываются подписывать документы и у таких смет приходится перепечатывать последний лист. Типичный пример такой сметы показан на скриншоте ниже:
К исполнителю, который печатает сметы они поступают в виде обычного Эксель файла, который надо просто распечатать. Чтобы не просматривать перед печатью каждый файл было решено автоматизировать процесс и как-то автоматически определять - остаются ли на последнем листе только подписанты или есть хотя бы одна цифра?
Самым простым виделось сделать это, пользуясь средствами самого Excel. Для этого подходило Visual Basic для приложений (VBA) в Office.
Проблема
Сметы создаются в приложении ГРАНД-Смета, версия 2024.2 - это указывается в колонтитуле Эксель файла и, возможно, у этого приложения есть такая кнопка, чтобы сделать всё красиво и не делать так, чтобы на последнем листе оставались только подписи.
Но организация, которая составляет эти сметы, и передаёт их на печать к нам в другую организацию, похоже с этой кнопкой не знакома. Поэтому в Excel часто сталкивались с ситуацией, когда последняя страница содержит только строки подписи, а цифры цен отображается на предыдущей странице.
Такой макет может вызвать недовольство или отказ от подписи со стороны директоров, которые предпочитают, чтобы цена была на той же странице, что и подписи.
Решение
Сценарий VBA под названием «AdjustRowHeightsForSignaturePage» предназначен для обработки множества книг Excel, в том числе в текущем и во вложенных каталогах, и изменения высоты последних нескольких строк, чтобы гарантировать, что окончательная цифра цены и строки подписи появятся на одной странице. Эта корректировка предотвращает ситуацию, когда последняя страница сметы лишена цифр.
Подготовка Microsoft Excel
Убедитесь, что Microsoft Excel установлен. Включение вкладки «Разработчик» в Excel позволяет получить доступ к инструментам и функциям, связанным с разработкой, включая макросы, Visual Basic для приложений (VBA). Вот как включить вкладку «Разработчик» в Excel:
1. Запустите Excel на своем компьютере.
2. Перейдите к параметрам. В зависимости от вашей версии Excel действия могут незначительно отличаться:
➡️ Для Excel 2010 и более поздних версий: нажмите вкладку «Файл» в верхнем левом углу, затем выберите «Параметры» в нижней части меню.
➡️ Для Excel 2007: нажмите круглую кнопку Office в верхнем левом углу, затем нажмите «Параметры Excel» в нижней части меню.
3. В диалоговом окне «Параметры Excel» слева вы увидите список категорий. Найдите и нажмите «Настроить ленту» (для Excel 2010 и более поздних версий) или «Популярные» (для Excel 2007).
4. Найдите параметр «Разработчик» в списке справа в разделе «Основные вкладки». Убедитесь, что флажок рядом с «Разработчик» установлен.
4. Установив флажок «Разработчик», нажмите кнопку «ОК» в нижней части диалогового окна «Параметры Excel», чтобы сохранить изменения и закрыть диалоговое окно.
5. После того как вы включили вкладку «Разработчик», вы должны увидеть ее на ленте Excel в верхней части окна Excel вместе с другими вкладками, такими как «Главная», «Вставка» и т.д.
Сценарий VBA для изменения высоты последних строк, если это требуется
Перед любыми массовыми манипуляциями с файлами рекомендую создать резервные копии файлов Excel простым копированием каталогов.
Чтобы вставить сценарий VBA в Excel и выполнить его, выполните следующие действия:
1. Включите вкладку «Разработчик» (если она еще не включена).
2. Получите доступ к редактору Visual Basic:
Нажмите вкладку «Разработчик» на ленте Excel.
В группе «Код» нажмите «Visual Basic» (или нажмите ALT+F11).
3. Вставьте скрипт:
В окне редактора Visual Basic убедитесь, что ваша книга выбрана в окне Project Explorer обычно с именем «VBAProject (имя файла)».
Щелкните правой кнопкой мыши на имя проекта или любую существующую папку модуля.
Выберите «Вставка» > «Модуль» в контекстном меню.
Вставьте код VBA:
' Подробнее: https://habr.com/ru/articles/820249/
Sub AdjustRowHeightsForSignaturePage()
Dim FileSystem As Object
Dim HostFolder As String
Dim FileName As String
Dim wb As Workbook
Dim ws As Worksheet
Dim rng As Range
' Определить путь к папке
HostFolder = ThisWorkbook.Path
' Создать экземпляр FileSystemObject
Set FileSystem = CreateObject("Scripting.FileSystemObject")
' Рекурсивная функция для поиска во вложенных каталогах
ProcessFiles HostFolder, FileSystem
MsgBox "Обработка всех файлов завершена", vbInformation
End Sub
Sub ProcessFiles(ByVal folderPath As String, ByVal fs As Object)
Dim subFolder As Object
Dim file As Object
Dim ws As Worksheet
Dim lastRow As Long
Dim startRow As Long
Dim pageBreaks As HPageBreaks
Dim breakCount As Long
Dim lastPageBreakRow As Long
Dim i As Long
On Error GoTo ErrorHandler
' Обработка файлов в текущем каталоге
For Each file In fs.GetFolder(folderPath).Files
If LCase(file.Name Like "*.xlsx*") Then
' Открыть книгу
Dim wb As Workbook
Set wb = Workbooks.Open(file.Path)
' Цикл по каждому листу в книге
For Each ws In wb.Worksheets
ActiveWindow.View = xlPageBreakPreview
' Найти последнюю использованную строку на рабочем листе, где 2 номер столбца
lastRow = ws.Cells(ws.Rows.Count, 2).End(xlUp).Row
' MsgBox "Последняя использованная строка в столбце 2 на рабочем листе: " & lastRow
' Определить начальную строку последних 20 строк
startRow = lastRow - 20
If startRow < 1 Then startRow = 1 ' Убедитесь, что начальная строка не меньше 1
' MsgBox "Начальная строка последних 20 строк: " & startRow
' Получить горизонтальные разрывы страниц
Set pageBreaks = ws.HPageBreaks
breakCount = 0
' Подсчитать количество разрывов документа в пределах последних 15 строк
' MsgBox "Количество разрывов документа: " & pageBreaks.Count
For i = 1 To pageBreaks.Count
' MsgBox "Разрыв страницы " & i & " находится в строке " & pageBreaks(i).Location.Row & vbNewLine & "Значение lastRow " & lastRow & " - 15 = " & lastRow - 15
If pageBreaks(i).Location.Row > lastRow - 14 Then
breakCount = breakCount + 1
End If
Next i
' Если последние 15 строк начинаются на новой странице с менее чем 15 строками, изменить высоту последних 20 строк
If breakCount > 0 And breakCount < 15 Then
For i = startRow To lastRow
ws.Rows(i).RowHeight = 25
Next i
MsgBox "Высота последних строк изменена для файла " & file.Name & vbNewLine & file.Path
End If
Next ws
' Сохранить и закрыть книгу
wb.Save
wb.Close
End If
Next file
' Обработка вложенных папок
For Each subFolder In fs.GetFolder(folderPath).SubFolders
ProcessFiles subFolder.Path, fs
Next subFolder
Exit Sub
ErrorHandler:
MsgBox "Произошла ошибка: " & Err.Description, vbExclamation
End Sub
4. Запустите сценарий VBA:
➡️ Запуск макроса.Можете запустить его, перейдя на вкладку «Разработчик», нажав «Макросы», выбрав макрос и нажав «Выполнить».
➡️ Запуск из VB: Можете запустить ее непосредственно из редактора Visual Basic, поместив курсор внутри процедуры и нажав F5 или выбрав «Выполнить» > «Выполнить Sub / UserForm» из меню.
Готово
Теперь надо проверить результаты и убедится, что скрипт выполнил нужные действия и изменил высоту последних строк, где это необходимо в других книгах Excel.
Итоги
Использование сценариев VBA позволяет решить проблему, когда последняя страница содержит только строки подписи без цен. Зачастую это приводит к недовольству или прямому отказу подписывать документ. Чтобы решить эту проблему сценарий Visual Basic для приложений (VBA) в Office может гарантировать то, что этого не случится, для этого сценарий регулирует высоту последних строк.
Пошаговое руководство, изложенное в этой статье, дает инструмент, позволяющий за минуты сделать преобразование в сотнях документов и выполнить то, что в противном случае потребовало бы часов выполнения вручную.
Автор: Михаил Шардин,
10 июня 2024 г.
Комментарии (17)
Kahelman
10.06.2024 03:09+1Делюсь лайк-хаком: пишите письмо на одной странице с основными параметрами, пишите детали как в приложении 1.
Руководитель подписывает письмо а сама смета -по барабану.
Если надо очень официально-то все равно каждая страница внизу подписывается
empenoso Автор
10.06.2024 03:09+1Хороший совет, но в конце каждой сметы всё равно подписи ставят - там форма такая
Kahelman
10.06.2024 03:09+1Форму поменяйте. На многих документах подпись стоит на первом листе с пометкой «утверждаю».
wepp
10.06.2024 03:09+1Форма определена НПА, это не просто смета к КП. Да, на первом (титульном) листе подписи и печати выглядят солидно, но тут смысл в итоговых цифрах, поэтому вполне логично именно такое расположение подписи.
Kahelman
10.06.2024 03:09+1Есть ещё лайфх: посылаем по email и без подписи.
Весь загнивающий запад так работает. Подпись только под договором, детали по e-mail.
qyix7z
10.06.2024 03:09+1For Each ws In wb.Worksheets
ActiveWindow.View = xlPageBreakPreview
Перебор листов в книге не делает лист активным. Зачем в цикле каждый раз выполняется
ActiveWindow.View = xlPageBreakPreview
?
Лучше написатьws.DisplayPageBreaks = True
- это заставит эксель пересчитать разделение на страницы на каждом листе.Вообще, если директору так надо видеть сумму перед подписью, то я в таких случаях просто ставлю
HPageBreaks
над строкой с суммой и не надо строчки раздвигать.
necr0x
10.06.2024 03:09+1Обоже, я думал в Германии бюрократия, ан нет, в России)) в Германии достаточно отправить на электронку ангебот (ценовое предложение, в котором будет перечень услуг и цен за квадратный метр, а так же общее количество метров). И всё. Даже подпись не нужна ни с чьей стороны. Это и является официальным договором по ценам для объекта в контексте которого идёт переписка.
Есть конечно так называемый Verhandlungstermin на котором самой сутью встречи является не наличие подписи, а переговоры с целью понизить некоторые позиции. Таким образом цены координируются сторонами и уже в этой версии документа необходимы подписи обоих участников.
Но как можно подписывать смету не видя при этом всего перечня? Это звучит как какая-то формальность. Если ты подписываешь видя только итоговую сумму, то это чисто формальная подпись, в таком случае можно и не видя сумму подписать.
Идиоты))
Kahelman
10.06.2024 03:09«Безумие и отвага»
Сами себе проблемы создаём, потом их героически преодолеваем.
Все таки не ясно о какого уровня руководителе идёт речь. Если директор- то по идее он не должен подписывать сметы только договоры с приложениями.
Если начальник уровня отдела, то надо бы директору настучать ему по голове, чтобы на ровном месте проблему не создавали.
wepp
10.06.2024 03:09+1Речь про сметы в составе проектно-сметной документации на строительство.
Подпись можно и "электронно" поставить, но тут даже по оформлению будет выглядеть некрасиво, если подпись будет в отрыве от остального содержимого.
qyix7z
10.06.2024 03:09+1Если ты подписываешь видя только итоговую сумму, то это чисто формальная подпись, в таком случае можно и не видя сумму подписать.
Смысл в том, что подписывается один лист. Остальные листы ретивые исполнители могут заменить. Если на листе с подписями будет итоговая сумма, то хотя бы она останется неизменной.
В целом предложенное решение автором - костыль, так как проблема не в технической плоскости, а в административной. Если уж ты при подписании не доверяешь, то подписывай каждую страницу или требуй, чтобы сшивали документ.
enabokov
10.06.2024 03:09+2Ооо, у меня была такая проблема в Crystal Reports в 2007 году для банковского отчёта. Нормального решения в CR не было, и я как-то извратился. Не помню уже как. Вроде я вставлял принудительный page break при некоторых условиях, чтобы часть строк и Итого попадали на новую страницу. Форму поменять было нельзя, потому как она была утверждена ЦБ.
KEugene
10.06.2024 03:09+1Я знаю, как случайно поломать скрипт. На любой строке ниже "визульно" последней (383 на примере) в ячейку ввести пробел. Например, где-то на четырехсотой.
Если люди, создающие сметы, не способны сразу сделать нормальную разметку, то от них вполне можно ожидать подобных сюрпризов.
Наверное, в скрипт надо ввести проверку, что выявленная последняя строка содержит значимую информацию. Можно сцепить значения ячеек, удалить пробелы и проверить длину того, что останется. Ну и определить порог. Если длина больше, то продолжаем. Меньше-ошибку в лог и к следующему файлу.
Кстати, при массовой обработке лучше не использовать msgbox, а писать лог или в консоль, или в текстовик. Нельзя отойти от компьютера, постоянно требуется нажатие кнопки. А уже в конце полноценное уведомление, типа, Успешно обработано Х файлов, ошибок Y. Детали в логе.
qyix7z
10.06.2024 03:09+1Если люди, создающие сметы, не способны сразу сделать нормальную разметку, то от них вполне можно ожидать подобных сюрпризов.
Это не люди:
Сметы создаются в приложении ГРАНД-Смета, версия 2024.2 - это указывается в колонтитуле Эксель файла и, возможно, у этого приложения есть такая кнопка, чтобы сделать всё красиво и не делать так, чтобы на последнем листе оставались только подписи.
Но организация, которая составляет эти сметы, и передаёт их на печать к нам в другую организацию, похоже с этой кнопкой не знакома.
Не будет там пробела в 400й строке.
Про msgbox и логи согласен.
TomskDiver
Как я понимаю, на предпоследней странице получится что несколько последних строк больше по высоте? Как вариант можно просто HPageBreaks вставить свой где надо. Тогда высоты будут одинаковые, но предпоследний лист будет чуть-чуть не весь заполнен на бумаге.
empenoso Автор
Да, на последней странице несколько последних строк будут больше по высоте
Beast2040
Проще чуть уменьшить масштаб листа чтобы подписи влезли на полный лист.