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

Программист 1С v8.3 (Обычные формы) 1С:Зарплата и Управление Персоналом Бухгалтерский учет
← На главную

При разработке обработок выгрузки данных (например, реестров в банк) часто возникает ситуация, когда один документ содержит ссылки на другие документы. Типичный пример: Платежное поручение, в табличной части которого перечислено несколько документов Ведомость на выплату зарплаты. Основная сложность здесь заключается в том, чтобы корректно "провалиться" внутрь каждой ведомости и извлечь данные о сотрудниках, суммах и лицевых счетах.

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

Анализ проблемы и поиск причины ошибки

Рассмотрим ситуацию, представленную в вопросе. Разработчик пытается использовать вложенные циклы для обхода данных. Ошибка возникает в строке Для Каждого СтрокаВедомости Из СтрокаВед1 Цикл. Проблема заключается в использовании неопределенной переменной СтрокаВед1. В контексте кода 1С, если мы находимся внутри цикла по табличной части документа (например, по ведомостям в платежке), текущая строка цикла содержит ссылку на документ ведомости. Чтобы получить доступ к данным этой ведомости, нужно обратиться к ее метаданным через эту ссылку.

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

Решение проблемы через вложенные циклы

Для исправления кода нам необходимо заменить некорректную переменную на правильный путь к данным. Путь будет выглядеть так: ТекущаяСтрокаПлатежки.Ведомость.ИмяТабличнойЧастиВедомости. Рассмотрим исправленный пример кода, который позволит корректно выгрузить данные:


Для Каждого СтрокаСПлатежкой Из МассивДокументов Цикл
    
    // Получаем объект платежки (хотя для чтения данных лучше использовать ссылку)
    Платежка = СтрокаСПлатежкой.ПолучитьОбъект();
    ДатаПлатежки = Формат(Платежка.Дата, "ДФ=dd.MM.yyyy");
    НомерПлатежки = СокрЛП(ПрефиксацияОбъектовКлиентСервер.НомерНаПечать(Платежка.Номер, Истина, Истина));
    
    Текст.ДобавитьСтроку("Д;ООО ""ТАИФ-СТ"";" + ДатаПлатежки + ";" + НомерПлатежки + ";");
    Текст.ДобавитьСтроку("Зачисление денежных средств");
    
    // Первый цикл: обходим ведомости, указанные в табличной части Платежного поручения
    Для каждого СтрокаВед Из Платежка.Ведомости Цикл    
        
        // Обязательно проверяем, заполнена ли ссылка на ведомость
        Если НЕ ЗначениеЗаполнено(СтрокаВед.Ведомость) Тогда
            Продолжить;
        КонецЕсли;

        // Второй цикл: обращаемся к ТЧ "Зарплата" конкретной ведомости через точку от ссылки
        // В типовых ЗУП 3.1 ТЧ ведомости называется "Зарплата"
        Для каждого СтрокаЗарплаты Из СтрокаВед.Ведомость.Зарплата Цикл
            
            Работник = СтрокаЗарплаты.Сотрудник;
            Сумма = СтрокаЗарплаты.КВыплате;
            
            // Получаем номер лицевого счета
            // Внимание: в некоторых конфигурациях он может храниться не в ТЧ, а в регистре
            ЛицевойСчет = СтрокаЗарплаты.НомерЛицевогоСчета;
            
            Если ПустаяСтрока(ЛицевойСчет) Тогда
                Сообщить("Перечисление (" + Сумма + " руб.) сотруднику " + Работник + " не может быть произведено: отсутствует лицевой счет!", СтатусСообщения.Важное);
                Продолжить;
            КонецЕсли;
            
            Текст.ДобавитьСтроку(ЛицевойСчет + ";" + Формат(Сумма, "ЧРД=.;ЧДЦ=2;ЧГ=0") + ";" + Строка(Работник));
            
        КонецЦикла;
    КонецЦикла;
КонецЦикла;

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

Одной из главных трудностей является определение точных имен объектов в конкретной конфигурации (ЗУП, ERP или БП). Чтобы не гадать, рекомендуем использовать следующие методы:

  1. Отладчик (Точка останова): Поставьте точку останова перед проблемным циклом. В табло (Shift+F9) вычислите значение переменной СтрокаВед. Разверните структуру и посмотрите, как называется реквизит, содержащий ссылку на документ (например, Ведомость). Затем в табло введите СтрокаВед.Ведомость и посмотрите список доступных табличных частей этого объекта.
  2. Конфигуратор: Найдите документ «Платежное поручение», перейдите на вкладку «Данные» и изучите состав табличной части. Затем найдите документ «Ведомость...» и посмотрите имя его основной табличной части (чаще всего это Зарплата).

Важные нюансы и оптимизация (Best Practices)

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

1. Избегайте ПолучитьОбъект() для чтения

В исходном коде используется Платежка.ПолучитьОбъект(). Это "тяжелая" операция, которая считывает все данные документа из базы в память. Если вам нужно только прочитать данные для выгрузки, работайте напрямую со ссылкой. Обращение к табличной части через точку от ссылки (ПлатежкаСсылка.Ведомости) работает быстрее.

2. Проблема N+1 запросов

Когда вы используете вложенный цикл типа Для каждого СтрокаЗарплаты Из СтрокаВед.Ведомость.Зарплата, платформа 1С выполняет отдельный запрос к базе данных для каждой ведомости, чтобы получить её табличную часть. Если в платежке 100 ведомостей, будет сделано 100 лишних запросов. На больших объемах данных это приведет к значительным задержкам.

3. Использование Запроса (Рекомендуемый способ)

Самый правильный способ — получить все данные одним запросом. Это позволит мгновенно выгрузить даже реестры на тысячи сотрудников. Проанализируем структуру такого запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ПлатежкаВедомости.Ведомость КАК Ведомость,
    |	ВедомостьЗарплата.Сотрудник КАК Сотрудник,
    |	ВедомостьЗарплата.КВыплате КАК Сумма,
    |	ВедомостьЗарплата.НомерЛицевогоСчета КАК ЛицевойСчет
    |ИЗ
    |	Документ.ПлатежноеПоручение.Ведомости КАК ПлатежкаВедомости
    |		ЛЕВОЕ СОЕДИНЕНИЕ Документ.ВедомостьНаВыплатуЗарплатыВБанк.Зарплата КАК ВедомостьЗарплата
    |		ПО ПлатежкаВедомости.Ведомость = ВедомостьЗарплата.Ссылка
    |ГДЕ
    |	ПлатежкаВедомости.Ссылка = &СсылкаНаПлатежку";

Запрос.УстановитьПараметр("СсылкаНаПлатежку", СсылкаНаПлатежку);
РезультатЗапроса = Запрос.Выполнить();

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

Особенности получения лицевых счетов

Проанализируем ситуацию с лицевыми счетами. В современных конфигурациях (например, 1С:ЗУП 3.1) номер счета может отсутствовать непосредственно в табличной части документа. Он часто хранится в регистре сведений ЛицевыеСчетаСотрудниковПоЗарплатнымПроектам. Если в вашем случае ЛицевойСчет оказывается неопределенным, необходимо использовать программный интерфейс конфигурации или прямой запрос к регистру по сотруднику и организации.

Подведем итог: чтобы правильно получить табличную часть вложенного документа, нужно обращаться через реквизит-ссылку текущей строки основной табличной части. Однако для разработки надежных и быстрых решений всегда отдавайте предпочтение запросам, а не вложенным циклам.

← На главную