В процессе работы бухгалтерии регулярно возникает задача проведения сверки взаиморасчетов с большим количеством контрагентов одновременно — например, в конце квартала или года. В типовой конфигурации «1С:Бухгалтерия предприятия 3.0» (включая версию КОРП) отсутствует стандартный помощник для пакетной генерации актов сверки «на лету» (в отличие от более тяжелых решений вроде 1С:ERP или 1С:Комплексная автоматизация). Бухгалтерам приходится вручную плодить десятки и сотни документов АктСверкиРасчетовСКонтрагентом, что сильно захламляет информационную базу.
В рамках этой статьи мы подробно разберем, как решить эту проблему программно с помощью внешней обработки. Мы рассмотрим экологичный способ формирования печатных форм актов сверки «в памяти» без непосредственной записи документов в базу данных. Кроме того, мы решим сопутствующую техническую задачу, часто возникающую при разработке подобных интерфейсов: обратное преобразование строкового представления месяца и года (например, «Январь_2026») в стандартный объект платформы Дата.
---
Если мы попытаемся решить задачу автоматического создания актов стандартным путем, то столкнемся с необходимостью программно создавать документы, записывать их, выводить на печать и затем помечать на удаление. Этот подход имеет множество минусов: растет объем транзакционного лога, увеличивается размер базы данных, могут возникать блокировки таблиц при активной работе пользователей.
Гораздо более изящное решение — формировать объект документа в оперативной памяти, заполнять его по данным регистров бухгалтерии, передавать этот незаписанный объект в печатную форму и выводить результат в единый ТабличныйДокумент для отправки на принтер. Давайте разберем этот процесс по шагам.
Шаг 1. Инициализация и заполнение объекта «в памяти»
Для начала нам необходимо создать объект документа в памяти сервера без вызова метода Записать(). Проанализируем пример кода, который инициализирует документ, заполняет его реквизиты шапки и вызывает штатные методы заполнения табличных частей по данным учета:
// Функция создает виртуальный документ "Акт сверки" и заполняет его данными расчетов
Функция СформироватьВиртуальныйАктСверки(Организация, Контрагент, НачалоПериода, КонецПериода) Экспорт
// Создаем объект документа в оперативной памяти (в базу он пока не записан, Ссылка пустая)
НовыйАкт = Документы.АктСверкиРасчетовСКонтрагентом.СоздатьДокумент();
// Заполняем ключевые реквизиты шапки
НовыйАкт.Дата = ТекущаяДата();
НовыйАкт.Организация = Организация;
НовыйАкт.Контрагент = Контрагент;
НовыйАкт.ДатаНачала = НачалоПериода;
НовыйАкт.ДатаОкончания = КонецПериода;
НовыйАкт.ВалютаДокумента = Справочники.Валюты.НайтиПоКоду("643"); // Рубли РФ
// Заполняем счета учета расчетов по умолчанию (60, 62, 76 и т.д.)
// Используем стандартный метод конфигурации БП 3.0
Документы.AктСверкиРасчетовСКонтрагентом.ЗаполнитьСчетаУчетаПоУмолчанию(НовыйАкт);
// Вызываем типовые процедуры заполнения табличных частей документа по регистрам
// Внимание: данные методы обращаются к базе данных за движениями, но сам объект не записывают!
НовыйАкт.ЗаполнитьПоДаннымОрганизации();
НовыйАкт.ЗаполнитьПоДаннымКонтрагента();
Возврат НовыйАкт;
КонецФункции
Шаг 2. Обход ограничений подсистемы печати БСП
Стандартный механизм печати в библиотеке стандартных подсистем (БСП) жестко завязан на передачу массива ссылок (МассивСсылок). Поскольку наш документ существует только в памяти и не имеет ссылки (свойство Ссылка возвращает ПустаяСсылка()), передать его в стандартные экспортные методы печати напрямую не получится — программа выдаст ошибку.
Чтобы обойти это ограничение, мы должны переопределить логику формирования печатной формы в нашей внешней обработке. Мы можем вытащить макет акта сверки и заполнить его вручную данными из табличных частей ПоДаннымОрганизации и ПоДаннымКонтрагента нашего виртуального объекта. Посмотрим на упрощенную схему реализации вывода макета:
Функция ПолучитьПечатнуюФормуАкта(ВиртуальныйДокумент)
ТабличныйДокумент = Новый ТабличныйДокумент;
ТабличныйДокумент.ИмяПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_АКТ_СВЕРКИ";
// Получаем макет из метаданных документа или из нашей внешней обработки
Макет = Документы.АктСверкиРасчетовСКонтрагентом.ПолучитьМакет("АктСверки");
// Заполняем область "Заголовок"
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьЗаголовок.Параметры.Организация = ВиртуальныйДокумент.Организация;
ОбластьЗаголовок.Параметры.Контрагент = ВиртуальныйДокумент.Контрагент;
ОбластьЗаголовок.Параметры.ПериодСверки = ПредставлениеПериода(ВиртуальныйДокумент.ДатаНачала, ВиртуальныйДокумент.ДатаОкончания);
ТабличныйДокумент.Вывести(ОбластьЗаголовок);
// Заполняем строки по данным организации
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
Для Каждого СтрокаДанных Из ВиртуальныйДокумент.ПоДаннымОрганизации Цикл
ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, СтрокаДанных);
ТабличныйДокумент.Вывести(ОбластьСтрока);
КонецЦикла;
// Заполняем подвалы и итоговые суммы...
// (Код вывода подвала аналогичен стандартному алгоритму)
Возврат ТабличныйДокумент;
КонецФункции
Объединив этот код в цикл по выбранным контрагентам, мы сможем вывести все сформированные акты сверки в один общий табличный документ (используя метод ВывестиВертикальнуюОбластьТабличногоДокумента() или просто разделяя акты разрывом страницы через ВывестиГоризонтальныйРазделительСтраниц()), после чего отправить его на печать одной кнопкой.
---
Вторая техническая проблема, затронутая на форуме, касается обратного преобразования строки формата месяца и года в системный тип данных Дата. Такое форматирование часто используется для наглядного именования колонок во временных таблицах или отчетах, например: "Январь_2026".
Платформа 1С не имеет встроенных интеллектуальных средств для разбора локализованных текстовых названий месяцев. Стандартная функция Дата() не сможет распознать строку вида "Январь_2026" и вызовет исключение времени выполнения. Чтобы решить эту задачу, нам потребуется написать собственную парсер-функцию.
Рассмотрим готовую функцию, которая разбирает подобную строку на составляющие, сопоставляет русскоязычное название месяца с его порядковым номером и конструирует валидную дату на первое число этого месяца:
// Функция преобразует строку вида "Январь_2026" в объект Дата (01.01.2026 00:00:00)
Функция ПолучитьДатуИзФорматаММММ_гггг(Знач СтрокаДаты) Экспорт
// Разделяем входящую строку по символу подчеркивания
ЧастиСтроки = СтрРазделить(СтрокаДаты, "_");
// Если разделитель не найден или формат нарушен, возвращаем пустую дату
Если ЧастиСтроки.Количество() < 2 Тогда
Возврат Дата(1, 1, 1);
КонецЕсли;
// Извлекаем название месяца и год, избавляясь от лишних пробелов
ИмяМесяца = НРег(СокрЛП(ЧастиСтроки[0]));
СтрокаГода = СокрЛП(ЧастиСтроки[1]);
// Приводим год к числовому типу
Попытка
Год = Число(СтрокаГода);
Исключение
Возврат Дата(1, 1, 1); // Возвращаем пустую дату в случае ошибки приведения типа
КонецПопытки;
// Создаем соответствие русскоязычных названий месяцев их порядковым номерам
СоответствиеМесяцев = Новый Соответствие;
СоответствиеМесяцев.Вставить("январь", 1);
СоответствиеМесяцев.Вставить("февраль", 2);
СоответствиеМесяцев.Вставить("март", 3);
СоответствиеМесяцев.Вставить("апрель", 4);
СоответствиеМесяцев.Вставить("май", 5);
СоответствиеМесяцев.Вставить("июнь", 6);
СоответствиеМесяцев.Вставить("июль", 7);
СоответствиеМесяцев.Вставить("август", 8);
СоответствиеМесяцев.Вставить("сентябрь", 9);
СоответствиеМесяцев.Вставить("октябрь", 10);
СоответствиеМесяцев.Вставить("ноябрь", 11);
СоответствиеМесяцев.Вставить("декабрь", 12);
// Получаем номер месяца из соответствия
НомерМесяца = СоответствиеМесяцев.Получить(ИмяМесяца);
// Если название месяца написано некорректно или не найдено в списке
Если НомерМесяца = Неопределено Тогда
Возврат Дата(1, 1, 1);
КонецЕсли;
// Формируем результирующую дату на первое число месяца
Попытка
РезультатДата = Дата(Год, НомерМесяца, 1);
Исключение
РезультатДата = Дата(1, 1, 1);
КонецПопытки;
Возврат РезультатДата;
КонецФункции
Проанализируем ключевые моменты этой функции:
НРег() для приведения названия месяца к нижнему регистру. Это предотвращает падение алгоритма из-за разного регистра символов (например, "Январь", "январь", "ЯНВАРЬ").СтрРазделить() позволяет легко разделить строку по любому указанному символу-разделителю. Если в вашей конфигурации используется пробел или дефис вместо подчеркивания, достаточно просто заменить символ разделителя в вызове функции.Попытка ... Исключение при приведении года к числу и конструировании объекта даты защитит вашу обработку от аварийного завершения работы при попадании некорректных данных на вход.Применение предложенных методик позволит вам существенно оптимизировать работу пользователей с печатью отчетности в «1С:Бухгалтерии 3.0» и повысить скорость обработки регулярных операций сверки взаиморасчетов, сохранив при этом чистоту и производительность информационной базы.