Как реализовать автозаполнение табличной части документа остатками из регистра?

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

В процессе разработки в среде 1С:Предприятие часто возникает задача автоматизации ввода данных. Типичный сценарий: пользователю необходимо, чтобы при выборе номенклатуры или нажатии специальной кнопки система сама подтягивала актуальные остатки из регистров и производила математические расчеты «на лету». В данной статье мы подробно разберем, как реализовать механизм заполнения табличной части (ТЧ) документа данными из регистра накопления МатериалыВПроизводстве, учитывая специфику подразделений и динамический пересчет колонок.

Анализ постановки задачи

Рассмотрим ситуацию: в документе есть табличная часть с колонками Номенклатура, Подразделение, ОстатокВПроизводстве, Передано и Получено. Нам необходимо решить две задачи:

  1. Первичное заполнение: при создании или заполнении документа получить данные из виртуальной таблицы остатков регистра на определенную дату.
  2. Динамический пересчет: реализовать формулу ИтоговыйОстаток = ОстатокИзРегистра + Передано - Получено, которая срабатывает при изменении пользователем количественных показателей.

Способ 1: Использование запроса для получения остатков

Для эффективной работы с данными в 1С всегда следует использовать механизм запросов. Проанализируем, как правильно обратиться к виртуальной таблице Остатки регистра накопления. Нам важно передать параметры: дату (момент времени), а также фильтры по номенклатуре и подразделению.

Рассмотрим пример правильного написания запроса с использованием конструктора и учетом синтаксиса переноса строк. Обратите внимание на использование символа вертикальной черты |, отсутствие которого часто приводит к ошибкам компиляции, упомянутым в обсуждении на форуме.


ТекстЗапроса = 
"ВЫБРАТЬ
|   МатериалыВПроизводствеОстатки.Затрата КАК Номенклатура,
|   МатериалыВПроизводствеОстатки.Подразделение КАК Подразделение,
|   МатериалыВПроизводствеОстатки.КоличествоОстаток КАК Количество
|ИЗ
|   РегистрНакопления.МатериалыВПроизводстве.Остатки(&Период, ) КАК МатериалыВПроизводствеОстатки
|ГДЕ
|   МатериалыВПроизводствеОстатки.Подразделение = &Подразделение";

Запрос = Новый Запрос(ТекстЗапроса);
// Важно: используем МоментВремени() для получения актуальных данных на точку в шкале времени
Запрос.УстановитьПараметр("Период", Объект.Дата); 
Запрос.УстановитьПараметр("Подразделение", Объект.Подразделение);

Способ 2: Оптимизированное заполнение ТЧ (Избегаем запросов в цикле)

Одной из главных ошибок начинающих разработчиков является выполнение запроса внутри цикла по строкам табличной части. Это существенно замедляет работу системы. Разберем более правильный и производительный алгоритм: выгрузка всех необходимых ключей (номенклатуры) в массив и получение всех остатков одним запросом.

Проанализируем шаги реализации:

  1. Сформируем массив уникальных ссылок на номенклатуру из табличной части документа.
  2. Передадим этот массив в запрос как параметр.
  3. Результат запроса выгрузим в таблицу значений для быстрого поиска.

// 1. Собираем номенклатуру
МассивНоменклатуры = Объект.Товары.ВыгрузитьКолонку("Номенклатура");

// 2. Получаем остатки одним пакетом
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   Остатки.Затрата КАК Номенклатура,
|   Остатки.КоличествоОстаток КАК Остаток
|ИЗ
|   РегистрНакопления.МатериалыВПроизводстве.Остатки(&Дата, Затрата В (&МассивНоменклатуры)) КАК Остатки";

Запрос.УстановитьПараметр("Дата", Новый Граница(Объект.Дата, ВидГраницы.Исключая));
Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);

ТаблицаОстатков = Запрос.Выполнить().Выгрузить();
ТаблицаОстатков.Индексы.Добавить("Номенклатура");

// 3. Заполняем ТЧ
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    ПараметрыПоиска = Новый Структура("Номенклатура", СтрокаТЧ.Номенклатура);
    НайденныеСтроки = ТаблицаОстатков.НайтиСтроки(ПараметрыПоиска);
    Если НайденныеСтроки.Количество() > 0 Тогда
        СтрокаТЧ.ОстатокВПроизводстве = НайденныеСтроки[0].Остаток;
    Иначе
        СтрокаТЧ.ОстатокВПроизводстве = 0;
    КонецЕсли;
КонецЦикла;

Динамический расчет в форме документа

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

Рассмотрим логику процедуры:


&НаКлиенте
Процедура ТоварыПереданоПриИзменении(Элемент)
    ТекущаяСтрока = Элементы.Товары.ТекущиеДанные;
    Если ТекущаяСтрока <> Неопределено Тогда
        // Рассчитываем итоговый показатель на лету
        // Предположим, что ИсходныйОстаток хранится в скрытой или расчетной колонке
        РассчитатьОстатокСтроки(ТекущаяСтрока);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура РассчитатьОстатокСтроки(Строка)
    // Математическая логика из сообщения автора
    Строка.ОстатокВПроизводстве = Строка.БазовыйОстаток + Строка.Передано - Строка.Получено;
КонецПроцедуры

Важные технические нюансы

При реализации подобных механизмов стоит обратить внимание на следующие моменты:

Архитектурный совет

Как справедливо заметили участники обсуждения, если документ создается только ради отображения сводных данных и печати макета, возможно, стоит рассмотреть создание Отчета на базе системы компоновки данных (СКД). Отчеты по своей природе лучше приспособлены для агрегации данных из разных регистров и не «засоряют» базу данных лишними записями, если хозяйственная операция фактически не совершается. Однако, если данные должны быть зафиксированы в истории — использование документа с автозаполнением является верным решением.

Таким образом, мы проанализировали основные подходы к автоматизации заполнения табличных частей. Сочетание эффективных запросов к виртуальным таблицам и грамотное использование событийных обработчиков формы позволяет создавать удобные и быстрые инструменты для конечных пользователей 1С.

← На главную