На многих форумах и в профессиональных сообществах 1С периодически поднимается вопрос о необходимости выполнения массовых операций с документами, таких как их запись или перепроведение, непосредственно при открытии формы списка. Эта задача, хотя на первый взгляд может показаться логичной для инициализации или актуализации данных, на самом деле является крайне нежелательной и даже опасной практикой в контексте работы платформы 1С:Предприятие. Давайте подробно разберем, почему такой подход противоречит основным принципам работы системы, какие риски он несет, и какие существуют правильные, безопасные и производительные альтернативы.
Представим ситуацию: вы сталкиваетесь с задачей, когда, по вашему мнению, каждый документ в списке должен быть программно записан при открытии формы. Возможно, это вызвано стремлением обновить какие-то данные, пересчитать итоги или исправить некорректные записи. Однако, пытаясь реализовать подобное поведение, вы рискуете столкнуться с рядом серьезных проблем.
Прежде чем рассматривать, как можно было бы теоретически реализовать такую идею (и почему ее не стоит реализовывать), давайте выясним основные причины, по которым это является анти-паттерном:
Риск нарушения целостности данных и логики учета. Повторная запись документов, особенно тех, которые уже проведены, может привести к непредсказуемым последствиям. Если документ уже сформировал движения по регистрам (бухгалтерским, управленческим, регистрам накопления и т.д.), его повторное проведение или запись может изменить эти движения, пересчитать итоги, затронуть взаиморасчеты и вызвать расхождения в учете. Платформа 1С строго следит за целостностью данных, и принудительная массовая перезапись может нарушить эту логику, особенно если она выполняется без должного контроля и понимания бизнес-процессов.
Например, в сообщении 4 участник форума справедливо отмечает: "Потому, что например, проведенные документы перепроведутся, и ответственные люди тебе голову оторвут. Задача такая зачем? Она противоречит всему." Это наглядно демонстрирует серьезность потенциальных проблем.
Критическое снижение производительности системы. Массовая перезапись документов при каждом открытии формы списка создает колоссальную нагрузку на сервер 1С и базу данных. Каждый документ — это отдельный объект, требующий выполнения транзакций, блокировок, записи в таблицы, обновления индексов. Если у вас сотни или тысячи документов в списке, и каждый пользователь при открытии формы запускает этот процесс, это неизбежно приведет к:
Негативный пользовательский опыт. Пользователь, открывающий список документов, ожидает увидеть актуальные данные и быстро взаимодействовать с ними. Запуск длительного процесса перезаписи без явного уведомления или возможности контроля вызовет недовольство и дезориентацию. Интерфейс будет "зависать", ожидая завершения фоновых (или не очень фоновых) операций.
Противоречие логике платформы. Форма списка в 1С предназначена для отображения данных, их фильтрации, сортировки и интерактивного взаимодействия с отдельными элементами (открытие, изменение). Она не является механизмом для массовой фоновой обработки данных. Для таких целей платформа предоставляет другие, более подходящие инструменты.
Давайте посмотрим, как можно было бы гипотетически попытаться реализовать такой механизм программно, чтобы понять его риски, и почему от него стоит отказаться.
В управляемых формах 1С события, которые срабатывают при открытии формы, это, например, ПриОткрытии и ПриСозданииНаСервере. В этих обработчиках мы получаем доступ к элементам формы, включая динамический список документов.
Сообщение 10 упоминает: "при открытии формы списка будет ПриОткрытии и ПриСозданииНаСервере, там будет Динамический список "Список", надо его перебрать и перезаписать объекты". Теоретически, вы могли бы попытаться получить данные из динамического списка, а затем перебрать их и записать. Вот как это могло бы выглядеть в упрощенном виде (ПРИМЕР КОДА ПОКАЗАН ИСКЛЮЧИТЕЛЬНО ДЛЯ ДЕМОНСТРАЦИИ АНТИ-ПАТТЕРНА И НЕ РЕКОМЕНДУЕТСЯ К ИСПОЛЬЗОВАНИЮ!):
// В обработчике ПриСозданииНаСервере или ПриОткрытии
// ИМИТАЦИЯ ОЧЕНЬ ОПАСНОГО И НЕЖЕЛАТЕЛЬНОГО КОДА!
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Получаем источник данных динамического списка (например, основной список формы)
// Обычно это Элементы.Список.Значение
// Но для работы с данными списка нужно получить его программно
ПереченьДокументов = Новый СписокЗначений;
// Получаем отбор и другие параметры динамического списка для получения данных
// Это очень упрощенный пример, в реальности сложнее получить все элементы динамического списка
// без использования СКД и без обхода всех страниц.
// Предположим, мы можем как-то получить итератор или коллекцию ссылок.
// Более реалистичный (но все еще опасный) способ - это запрос к базе данных
// для получения всех документов типа "РеализацияТоваровУслуг", отображаемых в списке
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДокументРеализацияТоваровУслуг.Ссылка КАК Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК ДокументРеализацияТоваровУслуг";
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Попытка
// Получаем объект документа
ДокументОбъект = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
// Выполняем запись (или перепроведение)
// Это может быть просто ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
// Или ДокументОбъект.Записать();
// В любом случае, это ОЧЕНЬ ДОЛГАЯ И РЕСУРСОЕМКАЯ ОПЕРАЦИЯ ДЛЯ МАССЫ ДОКУМЕНТОВ
// Пример записи (ВНИМАНИЕ: ОПАСНО!)
Если ДокументОбъект.Проведен Тогда
ДокументОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения); // Сначала отменяем проведение, если нужно
КонецЕсли;
// Здесь может быть логика по изменению реквизитов перед записью
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение); // Затем проводим
Сообщить("Документ " + ДокументОбъект.Номер + " успешно перезаписан.");
Исключение
Сообщить("Ошибка при записи документа " + ВыборкаДетальныеЗаписи.Ссылка + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
// После массовых операций, если они были, динамический список возможно потребуется обновить.
// Элементы.Список.Обновить(); // Это тоже может быть медленно
КонецПроцедуры
Такой код, даже если он был бы максимально оптимизирован, не только замедлит работу пользователя, но и, скорее всего, приведет к ошибкам, блокировкам и повреждению данных, как мы уже выяснили. Именно поэтому форумчане в сообщениях 4 и 10 настоятельно рекомендуют НЕ ДЕЛАТЬ ТАК и использовать другие подходы.
Если перед вами действительно стоит задача выполнения каких-либо действий с группой документов (перезапись, изменение реквизитов, перепроведение, корректировка движений), платформа 1С предоставляет для этого мощные и безопасные механизмы. Мы рассмотрим их подробнее.
Это основной и наиболее правильный способ для пакетной работы с данными в 1С. Обработка — это специализированный объект конфигурации, предназначенный для выполнения определенных действий, в том числе и для работы с набором документов. Давайте разберем по шагам, как это работает:
Создание обработки. Вы можете создать новую внешнюю обработку (файл .epf) или встроить обработку непосредственно в конфигурацию. В обработке мы создаем форму, на которой размещаем элементы управления для отбора документов и кнопки для запуска действий.
Реализация отбора документов. В форме обработки пользователи могут гибко задавать критерии отбора: по дате, организации, статусу, ответственному и любым другим реквизитам. Это позволяет выполнять действия не со всеми документами базы, а только с целевой выборкой, что значительно снижает нагрузку.
Для отбора чаще всего используются динамические списки в самой обработке или построители запросов.
// Пример получения документов по отбору в обработке
Функция ПолучитьДокументыДляОбработки()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДокументРеализацияТоваровУслуг.Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК ДокументРеализацияТоваровУслуг
|ГДЕ
| ДокументРеализацияТоваровУслуг.Дата МЕЖДУ &ДатаНачало И &ДатаОкончание
| И ДокументРеализацияТоваровУслуг.Организация = &Организация";
Запрос.УстановитьПараметр("ДатаНачало", ДатаНачало); // Это реквизиты формы обработки
Запрос.УстановитьПараметр("ДатаОкончание", ДатаОкончание);
Запрос.УстановитьПараметр("Организация", Организация);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Выполнение действий. После отбора пользователь (или сама программа) нажимает кнопку, которая запускает основной алгоритм обработки. Этот алгоритм перебирает отобранные документы и выполняет над ними необходимые операции (например, запись, проведение, изменение реквизитов).
// Пример кнопки "Перезаписать документы" на форме обработки
&НаКлиенте
Процедура ПерезаписатьДокументы(Команда)
Если Вопрос("Вы уверены, что хотите перезаписать выбранные документы?", РежимДиалогаВопрос.ДаНет) = КодВозвратаДиалога.Нет Тогда
Возврат;
КонецЕсли;
// Выполняем длительную операцию на сервере
ПерезаписатьДокументыНаСервере();
КонецПроцедура
&НаСервереБезКонтекста
Процедура ПерезаписатьДокументыНаСервере()
// Этот метод вызывается с клиента и выполняется на сервере
// В обработках часто используется передача списка ссылок
// или получение документов по сохраненным параметрам отбора.
// Предполагаем, что у нас есть список ссылок (например, из реквизита формы)
// СписокДокументовДляОбработки - это может быть таблица значений или массив ссылок
СписокСсылок = ОбработкаОбъект.СписокСсылокДокументов;
Для Каждого СсылкаДок Из СписокСсылок Цикл
Попытка
ДокументОбъект = СсылкаДок.ПолучитьОбъект();
Если ДокументОбъект.Проведен Тогда
ДокументОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
КонецЕсли;
// Здесь может быть какая-то логика изменения данных
ДокументОбъект.Комментарий = "Обработано через обработку " + ТекущаяДата();
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
Сообщить("Документ " + ДокументОбъект.Номер + " успешно обработан.");
Исключение
Сообщить("Ошибка при обработке документа " + СсылкаДок + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Контроль и обратная связь. Обработка позволяет выводить информацию о ходе выполнения, прогрессе, возникших ошибках. Пользователь видит, что происходит, и может контролировать процесс. Важно отметить, что длительные операции могут быть выполнены в фоновом режиме, что не блокирует работу пользователя с системой.
Именно этот подход (использование объекта Обработка) является наиболее универсальным и рекомендуемым. Как подчеркивают участники форума в сообщениях 4 и 10: "обработка наше все".
Для выполнения регулярных операций с документами, которые не требуют интерактивного участия пользователя и могут выполняться в нерабочее время или в периоды минимальной нагрузки, используются регламентные задания. Рассмотрим этот механизм:
Назначение. Регламентные задания идеально подходят для таких задач, как:
Принцип работы. Регламентное задание представляет собой фоновую задачу, которая выполняется на сервере 1С по заданному расписанию (например, каждый день в 02:00 ночи). Оно запускается без участия пользователя и не блокирует его работу. Логика выполнения регламентного задания обычно реализуется в модулях общих менеджеров или в модулях объектов, а затем "публикуется" как регламентное задание через конфигуратор и настраивается через пользовательский режим.
Преимущества. Использование регламентных заданий позволяет:
Пример кода для регламентного задания, который может быть вызван из общего модуля или модуля менеджера:
// В общем модуле (например, ОбщийМодульВыполненияРегламентныхЗаданий)
// Должен быть экспортный метод с аннотацией &НаСервереБезКонтекста и &ВнешнееСоединение
&НаСервереБезКонтекста
Процедура ПерепровестиДокументыЗаПрошлыйПериод()
НачалоПериода = НачалоДня(ДобавитьКДате(ТекущаяДата(), ВидДаты.День, -1)); // Вчерашний день
КонецПериода = КонецДня(НачалоПериода);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДокументРеализацияТоваровУслуг.Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК ДокументРеализацияТоваровУслуг
|ГДЕ
| ДокументРеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И ДокументРеализацияТоваровУслуг.Проведен = ИСТИНА"; // Или ЛОЖЬ, если нужно провести непроведенные
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДокументов = РезультатЗапроса.Выбрать();
Пока ВыборкаДокументов.Следующий() Цикл
Попытка
ДокументОбъект = ВыборкаДокументов.Ссылка.ПолучитьОбъект();
// Возможно, здесь должна быть дополнительная проверка перед перепроведением
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
ЗафиксироватьСообщениеПротокола("Документ " + ДокументОбъект.Ссылка + " успешно перепроведен.");
Исключение
ЗафиксироватьСообщениеПротокола("Ошибка при перепроведении документа " + ВыборкаДокументов.Ссылка + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецПроцедуры
// Вспомогательная функция для логирования (можно использовать ОбщегоНазначения.ЗаписатьВЖурналРегистрации или свой механизм)
&НаСервереБезКонтекста
Процедура ЗафиксироватьСообщениеПротокола(Сообщение)
// Пример записи в журнал регистрации
ЗаписьЖурналаРегистрации(
"ПерепроведениеДокументов",
УровеньЖурналаРегистрации.Информация,
Метаданные.РегламентныеЗадания.ПерепроведениеДокументов, // Имя вашего регламентного задания
Сообщение
);
КонецПроцедуры
Если вам требуется, чтобы список документов отображался с учетом изменений, внесенных *только что* (например, после создания нового документа или изменения реквизита в открытом документе), платформа 1С обычно обеспечивает актуализацию данных списка автоматически. Если же требуется специфическое поведение, вы можете программно обновить динамический список после определенных действий, используя метод Обновить() для элемента формы типа ДинамическийСписок:
&НаКлиенте
Процедура ПослеЗаписиДокумента()
// Предположим, вы вызвали эту процедуру после успешной записи документа
Если Элементы.Список.Доступность Тогда // Проверяем, что список доступен
Элементы.Список.Обновить(); // Обновляем данные динамического списка
КонецЕсли;
КонецПроцедуры
Однако, это обновление относится к *отображению* данных в списке, а не к их массовой записи. Использование этого метода после каждой записи нового документа или изменения текущего — это нормальная практика. Использование его для принудительного обновления всего списка после некой глобальной операции (если бы вы все-таки решились ее делать) может также быть медленным, но это уже следствие первичной неправильной идеи.
Мы выяснили, что попытка программно записать каждый документ при открытии формы списка в 1С:Предприятии является вредной и опасной практикой, которая может привести к серьезным проблемам с производительностью и целостностью данных. Вместо этого, для выполнения пакетных операций с документами следует использовать специально предназначенные для этого механизмы платформы:
Эти подходы позволяют решать задачи актуализации и модификации данных безопасно, эффективно и без ущерба для стабильности работы системы и удобства пользователей.