Часть 2. Соберите ежедневный отчёт одной кнопкой: VBA сам копирует данные, оформляет таблицу и готовит файл к отправке. Подробно разбираем реальный VBA-сценарий для Excel: как одной кнопкой собрать ежедневный отчёт, скопировать нужные строки, проставить дату, оформить таблицу и получить готовый лист для отправки руководителю или клиенту. С готовым кодом, пошаговым разбором и вариантами применения.
Когда отчёт нужно собирать каждый день, проблема почти никогда не в самом Excel. Проблема в повторяющемся ручном ритуале. Открыть файл. Найти нужные строки. Отфильтровать таблицу. Скопировать только актуальные данные. Перенести на новый лист. Проверить, не захватились ли лишние столбцы. Подтянуть шапку. Выделить заголовки. Подправить ширину. Убедиться, что дата стоит правильно. Потом ещё раз посмотреть, не ушла ли куда-нибудь пустая строка, потому что именно она любит появляться в самый неподходящий момент.
И всё это ради отчёта, который по своей сути меняется не так уж сильно. Меняются данные, даты, статусы, суммы, сотрудники, но сам процесс один и тот же. День за днём. Неделя за неделей. И вот здесь Excel либо остаётся послушной тетрадью, либо превращается в рабочий инструмент, который делает рутину сам.
Вторая часть серии как раз об этом. Не о красивом трюке, а о вещи, которая ощущается почти физически: нажал кнопку — и у тебя готов дневной отчёт в нормальном виде, а не полуфабрикат, собранный на скорую руку между звонком и сообщением в рабочем чате.
Реальная рабочая ситуация, в которой ручной отчёт начинает раздражать
Представим обычный день в офисе, отделе продаж, логистике, сопровождении или сервисе. Есть рабочая таблица, куда в течение дня заносятся сделки, заявки, обращения, оплаты, отгрузки, задачи, статусы. Вечером или утром нужно отправить руководителю сводку: что сделано сегодня, какие строки актуальны, кто в работе, что просрочено, что завершено.
Если делать это руками, почти всегда используют один и тот же путь. Фильтруют по дате. Иногда ещё по статусу. Потом копируют отобранные строки на отдельный лист. Вручную подписывают заголовок. Подправляют оформление, чтобы отчёт выглядел не как аварийный черновик. А потом отправляют файл или скриншот.
На бумаге звучит терпимо. На практике этот процесс съедает внимание. Самое неприятное даже не время. Самое неприятное — мелкие ошибки. Скопировали не ту дату. Захватили лишнюю строку. Забыли обновить заголовок. Утащили старое форматирование. Не отцентрировали таблицу. Отправили отчёт, а там в середине торчит вчерашняя запись. Excel в таких местах не виноват. Это чистая цена ручной рутины.
И вот в какой-то момент появляется здравая мысль: если структура отчёта одна и та же, почему я вообще собираю его руками?
Ответ простой: потому что макрос ещё не написан. Значит, пора написать.
Где этот сценарий особенно полезен
Сценарий 1. Отчёт по продажам или клиентским задачам
Есть таблица, где фиксируются обращения, счета, звонки, статусы, оплаты, встречи. Руководителю нужен ежедневный отчёт только за текущий день. VBA-макрос отбирает все строки с сегодняшней датой, переносит их на новый лист, оформляет таблицу, подписывает дату и делает отчёт готовым к отправке.
Сценарий 2. Отчёт по логистике, складу или производству
Есть журнал отгрузок, сборок, доставок или выполненных операций. Вечером нужно быстро собрать всё, что прошло за день: номер заказа, клиент, исполнитель, статус, комментарий. Макрос делает ровно это. Причём без риска забыть одну строку, потому что усталость к вечеру — не миф, а обычная человеческая реальность.
Именно такие сценарии особенно хорошо работают в статьях: читатель видит не абстрактную автоматизацию, а знакомую боль, с которой сталкивается в живой работе.
Как обычно пытаются решить это формулами — и почему этого часто мало
Конечно, можно собрать отчёт и формулами. Например, если у вас современная версия Excel, можно использовать:
=ФИЛЬТР(A2:G500;A2:A500=СЕГОДНЯ())
Иногда этого достаточно. Если нужен просто вывод строк в отдельном диапазоне, формула работает. Но на практике быстро всплывают ограничения.
- Во-первых, нужно не просто увидеть строки, а получить оформленный отчёт на отдельном листе.
- Во-вторых, часто требуется не просто фильтрация, а ещё и подготовка внешнего вида: заголовок, шапка, ширина столбцов, выделение заголовков, готовность к печати или отправке.
- В-третьих, отчёт нередко нужен в виде законченного блока, а не «живой формулы», которая тянет данные и может измениться от любого движения в исходной таблице.
Формула — хороший слесарный ключ. Но тут уже нужен не один ключ, а целый собранный механизм. Для этого VBA подходит куда лучше.
Что именно будет делать наш макрос
Берём рабочий лист с общей таблицей. Предположим, он называется Данные.
В колонке A у нас дата. В остальных колонках — клиент, задача, сумма, ответственный, статус и комментарий.
Макрос делает следующее:
- находит все строки, где дата равна сегодняшнему дню;
- создаёт новый лист с названием вроде Отчёт_14.03.2026;
- копирует туда заголовки;
- переносит только нужные строки;
- добавляет сверху название отчёта;
- оформляет шапку;
- выравнивает столбцы;
- подсвечивает заголовки;
- сообщает, что отчёт готов.
То есть он делает не только выборку, но и маленькую упаковку. А упаковка в Excel — штука недооценённая. Один и тот же набор данных можно отправить как сырой комок или как нормальный читаемый отчёт. Люди обычно благодарят именно за второе.
Как должна выглядеть исходная таблица
Для примера возьмём такую структуру на листе Данные:
A — Дата
B — Клиент
C — Задача
D — Сумма
E — Ответственный
F — Статус
G — Комментарий
Главное условие: в столбце A должны быть реальные даты, а не текст, похожий на даты. Это важный момент. Excel любит делать вид, что понял пользователя, но если дата хранится как текст, сравнение работает криво. А кривой отчёт никому не нужен.
Готовый VBA-код: кнопка для формирования ежедневного отчёта
Ниже — полный рабочий макрос. Его можно вставить в стандартный модуль и повесить на кнопку.
Sub СформироватьЕжедневныйОтчёт()
Dim wsSource As Worksheet*
Dim wsReport As Worksheet*
Dim lastRow As Long*
Dim lastCol As Long*
Dim i As Long*
Dim reportRow As Long*
Dim reportName As String*
Dim currentDate As Date*
Dim sh As Worksheet*
Dim sheetExists As Boolean*
Set wsSource = ThisWorkbook.Worksheets("Данные")*
currentDate = Date*
reportName = "Отчёт_" & Format(currentDate, "dd.mm.yyyy")*
sheetExists = False*
For Each sh In ThisWorkbook.Worksheets*
If sh.Name = reportName Then*
sheetExists = True*
Application.DisplayAlerts = False*
sh.Delete*
Application.DisplayAlerts = True*
Exit For*
End If*
Next sh*
Set wsReport = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))*
wsReport.Name = reportName*
lastRow = wsSource.Cells(wsSource.Rows.Count, 1).End(xlUp).Row*
lastCol = wsSource.Cells(1, wsSource.Columns.Count).End(xlToLeft).Column*
wsReport.Range("A1:G1").Merge*
wsReport.Range("A1").Value = "Ежедневный отчёт за " & Format(currentDate, "dd.mm.yyyy")*
wsReport.Range("A1").Font.Bold = True*
wsReport.Range("A1").Font.Size = 14*
wsReport.Range("A1").HorizontalAlignment = xlCenter*
wsSource.Range(wsSource.Cells(1, 1), wsSource.Cells(1, lastCol)).Copy Destination:=wsReport.Cells(3, 1)*
reportRow = 4*
For i = 2 To lastRow*
If Int(wsSource.Cells(i, 1).Value) = currentDate Then*
wsSource.Range(wsSource.Cells(i, 1), wsSource.Cells(i, lastCol)).Copy Destination:=wsReport.Cells(reportRow, 1)*
reportRow = reportRow + 1*
End If*
Next i*
If reportRow = 4 Then*
wsReport.Range("A4").Value = "За текущую дату записей не найдено."*
End If*
With wsReport.Range(wsReport.Cells(3, 1), wsReport.Cells(3, lastCol))*
.Font.Bold = True*
.Interior.Color = RGB(217, 225, 242)*
.HorizontalAlignment = xlCenter*
End With*
wsReport.Columns.AutoFit*
wsReport.Rows("1:3").RowHeight = 24*
MsgBox "Ежедневный отчёт сформирован.", vbInformation*End Sub
Что здесь происходит — подробно, без магии и без шаманства
Вот теперь разберём макрос по частям. Именно в таких местах человек начинает чувствовать, что VBA — это не чёрный ящик, а понятная логика.
1. Объявляем переменные
Сначала мы создаём набор переменных, в которых Excel будет хранить всё необходимое во время работы макроса.
wsSource — рабочий лист с исходной таблицей.
wsReport — лист, куда будет собран отчёт.
lastRow — последняя заполненная строка.
lastCol — последний используемый столбец.
i — счётчик цикла.
reportRow — строка, в которую будет вставляться очередная запись отчёта.
reportName — имя листа отчёта.
currentDate — текущая дата.
sh — переменная для перебора листов книги.
sheetExists — признак того, что лист с таким именем уже существует.
Это та самая арматура, без которой бетон не держит форму.
2. Указываем исходный лист
Set wsSource = ThisWorkbook.Worksheets("Данные")
Макрос ищет лист с именем Данные. Если у тебя лист называется Журнал, Продажи, Заявки или Свод, меняешь только это имя.
3. Берём текущую дату
currentDate = Date
Здесь всё просто: VBA берёт сегодняшнюю дату с компьютера пользователя.
Это значит, что макрос каждый день будет строить актуальный отчёт автоматически. Не нужно вручную прописывать дату. Мелочь, но именно из таких мелочей и складывается ощущение «всё работает само».
4. Формируем имя листа отчёта
reportName = "Отчёт_" & Format(currentDate, "dd.mm.yyyy")
Получается имя вроде Отчёт_14.03.2026.
Это удобно по двум причинам. Во-первых, сразу видно, за какой день отчёт. Во-вторых, такие листы легко искать позже, если нужно поднять историю.
5. Проверяем, не существует ли уже лист с таким именем
sheetExists = FalseFor Each sh In ThisWorkbook.Worksheets
If sh.Name = reportName Then*
sheetExists = True*
Application.DisplayAlerts = False*
sh.Delete*
Application.DisplayAlerts = True*
Exit For*
End If*Next sh
Здесь макрос перебирает все листы книги и ищет лист с таким же названием.
Если такой лист уже существует, он удаляется. Это важная часть сценария. Она нужна, чтобы при повторном запуске в тот же день не получился зоопарк из дублей и старых версий. Один день — один актуальный отчёт.
Application.DisplayAlerts = False временно отключает системное предупреждение Excel при удалении листа. Иначе программа начнёт лишние разговоры с пользователем, а нам нужен рабочий ритм, а не семейная терапия с диалоговыми окнами.
6. Создаём новый лист для отчёта
Set wsReport = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Worksheets(ThisWorkbook.Worksheets.Count))wsReport.Name = reportName
Создаётся новый лист в конце книги. Сразу после этого ему присваивается нужное имя.
7. Определяем размер исходной таблицы
lastRow = wsSource.Cells(wsSource.Rows.Count, 1).End(xlUp).RowlastCol = wsSource.Cells(1, wsSource.Columns.Count).End(xlToLeft).Column
Первая строка ищет последнюю заполненную строку в столбце A.
Вторая — последний заполненный столбец в первой строке.
Так макрос работает с живой таблицей, а не с жёстко прибитым диапазоном. Сегодня у тебя 50 строк, завтра 280 — код не нужно переписывать.
8. Делаем заголовок отчёта
wsReport.Range("A1:G1").MergewsReport.Range("A1").Value = "Ежедневный отчёт за " & Format(currentDate, "dd.mm.yyyy")wsReport.Range("A1").Font.Bold = TruewsReport.Range("A1").Font.Size = 14wsReport.Range("A1").HorizontalAlignment = xlCenter
Здесь макрос объединяет верхние ячейки, записывает название отчёта, делает его жирным, увеличивает размер шрифта и выравнивает по центру.
Это уже оформление. Оно не меняет данные, но делает итоговый лист похожим на нормальный рабочий документ, а не на копию куска таблицы.
9. Копируем заголовки столбцов
wsSource.Range(wsSource.Cells(1, 1), wsSource.Cells(1, lastCol)).Copy Destination:=wsReport.Cells(3, 1)
Первая строка исходной таблицы переносится на третью строку отчёта.
Почему не на первую? Потому что первая строка занята красивым заголовком. Вторая остаётся воздухом. Такая мелкая пауза в макете делает лист читаемее.
10. Определяем первую строку для данных
reportRow = 4
Данные начнут вставляться с четвёртой строки. Первая — заголовок отчёта. Вторая — отступ. Третья — шапка таблицы. Четвёртая — начало данных.
11. Перебираем все строки исходной таблицы
For i = 2 To lastRow
Начинаем со второй строки, чтобы не трогать заголовки.
12. Отбираем только строки за сегодняшнюю дату
If Int(wsSource.Cells(i, 1).Value) = currentDate Then
Вот это сердце сценария.
Макрос смотрит на значение в столбце A и сравнивает его с текущей датой.
Функция Int здесь нужна не просто так. Иногда в ячейке дата хранится вместе со временем: например, 14.03.2026 15:42. Визуально человек видит только дату, а для Excel это уже число с дробной частью. Int отсекает время и оставляет только дату. Полезный и очень рабочий приём.
13. Копируем подходящую строку в отчёт
wsSource.Range(wsSource.Cells(i, 1), wsSource.Cells(i, lastCol)).Copy Destination:=wsReport.Cells(reportRow, 1)reportRow = reportRow + 1
Если дата совпала, вся строка копируется на лист отчёта. Затем счётчик строк увеличивается на единицу, чтобы следующая запись не перезаписала предыдущую.
14. Если данных нет — выводим понятное сообщение
If reportRow = 4 Then
wsReport.Range("A4").Value = "За текущую дату записей не найдено."*End If
Если ни одна строка не подошла, макрос не оставляет пустой лист, а честно пишет, что за текущую дату записей нет.
Это очень человеческий штрих. Пользователь не будет сидеть и гадать: код сломался или просто данных нет.
15. Оформляем шапку таблицы
With wsReport.Range(wsReport.Cells(3, 1), wsReport.Cells(3, lastCol))
.Font.Bold = True*
.Interior.Color = RGB(217, 225, 242)*
.HorizontalAlignment = xlCenter*End With
Здесь заголовки столбцов становятся жирными, получают светлую заливку и выравнивание по центру.
Такой лист уже не стыдно отправить руководителю, клиенту или в общий чат команды.
16. Подгоняем ширину столбцов и высоту строк
wsReport.Columns.AutoFitwsReport.Rows("1:3").RowHeight = 24
Столбцы автоматически подстраиваются под содержимое. Верхние строки получают нормальную высоту.
17. Показываем итоговое сообщение
MsgBox "Ежедневный отчёт сформирован.", vbInformation
Финальный сигнал: всё готово, отчёт собран.
Почему этот макрос ценнее, чем кажется на первый взгляд
На поверхности — просто удобная кнопка. Но если смотреть шире, она даёт сразу несколько выгод.
- Во-первых, убирает повторяющуюся ручную работу. А именно повторяющаяся работа обычно сильнее всего выматывает.
- Во-вторых, сокращает риск ошибок. Когда отчёт собирается руками, ошибка — это не исключение, а обычный спутник спешки.
- В-третьих, делает результат единообразным. Сегодня отчёт собрал один сотрудник, завтра другой, а выглядит он одинаково аккуратно.
- В-четвёртых, создаёт ощущение профессионального роста. И вот это для серии 7 особенно важно. Читатель не просто скопировал кусок кода. Он сделал инструмент, который выглядит как реальное рабочее решение, а не как учебный пример из тетради.
Как изменить этот макрос под свою задачу
Теперь самое полезное — адаптация.
Если дата стоит не в столбце A
В коде у нас проверка идёт по первой колонке:
If Int(wsSource.Cells(i, 1).Value) = currentDate Then
Если дата у тебя находится, например, в столбце C, нужно заменить 1 на 3.
Получится так:
If Int(wsSource.Cells(i, 3).Value) = currentDate Then
Если нужно делать отчёт не за сегодня, а за вчера
Тогда вместо строки:
currentDate = Date
поставь:
currentDate = Date - 1
Это полезно, если отчёт формируют утром за прошедший день.
Если нужен отчёт только по статусу «Выполнено»
Можно добавить второе условие. Например, если статус находится в столбце F:
If Int(wsSource.Cells(i, 1).Value) = currentDate And wsSource.Cells(i, 6).Value = "Выполнено" Then
Теперь в отчёт будут попадать только выполненные записи за текущую дату.
Если нужен отчёт по конкретному сотруднику
Допустим, имя сотрудника находится в столбце E. Тогда можно добавить ещё одно условие:
If Int(wsSource.Cells(i, 1).Value) = currentDate And wsSource.Cells(i, 5).Value = "Иванов" Then
И отчёт будет уже персональным.
Если в отчёте не нужны все столбцы
В текущей версии копируется вся строка. Это удобно для универсальности. Но если тебе нужен только набор ключевых колонок, лучше сделать отдельную версию макроса, где данные переносятся по столбцам выборочно. Например: дата, клиент, сумма, статус.
Это особенно полезно, если исходная таблица перегружена служебными полями.
Ещё два живых варианта применения
Чтобы статья работала не только на одну профессию, а на разные сценарии, важно показать шире.
Для бухгалтера или финансового специалиста
Можно собирать ежедневный отчёт по платежам: поступления, контрагенты, суммы, комментарии, статус сверки. Нажал кнопку — получил готовую таблицу за день.
Для администратора, координатора или HR
Можно собирать отчёт по интервью, заявкам, выходам сотрудников, обращениям, задачам на день. Особенно удобно, когда информации много, а отправлять сводку нужно регулярно и без лишней возни.
Вот именно здесь читатель часто думает: «Под мою задачу это тоже подходит». А когда человек начинает мысленно примерять сценарий на себя, статья обычно уходит в сохранённые.
Микроистория, которую многие узнают
Обычно ежедневный отчёт кажется делом на десять минут. Пока не начинаешь его делать каждый день. Через неделю это уже раздражает. Через месяц начинает утомлять. Через три месяца человек уже не замечает, сколько внимания сливает в одну и ту же механическую процедуру.
А потом появляется кнопка.
И вдруг оказывается, что вечерний отчёт перестал быть маленьким ежедневным наказанием. Он просто есть. Нажал — получил. И пошёл дальше по работе, а не сидишь, как переписчик при канцелярии XIX века, аккуратно перекладывая строки из одной таблицы в другую.
Где логично поставить перелинковку внутри статьи
Внутри этой статьи хорошо работают переходы на материалы, которые усиливают сценарий.
Например, после разбора фильтрации по дате можно вставить переход на статью о подсветке просроченных задач — это логичное продолжение работы со сроками.
После блока про выбор нужных строк полезно увести читателя на материал об автоматической проверке заполненности таблицы — чтобы перед формированием отчёта сначала убедиться, что данные внесены без дыр.
А после этой статьи отлично пойдёт ссылка на материал о подготовке файла к отправке одной кнопкой. Потому что следующий естественный шаг после готового отчёта — сделать так, чтобы Excel ещё и сам приводил документ в порядок перед отправкой.
Такая перелинковка не выглядит искусственно. Она идёт по ходу самой рабочей логики. Именно это и нужно для глубины чтения.
Что можно положить в файл для Telegram к этой части
К этой статье лучше всего подходит не просто таблица, а маленький готовый комплект:
- лист с исходными данными;
- кнопка запуска отчёта;
- готовый макрос;
- вариант для отчёта за сегодня;
- вариант для отчёта за вчера;
- вариант с фильтрацией по статусу;
- короткая инструкция, какие строки менять под свою задачу.
Такие файлы ценятся выше всего. Не потому что они «красивые», а потому что их можно открыть и использовать почти сразу. Именно такие вещи чаще пересылают коллегам. А пересылки — это уже топливо для роста канала.
Вывод
Автоматизация в Excel по-настоящему начинается не там, где код сложный, а там, где он снимает повторяющуюся рутину с реальной работы. Ежедневный отчёт — идеальный пример такой задачи. Структура знакомая, боль понятная, выгода мгновенная.
Одна кнопка здесь экономит не только минуты. Она сохраняет внимание, снижает число ошибок и делает результат аккуратным без лишней ручной доработки. А это уже не просто «удобный макрос», а кусок рабочей системы.
Сохраните статью, если отчёты в вашей работе появляются чаще, чем хотелось бы. А если нужен готовый файл с примером таблицы и макросом — забирайте его в Telegram. Там же будет версия с доработкой под отчёт по статусу и сотруднику.
Подписывайтесь на канал.
В следующей части разберём сценарий, который ещё ближе к живой рутине: автоматическую проверку заполненности таблицы, чтобы Excel сам находил пустые ячейки до того, как ошибка уедет в отчёт, письмо или руководителю. Это уже не просто удобно. Это спасает от очень неловких ситуаций.