В процессе работы с конфигурациями 1С, особенно с такими как "Управление торговлей 10.3", часто возникает задача массового перепроведения документов для восстановления последовательности партионного учета. Основная сложность заключается в том, чтобы выбрать абсолютно все документы, которые могут влиять на регистр партий, а не только те, которые уже сделали по нему движения. Рассмотрим, как решить эту задачу правильно и надежно.
Проанализируем ситуацию: из-за ошибок в учете (например, не хватило остатка товара на складе) какой-то документ мог провеcтись, но не сделать движений по регистру ПартииТоваровНаСкладах. Если мы будем выбирать документы для перепроведения просто по наличию движений в этом регистре, мы пропустим такой "проблемный" документ. После исправления данных он должен сделать движения, но в нашу выборку он не попадет. Наша цель — найти способ получить список всех потенциальных регистраторов.
Самый надежный и правильный способ получить полный список типов документов, которые могут делать движения по определённому регистру накопления — это обратиться напрямую к метаданным конфигурации. Этот метод гарантирует, что мы получим все возможные типы документов-регистраторов, даже если ни один документ такого типа еще не создавал движений или не был проведен.
Рассмотрим по шагам, как это сделать программно.
Шаг 1. Получаем имена документов-регистраторов.
Для этого мы обращаемся к свойству Регистраторы нужного нам регистра накопления в метаданных. В цикле переберем коллекцию регистраторов и соберем их имена в массив.
// Создаем массив для хранения имен документов
ИменаДокументовРегистраторов = Новый Массив;
// Обращаемся к метаданным регистра накопления "ПартииТоваровНаСкладах"
Для Каждого Регистратор Из Метаданные.РегистрыНакопления.ПартииТоваровНаСкладах.Регистраторы Цикл
// Добавляем строковое имя документа в массив
// Например, "РеализацияТоваровУслуг", "ПоступлениеТоваровУслуг" и т.д.
ИменаДокументовРегистраторов.Добавить(Регистратор.Имя);
КонецЦикла;
// Теперь в массиве ИменаДокументовРегистраторов содержатся
// имена всех документов, которые могут делать движения по этому регистру.
Этот подход является наиболее предпочтительным, так как он напрямую читает структуру конфигурации и не зависит от наличия данных в информационной базе.
Шаг 2. Формируем динамический запрос для выборки документов.
Теперь, имея массив с именами документов, нам нужно выбрать сами документы из базы данных за определенный период. Поскольку документы разных типов хранятся в разных таблицах, для их одновременного получения необходимо использовать запрос с объединением (ОБЪЕДИНИТЬ ВСЕ). Текст такого запроса удобно формировать динамически в цикле.
// Предполагаем, что массив ИменаДокументовРегистраторов уже заполнен на предыдущем шаге
// Начальные параметры для выборки
ДатаНачала = '20230101';
ДатаОкончания = '20231231';
ТекстЗапроса = "";
// В цикле обходим массив с именами документов
Для Каждого ИмяДокумента Из ИменаДокументовРегистраторов Цикл
// Для каждого типа документа формируем свой блок ВЫБРАТЬ
ЧастьЗапроса = "
|ВЫБРАТЬ
| Ссылка,
| Дата,
| Проведен
|ИЗ
| Документ." + ИмяДокумента + "
|ГДЕ
| Дата МЕЖДУ &НачалоПериода И &КонецПериода И НЕ ПометкаУдаления";
// Объединяем части запроса через ОБЪЕДИНИТЬ ВСЕ
Если НЕ ПустаяСтрока(ТекстЗапроса) Тогда
ТекстЗапроса = ТекстЗапроса + "
|
|ОБЪЕДИНИТЬ ВСЕ
|";
КонецЕсли;
ТекстЗапроса = ТекстЗапроса + ЧастьЗапроса;
КонецЦикла;
// Добавляем сортировку для соблюдения хронологии
ТекстЗапроса = ТекстЗапроса + "
|
|УПОРЯДОЧИТЬ ПО
| Дата";
// Создаем и выполняем запрос
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));
РезультатВыборки = Запрос.Выполнить().Выбрать();
// Перебираем результат и перепроводим документы
Пока РезультатВыборки.Следующий() Цикл
// Здесь логика перепроведения документов
// ВАЖНО: простое перепроведение в цикле может быть опасным.
// Лучше использовать обертку Попытка-Исключение.
Попытка
ОбъектДокумента = РезультатВыборки.Ссылка.ПолучитьОбъект();
// Перепроводим только проведенные документы
Если ОбъектДокумента.Проведен Тогда
ОбъектДокумента.Записать(РежимЗаписиДокумента.Проведение);
КонецЕсли;
Исключение
Сообщить("Не удалось перепровести документ: " + РезультатВыборки.Ссылка + ". Ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
Важно: массовое перепроведение документов — ресурсоемкая операция. Она может заблокировать работу пользователей и привести к новым ошибкам. Всегда выполняйте такие операции в монопольном режиме, предварительно сделав резервную копию базы. Обязательно используйте механизм Попытка-Исключение, чтобы обработка не прервалась на первом же проблемном документе.
Существует и другой программный способ получить список типов-регистраторов, который также был предложен на форуме. Он заключается в создании пустого набора записей регистра и анализе типов, доступных для его отбора по полю Регистратор.
// Создаем пустой набор записей для регистра
НаборЗаписей = РегистрыНакопления.ПартииТоваровНаСкладах.СоздатьНаборЗаписей();
// Получаем доступные типы для отбора по регистратору
МассивТиповРегистраторов = НаборЗаписей.Отбор.Регистратор.ТипЗначения.Типы();
// Теперь в МассивТиповРегистраторов находятся объекты типа "Тип",
// описывающие все возможные документы-регистраторы.
// Дальнейший код для построения запроса будет немного отличаться,
// так как нужно будет получать имя из метаданных типа.
Этот метод тоже работает, но считается менее "правильным" с архитектурной точки зрения, так как для получения информации о структуре (метаданных) мы создаем объект данных (набор записей). Прямое обращение к объекту Метаданные, как в первом решении, является более логичным и эффективным.
Если вы не хотите писать код, можно воспользоваться стандартным инструментом, который есть в большинстве типовых конфигураций, включая "Управление торговлей 10.3".
Обработка "Групповое перепроведение документов" (обычно находится в меню "Сервис" -> "Универсальные обработки") позволяет выполнить ту же задачу без программирования.
Преимущества этого способа:
Недостаток:
Выбирайте способ, который лучше всего подходит под вашу задачу и уровень квалификации. Для разовых операций или для пользователей без прав на изменение конфигурации идеально подойдет штатная обработка. Для регулярных автоматизированных процедур лучше использовать программный метод с обращением к метаданным.