Как заполнить пустую сумму документа в форме списка для уже существующих записей в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке в среде 1С часто возникает ситуация, когда в уже функционирующую конфигурацию добавляется новый реквизит — например, СуммаДокумента. Если для новых документов мы можем легко настроить автоматическое заполнение в обработчике ПередЗаписью, то старые документы остаются с пустыми значениями. Это создает неудобства при просмотре списка, поиске и анализе данных. Давайте разберем, как эффективно решить эту задачу, не нарушая целостность учетных данных и не прибегая к массовому перепроведению документов за прошлые периоды.

Метод 1. Программное заполнение реквизитов через обработку

Самый правильный и надежный способ — это разовое заполнение данных в существующей базе. Как справедливо отметили участники форума, «на всю жизнь утяжелять список» расчетами «на лету» — плохая практика. Проанализируем, как реализовать скрипт для обновления данных.

Для того чтобы обновить старые записи, нам необходимо создать внешнюю обработку. Мы не будем использовать метод Записать(РежимЗаписиДокумента.Проведение), так как это может изменить остатки и движения по регистрам в закрытых периодах. Вместо этого мы воспользуемся режимом записи и специальным флагом ОбменДанными.Загрузка.

Рассмотрим пример кода, который выполнит эту задачу:


// 1. Выбираем все документы, где сумма еще не заполнена
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   РеализацияТоваровУслуг.Ссылка КАК Ссылка
    |ИЗ
    |   Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    |ГДЕ
    |   РеализацияТоваровУслуг.СуммаДокумента = 0";

РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    // 2. Получаем объект документа для изменения
    ДокументОбъект = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
    
    // 3. Рассчитываем сумму по табличной части "Работы"
    ДокументОбъект.СуммаДокумента = ДокументОбъект.Работы.Итог("Сумма");
    
    // 4. Устанавливаем режим загрузки, чтобы пропустить лишние проверки и не менять движения
    ДокументОбъект.ОбменДанными.Загрузка = Истина;
    
    // 5. Записываем объект без проведения
    Попытка
        ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
    Исключение
        Сообщить("Не удалось записать документ: " + ДокументОбъект.Ссылка + " Ошибка: " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

Важный нюанс: использование свойства ОбменДанными.Загрузка = Истина позволяет нам «обмануть» систему, сказав ей, что данные загружаются из внешнего источника. В этом случае платформа отключает большинство стандартных проверок. Однако помните, что если в коде модуля документа обработчик ПередЗаписью не содержит условия Если ОбменДанными.Загрузка Тогда Возврат; КонецЕсли;, то расчет суммы, прописанный там, сработает повторно. В нашей ситуации это даже полезно.

Метод 2. Использование произвольного запроса в Динамическом списке

Если документов немного или требуется мгновенный результат без изменения данных в базе, можно пойти по пути настройки формы списка. Проанализируем этот вариант. В настройках динамического списка (свойство ПроизвольныйЗапрос) мы можем изменить текст выборки данных.

Вместо того чтобы просто выбирать поле СуммаДокумента, мы можем вычислить его в самом запросе, соединив основную таблицу документа с его табличной частью. Посмотрим на примерную структуру такого запроса:


ВЫБРАТЬ
    Док.Ссылка,
    Док.Дата,
    Док.Номер,
    ВЫБОР
        КОГДА Док.СуммаДокумента = 0 ТОГДА ТаблицаСумм.ИтогСумма
        ИНАЧЕ Док.СуммаДокумента
    КОНЕЦ КАК СуммаДокумента
ИЗ
    Документ.РеализацияТоваровУслуг КАК Док
ЛЕВОЕ СОЕДИНЕНИЕ (
    ВЫБРАТЬ
        Работы.Ссылка КАК Ссылка,
        СУММА(Работы.Сумма) КАК ИтогСумма
    ИЗ
        Документ.РеализацияТоваровУслуг.Работы КАК Работы
    СГРУППИРОВАТЬ ПО
        Работы.Ссылка
) КАК ТаблицаСумм ПО Док.Ссылка = ТаблицаСумм.Ссылка

Рассмотрим плюсы и минусы этого подхода:

  1. Плюсы: данные отображаются сразу, не нужно запускать никаких обработок и менять старые документы.
  2. Минусы: существенно снижается производительность формы списка на больших объемах данных. Сортировка и отбор по вычисляемому полю будут работать медленно, так как СУБД придется каждый раз суммировать строки табличных частей.

Метод 3. Групповое изменение реквизитов (типовой функционал)

Если ваша конфигурация построена на базе БСП (Библиотека Стандартных Подсистем), выясним, как сделать это без написания кода. В пользовательском режиме существует обработка «Групповое изменение реквизитов».

Проанализируем шаги работы с ней:

  1. Выбираем тип объекта (ваш документ).
  2. Настраиваем отбор: СуммаДокумента Равно 0.
  3. В колонке «Дополнительные параметры» нажимаем «Специальные возможности» и разрешаем выполнение произвольного алгоритма (если это доступно в вашей версии).
  4. Если произвольный алгоритм недоступен, достаточно просто выбрать реквизит СуммаДокумента и указать новое значение. Но так как значение для каждого документа индивидуально (сумма ТЧ), лучше использовать программный метод, описанный выше.

Оптимизация и важные советы

Выясним, какие дополнительные действия помогут нам избежать проблем в будущем:

1. Индексирование реквизита. После того как вы заполните СуммаДокумента во всех записях, обязательно зайдите в Конфигуратор и установите свойство Индексировать (или Индексировать с доп. упорядочиванием) для этого реквизита. Это позволит пользователям мгновенно сортировать список по суммам и строить быстрые отчеты.

2. Работа с большими базами. Если у вас сотни тысяч документов, выполнение одного большого цикла может привести к блокировке таблицы и переполнению лога транзакций. В таких случаях рассмотрим стратегию порционной записи:


// Пример порционной записи
Счетчик = 0;
Пока Выборка.Следующий() Цикл
    // ... логика получения объекта ...
    ДокументОбъект.Записать();
    Счетчик = Счетчик + 1;
    
    Если Счетчик % 1000 = 0 Тогда
        // Каждую тысячу документов фиксируем транзакцию
        ОбработкаПрерыванияПользователя();
        Сообщить("Обработано: " + Счетчик);
    КонецЕсли;
КонецЦикла;

3. Итог по числовым полям. При использовании метода Итог("Сумма") убедитесь, что колонка в табличной части имеет строго числовой тип. Если там составной тип или ошибка в данных, метод может вернуть некорректный результат.

Подведем итог: для решения вашей задачи оптимальным является создание разовой обработки с использованием ОбменДанными.Загрузка = Истина. Это обеспечит высокую производительность списка в будущем и корректность данных «здесь и сейчас» без риска «развалить» прошлые периоды перепроведением.

← На главную